1 diff -aur compiz-deskmenu/Makefile compiz-deskmenu3/Makefile
2 --- compiz-deskmenu/Makefile 2008-03-14 16:25:23.000000000 -0700
3 +++ compiz-deskmenu3/Makefile 2010-11-15 15:58:20.000000000 -0800
7 -CPPFLAGS := `pkg-config --cflags dbus-glib-1 gdk-2.0 gtk+-2.0 libwnck-1.0`
8 -CPPFLAGS_CLIENT := `pkg-config --cflags dbus-glib-1`
9 +CPPFLAGS := `pkg-config --cflags gdk-2.0 gtk+-2.0 libwnck-1.0`
10 WARNINGS := -Wall -Wextra -Wno-unused-parameter
11 CFLAGS := -O2 $(WARNINGS)
12 -LDFLAGS := `pkg-config --libs dbus-glib-1 gdk-2.0 gtk+-2.0 libwnck-1.0`
13 +LDFLAGS := `pkg-config --libs gdk-2.0 gtk+-2.0 libwnck-1.0`
14 LDFLAGS_CLIENT := `pkg-config --libs dbus-glib-1`
16 -all: compiz-deskmenu-menu compiz-deskmenu
19 -compiz-deskmenu: deskmenu.c deskmenu-common.h
20 - $(CC) $(CPPFLAGS_CLIENT) $(CFLAGS) $(LDFLAGS_CLIENT) -o $@ $<
22 -compiz-deskmenu-menu: deskmenu-menu.c deskmenu-wnck.c deskmenu-wnck.h deskmenu-glue.h deskmenu-common.h deskmenu-menu.h
23 +compiz-deskmenu: deskmenu-menu.c deskmenu-wnck.c deskmenu-wnck.h deskmenu-menu.h
25 $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ deskmenu-menu.c deskmenu-wnck.c
27 -deskmenu-glue.h: deskmenu-service.xml
28 - dbus-binding-tool --mode=glib-server --prefix=deskmenu --output=$@ $^
31 mkdir -p $(DESTDIR)$(PREFIX)/bin/
32 install compiz-deskmenu $(DESTDIR)$(PREFIX)/bin/
33 - install compiz-deskmenu-menu $(DESTDIR)$(PREFIX)/bin/
34 install compiz-deskmenu-editor $(DESTDIR)$(PREFIX)/bin/
35 mkdir -p $(DESTDIR)/etc/xdg/compiz/deskmenu/
36 install menu.xml $(DESTDIR)/etc/xdg/compiz/deskmenu/
37 - mkdir -p $(DESTDIR)$(PREFIX)/share/dbus-1/services/
38 - install org.compiz_fusion.deskmenu.service $(DESTDIR)$(PREFIX)/share/dbus-1/services/
41 - rm -f compiz-deskmenu compiz-deskmenu-menu deskmenu-glue.h
42 + rm -f compiz-deskmenu
44 diff -aur compiz-deskmenu/README compiz-deskmenu3/README
45 --- compiz-deskmenu/README 2008-03-14 16:25:23.000000000 -0700
46 +++ compiz-deskmenu3/README 2010-11-16 17:55:54.000000000 -0800
50 +Kudos to Christopher Williams for the excellent program. This new version contains several updates.
54 * A recent version of GLib 2.x and GTK+ 2.x
55 * libwnck (2.20 is probably best, but not strictly required)
56 - * dbus (you must have a running session bus) and dbus-glib
58 It does not strictly require compiz (but it does need a recent version of the
59 vpswitch plugin for 'Initiate on Desktop' to work)
61 * separator: a simple GtkSeparatorMenuItem
62 * windowlist: libwnck-based window list menu.
63 * viewportlist: libwnck-based viewport list menu.
64 - * reload: reload button (it actually quits the menu)
65 + * pipe: dynamically creates any other menu item, as long as the script
66 + you make formats your entries properly
68 -Menu editor coming soon.
69 +Also, you can edit other menu files by doing this:
70 +compiz-deskmenu-editor /path/to/file
72 === Implementation ===
74 -It compiles into two binaries, compiz-deskmenu and compiz-deskmenu-menu.
75 -compiz-deskmenu is a simple dbus client that connects
76 -to org.compiz_fusion.deskmenu and calls the show method. The actual menu is
77 -compiz-deskmenu-menu, but you shouldn't ever need to manually launch it; the
78 -dbus service file will cause it to be automatically spawned when the name is
80 +Compiz-deskmenu compiles into one binary, which is what parses and
81 +displays the menu. If demanded, an apwal-esque version of this will be on its way.
82 diff -aur compiz-deskmenu/compiz-deskmenu-editor compiz-deskmenu3/compiz-deskmenu-editor
83 --- compiz-deskmenu/compiz-deskmenu-editor 2008-03-14 16:25:23.000000000 -0700
84 +++ compiz-deskmenu3/compiz-deskmenu-editor 2010-11-16 17:53:13.000000000 -0800
86 -#!/usr/bin/env python
88 +#!/usr/bin/env python2
89 +#TODO: An actual icon dialog and editing non-default files
92 from lxml import etree
93 from xdg import BaseDirectory
94 +import re #This is to autoset file mode for *.desktop icons
102 class DeskmenuEditor(gtk.Window):
104 - def __init__(self):
105 - gtk.Window.__init__(self)
107 - self.props.title = 'Compiz Deskmenu Editor'
108 - self.props.icon_name = 'gtk-edit'
109 - self.props.border_width = 12
110 - self.set_size_request(400, 400)
111 - self.model = gtk.TreeStore(object)
112 - self.add_menu(menu)
114 - vbox = gtk.VBox(spacing=12)
116 - scrolled = gtk.ScrolledWindow()
117 - scrolled.props.hscrollbar_policy = gtk.POLICY_NEVER
118 - scrolled.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
119 - treeview = gtk.TreeView(self.model)
120 - treeview.set_reorderable(True)
121 - cell = gtk.CellRendererText()
122 - elements = gtk.TreeViewColumn('Item', cell)
123 - elements.set_cell_data_func(cell, self.get_type)
124 - treeview.append_column(elements)
126 - name = gtk.TreeViewColumn('Name')
128 - cell = gtk.CellRendererPixbuf()
129 - name.pack_start(cell, False)
130 - name.set_cell_data_func(cell, self.get_icon)
132 - cell = gtk.CellRendererText()
133 - name.pack_start(cell)
134 - name.set_cell_data_func(cell, self.get_name)
136 - treeview.append_column(name)
137 - scrolled.add(treeview)
138 - vbox.pack_start(scrolled, True, True)
140 - ('deskmenu-element', gtk.TARGET_SAME_WIDGET, 0),
141 - ('text/uri-list', 0, 1),
143 - treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, targets, gtk.gdk.ACTION_DEFAULT|gtk.gdk.ACTION_MOVE)
144 - treeview.enable_model_drag_dest(targets, gtk.gdk.ACTION_MOVE)
146 - treeview.connect('drag-data-get', self.on_drag_data_get)
147 - treeview.connect('drag-data-received', self.on_drag_data_received)
149 - treeview.connect('row-activated', self.on_row_activated)
151 - treeview.connect('button-press-event', self.on_treeview_button_press_event)
152 - treeview.expand_all()
154 - self.selection = treeview.get_selection()
155 - self.selection.connect('changed', self.on_selection_changed)
157 - buttonbox = gtk.HButtonBox()
158 - vbox.pack_end(buttonbox, False, False)
160 - new = gtk.Button(stock=gtk.STOCK_NEW)
161 - new.connect('clicked', self.on_new_clicked)
162 - buttonbox.pack_start(new)
163 - self.edit = gtk.Button(stock=gtk.STOCK_EDIT)
164 - self.edit.connect('clicked', self.on_edit_clicked)
165 - buttonbox.pack_start(self.edit)
166 - self.delete = gtk.Button(stock=gtk.STOCK_DELETE)
167 - self.delete.connect('clicked', self.on_delete_clicked)
168 - buttonbox.pack_start(self.delete)
169 - close = gtk.Button(stock=gtk.STOCK_CLOSE)
170 - close.connect('clicked', self.on_close_clicked)
171 - buttonbox.pack_end(close)
175 - self.popup = gtk.Menu()
176 - self.edit_menu = gtk.ImageMenuItem(stock_id=gtk.STOCK_EDIT)
177 - self.edit_menu.connect('activate', self.on_edit_clicked)
178 - self.popup.append(self.edit_menu)
179 - self.delete_menu = gtk.ImageMenuItem(stock_id=gtk.STOCK_DELETE)
180 - self.delete_menu.connect('activate', self.on_delete_clicked)
181 - self.popup.append(self.delete_menu)
182 - self.popup.show_all()
184 - self.connect('destroy', self.on_close_clicked)
188 - def add_menu(self, m, parent=None):
189 - for item in m.children:
190 - iter = self.model.append(parent, [item])
191 - if item.node.tag == 'menu':
192 - self.add_menu(item, iter)
194 - def get_name(self, column, cell, model, iter):
195 - name = model.get_value(iter, 0).get_name()
198 - cell.set_property('text', name)
200 - def get_type(self, column, cell, model, iter):
201 - typ = model.get_value(iter, 0).get_type()
204 - cell.set_property('text', typ)
206 - def get_icon(self, column, cell, model, iter):
207 - icon = model.get_value(iter, 0).get_icon()
208 - if icon is not None:
209 - cell.set_property('icon-name', icon)
211 - cell.set_property('icon-name', None)
213 - def on_new_clicked(self, widget):
215 - NewItemDialog(*self.selection.get_selected())
217 - def on_edit_clicked(self, widget):
219 - EditItemDialog(*self.selection.get_selected())
221 - def on_delete_clicked(self, widget):
223 - model, row = self.selection.get_selected()
227 - current = model[row][0].node
229 - if current.tag == 'menu' and len(current):
230 - warning = gtk.MessageDialog(self, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, 'Delete menu element with %s children?' %len(current))
231 - warning.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_DELETE, gtk.RESPONSE_ACCEPT)
232 - if warning.run() != gtk.RESPONSE_ACCEPT:
237 - parent = model[row].parent
238 - if parent is not None:
239 - parent = parent[0].node
242 - parent.remove(current)
247 - def on_close_clicked(self, widget):
252 - def on_drag_data_get(self, treeview, context, selection, target_id,
254 - treeselection = treeview.get_selection()
255 - model, iter = treeselection.get_selected()
256 - data = model.get_string_from_iter(iter)
257 - selection.set(selection.target, 8, data)
259 - def on_drag_data_received(self, treeview, context, x, y, selection,
261 - model = treeview.get_model()
262 - data = selection.data
264 - drop_info = treeview.get_dest_row_at_pos(x, y)
265 - if selection.type == 'deskmenu-element':
266 - source = model[data][0]
268 - path, position = drop_info
269 - siter = model.get_iter(data)
270 - diter = model.get_iter(path)
272 - if model.get_path(model.get_iter_from_string(data)) == path:
275 - dest = model[path][0]
276 - if context.action == gtk.gdk.ACTION_MOVE:
277 - source.node.getparent().remove(source.node)
279 - if dest.node.tag == 'menu' and position in (gtk.TREE_VIEW_DROP_INTO_OR_BEFORE,
280 - gtk.TREE_VIEW_DROP_INTO_OR_AFTER):
281 - dest.node.append(source.node)
282 - fiter = model.append(diter, row=(source,))
284 - i = dest.node.getparent().index(dest.node)
285 - if position in (gtk.TREE_VIEW_DROP_INTO_OR_BEFORE,
286 - gtk.TREE_VIEW_DROP_BEFORE):
287 - dest.node.getparent().insert(i, source.node)
288 - fiter = model.insert_before(None, diter, row=(source,))
290 - dest.node.getparent().insert(i+1, source.node)
291 - fiter = model.insert_after(None, diter, row=(source,))
293 - if model.iter_has_child(siter):
294 - citer = model.iter_children(siter)
295 - while citer is not None:
296 - model.append(fiter, row=(model[citer][0],))
297 - citer = model.iter_next(citer)
298 - if context.action == gtk.gdk.ACTION_MOVE:
299 - context.finish(True, True, etime)
301 - elif selection.type == 'text/uri-list':
303 - path, position = drop_info
304 - uri = selection.data.replace('file:///', '/').strip()
305 - entry = ConfigParser.ConfigParser()
307 - launcher = Launcher()
308 - launcher.name = etree.SubElement(launcher.node, 'name')
309 - launcher.icon = etree.SubElement(launcher.node, 'icon')
310 - launcher.command = etree.SubElement(launcher.node, 'command')
312 - launcher.name.text = entry.get('Desktop Entry', 'Name')
313 - launcher.icon.text = entry.get('Desktop Entry', 'Icon').split('.')[0]
314 - launcher.command.text = entry.get('Desktop Entry', 'Exec').split('%')[0]
315 - except ConfigParser.Error:
317 - dest = model[path][0]
318 - diter = model.get_iter(path)
319 - if dest.node.tag == 'menu' and position in (gtk.TREE_VIEW_DROP_INTO_OR_BEFORE,
320 - gtk.TREE_VIEW_DROP_INTO_OR_AFTER):
321 - dest.node.append(launcher.node)
322 - fiter = model.append(diter, row=(launcher,))
324 - i = dest.node.getparent().index(dest.node)
325 - if position in (gtk.TREE_VIEW_DROP_INTO_OR_BEFORE,
326 - gtk.TREE_VIEW_DROP_BEFORE):
327 - dest.node.getparent().insert(i, launcher.node)
328 - fiter = model.insert_before(None, diter, row=(launcher,))
330 - dest.node.getparent().insert(i+1, launcher.node)
331 - fiter = model.insert_after(None, diter, row=(launcher,))
332 - if context.action == gtk.gdk.ACTION_MOVE:
333 - context.finish(True, True, etime)
334 + def __init__(self):
335 + gtk.Window.__init__(self)
337 + self.props.title = 'Compiz Deskmenu Editor'
338 + self.props.icon_name = 'gtk-edit'
339 + self.props.border_width = 12
340 + self.set_size_request(400, 400)
341 + self.model = gtk.TreeStore(object)
342 + self.add_menu(menu)
344 + vbox = gtk.VBox(spacing=12)
346 + scrolled = gtk.ScrolledWindow()
347 + scrolled.props.hscrollbar_policy = gtk.POLICY_NEVER
348 + scrolled.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
349 + treeview = gtk.TreeView(self.model)
350 + treeview.set_reorderable(True)
351 + cell = gtk.CellRendererText()
352 + elements = gtk.TreeViewColumn('Item', cell)
353 + elements.set_cell_data_func(cell, self.get_type)
354 + treeview.append_column(elements)
356 + name = gtk.TreeViewColumn('Name')
358 + cell = gtk.CellRendererPixbuf()
359 + name.pack_start(cell, False)
360 + name.set_cell_data_func(cell, self.get_icon)
362 + cell = gtk.CellRendererText()
363 + name.pack_start(cell)
364 + name.set_cell_data_func(cell, self.get_name)
366 + treeview.append_column(name)
367 + scrolled.add(treeview)
368 + vbox.pack_start(scrolled, True, True)
370 + ('deskmenu-element', gtk.TARGET_SAME_WIDGET, 0),
371 + ('text/uri-list', 0, 1),
373 + treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, targets, gtk.gdk.ACTION_DEFAULT|gtk.gdk.ACTION_MOVE)
374 + treeview.enable_model_drag_dest(targets, gtk.gdk.ACTION_MOVE)
376 + treeview.connect('drag-data-get', self.on_drag_data_get)
377 + treeview.connect('drag-data-received', self.on_drag_data_received)
379 + treeview.connect('row-activated', self.on_row_activated)
381 + treeview.connect('button-press-event', self.on_treeview_button_press_event)
382 + treeview.expand_all()
384 + self.selection = treeview.get_selection()
385 + self.selection.connect('changed', self.on_selection_changed)
387 + buttonbox = gtk.HButtonBox()
388 + vbox.pack_end(buttonbox, False, False)
390 + new = gtk.Button(stock=gtk.STOCK_NEW)
391 + new.connect('clicked', self.on_new_clicked)
392 + buttonbox.pack_start(new)
393 + self.edit = gtk.Button(stock=gtk.STOCK_EDIT)
394 + self.edit.connect('clicked', self.on_edit_clicked)
395 + buttonbox.pack_start(self.edit)
396 + self.delete = gtk.Button(stock=gtk.STOCK_DELETE)
397 + self.delete.connect('clicked', self.on_delete_clicked)
398 + buttonbox.pack_start(self.delete)
399 + close = gtk.Button(stock=gtk.STOCK_CLOSE)
400 + close.connect('clicked', self.on_close_clicked)
401 + buttonbox.pack_end(close)
405 + self.popup = gtk.Menu()
406 + self.edit_menu = gtk.ImageMenuItem(stock_id=gtk.STOCK_EDIT)
407 + self.edit_menu.connect('activate', self.on_edit_clicked)
408 + self.popup.append(self.edit_menu)
409 + self.delete_menu = gtk.ImageMenuItem(stock_id=gtk.STOCK_DELETE)
410 + self.delete_menu.connect('activate', self.on_delete_clicked)
411 + self.popup.append(self.delete_menu)
412 + self.popup.show_all()
414 + self.connect('destroy', self.on_close_clicked)
418 + def add_menu(self, m, parent=None):
419 + for item in m.children:
420 + iter = self.model.append(parent, [item])
421 + if item.node.tag == 'menu':
422 + self.add_menu(item, iter)
424 + def get_name(self, column, cell, model, iter):
425 + name = model.get_value(iter, 0).get_name()
428 + cell.set_property('text', name)
430 + def get_type(self, column, cell, model, iter):
431 + typ = model.get_value(iter, 0).get_type()
434 + cell.set_property('text', typ)
436 + def get_icon(self, column, cell, model, iter):
437 + icon = model.get_value(iter, 0).get_icon()
438 + icon_mode = model.get_value(iter, 0).get_icon_mode()
439 + if icon is not None:
440 + if icon_mode is not None:
441 + w = gtk.icon_size_lookup(gtk.ICON_SIZE_MENU)
442 + cell.set_property('pixbuf', gtk.gdk.pixbuf_new_from_file_at_size(os.path.expanduser(icon), w[0], w[0]))
443 + cell.set_property('icon-name', None) #possibly reduntant safety measure
445 + cell.set_property('icon-name', icon)
446 + cell.set_property('pixbuf', None) #possibly reduntant safety measure
448 + cell.set_property('icon-name', None)
449 + cell.set_property('pixbuf', None)
451 + def on_new_clicked(self, widget):
453 + NewItemDialog(*self.selection.get_selected())
455 + def on_edit_clicked(self, widget):
457 + EditItemDialog(*self.selection.get_selected())
459 + def on_delete_clicked(self, widget):
461 + model, row = self.selection.get_selected()
465 + current = model[row][0].node
467 + if current.tag == 'menu' and len(current):
468 + warning = gtk.MessageDialog(self, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, 'Delete menu element with %s children?' %len(current))
469 + warning.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_DELETE, gtk.RESPONSE_ACCEPT)
470 + if warning.run() != gtk.RESPONSE_ACCEPT:
475 + parent = model[row].parent
476 + if parent is not None:
477 + parent = parent[0].node
480 + parent.remove(current)
485 + def on_close_clicked(self, widget):
490 + def on_drag_data_get(self, treeview, context, selection, target_id,
492 + treeselection = treeview.get_selection()
493 + model, iter = treeselection.get_selected()
494 + data = model.get_string_from_iter(iter)
495 + selection.set(selection.target, 8, data)
497 + def on_drag_data_received(self, treeview, context, x, y, selection,
499 + model = treeview.get_model()
500 + data = selection.data
502 + drop_info = treeview.get_dest_row_at_pos(x, y)
503 + if selection.type == 'deskmenu-element':
504 + source = model[data][0]
506 + path, position = drop_info
507 + siter = model.get_iter(data)
508 + diter = model.get_iter(path)
510 + if model.get_path(model.get_iter_from_string(data)) == path:
513 + dest = model[path][0]
514 + if context.action == gtk.gdk.ACTION_MOVE:
515 + source.node.getparent().remove(source.node)
517 + if dest.node.tag == 'menu' and position in (gtk.TREE_VIEW_DROP_INTO_OR_BEFORE,
518 + gtk.TREE_VIEW_DROP_INTO_OR_AFTER):
519 + dest.node.append(source.node)
520 + fiter = model.append(diter, row=(source,))
522 + i = dest.node.getparent().index(dest.node)
523 + if position in (gtk.TREE_VIEW_DROP_INTO_OR_BEFORE,
524 + gtk.TREE_VIEW_DROP_BEFORE):
525 + dest.node.getparent().insert(i, source.node)
526 + fiter = model.insert_before(None, diter, row=(source,))
528 + dest.node.getparent().insert(i+1, source.node)
529 + fiter = model.insert_after(None, diter, row=(source,))
531 + if model.iter_has_child(siter):
532 + citer = model.iter_children(siter)
533 + while citer is not None:
534 + model.append(fiter, row=(model[citer][0],))
535 + citer = model.iter_next(citer)
536 + if context.action == gtk.gdk.ACTION_MOVE:
537 + context.finish(True, True, etime)
539 + elif selection.type == 'text/uri-list':
541 + path, position = drop_info
542 + uri = selection.data.replace('file:///', '/').strip()
543 + entry = ConfigParser.ConfigParser()
545 + launcher = Launcher()
546 + launcher.name = etree.SubElement(launcher.node, 'name')
547 + launcher.icon = etree.SubElement(launcher.node, 'icon')
548 + launcher.command = etree.SubElement(launcher.node, 'command')
550 + launcher.name.text = entry.get('Desktop Entry', 'Name')
551 + if re.search("/", entry.get('Desktop Entry', 'Icon')):
552 + launcher.icon.attrib['mode1'] = 'file'
553 + launcher.icon.text = entry.get('Desktop Entry', 'Icon')
554 + launcher.command.text = entry.get('Desktop Entry', 'Exec').split('%')[0]
555 + except ConfigParser.Error:
557 + dest = model[path][0]
558 + diter = model.get_iter(path)
559 + if dest.node.tag == 'menu' and position in (gtk.TREE_VIEW_DROP_INTO_OR_BEFORE,
560 + gtk.TREE_VIEW_DROP_INTO_OR_AFTER):
561 + dest.node.append(launcher.node)
562 + fiter = model.append(diter, row=(launcher,))
564 + i = dest.node.getparent().index(dest.node)
565 + if position in (gtk.TREE_VIEW_DROP_INTO_OR_BEFORE,
566 + gtk.TREE_VIEW_DROP_BEFORE):
567 + dest.node.getparent().insert(i, launcher.node)
568 + fiter = model.insert_before(None, diter, row=(launcher,))
570 + dest.node.getparent().insert(i+1, launcher.node)
571 + fiter = model.insert_after(None, diter, row=(launcher,))
572 + if context.action == gtk.gdk.ACTION_MOVE:
573 + context.finish(True, True, etime)
581 - def on_selection_changed(self, selection):
582 + def on_selection_changed(self, selection):
584 - model, row = selection.get_selected()
585 + model, row = selection.get_selected()
587 - sensitive = row and model.get_value(row, 0).editable
588 + sensitive = row and model.get_value(row, 0).editable
590 - self.edit.props.sensitive = sensitive
591 - self.edit_menu.props.sensitive = sensitive
592 - self.delete.props.sensitive = row
593 - self.delete_menu.props.sensitive = row
595 - def on_row_activated(self, treeview, path, view_column):
597 - model = treeview.get_model()
598 - EditItemDialog(model, model.get_iter(path))
600 - def on_treeview_button_press_event(self, treeview, event):
601 - if event.button == 3:
602 - pthinfo = treeview.get_path_at_pos(int(event.x), int(event.y))
603 - if pthinfo is not None:
604 - path, col, cellx, celly = pthinfo
605 - treeview.grab_focus()
606 - treeview.set_cursor(path, col, 0)
607 - self.popup.popup(None, None, None, event.button, event.time)
609 + self.edit.props.sensitive = sensitive
610 + self.edit_menu.props.sensitive = sensitive
611 + self.delete.props.sensitive = row
612 + self.delete_menu.props.sensitive = row
614 + def on_row_activated(self, treeview, path, view_column):
616 + model = treeview.get_model()
617 + EditItemDialog(model, model.get_iter(path))
619 + def on_treeview_button_press_event(self, treeview, event):
620 + if event.button == 3:
621 + pthinfo = treeview.get_path_at_pos(int(event.x), int(event.y))
622 + if pthinfo is not None:
623 + path, col, cellx, celly = pthinfo
624 + treeview.grab_focus()
625 + treeview.set_cursor(path, col, 0)
626 + self.popup.popup(None, None, None, event.button, event.time)
630 class NewItemDialog(gtk.Dialog):
632 - elementlist = ['Launcher', 'Menu', 'Separator', 'Windows List',
633 - 'Viewports List', 'Reload']
634 + elementlist = ['Launcher', 'Menu', 'Separator', 'Windows List',
635 + 'Viewports List', 'Pipeitem']
637 - def __init__(self, model, row):
638 - gtk.Dialog.__init__(self, 'New Item', None, 0, None)
639 + def __init__(self, model, row):
640 + gtk.Dialog.__init__(self, 'New Item', None, 0, None)
642 - self.set_size_request(250, 250)
643 + self.set_size_request(250, 250)
645 - self.props.border_width = 6
646 - self.vbox.props.spacing = 6
647 - self.set_has_separator(False)
648 - self.treeview = self.make_treeview()
650 - scroll = gtk.ScrolledWindow()
651 - scroll.add(self.treeview)
652 - scroll.props.hscrollbar_policy = gtk.POLICY_NEVER
653 - scroll.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
654 - self.vbox.pack_start(scroll, True, True)
656 - self.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
657 - gtk.STOCK_NEW, gtk.RESPONSE_ACCEPT)
659 - self.action_area.props.border_width = 0
665 - if self.run() == gtk.RESPONSE_ACCEPT:
666 - m, r = self.treeview.get_selection().get_selected()
668 - elementname = m[r][0]
672 - parent = sibling = None
674 - current = model[row][0]
675 - if current.node.tag == 'menu':
678 - parent = model[row].parent
679 - if parent is not None:
680 - parent = parent.iter
683 - parentelement = model[parent][0]
685 - parentelement = menu
687 - element = elementsbyname[elementname]()
689 - position = parentelement.node.index(current.node) + 1
690 - parentelement.node.insert(position, element.node)
691 - model.insert_after(parent, sibling, row=(element,))
693 - model.append(parent, row=(element,))
694 - parentelement.node.append(element.node)
699 - if element and element.editable:
700 - EditItemDialog(element=element)
702 - def make_treeview(self):
703 - model = gtk.ListStore(str)
704 - for el in self.elementlist:
707 - treeview = gtk.TreeView(model)
708 - column = gtk.TreeViewColumn(None, gtk.CellRendererText(), text=0)
709 - treeview.set_headers_visible(False)
710 - treeview.append_column(column)
711 + self.props.border_width = 6
712 + self.vbox.props.spacing = 6
713 + self.set_has_separator(False)
714 + self.treeview = self.make_treeview()
716 + scroll = gtk.ScrolledWindow()
717 + scroll.add(self.treeview)
718 + scroll.props.hscrollbar_policy = gtk.POLICY_NEVER
719 + scroll.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
720 + self.vbox.pack_start(scroll, True, True)
722 + self.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
723 + gtk.STOCK_NEW, gtk.RESPONSE_ACCEPT)
725 + self.action_area.props.border_width = 0
731 + if self.run() == gtk.RESPONSE_ACCEPT:
732 + m, r = self.treeview.get_selection().get_selected()
734 + elementname = m[r][0]
738 + parent = sibling = None
740 + current = model[row][0]
741 + if current.node.tag == 'menu':
744 + parent = model[row].parent
745 + if parent is not None:
746 + parent = parent.iter
749 + parentelement = model[parent][0]
751 + parentelement = menu
753 + element = elementsbyname[elementname]()
755 + position = parentelement.node.index(current.node) + 1
756 + parentelement.node.insert(position, element.node)
757 + model.insert_after(parent, sibling, row=(element,))
759 + model.append(parent, row=(element,))
760 + parentelement.node.append(element.node)
765 + if element and element.editable:
766 + EditItemDialog(element=element)
768 + def make_treeview(self):
769 + model = gtk.ListStore(str)
770 + for el in self.elementlist:
773 + treeview = gtk.TreeView(model)
774 + column = gtk.TreeViewColumn(None, gtk.CellRendererText(), text=0)
775 + treeview.set_headers_visible(False)
776 + treeview.append_column(column)
778 - treeview.connect('row-activated', self.on_row_activated)
780 + treeview.connect('row-activated', self.on_row_activated)
783 - def on_row_activated(self, treeview, path, view_column):
784 - self.response(gtk.RESPONSE_ACCEPT)
785 + def on_row_activated(self, treeview, path, view_column):
786 + self.response(gtk.RESPONSE_ACCEPT)
789 class EditItemDialog(gtk.Dialog):
791 - def __init__(self, model=None, row=None, element=None):
792 - gtk.Dialog.__init__(self, 'Edit Item', None, 0, None)
794 - self.set_size_request(300, -1)
795 + def __init__(self, model=None, row=None, element=None):
796 + gtk.Dialog.__init__(self, 'Edit Item', None, 0, None)
798 - self.props.border_width = 6
799 - self.vbox.props.spacing = 6
800 - self.set_has_separator(False)
801 + self.set_size_request(300, -1)
803 - if element is None:
806 - element = model.get_value(row, 0)
807 + self.props.border_width = 6
808 + self.vbox.props.spacing = 6
809 + self.set_has_separator(False)
811 - if not element.editable:
813 + if element is None:
816 + element = model.get_value(row, 0)
818 - for widget in element.get_options():
819 - self.vbox.pack_start(widget, False, False)
820 + if not element.editable:
823 - self.add_buttons(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
824 + for widget in element.get_options():
825 + self.vbox.pack_start(widget, False, False)
831 + self.add_buttons(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
841 - def __init__(self, node=None, parent=None, type=None):
843 + def __init__(self, node=None, parent=None, type=None):
845 - self.editable = False
846 + self.editable = False
849 - self.node = etree.Element('item')
850 - if type is not None:
851 - self.node.attrib['type'] = type
856 + self.node = etree.Element('item')
857 + if type is not None:
858 + self.node.attrib['type'] = type
863 + def get_name(self):
866 - def get_name(self):
868 + def get_type(self):
871 - def get_type(self):
873 + def get_icon(self):
876 - def get_icon(self):
878 + def get_icon_mode(self):
881 class Launcher(Item):
883 - def __init__(self, node=None):
885 + def __init__(self, node=None):
887 - Item.__init__(self, node)
890 - self.node = etree.Element('item', type='launcher')
892 - self.editable = True
894 - def get_name(self):
896 - subnode = self.node.find('name')
897 - if subnode is not None:
898 - name = subnode.text
899 - if subnode.attrib.get('mode') == 'exec':
900 - name = 'exec: %s' %name
905 - def get_type(self):
908 - def get_icon(self):
909 - iconnode = self.node.find('icon')
910 - if iconnode is not None:
911 - return iconnode.text
915 - def get_options(self):
918 - sgroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
920 - label = gtk.Label()
921 - label.set_alignment(0, 0.5)
922 - sgroup.add_widget(label)
923 - label.set_markup('<b>Name:</b>')
924 - widget = gtk.Entry()
926 - namenode = self.node.find('name')
927 - if namenode is not None:
928 - name = namenode.text
931 - widget.props.text = name
932 - widget.connect('changed', self.on_subnode_changed, 'name')
935 - hbox.pack_start(label)
936 - hbox.pack_start(widget, True, True)
937 - retlist.append(hbox)
939 - label = gtk.Label()
940 - label.set_alignment(0, 0.5)
941 - sgroup.add_widget(label)
942 - label.set_markup('<b>Name mode:</b>')
943 - widget = gtk.combo_box_new_text()
944 - widget.append_text('Normal')
945 - widget.append_text('Execute')
946 - widget.props.active = namenode is not None and namenode.attrib.get('mode') == 'exec'
947 - widget.connect('changed', self.on_name_mode_changed)
950 - hbox.pack_start(label)
951 - hbox.pack_start(widget, True, True)
952 - retlist.append(hbox)
954 - label = gtk.Label()
955 - label.set_alignment(0, 0.5)
956 - sgroup.add_widget(label)
957 - label.set_markup('<b>Icon:</b>')
958 - widget = gtk.Entry()
959 - iconnode = self.node.find('icon')
960 - if iconnode is not None:
961 - icon = iconnode.text
964 - widget.props.text = icon
965 - widget.connect('changed', self.on_subnode_changed, 'icon')
968 - hbox.pack_start(label)
969 - hbox.pack_start(widget, True, True)
970 - retlist.append(hbox)
972 - label = gtk.Label()
973 - label.set_alignment(0, 0.5)
974 - sgroup.add_widget(label)
975 - label.set_markup('<b>Command:</b>')
976 - widget = gtk.Entry()
977 - commandnode = self.node.find('command')
978 - if commandnode is not None:
979 - command = commandnode.text
982 - widget.props.text = command
983 - widget.connect('changed', self.on_subnode_changed, 'command')
986 - hbox.pack_start(label)
987 - hbox.pack_start(widget, True, True)
988 - retlist.append(hbox)
992 - def on_subnode_changed(self, widget, tag):
993 - text = widget.props.text
994 - subnode = self.node.find(tag)
996 - if subnode is None:
997 - subnode = etree.SubElement(self.node, tag)
998 - subnode.text = text
1000 - if subnode is not None:
1001 - self.node.remove(subnode)
1003 - def on_name_mode_changed(self, widget):
1004 - namenode = self.node.find('name')
1005 - if widget.props.active:
1006 - if namenode is None:
1007 - namenode = etree.SubElement(self.node, 'name')
1008 - namenode.attrib['mode'] = 'exec'
1009 - elif 'mode' in self.name.attrib:
1010 - namenode.attrib['mode'] = 'normal'
1011 + Item.__init__(self, node)
1014 + self.node = etree.Element('item', type='launcher')
1016 + self.editable = True
1018 + def get_name(self):
1020 + subnode = self.node.find('name')
1021 + if subnode is not None:
1022 + name = subnode.text
1023 + if subnode.attrib.get('mode') == 'exec':
1024 + name = 'exec: %s' %name
1029 + def get_type(self):
1032 + def get_icon(self):
1033 + iconnode = self.node.find('icon')
1034 + if iconnode is not None:
1035 + return iconnode.text
1039 + def get_icon_mode(self):
1040 + iconnode = self.node.find('icon')
1041 + if iconnode is not None:
1042 + if iconnode.attrib.get('mode1') == 'file':
1043 + return iconnode.attrib.get('mode1')
1047 + def get_options(self):
1050 + sgroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
1052 + label = gtk.Label()
1053 + label.set_alignment(0, 0.5)
1054 + sgroup.add_widget(label)
1055 + label.set_markup('<b>Name:</b>')
1056 + widget = gtk.Entry()
1058 + namenode = self.node.find('name')
1059 + if namenode is not None:
1060 + name = namenode.text
1063 + widget.props.text = name
1064 + widget.connect('changed', self.on_subnode_changed, 'name')
1067 + hbox.pack_start(label)
1068 + hbox.pack_start(widget, True, True)
1069 + retlist.append(hbox)
1071 + label = gtk.Label()
1072 + label.set_alignment(0, 0.5)
1073 + sgroup.add_widget(label)
1074 + label.set_markup('<b>Name mode:</b>')
1075 + widget = gtk.combo_box_new_text()
1076 + widget.append_text('Normal')
1077 + widget.append_text('Execute')
1078 + widget.props.active = namenode is not None and namenode.attrib.get('mode') == 'exec'
1079 + widget.connect('changed', self.on_name_mode_changed)
1082 + hbox.pack_start(label)
1083 + hbox.pack_start(widget, True, True)
1084 + retlist.append(hbox)
1086 + label = gtk.Label()
1087 + label.set_alignment(0, 0.5)
1088 + sgroup.add_widget(label)
1089 + label.set_markup('<b>Icon:</b>')
1090 + widget = gtk.Entry()
1092 + iconnode = self.node.find('icon')
1093 + if iconnode is not None:
1094 + icon = iconnode.text
1097 + widget.props.text = icon
1098 + widget.connect('changed', self.on_subnode_changed, 'icon')
1101 + hbox.pack_start(label)
1102 + hbox.pack_start(widget, True, True)
1103 + retlist.append(hbox)
1105 + label = gtk.Label()
1106 + label.set_alignment(0, 0.5)
1107 + sgroup.add_widget(label)
1108 + label.set_markup('<b>Icon mode:</b>')
1109 + widget = gtk.combo_box_new_text()
1110 + widget.append_text('Normal')
1111 + widget.append_text('File Path')
1112 + widget.props.active = iconnode is not None and iconnode.attrib.get('mode1') == 'file'
1113 + widget.connect('changed', self.on_icon_mode_changed)
1116 + hbox.pack_start(label)
1117 + hbox.pack_start(widget, True, True)
1118 + retlist.append(hbox)
1120 + label = gtk.Label()
1121 + label.set_alignment(0, 0.5)
1122 + sgroup.add_widget(label)
1123 + label.set_markup('<b>Command:</b>')
1124 + widget = gtk.Entry()
1125 + commandnode = self.node.find('command')
1126 + if commandnode is not None:
1127 + command = commandnode.text
1130 + widget.props.text = command
1131 + widget.connect('changed', self.on_subnode_changed, 'command')
1134 + hbox.pack_start(label)
1135 + hbox.pack_start(widget, True, True)
1136 + retlist.append(hbox)
1140 + def on_subnode_changed(self, widget, tag):
1141 + text = widget.props.text
1142 + subnode = self.node.find(tag)
1144 + if subnode is None:
1145 + subnode = etree.SubElement(self.node, tag)
1146 + subnode.text = text
1148 + if subnode is not None:
1149 + self.node.remove(subnode)
1151 + def on_name_mode_changed(self, widget):
1152 + namenode = self.node.find('name')
1153 + if widget.props.active:
1154 + if namenode is None:
1155 + namenode = etree.SubElement(self.node, 'name')
1156 + namenode.attrib['mode'] = 'exec'
1157 + elif 'mode' in namenode.attrib:
1158 + del namenode.attrib['mode']
1160 + def on_icon_mode_changed(self, widget):
1161 + iconnode = self.node.find('icon')
1162 + if widget.props.active:
1163 + if iconnode is None:
1164 + iconnode = etree.SubElement(self.node, 'icon')
1165 + iconnode.attrib['mode1'] = 'file'
1166 + elif 'mode1' in iconnode.attrib:
1167 + del iconnode.attrib['mode1']
1169 class Windowlist(Item):
1171 - def __init__(self, node=None):
1172 - Item.__init__(self, node, type='windowlist')
1174 - def get_type(self):
1175 - return 'Windows list'
1177 + def __init__(self, node=None):
1178 + Item.__init__(self, node, type='windowlist')
1179 + self.editable = True
1181 + def get_icon(self):
1182 + iconnode = self.node.find('icon')
1183 + if iconnode is not None:
1184 + return iconnode.text
1188 + def get_icon_mode(self):
1189 + iconnode = self.node.find('icon')
1190 + if iconnode is not None:
1191 + if iconnode.attrib.get('mode1') == 'file':
1192 + return iconnode.attrib.get('mode1')
1196 + def get_options(self):
1198 + sgroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
1200 + label = gtk.Label()
1201 + label.set_alignment(0, 0.5)
1202 + sgroup.add_widget(label)
1203 + label.set_markup('<b>Icon:</b>')
1204 + widget = gtk.Entry()
1206 + iconnode = self.node.find('icon')
1207 + if iconnode is not None:
1208 + icon = iconnode.text
1211 + widget.props.text = icon
1212 + widget.connect('changed', self.on_subnode_changed, 'icon')
1215 + hbox.pack_start(label)
1216 + hbox.pack_start(widget, True, True)
1217 + retlist.append(hbox)
1219 + label = gtk.Label()
1220 + label.set_alignment(0, 0.5)
1221 + sgroup.add_widget(label)
1222 + label.set_markup('<b>Icon mode:</b>')
1223 + widget = gtk.combo_box_new_text()
1224 + widget.append_text('Normal')
1225 + widget.append_text('File Path')
1226 + widget.props.active = iconnode is not None and iconnode.attrib.get('mode1') == 'file'
1227 + widget.connect('changed', self.on_icon_mode_changed)
1230 + hbox.pack_start(label)
1231 + hbox.pack_start(widget, True, True)
1232 + retlist.append(hbox)
1236 + def on_subnode_changed(self, widget, tag):
1237 + text = widget.props.text
1238 + subnode = self.node.find(tag)
1240 + if subnode is None:
1241 + subnode = etree.SubElement(self.node, tag)
1242 + subnode.text = text
1244 + if subnode is not None:
1245 + self.node.remove(subnode)
1247 + def on_icon_mode_changed(self, widget):
1248 + iconnode = self.node.find('icon')
1249 + if widget.props.active:
1250 + if iconnode is None:
1251 + iconnode = etree.SubElement(self.node, 'icon')
1252 + iconnode.attrib['mode1'] = 'file'
1253 + elif 'mode1' in iconnode.attrib:
1254 + del iconnode.attrib['mode1']
1256 + def get_type(self):
1257 + return 'Windows list'
1259 class Viewportlist(Item):
1261 - def __init__(self, node=None):
1262 - Item.__init__(self, node, type='viewportlist')
1263 - self.editable = True
1264 - self.wrap = self.node.find('wrap')
1266 - def get_type(self):
1267 - return 'Viewports list'
1269 - def get_options(self):
1271 - widget = gtk.CheckButton("Wrap Viewports")
1272 - widget.props.active = self.get_wrap()
1273 - widget.connect('toggled', self.on_wrap_changed)
1274 - retlist.append(widget)
1278 - def get_wrap(self):
1279 - if self.wrap is not None:
1280 - return self.wrap.text == 'true'
1283 - def on_wrap_changed(self, widget):
1284 - if self.wrap is None:
1285 - self.wrap = etree.SubElement(self.node, 'wrap')
1286 - if widget.props.active:
1290 - self.wrap.text = text
1293 -class Reload(Item):
1295 - def __init__(self, node=None):
1296 - Item.__init__(self, node, type='reload')
1298 - def get_type(self):
1302 + def __init__(self, node=None): #change to be an attribute of viewportlist
1303 + Item.__init__(self, node, type='viewportlist')
1304 + self.editable = True
1305 + self.wrap = self.node.find('wrap')
1307 + def get_type(self):
1308 + return 'Viewports list'
1310 + def get_icon(self):
1311 + iconnode = self.node.find('icon')
1312 + if iconnode is not None:
1313 + return iconnode.text
1317 + def get_icon_mode(self):
1318 + iconnode = self.node.find('icon')
1319 + if iconnode is not None:
1320 + if iconnode.attrib.get('mode1') == 'file':
1321 + return iconnode.attrib.get('mode1')
1326 + def get_options(self):
1328 + sgroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
1329 + widget = gtk.CheckButton("Wrap Viewports")
1330 + widget.props.active = self.get_wrap()
1331 + widget.connect('toggled', self.on_wrap_changed)
1332 + retlist.append(widget)
1334 + label = gtk.Label()
1335 + label.set_alignment(0, 0.5)
1336 + sgroup.add_widget(label)
1337 + label.set_markup('<b>Icon:</b>')
1338 + widget = gtk.Entry()
1340 + iconnode = self.node.find('icon')
1341 + if iconnode is not None:
1342 + icon = iconnode.text
1345 + widget.props.text = icon
1346 + widget.connect('changed', self.on_subnode_changed, 'icon')
1349 + hbox.pack_start(label)
1350 + hbox.pack_start(widget, True, True)
1351 + retlist.append(hbox)
1353 + label = gtk.Label()
1354 + label.set_alignment(0, 0.5)
1355 + sgroup.add_widget(label)
1356 + label.set_markup('<b>Icon mode:</b>')
1357 + widget = gtk.combo_box_new_text()
1358 + widget.append_text('Normal')
1359 + widget.append_text('File Path')
1360 + widget.props.active = iconnode is not None and iconnode.attrib.get('mode1') == 'file'
1361 + widget.connect('changed', self.on_icon_mode_changed)
1364 + hbox.pack_start(label)
1365 + hbox.pack_start(widget, True, True)
1366 + retlist.append(hbox)
1368 + label = gtk.Label()
1369 + label.set_alignment(0, 0.5)
1370 + sgroup.add_widget(label)
1371 + label.set_markup('<b>Viewport Icon:</b>')
1372 + widget = gtk.Entry()
1374 + vpiconnode = self.node.find('vpicon')
1375 + if vpiconnode is not None:
1376 + icon = vpiconnode.text
1379 + widget.props.text = icon
1380 + widget.connect('changed', self.on_subnode_changed, 'vpicon')
1383 + hbox.pack_start(label)
1384 + hbox.pack_start(widget, True, True)
1385 + retlist.append(hbox)
1387 + label = gtk.Label()
1388 + label.set_alignment(0, 0.5)
1389 + sgroup.add_widget(label)
1390 + label.set_markup('<b>Viewport Icon mode:</b>')
1391 + widget = gtk.combo_box_new_text()
1392 + widget.append_text('Normal')
1393 + widget.append_text('File Path')
1394 + widget.props.active = vpiconnode is not None and vpiconnode.attrib.get('mode1') == 'file'
1395 + widget.connect('changed', self.on_vpicon_mode_changed)
1398 + hbox.pack_start(label)
1399 + hbox.pack_start(widget, True, True)
1400 + retlist.append(hbox)
1404 + def get_wrap(self):
1405 + if self.wrap is not None:
1406 + return self.wrap.text == 'true'
1409 + def on_subnode_changed(self, widget, tag):
1410 + text = widget.props.text
1411 + subnode = self.node.find(tag)
1413 + if subnode is None:
1414 + subnode = etree.SubElement(self.node, tag)
1415 + subnode.text = text
1417 + if subnode is not None:
1418 + self.node.remove(subnode)
1420 + def on_wrap_changed(self, widget):
1421 + if self.wrap is None:
1422 + self.wrap = etree.SubElement(self.node, 'wrap')
1423 + if widget.props.active:
1427 + self.wrap.text = text
1429 + def on_icon_mode_changed(self, widget):
1430 + iconnode = self.node.find('icon')
1431 + if widget.props.active:
1432 + if iconnode is None:
1433 + iconnode = etree.SubElement(self.node, 'icon')
1434 + iconnode.attrib['mode1'] = 'file'
1435 + elif 'mode1' in iconnode.attrib:
1436 + del iconnode.attrib['mode1']
1438 + def on_vpicon_mode_changed(self, widget):
1439 + iconnode = self.node.find('vpicon')
1440 + if widget.props.active:
1441 + if iconnode is None:
1442 + iconnode = etree.SubElement(self.node, 'vpicon')
1443 + iconnode.attrib['mode1'] = 'file'
1444 + elif 'mode1' in iconnode.attrib:
1445 + del iconnode.attrib['mode1']
1447 class Separator(object):
1449 - def __init__(self, node=None, parent=None):
1451 - self.editable = False
1452 - if self.node is None:
1453 - self.node = etree.Element('separator')
1455 - def get_name(self):
1458 - def get_type(self):
1459 - return 'Separator'
1461 + def __init__(self, node=None, parent=None):
1463 + self.editable = False
1464 + if self.node is None:
1465 + self.node = etree.Element('separator')
1467 + def get_name(self):
1470 + def get_type(self):
1471 + return 'Separator'
1473 + def get_icon(self):
1476 + def get_icon_mode(self):
1479 +class Pipe(object):
1481 + def __init__(self, node=None):
1483 + self.children = []
1484 + self.editable = True
1487 + self.node = etree.Element('pipe', command='')
1489 + for child in self.node.getchildren():
1491 + self.children.append(self.make_child(child))
1496 + def make_child(self, child):
1497 + return elements[child.tag](child)
1499 + def get_name(self):
1500 + name = self.node.attrib.get('command', '')
1503 + def get_icon(self):
1506 + def get_icon_mode(self):
1509 + def get_type(self):
1512 + def get_options(self):
1515 + sgroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
1517 + label = gtk.Label()
1518 + label.set_alignment(0, 0.5)
1519 + label.set_markup('<b>Command:</b>')
1520 + widget = gtk.Entry()
1521 + widget.props.text = self.node.attrib.get('command', '')
1522 + widget.connect('changed', self.on_command_changed)
1525 + hbox.pack_start(label)
1526 + hbox.pack_start(widget, True, True)
1527 + retlist.append(hbox)
1529 - def get_icon(self):
1533 + def on_command_changed(self, widget):
1534 + self.node.attrib['command'] = widget.props.text
1538 - def __init__(self, node=None):
1540 - self.children = []
1541 - self.editable = True
1544 - self.node = etree.Element('menu', name='')
1546 - for child in self.node.getchildren():
1548 - self.children.append(self.make_child(child))
1553 - def make_child(self, child):
1554 - return elements[child.tag](child)
1556 - def get_name(self):
1557 - return self.node.attrib.get('name', '')
1559 - def get_type(self):
1562 - def get_icon(self):
1565 - def get_options(self):
1568 - label = gtk.Label()
1569 - label.set_alignment(0, 0.5)
1570 - label.set_markup('<b>Name:</b>')
1571 - widget = gtk.Entry()
1572 - widget.props.text = self.node.attrib.get('name', '')
1573 - widget.connect('changed', self.on_name_changed)
1575 - hbox.pack_start(label)
1576 - hbox.pack_start(widget, True, True)
1577 - retlist.append(hbox)
1581 - def on_name_changed(self, widget):
1582 - self.node.attrib['name'] = widget.props.text
1584 + def __init__(self, node=None):
1586 + self.children = []
1587 + self.editable = True
1590 + self.node = etree.Element('menu', name='')
1592 + for child in self.node.getchildren():
1594 + self.children.append(self.make_child(child))
1599 + def make_child(self, child):
1600 + return elements[child.tag](child)
1602 + def get_name(self):
1603 + name = self.node.attrib.get('name', '')
1604 + if self.node.attrib.get('mode') == 'exec':
1605 + name = 'exec: %s' %name
1608 + def get_icon(self):
1609 + return self.node.attrib.get('icon', '')
1611 + def get_icon_mode(self):
1612 + if self.node.attrib.get('mode1') == 'file':
1613 + return self.node.attrib.get('mode1')
1617 + def get_type(self):
1620 + def get_options(self):
1623 + sgroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
1625 + label = gtk.Label()
1626 + label.set_alignment(0, 0.5)
1627 + label.set_markup('<b>Name:</b>')
1628 + widget = gtk.Entry()
1629 + widget.props.text = self.node.attrib.get('name', '')
1630 + widget.connect('changed', self.on_name_changed)
1633 + hbox.pack_start(label)
1634 + hbox.pack_start(widget, True, True)
1635 + retlist.append(hbox)
1637 + label = gtk.Label()
1638 + label.set_alignment(0, 0.5)
1639 + sgroup.add_widget(label)
1640 + label.set_markup('<b>Name mode:</b>')
1641 + widget = gtk.combo_box_new_text()
1642 + widget.append_text('Normal')
1643 + widget.append_text('Execute')
1644 + widget.props.active = self.node.attrib.get('name') is not None and self.node.attrib.get('mode') == 'exec'
1645 + widget.connect('changed', self.on_name_mode_changed)
1648 + hbox.pack_start(label)
1649 + hbox.pack_start(widget, True, True)
1650 + retlist.append(hbox)
1652 + #TODO:Make this actually edit icon
1653 + label = gtk.Label()
1654 + label.set_alignment(0, 0.5)
1655 + sgroup.add_widget(label)
1656 + label.set_markup('<b>Icon:</b>')
1657 + widget = gtk.Entry()
1658 + if self.node.attrib.get('icon') is not None:
1659 + widget.props.text = self.node.attrib.get('icon')
1661 + widget.props.text = ''
1662 + #widget.props.text = self.node.attrib.get('icon')
1663 + widget.connect('changed', self.on_icon_changed)
1666 + hbox.pack_start(label)
1667 + hbox.pack_start(widget, True, True)
1668 + retlist.append(hbox)
1670 + label = gtk.Label()
1671 + label.set_alignment(0, 0.5)
1672 + sgroup.add_widget(label)
1673 + label.set_markup('<b>Icon mode:</b>')
1674 + widget = gtk.combo_box_new_text()
1675 + widget.append_text('Normal')
1676 + widget.append_text('File Path')
1677 + widget.props.active = self.node.attrib.get('icon') is not None and self.node.attrib.get('mode1') == 'file'
1678 + widget.connect('changed', self.on_icon_mode_changed)
1681 + hbox.pack_start(label)
1682 + hbox.pack_start(widget, True, True)
1683 + retlist.append(hbox)
1687 + def on_name_changed(self, widget):
1688 + self.node.attrib['name'] = widget.props.text
1689 + def on_name_mode_changed(self, widget): #EDIT THIS
1690 + if widget.props.active:
1691 + self.node.attrib['mode'] = 'exec'
1692 + elif 'mode' in self.node.attrib:
1693 + del self.node.attrib['mode']
1694 + def on_icon_changed(self, widget):
1695 + if widget.props.text != '':
1696 + self.node.attrib['icon'] = widget.props.text
1698 + del self.node.attrib['icon']
1699 + def on_icon_mode_changed(self, widget): #EDIT THIS
1700 + if widget.props.active:
1701 + self.node.attrib['mode1'] = 'file'
1702 + elif 'mode1' in self.node.attrib:
1703 + del self.node.attrib['mode1']
1706 - 'launcher': Launcher,
1707 - 'windowlist': Windowlist,
1708 - 'viewportlist': Viewportlist,
1710 + 'launcher': Launcher,
1711 + 'windowlist': Windowlist,
1712 + 'viewportlist': Viewportlist,
1716 def make_item(node):
1718 - itemtype = node.attrib.get('type')
1719 - return itemtypes.get(itemtype, Item)(node)
1720 + itemtype = node.attrib.get('type')
1721 + return itemtypes.get(itemtype, Item)(node)
1724 def indent(elem, level=0):
1725 - i = "\n" + level*" "
1727 - if not elem.text or not elem.text.strip():
1728 - elem.text = i + " "
1730 - indent(e, level+1)
1731 - if not e.tail or not e.tail.strip():
1733 - if not e.tail or not e.tail.strip():
1736 - if level and (not elem.tail or not elem.tail.strip()):
1738 + i = "\n" + level*" "
1740 + if not elem.text or not elem.text.strip():
1741 + elem.text = i + " "
1743 + indent(e, level+1)
1744 + if not e.tail or not e.tail.strip():
1746 + if not e.tail or not e.tail.strip():
1749 + if level and (not elem.tail or not elem.tail.strip()):
1755 - menufile.write(open(os.path.join(configdir, 'menu.xml'), 'w'))
1757 + menufile.write(open(filename, 'w'))
1759 - if bus is not None:
1761 - bus.get_object('org.compiz_fusion.deskmenu',
1762 - '/org/compiz_fusion/deskmenu/menu').reload()
1763 - except dbus.DBusException:
1766 -elements = {'menu': Menu, 'item': make_item, 'separator': Separator}
1767 +elements = {'menu': Menu, 'item': make_item, 'separator': Separator, 'pipe': Pipe}
1770 - 'Launcher': Launcher,
1771 - 'Windows List': Windowlist,
1772 - 'Viewports List': Viewportlist,
1774 - 'Separator': Separator,
1776 + 'Launcher': Launcher,
1777 + 'Windows List': Windowlist,
1778 + 'Viewports List': Viewportlist,
1779 + 'Separator': Separator,
1785 if __name__ == '__main__':
1789 - bus = dbus.SessionBus()
1790 - except dbus.DBusException:
1795 - filename = BaseDirectory.load_first_config('compiz/deskmenu/menu.xml')
1796 - menufile = etree.parse(filename)
1797 - root = menufile.getroot()
1799 - configdir = BaseDirectory.save_config_path('compiz/deskmenu')
1803 + if len(sys.argv) == 2 :
1804 + if open(sys.argv[1]):
1805 + filename = sys.argv[1]
1807 + filename = BaseDirectory.load_first_config('compiz/deskmenu/menu.xml')
1808 + menufile = etree.parse(filename)
1809 + root = menufile.getroot()
1813 diff -aur compiz-deskmenu/deskmenu-menu.c compiz-deskmenu3/deskmenu-menu.c
1814 --- compiz-deskmenu/deskmenu-menu.c 2008-03-14 16:25:23.000000000 -0700
1815 +++ compiz-deskmenu3/deskmenu-menu.c 2010-11-16 15:41:15.000000000 -0800
1818 - * compiz-deskmenu is free software; you can redistribute it and/or modify
1819 - * it under the terms of the GNU General Public License as published by
1820 - * the Free Software Foundation; either version 2 of the License, or
1821 - * (at your option) any later version.
1823 - * compiz-deskmenu is distributed in the hope that it will be useful,
1824 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
1825 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1826 - * GNU General Public License for more details.
1828 - * You should have received a copy of the GNU General Public License
1829 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
1831 - * Copyright 2008 Christopher Williams <christopherw@verizon.net>
1834 -#include <stdlib.h>
1835 -#include <string.h>
1836 -#include <dbus/dbus-glib-lowlevel.h>
1837 -#include <gtk/gtk.h>
1839 -#define HAVE_WNCK 1
1842 -#include "deskmenu-wnck.h"
1845 -#include "deskmenu-menu.h"
1846 -#include "deskmenu-glue.h"
1849 -G_DEFINE_TYPE(Deskmenu, deskmenu, G_TYPE_OBJECT)
1852 -deskmenu_error_quark (void)
1854 - static GQuark quark = 0;
1856 - quark = g_quark_from_static_string ("deskmenu_error");
1861 -quit (GtkWidget *widget,
1868 -launcher_activated (GtkWidget *widget,
1871 - GError *error = NULL;
1872 - Deskmenu *deskmenu;
1874 - deskmenu = g_object_get_data (G_OBJECT (widget), "deskmenu");
1876 - if (!gdk_spawn_on_screen (gdk_screen_get_default (),
1877 - g_get_home_dir (),
1878 - g_strsplit (command, " ", 0),
1879 - deskmenu->envp, G_SPAWN_SEARCH_PATH,
1880 - NULL, NULL, NULL, &error))
1882 - GtkWidget *message = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
1883 - GTK_BUTTONS_CLOSE, "%s", error->message);
1884 - gtk_dialog_run (GTK_DIALOG (message));
1885 - gtk_widget_destroy (message);
1891 -launcher_name_exec_update (GtkWidget *label)
1893 - gchar *exec, *stdout;
1894 - exec = g_object_get_data (G_OBJECT (label), "exec");
1895 - if (g_spawn_command_line_sync (exec, &stdout, NULL, NULL, NULL))
1896 - gtk_label_set_text (GTK_LABEL (label), g_strstrip(stdout));
1898 - gtk_label_set_text (GTK_LABEL (label), "execution error");
1903 -deskmenu_construct_item (Deskmenu *deskmenu)
1905 - DeskmenuItem *item = deskmenu->current_item;
1906 - GtkWidget *menu_item;
1907 - gchar *name, *icon, *command;
1909 - switch (item->type)
1911 - case DESKMENU_ITEM_LAUNCHER:
1912 - if (item->name_exec)
1917 - name = g_strstrip (item->name->str);
1919 - menu_item = gtk_image_menu_item_new ();
1920 - label = gtk_label_new_with_mnemonic (NULL);
1921 - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1923 - g_object_set_data (G_OBJECT (label), "exec", g_strdup (name));
1924 - gtk_container_add (GTK_CONTAINER (menu_item), label);
1925 - hook = g_hook_alloc (deskmenu->show_hooks);
1927 - hook->data = (gpointer) label;
1928 - hook->func = (GHookFunc *) launcher_name_exec_update;
1929 - g_hook_append (deskmenu->show_hooks, hook);
1934 - name = g_strstrip (item->name->str);
1938 - menu_item = gtk_image_menu_item_new_with_mnemonic (name);
1944 - icon = g_strstrip (item->icon->str);
1945 - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
1946 - gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
1949 - if (item->command)
1951 - command = g_strstrip (item->command->str);
1952 - g_object_set_data (G_OBJECT (menu_item), "deskmenu", deskmenu);
1953 - g_signal_connect (G_OBJECT (menu_item), "activate",
1954 - G_CALLBACK (launcher_activated), g_strdup (command));
1957 - gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
1962 - case DESKMENU_ITEM_WINDOWLIST:
1963 - menu_item = gtk_menu_item_new_with_mnemonic ("_Windows");
1965 - DeskmenuWindowlist *windowlist = deskmenu_windowlist_new ();
1967 - gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
1968 - windowlist->menu);
1969 - gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
1973 - case DESKMENU_ITEM_VIEWPORTLIST:
1974 - menu_item = gtk_menu_item_new_with_mnemonic ("_Viewports");
1976 - DeskmenuVplist *vplist = deskmenu_vplist_new ();
1979 - && strcmp (g_strstrip (item->wrap->str), "true") == 0)
1980 - vplist->wrap = TRUE;
1982 - gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
1984 - gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
1988 - case DESKMENU_ITEM_RELOAD:
1989 - menu_item = gtk_image_menu_item_new_with_mnemonic ("_Reload");
1990 - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
1991 - gtk_image_new_from_stock (GTK_STOCK_REFRESH,
1992 - GTK_ICON_SIZE_MENU));
1993 - g_signal_connect (G_OBJECT (menu_item), "activate",
1994 - G_CALLBACK (quit), NULL);
1995 - gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
2004 -/* The handler functions. */
2007 -start_element (GMarkupParseContext *context,
2008 - const gchar *element_name,
2009 - const gchar **attr_names,
2010 - const gchar **attr_values,
2011 - gpointer user_data,
2014 - Deskmenu *deskmenu = DESKMENU (user_data);
2015 - DeskmenuElementType element_type;
2016 - const gchar **ncursor = attr_names, **vcursor = attr_values;
2017 - GtkWidget *item, *menu;
2019 - element_type = GPOINTER_TO_INT (g_hash_table_lookup
2020 - (deskmenu->element_hash, element_name));
2022 - if ((deskmenu->menu && !deskmenu->current_menu)
2023 - || (!deskmenu->menu && element_type != DESKMENU_ELEMENT_MENU))
2025 - gint line_num, char_num;
2026 - g_markup_parse_context_get_position (context, &line_num, &char_num);
2027 - g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2028 - "Error on line %d char %d: Element '%s' declared outside of "
2029 - "toplevel menu element", line_num, char_num, element_name);
2033 - switch (element_type)
2035 - case DESKMENU_ELEMENT_MENU:
2037 - if (deskmenu->current_item != NULL)
2039 - gint line_num, char_num;
2040 - g_markup_parse_context_get_position (context, &line_num,
2042 - g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2043 - "Error on line %d char %d: Element 'menu' cannot be nested "
2044 - "inside of an item element", line_num, char_num);
2048 - if (!deskmenu->menu)
2050 - deskmenu->menu = gtk_menu_new ();
2051 - g_object_set_data (G_OBJECT (deskmenu->menu), "parent menu",
2053 - deskmenu->current_menu = deskmenu->menu;
2057 - gchar *name = NULL;
2060 - if (strcmp (*ncursor, "name") == 0)
2061 - name = g_strdup (*vcursor);
2063 - g_set_error (error, G_MARKUP_ERROR,
2064 - G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
2065 - "Unknown attribute: %s", *ncursor);
2070 - item = gtk_menu_item_new_with_mnemonic (name);
2072 - item = gtk_menu_item_new_with_mnemonic ("");
2073 - gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
2075 - menu = gtk_menu_new ();
2076 - g_object_set_data (G_OBJECT (menu), "parent menu",
2077 - deskmenu->current_menu);
2078 - deskmenu->current_menu = menu;
2079 - gtk_menu_item_set_submenu (GTK_MENU_ITEM (item),
2080 - deskmenu->current_menu);
2085 - case DESKMENU_ELEMENT_SEPARATOR:
2086 - break; /* build it in the end function */
2088 - case DESKMENU_ELEMENT_ITEM:
2090 - if (deskmenu->current_item != NULL)
2092 - gint line_num, char_num;
2093 - g_markup_parse_context_get_position (context, &line_num,
2095 - g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2096 - "Error on line %d char %d: Element 'item' cannot be nested "
2097 - "inside of another item element", line_num, char_num);
2101 - deskmenu->current_item = g_slice_new0 (DeskmenuItem);
2104 - if (strcmp (*ncursor, "type") == 0)
2105 - deskmenu->current_item->type = GPOINTER_TO_INT
2106 - (g_hash_table_lookup (deskmenu->item_hash, *vcursor));
2108 - g_set_error (error, G_MARKUP_ERROR,
2109 - G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
2110 - "Unknown attribute: %s", *ncursor);
2116 - case DESKMENU_ELEMENT_NAME:
2119 - if ((strcmp (*ncursor, "mode") == 0)
2120 - && (strcmp (*vcursor, "exec") == 0))
2121 - deskmenu->current_item->name_exec = TRUE;
2124 - } /* no break here to let it fall through */
2125 - case DESKMENU_ELEMENT_ICON:
2126 - case DESKMENU_ELEMENT_COMMAND:
2127 - case DESKMENU_ELEMENT_WRAP:
2128 - if (deskmenu->current_item)
2129 - deskmenu->current_item->current_element = element_type;
2133 - g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
2134 - "Unknown element: %s", element_name);
2140 -text (GMarkupParseContext *context,
2141 - const gchar *text,
2143 - gpointer user_data,
2146 - Deskmenu *deskmenu = DESKMENU (user_data);
2147 - DeskmenuItem *item = deskmenu->current_item;
2149 - if (!(item && item->current_element))
2152 - switch (item->current_element)
2154 - case DESKMENU_ELEMENT_NAME:
2156 - item->name = g_string_new_len (text, text_len);
2158 - g_string_append_len (item->name, text, text_len);
2161 - case DESKMENU_ELEMENT_ICON:
2163 - item->icon = g_string_new_len (text, text_len);
2165 - g_string_append_len (item->icon, text, text_len);
2168 - case DESKMENU_ELEMENT_COMMAND:
2169 - if (!item->command)
2170 - item->command = g_string_new_len (text, text_len);
2172 - g_string_append_len (item->command, text, text_len);
2175 - case DESKMENU_ELEMENT_WRAP:
2177 - item->wrap = g_string_new_len (text, text_len);
2179 - g_string_append_len (item->wrap, text, text_len);
2189 -end_element (GMarkupParseContext *context,
2190 - const gchar *element_name,
2191 - gpointer user_data,
2195 - DeskmenuElementType element_type;
2196 - Deskmenu *deskmenu = DESKMENU (user_data);
2197 - GtkWidget *parent, *item;
2198 - element_type = GPOINTER_TO_INT (g_hash_table_lookup
2199 - (deskmenu->element_hash, element_name));
2201 - switch (element_type)
2203 - case DESKMENU_ELEMENT_MENU:
2205 - g_return_if_fail (deskmenu->current_item == NULL);
2207 - parent = g_object_get_data (G_OBJECT (deskmenu->current_menu),
2210 - deskmenu->current_menu = parent;
2214 - case DESKMENU_ELEMENT_SEPARATOR:
2215 - item = gtk_separator_menu_item_new ();
2216 - gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
2220 - case DESKMENU_ELEMENT_ITEM:
2222 - g_return_if_fail (deskmenu->current_item != NULL);
2224 - /* finally make the item ^_^ */
2225 - deskmenu_construct_item (deskmenu);
2227 - /* free data used to make it */
2228 - if (deskmenu->current_item->name)
2229 - g_string_free (deskmenu->current_item->name, TRUE);
2230 - if (deskmenu->current_item->icon)
2231 - g_string_free (deskmenu->current_item->icon, TRUE);
2232 - if (deskmenu->current_item->command)
2233 - g_string_free (deskmenu->current_item->command, TRUE);
2234 - if (deskmenu->current_item->wrap)
2235 - g_string_free (deskmenu->current_item->wrap, TRUE);
2236 - g_slice_free (DeskmenuItem, deskmenu->current_item);
2237 - deskmenu->current_item = NULL;
2245 -/* The list of what handler does what. */
2246 -static GMarkupParser parser = {
2257 -deskmenu_class_init (DeskmenuClass *deskmenu_class)
2259 - dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (deskmenu_class),
2260 - &dbus_glib_deskmenu_object_info);
2263 -/* Instance init */
2265 -deskmenu_init (Deskmenu *deskmenu)
2268 - deskmenu->show_hooks = g_slice_new0 (GHookList);
2270 - g_hook_list_init (deskmenu->show_hooks, sizeof (GHook));
2273 - deskmenu->menu = NULL;
2274 - deskmenu->current_menu = NULL;
2275 - deskmenu->current_item = NULL;
2277 - deskmenu->envp = NULL;
2279 - deskmenu->item_hash = g_hash_table_new (g_str_hash, g_str_equal);
2281 - g_hash_table_insert (deskmenu->item_hash, "launcher",
2282 - GINT_TO_POINTER (DESKMENU_ITEM_LAUNCHER));
2284 - g_hash_table_insert (deskmenu->item_hash, "windowlist",
2285 - GINT_TO_POINTER (DESKMENU_ITEM_WINDOWLIST));
2286 - g_hash_table_insert (deskmenu->item_hash, "viewportlist",
2287 - GINT_TO_POINTER (DESKMENU_ITEM_VIEWPORTLIST));
2289 - g_hash_table_insert (deskmenu->item_hash, "reload",
2290 - GINT_TO_POINTER (DESKMENU_ITEM_RELOAD));
2292 - deskmenu->element_hash = g_hash_table_new (g_str_hash, g_str_equal);
2294 - g_hash_table_insert (deskmenu->element_hash, "menu",
2295 - GINT_TO_POINTER (DESKMENU_ELEMENT_MENU));
2296 - g_hash_table_insert (deskmenu->element_hash, "separator",
2297 - GINT_TO_POINTER (DESKMENU_ELEMENT_SEPARATOR));
2298 - g_hash_table_insert (deskmenu->element_hash, "item",
2299 - GINT_TO_POINTER (DESKMENU_ELEMENT_ITEM));
2300 - g_hash_table_insert (deskmenu->element_hash, "name",
2301 - GINT_TO_POINTER (DESKMENU_ELEMENT_NAME));
2302 - g_hash_table_insert (deskmenu->element_hash, "icon",
2303 - GINT_TO_POINTER (DESKMENU_ELEMENT_ICON));
2304 - g_hash_table_insert (deskmenu->element_hash, "command",
2305 - GINT_TO_POINTER (DESKMENU_ELEMENT_COMMAND));
2306 - g_hash_table_insert (deskmenu->element_hash, "wrap",
2307 - GINT_TO_POINTER (DESKMENU_ELEMENT_WRAP));
2312 -deskmenu_parse_file (Deskmenu *deskmenu,
2313 - gchar *configpath)
2315 - GError *error = NULL;
2316 - gboolean success = FALSE;
2321 - configpath = g_build_path (G_DIR_SEPARATOR_S,
2322 - g_get_user_config_dir (),
2328 - GMarkupParseContext *context = g_markup_parse_context_new (&parser,
2329 - 0, deskmenu, NULL);
2331 - if (!g_file_get_contents (configpath, &text, &length, NULL))
2333 - const gchar* const *cursor = g_get_system_config_dirs ();
2334 - gchar *path = NULL;
2337 - g_free (configpath);
2339 - path = g_strdup (*cursor);
2340 - configpath = g_build_path (G_DIR_SEPARATOR_S,
2347 - if (g_file_get_contents (configpath, &text, &length, NULL))
2363 - g_printerr ("Couldn't find a menu file\n");
2367 - if (!g_markup_parse_context_parse (context, text, length, &error)
2368 - || !g_markup_parse_context_end_parse (context, &error))
2370 - g_printerr ("Parse of %s failed with message: %s \n",
2371 - configpath, error->message);
2372 - g_error_free (error);
2377 - g_free (configpath);
2378 - g_markup_parse_context_free (context);
2380 - gtk_widget_show_all (deskmenu->menu);
2383 -/* The show method */
2385 -deskmenu_show (Deskmenu *deskmenu,
2389 - g_hook_list_invoke (deskmenu->show_hooks, FALSE);
2391 - if (deskmenu->envp)
2392 - g_strfreev (deskmenu->envp);
2394 - deskmenu->envp = g_strdupv (env);
2396 - gtk_menu_popup (GTK_MENU (deskmenu->menu),
2397 - NULL, NULL, NULL, NULL,
2402 -/* The reload method */
2404 -deskmenu_reload (Deskmenu *deskmenu,
2415 - DBusGConnection *connection;
2416 - GError *error = NULL;
2417 - GObject *deskmenu;
2421 - gchar *filename = NULL;
2422 - GOptionContext *context;
2423 - GOptionEntry entries[] =
2425 - { "menu", 'm', 0, G_OPTION_ARG_FILENAME, &filename,
2426 - "Use FILE instead of the default menu file", "FILE" },
2427 - { NULL, 0, 0, 0, NULL, NULL, NULL }
2430 - context = g_option_context_new (NULL);
2431 - g_option_context_add_main_entries (context, entries, NULL);
2432 - g_option_context_add_group (context, gtk_get_option_group (TRUE));
2433 - if (!g_option_context_parse (context, &argc, &argv, &error))
2435 - g_printerr ("option parsing failed: %s", error->message);
2436 - g_error_free (error);
2439 - g_option_context_free (context);
2441 - /* Obtain a connection to the session bus */
2442 - connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
2443 - if (connection == NULL)
2445 - g_printerr ("Failed to open connection to bus: %s", error->message);
2446 - g_error_free (error);
2451 - wnck_set_client_type (WNCK_CLIENT_TYPE_PAGER);
2454 - gtk_init (&argc, &argv);
2456 - deskmenu = g_object_new (DESKMENU_TYPE, NULL);
2458 - deskmenu_parse_file (DESKMENU (deskmenu), filename);
2460 - dbus_g_connection_register_g_object (connection,
2461 - DESKMENU_PATH_DBUS,
2464 - if (!dbus_bus_request_name (dbus_g_connection_get_connection (connection),
2465 - DESKMENU_SERVICE_DBUS,
2466 - DBUS_NAME_FLAG_REPLACE_EXISTING,
2476 + * compiz-deskmenu is free software; you can redistribute it and/or modify
2477 + * it under the terms of the GNU General Public License as published by
2478 + * the Free Software Foundation; either version 2 of the License, or
2479 + * (at your option) any later version.
2481 + * compiz-deskmenu is distributed in the hope that it will be useful,
2482 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2483 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2484 + * GNU General Public License for more details.
2486 + * You should have received a copy of the GNU General Public License
2487 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
2489 + * Copyright 2008 Christopher Williams <christopherw@verizon.net>
2495 + TODO: Add a viewport # indicator for the window list for accesiblity reasons difficulty: hard
2496 + TODO: Add configuration for menu icon size difficulty: easy
2497 + TODO: Add toggle of tearables difficulty: easy
2498 + TODO: Add a sane icon dialog difficulty: medium-hard
2499 + TODO: Make the editor able to edit non-default files
2500 +For fun, might not implement:
2501 +TODO: Add ability to call up menus from the menu.xml file by name, if this is really, really needed or requested
2504 +#include <stdlib.h>
2505 +#include <string.h>
2506 +#include <gtk/gtk.h>
2508 +#define HAVE_WNCK 1
2511 +#include "deskmenu-wnck.h"
2514 +#include "deskmenu-menu.h"
2517 +G_DEFINE_TYPE(Deskmenu, deskmenu, G_TYPE_OBJECT) //this is calling deskmenu_class_init
2520 +deskmenu_error_quark (void)
2522 + static GQuark quark = 0;
2524 + quark = g_quark_from_static_string ("deskmenu_error");
2529 +quit (GtkWidget *widget,
2535 +//stolen from openbox, possibly move this outside in order to make it a function to parse launchers and icon location
2536 +gchar *parse_expand_tilde(const gchar *f)
2544 +regex = g_regex_new("(?:^|(?<=[ \\t]))~(?:(?=[/ \\t])|$)",
2545 + G_REGEX_MULTILINE | G_REGEX_RAW, 0, NULL);
2546 +ret = g_regex_replace_literal(regex, f, -1, 0, g_get_home_dir(), 0, NULL);
2547 +g_regex_unref(regex);
2553 +//This is how menu command is launched
2555 +launcher_activated (GtkWidget *widget,
2558 + GError *error = NULL;
2559 + Deskmenu *deskmenu;
2561 + deskmenu = g_object_get_data (G_OBJECT (widget), "deskmenu");
2562 + if (!gdk_spawn_command_line_on_screen (gdk_screen_get_default (), parse_expand_tilde(command), &error))
2564 + GtkWidget *message = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
2565 + GTK_BUTTONS_CLOSE, "%s", error->message);
2566 + gtk_dialog_run (GTK_DIALOG (message));
2567 + gtk_widget_destroy (message);
2572 +//place & in front of stdout for standard stdout, how a command is launched as an exec
2574 +launcher_name_exec_update (GtkWidget *label)
2576 + gchar *exec, *stdout;
2577 + exec = g_object_get_data (G_OBJECT (label), "exec");
2578 + if (g_spawn_command_line_sync (parse_expand_tilde(exec), &stdout, NULL, NULL, NULL))
2579 + gtk_label_set_text (GTK_LABEL (label), g_strstrip(stdout));
2581 + gtk_label_set_text (GTK_LABEL (label), "execution error");
2586 +deskmenu_construct_item (Deskmenu *deskmenu)
2588 + DeskmenuItem *item = deskmenu->current_item;
2589 + GtkWidget *menu_item;
2590 + gchar *name, *icon, *command, *vpicon;
2592 +//constructs the items in menu
2593 + switch (item->type)
2595 + case DESKMENU_ITEM_LAUNCHER:
2596 + if (item->name_exec)
2601 + name = g_strstrip (item->name->str);
2603 + menu_item = gtk_image_menu_item_new ();
2604 + label = gtk_label_new_with_mnemonic (NULL);
2605 + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2607 + g_object_set_data (G_OBJECT (label), "exec", g_strdup (name));
2608 + gtk_container_add (GTK_CONTAINER (menu_item), label);
2609 + hook = g_hook_alloc (deskmenu->show_hooks);
2611 + hook->data = (gpointer) label;
2612 + hook->func = (GHookFunc *) launcher_name_exec_update;
2613 + g_hook_append (deskmenu->show_hooks, hook);
2618 + name = g_strstrip (item->name->str);
2622 + menu_item = gtk_image_menu_item_new_with_mnemonic (name);
2627 + icon = g_strstrip (item->icon->str);
2628 + if (item->icon_file) {
2629 + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
2630 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM
2631 + (menu_item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (parse_expand_tilde(icon), w, h, NULL)));
2634 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
2635 + gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
2639 + if (item->command)
2642 + command = g_strstrip (item->command->str);
2643 + g_object_set_data (G_OBJECT (menu_item), "deskmenu", deskmenu);
2644 + g_signal_connect (G_OBJECT (menu_item), "activate",
2645 + G_CALLBACK (launcher_activated), g_strdup (command));
2648 + gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
2652 + case DESKMENU_ITEM_WINDOWLIST:
2653 + menu_item = gtk_image_menu_item_new_with_mnemonic ("_Windows");
2655 + DeskmenuWindowlist *windowlist = deskmenu_windowlist_new ();
2656 + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
2657 + windowlist->menu);
2658 + gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
2662 + windowlist->images = TRUE;
2663 + icon = g_strstrip (item->icon->str);
2664 + if (item->icon_file) {
2665 + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
2666 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM
2667 + (menu_item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (parse_expand_tilde(icon), w, h, NULL)));
2670 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
2671 + gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
2676 + case DESKMENU_ITEM_VIEWPORTLIST:
2677 + menu_item = gtk_image_menu_item_new_with_mnemonic ("_Viewports");
2679 + DeskmenuVplist *vplist = deskmenu_vplist_new ();
2681 + && strcmp (g_strstrip (item->wrap->str), "true") == 0)
2682 + vplist->wrap = TRUE;
2684 + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
2686 + gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
2690 + vplist->images = TRUE;
2691 + icon = g_strstrip (item->icon->str);
2692 + if (item->icon_file) {
2693 + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
2694 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM
2695 + (menu_item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (parse_expand_tilde(icon), w, h, NULL)));
2698 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
2699 + gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
2704 + vpicon = g_strstrip (parse_expand_tilde(item->vpicon->str));
2705 + if (item->vpicon_file) {
2706 + vplist->file = TRUE;
2708 + vplist->icon = vpicon;
2718 +/* The handler functions. */
2721 +start_element (GMarkupParseContext *context,
2722 + const gchar *element_name,
2723 + const gchar **attr_names,
2724 + const gchar **attr_values,
2725 + gpointer user_data,
2728 + Deskmenu *deskmenu = DESKMENU (user_data);
2729 + DeskmenuElementType element_type;
2730 + const gchar **ncursor = attr_names, **vcursor = attr_values;
2731 + GtkWidget *item, *menu;
2733 + element_type = GPOINTER_TO_INT (g_hash_table_lookup
2734 + (deskmenu->element_hash, element_name));
2736 + //TODO: maybe this could be edited to see the new compiz-deskmenu element, if this is needed in order to make pipes
2737 + if ((deskmenu->menu && !deskmenu->current_menu)
2738 + || (!deskmenu->menu && element_type != DESKMENU_ELEMENT_MENU))
2740 + gint line_num, char_num;
2741 + g_markup_parse_context_get_position (context, &line_num, &char_num);
2742 + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2743 + "Error on line %d char %d: Element '%s' declared outside of "
2744 + "toplevel menu element", line_num, char_num, element_name);
2748 + switch (element_type)
2750 + case DESKMENU_ELEMENT_MENU:
2752 + if (deskmenu->current_item != NULL)
2754 + gint line_num, char_num;
2755 + g_markup_parse_context_get_position (context, &line_num,
2757 + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2758 + "Error on line %d char %d: Element 'menu' cannot be nested "
2759 + "inside of an item element", line_num, char_num);
2762 + if (!deskmenu->menu)
2764 + deskmenu->menu = gtk_menu_new ();
2765 + g_object_set_data (G_OBJECT (deskmenu->menu), "parent menu",
2767 + deskmenu->current_menu = deskmenu->menu;
2771 + gchar *name = NULL;
2772 + gchar *icon = NULL;
2773 + gboolean name_exec = FALSE;
2774 + gboolean icon_file = FALSE;
2778 + if (strcmp (*ncursor, "name") == 0)
2779 + name = g_strdup (*vcursor);
2780 + else if (strcmp (*ncursor, "icon") == 0)
2781 + icon = g_strdup (*vcursor);
2782 + else if ((strcmp (*ncursor, "mode") == 0)
2783 + && (strcmp (*vcursor, "exec") == 0))
2785 + else if ((strcmp (*ncursor, "mode1") == 0)
2786 + && (strcmp (*vcursor, "file") == 0))
2789 + g_set_error (error, G_MARKUP_ERROR,
2790 + G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
2791 + "Unknown attribute: %s", *ncursor);
2800 + item = gtk_image_menu_item_new ();
2801 + label = gtk_label_new_with_mnemonic (NULL);
2802 + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2804 + g_object_set_data (G_OBJECT (label), "exec", g_strdup (name));
2805 + gtk_container_add (GTK_CONTAINER (item), label);
2806 + hook = g_hook_alloc (deskmenu->show_hooks);
2808 + hook->data = (gpointer) label;
2809 + hook->func = (GHookFunc *) launcher_name_exec_update;
2810 + g_hook_append (deskmenu->show_hooks, hook);
2815 + item = gtk_image_menu_item_new_with_mnemonic (name); //allow menus to have icons
2818 + item = gtk_image_menu_item_new_with_mnemonic ("");
2819 + gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
2825 + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
2826 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM
2827 + (item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (parse_expand_tilde(icon), w, h, NULL)));
2830 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
2831 + gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
2834 + menu = gtk_menu_new ();
2835 + g_object_set_data (G_OBJECT (menu), "parent menu",
2836 + deskmenu->current_menu);
2837 + deskmenu->current_menu = menu;
2838 + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item),
2839 + deskmenu->current_menu);
2845 + case DESKMENU_ELEMENT_SEPARATOR:
2846 + break; /* build it in the end function */
2848 + case DESKMENU_ELEMENT_ITEM:
2850 + if (deskmenu->current_item != NULL)
2852 + gint line_num, char_num;
2853 + g_markup_parse_context_get_position (context, &line_num,
2855 + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2856 + "Error on line %d char %d: Element 'item' cannot be nested "
2857 + "inside of another item element", line_num, char_num);
2861 + deskmenu->current_item = g_slice_new0 (DeskmenuItem);
2864 + if (strcmp (*ncursor, "type") == 0)
2865 + deskmenu->current_item->type = GPOINTER_TO_INT
2866 + (g_hash_table_lookup (deskmenu->item_hash, *vcursor));
2868 + g_set_error (error, G_MARKUP_ERROR,
2869 + G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
2870 + "Unknown attribute: %s", *ncursor);
2876 + case DESKMENU_ELEMENT_NAME:
2879 + if ((strcmp (*ncursor, "mode") == 0)
2880 + && (strcmp (*vcursor, "exec") == 0))
2881 + deskmenu->current_item->name_exec = TRUE;
2884 + } /* no break here to let it fall through */
2885 + case DESKMENU_ELEMENT_ICON:
2888 + if ((strcmp (*ncursor, "mode1") == 0)
2889 + && (strcmp (*vcursor, "file") == 0))
2890 + deskmenu->current_item->icon_file = TRUE;
2893 + } /* no break here to let it fall through */
2894 + case DESKMENU_ELEMENT_VPICON:
2897 + if ((strcmp (*ncursor, "mode1") == 0)
2898 + && (strcmp (*vcursor, "file") == 0))
2899 + deskmenu->current_item->vpicon_file = TRUE;
2902 + } /* no break here to let it fall through */
2903 + case DESKMENU_ELEMENT_COMMAND:
2904 + case DESKMENU_ELEMENT_WRAP:
2905 + if (deskmenu->current_item)
2906 + deskmenu->current_item->current_element = element_type;
2909 + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
2910 + "Unknown element: %s", element_name);
2914 +//dealing with empty attributes
2916 +text (GMarkupParseContext *context,
2917 + const gchar *text,
2919 + gpointer user_data,
2922 + Deskmenu *deskmenu = DESKMENU (user_data);
2923 + DeskmenuItem *item = deskmenu->current_item;
2925 + if (!(item && item->current_element))
2928 + switch (item->current_element)
2930 + case DESKMENU_ELEMENT_NAME:
2932 + item->name = g_string_new_len (text, text_len);
2934 + g_string_append_len (item->name, text, text_len);
2937 + case DESKMENU_ELEMENT_ICON:
2939 + item->icon = g_string_new_len (text, text_len);
2941 + g_string_append_len (item->icon, text, text_len);
2944 + case DESKMENU_ELEMENT_VPICON:
2945 + if (!item->vpicon)
2946 + item->vpicon = g_string_new_len (text, text_len);
2948 + g_string_append_len (item->vpicon, text, text_len);
2951 + case DESKMENU_ELEMENT_COMMAND:
2952 + if (!item->command)
2953 + item->command = g_string_new_len (text, text_len);
2955 + g_string_append_len (item->command, text, text_len);
2958 + case DESKMENU_ELEMENT_WRAP:
2960 + item->wrap = g_string_new_len (text, text_len);
2962 + g_string_append_len (item->wrap, text, text_len);
2972 +end_element (GMarkupParseContext *context,
2973 + const gchar *element_name,
2974 + gpointer user_data,
2978 + DeskmenuElementType element_type;
2979 + Deskmenu *deskmenu = DESKMENU (user_data);
2980 + GtkWidget *parent, *item;
2981 + element_type = GPOINTER_TO_INT (g_hash_table_lookup
2982 + (deskmenu->element_hash, element_name));
2984 + switch (element_type)
2986 + case DESKMENU_ELEMENT_MENU:
2988 + g_return_if_fail (deskmenu->current_item == NULL);
2990 + parent = g_object_get_data (G_OBJECT (deskmenu->current_menu),
2993 + deskmenu->current_menu = parent;
2997 + case DESKMENU_ELEMENT_SEPARATOR:
2998 + item = gtk_separator_menu_item_new ();
2999 + gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
3003 + case DESKMENU_ELEMENT_ITEM:
3005 + g_return_if_fail (deskmenu->current_item != NULL);
3007 + /* finally make the item ^_^ */
3008 + deskmenu_construct_item (deskmenu);
3010 + /* free data used to make it */
3011 + if (deskmenu->current_item->name)
3012 + g_string_free (deskmenu->current_item->name, TRUE);
3013 + if (deskmenu->current_item->icon)
3014 + g_string_free (deskmenu->current_item->icon, TRUE);
3015 + if (deskmenu->current_item->command)
3016 + g_string_free (deskmenu->current_item->command, TRUE);
3017 + if (deskmenu->current_item->wrap)
3018 + g_string_free (deskmenu->current_item->wrap, TRUE);
3019 + if (deskmenu->current_item->vpicon)
3020 + g_string_free (deskmenu->current_item->vpicon, TRUE);
3021 + g_slice_free (DeskmenuItem, deskmenu->current_item);
3022 + deskmenu->current_item = NULL;
3029 +/* The list of what handler does what. */
3030 +//this parses menus
3031 +static GMarkupParser parser = {
3042 +deskmenu_class_init (DeskmenuClass *deskmenu_class)
3044 + //G_TYPE_FROM_CLASS (deskmenu_class); //I have NO idea what's going on here, but apparently, just initializing this function makes it work
3047 +/* Instance init, matches up words to types, note how there's no handler for pipe since it's replaced in its own chunk */
3049 +deskmenu_init (Deskmenu *deskmenu)
3052 + deskmenu->show_hooks = g_slice_new0 (GHookList);
3054 + g_hook_list_init (deskmenu->show_hooks, sizeof (GHook));
3057 + deskmenu->menu = NULL;
3058 + deskmenu->current_menu = NULL;
3059 + deskmenu->current_item = NULL;
3061 + deskmenu->item_hash = g_hash_table_new (g_str_hash, g_str_equal);
3063 + g_hash_table_insert (deskmenu->item_hash, "launcher",
3064 + GINT_TO_POINTER (DESKMENU_ITEM_LAUNCHER));
3066 + g_hash_table_insert (deskmenu->item_hash, "windowlist",
3067 + GINT_TO_POINTER (DESKMENU_ITEM_WINDOWLIST));
3068 + g_hash_table_insert (deskmenu->item_hash, "viewportlist",
3069 + GINT_TO_POINTER (DESKMENU_ITEM_VIEWPORTLIST));
3072 + deskmenu->element_hash = g_hash_table_new (g_str_hash, g_str_equal);
3074 + g_hash_table_insert (deskmenu->element_hash, "menu",
3075 + GINT_TO_POINTER (DESKMENU_ELEMENT_MENU));
3076 + g_hash_table_insert (deskmenu->element_hash, "separator",
3077 + GINT_TO_POINTER (DESKMENU_ELEMENT_SEPARATOR));
3078 + g_hash_table_insert (deskmenu->element_hash, "item",
3079 + GINT_TO_POINTER (DESKMENU_ELEMENT_ITEM));
3080 + g_hash_table_insert (deskmenu->element_hash, "name",
3081 + GINT_TO_POINTER (DESKMENU_ELEMENT_NAME));
3082 + g_hash_table_insert (deskmenu->element_hash, "icon",
3083 + GINT_TO_POINTER (DESKMENU_ELEMENT_ICON));
3084 + g_hash_table_insert (deskmenu->element_hash, "vpicon",
3085 + GINT_TO_POINTER (DESKMENU_ELEMENT_VPICON));
3086 + g_hash_table_insert (deskmenu->element_hash, "command",
3087 + GINT_TO_POINTER (DESKMENU_ELEMENT_COMMAND));
3088 + g_hash_table_insert (deskmenu->element_hash, "wrap",
3089 + GINT_TO_POINTER (DESKMENU_ELEMENT_WRAP));
3094 +deskmenu_parse_file (Deskmenu *deskmenu,
3095 + gchar *configpath)
3097 + GError *error = NULL;
3098 + gboolean success = FALSE;
3099 + gchar *text, *exec, *stdout;
3101 + GRegex *regex, *command;
3105 + configpath = g_build_path (G_DIR_SEPARATOR_S,
3106 + g_get_user_config_dir (),
3112 + GMarkupParseContext *context = g_markup_parse_context_new (&parser,
3113 + 0, deskmenu, NULL);
3115 + if (!g_file_get_contents (configpath, &text, &length, NULL))
3117 + const gchar* const *cursor = g_get_system_config_dirs ();
3118 + gchar *path = NULL;
3121 + g_free (configpath);
3123 + path = g_strdup (*cursor);
3124 + configpath = g_build_path (G_DIR_SEPARATOR_S,
3131 + if (g_file_get_contents (configpath, &text, &length, NULL))
3147 + g_printerr ("Couldn't find a menu file\n");
3152 + regex = g_regex_new("(<pipe command=\".*\"/>)", G_REGEX_MULTILINE | G_REGEX_RAW, 0, NULL);
3153 + command = g_regex_new("<pipe command=\"|\"/>", G_REGEX_MULTILINE | G_REGEX_RAW, 0, NULL);
3154 + gchar **menu_chunk = g_regex_split (regex, text, 0); //this splits the menu into parsable chunks, needed for pipe item capabilities
3156 + g_free(text); //we no longer need the loaded file
3158 + //this loop will replace the pipeitem chunk with its output, other chunks are let through as is
3159 + while (menu_chunk[i])
3161 + if (g_regex_match (regex,menu_chunk[i],0,0))
3163 + exec = parse_expand_tilde(g_strstrip(g_regex_replace_literal(command, menu_chunk[i], -1, 0, "", 0, NULL)));
3164 + g_spawn_command_line_sync (exec, &stdout, NULL, NULL, NULL);
3165 + menu_chunk[i] = stdout;
3169 + g_regex_unref(regex); //free the pipeitem chunk checker
3170 + g_regex_unref(command); //free the pipe command extractor
3173 + while (menu_chunk[i])
3175 + g_markup_parse_context_parse (context, menu_chunk[i], strlen(menu_chunk[i]), &error);
3176 + //fix error reporting here, otherwise, it works fine
3180 + g_strfreev(menu_chunk); //free the menu chunks and their container
3181 + g_free (configpath); //free the file path
3182 + g_markup_parse_context_free (context); //free the parser
3184 + gtk_widget_show_all (deskmenu->menu);
3187 +/* The show method */
3189 +deskmenu_show (Deskmenu *deskmenu,
3192 + g_hook_list_invoke (deskmenu->show_hooks, FALSE);
3194 +//sloppy fix until dbus is removed
3195 + g_signal_connect_swapped (GTK_MENU (deskmenu->menu), "deactivate",
3196 + G_CALLBACK (quit), NULL);
3198 + gtk_menu_popup (GTK_MENU (deskmenu->menu),
3199 + NULL, NULL, NULL, NULL,
3208 + GError *error = NULL;
3209 + GObject *deskmenu;
3213 + gchar *filename = NULL;
3214 + GOptionContext *context;
3215 + GOptionEntry entries[] =
3217 + { "menu", 'm', 0, G_OPTION_ARG_FILENAME, &filename,
3218 + "Use FILE instead of the default menu file", "FILE" },
3219 + { NULL, 0, 0, 0, NULL, NULL, NULL }
3222 + context = g_option_context_new (NULL);
3223 + g_option_context_add_main_entries (context, entries, NULL);
3224 + g_option_context_add_group (context, gtk_get_option_group (TRUE));
3225 + if (!g_option_context_parse (context, &argc, &argv, &error))
3227 + g_printerr ("option parsing failed: %s", error->message);
3228 + g_error_free (error);
3231 + g_option_context_free (context);
3234 + wnck_set_client_type (WNCK_CLIENT_TYPE_PAGER);
3237 + gtk_init (&argc, &argv);
3239 + deskmenu = g_object_new (DESKMENU_TYPE, NULL);
3241 + deskmenu_parse_file (DESKMENU (deskmenu), filename);
3243 + deskmenu_show (DESKMENU (deskmenu), &error);
3249 diff -aur compiz-deskmenu/deskmenu-menu.h compiz-deskmenu3/deskmenu-menu.h
3250 --- compiz-deskmenu/deskmenu-menu.h 2008-03-14 16:25:23.000000000 -0700
3251 +++ compiz-deskmenu3/deskmenu-menu.h 2010-11-16 15:39:49.000000000 -0800
3253 * Copyright 2008 Christopher Williams <christopherw@verizon.net>
3256 -#include "deskmenu-common.h"
3258 typedef struct Deskmenu Deskmenu;
3259 typedef struct DeskmenuClass DeskmenuClass;
3260 typedef struct DeskmenuItem DeskmenuItem;
3262 DESKMENU_ITEM_NONE = 0,
3263 DESKMENU_ITEM_LAUNCHER,
3264 DESKMENU_ITEM_WINDOWLIST,
3265 - DESKMENU_ITEM_VIEWPORTLIST,
3266 - DESKMENU_ITEM_RELOAD
3267 + DESKMENU_ITEM_VIEWPORTLIST
3272 DESKMENU_ELEMENT_NAME,
3273 DESKMENU_ELEMENT_ICON,
3274 DESKMENU_ELEMENT_COMMAND,
3275 - DESKMENU_ELEMENT_WRAP
3276 + DESKMENU_ELEMENT_WRAP,
3277 + DESKMENU_ELEMENT_VPICON
3278 } DeskmenuElementType;
3282 DeskmenuElementType current_element;
3285 + gboolean icon_file;
3286 + gboolean vpicon_file;
3298 GHashTable *item_hash;
3299 GHashTable *element_hash;
3300 GHookList *show_hooks;
3304 struct DeskmenuClass
3308 #define DESKMENU_TYPE (deskmenu_get_type ())
3309 -#define DESKMENU(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), DESKMENU_TYPE, Deskmenu))
3310 -#define DESKMENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DESKMENU_TYPE, DeskmenuClass))
3311 +#define DESKMENU(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), DESKMENU_TYPE, Deskmenu)) //looks to see if it isn't a deskmenu already, if it isn't, make it one
3312 +#define DESKMENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DESKMENU_TYPE, DeskmenuClass)) //looks to see if class cast, if it isn't, cast it
3313 #define IS_DESKMENU(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), DESKMENU_TYPE))
3314 #define IS_DESKMENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DESKMENU_TYPE))
3315 #define DESKMENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DESKMENU_TYPE, DeskMenu))
3318 GQuark deskmenu_error_quark (void);
3319 #define DESKMENU_ERROR deskmenu_error_quark ()
3322 -gboolean deskmenu_show (Deskmenu *deskmenu, gchar **env, GError **error);
3323 -gboolean deskmenu_reload (Deskmenu *deskmenu, GError **error);
3326 diff -aur compiz-deskmenu/deskmenu-wnck.c compiz-deskmenu3/deskmenu-wnck.c
3327 --- compiz-deskmenu/deskmenu-wnck.c 2008-03-14 16:25:23.000000000 -0700
3328 +++ compiz-deskmenu3/deskmenu-wnck.c 2010-11-15 18:46:24.000000000 -0800
3329 @@ -113,18 +113,28 @@
3334 + //wnck_window_get_workspace (dmwin->window)
3335 + //TODO: get this to calculate right
3337 + column = wnck_workspace_get_viewport_x (wnck_window_get_workspace (dmwin->window));
3338 + width = wnck_workspace_get_width (wnck_screen_get_workspace (wnck_screen_get_default (), 0))/wnck_screen_get_width (wnck_screen_get_default ());
3339 + row = wnck_workspace_get_viewport_y (wnck_window_get_workspace (dmwin->window));
3340 + vpidNumber = column + ((row) * width);
3341 + vpid = g_strdup_printf ("%d %d %d %d :",vpidNumber,width,column,row);
3343 + decorated_name = g_strconcat ("[",vpid, "] ", ante, mnemonic, name->str, post, NULL);
3345 decorated_name = g_strconcat (ante, mnemonic, name->str, post, NULL);
3347 unescaped = g_strconcat (ante, wnck_window_get_name (dmwin->window),
3350 gtk_label_set_text_with_mnemonic (GTK_LABEL (dmwin->label), decorated_name);
3352 gtk_widget_set_size_request (dmwin->label,
3353 wnck_selector_get_width (dmwin->windowlist->menu, unescaped), -1);
3355 g_string_free (name, TRUE);
3357 g_free (decorated_name);
3360 @@ -171,19 +181,18 @@
3363 gboolean free_pixbuf;
3365 - pixbuf = wnck_window_get_mini_icon (window);
3366 - free_pixbuf = FALSE;
3367 - if (wnck_window_is_minimized (window))
3369 - pixbuf = wnck_selector_dimm_icon (pixbuf);
3370 - free_pixbuf = TRUE;
3373 - gtk_image_set_from_pixbuf (GTK_IMAGE (dmwin->image), pixbuf);
3376 - g_object_unref (pixbuf);
3377 + pixbuf = wnck_window_get_mini_icon (window);
3378 + free_pixbuf = FALSE;
3379 + if (wnck_window_is_minimized (window))
3381 + pixbuf = wnck_selector_dimm_icon (pixbuf);
3382 + free_pixbuf = TRUE;
3385 + gtk_image_set_from_pixbuf (GTK_IMAGE (dmwin->image), pixbuf);
3388 + g_object_unref (pixbuf);
3392 @@ -257,10 +266,11 @@
3393 gtk_label_set_ellipsize (GTK_LABEL (dmwin->label), PANGO_ELLIPSIZE_END);
3395 dmwin->image = gtk_image_new ();
3397 + if(windowlist->images) {
3398 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (dmwin->item),
3403 g_signal_connect (G_OBJECT (dmwin->item), "activate",
3404 G_CALLBACK (activate_window), window);
3409 item = gtk_image_menu_item_new_with_mnemonic (name);
3410 - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
3411 - gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU));
3412 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
3413 + gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU));
3414 g_object_set_data (G_OBJECT (item), "direction",
3415 GINT_TO_POINTER (direction));
3416 g_signal_connect (G_OBJECT (item), "activate",
3417 @@ -520,6 +530,17 @@
3418 gtk_widget_hide (vplist->go_up);
3419 gtk_widget_hide (vplist->go_down);
3421 + if(!vplist->images) //this rips off those arrows if you don't want images AT ALL
3423 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (vplist->go_left),
3424 + gtk_image_new_from_stock ("", GTK_ICON_SIZE_MENU));
3425 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (vplist->go_right),
3426 + gtk_image_new_from_stock ("", GTK_ICON_SIZE_MENU));
3427 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (vplist->go_up),
3428 + gtk_image_new_from_stock ("", GTK_ICON_SIZE_MENU));
3429 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (vplist->go_up),
3430 + gtk_image_new_from_stock ("", GTK_ICON_SIZE_MENU));
3432 gtk_widget_set_no_show_all (vplist->go_left,
3433 !deskmenu_vplist_can_move (vplist, WNCK_MOTION_LEFT));
3434 gtk_widget_set_no_show_all (vplist->go_right,
3435 @@ -531,15 +552,34 @@
3440 + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
3442 if (new_count > vplist->old_count)
3446 +//TODO: edit this section to add thumnbnails for ports, possibly just set the thumbnails to be viewport wallpapers?
3447 for (i = vplist->old_count; i < new_count; i++)
3449 text = g_strdup_printf ("Viewport _%i", i + 1);
3450 - item = gtk_menu_item_new_with_mnemonic (text);
3451 + item = gtk_image_menu_item_new_with_mnemonic (text);
3452 + if (vplist->images)
3453 + { //this'll set viewport thumbnail later if I can figure out how
3454 + if (vplist->icon){
3455 + if (vplist->file) {
3456 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM
3457 + (item), gtk_image_new_from_pixbuf (gdk_pixbuf_new_from_file_at_size (vplist->icon, w, h, NULL)));
3460 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
3461 + gtk_image_new_from_icon_name (vplist->icon, GTK_ICON_SIZE_MENU));
3465 + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
3466 + gtk_image_new_from_icon_name ("user-desktop", GTK_ICON_SIZE_MENU));
3469 g_object_set_data (G_OBJECT (item), "viewport",
3470 GUINT_TO_POINTER (i + 1));
3471 g_signal_connect (G_OBJECT (item), "activate",
3477 diff -aur compiz-deskmenu/deskmenu-wnck.h compiz-deskmenu3/deskmenu-wnck.h
3478 --- compiz-deskmenu/deskmenu-wnck.h 2008-03-14 16:25:23.000000000 -0700
3479 +++ compiz-deskmenu3/deskmenu-wnck.h 2010-11-15 17:34:36.000000000 -0800
3482 GtkWidget *empty_item;
3484 + gboolean images; //toggles use of icons
3485 } DeskmenuWindowlist;
3487 typedef struct DeskmenuWindow
3490 GPtrArray *goto_items;
3492 + gboolean images; //toggles use of icons
3493 + gboolean file; // whether the icon of choice is from theme or not
3494 /* store some calculations */
3495 guint hsize; /* 1-indexed horizontal viewport count */
3498 guint workspace_height;
3499 guint old_count; /* store old hsize * vsize */
3500 guint old_vpid; /* store old viewport number */
3501 + gchar *icon; /* stores viewport icon of choice */
3504 DeskmenuWindowlist* deskmenu_windowlist_new (void);