Advertisement
Guest User

Untitled

a guest
Jul 17th, 2019
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 71.24 KB | None | 0 0
  1. #!/usr/bin/python2
  2.  
  3. import cgi
  4. import filecmp
  5. import gettext
  6. import locale
  7. import os
  8. import subprocess
  9. import threading
  10. import urllib
  11.  
  12. import gi
  13. gi.require_version("Gtk", "3.0")
  14. gi.require_version("MateMenu", "2.0")
  15. from gi.repository import Gtk, Gdk, GdkPixbuf, Gio, GLib, MateMenu
  16.  
  17. import plugins.recentHelper as RecentHelper
  18. from plugins.easybuttons import (ApplicationLauncher, CategoryButton,
  19. FavApplicationLauncher,
  20. MenuApplicationLauncher)
  21.  
  22. # i18n
  23. gettext.install("mintmenu", "/usr/share/linuxmint/locale")
  24. locale.bindtextdomain("mintmenu", "/usr/share/linuxmint/locale")
  25. locale.textdomain("mintmenu")
  26.  
  27. home = os.path.expanduser("~")
  28.  
  29. class PackageDescriptor():
  30. def __init__(self, name, summary, description):
  31. self.name = name
  32. self.summary = summary
  33. self.description = description
  34.  
  35. # import time
  36. # def print_timing(func):
  37. # def wrapper(*arg):
  38. # t1 = time.time()
  39. # res = func(*arg)
  40. # t2 = time.time()
  41. # print('%s took %0.3f ms' % (func.func_name, (t2-t1)*1000.0))
  42. # return res
  43. # return wrapper
  44.  
  45. # Helper function for retrieving the user's location for storing new or modified menu items
  46. def get_user_item_path():
  47. item_dir = None
  48.  
  49. if 'XDG_DATA_HOME' in os.environ:
  50. item_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'applications')
  51. else:
  52. item_dir = os.path.join(home, '.local/share/applications')
  53.  
  54. if not os.path.isdir(item_dir):
  55. os.makedirs(item_dir)
  56.  
  57. return item_dir
  58.  
  59. def get_system_item_paths():
  60. item_dirs = []
  61. if 'XDG_DATA_DIRS' in os.environ:
  62. item_dirs = os.environ['XDG_DATA_DIRS'].split(":")
  63. item_dirs.append(os.path.join('/usr', 'share'))
  64. return item_dirs
  65.  
  66. def rel_path(target, base=os.curdir):
  67. if not os.path.exists(target):
  68. raise OSError("Target does not exist: %s" % target)
  69.  
  70. if not os.path.isdir(base):
  71. raise OSError("Base is not a directory or does not exist: %s" % base)
  72.  
  73. base_list = (os.path.abspath(base)).split(os.sep)
  74. target_list = (os.path.abspath(target)).split(os.sep)
  75.  
  76. for i in range(min(len(base_list), len(target_list))):
  77. if base_list[i] != target_list[i]:
  78. break
  79. else:
  80. i += 1
  81.  
  82. rel_list = [os.pardir] * (len(base_list) - i) + target_list[i:]
  83. return os.path.join(*rel_list)
  84.  
  85. def get_contents(item):
  86. contents = []
  87. item_iter = item.iter()
  88. item_type = item_iter.next()
  89.  
  90. while item_type != MateMenu.TreeItemType.INVALID:
  91. item = None
  92. if item_type == MateMenu.TreeItemType.DIRECTORY:
  93. item = item_iter.get_directory()
  94. elif item_type == MateMenu.TreeItemType.ENTRY:
  95. item = item_iter.get_entry()
  96. elif item_type == MateMenu.TreeItemType.HEADER:
  97. item = item_iter.get_header()
  98. elif item_type == MateMenu.TreeItemType.ALIAS:
  99. item = item_iter.get_alias()
  100. elif item_type == MateMenu.TreeItemType.SEPARATOR:
  101. item = item_iter.get_separator()
  102. if item:
  103. contents.append(item)
  104. item_type = item_iter.next()
  105. return contents
  106.  
  107. class Menu:
  108.  
  109. def __init__(self, MenuToLookup):
  110. self.tree = MateMenu.Tree.new(MenuToLookup, MateMenu.TreeFlags.SORT_DISPLAY_NAME)
  111. self.tree.load_sync()
  112. self.directory = self.tree.get_root_directory()
  113.  
  114. def getMenus(self, parent=None):
  115. if parent == None:
  116. #gives top-level "Applications" item
  117. yield self.tree.root
  118. else:
  119. for menu in get_contents(parent):
  120. if isinstance(menu, MateMenu.TreeDirectory) and self.__isVisible(menu):
  121. yield menu
  122.  
  123. def getItems(self, menu):
  124. for item in get_contents(menu):
  125. if isinstance(item, MateMenu.TreeEntry) and \
  126. item.get_desktop_file_id()[-19:] != '-usercustom.desktop' and \
  127. self.__isVisible(item):
  128. yield item
  129.  
  130. def __isVisible(self, item):
  131. if isinstance(item, MateMenu.TreeEntry):
  132. return not(item.get_is_excluded() or item.get_is_nodisplay())
  133. if isinstance(item, MateMenu.TreeDirectory) and len(get_contents(item)):
  134. return True
  135.  
  136. class SuggestionButton(Gtk.Button):
  137.  
  138. def __init__(self, iconName, iconSize, label):
  139. Gtk.Button.__init__(self)
  140. self.set_relief(Gtk.ReliefStyle.NONE)
  141. self.set_size_request(-1, -1)
  142. Align1 = Gtk.Alignment()
  143. Align1.set(0, 0.5, 1.0, 0)
  144. HBox1 = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
  145. labelBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2)
  146. if iconName.startswith("/"):
  147. self.image = Gtk.Image.new_from_pixbuf(GdkPixbuf.Pixbuf.new_from_file_at_size(iconName, iconSize, iconSize))
  148. else:
  149. self.image = Gtk.Image.new_from_icon_name(iconName, Gtk.IconSize.DIALOG)
  150. self.image.set_pixel_size(iconSize)
  151. HBox1.pack_start(self.image, False, False, 5)
  152. self.label = Gtk.Label()
  153. self.label.set_markup(label)
  154. self.label.set_ellipsize(3)
  155. self.label.set_alignment(0.0, 1.0)
  156. labelBox.pack_start(self.label, True, True, 2)
  157. HBox1.pack_start(labelBox, True, True, 2)
  158. Align1.add(HBox1)
  159. self.add(Align1)
  160. self.show_all()
  161.  
  162. def set_image(self, path):
  163. self.image.set_from_file(path)
  164.  
  165. def set_text(self, text):
  166. self.label.set_markup(text)
  167.  
  168. def set_icon_size (self, size):
  169. self.image.set_pixel_size(size)
  170.  
  171. class pluginclass(object):
  172. TARGET_TYPE_TEXT = 80
  173. toButton = (Gtk.TargetEntry.new("text/uri-list", 0, TARGET_TYPE_TEXT),
  174. Gtk.TargetEntry.new("text/uri-list", 0, TARGET_TYPE_TEXT))
  175. TARGET_TYPE_FAV = 81
  176. toFav = (Gtk.TargetEntry.new("FAVORITES", Gtk.TargetFlags.SAME_APP, 81),
  177. Gtk.TargetEntry.new("text/plain", 0, 100),
  178. Gtk.TargetEntry.new("text/uri-list", 0, 101))
  179. fromFav = (Gtk.TargetEntry.new("FAVORITES", Gtk.TargetFlags.SAME_APP, 81),
  180. Gtk.TargetEntry.new("FAVORITES", Gtk.TargetFlags.SAME_APP, 81))
  181.  
  182. #@print_timing
  183. def __init__(self, mintMenuWin, toggleButton, de):
  184. self.mintMenuWin = mintMenuWin
  185. RecentHelper.mintMenuWin = mintMenuWin
  186. self.mainMenus = []
  187. self.toggleButton = toggleButton
  188. self.menuFiles = []
  189. self.de = de
  190.  
  191. # Detect the locale (this is used for the Wikipedia search)
  192. self.lang = "en"
  193. lang = os.getenv('LANG')
  194. if lang is not None and lang != "":
  195. self.lang = lang.split("_")[0]
  196.  
  197. self.builder = Gtk.Builder()
  198. self.builder.set_translation_domain("mintmenu")
  199. self.builder.add_from_file("/usr/share/linuxmint/mintmenu/applications.ui")
  200.  
  201. # Read GLADE file
  202. self.main_box = self.builder.get_object("main_box")
  203. self.notebook = self.builder.get_object("notebook2")
  204. self.search_bar = self.builder.get_object("search_bar")
  205. self.searchEntry = self.builder.get_object("searchEntry")
  206. self.searchButton = self.builder.get_object("searchButton")
  207. self.showAllAppsButton = self.builder.get_object("showAllAppsButton")
  208. self.showFavoritesButton = self.builder.get_object("showFavoritesButton")
  209. self.applicationsBox = self.builder.get_object("applicationsBox")
  210. self.categoriesBox = self.builder.get_object("categoriesBox")
  211. self.favoritesBox = self.builder.get_object("favoritesBox")
  212. self.applicationsScrolledWindow = self.builder.get_object("applicationsScrolledWindow")
  213.  
  214.  
  215. self.headingstocolor = [self.builder.get_object("label6"), self.builder.get_object("label2")]
  216. self.numApps = 0
  217. # These properties are NECESSARY to maintain consistency
  218.  
  219. # Set 'window' property for the plugin (Must be the root widget)
  220. self.window = self.builder.get_object("mainWindow")
  221.  
  222. # Set 'heading' property for plugin
  223. self.heading = ""#_("Applications")
  224.  
  225. # This should be the first item added to the window in glade
  226. self.content_holder = self.builder.get_object("Applications")
  227.  
  228. # Items to get custom colors
  229. self.itemstocolor = [self.builder.get_object("viewport1"),
  230. self.builder.get_object("viewport2"),
  231. self.builder.get_object("viewport3")]
  232.  
  233. # Unset all timers
  234. self.filterTimer = None
  235. self.menuChangedTimer = None
  236. # Hookup for text input
  237. self.keyPress_handler = self.mintMenuWin.window.connect("key-press-event", self.keyPress)
  238.  
  239. self.favoritesBox.connect("drag-data-received", self.ReceiveCallback)
  240. self.favoritesBox.drag_dest_set(Gtk.DestDefaults.MOTION |
  241. Gtk.DestDefaults.HIGHLIGHT |
  242. Gtk.DestDefaults.DROP,
  243. self.toButton, Gdk.DragAction.COPY)
  244. self.showFavoritesButton.connect("drag-data-received", self.ReceiveCallback)
  245. self.showFavoritesButton.drag_dest_set(Gtk.DestDefaults.MOTION |
  246. Gtk.DestDefaults.HIGHLIGHT |
  247. Gtk.DestDefaults.DROP,
  248. self.toButton, Gdk.DragAction.COPY)
  249.  
  250. # self.searchButton.connect("button_release_event", self.SearchWithButton)
  251. try:
  252. # GSettings stuff
  253. self.settings = Gio.Settings("com.linuxmint.mintmenu.plugins.applications")
  254. self.GetGSettingsEntries()
  255. self.settings.connect("changed::icon-size", self.changeIconSize)
  256. self.settings.connect("changed::favicon-size", self.changeFavIconSize)
  257. self.settings.connect("changed::height", self.changePluginSize)
  258. self.settings.connect("changed::width", self.changePluginSize)
  259. self.settings.connect("changed::categories-mouse-over", self.changeCategoriesMouseOver)
  260. self.settings.connect("changed::swap-generic-name", self.changeSwapGenericName)
  261. self.settings.connect("changed::show-category-icons", self.changeShowCategoryIcons)
  262. self.settings.connect("changed::show-application-comments", self.changeShowApplicationComments)
  263. self.settings.connect("changed::search-on-top", self.positionSearchBar)
  264. self.settings.connect("changed::use-apt", self.switchAPTUsage)
  265. self.settings.connect("changed::fav-cols", self.changeFavCols)
  266. self.settings.connect("changed::remember-filter", self.changeRememberFilter)
  267. self.settings.connect("changed::enable-internet-search", self.changeEnableInternetSearch)
  268. self.settings.connect("changed::category-hover-delay", self.GetGSettingsEntries)
  269. self.settings.connect("changed::do-not-filter", self.GetGSettingsEntries)
  270. self.settings.connect("changed::enable-internet-search", self.GetGSettingsEntries)
  271. self.settings.connect("changed::search-command", self.GetGSettingsEntries)
  272. self.settings.connect("changed::default-tab", self.GetGSettingsEntries)
  273. except Exception as e:
  274. print(e)
  275.  
  276. self.positionSearchBar()
  277.  
  278. self.currentFavCol = 0
  279. self.favorites = []
  280.  
  281. self.content_holder.set_size_request(self.width, self.height)
  282. # Calculate applicationsBox width based on categoryBox width, but since
  283. # we won't have that until the menu has been shown go with an estimate
  284. self.applicationsBox.set_size_request(self.width - 155, -1)
  285. # Add margin for scrollbars to categoriesBox
  286. categoriesScrolledWindow = self.builder.get_object("categoriesScrolledWindow")
  287. scrollbar_width = categoriesScrolledWindow.get_vscrollbar().get_preferred_width()
  288. self.categoriesBox.set_margin_right(scrollbar_width.natural_width + 2)
  289.  
  290. self.buildingButtonList = False
  291. self.stopBuildingButtonList = False
  292.  
  293. self.categoryList = []
  294. self.applicationList = []
  295.  
  296. #dirty ugly hack, to get favorites drag origin position
  297. self.drag_origin = None
  298.  
  299. self.rebuildLock = False
  300. self.activeFilter = (1, "", self.searchEntry)
  301.  
  302. self.adminMenu = None
  303.  
  304. for mainitems in ["mate-applications.menu", "mate-settings.menu"]:
  305. mymenu = Menu(mainitems)
  306. mymenu.tree.connect("changed", self.menuChanged, None)
  307. self.menuFiles.append(mymenu)
  308.  
  309. self.refresh_apt_cache()
  310. self.suggestions = []
  311. self.current_suggestion = None
  312. self.panel = "top"
  313. self.panel_position = -1
  314.  
  315. self.builder.get_object("searchButton").connect("button-press-event", self.searchPopup)
  316.  
  317. # self.icon_theme = Gtk.IconTheme.get_default()
  318. # self.icon_theme.connect("changed", self.on_icon_theme_changed)
  319.  
  320. def refresh_apt_cache(self):
  321. if self.useAPT:
  322. path = "%s/.linuxmint/mintMenu" % home
  323. if not os.path.exists(path):
  324. os.makedirs(path)
  325. subprocess.Popen(["/usr/lib/linuxmint/mintMenu/plugins/get_apt_cache.py", "%s/apt.cache" % path])
  326.  
  327. def get_panel(self):
  328. panelsettings = Gio.Settings.new("org.mate.panel")
  329. applet_list = panelsettings.get_strv("object-id-list")
  330. for applet in applet_list:
  331. object_schema = Gio.Settings.new_with_path("org.mate.panel.object", "/org/mate/panel/objects/%s/" % applet)
  332. keys = object_schema.list_keys()
  333. if "applet-iid" in keys:
  334. iid = object_schema.get_string("applet-iid")
  335. if iid is not None and iid.find("MintMenu") != -1:
  336. self.panel = object_schema.get_string("toplevel-id")
  337. self.panel_position = object_schema.get_int("position") + 1
  338.  
  339. def apturl_install(self, widget, pkg_name):
  340. subprocess.Popen(["xdg-open", "apt://%s" % pkg_name])
  341. # if os.path.exists("/usr/bin/apturl"):
  342. # os.system("/usr/bin/apturl apt://%s &" % pkg_name)
  343. # else:
  344. # os.system("xdg-open apt://" + pkg_name + " &")
  345. self.mintMenuWin.hide()
  346.  
  347. @staticmethod
  348. def wake():
  349. return
  350.  
  351. def destroy(self):
  352. self.content_holder.destroy()
  353. self.searchEntry.destroy()
  354. self.searchButton.destroy()
  355. self.showAllAppsButton.destroy()
  356. self.showFavoritesButton.destroy()
  357. self.applicationsBox.destroy()
  358. self.categoriesBox.destroy()
  359. self.favoritesBox.destroy()
  360.  
  361. self.mintMenuWin.window.disconnect(self.keyPress_handler)
  362.  
  363. def changePluginSize(self, settings, key):
  364. if key == "width":
  365. self.width = settings.get_int(key)
  366. self.applicationsBox.set_size_request(self.width - self.categoriesBox.get_preferred_width().natural_width, -1)
  367.  
  368. elif key == "height":
  369. self.heigth = settings.get_int(key)
  370. self.content_holder.set_size_request(self.width, self.height)
  371.  
  372. def changeSwapGenericName(self, settings, key):
  373. self.swapgeneric = settings.get_boolean(key)
  374.  
  375. for child in self.favoritesBox:
  376. if isinstance(child, FavApplicationLauncher):
  377. child.setSwapGeneric(self.swapgeneric)
  378.  
  379. def changeShowCategoryIcons(self, settings, key):
  380. self.showcategoryicons = settings.get_boolean(key)
  381.  
  382. if self.showcategoryicons:
  383. categoryIconSize = self.iconSize
  384. else:
  385. categoryIconSize = 0
  386.  
  387. for child in self.categoriesBox:
  388. child.setIconSize(categoryIconSize)
  389.  
  390. def changeIconSize(self, settings, key):
  391. self.iconSize = settings.get_int(key)
  392.  
  393. if self.showcategoryicons:
  394. categoryIconSize = self.iconSize
  395. else:
  396. categoryIconSize = 0
  397.  
  398. for child in self.categoriesBox:
  399. child.setIconSize(categoryIconSize)
  400.  
  401. for child in self.applicationsBox:
  402. try:
  403. child.setIconSize(self.iconSize)
  404. except:
  405. pass
  406.  
  407. def changeFavIconSize(self, settings, key):
  408. self.faviconsize = settings.get_int(key)
  409.  
  410. for child in self.favoritesBox:
  411. if isinstance(child, FavApplicationLauncher):
  412. child.setIconSize(self.faviconsize)
  413.  
  414. def positionSearchBar(self, settings=None, key=None):
  415. self.main_box.remove(self.notebook)
  416. self.main_box.remove(self.search_bar)
  417. if self.settings.get_boolean("search-on-top"):
  418. self.main_box.pack_start(self.search_bar, False, False, 0)
  419. self.main_box.pack_start(self.notebook, True, True, 0)
  420. else:
  421. self.main_box.pack_start(self.notebook, True, True, 0)
  422. self.main_box.pack_start(self.search_bar, False, False, 0)
  423.  
  424. def switchAPTUsage(self, settings, key):
  425. self.useAPT = settings.get_boolean(key)
  426. self.refresh_apt_cache()
  427.  
  428. def changeRememberFilter(self, settings, key):
  429. self.rememberFilter = settings.get_boolean(key)
  430.  
  431. def changeEnableInternetSearch(self, settings, key):
  432. self.enableInternetSearch = settings.get_boolean(key)
  433.  
  434. def changeShowApplicationComments(self, settings, key):
  435. self.showapplicationcomments = settings.get_boolean(key)
  436. for child in self.applicationsBox:
  437. child.setShowComment(self.showapplicationcomments)
  438.  
  439. def changeCategoriesMouseOver(self, settings, key):
  440. self.categories_mouse_over = settings.get_boolean(key)
  441. for child in self.categoriesBox:
  442. if self.categories_mouse_over and not child.mouseOverHandlerIds:
  443. startId = child.connect("enter", self.StartFilter, child.filter)
  444. stopId = child.connect("leave", self.StopFilter)
  445. child.mouseOverHandlerIds = (startId, stopId)
  446. elif not self.categories_mouse_over and child.mouseOverHandlerIds:
  447. child.disconnect(child.mouseOverHandlerIds[0])
  448. child.disconnect(child.mouseOverHandlerIds[1])
  449. child.mouseOverHandlerIds = None
  450.  
  451. def changeFavCols(self, settings, key):
  452. self.favCols = settings.get_int(key)
  453. for fav in self.favorites:
  454. self.favoritesBox.remove(fav)
  455. self.favoritesPositionOnGrid(fav)
  456.  
  457. def RegenPlugin(self, *args, **kargs):
  458. self.refresh_apt_cache()
  459.  
  460. # save old config - this is necessary because the app will notified
  461. # when it sets the default values and you don't want the to reload
  462. # itself several times
  463. oldcategories_mouse_over = self.categories_mouse_over
  464. oldiconsize = self.iconSize
  465. oldfaviconsize = self.faviconsize
  466. oldswapgeneric = self.swapgeneric
  467. oldshowcategoryicons = self.showcategoryicons
  468. oldcategoryhoverdelay = self.categoryhoverdelay
  469. oldicon = self.icon
  470. oldhideseparator = self.hideseparator
  471. oldshowapplicationcomments = self.showapplicationcomments
  472.  
  473. self.GetGSettingsEntries()
  474.  
  475. # if the config hasn't changed return
  476. if (oldcategories_mouse_over == self.categories_mouse_over and
  477. oldiconsize == self.iconSize and
  478. oldfaviconsize == self.faviconsize and
  479. oldswapgeneric == self.swapgeneric and
  480. oldshowcategoryicons == self.showcategoryicons and
  481. oldcategoryhoverdelay == self.categoryhoverdelay and
  482. oldicon == self.icon and
  483. oldhideseparator == self.hideseparator and
  484. oldshowapplicationcomments == self.showapplicationcomments
  485. ):
  486. return
  487.  
  488. self.Todos()
  489. self.buildFavorites()
  490. RecentHelper.buildRecentApps()
  491. self.RebuildPlugin()
  492.  
  493. def GetGSettingsEntries(self, settings=None, key=None):
  494.  
  495. self.categories_mouse_over = self.settings.get_boolean("categories-mouse-over")
  496. self.width = self.settings.get_int("width")
  497. self.height = self.settings.get_int("height")
  498. self.donotfilterapps = self.settings.get_boolean("do-not-filter")
  499. self.iconSize = self.settings.get_int("icon-size")
  500. self.faviconsize = self.settings.get_int("favicon-size")
  501. self.favCols = self.settings.get_int("fav-cols")
  502. self.swapgeneric = self.settings.get_boolean("swap-generic-name")
  503. self.showcategoryicons = self.settings.get_boolean("show-category-icons")
  504. self.categoryhoverdelay = self.settings.get_int("category-hover-delay")
  505. self.showapplicationcomments = self.settings.get_boolean("show-application-comments")
  506. self.useAPT = self.settings.get_boolean("use-apt")
  507. self.rememberFilter = self.settings.get_boolean("remember-filter")
  508. self.enableInternetSearch = self.settings.get_boolean("enable-internet-search")
  509.  
  510. self.lastActiveTab = self.settings.get_int("last-active-tab")
  511. self.defaultTab = self.settings.get_int("default-tab")
  512.  
  513. # Search tool
  514. self.searchtool = self.settings.get_string("search-command")
  515. if self.searchtool == "beagle-search SEARCH_STRING":
  516. self.searchtool = "mate-search-tool --named \"%s\" --start"
  517. self.settings.set_string("search-command", "mate-search-tool --named \"%s\" --start")
  518.  
  519. # Plugin icon
  520. self.icon = self.settings.get_string("icon")
  521.  
  522. # Hide vertical dotted separator
  523. self.hideseparator = self.settings.get_boolean("hide-separator")
  524.  
  525. def RebuildPlugin(self):
  526. self.content_holder.set_size_request(self.width, self.height)
  527.  
  528. def checkMintMenuFolder(self):
  529. if os.path.exists(os.path.join(os.path.expanduser("~"), ".linuxmint", "mintMenu", "applications")):
  530. return True
  531. try:
  532. os.makedirs(os.path.join(os.path.expanduser("~"), ".linuxmint", "mintMenu", "applications"))
  533. return True
  534. except:
  535. pass
  536. return False
  537.  
  538. def onShowMenu(self):
  539. if self.favorites:
  540. if self.defaultTab == -1:
  541. self.changeTab(self.lastActiveTab)
  542. else:
  543. self.changeTab((self.defaultTab - 1) * -1)
  544. else:
  545. self.changeTab(1)
  546.  
  547. if self.rememberFilter and self.searchEntry.get_text().strip() != "":
  548. self.Filter(self.activeFilter[2], self.activeFilter[1])
  549.  
  550. def onHideMenu(self):
  551. self.settings.set_int("last-active-tab", self.lastActiveTab)
  552.  
  553. def changeTab(self, tabNum, clear = True):
  554. notebook = self.builder.get_object("notebook2")
  555. if tabNum == 0:
  556. notebook.set_current_page(0)
  557. elif tabNum == 1:
  558. notebook.set_current_page(1)
  559.  
  560. self.focusSearchEntry(clear)
  561. self.lastActiveTab = tabNum
  562.  
  563. def Todos(self):
  564. self.searchEntry.connect("popup-menu", self.blockOnPopup)
  565. self.searchEntry.connect("button-press-event", self.blockOnRightPress)
  566. self.searchEntry.connect("changed", self.Filter)
  567. self.searchEntry.connect("activate", self.Search)
  568. self.showAllAppsButton.connect("clicked", lambda widget: self.changeTab(1))
  569. self.showFavoritesButton.connect("clicked", lambda widget: self.changeTab(0))
  570. self.buildButtonList()
  571.  
  572. def blockOnPopup(self, *args):
  573. self.mintMenuWin.stopHiding()
  574. return False
  575.  
  576. def blockOnRightPress(self, widget, event):
  577. if event.button == 3:
  578. self.mintMenuWin.stopHiding()
  579. return False
  580.  
  581. def focusSearchEntry(self, clear = True):
  582. # grab_focus() does select all text,
  583. # restoring the original selection is somehow broken, so just select the end
  584. # of the existing text, that's the most likely candidate anyhow
  585. self.searchEntry.grab_focus()
  586. if self.rememberFilter or not clear:
  587. self.searchEntry.select_region(0, -1)
  588. else:
  589. self.searchEntry.set_text("")
  590.  
  591. def buildButtonList(self):
  592. if self.buildingButtonList:
  593. self.stopBuildingButtonList = True
  594. GLib.timeout_add(100, self.buildButtonList)
  595. return
  596. self.stopBuildingButtonList = False
  597. self.updateBoxes(False)
  598.  
  599. def categoryBtnFocus(self, widget, event, category):
  600. self.scrollItemIntoView(widget)
  601. self.StartFilter(widget, category)
  602.  
  603. def StartFilter(self, widget, category):
  604. # if there is a timer for a different category running stop it
  605. if self.filterTimer:
  606. GLib.source_remove(self.filterTimer)
  607. self.filterTimer = GLib.timeout_add(self.categoryhoverdelay, self.Filter, widget, category)
  608.  
  609. def StopFilter(self, widget):
  610. if self.filterTimer:
  611. GLib.source_remove(self.filterTimer)
  612. self.filterTimer = None
  613.  
  614. def add_suggestion(self, icon=None, label=None, tooltip=None, callback=None, *args):
  615. if icon:
  616. item = SuggestionButton(icon, self.iconSize, label)
  617. item.connect("clicked", callback, *args)
  618. if tooltip:
  619. item.set_tooltip_text(tooltip)
  620. else:
  621. item = Gtk.SeparatorMenuItem()
  622. item.show_all()
  623. self.applicationsBox.add(item)
  624. self.suggestions.append(item)
  625.  
  626. def add_search_suggestions(self, text):
  627. text = "<b>%s</b>" % cgi.escape(text)
  628. if self.enableInternetSearch:
  629. self.add_suggestion("/usr/lib/linuxmint/mintMenu/search_engines/ddg.svg",
  630. _("Search DuckDuckGo for %s") % text, None, self.search_ddg)
  631. self.add_suggestion("/usr/lib/linuxmint/mintMenu/search_engines/wikipedia.svg",
  632. _("Search Wikipedia for %s") % text, None, self.search_wikipedia)
  633. self.add_suggestion()
  634.  
  635. self.add_suggestion("accessories-dictionary", _("Lookup %s in Dictionary") % text, None,
  636. self.search_dictionary)
  637. self.add_suggestion("edit-find", _("Search Computer for %s") % text, None, self.Search)
  638.  
  639. self.applicationsBox.get_children()[-1].grab_focus()
  640.  
  641. def add_apt_filter_results(self, keyword):
  642. try:
  643. # Wait to see if the keyword has changed.. before doing anything
  644. current_keyword = self.searchEntry.get_text()
  645. if keyword != current_keyword:
  646. return
  647. found_packages = []
  648. found_in_name = []
  649. found_elsewhere = []
  650. keywords = keyword.split(" ")
  651. path = os.path.join(home, ".linuxmint/mintMenu/apt.cache")
  652. if not os.path.isfile(path):
  653. return
  654. with open(path) as aptcache:
  655. pkgs = [line for line in aptcache.readlines() if all(keyword in line for keyword in keywords)]
  656. for pkg in pkgs:
  657. values = pkg.split("###")
  658. if len(values) == 4:
  659. status = values[0]
  660. if status == "ERROR":
  661. print("Could not refresh APT cache")
  662. elif status == "CACHE":
  663. name = values[1]
  664. summary = values[2]
  665. description = values[3].replace("~~~", "\n")
  666. package = PackageDescriptor(name, summary, description)
  667. # See if all keywords are in the name (so we put these results at the top of the list)
  668. some_found = False
  669. some_not_found = False
  670. for word in keywords:
  671. if word in package.name:
  672. some_found = True
  673. else:
  674. some_not_found = True
  675. if some_found and not some_not_found:
  676. found_in_name.append(package)
  677. else:
  678. found_elsewhere.append(package)
  679. else:
  680. print("Invalid status code:",status)
  681. found_packages.extend(found_in_name)
  682. found_packages.extend(found_elsewhere)
  683. if keyword == self.searchEntry.get_text() and len(found_packages) > 0:
  684. self.add_suggestion()
  685. # Reduce the number of results to 10 max...
  686. # it takes a HUGE amount of time to add the GTK box in the menu otherwise..
  687. if len(found_packages) > 10:
  688. found_packages = found_packages[:10]
  689. for pkg in found_packages:
  690. name = pkg.name
  691. for word in keywords:
  692. if word != "":
  693. name = name.replace(word, "<b>%s</b>" % word)
  694. self.add_suggestion("package-x-generic",
  695. _("Install package '%s'") % name,
  696. "%s\n\n%s\n\n%s" % (pkg.name, pkg.summary, pkg.description),
  697. self.apturl_install, pkg.name)
  698. #if cache != self.current_results:
  699. # self.current_results.append(pkg)
  700.  
  701. #if len(found_packages) == 0:
  702. # gtk.gdk.threads_enter()
  703. # try:
  704. # self.applicationsBox.remove(self.last_separator)
  705. # self.suggestions.remove(self.last_separator)
  706. # finally:
  707. # gtk.gdk.threads_leave()
  708.  
  709. except Exception as e:
  710. print(e)
  711.  
  712. def add_apt_filter_results_sync(self, cache, keyword):
  713. try:
  714. found_packages = []
  715. keywords = keyword.split(" ")
  716. if cache is not None:
  717. for pkg in cache:
  718. some_found = False
  719. some_not_found = False
  720. for word in keywords:
  721. if word in pkg.name:
  722. some_found = True
  723. else:
  724. some_not_found = True
  725. if some_found and not some_not_found:
  726. found_packages.append(pkg)
  727.  
  728. if len(found_packages) > 0:
  729. self.add_suggestion()
  730.  
  731. for pkg in found_packages:
  732. name = pkg.name
  733. for word in keywords:
  734. if word != "":
  735. name = name.replace(word, "<b>%s</b>" % word)
  736. self.add_suggestion(Gtk.STOCK_ADD,
  737. _("Install package '%s'") % name,
  738. "%s\n\n%s\n\n%s" % (pkg.name, pkg.summary, pkg.description),
  739. self.apturl_install, pkg.name)
  740.  
  741. #if len(found_packages) == 0:
  742. # self.applicationsBox.remove(self.last_separator)
  743. # self.suggestions.remove(self.last_separator)
  744.  
  745. except Exception as e:
  746. print(e)
  747.  
  748. def Filter(self, widget, category = None):
  749. self.filterTimer = None
  750.  
  751. for suggestion in self.suggestions:
  752. self.applicationsBox.remove(suggestion)
  753. self.suggestions = []
  754.  
  755. if widget == self.searchEntry:
  756. if self.donotfilterapps:
  757. widget.set_text("")
  758. else:
  759. text = widget.get_text()
  760. if self.lastActiveTab != 1:
  761. self.changeTab(1, clear = False)
  762. text = widget.get_text()
  763. showns = False # Are any app shown?
  764. shownList = []
  765. for i in self.applicationsBox.get_children():
  766. shown = i.filterText(text)
  767. if shown:
  768. dupe = False
  769. for item in shownList:
  770. if i.desktopFile == item.desktopFile:
  771. dupe = True
  772. if dupe:
  773. i.hide()
  774. else:
  775. shownList.append(i)
  776. #if this is the first matching item
  777. #focus it
  778. if(not showns):
  779. i.grab_focus()
  780. showns = True
  781. if not showns:
  782. if len(text) >= 3:
  783. self.add_search_suggestions(text)
  784. if self.useAPT:
  785. GLib.timeout_add(300, self.add_apt_filter_results, text)
  786. for i in self.categoriesBox.get_children():
  787. i.released()
  788. i.set_relief(Gtk.ReliefStyle.NONE)
  789.  
  790. allButton = self.categoriesBox.get_children()[0]
  791. allButton.set_relief(Gtk.ReliefStyle.HALF)
  792. self.activeFilter = (0, text, widget)
  793. else:
  794. #print "CATFILTER"
  795. self.activeFilter = (1, category, widget)
  796. if category == "":
  797. listedDesktopFiles = []
  798. for i in self.applicationsBox.get_children():
  799. if not i.desktop_file_path in listedDesktopFiles:
  800. listedDesktopFiles.append(i.desktop_file_path)
  801. i.show_all()
  802. else:
  803. i.hide()
  804. else:
  805. for i in self.applicationsBox.get_children():
  806. i.filterCategory(category)
  807.  
  808. for i in self.categoriesBox.get_children():
  809. i.released()
  810. i.set_relief(Gtk.ReliefStyle.NONE)
  811. widget.set_relief(Gtk.ReliefStyle.HALF)
  812.  
  813. self.applicationsScrolledWindow.get_vadjustment().set_value(0)
  814.  
  815. def FilterAndClear(self, widget, category = None):
  816. self.searchEntry.set_text("")
  817. self.Filter(widget, category)
  818.  
  819. def keyPress(self, widget, event):
  820. """ Forward all text to the search box """
  821. if event.string.strip() or event.keyval == Gdk.KEY_space:
  822. self.searchEntry.event(event)
  823. return True
  824. return False
  825.  
  826. def favPopup(self, widget, event):
  827. if not event.button == 3:
  828. return
  829. if event.y > widget.get_allocation().height / 2:
  830. insertBefore = False
  831. else:
  832. insertBefore = True
  833.  
  834. if widget.type == "location":
  835. mTree = Gtk.Menu()
  836. mTree.set_events(Gdk.EventMask.POINTER_MOTION_MASK |
  837. Gdk.EventMask.POINTER_MOTION_HINT_MASK |
  838. Gdk.EventMask.BUTTON_PRESS_MASK |
  839. Gdk.EventMask.BUTTON_RELEASE_MASK)
  840. #i18n
  841. desktopMenuItem = Gtk.MenuItem(_("Add to desktop"))
  842. panelMenuItem = Gtk.MenuItem(_("Add to panel"))
  843. separator1 = Gtk.SeparatorMenuItem()
  844. insertSpaceMenuItem = Gtk.MenuItem(_("Insert space"))
  845. insertSeparatorMenuItem = Gtk.MenuItem(_("Insert separator"))
  846. separator2 = Gtk.SeparatorMenuItem()
  847. startupMenuItem = Gtk.CheckMenuItem(_("Launch when I log in"))
  848. separator3 = Gtk.SeparatorMenuItem()
  849. launchMenuItem = Gtk.MenuItem(_("Launch"))
  850. removeFromFavMenuItem = Gtk.MenuItem(_("Remove from favorites"))
  851. separator4 = Gtk.SeparatorMenuItem()
  852. propsMenuItem = Gtk.MenuItem(_("Edit properties"))
  853.  
  854. desktopMenuItem.connect("activate", self.add_to_desktop, widget)
  855. panelMenuItem.connect("activate", self.add_to_panel, widget)
  856. insertSpaceMenuItem.connect("activate", self.onFavoritesInsertSpace, widget, insertBefore)
  857. insertSeparatorMenuItem.connect("activate", self.onFavoritesInsertSeparator, widget, insertBefore)
  858. if widget.isInStartup():
  859. startupMenuItem.set_active(True)
  860. startupMenuItem.connect("toggled", self.onRemoveFromStartup, widget)
  861. else:
  862. startupMenuItem.set_active(False)
  863. startupMenuItem.connect("toggled", self.onAddToStartup, widget)
  864. launchMenuItem.connect("activate", self.onLaunchApp, widget)
  865. removeFromFavMenuItem.connect("activate", self.onFavoritesRemove, widget)
  866. propsMenuItem.connect("activate", self.onPropsApp, widget)
  867.  
  868. if self.de == "mate":
  869. mTree.append(desktopMenuItem)
  870. mTree.append(panelMenuItem)
  871. mTree.append(separator1)
  872. mTree.append(insertSpaceMenuItem)
  873. mTree.append(insertSeparatorMenuItem)
  874. mTree.append(separator2)
  875. mTree.append(startupMenuItem)
  876. mTree.append(separator3)
  877. mTree.append(launchMenuItem)
  878. mTree.append(removeFromFavMenuItem)
  879. mTree.append(separator4)
  880. mTree.append(propsMenuItem)
  881. else:
  882. mTree = Gtk.Menu()
  883. mTree.set_events(Gdk.EventMask.POINTER_MOTION_MASK |
  884. Gdk.EventMask.POINTER_MOTION_HINT_MASK |
  885. Gdk.EventMask.BUTTON_PRESS_MASK |
  886. Gdk.EventMask.BUTTON_RELEASE_MASK)
  887.  
  888. #i18n
  889. removeMenuItem = Gtk.MenuItem(_("Remove"))
  890. insertSpaceMenuItem = Gtk.MenuItem(_("Insert space"))
  891. insertSeparatorMenuItem = Gtk.MenuItem(_("Insert separator"))
  892. mTree.append(removeMenuItem)
  893. mTree.append(insertSpaceMenuItem)
  894. mTree.append(insertSeparatorMenuItem)
  895.  
  896. removeMenuItem.connect("activate", self.onFavoritesRemove, widget)
  897. insertSpaceMenuItem.connect("activate", self.onFavoritesInsertSpace, widget, insertBefore)
  898. insertSeparatorMenuItem.connect("activate", self.onFavoritesInsertSeparator, widget, insertBefore)
  899. mTree.show_all()
  900. self.mintMenuWin.stopHiding()
  901. mTree.attach_to_widget(widget, None)
  902. if (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION) >= (3, 22):
  903. mTree.popup_at_pointer(event)
  904. else:
  905. mTree.popup(None, None, None, None, event.button, event.time)
  906.  
  907. def menuPopup(self, widget, event):
  908. if not event.button == 3:
  909. return
  910. mTree = Gtk.Menu()
  911. #i18n
  912. desktopMenuItem = Gtk.MenuItem(_("Add to desktop"))
  913. panelMenuItem = Gtk.MenuItem(_("Add to panel"))
  914. separator1 = Gtk.SeparatorMenuItem()
  915. favoriteMenuItem = Gtk.CheckMenuItem(_("Show in my favorites"))
  916. startupMenuItem = Gtk.CheckMenuItem(_("Launch when I log in"))
  917. separator2 = Gtk.SeparatorMenuItem()
  918. launchMenuItem = Gtk.MenuItem(_("Launch"))
  919. uninstallMenuItem = Gtk.MenuItem(_("Uninstall"))
  920. deleteMenuItem = Gtk.MenuItem(_("Delete from menu"))
  921. separator3 = Gtk.SeparatorMenuItem()
  922. propsMenuItem = Gtk.MenuItem(_("Edit properties"))
  923.  
  924. if self.de == "mate":
  925. mTree.append(desktopMenuItem)
  926. mTree.append(panelMenuItem)
  927. mTree.append(separator1)
  928.  
  929. mTree.append(favoriteMenuItem)
  930. mTree.append(startupMenuItem)
  931. mTree.append(separator2)
  932. mTree.append(launchMenuItem)
  933. mTree.append(uninstallMenuItem)
  934. if home in widget.desktopFile:
  935. mTree.append(deleteMenuItem)
  936. deleteMenuItem.connect("activate", self.delete_from_menu, widget)
  937. mTree.append(separator3)
  938. mTree.append(propsMenuItem)
  939. mTree.show_all()
  940.  
  941. desktopMenuItem.connect("activate", self.add_to_desktop, widget)
  942. panelMenuItem.connect("activate", self.add_to_panel, widget)
  943. launchMenuItem.connect("activate", self.onLaunchApp, widget)
  944. propsMenuItem.connect("activate", self.onPropsApp, widget)
  945. uninstallMenuItem.connect("activate", self.onUninstallApp, widget)
  946.  
  947. if self.isLocationInFavorites(widget.desktopFile):
  948. favoriteMenuItem.set_active(True)
  949. favoriteMenuItem.connect("toggled", self.onRemoveFromFavorites, widget)
  950. else:
  951. favoriteMenuItem.set_active(False)
  952. favoriteMenuItem.connect("toggled", self.onAddToFavorites, widget)
  953.  
  954. if widget.isInStartup():
  955. startupMenuItem.set_active(True)
  956. startupMenuItem.connect("toggled", self.onRemoveFromStartup, widget)
  957. else:
  958. startupMenuItem.set_active(False)
  959. startupMenuItem.connect("toggled", self.onAddToStartup, widget)
  960.  
  961. self.mintMenuWin.stopHiding()
  962. mTree.attach_to_widget(widget, None)
  963. mTree.popup(None, None, None, None, event.button, event.time)
  964.  
  965. def searchPopup(self, widget, event):
  966. def add_menu_item(icon=None, text=None, callback=None):
  967. box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
  968. if icon == None:
  969. menuItem = Gtk.SeparatorMenuItem()
  970. else:
  971. if icon.startswith("/"):
  972. icon = Gtk.Image.new_from_pixbuf(GdkPixbuf.Pixbuf.new_from_file_at_size(icon, 16, 16))
  973. else:
  974. icon = Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.SMALL_TOOLBAR)
  975. box.add(icon)
  976. box.pack_start(Gtk.Label.new(text), False, False, 5)
  977. menuItem = Gtk.MenuItem()
  978. menuItem.connect("activate", callback)
  979. menuItem.add(box)
  980. menu.append(menuItem)
  981.  
  982. menu = Gtk.Menu()
  983.  
  984. if self.enableInternetSearch:
  985. add_menu_item('/usr/lib/linuxmint/mintMenu/search_engines/ddg.svg', _("Search DuckDuckGo"), self.search_ddg)
  986. add_menu_item('/usr/lib/linuxmint/mintMenu/search_engines/wikipedia.svg', _("Search Wikipedia"), self.search_wikipedia)
  987.  
  988. add_menu_item('accessories-dictionary', _("Search Dictionary"), self.search_dictionary)
  989. add_menu_item("edit-find", _("Search Computer"), self.Search)
  990. add_menu_item()
  991. add_menu_item('/usr/lib/linuxmint/mintMenu/search_engines/software.png', _("Find Software"), self.search_mint_software)
  992. add_menu_item('/usr/lib/linuxmint/mintMenu/search_engines/tutorials.png', _("Find Tutorials"), self.search_mint_tutorials)
  993. add_menu_item('/usr/lib/linuxmint/mintMenu/search_engines/hardware.png', _("Find Hardware"), self.search_mint_hardware)
  994. add_menu_item('/usr/lib/linuxmint/mintMenu/search_engines/ideas.png', _("Find Ideas"), self.search_mint_ideas)
  995. add_menu_item('/usr/lib/linuxmint/mintMenu/search_engines/users.png', _("Find Users"), self.search_mint_users)
  996.  
  997. menu.show_all()
  998.  
  999. self.mintMenuWin.stopHiding()
  1000. menu.attach_to_widget(self.searchButton, None)
  1001. menu.popup(None, None, None, None, event.button, event.time)
  1002.  
  1003. self.focusSearchEntry(clear = False)
  1004.  
  1005. def search_ddg(self, widget):
  1006. text = urllib.quote_plus(self.searchEntry.get_text().strip())
  1007. subprocess.Popen(["xdg-open", "https://duckduckgo.com/?q=%s" % text])
  1008. self.mintMenuWin.hide()
  1009.  
  1010. def search_google(self, widget):
  1011. text = urllib.quote_plus(self.searchEntry.get_text().strip())
  1012. subprocess.Popen(["xdg-open", "https://www.google.com/search?q=%s" % text])
  1013. self.mintMenuWin.hide()
  1014.  
  1015. def search_wikipedia(self, widget):
  1016. text = urllib.quote_plus(self.searchEntry.get_text().strip())
  1017. subprocess.Popen(["xdg-open", "https://en.wikipedia.org/wiki/Special:Search?search=%s" % text])
  1018. self.mintMenuWin.hide()
  1019.  
  1020. def search_dictionary(self, widget):
  1021. text = self.searchEntry.get_text().strip()
  1022. subprocess.Popen(["mate-dictionary", "%s" % text])
  1023. self.mintMenuWin.hide()
  1024.  
  1025. def search_mint_tutorials(self, widget):
  1026. text = urllib.quote(self.searchEntry.get_text().strip())
  1027. subprocess.Popen(["xdg-open", "https://community.linuxmint.com/index.php/tutorial/search/0/%s" % text])
  1028. self.mintMenuWin.hide()
  1029.  
  1030. def search_mint_ideas(self, widget):
  1031. text = urllib.quote(self.searchEntry.get_text().strip())
  1032. subprocess.Popen(["xdg-open", "https://community.linuxmint.com/index.php/idea/search/0/%s" % text])
  1033. self.mintMenuWin.hide()
  1034.  
  1035. def search_mint_users(self, widget):
  1036. text = urllib.quote(self.searchEntry.get_text().strip())
  1037. subprocess.Popen(["xdg-open", "https://community.linuxmint.com/index.php/user/search/0/%s" % text])
  1038. self.mintMenuWin.hide()
  1039.  
  1040. def search_mint_hardware(self, widget):
  1041. text = urllib.quote(self.searchEntry.get_text().strip())
  1042. subprocess.Popen(["xdg-open", "https://community.linuxmint.com/index.php/hardware/search/0/%s" % text])
  1043. self.mintMenuWin.hide()
  1044.  
  1045. def search_mint_software(self, widget):
  1046. text = urllib.quote(self.searchEntry.get_text())
  1047. subprocess.Popen(["xdg-open", "https://community.linuxmint.com/index.php/software/search/0/%s" % text])
  1048. self.mintMenuWin.hide()
  1049.  
  1050. def add_to_desktop(self, widget, desktopEntry):
  1051. subprocess.Popen(["xdg-desktop-icon", "install", "--novendor", desktopEntry.desktopFile])
  1052.  
  1053. def add_to_panel(self, widget, desktopEntry):
  1054. self.get_panel()
  1055. i = 0
  1056. panel_schema = Gio.Settings.new("org.mate.panel")
  1057. applet_list = panel_schema.get_strv("object-id-list")
  1058.  
  1059. while True:
  1060. test_obj = "object_%d" % i
  1061. if test_obj in applet_list:
  1062. i += 1
  1063. else:
  1064. break
  1065.  
  1066. path = "/org/mate/panel/objects/%s/" % test_obj
  1067. new_schema = Gio.Settings.new_with_path("org.mate.panel.object", path)
  1068. new_schema.set_string("launcher-location", desktopEntry.desktopFile)
  1069. new_schema.set_string("object-type", "launcher")
  1070. new_schema.set_string("toplevel-id", self.panel)
  1071. new_schema.set_int("position", self.panel_position)
  1072. applet_list.append(test_obj)
  1073. panel_schema.set_strv("object-id-list", applet_list)
  1074.  
  1075. def delete_from_menu(self, widget, desktopEntry):
  1076. try:
  1077. os.unlink(desktopEntry.desktopFile)
  1078. except Exception as e:
  1079. print(e)
  1080.  
  1081. def onLaunchApp(self, menu, widget):
  1082. widget.execute()
  1083. self.mintMenuWin.hide()
  1084.  
  1085. def onPropsApp(self, menu, widget):
  1086. newFileFlag = False
  1087. sysPaths = get_system_item_paths()
  1088.  
  1089. for path in sysPaths:
  1090. path = os.path.join(path, "applications")
  1091. relPath = os.path.relpath(widget.desktopFile, path)
  1092.  
  1093. if widget.desktopFile == os.path.join(path, relPath):
  1094. filePath = os.path.join(get_user_item_path(), relPath)
  1095. (head,tail) = os.path.split(filePath)
  1096.  
  1097. if not os.path.isdir(head):
  1098. os.makedirs(head)
  1099.  
  1100. if not os.path.isfile(filePath):
  1101. data = open(widget.desktopFile).read()
  1102. open(filePath, 'w').write(data)
  1103. newFileFlag = True
  1104. break
  1105.  
  1106. else:
  1107. filePath = widget.desktopFile
  1108.  
  1109. self.mintMenuWin.hide()
  1110. Gdk.flush()
  1111.  
  1112. editProcess = subprocess.Popen(["/usr/bin/mate-desktop-item-edit", filePath])
  1113. subprocess.Popen.communicate(editProcess)
  1114.  
  1115. if newFileFlag:
  1116. if filecmp.cmp(widget.desktopFile, filePath):
  1117. os.remove(filePath)
  1118. else:
  1119. favoriteChange = 0
  1120. for favorite in self.favorites:
  1121. if favorite.type == "location":
  1122. if favorite.desktopFile == widget.desktopFile:
  1123. favorite.desktopFile = filePath
  1124. favoriteChange = 1
  1125. if favoriteChange == 1:
  1126. self.favoritesSave()
  1127. self.buildFavorites()
  1128. else:
  1129. self.buildFavorites()
  1130.  
  1131. def onUninstallApp(self, menu, widget):
  1132. widget.uninstall()
  1133. self.mintMenuWin.hide()
  1134.  
  1135. def onFavoritesInsertSpace(self, menu, widget, insertBefore):
  1136. if insertBefore:
  1137. self.favoritesAdd(self.favoritesBuildSpace(), widget.position)
  1138. else:
  1139. self.favoritesAdd(self.favoritesBuildSpace(), widget.position + 1)
  1140.  
  1141. def onFavoritesInsertSeparator(self, menu, widget, insertBefore):
  1142. if insertBefore:
  1143. self.favoritesAdd(self.favoritesBuildSeparator(), widget.position)
  1144. else:
  1145. self.favoritesAdd(self.favoritesBuildSeparator(), widget.position + 1)
  1146.  
  1147. def onFavoritesRemove(self, menu, widget):
  1148. self.favoritesRemove(widget.position)
  1149.  
  1150. def onAddToStartup(self, menu, widget):
  1151. widget.addToStartup()
  1152.  
  1153. def onRemoveFromStartup(self, menu, widget):
  1154. widget.removeFromStartup()
  1155.  
  1156. def onAddToFavorites(self, menu, widget):
  1157. self.favoritesAdd(self.favoritesBuildLauncher(widget.desktopFile))
  1158.  
  1159. def onRemoveFromFavorites(self, menu, widget):
  1160. self.favoritesRemoveLocation(widget.desktopFile)
  1161.  
  1162. def ReceiveCallback(self, widget, context, x, y, selection, targetType, time):
  1163. if targetType == self.TARGET_TYPE_TEXT:
  1164. for uri in selection.get_uris():
  1165. self.favoritesAdd(self.favoritesBuildLauncher(uri))
  1166.  
  1167. def Search(self, widget):
  1168. text = self.searchEntry.get_text().strip()
  1169. if text != "":
  1170. for app_button in self.applicationsBox.get_children():
  1171. if(isinstance(app_button, ApplicationLauncher) and app_button.filterText(text)):
  1172. app_button.execute()
  1173. self.mintMenuWin.hide()
  1174. return
  1175.  
  1176. self.mintMenuWin.hide()
  1177. fullstring = self.searchtool.replace("%s", text)
  1178. os.system(fullstring + " &")
  1179.  
  1180. def SearchWithButton(self, widget, event):
  1181. self.Search(widget)
  1182.  
  1183. def do_plugin(self):
  1184. self.Todos()
  1185. self.buildFavorites()
  1186.  
  1187. # Scroll button into view
  1188. def scrollItemIntoView(self, widget, event = None):
  1189. viewport = widget.get_parent()
  1190. while not isinstance(viewport, Gtk.Viewport):
  1191. if not viewport.get_parent():
  1192. return
  1193. viewport = viewport.get_parent()
  1194. aloc = widget.get_allocation()
  1195. viewport.get_vadjustment().clamp_page(aloc.y, aloc.y + aloc.height)
  1196.  
  1197. def favoritesBuildSpace(self):
  1198. space = Gtk.EventBox()
  1199. space.set_size_request(-1, 20)
  1200. space.set_visible_window(False)
  1201. space.connect("button-press-event", self.favPopup)
  1202. space.type = "space"
  1203. space.show()
  1204. return space
  1205.  
  1206. def favoritesBuildSeparator(self):
  1207. separator = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)
  1208. separator.set_margin_top(5)
  1209. separator.set_margin_bottom(5)
  1210. separator.type = "separator"
  1211.  
  1212. separator.show_all()
  1213. box = Gtk.EventBox()
  1214. box.type = "separator"
  1215. box.add(separator)
  1216. box.set_visible_window(False)
  1217. box.connect("button-press-event", self.favPopup)
  1218. box.show_all()
  1219. return box
  1220.  
  1221. def favoritesBuildLauncher(self, location):
  1222. try:
  1223. # For Folders and Network Shares
  1224. location = "".join(location.split("%20"))
  1225.  
  1226. # TODO: Do we still need this?
  1227. #For Special locations
  1228. if location == "x-nautilus-desktop:///computer":
  1229. location = "/usr/share/applications/nautilus-computer.desktop"
  1230. elif location == "x-nautilus-desktop:///home":
  1231. location = "/usr/share/applications/nautilus-home.desktop"
  1232. elif location == "x-nautilus-desktop:///network":
  1233. location = "/usr/share/applications/network-scheme.desktop"
  1234. elif location.startswith("x-nautilus-desktop:///"):
  1235. location = "/usr/share/applications/nautilus-computer.desktop"
  1236.  
  1237. if location.startswith("file://"):
  1238. location = location[7:]
  1239.  
  1240. # Don't add a location twice
  1241. for fav in self.favorites:
  1242. if fav.type == "location" and fav.desktopFile == location:
  1243. return None
  1244.  
  1245. favButton = FavApplicationLauncher(location, self.faviconsize, self.swapgeneric)
  1246. if favButton.appExec:
  1247. favButton.show()
  1248. favButton.connect("popup-menu", self.favPopup)
  1249. favButton.connect("button-press-event", self.favPopup)
  1250. favButton.connect("focus-in-event", self.scrollItemIntoView)
  1251. favButton.connect("clicked", RecentHelper.applicationButtonClicked)
  1252.  
  1253. self.mintMenuWin.setTooltip(favButton, favButton.getTooltip())
  1254. favButton.type = "location"
  1255. return favButton
  1256. except Exception as e:
  1257. print("File in favorites not found: '%s': %s" % (location, e))
  1258.  
  1259. return None
  1260.  
  1261. def buildFavorites(self):
  1262. try:
  1263. path = os.path.join(home, ".linuxmint/mintMenu/applications.list")
  1264. if os.path.isdir(path):
  1265. # dir created by a bug in mint 19.2 beta
  1266. os.system("rm -rf %s" % path)
  1267. if not os.path.exists(path):
  1268. os.system("mkdir -p ~/.linuxmint/mintMenu")
  1269. os.system("cp /usr/lib/linuxmint/mintMenu/applications.list " + path)
  1270.  
  1271. applicationsList = open(path).readlines()
  1272.  
  1273. self.favorites = []
  1274.  
  1275. for child in self.favoritesBox:
  1276. child.destroy()
  1277.  
  1278. position = 0
  1279.  
  1280. for app in applicationsList :
  1281. app = app.strip()
  1282.  
  1283. if app[0:9] == "location:":
  1284. favButton = self.favoritesBuildLauncher(app[9:])
  1285. elif app == "space":
  1286. favButton = self.favoritesBuildSpace()
  1287. elif app == "separator":
  1288. favButton = self.favoritesBuildSeparator()
  1289. else:
  1290. if app.endswith(".desktop"):
  1291. favButton = self.favoritesBuildLauncher(app)
  1292. else:
  1293. favButton = None
  1294.  
  1295. if favButton:
  1296. favButton.position = position
  1297. self.favorites.append(favButton)
  1298. self.favoritesPositionOnGrid(favButton)
  1299. favButton.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, self.toFav, Gdk.DragAction.COPY)
  1300. favButton.drag_dest_set(Gtk.DestDefaults.MOTION |
  1301. Gtk.DestDefaults.HIGHLIGHT |
  1302. Gtk.DestDefaults.DROP,
  1303. self.toFav, Gdk.DragAction.COPY)
  1304. favButton.connect("drag-data-get", self.on_drag_data_get)
  1305. favButton.connect("drag-data-received", self.on_drag_data_received)
  1306. position += 1
  1307.  
  1308. self.favoritesSave()
  1309. except Exception as e:
  1310. print(e)
  1311.  
  1312. def favoritesPositionOnGrid(self, favorite):
  1313. row = 0
  1314. col = 0
  1315. for fav in self.favorites:
  1316. if (fav.type == "separator" or fav.type == "space") and col != 0:
  1317. row += 1
  1318. col = 0
  1319. if fav.position == favorite.position:
  1320. break
  1321. col += 1
  1322. if fav.type == "separator" or fav.type == "space":
  1323. row += 1
  1324. col = 0
  1325. if col >= self.favCols:
  1326. row += 1
  1327. col = 0
  1328.  
  1329. if favorite.type == "separator" or favorite.type == "space":
  1330. self.favoritesBox.attach(favorite, col, row, self.favCols, 1)
  1331. else:
  1332. self.favoritesBox.attach(favorite, col, row, 1, 1)
  1333.  
  1334. def favoritesReorder(self, oldposition, newposition):
  1335. if oldposition == newposition:
  1336. return
  1337. tmp = self.favorites[oldposition]
  1338. if newposition > oldposition:
  1339. if (self.favorites[newposition - 1].type == "space" or
  1340. self.favorites[newposition - 1].type == "separator") and self.favCols > 1:
  1341. newposition = newposition - 1
  1342. for i in range(oldposition, newposition):
  1343. self.favorites[i] = self.favorites[i + 1]
  1344. self.favorites[i].position = i
  1345. elif newposition < oldposition:
  1346. for i in range(0, oldposition - newposition):
  1347. self.favorites[oldposition - i] = self.favorites[oldposition - i - 1]
  1348. self.favorites[oldposition - i] .position = oldposition - i
  1349. self.favorites[newposition] = tmp
  1350. self.favorites[newposition].position = newposition
  1351.  
  1352. for fav in self.favorites:
  1353. self.favoritesBox.remove(fav)
  1354. self.favoritesPositionOnGrid(fav)
  1355.  
  1356. self.favoritesSave()
  1357.  
  1358. def favoritesAdd(self, favButton, position = -1):
  1359. if favButton:
  1360. favButton.position = len(self.favorites)
  1361. self.favorites.append(favButton)
  1362. self.favoritesPositionOnGrid(favButton)
  1363.  
  1364. favButton.connect("drag-data-received", self.on_drag_data_received)
  1365. favButton.drag_dest_set(Gtk.DestDefaults.MOTION |
  1366. Gtk.DestDefaults.HIGHLIGHT |
  1367. Gtk.DestDefaults.DROP,
  1368. self.toFav, Gdk.DragAction.COPY)
  1369. favButton.connect("drag-data-get", self.on_drag_data_get)
  1370. favButton.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, self.toFav, Gdk.DragAction.COPY)
  1371.  
  1372. if position >= 0:
  1373. self.favoritesReorder(favButton.position, position)
  1374.  
  1375. self.favoritesSave()
  1376.  
  1377. def favoritesRemove(self, position):
  1378. tmp = self.favorites[position]
  1379. self.favorites.remove(self.favorites[position])
  1380. tmp.destroy()
  1381.  
  1382. for i in range(position, len(self.favorites)):
  1383. self.favorites[i].position = i
  1384. self.favoritesBox.remove(self.favorites[i])
  1385. self.favoritesPositionOnGrid(self.favorites[i])
  1386. self.favoritesSave()
  1387.  
  1388. def favoritesRemoveLocation(self, location):
  1389. for fav in self.favorites:
  1390. if fav.type == "location" and fav.desktopFile == location:
  1391. self.favoritesRemove(fav.position)
  1392.  
  1393. def favoritesSave(self):
  1394. try:
  1395. self.checkMintMenuFolder()
  1396. with open(os.path.join(home, ".linuxmint/mintMenu/applications.list") , "w") as appListFile:
  1397. for favorite in self.favorites:
  1398. if favorite.type == "location":
  1399. appListFile.write("location:" + favorite.desktopFile + "\n")
  1400. else:
  1401. appListFile.write(favorite.type + "\n")
  1402. except Exception as e:
  1403. msgDlg = Gtk.MessageDialog(None, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK,
  1404. _("Couldn't save favorites. Check if you have write access to ~/.linuxmint/mintMenu") +
  1405. "\n(" + e.__str__() + ")")
  1406. msgDlg.run()
  1407. msgDlg.destroy()
  1408.  
  1409. def isLocationInFavorites(self, location):
  1410. for fav in self.favorites:
  1411. if fav.type == "location" and fav.desktopFile == location:
  1412. return True
  1413. return False
  1414.  
  1415. def on_drag_data_get(self, widget, context, selection, info, time):
  1416. if info == self.TARGET_TYPE_FAV:
  1417. self.drag_origin = widget.position
  1418. # FIXME: This fails in python3:
  1419. selection.set(selection.get_target(), 8, str(widget.position))
  1420.  
  1421. def on_drag_data_received(self, widget, context, x, y, selection, info, time):
  1422. if info == self.TARGET_TYPE_FAV:
  1423. self.favoritesReorder(int(selection.get_data()), widget.position)
  1424.  
  1425. # def on_icon_theme_changed(self, theme):
  1426. # print("on_icon_theme_changed")
  1427. # self.menuChanged(0, 0)
  1428.  
  1429. def menuChanged(self, x, y):
  1430. # print("menuChanged")
  1431. # wait 1s, to avoid building the menu multiple times concurrently
  1432. if self.menuChangedTimer:
  1433. GLib.source_remove(self.menuChangedTimer)
  1434.  
  1435. self.menuChangedTimer = GLib.timeout_add(1000, self.updateBoxes, True)
  1436.  
  1437. #@print_timing
  1438. def updateBoxes(self, menu_has_changed):
  1439. # print("updateBoxes")
  1440. # FIXME: This is really bad!
  1441. if self.rebuildLock:
  1442. return
  1443.  
  1444. self.rebuildLock = True
  1445. self.menuChangedTimer = None
  1446.  
  1447. try:
  1448. self.loadMenuFiles()
  1449.  
  1450. # Find added and removed categories than update the category list
  1451. newCategoryList = self.buildCategoryList()
  1452. addedCategories = []
  1453. removedCategories = []
  1454.  
  1455. # TODO: optimize this!!!
  1456. if not self.categoryList:
  1457. addedCategories = newCategoryList
  1458. else:
  1459. for item in newCategoryList:
  1460. found = False
  1461. for item2 in self.categoryList:
  1462. pass
  1463. if (item["name"] == item2["name"] and
  1464. item["icon"] == item2["icon"] and
  1465. item["tooltip"] == item2["tooltip"] and
  1466. item["index"] == item2["index"]
  1467. ):
  1468. found = True
  1469. break
  1470. if not found:
  1471. addedCategories.append(item)
  1472.  
  1473. for item in self.categoryList:
  1474. found = False
  1475. for item2 in newCategoryList:
  1476. if (item["name"] == item2["name"] and
  1477. item["icon"] == item2["icon"] and
  1478. item["tooltip"] == item2["tooltip"] and
  1479. item["index"] == item2["index"]
  1480. ):
  1481. found = True
  1482. break
  1483. if not found:
  1484. removedCategories.append(item)
  1485.  
  1486. if self.showcategoryicons:
  1487. categoryIconSize = self.iconSize
  1488. else:
  1489. categoryIconSize = 0
  1490.  
  1491. for item in removedCategories:
  1492. try:
  1493. button = item["button"]
  1494. self.categoryList.remove(item)
  1495. button.destroy()
  1496. del item
  1497. except Exception as e:
  1498. print(e)
  1499.  
  1500. if addedCategories:
  1501. sortedCategoryList = []
  1502. for item in self.categoryList:
  1503. try:
  1504. self.categoriesBox.remove(item["button"])
  1505. sortedCategoryList.append((str(item["index"]) + item["name"], item["button"]))
  1506. except Exception as e:
  1507. print(e)
  1508.  
  1509. # Create new category buttons and add them to the list
  1510. for item in addedCategories:
  1511. try:
  1512. item["button"] = CategoryButton(item["icon"], categoryIconSize, [item["name"]], item["filter"])
  1513.  
  1514. if self.categories_mouse_over:
  1515. startId = item["button"].connect("enter", self.StartFilter, item["filter"])
  1516. stopId = item["button"].connect("leave", self.StopFilter)
  1517. item["button"].mouseOverHandlerIds = (startId, stopId)
  1518. else:
  1519. item["button"].mouseOverHandlerIds = None
  1520.  
  1521. item["button"].connect("clicked", self.FilterAndClear, item["filter"])
  1522. item["button"].connect("focus-in-event", self.categoryBtnFocus, item["filter"])
  1523. item["button"].show()
  1524.  
  1525. self.categoryList.append(item)
  1526. sortedCategoryList.append((str(item["index"]) + item["name"], item["button"]))
  1527. except Exception as e:
  1528. print(e)
  1529.  
  1530. sortedCategoryList.sort()
  1531.  
  1532. for item in sortedCategoryList:
  1533. try:
  1534. self.categoriesBox.pack_start(item[1], False, False, 0)
  1535. except Exception as e:
  1536. print(e)
  1537.  
  1538. # Find added and removed applications add update the application list
  1539. newApplicationList = self.buildApplicationList()
  1540. addedApplications = []
  1541. removedApplications = []
  1542.  
  1543. # TODO: optimize this!!!
  1544. if not self.applicationList:
  1545. addedApplications = newApplicationList
  1546. else:
  1547. for item in newApplicationList:
  1548. found = False
  1549. for item2 in self.applicationList:
  1550. if item["entry"].get_desktop_file_path() == item2["entry"].get_desktop_file_path():
  1551. found = True
  1552. break
  1553. if not found:
  1554. addedApplications.append(item)
  1555.  
  1556. key = 0
  1557. for item in self.applicationList:
  1558. found = False
  1559. for item2 in newApplicationList:
  1560. if item["entry"].get_desktop_file_path() == item2["entry"].get_desktop_file_path():
  1561. found = True
  1562. break
  1563. if not found:
  1564. removedApplications.append(key)
  1565. else:
  1566. # don't increment the key if this item is going to be removed
  1567. # because when it is removed the index of all later items is
  1568. # going to be decreased
  1569. key += 1
  1570.  
  1571. for key in removedApplications:
  1572. self.applicationList[key]["button"].destroy()
  1573. del self.applicationList[key]
  1574. if addedApplications:
  1575. sortedApplicationList = []
  1576. for item in self.applicationList:
  1577. self.applicationsBox.remove(item["button"])
  1578. sortedApplicationList.append((item["button"].appName, item["button"]))
  1579. for item in addedApplications:
  1580. item["button"] = MenuApplicationLauncher(item["entry"].get_desktop_file_path(),
  1581. self.iconSize, item["category"], self.showapplicationcomments,
  1582. highlight=(True and menu_has_changed))
  1583. if item["button"].appExec:
  1584. self.mintMenuWin.setTooltip(item["button"], item["button"].getTooltip())
  1585. item["button"].connect("button-press-event", self.menuPopup)
  1586. item["button"].connect("focus-in-event", self.scrollItemIntoView)
  1587. item["button"].connect("clicked", RecentHelper.applicationButtonClicked)
  1588. if self.activeFilter[0] == 0:
  1589. item["button"].filterText(self.activeFilter[1])
  1590. else:
  1591. item["button"].filterCategory(self.activeFilter[1])
  1592. item["button"].desktop_file_path = item["entry"].get_desktop_file_path()
  1593. sortedApplicationList.append((item["button"].appName.upper(), item["button"]))
  1594. self.applicationList.append(item)
  1595. else:
  1596. item["button"].destroy()
  1597.  
  1598. sortedApplicationList.sort()
  1599. launcherNames = [] # Keep track of launcher names so we don't add them twice in the list..
  1600. for item in sortedApplicationList:
  1601. launcherName = item[0]
  1602. button = item[1]
  1603. self.applicationsBox.add(button)
  1604. if launcherName in launcherNames:
  1605. button.hide()
  1606. else:
  1607. launcherNames.append(launcherName)
  1608. except Exception as e:
  1609. print(e)
  1610.  
  1611. self.rebuildLock = False
  1612.  
  1613. # Reload the menufiles from the filesystem
  1614. def loadMenuFiles(self):
  1615. if len(self.menuFiles) > 0:
  1616. for menu in self.menuFiles:
  1617. menu.tree.disconnect_by_func(self.menuChanged)
  1618. self.menuFiles = []
  1619. for mainitems in ["mate-applications.menu", "mate-settings.menu"]:
  1620. mymenu = Menu(mainitems )
  1621. mymenu.tree.connect("changed", self.menuChanged, None)
  1622. self.menuFiles.append(mymenu)
  1623.  
  1624. # Build a list of all categories in the menu ([{"name", "icon", tooltip"}]
  1625. def buildCategoryList(self):
  1626. newCategoryList = [{"name": _("All"),
  1627. "icon": "edit-select-all",
  1628. "tooltip": _("Show all applications"),
  1629. "filter":"", "index": 0}]
  1630. num = 1
  1631. for menu in self.menuFiles:
  1632. for child in get_contents(menu.directory):
  1633. if isinstance(child, MateMenu.TreeDirectory):
  1634. name = child.get_name()
  1635. icon = child.get_icon().to_string()
  1636. newCategoryList.append({"name": name,
  1637. "icon": icon,
  1638. "tooltip": name,
  1639. "filter": name,
  1640. "index": num})
  1641. num += 1
  1642. return newCategoryList
  1643.  
  1644. # Build a list containing the DesktopEntry object and the category of each application in the menu
  1645. def buildApplicationList(self):
  1646. newApplicationsList = []
  1647.  
  1648. def find_applications_recursively(app_list, directory, catName):
  1649. for item in get_contents(directory):
  1650. if isinstance(item, MateMenu.TreeEntry):
  1651. app_list.append({"entry": item, "category": catName})
  1652. elif isinstance(item, MateMenu.TreeDirectory):
  1653. find_applications_recursively(app_list, item, catName)
  1654.  
  1655. for menu in self.menuFiles:
  1656. directory = menu.directory
  1657. for entry in get_contents(directory):
  1658. if isinstance(entry, MateMenu.TreeDirectory) and len(get_contents(entry)):
  1659. #Entry is a top-level category
  1660. #catName = entry.get_name()
  1661. #icon = str(entry.get_icon().to_string())
  1662. #if (icon == "applications-system" or icon == "applications-other"):
  1663. # catName = self.adminMenu
  1664. for item in get_contents(entry):
  1665. if isinstance(item, MateMenu.TreeDirectory):
  1666. find_applications_recursively(newApplicationsList, item, entry.get_name())
  1667. elif isinstance(item, MateMenu.TreeEntry):
  1668. newApplicationsList.append({"entry": item, "category": entry.get_name()})
  1669. #elif isinstance(entry, MateMenu.TreeEntry):
  1670. # if not (entry.get_is_excluded() or entry.get_is_nodisplay()):
  1671. # print "=======>>> " + item.get_name() + " = top level"
  1672. # newApplicationsList.append({"entry": item, "category": ""})
  1673.  
  1674. return newApplicationsList
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement