diff --git a/debian/control b/debian/control index cca03e8..644ff65 100644 --- a/debian/control +++ b/debian/control @@ -10,20 +10,19 @@ Architecture: all Depends: ${python:Depends}, ${misc:Depends}, - mint-common, - python (>= 2.4), python (<< 3), - python-apt, - python-configobj, - python-setproctitle, - python-xlib, - python-xdg, + python3 (>= 3.3), + python3-apt, + python3-configobj, + python3-setproctitle, + python3-xlib, + python3-xdg, xdg-utils, libglib2.0-bin, mate-menus, - python-mate-menu, gir1.2-matepanelapplet-4.0, gir1.2-gtk-3.0, gir1.2-mate-desktop, + gir1.2-matemenu-2.0, mozo Description: Advanced MATE menu One of the most advanced menus under Linux. MintMenu supports filtering, diff --git a/debian/postinst b/debian/postinst index d858a4f..fe5bec5 100644 --- a/debian/postinst +++ b/debian/postinst @@ -19,7 +19,7 @@ set -e case "$1" in configure) glib-compile-schemas /usr/share/glib-2.0/schemas - python -m compileall -qf /usr/lib/linuxmint/mintMenu/ + python3 -m compileall -qf /usr/lib/linuxmint/mintMenu/ ;; abort-upgrade|abort-remove|abort-deconfigure) diff --git a/debian/rules b/debian/rules index 0751f93..097372c 100755 --- a/debian/rules +++ b/debian/rules @@ -3,7 +3,7 @@ DEB_VERSION := $(shell dpkg-parsechangelog | egrep '^Version:' | cut -f 2 -d ' ') %: - dh ${@} --with-python2 + dh ${@} # Inject version number in the code override_dh_installdeb: diff --git a/usr/lib/linuxmint/mintMenu/keybinding.py b/usr/lib/linuxmint/mintMenu/keybinding.py index 0f80731..f4d1a67 100644 --- a/usr/lib/linuxmint/mintMenu/keybinding.py +++ b/usr/lib/linuxmint/mintMenu/keybinding.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # -*- coding: utf-8; -*- # Copyright (C) 2013 Ozcan Esen @@ -118,7 +118,7 @@ class GlobalKeyBinding(GObject.GObject, threading.Thread): self.grab(self.keytext) def get_mask_combinations(self, mask): - return [x for x in xrange(mask+1) if not (x & ~mask)] + return [x for x in range(mask+1) if not (x & ~mask)] def idle(self): self.emit("activate") diff --git a/usr/lib/linuxmint/mintMenu/mintMenu.py b/usr/lib/linuxmint/mintMenu/mintMenu.py index daf7b9a..e87f4d5 100755 --- a/usr/lib/linuxmint/mintMenu/mintMenu.py +++ b/usr/lib/linuxmint/mintMenu/mintMenu.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 import gc import gettext @@ -168,7 +168,7 @@ class MainWindow(object): try: X = __import__(plugin) # If no parameter passed to plugin it is autonomous - if X.pluginclass.__init__.func_code.co_argcount == 1: + if X.pluginclass.__init__.__code__.co_argcount == 1: MyPlugin = X.pluginclass() else: # pass mintMenu and togglebutton instance so that the plugin can use it @@ -540,9 +540,8 @@ class MenuWin(object): self.do_image(self.buttonIcon, False) self.systemlabel = Gtk.Label(label= "%s " % self.buttonText) if os.path.isfile("/etc/linuxmint/info"): - with open("/etc/linuxmint/info") as info: + with open("/etc/linuxmint/info", encoding = "utf-8") as info: for line in info: - line = line.decode("utf-8") if line.startswith("DESCRIPTION="): tooltip = line.split("=",1)[1].strip('"\n') self.systemlabel.set_tooltip_text(tooltip) @@ -638,7 +637,7 @@ class MenuWin(object): self.do_image(self.buttonIcon, False) self.sizeButton() - def hotkeyChanged (self, schema, key): + def hotkeyChanged(self, schema, key): self.hotkeyText = self.settings.get_string("hot-key") self.keybinder.rebind(self.hotkeyText) diff --git a/usr/lib/linuxmint/mintMenu/plugins/__init__.py b/usr/lib/linuxmint/mintMenu/plugins/__init__.py index 0e1d5dd..a93a4bf 100755 --- a/usr/lib/linuxmint/mintMenu/plugins/__init__.py +++ b/usr/lib/linuxmint/mintMenu/plugins/__init__.py @@ -1 +1 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 diff --git a/usr/lib/linuxmint/mintMenu/plugins/applications.py b/usr/lib/linuxmint/mintMenu/plugins/applications.py index b952bf3..6efef21 100755 --- a/usr/lib/linuxmint/mintMenu/plugins/applications.py +++ b/usr/lib/linuxmint/mintMenu/plugins/applications.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 import cgi import filecmp @@ -10,9 +10,9 @@ import urllib import gi gi.require_version("Gtk", "3.0") -from gi.repository import Gtk, Gdk, GdkPixbuf, Gio, GLib +gi.require_version('MateMenu', '2.0') +from gi.repository import Gtk, Gdk, GdkPixbuf, Gio, GLib, MateMenu -import matemenu import plugins.recentHelper as RecentHelper from plugins.easybuttons import (ApplicationLauncher, CategoryButton, FavApplicationLauncher, @@ -79,10 +79,33 @@ def rel_path(target, base=os.curdir): rel_list = [os.pardir] * (len(base_list) - i) + target_list[i:] return os.path.join(*rel_list) +def get_contents(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 + class Menu: def __init__(self, MenuToLookup): - self.tree = matemenu.lookup_tree(MenuToLookup) + self.tree = MateMenu.Tree.new(MenuToLookup, MateMenu.TreeFlags.SORT_DISPLAY_NAME) + self.tree.load_sync() self.directory = self.tree.get_root_directory() def getMenus(self, parent=None): @@ -90,21 +113,21 @@ class Menu: #gives top-level "Applications" item yield self.tree.root else: - for menu in parent.get_contents(): - if menu.get_type() == matemenu.TYPE_DIRECTORY and self.__isVisible(menu): + for menu in get_contents(parent): + if isinstance(menu, MateMenu.TreeDirectory) and self.__isVisible(menu): yield menu def getItems(self, menu): - for item in menu.get_contents(): - if item.get_type() == matemenu.TYPE_ENTRY and \ - item.get_desktop_file_id()[-19:] != '-usercustom.desktop' and \ - self.__isVisible(item): + for item in get_contents(menu): + if isinstance(item, MateMenu.TreeEntry) and \ + item.get_desktop_file_id()[-19:] != '-usercustom.desktop' and \ + self.__isVisible(item): yield item def __isVisible(self, item): - if item.get_type() == matemenu.TYPE_ENTRY: + if isinstance(item, MateMenu.TreeEntry): return not(item.get_is_excluded() or item.get_is_nodisplay()) - if item.get_type() == matemenu.TYPE_DIRECTORY and len(item.get_contents()): + if isinstance(item, MateMenu.TreeDirectory) and len(get_contents(item)): return True class SuggestionButton(Gtk.Button): @@ -159,6 +182,7 @@ class pluginclass(object): RecentHelper.mintMenuWin = mintMenuWin self.mainMenus = [] self.toggleButton = toggleButton + self.menuFiles = [] self.de = de # Detect the locale (this is used for the Wikipedia search) @@ -266,7 +290,8 @@ class pluginclass(object): for mainitems in ["mate-applications.menu", "mate-settings.menu"]: mymenu = Menu(mainitems) - mymenu.tree.add_monitor(self.menuChanged, None) + mymenu.tree.connect("changed", self.menuChanged, None) + self.menuFiles.append(mymenu) self.refresh_apt_cache() self.suggestions = [] @@ -972,17 +997,17 @@ class pluginclass(object): self.focusSearchEntry(clear = False) def search_ddg(self, widget): - text = urllib.quote_plus(self.searchEntry.get_text().strip()) + text = urllib.parse.quote_plus(self.searchEntry.get_text().strip()) subprocess.Popen(["xdg-open", "https://duckduckgo.com/?q=%s" % text]) self.mintMenuWin.hide() def search_google(self, widget): - text = urllib.quote_plus(self.searchEntry.get_text().strip()) + text = urllib.parse.quote_plus(self.searchEntry.get_text().strip()) subprocess.Popen(["xdg-open", "https://www.google.com/search?q=%s" % text]) self.mintMenuWin.hide() def search_wikipedia(self, widget): - text = urllib.quote_plus(self.searchEntry.get_text().strip()) + text = urllib.parse.quote_plus(self.searchEntry.get_text().strip()) subprocess.Popen(["xdg-open", "https://en.wikipedia.org/wiki/Special:Search?search=%s" % text]) self.mintMenuWin.hide() @@ -992,27 +1017,27 @@ class pluginclass(object): self.mintMenuWin.hide() def search_mint_tutorials(self, widget): - text = urllib.quote(self.searchEntry.get_text().strip()) + text = urllib.parse.quote(self.searchEntry.get_text().strip()) subprocess.Popen(["xdg-open", "https://community.linuxmint.com/index.php/tutorial/search/0/%s" % text]) self.mintMenuWin.hide() def search_mint_ideas(self, widget): - text = urllib.quote(self.searchEntry.get_text().strip()) + text = urllib.parse.quote(self.searchEntry.get_text().strip()) subprocess.Popen(["xdg-open", "https://community.linuxmint.com/index.php/idea/search/0/%s" % text]) self.mintMenuWin.hide() def search_mint_users(self, widget): - text = urllib.quote(self.searchEntry.get_text().strip()) + text = urllib.parse.quote(self.searchEntry.get_text().strip()) subprocess.Popen(["xdg-open", "https://community.linuxmint.com/index.php/user/search/0/%s" % text]) self.mintMenuWin.hide() def search_mint_hardware(self, widget): - text = urllib.quote(self.searchEntry.get_text().strip()) + text = urllib.parse.quote(self.searchEntry.get_text().strip()) subprocess.Popen(["xdg-open", "https://community.linuxmint.com/index.php/hardware/search/0/%s" % text]) self.mintMenuWin.hide() def search_mint_software(self, widget): - text = urllib.quote(self.searchEntry.get_text()) + text = urllib.parse.quote(self.searchEntry.get_text()) subprocess.Popen(["xdg-open", "https://community.linuxmint.com/index.php/software/search/0/%s" % text]) self.mintMenuWin.hide() @@ -1190,7 +1215,7 @@ class pluginclass(object): def favoritesBuildLauncher(self, location): try: # For Folders and Network Shares - location = "".join(location.split("%20")) + location = location.replace("%20", " ") # TODO: Do we still need this? #For Special locations @@ -1234,7 +1259,7 @@ class pluginclass(object): os.system("mkdir -p " + path) os.system("cp /usr/lib/linuxmint/mintMenu/applications.list " + path) - applicationsList = open(path).readlines() + applicationsList = open(path, encoding="UTF-8").readlines() self.favorites = [] @@ -1381,8 +1406,7 @@ class pluginclass(object): def on_drag_data_get(self, widget, context, selection, info, time): if info == self.TARGET_TYPE_FAV: self.drag_origin = widget.position - # FIXME: This fails in python3: - selection.set(selection.get_target(), 8, str(widget.position)) + selection.set(selection.get_target(), 8, str(widget.position).encode()) def on_drag_data_received(self, widget, context, x, y, selection, info, time): if info == self.TARGET_TYPE_FAV: @@ -1579,9 +1603,14 @@ class pluginclass(object): # Reload the menufiles from the filesystem def loadMenuFiles(self): - self.menuFiles = [] + if len(self.menuFiles) > 0: + for menu in self.menuFiles: + menu.tree.disconnect_by_func(self.menuChanged) + self.menuFiles = [] for mainitems in ["mate-applications.menu", "mate-settings.menu"]: - self.menuFiles.append(Menu(mainitems)) + mymenu = Menu( mainitems ) + mymenu.tree.connect("changed", self.menuChanged, None) + self.menuFiles.append(mymenu) # Build a list of all categories in the menu ([{"name", "icon", tooltip"}] def buildCategoryList(self): @@ -1591,16 +1620,14 @@ class pluginclass(object): "filter":"", "index": 0}] num = 1 for menu in self.menuFiles: - for child in menu.directory.get_contents(): - if child.get_type() == matemenu.TYPE_DIRECTORY: - icon = str(child.icon) - #if (icon == "preferences-system"): - # self.adminMenu = child.name - #if (icon != "applications-system" and icon != "applications-other"): - newCategoryList.append({"name": child.name, - "icon": child.icon, - "tooltip": child.name, - "filter": child.name, + for child in get_contents(menu.directory): + if isinstance(child, MateMenu.TreeDirectory): + name = child.get_name() + icon = child.get_icon().to_string() + newCategoryList.append({"name": name, + "icon": icon, + "tooltip": name, + "filter": name, "index": num}) num += 1 return newCategoryList @@ -1610,29 +1637,30 @@ class pluginclass(object): newApplicationsList = [] def find_applications_recursively(app_list, directory, catName): - for item in directory.get_contents(): - if item.get_type() == matemenu.TYPE_ENTRY: + for item in get_contents(directory): + if isinstance(item, MateMenu.TreeEntry): + #print("=======>>> " + str(item.get_name()) + " = " + str(catName)) app_list.append({"entry": item, "category": catName}) - elif item.get_type() == matemenu.TYPE_DIRECTORY: + elif isinstance(item, MateMenu.TreeDirectory): find_applications_recursively(app_list, item, catName) for menu in self.menuFiles: directory = menu.directory - for entry in directory.get_contents(): - if entry.get_type() == matemenu.TYPE_DIRECTORY and len(entry.get_contents()): + for entry in get_contents(directory): + if isinstance(entry, MateMenu.TreeDirectory) and len(get_contents(entry)): #Entry is a top-level category - #catName = entry.name - #icon = str(entry.icon) + #catName = entry.get_name() + #icon = entry.get_icon().to_string() #if (icon == "applications-system" or icon == "applications-other"): # catName = self.adminMenu - for item in entry.get_contents(): - if item.get_type() == matemenu.TYPE_DIRECTORY: - find_applications_recursively(newApplicationsList, item, entry.name) - elif item.get_type() == matemenu.TYPE_ENTRY: - newApplicationsList.append({"entry": item, "category": entry.name}) - #elif entry.get_type() == matemenu.TYPE_ENTRY: + for item in get_contents(entry): + if isinstance(item, MateMenu.TreeDirectory): + find_applications_recursively(newApplicationsList, item, entry.get_name()) + elif isinstance(item, MateMenu.TreeEntry): + newApplicationsList.append( { "entry": item, "category": entry.get_name() } ) + #elif isinstance(entry, MateMenu.TreeEntry): # if not (entry.get_is_excluded() or entry.get_is_nodisplay()): - # print "=======>>> " + item.name + " = top level" - # newApplicationsList.append({"entry": item, "category": ""}) + # print("=======>>> " + item.get_name() + " = top level") + # newApplicationsList.append({"entry": item, "category": ""}) return newApplicationsList diff --git a/usr/lib/linuxmint/mintMenu/plugins/easybuttons.py b/usr/lib/linuxmint/mintMenu/plugins/easybuttons.py index cebd1ea..86a7c21 100755 --- a/usr/lib/linuxmint/mintMenu/plugins/easybuttons.py +++ b/usr/lib/linuxmint/mintMenu/plugins/easybuttons.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 import os.path import shutil @@ -89,7 +89,6 @@ class IconManager(GObject.GObject): image = Gtk.Image.new_from_icon_name(realIconName, Gtk.IconSize.DND) image.set_pixel_size(iconSize) return image - except Exception as e: print("Exception %s: %s" % (e.__class__.__name__, e)) return None @@ -127,7 +126,7 @@ class easyButton(Gtk.Button): if labels: for label in labels: - if isinstance(label, basestring): + if isinstance(label, str): self.addLabel(label) elif isinstance(label, list): self.addLabel(label[0], label[1]) @@ -315,13 +314,7 @@ class ApplicationLauncher(easyButton): return True def strip_accents(self, string): - value = string - if isinstance(string, unicode): - try: - value = string.encode('UTF8', 'ignore') - except: - pass - return value + return string def getTooltip(self): tooltip = self.appName diff --git a/usr/lib/linuxmint/mintMenu/plugins/easygsettings.py b/usr/lib/linuxmint/mintMenu/plugins/easygsettings.py index 96891da..4cac2c9 100644 --- a/usr/lib/linuxmint/mintMenu/plugins/easygsettings.py +++ b/usr/lib/linuxmint/mintMenu/plugins/easygsettings.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 from gi.repository import Gio diff --git a/usr/lib/linuxmint/mintMenu/plugins/execute.py b/usr/lib/linuxmint/mintMenu/plugins/execute.py index 7835f2e..86b8c34 100755 --- a/usr/lib/linuxmint/mintMenu/plugins/execute.py +++ b/usr/lib/linuxmint/mintMenu/plugins/execute.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 import os from gi.repository import Gio diff --git a/usr/lib/linuxmint/mintMenu/plugins/filemonitor.py b/usr/lib/linuxmint/mintMenu/plugins/filemonitor.py index 482d170..f0dd1c2 100755 --- a/usr/lib/linuxmint/mintMenu/plugins/filemonitor.py +++ b/usr/lib/linuxmint/mintMenu/plugins/filemonitor.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 import os import os.path diff --git a/usr/lib/linuxmint/mintMenu/plugins/places.py b/usr/lib/linuxmint/mintMenu/plugins/places.py index a1f795f..68e55d3 100755 --- a/usr/lib/linuxmint/mintMenu/plugins/places.py +++ b/usr/lib/linuxmint/mintMenu/plugins/places.py @@ -1,10 +1,9 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 import gettext import os -import string -from glob import glob -from urllib import unquote +import shutil +from urllib.parse import unquote import gi gi.require_version("Gtk", "3.0") @@ -62,11 +61,14 @@ class pluginclass(object): self.settings.notifyAdd("show-gtk-bookmarks", self.RegenPlugin) self.settings.notifyAdd("height", self.changePluginSize) self.settings.notifyAdd("width", self.changePluginSize) - self.loadSettings() self.content_holder.set_size_request(self.width, self.height) + # Variables + self.trash_info = os.path.join(home, ".local/share/Trash/info") + self.trash_files = os.path.join(home, ".local/share/Trash/files") + def wake(self): if self.showtrash: self.refreshTrash() @@ -186,7 +188,6 @@ class pluginclass(object): self.trashButton.connect("clicked", self.ButtonClicked, "xdg-open trash:") self.trashButton.show() self.trashButton.connect("button-release-event", self.trashPopup) - self.trash_path = os.path.join(home, ".local/share/Trash/info") self.refreshTrash() self.placesBtnHolder.pack_start(self.trashButton, False, False, 0) self.mintMenuWin.setTooltip(self.trashButton, _("Browse deleted files")) @@ -247,8 +248,8 @@ class pluginclass(object): trashMenu.popup(None, None, None, None, 3, 0) def emptyTrash(self, menu, widget): - os.system("rm -rf " + home + "/.local/share/Trash/info/*") - os.system("rm -rf " + home + "/.local/share/Trash/files/*") + shutil.rmtree(self.trash_info) + shutil.rmtree(self.trash_files) self.trashButton.setIcon("user-trash") def ButtonClicked(self, widget, Exec): @@ -262,7 +263,7 @@ class pluginclass(object): self.do_gtk_bookmarks() def refreshTrash(self): - if os.path.exists(self.trash_path) and glob(os.path.join(self.trash_path, "*")): + if os.path.isdir(self.trash_info) and os.listdir(self.trash_info): iconName = "user-trash-full" else: iconName = "user-trash" diff --git a/usr/lib/linuxmint/mintMenu/plugins/recent.py b/usr/lib/linuxmint/mintMenu/plugins/recent.py index 245e85f..e9a6b9b 100755 --- a/usr/lib/linuxmint/mintMenu/plugins/recent.py +++ b/usr/lib/linuxmint/mintMenu/plugins/recent.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 import os import subprocess @@ -173,7 +173,7 @@ class pluginclass: self.Win.hide() try: - subprocess.check_call(["xdg-open", filename]) + subprocess.run(["xdg-open", filename], check=True) except subprocess.CalledProcessError: dialog = Gtk.MessageDialog(self.window, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, _("The file or location could not be opened.")) diff --git a/usr/lib/linuxmint/mintMenu/plugins/recentHelper.py b/usr/lib/linuxmint/mintMenu/plugins/recentHelper.py index 9f3d792..a38eb15 100644 --- a/usr/lib/linuxmint/mintMenu/plugins/recentHelper.py +++ b/usr/lib/linuxmint/mintMenu/plugins/recentHelper.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 import os diff --git a/usr/lib/linuxmint/mintMenu/pointerMonitor.py b/usr/lib/linuxmint/mintMenu/pointerMonitor.py index 7f6292c..bf2ce38 100644 --- a/usr/lib/linuxmint/mintMenu/pointerMonitor.py +++ b/usr/lib/linuxmint/mintMenu/pointerMonitor.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 import threading @@ -56,7 +56,6 @@ class PointerMonitor(GObject.GObject, threading.Thread): pdevice = Gdk.Display.get_default().get_device_manager().get_client_pointer() p = self.get_window().get_device_position(pdevice) g = self.get_size() - if p.x >= 0 and p.y >= 0 and p.x <= g.width and p.y <= g.height: break else: