1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
#!/usr/bin/python3
# Reads a given directory and set a random
# wallpaper using the images on that dir.
import subprocess
import os
import os.path
import re
import random
import sys
import tempfile
class Display:
index = None
name = None
offset = None
size = None
wall_filename = None
def __lt__(self, other):
if self.offset[1] != other.offset[1]:
return self.offset[1] < other.offset[1]
return self.offset[0] < other.offset[0]
def detect_screen_geometry():
screen = None
displays = []
p = subprocess.Popen('xrandr', stdout = subprocess.PIPE, text = True)
for line in p.stdout:
if line.startswith('Screen'):
if screen:
sys.stderr.write('Multiple X screens, not supported by this script\n')
raise NotImplementedError
m = re.search(r'current (\d*) x (\d*),', line)
try:
screen = [int(m.group(1)), int(m.group(2))]
except:
sys.stderr.write('Unsupported screen specification line: %s' % line)
raise
elif ' connected ' in line:
m = re.match(r'(\S*) connected (\S+ )*(\d*)x(\d*)([+-]\d*)([+-]\d*)', line)
if m:
d = Display()
d.name = m.group(1)
d.offset = (int(m.group(5)), int(m.group(6)))
d.size = (int(m.group(3)), int(m.group(4)))
if d.size[0] <= 0 or d.size[1] <= 0:
sys.stderr.write('Invalid non-positive display dimensions\n')
raise ValueError
if d.offset[0] < 0 or d.offset[1] < 0:
sys.stderr.write('Negative display geometry offset, this is not supported\n')
raise NotImplementedError
displays.append(d)
if screen is None:
sys.stderr.write('Missing screen specification in xrandr output\n')
raise ValueError
# sort the displays in the render scan order
displays = sorted(displays)
for i, d in enumerate(displays):
d.index = i
return screen, displays
if len(sys.argv) < 3:
sys.stderr.write('Usage: %s <wallpaper_dir> <state dir> <display number 0> [<display number 1> ... ]\n'%(sys.argv[0]))
sys.exit(-1)
# parse the commandline
wall_dir = os.path.expandvars(sys.argv[1])
state_dir = os.path.expandvars(sys.argv[2])
sys.stderr.write('Trying directory %s.\n'%wall_dir)
if not os.path.isdir(wall_dir):
sys.stderr.write('Path %s is not a directory, aborting.\n'%wall_dir)
sys.exit(-1)
if not os.path.isdir(state_dir):
sys.stderr.write('Invalid state dir supplied, won\'t store/use any state\n')
state_dir = None
screen, displays = detect_screen_geometry()
sys.stderr.write('The X screen resolution is %dx%d.\n' % (screen[0], screen[1]))
sys.stderr.write('The connected displays are:\n')
for i, d in enumerate(displays):
sys.stderr.write(' %d: %s - %d x %d at (%d, %d)\n' % (d.index, d.name, d.size[0], d.size[1], d.offset[0], d.offset[1]))
# pick a new wallpaper for each specified display
files = os.listdir(wall_dir)
random.seed()
if len(sys.argv) >= 4 and sys.argv[3] == 'all':
disp_indices = range(len(displays))
else:
disp_indices = map(int, sys.argv[3:])
for d_idx in disp_indices:
if d_idx >= len(displays):
sys.stderr.write('Display index %d is too large, there are only %d connected displays\n'
% (d_idx, len(displays)))
raise ValueError
d = displays[d_idx]
wallfile = random.choice(files)
sys.stderr.write('Picking wall %s for display %d (%s)\n' % (wallfile, d.index, d.name))
if state_dir:
fname = os.path.join(state_dir, '%d.png' % d.index)
else:
d.tfile = tempfile.NamedTemporaryFile()
fname = d.tfile.name
subprocess.check_call(['convert', '-size', '%dx%d' %(d.size[0], d.size[1]), 'canvas:black',
os.path.join(wall_dir, wallfile), '-resize', '%dx%d' % (d.size[0], d.size[1]),
'-gravity', 'center', '-composite', fname])
d.wall_filename = fname
# compose the wallpaper file
tf = tempfile.NamedTemporaryFile()
cmdline = ['convert', '-size', '%dx%d' % (screen[0], screen[1]), 'canvas:black']
for d in displays:
fname = d.wall_filename
if fname is None and state_dir:
tmpname = os.path.join(state_dir, '%d.png' % d.index)
if os.path.isfile(tmpname):
fname = tmpname
if fname is not None:
cmdline.extend([fname, '-geometry', '+%d+%d' %(d.offset[0], d.offset[1]), '-composite'])
cmdline.append('png:' + tf.name)
subprocess.check_call(cmdline)
# set the background
try:
subprocess.check_call(['feh', '--bg-center', '--no-xinerama', tf.name])
except (subprocess.CalledProcessError, OSError):
sys.stderr.write('Error setting the wallpaper. Is feh installed?\n')
sys.exit(-1)
sys.exit(0)
|