1 """Set a random background image (XWin)
3 Select a random image from a (list of) directory(s)
4 and set it as the desktop wallpaper (display it in the root window)
9 from fcntl import flock, LOCK_EX, LOCK_UN, LOCK_NB
10 from datetime import timedelta
18 from xsetbg_conf import xsetbg_dir, xsetbg_conf
19 from xsetbg_db import xsetbg_db
25 sys.exit("%s: Error: %s\n" % (sys.argv[0], error_str))
29 error("No database found. Run rescan_fs.py. Abort.")
31 if xsetbg_db.select().count() == 0:
32 error("No images found. Run rescan_fs.py. Abort.")
35 # minimum time in seconds between background image changes
36 if xsetbg_conf.has_option("xsetbg", "min_pause"):
37 min_pause = xsetbg_conf.getint("xsetbg", "min_pause")
41 borders = xsetbg_conf.get("xsetbg", "borders").split(',')
42 if xsetbg_conf.has_option("xsetbg", "borders"):
43 borders = [border.strip() for border in
44 xsetbg_conf.get("xsetbg", "borders").split(',')]
46 borders = ["darkcyan", "steelblue", "midnightblue"]
48 # minimum time in seconds between occurences of the same image
49 if xsetbg_conf.has_option("xsetbg", "min_delay"):
50 min_delay = xsetbg_conf.get("xsetbg", "min_delay")
52 # Borrowed from http://stackoverflow.com/a/2765366
53 td_re = re.compile('(?:(?P<years>\\d+)y)?'
54 '(?:(?P<months>\\d+)m)?'
55 '(?:(?P<days>\\d+)d)?'
56 '(?:T(?:(?P<hours>\\d+)h)?'
57 '(?:(?P<minutes>\\d+)m)?(?:(?P<seconds>\\d+)s)?)?')
58 td_dict = td_re.match(min_delay).groupdict(0)
59 delta = timedelta(days=int(td_dict['days']) +
60 (int(td_dict['months']) * 30) +
61 (int(td_dict['years']) * 365),
62 hours=int(td_dict['hours']),
63 minutes=int(td_dict['minutes']),
64 seconds=int(td_dict['seconds']))
67 min_delay = delta.days * 24*3600 + delta.seconds
69 min_delay = int(min_delay)
72 min_delay = 3600*24 # 24 hours
76 '(is_image = 1) AND (last_shown IS NULL OR last_shown < %d)' %
77 (time() - min_delay)).count() == 0:
78 error("No unshown images found. Run rescan_fs.py "
79 "or decrease min_delay. Abort.")
81 fs_encoding = xsetbg_conf.get("images", "fs_encoding")
84 def change(force=False):
85 # Use the program's file as the lock file:
86 # lock it to prevent two processes run in parallel.
87 lock_file = open(os.path.join(xsetbg_dir, 'xsetbg.py'), 'r')
90 flock(lock_file, LOCK_EX | LOCK_NB)
91 except IOError: # already locked
96 timestamp = xsetbg_db.select(
97 '(is_image = 1) AND (last_shown IS NOT NULL)',
98 orderBy='-last_shown')[0].last_shown
101 if not force and timestamp is not None and \
102 current_time - timestamp < min_pause:
103 # Too early to change background
106 # Select a random image that has never been shown
107 not_shown_select = xsetbg_db.select(
108 '(is_image = 1) AND (last_shown IS NULL)')
109 not_shown_count = not_shown_select.count()
111 row = not_shown_select[random.randint(0, not_shown_count - 1)]
113 old_shown_select = xsetbg_db.select(
114 '(is_image = 1) AND '
115 '(last_shown IS NOT NULL AND last_shown < %d)' %
116 current_time - min_delay)
117 old_shown_count = old_shown_select.count()
119 row = old_shown_select[random.randint(0, old_shown_count - 1)]
121 error("No images to show found. Run rescan_fs.py "
122 "or decrease min_delay. Abort.")
124 program_options = ["xli", "-border", random.choice(borders),
125 "-center", "-onroot", "-quiet", "-zoom", "auto",
126 row.full_name.encode(fs_encoding)]
128 ext = os.path.splitext(row.full_name)[1].lower()
129 if ext in ('tif', 'tiff'):
130 program_options[0] = 'xsetbg'
133 program_options = ['display', '-backdrop',
134 '-background', random.choice(borders),
136 row.full_name.encode(fs_encoding)]
138 rc = subprocess.call(program_options)
140 error("cannot execute xli!")
142 row.last_shown = current_time
145 # Unlock and close the lock file
146 flock(lock_file, LOCK_UN)