Created
July 19, 2020 09:24
-
-
Save supertin/2a3e9e9439695030a7e294220d58e7c3 to your computer and use it in GitHub Desktop.
XScreensaver digital clock hack in Python3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
ClockScreensaver - Show a simple digital clock using XScreensaver | |
Copyright (C) 2020 Tim Bates | |
Based on WebScreensaver - Copyright (C) 2012-2017 Lucas Martin-King & Thomas Reifenberger | |
This program is free software; you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation; either version 2 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License along | |
with this program; if not, write to the Free Software Foundation, Inc., | |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
Can be run standalone to test. To add to xscreensaver, save somewhere | |
convenient, and add the full path to your ".xscreensaver" file. Set | |
command line parameters (colour, size) using xscreensaver's config tool. | |
""" | |
import os | |
import signal | |
import random | |
import time | |
from time import sleep | |
import gi | |
gi.require_version('Gtk', '3.0') | |
gi.require_version('GdkX11', '3.0') | |
from gi.repository import Gtk, Gdk, GdkX11, GLib | |
class ClockScreensaver(object): | |
''' | |
Hopefully a simple digital clock screensaver | |
''' | |
def __init__(self, window_id=None, size=190000, colour="blue"): | |
self.window_id = window_id | |
# Set the default style variables if blank was passed | |
if size == None: | |
self.size = 190000 | |
else: | |
self.size = size | |
if colour == None: | |
self.colour = "blue" | |
else: | |
self.colour = colour | |
#Set a default window size (this is too small for the default font size, but it shouldn't matter) | |
self.w = 640 | |
self.h = 480 | |
def setup_window(self): | |
'''Perform some magic (if needed) to set up a Gtk window''' | |
if self.window_id: | |
self.win = Gtk.Window(Gtk.WindowType.POPUP) | |
gdk_display = GdkX11.X11Display.get_default() | |
self.gdk_win = GdkX11.X11Window.foreign_new_for_display(gdk_display, self.window_id) | |
# We show the window so we get a Gdk Window, | |
# then we we can reparent it... | |
self.win.show() | |
self.win.get_window().reparent(self.gdk_win, 0, 0) | |
x, y, w, h = self.gdk_win.get_geometry() | |
# Make us cover our parent window | |
self.win.move(0, 0) | |
self.win.set_default_size(w, h) | |
self.win.set_size_request(w, h) | |
self.w, self.h = w, h | |
else: | |
self.win = Gtk.Window() | |
self.win.set_default_size(self.w, self.h) | |
def setup(self): | |
'''Do all the things!''' | |
self.setup_window() | |
self.win.set_title("Clock Screensaver") | |
def terminate(*args): | |
Gtk.main_quit() | |
self.win.connect('destroy', terminate) | |
self.win.connect('delete-event', terminate) | |
signal.signal(signal.SIGINT, signal.SIG_DFL) | |
signal.signal(signal.SIGTERM, terminate) | |
# Create a label and set a generic text for debugging purposes (it should change to the time before anything is shown). | |
self.fixed = Gtk.Fixed() | |
self.label = Gtk.Label() | |
self.label.set_markup("<b>CLOCK HERE</b>") | |
self.label.set_justify(Gtk.Justification.CENTER) | |
# Now shove the label into a "fixed" frame so it can be repostioned. | |
self.fixed.put(self.label, 0, 0) | |
# And add the frame to the window. | |
self.win.add(self.fixed) | |
# Set the CSS for the background and set up the CSS settings. | |
css = b""" | |
* { | |
background-color: black; | |
} | |
""" | |
css_provider = Gtk.CssProvider() | |
css_provider.load_from_data(css) | |
context = Gtk.StyleContext() | |
screen = Gdk.Screen.get_default() | |
context.add_provider_for_screen(screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) | |
#Show it all. Duh. | |
self.win.show_all() | |
def updateclock(self): | |
#Update the actual clock text | |
self.label.set_markup("<span foreground='" + str(self.colour) + "' size='" + str(self.size) + "'>" + time.strftime("%X") + "</span>") | |
#Return true to reset the timer (I think - it doesn't repeat without it) | |
return True | |
def clocktimer(self): | |
#Schedule the clock to update roughly every second (1000 milliseconds) | |
GLib.timeout_add(1000, self.updateclock) | |
def movelabel(self): | |
#Move the label to a random space with a 100x600 range. On some screens, this will result in it running off the edge, but | |
#it works at 1920x1080 on the phone running PostmarketOS that I made this for. Adjust if required I guess. | |
self.fixed.move(self.label, random.randrange(0, 100, 1), random.randrange(0, 600, 1)) | |
return True | |
def movetimer(self): | |
#Schedule random repositioning of the label to prevent burnin | |
GLib.timeout_add(10000, self.movelabel) | |
@classmethod | |
def determine_window_id(cls, win_id=None): | |
'''Try and get an XID to use as our parent window''' | |
if not win_id: | |
win_id = os.getenv('XSCREENSAVER_WINDOW') | |
if win_id: | |
win_id = int(win_id, 16) | |
return win_id | |
if __name__ == "__main__": | |
import argparse | |
parser = argparse.ArgumentParser(description='ClockScreensaver: Simple digital clock as your screensaver') | |
parser.add_argument('-window-id', help='XID of Window to draw on') | |
parser.add_argument('-size', help='Font size. Default is 190000') | |
parser.add_argument('-colour', help='Font colour. Yes. English spelling') | |
args = parser.parse_args() | |
saver = ClockScreensaver(window_id=ClockScreensaver.determine_window_id(args.window_id), colour=args.colour, size=args.size) | |
saver.setup() | |
#Manually update clock text for the first time, then start the clock timer and positioning timer. | |
saver.updateclock() | |
saver.clocktimer() | |
saver.movetimer() | |
#Start the GTK process - after this, everything must be handled by GTK | |
Gtk.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment