1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import glob, gtk
22 import xml.dom.minidom
23 from xml.dom.minidom import Node
24 import os
25 import gettext
26 import screenlets
27
28 gettext.textdomain('screenlets')
29 gettext.bindtextdomain('screenlets', screenlets.INSTALL_PREFIX + '/share/locale')
30
32 return gettext.gettext(s)
33
35 """Convenience function to create a menuitem, connect
36 a callback, and add the menuitem to menu."""
37 if label == "-":
38 item = gtk.SeparatorMenuItem()
39 else:
40 item = gtk.MenuItem(label)
41 return add_menuitem_with_item(menu, item, callback, cb_data)
42
48
50 """Convenience function to add submenuitems to a right-click menu through a list.
51
52 images is an optional list of filenames to be used as an image in each menuitem.
53 Each item in the list should either be a string or None. (If an item is None, gtk's
54 no-image icon will be used.)
55
56 If callback is not None, each menuitem will be connected to callback with it's
57 label as callback data. If prefix exists, prefix will be prefixed to the label's
58 name in the callback data.
59
60 Returns the new submenu."""
61 root_item = gtk.MenuItem(label)
62 root_menu.append(root_item)
63 root_item.show()
64
65 menu = gtk.Menu()
66 root_item.set_submenu(menu)
67
68 i = 0
69 for name in lst:
70
71 if images is not None:
72 item = ImageMenuItem(label=name)
73
74 if images[i] is not None:
75 pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(images[i], *image_size)
76 item.set_image_from_pixbuf(pixbuf)
77
78 else:
79 item.set_image_from_file('')
80
81 else:
82 item = gtk.MenuItem(name)
83 if callback is not None:
84 if prefix is not None:
85 item.connect("activate", callback, prefix+name)
86 else:
87 item.connect("activate", callback, name)
88 item.show()
89 menu.append(item)
90 i += 1
91
92 return menu
93
95 """Convenience function to add a menuitem to a menu
96 and connect a callback."""
97 if callback:
98 if cb_data:
99 item.connect("activate", callback, cb_data)
100 else:
101 item.connect("activate", callback)
102 menu.append(item)
103 item.show()
104 return item
105
107 """Creates a menu from an XML-file and returns None if something went wrong"""
108 doc = None
109 try:
110 doc = xml.dom.minidom.parse(filename)
111 except Exception, e:
112 print "XML-Error: %s" % str(e)
113 return None
114 return create_menu_from_xml(doc.firstChild, callback)
115
117 """Create a gtk.Menu by an XML-Node"""
118 menu = gtk.Menu()
119 for node in node.childNodes:
120
121 type = node.nodeType
122 if type == Node.ELEMENT_NODE:
123 label = node.getAttribute("label")
124 id = node.getAttribute("id")
125 item = None
126 is_check = False
127
128 if node.nodeName == "item":
129 item = gtk.MenuItem(label)
130
131 elif node.nodeName == "checkitem":
132 item = gtk.CheckMenuItem(label)
133 is_check = True
134 if node.hasAttribute("checked"):
135 item.set_active(True)
136
137 elif node.nodeName == "imageitem":
138 icon = node.getAttribute("icon")
139 item = imageitem_from_name(icon, label, icon_size)
140
141 elif node.nodeName == "separator":
142 item = gtk.SeparatorMenuItem()
143
144 elif node.nodeName == "appdir":
145
146 path = node.getAttribute("path")
147 appmenu = ApplicationMenu(path)
148 cats = node.getAttribute("cats").split(",")
149 for cat in cats:
150 item = gtk.MenuItem(cat)
151
152 submenu = appmenu.get_menu_for_category(cat, callback)
153 item.set_submenu(submenu)
154 item.show()
155 menu.append(item)
156 item = None
157
158 elif node.nodeName == "scandir":
159
160 dir = node.getAttribute("directory")
161
162 dir = dir.replace('$HOME', os.environ['HOME'])
163
164 idprfx = node.getAttribute("id_prefix")
165 idsufx = node.getAttribute("id_suffix")
166 srch = node.getAttribute("search").split(',')
167 repl = node.getAttribute("replace").split(',')
168 skp = node.getAttribute("skip").split(',')
169
170 flt = node.getAttribute("filter")
171 if flt=='':
172 flt='*'
173
174
175 fill_menu_from_directory(dir, menu, callback, filter=flt,
176 id_prefix=idprfx, id_suffix=idsufx, search=srch,
177 replace=repl, skip=skp)
178
179 if item:
180 if node.hasChildNodes():
181
182 submenu = create_menu_from_xml(node,
183 callback, icon_size)
184 item.set_submenu(submenu)
185 item.show()
186 if id:
187 item.connect("activate", callback, id)
188 menu.append(item)
189 return menu
190
193 """Create MenuItems from a directory.
194 TODO: use regular expressions"""
195
196 lst = glob.glob(dirname + "/" + filter)
197
198 lst.sort()
199 dlen = len(dirname) + 1
200
201 for filename in lst:
202
203 fname = filename[dlen:]
204
205 if skip.count(fname)<1:
206
207
208 l = len(search)
209 if l>0 and l == len(replace):
210 for i in xrange(l):
211 fname = fname.replace(search[i], replace[i])
212
213 id = id_prefix + fname + id_suffix
214
215
216 item = gtk.MenuItem(fname)
217 item.connect("activate", callback, id)
218 item.show()
219 menu.append(item)
220
222 """Creates a new gtk.ImageMenuItem from a given icon/filename.
223 If an absolute path is not given, the function checks for the name
224 of the icon within the current gtk-theme."""
225 item = gtk.ImageMenuItem(label)
226 image = gtk.Image()
227 if filename and filename[0]=='/':
228
229 try:
230 image.set_from_file(filename)
231 pb = image.get_pixbuf()
232
233 if pb.get_width() > icon_size :
234 pb2 = pb.scale_simple(
235 icon_size, icon_size,
236 gtk.gdk.INTERP_HYPER)
237 image.set_from_pixbuf(pb2)
238 else:
239 image.set_from_pixbuf(pb)
240 except:
241 print "Error while creating image from file: %s" % filename
242 return None
243 else:
244 image.set_from_icon_name(filename, 3)
245 if image:
246 item.set_image(image)
247 return item
248
250 """Read ".desktop"-file into a dict
251 NOTE: Should use utils.IniReader ..."""
252 list = {}
253 f=None
254 try:
255 f = open (filename, "r")
256 except:
257 print "Error: file %s not found." % filename
258 if f:
259 lines = f.readlines()
260 for line in lines:
261 if line[0] != "#" and line !="\n" and line[0] != "[":
262 ll = line.split('=', 1)
263 if len(ll) > 1:
264 list[ll[0]] = ll[1].replace("\n", "")
265 return list
266
267
268
269
270
272 """A utility-class to simplify the creation of gtk.Menus from directories with
273 desktop-files. Reads all files in one or multiple directories into its internal list
274 and offers an easy way to create entire categories as complete gtk.Menu
275 with gtk.ImageMenuItems. """
276
277
278 __path = ""
279
280 __applications = []
281
287
289 """read all desktop-files in a directory into the internal list
290 and sort them into the available categories"""
291 dirlst = glob.glob(path + '/*')
292
293 namelen = len(path)
294 for file in dirlst:
295 if file[-8:]=='.desktop':
296 fname = file[namelen:]
297
298 df = read_desktop_file(file)
299 name = ""
300 icon = ""
301 cmd = ""
302 try:
303 name = df['Name']
304 icon = df['Icon']
305 cmd = df['Exec']
306 cats = df['Categories'].split(';')
307
308
309 self.__applications.append(df)
310 except Exception, ex:
311 print "Exception: %s" % str(ex)
312 print "An error occured with desktop-file: %s" % file
313
315 """returns a gtk.Menu with all apps in the given category"""
316
317 applist = []
318 for app in self.__applications:
319 try:
320 if (';'+app['Categories']).count(';'+cat_name+';') > 0:
321 applist.append(app)
322 except:
323 pass
324
325
326 for app in applist:
327 if applist.count(app) > 1:
328 applist.remove(app)
329
330 applist.sort()
331
332 menu = gtk.Menu()
333 for app in applist:
334 item = imageitem_from_name(app['Icon'], app['Name'], 24)
335 if item:
336 item.connect("activate", callback, "exec:" + app['Exec'])
337 item.show()
338 menu.append(item)
339
340 return menu
341
362
363
365 """A menuitem with a custom image and label.
366 To set the image to a non-stock image, just
367 create the menuitem without an image and then
368 set the image with the appropriate method."""
369
371 """stock: a stock image or 'none'.
372 label: text to set as the label or None."""
373
374 super(ImageMenuItem, self).__init__(stock)
375
376
377 self.label = self.get_child()
378 self.image = self.get_image()
379
380
381 if label is not None:
382 self.set_label(label)
383
385 """Set the image from file."""
386 self.image.set_from_file(filename)
387
389 """Set the image from a pixbuf."""
390 self.image.set_from_pixbuf(pixbuf)
391
393 """Set the image from a stock image."""
394 self.image.set_from_stock(name, gtk.ICON_SIZE_MENU)
395
399
401 """Resize the menuitem's image."""
402 self.image.set_size_request(width, height)
403