~schnouki/smartbg

6a6a961a05d1963a6ed46821b7a5eab4a29149a2 — Thomas Jost 9 years ago 6d79320
Use Xlib rather than GTK/GDK for setting the wallpaper

This allows urxvt & friends to display the wallpaper with pseudo-transparency.
1 files changed, 52 insertions(+), 7 deletions(-)

M smartbg
M smartbg => smartbg +52 -7
@@ 17,6 17,9 @@ import pygtk
pygtk.require('2.0')
import gtk

import Xlib.Xatom, Xlib.display
import Xlib.X as X

IMG_EXTENSIONS = ("bmp", "jpg", "jpeg", "png")
TRANSITION_FPS = 25



@@ 73,13 76,55 @@ def add_image_to_pixbuf(pb, geom, img):

    pix.copy_area(0, 0, iw, ih, pb, gx + off_x, gy + off_y)

def set_wallpaper(win, pb):
    # Set the background pixmap and draw it too (needed for visible AND hidden
    # zones to be updated)
def set_wallpaper(pb):
    # Get a pixmap from the pixbuf
    (pm, mask) = pb.render_pixmap_and_mask()
    win.set_back_pixmap(pm, False)
    win.clear()
    win.draw_pixbuf(None, pb, 0, 0, 0, 0, sw, sh)

    # Let the Xlib fun begin!
    # This is largely inspired by feh and esetroot
    # (http://www.eterm.org/docs/view.php?doc=ref#trans)
    # Create a new display,
    dpy = Xlib.display.Display()
    xscr = dpy.screen()
    xwin = xscr.root

    # Copy pixmap to this display
    pm2 = xwin.create_pixmap(xscr.width_in_pixels, xscr.height_in_pixels, xscr.root_depth)
    gc = pm2.create_gc(fill_style=X.FillTiled, tile=pm.xid)
    pm2.fill_rectangle(gc, 0, 0, xscr.width_in_pixels, xscr.height_in_pixels)
    gc.free()
    dpy.sync()

    # Check if the properties exist and are equal
    prop_root = dpy.intern_atom("_XROOTPMAP_ID", True)
    prop_esetroot = dpy.intern_atom("ESETROOT_PMAP_ID", True)
    if prop_root != X.NONE and prop_esetroot != X.NONE:
        p1 = xwin.get_property(prop_root, X.AnyPropertyType, 0, 1, False)
        if p1 is not None and p1.property_type == Xlib.Xatom.PIXMAP:
            p2 = xwin.get_property(prop_root, X.AnyPropertyType, 0, 1, False)
            if p2 is not None and p2.property_type == Xlib.Xatom.PIXMAP and p1.value == p2.value:
                # It's safe: kill the pixmap
                xpm = dpy.create_resource_object("pixmap", p1.value[0])
                xpm.kill_client()

    # Locate the properties, create them if they don't exist
    prop_root = dpy.intern_atom("_XROOTPMAP_ID", False)
    prop_esetroot = dpy.intern_atom("ESETROOT_PMAP_ID", False)
    if prop_root == X.NONE or prop_esetroot == X.NONE:
        raise ValueError("prop is X.NONE")

    # Set them
    xwin.change_property(prop_root, Xlib.Xatom.PIXMAP, 32, [pm2.__resource__()], X.PropModeReplace)
    xwin.change_property(prop_esetroot, Xlib.Xatom.PIXMAP, 32, [pm2.__resource__()], X.PropModeReplace)

    # Now set the root window background pixmap
    xwin.change_attributes(background_pixmap=pm2.__resource__())
    xwin.clear_area()

    # And we're done!
    dpy.sync()
    dpy.set_close_down_mode(X.RetainPermanent)
    dpy.close()

# Parse command-line
parser = optparse.OptionParser()


@@ 129,4 174,4 @@ if options.duration > 0:
        d = step_duration - ((t2 - t1) * 1000.)

# Now render the wallpaper for good (even if there was a transition)
set_wallpaper(win, wp)
set_wallpaper(wp)