summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryetist <[email protected]>2018-04-25 13:38:33 +0800
committeryetist <[email protected]>2018-05-31 09:42:18 +0800
commitaf199835310b06f403ea130543d6c988ea955f29 (patch)
treec24eea5ca140f3aaa2f29cfbcf7d2bc28a15d8d2
parent80873ff2ec320d0a4feffdec97e86d626e2cf7db (diff)
downloadmozo-af199835310b06f403ea130543d6c988ea955f29.tar.bz2
mozo-af199835310b06f403ea130543d6c988ea955f29.tar.xz
Support new mate-menus api
- Requires mate-menus 1.21.0 - Use Gobject-introspection - Migrate to python3
-rw-r--r--Mozo/MainWindow.py130
-rw-r--r--Mozo/MenuEditor.py199
-rw-r--r--Mozo/util.py78
-rw-r--r--acinclude.m48
-rw-r--r--configure.ac4
-rw-r--r--mozo.in2
6 files changed, 247 insertions, 174 deletions
diff --git a/Mozo/MainWindow.py b/Mozo/MainWindow.py
index 75533fa..849de09 100644
--- a/Mozo/MainWindow.py
+++ b/Mozo/MainWindow.py
@@ -16,12 +16,13 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-import matemenu
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
+gi.require_version('MateMenu', '2.0')
from gi.repository import GLib, Gio
from gi.repository import Gtk, Gdk, GdkPixbuf
+from gi.repository import MateMenu
import cgi
import os
import gettext
@@ -40,7 +41,6 @@ from Mozo.MenuEditor import MenuEditor
from Mozo import util
class MainWindow:
- timer = None
#hack to make editing menu properties work
allow_update = True
#drag-and-drop stuff
@@ -77,40 +77,38 @@ class MainWindow:
keyval, modifier = Gtk.accelerator_parse('F1')
accelgroup.connect(keyval, modifier, Gtk.AccelFlags.VISIBLE, self.on_help_button_clicked)
self.tree.get_object('mainwindow').add_accel_group(accelgroup)
+ self.main_window = self.tree.get_object('mainwindow')
def run(self):
self.loadMenus()
- self.editor.applications.tree.add_monitor(self.menuChanged, None)
- self.editor.settings.tree.add_monitor(self.menuChanged, None)
+ self.editor.applications.tree.connect("changed", self.menuChanged)
+ self.editor.settings.tree.connect("changed", self.menuChanged)
self.tree.get_object('mainwindow').show_all()
Gtk.main()
def menuChanged(self, *a):
- if self.timer:
- GLib.Source.remove(self.timer)
- self.timer = None
- self.timer = GLib.timeout_add(3, self.loadUpdates)
+ self.loadUpdates()
def loadUpdates(self):
if not self.allow_update:
- self.timer = None
return False
menu_tree = self.tree.get_object('menu_tree')
item_tree = self.tree.get_object('item_tree')
items, iter = item_tree.get_selection().get_selected()
update_items = False
- item_id, separator_path = None, None
+ update_type = None
+ item_id = None
if iter:
update_items = True
- if items[iter][3].get_type() == matemenu.TYPE_DIRECTORY:
+ if isinstance(items[iter][3], MateMenu.TreeDirectory):
item_id = os.path.split(items[iter][3].get_desktop_file_path())[1]
- update_items = True
- elif items[iter][3].get_type() == matemenu.TYPE_ENTRY:
+ update_type = MateMenu.TreeItemType.DIRECTORY
+ elif isinstance(items[iter][3], MateMenu.TreeEntry):
item_id = items[iter][3].get_desktop_file_id()
- update_items = True
- elif items[iter][3].get_type() == matemenu.TYPE_SEPARATOR:
- item_id = items.get_path(iter).to_string()
- update_items = True
+ update_type = MateMenu.TreeItemType.ENTRY
+ elif isinstance(items[iter][3], MateMenu.TreeSeparator):
+ item_id = items.get_path(iter)
+ update_type = MateMenu.TreeItemType.SEPARATOR
menus, iter = menu_tree.get_selection().get_selected()
update_menus = False
menu_id = None
@@ -132,12 +130,13 @@ class MainWindow:
i = 0
for item in item_tree.get_model():
found = False
- if item[3].get_type() == matemenu.TYPE_ENTRY and item[3].get_desktop_file_id() == item_id:
- found = True
- if item[3].get_type() == matemenu.TYPE_DIRECTORY and item[3].get_desktop_file_path():
- if os.path.split(item[3].get_desktop_file_path())[1] == item_id:
+ if update_type != MateMenu.TreeItemType.SEPARATOR:
+ if isinstance (item[3], MateMenu.TreeEntry) and item[3].get_desktop_file_id() == item_id:
found = True
- if item[3].get_type() == matemenu.TYPE_SEPARATOR:
+ if isinstance (item[3], MateMenu.TreeDirectory) and item[3].get_desktop_file_path() and update_type == MateMenu.TreeItemType.DIRECTORY:
+ if os.path.split(item[3].get_desktop_file_path())[1] == item_id:
+ found = True
+ if isinstance(item[3], MateMenu.TreeSeparator):
if not isinstance(item_id, tuple):
#we may not skip the increment via "continue"
i += 1
@@ -155,7 +154,6 @@ class MainWindow:
self.on_item_tree_cursor_changed(item_tree)
break
i += 1
- self.timer = None
return False
def findMenu(self, menus, path, iter, menu_id):
@@ -179,15 +177,16 @@ class MainWindow:
column.set_spacing(4)
cell = Gtk.CellRendererPixbuf()
column.pack_start(cell, False)
- column.set_attributes(cell, pixbuf=0)
+ column.add_attribute(cell, 'pixbuf', 0)
cell = Gtk.CellRendererText()
cell.set_fixed_size(-1, 25)
column.pack_start(cell, True)
- column.set_attributes(cell, markup=1)
+ column.add_attribute(cell, 'markup', 1)
column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
menus.append_column(column)
menus.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, self.dnd_menus, Gdk.DragAction.COPY)
menus.enable_model_drag_dest(self.dnd_both, Gdk.DragAction.PRIVATE)
+ menus.get_selection().set_mode(Gtk.SelectionMode.BROWSE)
def setupItemTree(self):
items = self.tree.get_object('item_tree')
@@ -195,7 +194,7 @@ class MainWindow:
cell = Gtk.CellRendererToggle()
cell.connect('toggled', self.on_item_tree_show_toggled)
column.pack_start(cell, True)
- column.set_attributes(cell, active=0)
+ column.add_attribute(cell, 'active', 0)
#hide toggle for separators
column.set_cell_data_func(cell, self._cell_data_toggle_func)
items.append_column(column)
@@ -203,11 +202,11 @@ class MainWindow:
column.set_spacing(4)
cell = Gtk.CellRendererPixbuf()
column.pack_start(cell, False)
- column.set_attributes(cell, pixbuf=1)
+ column.add_attribute(cell, 'pixbuf', 1)
cell = Gtk.CellRendererText()
cell.set_fixed_size(-1, 25)
column.pack_start(cell, True)
- column.set_attributes(cell, markup=2)
+ column.add_attribute(cell, 'markup', 2)
items.append_column(column)
self.item_store = Gtk.ListStore(bool, GdkPixbuf.Pixbuf, str, object)
items.set_model(self.item_store)
@@ -215,7 +214,7 @@ class MainWindow:
items.enable_model_drag_dest(self.dnd_items, Gdk.DragAction.PRIVATE)
def _cell_data_toggle_func(self, tree_column, renderer, model, treeiter, data=None):
- if model[treeiter][3].get_type() == matemenu.TYPE_SEPARATOR:
+ if isinstance(model[treeiter][3], MateMenu.TreeSeparator):
renderer.set_property('visible', False)
else:
renderer.set_property('visible', True)
@@ -254,22 +253,19 @@ class MainWindow:
def loadItems(self, menu, menu_path):
self.item_store.clear()
for item, show in self.editor.getItems(menu):
- menu_icon = None
- if item.get_type() == matemenu.TYPE_SEPARATOR:
+ icon = util.getIcon(item)
+ if isinstance(item, MateMenu.TreeSeparator):
name = '---'
- icon = None
- elif item.get_type() == matemenu.TYPE_ENTRY:
+ elif isinstance(item, MateMenu.TreeEntry):
if show:
- name = cgi.escape(item.get_display_name())
+ name = cgi.escape(item.get_app_info().get_display_name())
else:
- name = '<small><i>' + cgi.escape(item.get_display_name()) + '</i></small>'
- icon = util.getIcon(item)
+ name = '<small><i>' + cgi.escape(item.get_app_info().get_display_name()) + '</i></small>'
else:
if show:
name = cgi.escape(item.get_name())
else:
name = '<small><i>' + cgi.escape(item.get_name()) + '</i></small>'
- icon = util.getIcon(item)
self.item_store.append((show, icon, name, item))
#this is a little timeout callback to insert new items after
@@ -346,11 +342,11 @@ class MainWindow:
if not iter:
return
item = items[iter][3]
- if item.get_type() == matemenu.TYPE_ENTRY:
+ if isinstance(item, MateMenu.TreeEntry):
self.editor.deleteItem(item)
- elif item.get_type() == matemenu.TYPE_DIRECTORY:
+ elif isinstance(item, MateMenu.TreeDirectory):
self.editor.deleteMenu(item)
- elif item.get_type() == matemenu.TYPE_SEPARATOR:
+ elif isinstance(item, MateMenu.TreeSeparator):
self.editor.deleteSeparator(item)
def on_edit_revert_to_original_activate(self, menu):
@@ -359,9 +355,9 @@ class MainWindow:
if not iter:
return
item = items[iter][3]
- if item.get_type() == matemenu.TYPE_ENTRY:
+ if isinstance(item, MateMenu.TreeEntry):
self.editor.revertItem(item)
- elif item.get_type() == matemenu.TYPE_DIRECTORY:
+ elif isinstance(item, MateMenu.TreeDirectory):
self.editor.revertMenu(item)
def on_edit_properties_activate(self, menu):
@@ -370,13 +366,13 @@ class MainWindow:
if not iter:
return
item = items[iter][3]
- if item.get_type() not in (matemenu.TYPE_ENTRY, matemenu.TYPE_DIRECTORY):
+ if not isinstance(item, MateMenu.TreeEntry) and not isinstance(item, MateMenu.TreeDirectory):
return
- if item.get_type() == matemenu.TYPE_ENTRY:
+ if isinstance(item, MateMenu.TreeEntry):
file_path = os.path.join(util.getUserItemPath(), item.get_desktop_file_id())
file_type = 'Item'
- elif item.get_type() == matemenu.TYPE_DIRECTORY:
+ elif isinstance(item, MateMenu.TreeDirectory):
file_path = os.path.join(util.getUserDirectoryPath(), os.path.split(item.get_desktop_file_path())[1])
file_type = 'Menu'
@@ -391,7 +387,10 @@ class MainWindow:
GLib.timeout_add(100, self.waitForEditProcess, process, file_path)
def on_menu_tree_cursor_changed(self, treeview):
- menus, iter = treeview.get_selection().get_selected()
+ selection = treeview.get_selection()
+ if selection is None:
+ return
+ menus, iter = selection.get_selected()
if iter is None:
return
menu_path = menus.get_path(iter)
@@ -404,6 +403,8 @@ class MainWindow:
self.tree.get_object('move_up_button').set_sensitive(False)
self.tree.get_object('move_down_button').set_sensitive(False)
self.tree.get_object('new_separator_button').set_sensitive(False)
+ self.tree.get_object('properties_button').set_sensitive(False)
+ self.tree.get_object('delete_button').set_sensitive(False)
def on_menu_tree_drag_data_get(self, treeview, context, selection, target_id, etime):
menus, iter = treeview.get_selection().get_selected()
@@ -423,12 +424,12 @@ class MainWindow:
return False
item = self.drag_data
new_parent = menus[path][2]
- if item.get_type() == matemenu.TYPE_ENTRY:
+ if isinstance(item, MateMenu.TreeEntry):
self.editor.copyItem(item, new_parent)
- elif item.get_type() == matemenu.TYPE_DIRECTORY:
+ elif isinstance(item, MateMenu.TreeDirectory):
if not self.editor.moveMenu(item, new_parent):
self.loadUpdates()
- elif item.get_type() == matemenu.TYPE_SEPARATOR:
+ elif isinstance(item, MateMenu.TreeSeparator):
self.editor.moveSeparator(item, new_parent)
else:
context.finish(False, False, etime)
@@ -437,7 +438,7 @@ class MainWindow:
def on_item_tree_show_toggled(self, cell, path):
item = self.item_store[path][3]
- if item.get_type() == matemenu.TYPE_SEPARATOR:
+ if isinstance(item, MateMenu.TreeSeparator):
return
if self.item_store[path][0]:
self.editor.setVisible(item, False)
@@ -446,7 +447,10 @@ class MainWindow:
self.item_store[path][0] = not self.item_store[path][0]
def on_item_tree_cursor_changed(self, treeview):
- items, iter = treeview.get_selection().get_selected()
+ selection = treeview.get_selection()
+ if selection is None:
+ return
+ items, iter = selection.get_selected()
if iter is None:
return
@@ -458,7 +462,7 @@ class MainWindow:
can_revert = self.editor.canRevert(item)
self.tree.get_object('edit_revert_to_original').set_sensitive(can_revert)
- can_edit = not item.get_type() == matemenu.TYPE_SEPARATOR
+ can_edit = not isinstance(item, MateMenu.TreeSeparator)
self.tree.get_object('edit_properties').set_sensitive(can_edit)
self.tree.get_object('properties_button').set_sensitive(can_edit)
@@ -517,7 +521,7 @@ class MainWindow:
path, position = drop_info
target = items[path][3]
# move the item to the directory, if the item was dropped into it
- if (target.get_type() == matemenu.TYPE_DIRECTORY) and (position in types_into):
+ if isinstance(target, MateMenu.TreeDirectory) and (position in types_into):
# append the selected item to the choosen menu
destination = target
elif position in types_before:
@@ -530,12 +534,12 @@ class MainWindow:
else:
path = (len(items) - 1,)
after = items[path][3]
- if item.get_type() == matemenu.TYPE_ENTRY:
+ if isinstance(item, MateMenu.TreeEntry):
self.editor.moveItem(item, destination, before, after)
- elif item.get_type() == matemenu.TYPE_DIRECTORY:
+ elif isinstance(item, MateMenu.TreeDirectory):
if not self.editor.moveMenu(item, destination, before, after):
self.loadUpdates()
- elif item.get_type() == matemenu.TYPE_SEPARATOR:
+ elif isinstance(item, MateMenu.TreeSeparator):
self.editor.moveSeparator(item, destination, before, after)
context.finish(True, True, etime)
elif str(selection.get_target()) == 'text/plain':
@@ -587,12 +591,12 @@ class MainWindow:
if path.get_indices()[0] == 0:
return
item = items[path][3]
- before = items[(path[0] - 1,)][3]
- if item.get_type() == matemenu.TYPE_ENTRY:
+ before = items[(path.get_indices()[0] - 1,)][3]
+ if isinstance(item, MateMenu.TreeEntry):
self.editor.moveItem(item, item.get_parent(), before=before)
- elif item.get_type() == matemenu.TYPE_DIRECTORY:
+ elif isinstance(item, MateMenu.TreeDirectory):
self.editor.moveMenu(item, item.get_parent(), before=before)
- elif item.get_type() == matemenu.TYPE_SEPARATOR:
+ elif isinstance(item, MateMenu.TreeSeparator):
self.editor.moveSeparator(item, item.get_parent(), before=before)
def on_move_down_button_clicked(self, button):
@@ -606,11 +610,11 @@ class MainWindow:
return
item = items[path][3]
after = items[path][3]
- if item.get_type() == matemenu.TYPE_ENTRY:
+ if isinstance(item, MateMenu.TreeEntry):
self.editor.moveItem(item, item.get_parent(), after=after)
- elif item.get_type() == matemenu.TYPE_DIRECTORY:
+ elif isinstance(item, MateMenu.TreeDirectory):
self.editor.moveMenu(item, item.get_parent(), after=after)
- elif item.get_type() == matemenu.TYPE_SEPARATOR:
+ elif isinstance(item, MateMenu.TreeSeparator):
self.editor.moveSeparator(item, item.get_parent(), after=after)
def on_mainwindow_undo(self, accelgroup, window, keyval, modifier):
diff --git a/Mozo/MenuEditor.py b/Mozo/MenuEditor.py
index 62832e6..17315da 100644
--- a/Mozo/MenuEditor.py
+++ b/Mozo/MenuEditor.py
@@ -22,8 +22,9 @@ import re
import xml.dom.minidom
import xml.parsers.expat
import locale
-import matemenu
-from gi.repository import GLib
+import gi
+gi.require_version('MateMenu', '2.0')
+from gi.repository import MateMenu, GLib
from Mozo import util
class Menu:
@@ -32,41 +33,56 @@ class Menu:
path = None
dom = None
-class MenuEditor:
+class MenuEditor(object):
def __init__(self):
self.locale = locale.getdefaultlocale()[0]
- self.__loadMenus()
self.__undo = []
self.__redo = []
+ self.applications = Menu()
+ self.applications.tree = MateMenu.Tree.new('mate-applications.menu', MateMenu.TreeFlags.SHOW_EMPTY|MateMenu.TreeFlags.INCLUDE_EXCLUDED|MateMenu.TreeFlags.INCLUDE_NODISPLAY|MateMenu.TreeFlags.SHOW_ALL_SEPARATORS|MateMenu.TreeFlags.SORT_DISPLAY_NAME)
+ self.applications.visible_tree = MateMenu.Tree.new('mate-applications.menu', MateMenu.TreeFlags.SORT_DISPLAY_NAME)
+ self.applications.tree.sort_key = MateMenu.TreeFlags.SORT_DISPLAY_NAME
+ self.applications.visible_tree.sort_key = MateMenu.TreeFlags.SORT_DISPLAY_NAME
+ self.applications.tree.connect('changed', self.menuChanged)
+ self.settings = Menu()
+ self.settings.tree = MateMenu.Tree.new('mate-settings.menu', MateMenu.TreeFlags.SHOW_EMPTY|MateMenu.TreeFlags.INCLUDE_EXCLUDED|MateMenu.TreeFlags.INCLUDE_NODISPLAY|MateMenu.TreeFlags.SHOW_ALL_SEPARATORS|MateMenu.TreeFlags.SORT_DISPLAY_NAME)
+ self.settings.visible_tree = MateMenu.Tree.new('mate-settings.menu', MateMenu.TreeFlags.SORT_DISPLAY_NAME)
+ self.settings.tree.sort_key = MateMenu.TreeFlags.SORT_DISPLAY_NAME
+ self.settings.visible_tree.sort_key = MateMenu.TreeFlags.SORT_DISPLAY_NAME
+ self.settings.tree.connect('changed', self.menuChanged)
+ self.load()
+ self.__loadMenus()
def __loadMenus(self):
- self.applications = Menu()
- self.applications.tree = matemenu.lookup_tree('mate-applications.menu', matemenu.FLAGS_SHOW_EMPTY|matemenu.FLAGS_INCLUDE_EXCLUDED|matemenu.FLAGS_INCLUDE_NODISPLAY|matemenu.FLAGS_SHOW_ALL_SEPARATORS)
- self.applications.visible_tree = matemenu.lookup_tree('mate-applications.menu')
- self.applications.tree.sort_key = matemenu.SORT_DISPLAY_NAME
- self.applications.visible_tree.sort_key = matemenu.SORT_DISPLAY_NAME
- self.applications.path = os.path.join(util.getUserMenuPath(), self.applications.tree.get_menu_file())
+ self.applications.path = os.path.join(util.getUserMenuPath(), self.applications.tree.props.menu_basename)
try:
self.applications.dom = xml.dom.minidom.parse(self.applications.path)
except (IOError, xml.parsers.expat.ExpatError):
self.applications.dom = xml.dom.minidom.parseString(util.getUserMenuXml(self.applications.tree))
util.removeWhitespaceNodes(self.applications.dom)
- self.settings = Menu()
- self.settings.tree = matemenu.lookup_tree('mate-settings.menu', matemenu.FLAGS_SHOW_EMPTY|matemenu.FLAGS_INCLUDE_EXCLUDED|matemenu.FLAGS_INCLUDE_NODISPLAY|matemenu.FLAGS_SHOW_ALL_SEPARATORS)
- self.settings.visible_tree = matemenu.lookup_tree('mate-settings.menu')
- self.settings.tree.sort_key = matemenu.SORT_DISPLAY_NAME
- self.settings.visible_tree.sort_key = matemenu.SORT_DISPLAY_NAME
- self.settings.path = os.path.join(util.getUserMenuPath(), self.settings.tree.get_menu_file())
+ self.settings.path = os.path.join(util.getUserMenuPath(), self.settings.tree.props.menu_basename)
try:
self.settings.dom = xml.dom.minidom.parse(self.settings.path)
except (IOError, xml.parsers.expat.ExpatError):
self.settings.dom = xml.dom.minidom.parseString(util.getUserMenuXml(self.settings.tree))
util.removeWhitespaceNodes(self.settings.dom)
-
self.save(True)
+ def load(self):
+ if not self.applications.tree.load_sync():
+ raise ValueError("can not load menu tree %r" % (self.applications.tree.props.menu_basename,))
+ if not self.settings.tree.load_sync():
+ raise ValueError("can not load menu tree %r" % (self.settings.tree.props.menu_basename,))
+ if not self.applications.visible_tree.load_sync():
+ raise ValueError("can not load menu tree %r" % (self.applications.visible_tree.props.menu_basename,))
+ if not self.settings.visible_tree.load_sync():
+ raise ValueError("can not load menu tree %r" % (self.settings.visible_tree.props.menu_basename,))
+
+ def menuChanged(self, *a):
+ self.load()
+
def save(self, from_loading=False):
for menu in ('applications', 'settings'):
with codecs.open(getattr(self, menu).path, 'w', 'utf-8') as f:
@@ -91,8 +107,8 @@ class MenuEditor:
def revert(self):
for name in ('applications', 'settings'):
menu = getattr(self, name)
- self.revertTree(menu.tree.root)
- path = os.path.join(util.getUserMenuPath(), menu.tree.get_menu_file())
+ self.revertTree(menu.tree.get_root_directory())
+ path = os.path.join(util.getUserMenuPath(), menu.tree.props.menu_basename)
try:
os.unlink(path)
except OSError:
@@ -108,11 +124,16 @@ class MenuEditor:
self.save()
def revertTree(self, menu):
- for child in menu.get_contents():
- if child.get_type() == matemenu.TYPE_DIRECTORY:
- self.revertTree(child)
- elif child.get_type() == matemenu.TYPE_ENTRY:
- self.revertItem(child)
+ item_iter = menu.iter()
+ item_type = item_iter.next()
+ while item_type != MateMenu.TreeItemType.INVALID:
+ if item_type == MateMenu.TreeItemType.DIRECTORY:
+ item = item_iter.get_directory()
+ self.revertTree(item)
+ elif item_type == MateMenu.TreeItemType.ENTRY:
+ item = item_iter.get_entry()
+ self.revertItem(item)
+ item_type = item_iter.next()
self.revertMenu(menu)
def revertItem(self, item):
@@ -206,29 +227,55 @@ class MenuEditor:
def getMenus(self, parent=None):
if parent is None:
- yield self.applications.tree.root
- yield self.settings.tree.root
+ yield self.applications.tree.get_root_directory()
+ yield self.settings.tree.get_root_directory()
else:
- for menu in parent.get_contents():
- if menu.get_type() == matemenu.TYPE_DIRECTORY:
- yield (menu, self.__isVisible(menu))
+ item_iter = parent.iter()
+ item_type = item_iter.next()
+ while item_type != MateMenu.TreeItemType.INVALID:
+ if item_type == MateMenu.TreeItemType.DIRECTORY:
+ item = item_iter.get_directory()
+ yield (item, self.__isVisible(item))
+ item_type = item_iter.next()
+
+ def getContents(self, item):
+ contents = []
+ item_iter = item.iter()
+ item_type = item_iter.next()
+
+ while item_type != MateMenu.TreeItemType.INVALID:
+ item = None
+ if item_type == MateMenu.TreeItemType.DIRECTORY:
+ item = item_iter.get_directory()
+ elif item_type == MateMenu.TreeItemType.ENTRY:
+ item = item_iter.get_entry()
+ elif item_type == MateMenu.TreeItemType.HEADER:
+ item = item_iter.get_header()
+ elif item_type == MateMenu.TreeItemType.ALIAS:
+ item = item_iter.get_alias()
+ elif item_type == MateMenu.TreeItemType.SEPARATOR:
+ item = item_iter.get_separator()
+ if item:
+ contents.append(item)
+ item_type = item_iter.next()
+ return contents
def getItems(self, menu):
- for item in menu.get_contents():
- if item.get_type() == matemenu.TYPE_SEPARATOR:
- yield (item, True)
+ for item in self.getContents(menu):
+ if isinstance(item, MateMenu.TreeSeparator):
+ yield(item, True)
else:
- if item.get_type() == matemenu.TYPE_ENTRY and item.get_desktop_file_id()[-19:] == '-usercustom.desktop':
- continue
+ if isinstance(item, MateMenu.TreeEntry) and item.get_desktop_file_id()[-19:] == '-usercustom.desktop':
+ continue
yield (item, self.__isVisible(item))
def canRevert(self, item):
- if item.get_type() == matemenu.TYPE_ENTRY:
+ if isinstance(item, MateMenu.TreeEntry):
if util.getItemPath(item.get_desktop_file_id()) is not None:
path = util.getUserItemPath()
if os.path.isfile(os.path.join(path, item.get_desktop_file_id())):
return True
- elif item.get_type() == matemenu.TYPE_DIRECTORY:
+ elif isinstance(item, MateMenu.TreeDirectory):
if item.get_desktop_file_path():
file_id = os.path.split(item.get_desktop_file_path())[1]
else:
@@ -241,7 +288,7 @@ class MenuEditor:
def setVisible(self, item, visible):
dom = self.__getMenu(item).dom
- if item.get_type() == matemenu.TYPE_ENTRY:
+ if isinstance(item, MateMenu.TreeEntry):
self.__addUndo([self.__getMenu(item), item])
menu_xml = self.__getXmlMenu(self.__getPath(item.get_parent()), dom.documentElement, dom)
if visible:
@@ -250,10 +297,12 @@ class MenuEditor:
else:
self.__addXmlFilename(menu_xml, dom, item.get_desktop_file_id(), 'Exclude')
self.__addXmlTextElement(menu_xml, 'AppDir', util.getUserItemPath(), dom)
- elif item.get_type() == matemenu.TYPE_DIRECTORY:
+ elif isinstance(item, MateMenu.TreeDirectory):
self.__addUndo([self.__getMenu(item), item])
+ item_iter = item.iter()
+ first_child_type = item_iter.next()
#don't mess with it if it's empty
- if len(item.get_contents()) == 0:
+ if first_child_type == MateMenu.TreeItemType.INVALID:
return
menu_xml = self.__getXmlMenu(self.__getPath(item), dom.documentElement, dom)
for node in self.__getXmlNodesByName(['Deleted', 'NotDeleted'], menu_xml):
@@ -264,7 +313,7 @@ class MenuEditor:
def createItem(self, parent, before, after, **kwargs):
file_id = self.__writeItem(None, **kwargs)
- self.insertExternalItem(file_id, parent.menu_id, before, after)
+ self.insertExternalItem(file_id, parent.get_menu_id(), before, after)
def insertExternalItem(self, file_id, parent_id, before=None, after=None):
parent = self.__findMenu(parent_id)
@@ -292,7 +341,8 @@ class MenuEditor:
def editItem(self, item, icon, name, comment, command, use_term, parent=None, final=True):
#if nothing changed don't make a user copy
- if icon == item.get_icon() and name == item.get_display_name() and comment == item.get_comment() and command == item.get_exec() and use_term == item.get_launch_in_terminal():
+ app_info = item.get_app_info()
+ if icon == app_info.get_icon() and name == app_info.get_display_name() and comment == item.get_comment() and command == item.get_exec() and use_term == item.get_launch_in_terminal():
return
#hack, item.get_parent() seems to fail a lot
if not parent:
@@ -328,7 +378,8 @@ class MenuEditor:
util.fillKeyFile(keyfile, dict(Categories=[], Hidden=False))
- file_id = util.getUniqueFileId(item.get_name().replace(os.sep, '-'), '.desktop')
+ app_info = item.get_app_info()
+ file_id = util.getUniqueFileId(app_info.get_name().replace(os.sep, '-'), '.desktop')
out_path = os.path.join(util.getUserItemPath(), file_id)
contents, length = keyfile.to_data()
@@ -409,7 +460,7 @@ class MenuEditor:
def deleteSeparator(self, item):
parent = item.get_parent()
- contents = parent.get_contents()
+ contents = self.getContents(parent)
contents.remove(item)
layout = self.__createLayout(contents)
dom = self.__getMenu(parent).dom
@@ -435,13 +486,13 @@ class MenuEditor:
file_path = util.getDirectoryPath(item[1])
else:
continue
- elif item.get_type() == matemenu.TYPE_DIRECTORY:
+ elif isinstance(item, MateMenu.TreeDirectory):
if item.get_desktop_file_path() is None:
continue
file_path = os.path.join(util.getUserDirectoryPath(), os.path.split(item.get_desktop_file_path())[1])
if not os.path.isfile(file_path):
file_path = item.get_desktop_file_path()
- elif item.get_type() == matemenu.TYPE_ENTRY:
+ elif isinstance(item, MateMenu.TreeEntry):
file_path = os.path.join(util.getUserItemPath(), item.get_desktop_file_id())
if not os.path.isfile(file_path):
file_path = item.get_desktop_file_path()
@@ -465,39 +516,45 @@ class MenuEditor:
root = root.get_parent()
else:
break
- if root.menu_id == self.applications.tree.root.menu_id:
+ if root.get_menu_id() == self.applications.tree.get_root_directory().get_menu_id():
return self.applications
return self.settings
def __findMenu(self, menu_id, parent=None):
if parent is None:
- menu = self.__findMenu(menu_id, self.applications.tree.root)
+ menu = self.__findMenu(menu_id, self.applications.tree.get_root_directory())
if menu is not None:
return menu
else:
- return self.__findMenu(menu_id, self.settings.tree.root)
- if menu_id == self.applications.tree.root.menu_id:
- return self.applications.tree.root
- if menu_id == self.settings.tree.root.menu_id:
- return self.settings.tree.root
- for item in parent.get_contents():
- if item.get_type() == matemenu.TYPE_DIRECTORY:
- if item.menu_id == menu_id:
+ return self.__findMenu(menu_id, self.settings.tree.get_root_directory())
+ if menu_id == self.applications.tree.get_root_directory().get_menu_id():
+ return self.applications.tree.get_root_directory()
+ if menu_id == self.settings.tree.get_root_directory().get_menu_id():
+ return self.settings.tree.get_root_directory()
+
+ item_iter = parent.iter()
+ item_type = item_iter.next()
+ while item_type != MateMenu.TreeItemType.INVALID:
+ if item_type == MateMenu.TreeItemType.DIRECTORY:
+ item = item_iter.get_directory()
+ if item.get_menu_id() == menu_id:
return item
menu = self.__findMenu(menu_id, item)
if menu is not None:
return menu
+ item_type = item_iter.next()
def __isVisible(self, item):
- if item.get_type() == matemenu.TYPE_ENTRY:
- return not (item.get_is_excluded() or item.get_is_nodisplay())
+ if isinstance(item, MateMenu.TreeEntry):
+ app_info = item.get_app_info()
+ return not (item.get_is_excluded() or app_info.get_nodisplay())
menu = self.__getMenu(item)
if menu == self.applications:
- root = self.applications.visible_tree.root
+ root = self.applications.visible_tree.get_root_directory()
elif menu == self.settings:
- root = self.settings.visible_tree.root
- if item.get_type() == matemenu.TYPE_DIRECTORY:
- if self.__findMenu(item.menu_id, root) is None:
+ root = self.settings.visible_tree.get_root_directory()
+ if isinstance(item, MateMenu.TreeDirectory):
+ if self.__findMenu(item.get_menu_id(), root) is None:
return False
return True
@@ -682,11 +739,11 @@ class MenuEditor:
layout.parseMenuname(item[1])
elif item[0] == 'Item':
layout.parseFilename(item[1])
- elif item.get_type() == matemenu.TYPE_DIRECTORY:
+ elif isinstance(item, MateMenu.TreeDirectory):
layout.parseMenuname(item.get_menu_id())
- elif item.get_type() == matemenu.TYPE_ENTRY:
+ elif isinstance(item, MateMenu.TreeEntry):
layout.parseFilename(item.get_desktop_file_id())
- elif item.get_type() == matemenu.TYPE_SEPARATOR:
+ elif isinstance(item, MateMenu.TreeSeparator):
layout.parseSeparator()
layout.order.append(['Merge', 'files'])
return layout
@@ -695,20 +752,24 @@ class MenuEditor:
xml_parent = self.__getXmlMenu(self.__getPath(parent), dom.documentElement, dom)
self.__addXmlFilename(xml_parent, dom, file_id, 'Include')
+ def moveItem(self, parent, item, before=None, after=None):
+ self.__positionItem(parent, item, before=before, after=after)
+ self.save()
+
def __positionItem(self, parent, item, before=None, after=None):
+ contents = self.getContents(parent)
if after:
- index = parent.contents.index(after) + 1
+ index = contents.index(after) + 1
elif before:
- index = parent.contents.index(before)
+ index = contents.index(before)
else:
# append the item to the list
- index = len(parent.contents)
- contents = parent.contents
+ index = len(contents)
#if this is a move to a new parent you can't remove the item
if item in contents:
# decrease the destination index, if we shorten the list
if (before and (contents.index(item) < index)) \
- or (after and (contents.index(item) < index - 1)):
+ or (after and (contents.index(item) < index - 1)):
index -= 1
contents.remove(item)
contents.insert(index, item)
diff --git a/Mozo/util.py b/Mozo/util.py
index bb9e1c6..992731d 100644
--- a/Mozo/util.py
+++ b/Mozo/util.py
@@ -18,24 +18,26 @@
import os
import xml.dom.minidom
-import matemenu
import gi
+gi.require_version('Gtk', '3.0')
+gi.require_version('MateMenu', '2.0')
from collections import Sequence
from gi.repository import GLib, Gtk, Gdk, GdkPixbuf
+from gi.repository import MateMenu
DESKTOP_GROUP = GLib.KEY_FILE_DESKTOP_GROUP
KEY_FILE_FLAGS = GLib.KeyFileFlags.KEEP_COMMENTS | GLib.KeyFileFlags.KEEP_TRANSLATIONS
def fillKeyFile(keyfile, items):
- for key, item in items.iteritems():
+ for key, item in items.items():
if item is None:
continue
if isinstance(item, bool):
keyfile.set_boolean(DESKTOP_GROUP, key, item)
- elif isinstance(item, Sequence):
+ elif isinstance(item, Sequence) and not isinstance(item, (str, bytes, bytearray)):
keyfile.set_string_list(DESKTOP_GROUP, key, item)
- elif isinstance(item, basestring):
+ elif isinstance(item, str):
keyfile.set_string(DESKTOP_GROUP, key, item)
def getUniqueFileId(name, extension):
@@ -123,49 +125,55 @@ def getSystemMenuPath(file_id):
return None
def getUserMenuXml(tree):
- system_file = getSystemMenuPath(tree.get_menu_file())
- name = tree.root.get_menu_id()
+ system_file = getSystemMenuPath(os.path.basename(tree.get_canonical_menu_path()))
+ name = tree.get_root_directory().get_menu_id()
menu_xml = "<!DOCTYPE Menu PUBLIC '-//freedesktop//DTD Menu 1.0//EN' 'http://standards.freedesktop.org/menu-spec/menu-1.0.dtd'>\n"
menu_xml += "<Menu>\n <Name>" + name + "</Name>\n "
menu_xml += "<MergeFile type=\"parent\">" + system_file + "</MergeFile>\n</Menu>\n"
return menu_xml
def getIcon(item):
- pixbuf, path = None, None
- if item is None:
- return None
- if isinstance(item, str):
+ iconName = None
+ gicon = None
+ if isinstance(item, MateMenu.TreeDirectory):
+ gicon = item.get_icon()
+ elif isinstance(item, MateMenu.TreeEntry):
+ app_info = item.get_app_info()
+ gicon = app_info.get_icon()
+ elif isinstance(item, str):
iconName = item
- else:
- iconName = item.get_icon()
if iconName and not '/' in iconName and iconName[-3:] in ('png', 'svg', 'xpm'):
iconName = iconName[:-4]
+
+ pixbuf = None
icon_theme = Gtk.IconTheme.get_default()
- try:
- pixbuf = icon_theme.load_icon(iconName, 24, 0)
- path = icon_theme.lookup_icon(iconName, 24, 0).get_filename()
- except:
- if iconName and '/' in iconName:
- try:
- pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(iconName, 24, 24)
- path = iconName
- except:
- pass
- if pixbuf is None:
- if item.get_type() == matemenu.TYPE_DIRECTORY:
- iconName = 'mate-fs-directory'
- elif item.get_type() == matemenu.TYPE_ENTRY:
- iconName = 'application-default-icon'
- try:
- pixbuf = icon_theme.load_icon(iconName, 24, 0)
- path = icon_theme.lookup_icon(iconName, 24, 0).get_filename()
- except:
- return None
+ if gicon:
+ info = icon_theme.lookup_by_gicon(gicon, 24, 0)
+ try:
+ pixbuf = info.load_icon()
+ except:
+ pass
+ elif iconName is not None:
+ try:
+ pixbuf = icon_theme.load_icon(iconName, 24, 0)
+ except:
+ if iconName and '/' in iconName:
+ try:
+ pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(iconName, 24, 24)
+ except:
+ pass
+ # fallback to use image-missing icon
+ if pixbuf is None:
+ try:
+ pixbuf = icon_theme.load_icon('image-missing', 24, 0)
+ except:
+ pass
if pixbuf is None:
return None
- if pixbuf.get_width() != 24 or pixbuf.get_height() != 24:
- pixbuf = pixbuf.scale_simple(24, 24, GdkPixbuf.InterpType.HYPER)
- return pixbuf
+ else:
+ if pixbuf.get_width() != 24 or pixbuf.get_height() != 24:
+ pixbuf = pixbuf.scale_simple(24, 24, GdkPixbuf.InterpType.HYPER)
+ return pixbuf
def removeWhitespaceNodes(node):
remove_list = []
diff --git a/acinclude.m4 b/acinclude.m4
index 1227123..8babc67 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -71,7 +71,7 @@ AC_DEFUN([AM_PATH_PYTHON_VERSION],
dnl library.
AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
- [am_cv_python_version=`$PYTHON -c "import sys; print sys.version[[:3]]"`])
+ [am_cv_python_version=`$PYTHON -c "import sys; print(sys.version[[:3]])"`])
AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
dnl Use the values of $prefix and $exec_prefix for the corresponding
@@ -86,7 +86,7 @@ AC_DEFUN([AM_PATH_PYTHON_VERSION],
dnl to know which OS platform Python thinks this is.
AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
- [am_cv_python_platform=`$PYTHON -c "import sys; print sys.platform"`])
+ [am_cv_python_platform=`$PYTHON -c "import sys; print(sys.platform)"`])
AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
@@ -101,7 +101,7 @@ AC_DEFUN([AM_PATH_PYTHON_VERSION],
dnl doesn't work.
AC_CACHE_CHECK([for $am_display_PYTHON script directory],
[am_cv_python_pythondir],
- [am_cv_python_pythondir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(0,0,prefix='$PYTHON_PREFIX')" 2>/dev/null ||
+ [am_cv_python_pythondir=`$PYTHON -c "from distutils import sysconfig; print(sysconfig.get_python_lib(0,0,prefix='$PYTHON_PREFIX'))" 2>/dev/null ||
echo "$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages"`])
AC_SUBST([pythondir], [$am_cv_python_pythondir])
@@ -118,7 +118,7 @@ AC_DEFUN([AM_PATH_PYTHON_VERSION],
dnl doesn't work.
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
[am_cv_python_pyexecdir],
- [am_cv_python_pyexecdir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(1,0,prefix='$PYTHON_EXEC_PREFIX')" 2>/dev/null ||
+ [am_cv_python_pyexecdir=`$PYTHON -c "from distutils import sysconfig; print(sysconfig.get_python_lib(1,0,prefix='$PYTHON_EXEC_PREFIX'))" 2>/dev/null ||
echo "${PYTHON_EXEC_PREFIX}/lib/python${PYTHON_VERSION}/site-packages"`])
AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
diff --git a/configure.ac b/configure.ac
index 8348533..c35cf4c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,9 +18,9 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package])
AM_GLIB_GNU_GETTEXT
IT_PROG_INTLTOOL([0.40.0])
-AM_PATH_PYTHON_VERSION(2.7, 2.7.0)
+AM_PATH_PYTHON(3.5)
-PKG_CHECK_MODULES(MOZO, libmate-menu >= 1.1.0 pygobject-3.0)
+PKG_CHECK_MODULES(MOZO, libmate-menu >= 1.21.0 pygobject-3.0)
AC_ARG_ENABLE(icon-update, AC_HELP_STRING([--disable-icon-update],
[Disable icon cache update]))
diff --git a/mozo.in b/mozo.in
index 52b4157..7a42108 100644
--- a/mozo.in
+++ b/mozo.in
@@ -28,7 +28,7 @@ def main():
version = config.VERSION
except:
datadir = './data/'
- version = '1.7.0'
+ version = '1.21.0'
app = MainWindow(datadir, version, sys.argv)
app.run()