1 #!/usr/bin/python
 2 # simple program for setting a window's icon dynamically
 3 import gtk
 4 import warnings
 5 from sys import argv, exit
 6 from struct import pack, unpack
 7 from optparse import OptionParser
 8 
 9 # parse some options
10 parser = OptionParser()
11 parser.add_option("--graphic", "--img", "--image", type="string",
12     dest="imagefile", metavar="FILE",
13     help="Image file for icon")
14 parser.add_option("--id", type="int", dest="window_id",
15     help="Window ID whose icon is being set")
16 parser.add_option("-v","--verbose")
17 parser.add_option("-s","--silent","-q","--quiet")
18 (options, args) = parser.parse_args()
19 
20 # allow image file and window ID to be given positionally
21 if not options.imagefile and len(args):
22     options.imagefile = args[0]
23     args = args[1:]
24 if not options.window_id and len(args):
25     options.window_id = int(args[0], 0)
26     args = args[1:]
27 
28 # really simple error handling
29 def err(msg=None):
30     if msg and not options.silent:
31         print msg
32     exit(1)
33 
34 # use GDK to load a graphics file into an array of pixels
35 pixmap = gtk.gdk.pixbuf_new_from_file(options.imagefile)
36 if not pixmap:
37     err("Couldn't load pixmap")
38 warnings.filterwarnings('ignore','PyArray_FromDimsAndDataAndDescr',DeprecationWarning)
39 pixels = pixmap.get_pixels_array()
40 
41 # prop will contain an array of 32-bit integers
42 # starting with width, height, then pixel information
43 prop = []
44 prop += [len(pixels[0])]
45 prop += [len(pixels   )]
46 
47 # pixel information is stored in the odd order: alpha, red, green, blue
48 for row in pixels:
49     for p in row:
50         p = p.tolist()
51         if len(p) < 4:
52             p += [255]
53         p = p[3:] + p[:-1]
54         argb = int(0)
55         for i in range(len(p)):
56             argb += p[i] << (8 * (len(p)-i-1))
57         prop += unpack("i",pack("I",argb))
58 
59 # grab a handle to the window, then delete and reset its _NET_WM_ICON
60 window = gtk.gdk.window_foreign_new(options.window_id)
61 if not window:
62     err("Couldn't open window")
63 window.property_delete("_NET_WM_ICON")
64 window.property_change("_NET_WM_ICON","CARDINAL",32,gtk.gdk.PROP_MODE_REPLACE,prop)
65 
66 # many window managers need a hint that the icon has changed
67 # bits 2, 3, and 5 of the WM_HINTS flags int are, respectively:
68 # IconPixmapHint, IconWindowHint, and IconMaskHint
69 wmhints = window.property_get("WM_HINTS")
70 if wmhints:
71     wmhints_type,wmhints_fmt,wmhints_tuple=wmhints
72     wmhints_flags = wmhints_tuple[0]
73     for member in [2,3,5]:
74         if wmhints_flags & (1 << member):
75             wmhints_flags ^= 1 << member
76             wmhints_tuple[member+1] = 0
77     window.property_change("WM_HINTS",wmhints_type,wmhints_fmt,gtk.gdk.PROP_MODE_REPLACE,wmhints_tuple)