b7a1fa0b94
Since the move to GTK3 custom color support is extremely hacky and buggy: - It relies on gtk_widget_override_color() which is deprecated - Only one call to gtk_widget_override_color() is functional, successive calls are ignored, leading to the menu not changing colors when the custom colors are changed or enabled/disabled. - RegenPlugins leads to a loss of color. - Theme changes are broken due to overridden colors. The feature is also very niche and quite unecessary. If a custom color is better than the default one we should apply the change in the theme or define a new theme which inherits ours and simply defines the menu differently. The way to do this, in line with GTK's design, is via CSS at theme level.
738 lines
29 KiB
Python
Executable File
738 lines
29 KiB
Python
Executable File
#!/usr/bin/python2
|
|
|
|
import locale
|
|
import gc
|
|
import gettext
|
|
import os
|
|
import sys
|
|
import traceback
|
|
|
|
import gi
|
|
gi.require_version("Gtk", "3.0")
|
|
gi.require_version('MatePanelApplet', '4.0')
|
|
from gi.repository import Gtk, GdkPixbuf, Gdk, GObject
|
|
from gi.repository import MatePanelApplet
|
|
from gi.repository import Gio
|
|
|
|
import xdg.Config
|
|
|
|
import keybinding
|
|
import pointerMonitor
|
|
import setproctitle
|
|
from plugins.execute import Execute
|
|
|
|
GObject.threads_init()
|
|
|
|
# Rename the process
|
|
setproctitle.setproctitle('mintmenu')
|
|
|
|
# i18n
|
|
gettext.install("mintmenu", "/usr/share/linuxmint/locale")
|
|
locale.bindtextdomain("mintmenu", "/usr/share/linuxmint/locale")
|
|
locale.textdomain("mintmenu")
|
|
|
|
NAME = _("Menu")
|
|
PATH = os.path.abspath(os.path.dirname(sys.argv[0]))
|
|
|
|
sys.path.append(os.path.join(PATH , "plugins"))
|
|
|
|
windowManager = os.getenv("DESKTOP_SESSION")
|
|
if not windowManager:
|
|
windowManager = "MATE"
|
|
xdg.Config.setWindowManager(windowManager.upper())
|
|
|
|
|
|
class MainWindow(object):
|
|
"""This is the main class for the application"""
|
|
|
|
def __init__(self, toggleButton, settings, de):
|
|
|
|
self.settings = settings
|
|
self.path = PATH
|
|
sys.path.append(os.path.join(self.path, "plugins"))
|
|
|
|
self.de = de
|
|
self.icon = "/usr/lib/linuxmint/mintMenu/visualisation-logo.png"
|
|
|
|
self.toggle = toggleButton
|
|
builder = Gtk.Builder()
|
|
builder.set_translation_domain("mintmenu")
|
|
builder.add_from_file("/usr/share/linuxmint/mintmenu/main.ui")
|
|
self.window = builder.get_object("mainWindow")
|
|
self.paneholder = builder.get_object("paneholder")
|
|
|
|
builder.connect_signals(self)
|
|
|
|
self.window.connect("key-press-event", self.onKeyPress)
|
|
self.window.connect("focus-in-event", self.onFocusIn)
|
|
self.loseFocusId = self.window.connect("focus-out-event", self.onFocusOut)
|
|
self.loseFocusBlocked = False
|
|
|
|
self.window.stick()
|
|
|
|
plugindir = os.path.join(os.path.expanduser("~"), ".linuxmint/mintMenu/plugins")
|
|
sys.path.append(plugindir)
|
|
|
|
self.settings.connect("changed::plugins-list", self.RegenPlugins)
|
|
self.settings.connect("changed::start-with-favorites", self.toggleStartWithFavorites)
|
|
self.settings.connect("changed::tooltips-enabled", self.toggleTooltipsEnabled)
|
|
|
|
self.getSetGSettingEntries()
|
|
|
|
self.tooltipsWidgets = []
|
|
|
|
self.PopulatePlugins()
|
|
self.toggleTooltipsEnabled(self.settings, "tooltips-enabled")
|
|
self.firstTime = True
|
|
|
|
@classmethod
|
|
def on_window1_destroy (widget, data=None):
|
|
Gtk.main_quit()
|
|
sys.exit(0)
|
|
|
|
def wakePlugins(self):
|
|
# Call each plugin and let them know we're showing up
|
|
for plugin in self.plugins.values():
|
|
if hasattr(plugin, "wake"):
|
|
plugin.wake()
|
|
|
|
def toggleTooltipsEnabled(self, settings, key, args=None):
|
|
enableTooltips = settings.get_boolean(key)
|
|
for widget in self.tooltipsWidgets:
|
|
widget.set_has_tooltip(enableTooltips)
|
|
|
|
def toggleStartWithFavorites(self, settings, key):
|
|
self.startWithFavorites = settings.get_boolean(key)
|
|
|
|
def getSetGSettingEntries(self):
|
|
self.dottedfile = os.path.join(self.path, "dotted.png")
|
|
self.pluginlist = self.settings.get_strv("plugins-list")
|
|
self.offset = self.settings.get_int("offset")
|
|
self.enableTooltips = self.settings.get_boolean("tooltips-enabled")
|
|
self.startWithFavorites = self.settings.get_boolean("start-with-favorites")
|
|
|
|
def PopulatePlugins(self):
|
|
PluginPane = Gtk.EventBox()
|
|
PluginPane.show()
|
|
PaneLadder = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
PluginPane.add(PaneLadder)
|
|
ImageBox = Gtk.EventBox()
|
|
ImageBox.show()
|
|
|
|
seperatorImage = GdkPixbuf.Pixbuf.new_from_file(self.dottedfile)
|
|
|
|
self.plugins = {}
|
|
|
|
for plugin in self.pluginlist:
|
|
if plugin in self.plugins:
|
|
print("Duplicate plugin in list: %s" % plugin)
|
|
continue
|
|
|
|
if plugin != "newpane":
|
|
try:
|
|
X = __import__(plugin)
|
|
# If no parameter passed to plugin it is autonomous
|
|
if X.pluginclass.__init__.func_code.co_argcount == 1:
|
|
MyPlugin = X.pluginclass()
|
|
else:
|
|
# pass mintMenu and togglebutton instance so that the plugin can use it
|
|
MyPlugin = X.pluginclass(self, self.toggle, self.de)
|
|
|
|
if not MyPlugin.icon:
|
|
MyPlugin.icon = "mate-logo-icon.png"
|
|
|
|
#if hasattr(MyPlugin, "hideseparator") and not MyPlugin.hideseparator:
|
|
# Image1 = Gtk.Image()
|
|
# Image1.set_from_pixbuf(seperatorImage)
|
|
# if not ImageBox.get_child():
|
|
# ImageBox.add(Image1)
|
|
# Image1.show()
|
|
|
|
#print u"Loading plugin '" + plugin + "' : sucessful"
|
|
except Exception:
|
|
MyPlugin = Gtk.EventBox() #Fake class for MyPlugin
|
|
MyPlugin.heading = _("Couldn't load plugin:") + " " + plugin
|
|
MyPlugin.content_holder = Gtk.EventBox()
|
|
|
|
# create traceback
|
|
info = sys.exc_info()
|
|
|
|
errorLabel = Gtk.Label("\n".join(traceback.format_exception(info[0], info[1], info[2])).replace("\\n", "\n"))
|
|
errorLabel.set_selectable(True)
|
|
errorLabel.set_line_wrap(True)
|
|
errorLabel.set_alignment(0.0, 0.0)
|
|
errorLabel.set_padding(5, 5)
|
|
errorLabel.show()
|
|
|
|
MyPlugin.content_holder.add(errorLabel)
|
|
MyPlugin.add(MyPlugin.content_holder)
|
|
MyPlugin.width = 270
|
|
MyPlugin.icon = 'mate-logo-icon.png'
|
|
print("Unable to load %s plugin" % plugin)
|
|
|
|
MyPlugin.content_holder.show()
|
|
|
|
VBox1 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
if MyPlugin.heading != "":
|
|
label1 = Gtk.Label()
|
|
label1.set_markup("<span size=\"12000\" weight=\"bold\">%s</span>" % MyPlugin.heading)
|
|
Align1 = Gtk.Alignment.new(0, 0, 0, 0)
|
|
Align1.set_padding(10, 5, 10, 0)
|
|
Align1.add(label1)
|
|
Align1.show()
|
|
label1.show()
|
|
heading = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
|
|
heading.set_size_request(MyPlugin.width, -1)
|
|
|
|
heading.add(Align1)
|
|
heading.show()
|
|
VBox1.pack_start(heading, False, False, 0)
|
|
VBox1.show()
|
|
#Add plugin to Plugin Box under heading button
|
|
MyPlugin.content_holder.get_parent().remove(MyPlugin.content_holder)
|
|
VBox1.add(MyPlugin.content_holder)
|
|
|
|
#Add plugin to main window
|
|
PaneLadder.pack_start(VBox1 , True, True, 0)
|
|
PaneLadder.show()
|
|
|
|
try:
|
|
MyPlugin.get_window().destroy()
|
|
except AttributeError:
|
|
pass
|
|
|
|
try:
|
|
if hasattr(MyPlugin, 'do_plugin'):
|
|
MyPlugin.do_plugin()
|
|
if hasattr(MyPlugin, 'height'):
|
|
MyPlugin.content_holder.set_size_request(-1, MyPlugin.height)
|
|
except:
|
|
# create traceback
|
|
info = sys.exc_info()
|
|
|
|
error = _("Couldn't initialize plugin") + " " + plugin + " : " + "\n".join(traceback.format_exception(info[0], info[1], info[2])).replace("\\n", "\n")
|
|
msgDlg = Gtk.MessageDialog(None, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, error)
|
|
msgDlg.run()
|
|
msgDlg.destroy()
|
|
|
|
self.plugins[plugin] = MyPlugin
|
|
|
|
else:
|
|
self.paneholder.pack_start(ImageBox, False, False, 0)
|
|
self.paneholder.pack_start(PluginPane, False, False, 0)
|
|
PluginPane = Gtk.EventBox()
|
|
PaneLadder = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
PluginPane.add(PaneLadder)
|
|
ImageBox = Gtk.EventBox()
|
|
ImageBox.show()
|
|
PluginPane.show_all()
|
|
|
|
if self.plugins and hasattr(MyPlugin, 'hideseparator') and not MyPlugin.hideseparator:
|
|
Image1 = Gtk.Image()
|
|
Image1.set_from_pixbuf(seperatorImage)
|
|
Image1.show()
|
|
#ImageBox.add(Image1)
|
|
|
|
Align1 = Gtk.Alignment.new(0, 0, 0, 0)
|
|
Align1.set_padding(0, 0, 6, 6)
|
|
Align1.add(Image1)
|
|
ImageBox.add(Align1)
|
|
ImageBox.show_all()
|
|
|
|
|
|
self.paneholder.pack_start(ImageBox, False, False, 0)
|
|
self.paneholder.pack_start(PluginPane, False, False, 0)
|
|
|
|
def setTooltip(self, widget, tip):
|
|
self.tooltipsWidgets.append(widget)
|
|
widget.set_tooltip_text(tip)
|
|
|
|
def RegenPlugins(self, *args, **kargs):
|
|
#print u"Reloading Plugins..."
|
|
for item in self.paneholder:
|
|
item.destroy()
|
|
|
|
for plugin in self.plugins.values():
|
|
if hasattr(plugin, "destroy"):
|
|
plugin.destroy()
|
|
|
|
try:
|
|
del plugin
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
del self.plugins
|
|
except:
|
|
pass
|
|
|
|
gc.collect()
|
|
|
|
self.getSetGSettingEntries()
|
|
self.PopulatePlugins()
|
|
self.toggleTooltipsEnabled(self.settings, "tooltips-enabled")
|
|
|
|
#print NAME+u" reloaded"
|
|
|
|
def onKeyPress(self, widget, event):
|
|
if event.keyval == Gdk.KEY_Escape:
|
|
self.hide()
|
|
return True
|
|
return False
|
|
|
|
def show(self):
|
|
self.window.present()
|
|
|
|
# Hack for opacity not showing on first composited draw
|
|
if self.firstTime:
|
|
self.firstTime = False
|
|
self.window.set_opacity(1.0)
|
|
|
|
self.window.get_window().focus(Gdk.CURRENT_TIME)
|
|
|
|
for plugin in self.plugins.values():
|
|
if hasattr(plugin, "onShowMenu"):
|
|
plugin.onShowMenu()
|
|
|
|
if "applications" in self.plugins and hasattr(self.plugins["applications"], "focusSearchEntry"):
|
|
if self.startWithFavorites:
|
|
self.plugins["applications"].changeTab(0)
|
|
self.plugins["applications"].focusSearchEntry()
|
|
|
|
def hide(self):
|
|
for plugin in self.plugins.values():
|
|
if hasattr(plugin, "onHideMenu"):
|
|
plugin.onHideMenu()
|
|
|
|
self.window.hide()
|
|
|
|
def onFocusIn(self, *args):
|
|
if self.loseFocusBlocked:
|
|
self.window.handler_unblock(self.loseFocusId)
|
|
self.loseFocusBlocked = False
|
|
|
|
return False
|
|
|
|
def onFocusOut(self, *args):
|
|
if self.window.get_visible():
|
|
self.hide()
|
|
return False
|
|
|
|
def stopHiding(self):
|
|
if not self.loseFocusBlocked:
|
|
self.window.handler_block(self.loseFocusId)
|
|
self.loseFocusBlocked = True
|
|
|
|
class MenuWin(object):
|
|
|
|
def __init__(self, applet, iid):
|
|
self.applet = applet
|
|
self.detect_desktop_environment()
|
|
self.settings = Gio.Settings.new("com.linuxmint.mintmenu")
|
|
self.icon_theme = Gtk.IconTheme.get_default()
|
|
self.loadSettings()
|
|
|
|
self.createPanelButton()
|
|
|
|
self.mate_settings = Gio.Settings.new("org.mate.interface")
|
|
self.mate_settings.connect("changed::gtk-theme", self.changeTheme)
|
|
|
|
self.settings.connect("changed::applet-text", self.reloadSettings)
|
|
self.settings.connect("changed::theme-name", self.changeTheme)
|
|
self.settings.connect("changed::hot-key", self.reloadSettings)
|
|
self.settings.connect("changed::applet-icon", self.reloadSettings)
|
|
self.settings.connect("changed::show-applet-icon", self.reloadSettings)
|
|
self.settings.connect("changed::applet-icon-size", self.reloadSettings)
|
|
|
|
self.applet.set_flags(MatePanelApplet.AppletFlags.EXPAND_MINOR)
|
|
self.applet.connect("button-press-event", self.showMenu)
|
|
self.applet.connect("change-orient", self.changeOrientation)
|
|
self.applet.connect("enter-notify-event", self.enter_notify)
|
|
self.applet.connect("leave-notify-event", self.leave_notify)
|
|
|
|
self.mainwin = MainWindow(self.button_box, self.settings, self.de)
|
|
self.mainwin.window.connect("map-event", self.onWindowMap)
|
|
self.mainwin.window.connect("unmap-event", self.onWindowUnmap)
|
|
self.mainwin.window.connect("size-allocate", lambda *args: self.positionMenu())
|
|
|
|
self.mainwin.window.set_name("mintmenu") # Name used in Gtk RC files
|
|
self.applyTheme()
|
|
|
|
if self.mainwin.icon:
|
|
Gtk.Window.set_default_icon_name(self.mainwin.icon)
|
|
|
|
try:
|
|
self.keybinder = keybinding.GlobalKeyBinding()
|
|
if self.hotkeyText != "":
|
|
self.keybinder.grab(self.hotkeyText)
|
|
self.keybinder.connect("activate", self.onBindingPress)
|
|
self.keybinder.start()
|
|
self.settings.connect("changed::hot-key", self.hotkeyChanged)
|
|
print("Binding to Hot Key: %s" % self.hotkeyText)
|
|
except Exception as e:
|
|
self.keybinder = None
|
|
print("** WARNING ** - Keybinder Error")
|
|
print("Error Report :\n", e)
|
|
|
|
self.applet.set_can_focus(False)
|
|
|
|
try:
|
|
self.pointerMonitor = pointerMonitor.PointerMonitor()
|
|
self.pointerMonitor.connect("activate", self.onPointerOutside)
|
|
self.mainwin.window.connect("realize", self.onRealize)
|
|
except Exception as e:
|
|
print("** WARNING ** - Pointer Monitor Error")
|
|
print("Error Report :\n", e)
|
|
|
|
def onWindowMap(self, *args):
|
|
self.applet.get_style_context().set_state(Gtk.StateFlags.SELECTED)
|
|
self.button_box.get_style_context().set_state(Gtk.StateFlags.SELECTED)
|
|
if self.keybinder is not None:
|
|
self.keybinder.set_focus_window(self.mainwin.window.get_window())
|
|
return False
|
|
|
|
def onWindowUnmap(self, *args):
|
|
self.applet.get_style_context().set_state(Gtk.StateFlags.NORMAL)
|
|
self.button_box.get_style_context().set_state(Gtk.StateFlags.NORMAL)
|
|
if self.keybinder is not None:
|
|
self.keybinder.set_focus_window()
|
|
return False
|
|
|
|
def onRealize(self, *args):
|
|
self.pointerMonitor.addWindowToMonitor(self.mainwin.window.get_window())
|
|
self.pointerMonitor.addWindowToMonitor(self.applet.get_window())
|
|
self.pointerMonitor.start()
|
|
return False
|
|
|
|
def onPointerOutside(self, *args):
|
|
self.mainwin.hide()
|
|
return True
|
|
|
|
def onBindingPress(self, binder):
|
|
self.toggleMenu()
|
|
return True
|
|
|
|
def enter_notify(self, applet, event):
|
|
self.set_applet_icon(True)
|
|
|
|
def leave_notify(self, applet, event):
|
|
# Hack for mate-panel-test-applets focus issue (this can be commented)
|
|
# if event.state & Gdk.ModifierType.BUTTON1_MASK and applet.get_style_context().get_state() & Gtk.StateFlags.SELECTED:
|
|
# if event.x >= 0 and event.y >= 0 and event.x < applet.get_window().get_width() and event.y < applet.get_window().get_height():
|
|
# self.mainwin.stopHiding()
|
|
|
|
self.set_applet_icon()
|
|
|
|
def set_applet_icon(self, saturate=False):
|
|
if saturate:
|
|
self.button_icon.set_from_pixbuf(self.saturated_pixbuf)
|
|
else:
|
|
self.button_icon.set_from_pixbuf(self.pixbuf)
|
|
|
|
def createPanelButton(self):
|
|
self.button_icon = Gtk.Image()
|
|
self.set_applet_icon()
|
|
self.systemlabel = Gtk.Label(label= "%s " % self.buttonText)
|
|
if os.path.isfile("/etc/linuxmint/info"):
|
|
with open("/etc/linuxmint/info") 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)
|
|
self.button_icon.set_tooltip_text(tooltip)
|
|
break
|
|
if self.applet.get_orient() == MatePanelApplet.AppletOrient.UP or self.applet.get_orient() == MatePanelApplet.AppletOrient.DOWN:
|
|
self.button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
|
|
self.button_box.pack_start(self.button_icon, False, False, 0)
|
|
self.button_box.pack_start(self.systemlabel, False, False, 0)
|
|
self.button_icon.set_padding(5, 0)
|
|
# if we have a vertical panel
|
|
elif self.applet.get_orient() == MatePanelApplet.AppletOrient.LEFT:
|
|
self.button_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
self.systemlabel.set_angle(270)
|
|
self.button_box.pack_start(self.button_icon , False, False, 0)
|
|
self.button_box.pack_start(self.systemlabel , False, False, 0)
|
|
self.button_icon.set_padding(0, 5)
|
|
elif self.applet.get_orient() == MatePanelApplet.AppletOrient.RIGHT:
|
|
self.button_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
self.systemlabel.set_angle(90)
|
|
self.button_box.pack_start(self.systemlabel , False, False, 0)
|
|
self.button_box.pack_start(self.button_icon , False, False, 0)
|
|
self.button_icon.set_padding(0, 5)
|
|
|
|
self.button_box.set_homogeneous(False)
|
|
self.button_box.show_all()
|
|
self.sizeButton()
|
|
self.button_box.get_style_context().add_class('mintmenu')
|
|
self.applet.add(self.button_box)
|
|
self.applet.set_background_widget(self.applet)
|
|
|
|
def loadSettings(self, *args, **kargs):
|
|
self.showIcon = self.settings.get_boolean("show-applet-icon")
|
|
self.buttonText = self.settings.get_string("applet-text")
|
|
self.theme_name = self.settings.get_string("theme-name")
|
|
self.hotkeyText = self.settings.get_string("hot-key")
|
|
|
|
applet_icon = self.settings.get_string("applet-icon")
|
|
if not (os.path.exists(applet_icon) or self.icon_theme.has_icon(applet_icon)):
|
|
self.settings.reset("applet-icon")
|
|
applet_icon = self.settings.get_string("applet-icon")
|
|
if "/" in applet_icon:
|
|
if applet_icon.endswith(".svg"):
|
|
self.pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(applet_icon, -1, 22)
|
|
else:
|
|
self.pixbuf = GdkPixbuf.Pixbuf.new_from_file(applet_icon)
|
|
else:
|
|
self.pixbuf = self.icon_theme.load_icon(applet_icon, 22, 0)
|
|
self.saturated_pixbuf = self.pixbuf.copy()
|
|
GdkPixbuf.Pixbuf.saturate_and_pixelate(self.saturated_pixbuf, self.saturated_pixbuf, 1.5, False)
|
|
self.buttonIcon = self.settings.get_string("applet-icon")
|
|
self.iconSize = self.settings.get_int("applet-icon-size")
|
|
|
|
def changeTheme(self, *args):
|
|
self.reloadSettings()
|
|
self.applyTheme()
|
|
|
|
def applyTheme(self):
|
|
style_settings = Gtk.Settings.get_default()
|
|
desktop_theme = self.mate_settings.get_string('gtk-theme')
|
|
if self.theme_name == "default":
|
|
style_settings.set_property("gtk-theme-name", desktop_theme)
|
|
else:
|
|
try:
|
|
style_settings.set_property("gtk-theme-name", self.theme_name)
|
|
except:
|
|
style_settings.set_property("gtk-theme-name", desktop_theme)
|
|
|
|
def changeOrientation(self, *args, **kargs):
|
|
if self.applet.get_orient() == MatePanelApplet.AppletOrient.UP or self.applet.get_orient() == MatePanelApplet.AppletOrient.DOWN:
|
|
tmpbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
|
|
self.systemlabel.set_angle(0)
|
|
self.button_box.reorder_child(self.button_icon, 0)
|
|
self.button_icon.set_padding(5, 0)
|
|
elif self.applet.get_orient() == MatePanelApplet.AppletOrient.LEFT:
|
|
tmpbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
self.systemlabel.set_angle(270)
|
|
self.button_box.reorder_child(self.button_icon, 0)
|
|
self.button_icon.set_padding(0, 5)
|
|
elif self.applet.get_orient() == MatePanelApplet.AppletOrient.RIGHT:
|
|
tmpbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
self.systemlabel.set_angle(90)
|
|
self.button_box.reorder_child(self.button_icon, 1)
|
|
self.button_icon.set_padding(0, 5)
|
|
|
|
tmpbox.set_homogeneous(False)
|
|
|
|
# reparent all the hboxes to the new tmpbox
|
|
for i in self.button_box:
|
|
i.reparent(tmpbox)
|
|
|
|
self.button_box.destroy()
|
|
|
|
self.button_box = tmpbox
|
|
self.button_box.show()
|
|
|
|
# this call makes sure width stays intact
|
|
self.updateButton()
|
|
self.applet.add(self.button_box)
|
|
|
|
def updateButton(self):
|
|
self.systemlabel.set_text(self.buttonText)
|
|
self.button_icon.clear()
|
|
self.set_applet_icon()
|
|
self.sizeButton()
|
|
|
|
def hotkeyChanged (self, schema, key):
|
|
self.hotkeyText = self.settings.get_string("hot-key")
|
|
self.keybinder.rebind(self.hotkeyText)
|
|
|
|
def sizeButton(self):
|
|
if self.showIcon:
|
|
self.button_icon.show()
|
|
else:
|
|
self.button_icon.hide()
|
|
|
|
# This code calculates width and height for the button_box
|
|
# and takes the orientation and scale factor in account
|
|
bi_req = self.button_icon.get_preferred_size()[1]
|
|
bi_scale = self.button_icon.get_scale_factor()
|
|
sl_req = self.systemlabel.get_preferred_size()[1]
|
|
sl_scale = self.systemlabel.get_scale_factor()
|
|
if self.applet.get_orient() == MatePanelApplet.AppletOrient.UP or self.applet.get_orient() == MatePanelApplet.AppletOrient.DOWN:
|
|
if self.showIcon:
|
|
self.applet.set_size_request(sl_req.width / sl_scale + bi_req.width / bi_scale + 5, bi_req.height)
|
|
else:
|
|
self.applet.set_size_request(sl_req.width / sl_scale + 2, bi_req.height)
|
|
else:
|
|
if self.showIcon:
|
|
self.applet.set_size_request(bi_req.width, sl_req.height / sl_scale + bi_req.height / bi_scale + 5)
|
|
else:
|
|
self.applet.set_size_request(bi_req.width, sl_req.height / sl_scale + 2)
|
|
|
|
def reloadSettings(self, *args):
|
|
self.loadSettings()
|
|
self.updateButton()
|
|
|
|
def showAboutDialog(self, action, userdata = None):
|
|
about = Gtk.AboutDialog()
|
|
about.set_name("mintMenu")
|
|
about.set_version("__DEB_VERSION__")
|
|
try:
|
|
gpl = open('/usr/share/common-licenses/GPL','r').read()
|
|
about.set_license(gpl)
|
|
except Exception as e:
|
|
print(e)
|
|
about.set_comments(_("Advanced MATE Menu"))
|
|
# about.set_authors(["Clement Lefebvre <clem@linuxmint.com>", "Lars-Peter Clausen <lars@laprican.de>"])
|
|
about.set_translator_credits(("translator-credits"))
|
|
# about.set_copyright(_("Based on USP from S.Chanderbally"))
|
|
about.set_logo(GdkPixbuf.Pixbuf.new_from_file("/usr/lib/linuxmint/mintMenu/icon.svg"))
|
|
about.connect("response", lambda dialog, r: dialog.destroy())
|
|
about.show()
|
|
|
|
def showPreferences(self, action, userdata = None):
|
|
Execute("/usr/lib/linuxmint/mintMenu/preferences.py")
|
|
|
|
def showMenuEditor(self, action, userdata = None):
|
|
Execute("mozo")
|
|
|
|
def showMenu(self, widget=None, event=None):
|
|
if event == None or event.button == 1:
|
|
self.toggleMenu()
|
|
# show right click menu
|
|
elif event.button == 3:
|
|
self.create_menu()
|
|
# allow middle click and drag
|
|
elif event.button == 2:
|
|
self.mainwin.hide()
|
|
|
|
def toggleMenu(self):
|
|
if self.applet.get_style_context().get_state() & Gtk.StateFlags.SELECTED:
|
|
self.mainwin.hide()
|
|
else:
|
|
self.positionMenu()
|
|
self.mainwin.show()
|
|
self.wakePlugins()
|
|
|
|
def wakePlugins(self):
|
|
self.mainwin.wakePlugins()
|
|
|
|
def positionMenu(self):
|
|
# Get our own dimensions & position
|
|
ourWidth = self.mainwin.window.get_size()[0]
|
|
ourHeight = self.mainwin.window.get_size()[1] + self.mainwin.offset
|
|
|
|
# Get the dimensions/position of the widgetToAlignWith
|
|
try:
|
|
entryX = self.applet.get_window().get_origin().x
|
|
entryY = self.applet.get_window().get_origin().y
|
|
except:
|
|
# In Betsy get_origin returns an unamed tuple so the code above fails
|
|
entryX = self.applet.get_window().get_origin()[1]
|
|
entryY = self.applet.get_window().get_origin()[2]
|
|
|
|
entryWidth, entryHeight = self.applet.get_allocation().width, self.applet.get_allocation().height
|
|
entryHeight = entryHeight + self.mainwin.offset
|
|
|
|
# Get the monitor dimensions
|
|
display = self.applet.get_display()
|
|
if (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION) >= (3, 22):
|
|
monitor = display.get_monitor_at_window(self.applet.get_window())
|
|
monitorGeometry = monitor.get_geometry()
|
|
else:
|
|
screen = display.get_default_screen()
|
|
monitor = screen.get_monitor_at_window(self.applet.get_window())
|
|
monitorGeometry = screen.get_monitor_geometry(monitor)
|
|
|
|
applet_orient = self.applet.get_orient()
|
|
if applet_orient == MatePanelApplet.AppletOrient.UP:
|
|
newX = entryX
|
|
newY = entryY - ourHeight
|
|
elif applet_orient == MatePanelApplet.AppletOrient.DOWN:
|
|
newX = entryX
|
|
newY = entryY + entryHeight
|
|
elif applet_orient == MatePanelApplet.AppletOrient.RIGHT:
|
|
newX = entryX + entryWidth
|
|
newY = entryY
|
|
elif applet_orient == MatePanelApplet.AppletOrient.LEFT:
|
|
newX = entryX - ourWidth
|
|
newY = entryY
|
|
|
|
# Adjust for offset if we reach the end of the screen
|
|
# Bind to the right side
|
|
if newX + ourWidth > (monitorGeometry.x + monitorGeometry.width):
|
|
newX = (monitorGeometry.x + monitorGeometry.width) - ourWidth
|
|
if applet_orient == MatePanelApplet.AppletOrient.LEFT:
|
|
newX -= entryWidth
|
|
|
|
# Bind to the left side
|
|
if newX < monitorGeometry.x:
|
|
newX = monitorGeometry.x
|
|
if applet_orient == MatePanelApplet.AppletOrient.RIGHT:
|
|
newX -= entryWidth
|
|
|
|
# Bind to the bottom
|
|
if newY + ourHeight > (monitorGeometry.y + monitorGeometry.height):
|
|
newY = (monitorGeometry.y + monitorGeometry.height) - ourHeight
|
|
if applet_orient == MatePanelApplet.AppletOrient.UP:
|
|
newY -= entryHeight
|
|
|
|
# Bind to the top
|
|
if newY < monitorGeometry.y:
|
|
newY = monitorGeometry.y
|
|
if applet_orient == MatePanelApplet.AppletOrient.DOWN:
|
|
newY -= entryHeight
|
|
|
|
# Move window
|
|
self.mainwin.window.move(newX, newY)
|
|
|
|
# this callback is to create a context menu
|
|
def create_menu(self):
|
|
action_group = Gtk.ActionGroup(name="context-menu")
|
|
action = Gtk.Action(name="MintMenuPrefs", label=_("Preferences"), tooltip=None)
|
|
action.connect("activate", self.showPreferences)
|
|
action_group.add_action(action)
|
|
action = Gtk.Action(name="MintMenuEdit", label=_("Edit menu"), tooltip=None)
|
|
action.connect("activate", self.showMenuEditor)
|
|
action_group.add_action(action)
|
|
action = Gtk.Action(name="MintMenuReload", label=_("Reload plugins"), tooltip=None)
|
|
action.connect("activate", self.mainwin.RegenPlugins)
|
|
action_group.add_action(action)
|
|
action = Gtk.Action(name="MintMenuAbout", label=_("About"), tooltip=None)
|
|
action.connect("activate", self.showAboutDialog)
|
|
action_group.add_action(action)
|
|
action_group.set_translation_domain ("mintmenu")
|
|
|
|
xml = os.path.join(os.path.join(os.path.dirname(__file__)), "popup.xml")
|
|
self.applet.setup_menu_from_file(xml, action_group)
|
|
|
|
def detect_desktop_environment (self):
|
|
self.de = "mate"
|
|
try:
|
|
de = os.environ["XDG_CURRENT_DESKTOP"].lower()
|
|
if de in ["gnome", "gnome-shell", "mate", "kde", "xfce"]:
|
|
self.de = de
|
|
elif de in ['cinnamon', 'x-cinnamon']:
|
|
self.de = 'cinnamon'
|
|
else:
|
|
if os.path.exists("/usr/bin/caja"):
|
|
self.de = "mate"
|
|
elif os.path.exists("/usr/bin/thunar"):
|
|
self.de = "xfce"
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
def applet_factory(applet, iid, data):
|
|
MenuWin(applet, iid)
|
|
applet.show()
|
|
return True
|
|
|
|
def quit_all(widget):
|
|
Gtk.main_quit()
|
|
sys.exit(0)
|
|
|
|
MatePanelApplet.Applet.factory_main("MintMenuAppletFactory", True,
|
|
MatePanelApplet.Applet.__gtype__,
|
|
applet_factory, None)
|