Writing a simple desktop widget for Ubuntu

I needed a way to display the contents of an HTML file on my desktop, in such a way that it looks like it’s part of the wallpaper. Fortunately, most of the answer was in How can I make my own custom desktop widgets? on Ask Ubuntu, along with Create a Gtk Window insensitive to Show Desktop and Won’t show in Launcher. Combining that with the excellent Python GI API Reference which contains everything and which I can never find when I go looking for it, I came up with a simple little Python app. I have it monitoring the HTML file which it displays for changes; when that file changes, I refresh the widget.

from gi.repository import WebKit, Gtk, Gdk, Gio, GLib
import signal, os

class MainWin(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, skip_pager_hint=True, skip_taskbar_hint=True)
        self.set_wmclass("sildesktopwidget","sildesktopwidget")
        self.set_type_hint(Gdk.WindowTypeHint.DOCK)
        self.set_size_request(600,400)
        self.set_keep_below(True)

        #Set transparency
        screen = self.get_screen()
        rgba = screen.get_rgba_visual()
        self.set_visual(rgba)
        self.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA(0,0,0,0))

        #Add all the parts
        self.view = WebKit.WebView()
        self.view.set_transparent(True)
        self.view.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA(0,0,0,0))
        self.view.props.settings.props.enable_default_context_menu = False
        self.view.load_uri("file:///home/aquarius/Work/jobs.html")

        box = Gtk.Box()
        self.add(box)
        box.pack_start(self.view, True, True, 0)
        self.set_decorated(False)
        self.connect("destroy", lambda q: Gtk.main_quit())

        #Show all the parts
        self.show_all()
        self.move(100,100)

def refresh_file(*args):
    print args
    mainwin.view.reload()

def file_changed(monitor, file, unknown, event):
    # reload
    GLib.timeout_add_seconds(2, refresh_file)

if __name__ == '__main__':
    gio_file = Gio.File.new_for_path("/home/aquarius/Work/jobs.html")
    monitor = gio_file.monitor_file(Gio.FileMonitorFlags.NONE, None)
    monitor.connect("changed", file_changed)

    mainwin = MainWin()
    signal.signal(signal.SIGINT, signal.SIG_DFL) # make ^c work
    Gtk.main()

Lots of little tricks in there: the widget acts as a widget (that is: it stays glued to the desktop, and doesn’t vanish when you Show Desktop) because of the Gdk.WindowTypeHint.DOCK, skip_pager_hint=True, skip_taskbar_hint=True, and set_keep_below(True) parts; it’s transparent because the HTML file sets its background colour to rgba(0,0,0,0) with CSS and then we use override_background_color to make that actually be transparent; the window has no decorations because of set_decorated(False). Then I just add it to Startup Applications and we’re done.

I'm currently available for hire, to help you plan, architect, and build new systems, and for technical writing and articles. You can take a look at some projects I've worked on and some of my writing. If you'd like to talk about your upcoming project, do get in touch.

More in the discussion (powered by webmentions)

  • (no mentions, yet.)