d7500875ec
Restructured a bit how theming and coloring works. Now theme and color changes work on the fly. No need to restart mintMenu anymore. Note that changing theme no longer regenerates plugins, so it's faster. Fixes issue #47
864 lines
34 KiB
Python
Executable File
864 lines
34 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
import gi
|
|
gi.require_version("Gtk", "2.0")
|
|
|
|
from gi.repository import Gtk, GdkPixbuf, Gdk, GObject
|
|
from gi.repository import MatePanelApplet
|
|
from gi.repository import Gio
|
|
|
|
try:
|
|
import sys
|
|
from gi.repository import Pango
|
|
import os
|
|
import commands
|
|
import gettext
|
|
import traceback
|
|
import time
|
|
import gc
|
|
import ctypes
|
|
from ctypes import *
|
|
import capi
|
|
import xdg.Config
|
|
import keybinding
|
|
except Exception, e:
|
|
print e
|
|
sys.exit( 1 )
|
|
|
|
GObject.threads_init()
|
|
|
|
gtk = CDLL("libgtk-x11-2.0.so.0")
|
|
gdk = CDLL("libgdk-x11-2.0.so.0")
|
|
|
|
# Rename the process
|
|
architecture = commands.getoutput("uname -a")
|
|
if (architecture.find("x86_64") >= 0):
|
|
import ctypes
|
|
libc = ctypes.CDLL('libc.so.6')
|
|
libc.prctl(15, 'mintmenu', 0, 0, 0)
|
|
else:
|
|
import dl
|
|
if os.path.exists('/lib/libc.so.6'):
|
|
libc = dl.open('/lib/libc.so.6')
|
|
libc.call('prctl', 15, 'mintmenu', 0, 0, 0)
|
|
elif os.path.exists('/lib/i386-linux-gnu/libc.so.6'):
|
|
libc = dl.open('/lib/i386-linux-gnu/libc.so.6')
|
|
libc.call('prctl', 15, 'mintmenu', 0, 0, 0)
|
|
|
|
# i18n
|
|
gettext.install("mintmenu", "/usr/share/linuxmint/locale")
|
|
|
|
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() )
|
|
|
|
from execute import *
|
|
|
|
class MainWindow( object ):
|
|
"""This is the main class for the application"""
|
|
|
|
def __init__( self, toggleButton, settings, keybinder ):
|
|
|
|
self.settings = settings
|
|
self.keybinder = keybinder
|
|
self.path = PATH
|
|
sys.path.append( os.path.join( self.path, "plugins") )
|
|
|
|
self.detect_desktop_environment()
|
|
|
|
self.icon = "/usr/lib/linuxmint/mintMenu/visualisation-logo.png"
|
|
|
|
self.toggle = toggleButton
|
|
# Load UI file and extract widgets
|
|
builder = Gtk.Builder()
|
|
builder.add_from_file(os.path.join( self.path, "mintMenu.glade" ))
|
|
self.window = builder.get_object( "mainWindow" )
|
|
self.paneholder = builder.get_object( "paneholder" )
|
|
self.border = builder.get_object( "border" )
|
|
|
|
builder.connect_signals(self)
|
|
|
|
self.panesToColor = [ ]
|
|
self.headingsToColor = [ ]
|
|
|
|
self.window.connect( "map-event", self.onMap )
|
|
self.window.connect( "show", self.onShow )
|
|
self.window.connect( "unmap-event", self.onUnmap )
|
|
self.window.connect( "button-press-event", self.onButtonPress )
|
|
self.window.connect( "key-press-event", self.onKeyPress )
|
|
self.window.connect( "grab-broken-event", self.onGrabBroken )
|
|
|
|
self.window.stick()
|
|
|
|
plugindir = os.path.join( os.path.expanduser( "~" ), ".linuxmint/mintMenu/plugins" )
|
|
sys.path.append( plugindir )
|
|
|
|
self.panelSettings = Gio.Settings.new("org.mate.panel")
|
|
self.panelSettings.connect( "changed::tooltips-enabled", self.toggleTooltipsEnabled )
|
|
|
|
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.settings.connect( "changed::use-custom-color", self.toggleUseCustomColor )
|
|
self.settings.connect( "changed::custom-border-color", self.toggleCustomBorderColor )
|
|
self.settings.connect( "changed::custom-heading-color", self.toggleCustomHeadingColor )
|
|
self.settings.connect( "changed::custom-color", self.toggleCustomBackgroundColor )
|
|
self.settings.connect( "changed::border-width", self.toggleBorderWidth )
|
|
self.settings.connect( "changed::opacity", self.toggleOpacity )
|
|
|
|
self.getSetGSettingEntries()
|
|
|
|
self.tooltips = Gtk.Tooltips()
|
|
if self.globalEnableTooltips and self.enableTooltips:
|
|
self.tooltips.enable()
|
|
else:
|
|
self.tooltips.disable()
|
|
|
|
self.PopulatePlugins();
|
|
self.loadTheme()
|
|
self.firstTime = True;
|
|
|
|
def on_window1_destroy (self, 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):
|
|
if key == "tooltips-enabled":
|
|
self.globalEnableTooltips = settings.get_boolean(key)
|
|
else:
|
|
self.enableTooltips = settings.get_boolean(key)
|
|
|
|
if self.globalEnableTooltips and self.enableTooltips:
|
|
self.tooltips.enable()
|
|
else:
|
|
self.tooltips.disable()
|
|
|
|
def toggleStartWithFavorites( self, settings, key, args = None ):
|
|
self.startWithFavorites = settings.get_boolean(key)
|
|
|
|
def toggleBorderWidth( self, settings, key, args = None ):
|
|
self.borderwidth = settings.get_int(key)
|
|
self.SetupMintMenuBorder()
|
|
|
|
def toggleOpacity( self, settings, key, args = None ):
|
|
self.opacity = settings.get_int(key)
|
|
self.SetupMintMenuOpacity()
|
|
|
|
def toggleUseCustomColor( self, settings, key, args = None ):
|
|
self.usecustomcolor = settings.get_boolean(key)
|
|
self.loadTheme()
|
|
|
|
def toggleCustomBorderColor( self, settings, key, args = None ):
|
|
self.custombordercolor = settings.get_string(key)
|
|
self.SetupMintMenuBorder()
|
|
|
|
def toggleCustomBackgroundColor( self, settings, key, args = None):
|
|
self.customcolor = settings.get_string(key)
|
|
self.SetPaneColors( self.panesToColor )
|
|
|
|
def toggleCustomHeadingColor( self, settings, key, args = None ):
|
|
self.customheadingcolor = settings.get_string(key)
|
|
self.SetHeadingStyle( self.headingsToColor )
|
|
|
|
def getSetGSettingEntries( self ):
|
|
self.dottedfile = os.path.join( self.path, "dotted.png")
|
|
|
|
self.pluginlist = self.settings.get_strv( "plugins-list" )
|
|
self.usecustomcolor = self.settings.get_boolean( "use-custom-color" )
|
|
self.customcolor = self.settings.get_string( "custom-color" )
|
|
self.customheadingcolor = self.settings.get_string( "custom-heading-color" )
|
|
self.custombordercolor = self.settings.get_string( "custom-border-color" )
|
|
self.borderwidth = self.settings.get_int( "border-width" )
|
|
self.opacity = self.settings.get_int( "opacity" )
|
|
self.offset = self.settings.get_int( "offset" )
|
|
self.enableTooltips = self.settings.get_boolean( "tooltips-enabled" )
|
|
self.startWithFavorites = self.settings.get_boolean( "start-with-favorites" )
|
|
|
|
self.globalEnableTooltips = self.panelSettings.get_boolean( "tooltips-enabled" )
|
|
|
|
def SetupMintMenuBorder( self, defaultStyle = None ):
|
|
if self.usecustomcolor:
|
|
self.window.modify_bg( Gtk.StateType.NORMAL, Gdk.color_parse( self.custombordercolor ) )
|
|
elif defaultStyle is not None:
|
|
self.window.modify_bg( Gtk.StateType.NORMAL, defaultStyle.lookup_color('bg_color')[1] )
|
|
self.border.set_padding( self.borderwidth, self.borderwidth, self.borderwidth, self.borderwidth )
|
|
|
|
def SetupMintMenuOpacity( self ):
|
|
print "Opacity is: " + str(self.opacity)
|
|
opacity = float(self.opacity) / float(100)
|
|
print "Setting opacity to: " + str(opacity)
|
|
self.window.set_opacity(opacity)
|
|
|
|
def detect_desktop_environment (self):
|
|
self.de = "mate"
|
|
try:
|
|
de = os.environ["DESKTOP_SESSION"]
|
|
if de in ["gnome", "gnome-shell", "mate", "kde", "xfce"]:
|
|
self.de = de
|
|
else:
|
|
if os.path.exists("/usr/bin/caja"):
|
|
self.de = "mate"
|
|
elif os.path.exists("/usr/bin/thunar"):
|
|
self.de = "xfce"
|
|
except Exception, detail:
|
|
print detail
|
|
|
|
def PopulatePlugins( self ):
|
|
self.panesToColor = [ ]
|
|
self.headingsToColor = [ ]
|
|
start = time.time()
|
|
PluginPane = Gtk.EventBox()
|
|
PluginPane.show()
|
|
PaneLadder = Gtk.VBox( False, 0 )
|
|
PluginPane.add( PaneLadder )
|
|
ImageBox = Gtk.EventBox()
|
|
ImageBox.show()
|
|
self.panesToColor.extend( [ PluginPane, ImageBox ] )
|
|
|
|
seperatorImage = GdkPixbuf.Pixbuf.new_from_file( self.dottedfile )
|
|
|
|
self.plugins = {}
|
|
|
|
for plugin in self.pluginlist:
|
|
if plugin in self.plugins:
|
|
print u"Duplicate plugin in list: ", 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, e:
|
|
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 u"Unable to load " + plugin + " plugin :-("
|
|
|
|
|
|
self.panesToColor.append( MyPlugin.content_holder )
|
|
MyPlugin.content_holder.show()
|
|
|
|
VBox1 = Gtk.VBox( False, 0 )
|
|
if MyPlugin.heading != "":
|
|
Label1 = Gtk.Label(label= MyPlugin.heading )
|
|
Align1 = Gtk.Alignment.new( 0, 0, 0, 0 )
|
|
Align1.set_padding( 10, 5, 10, 0 )
|
|
Align1.add( Label1 )
|
|
self.headingsToColor.append( Label1 )
|
|
Align1.show()
|
|
Label1.show()
|
|
|
|
if not hasattr( MyPlugin, 'sticky' ) or MyPlugin.sticky == True:
|
|
heading = Gtk.EventBox()
|
|
Align1.set_padding( 0, 0, 10, 0 )
|
|
heading.set_visible_window( False )
|
|
heading.set_size_request( MyPlugin.width, 30 )
|
|
else:
|
|
heading = Gtk.HBox()
|
|
#heading.set_relief( Gtk.ReliefStyle.NONE )
|
|
heading.set_size_request( MyPlugin.width, -1 )
|
|
#heading.set_sensitive(False)
|
|
#heading.connect( "button_press_event", self.TogglePluginView, VBox1, MyPlugin.icon, MyPlugin.heading, MyPlugin )
|
|
|
|
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.reparent( VBox1 )
|
|
|
|
#Add plugin to main window
|
|
PaneLadder.pack_start( VBox1 , True, True, 0)
|
|
PaneLadder.show()
|
|
|
|
if MyPlugin.window:
|
|
MyPlugin.window.destroy()
|
|
|
|
try:
|
|
if hasattr( MyPlugin, 'do_plugin' ):
|
|
MyPlugin.do_plugin()
|
|
if hasattr( MyPlugin, 'height' ):
|
|
MyPlugin.content_holder.set_size_request( -1, MyPlugin.height )
|
|
if hasattr( MyPlugin, 'itemstocolor' ):
|
|
self.panesToColor.extend( MyPlugin.itemstocolor )
|
|
if hasattr( MyPlugin, 'headingstocolor' ):
|
|
self.headingsToColor.extend( MyPlugin.headingstocolor )
|
|
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.VBox( False, 0 )
|
|
PluginPane.add( PaneLadder )
|
|
ImageBox = Gtk.EventBox()
|
|
self.panesToColor.extend( [ PluginPane, ImageBox ] )
|
|
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 )
|
|
self.tooltips.disable()
|
|
#print u"Loading", (time.time() - start), "s"
|
|
|
|
# A little hacky but works
|
|
def getDefaultStyle( self ):
|
|
widget = Gtk.EventBox()
|
|
widget.show()
|
|
return Gtk.rc_get_style(widget)
|
|
|
|
def loadTheme( self ):
|
|
defaultStyle = self.getDefaultStyle()
|
|
self.SetPaneColors( self.panesToColor, defaultStyle )
|
|
self.SetupMintMenuBorder( defaultStyle )
|
|
self.SetHeadingStyle( self.headingsToColor )
|
|
|
|
def SetPaneColors( self, items, defaultStyle = None ):
|
|
if self.usecustomcolor:
|
|
for item in items:
|
|
item.modify_bg( Gtk.StateType.NORMAL, Gdk.color_parse( self.customcolor ) )
|
|
# TODO: Changing background color isn't working for pixmaps! The following does not work:
|
|
item.get_style().bg_pixmap[Gtk.StateType.NORMAL] = None
|
|
elif defaultStyle is not None:
|
|
for item in items:
|
|
item.modify_bg( Gtk.StateType.NORMAL, defaultStyle.lookup_color('bg_color')[1] )
|
|
item.get_style().bg_pixmap[Gtk.StateType.NORMAL] = defaultStyle.bg_pixmap[Gtk.StateType.NORMAL]
|
|
|
|
def SetHeadingStyle( self, items ):
|
|
if self.usecustomcolor:
|
|
color = self.customheadingcolor
|
|
else:
|
|
color = None
|
|
|
|
for item in items:
|
|
item.set_use_markup(True)
|
|
text = item.get_text()
|
|
if color == None:
|
|
markup = '<span size="12000" weight="bold">%s</span>' % (text)
|
|
else:
|
|
markup = '<span size="12000" weight="bold" color="%s">%s</span>' % (color, text)
|
|
item.set_markup( markup )
|
|
|
|
def setTooltip( self, widget, tip, tipPrivate = None ):
|
|
self.tooltips.set_tip( widget, tip, tipPrivate )
|
|
|
|
def RegenPlugins( self, *args, **kargs ):
|
|
#print
|
|
#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.loadTheme()
|
|
|
|
#print NAME+u" reloaded"
|
|
|
|
|
|
def show( self ):
|
|
self.window.present()
|
|
|
|
# Hack for opacity not showing on first composited draw
|
|
if self.firstTime:
|
|
self.firstTime = False
|
|
self.SetupMintMenuOpacity()
|
|
|
|
if ( "applications" in self.plugins ) and ( hasattr( self.plugins["applications"], "focusSearchEntry" ) ):
|
|
if (self.startWithFavorites):
|
|
self.plugins["applications"].changeTab(0)
|
|
self.plugins["applications"].focusSearchEntry()
|
|
|
|
def grab( self ):
|
|
gdk.gdk_pointer_grab (hash(self.window.window), True, Gdk.EventMask.BUTTON_PRESS_MASK, None, None, Gdk.CURRENT_TIME)
|
|
Gdk.keyboard_grab( self.window.window, False, Gdk.CURRENT_TIME )
|
|
Gtk.grab_add(self.window)
|
|
|
|
def ungrab( self ):
|
|
Gtk.grab_remove(self.window)
|
|
self.window.hide()
|
|
Gdk.pointer_ungrab(Gdk.CURRENT_TIME)
|
|
Gdk.keyboard_ungrab(Gdk.CURRENT_TIME)
|
|
|
|
def onMap( self, widget, event ):
|
|
self.grab()
|
|
|
|
def onShow( self, widget ):
|
|
for plugin in self.plugins.values():
|
|
if hasattr( plugin, "onShowMenu" ):
|
|
plugin.onShowMenu()
|
|
|
|
def onUnmap( self, widget, event ):
|
|
self.ungrab()
|
|
|
|
for plugin in self.plugins.values():
|
|
if hasattr( plugin, "onHideMenu" ):
|
|
plugin.onHideMenu()
|
|
|
|
def onKeyPress( self, widget, event ):
|
|
if event.keyval == Gdk.KEY_Escape or self.keybinder.is_hotkey(event.keyval, event.get_state()):
|
|
self.hide()
|
|
return True
|
|
return False
|
|
|
|
def onButtonPress( self, widget, event ):
|
|
# Check if the pointer is within the menu, else hide the menu
|
|
winatptr = Gdk.window_at_pointer()
|
|
if winatptr:
|
|
win = winatptr[0]
|
|
while win:
|
|
if win == self.window.window:
|
|
break
|
|
win = capi.get_widget(gdk.gdk_window_get_parent (hash(win)))
|
|
if not win:
|
|
self.hide( True )
|
|
else:
|
|
self.hide( True )
|
|
|
|
return True
|
|
|
|
def onGrabBroken( self, widget, event ):
|
|
if event.grab_broken.grab_window:
|
|
try:
|
|
win = event.grab_broken.grab_window
|
|
data = c_void_p()
|
|
gdk.gdk_window_get_user_data(hash(win), byref(data))
|
|
theft = capi.get_widget(ctypes.cast(data, POINTER(capi._PyGObject_Functions)))
|
|
theft.connect( "event", self.onGrabTheftEvent )
|
|
except Exception, detail:
|
|
print detail
|
|
self.window.hide()
|
|
|
|
def onGrabTheftEvent( self, widget, event ):
|
|
if event.type == Gdk.EventType.UNMAP or event.type == Gdk.EventType.SELECTION_CLEAR:
|
|
self.grab()
|
|
|
|
def hide(self, forceHide = False):
|
|
self.window.hide()
|
|
|
|
class MenuWin( object ):
|
|
def __init__( self, applet, iid ):
|
|
self.applet = applet
|
|
self.settings = Gio.Settings.new("com.linuxmint.mintmenu")
|
|
self.keybinder = keybinding.GlobalKeyBinding()
|
|
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::hide-applet-icon", self.reloadSettings )
|
|
self.settings.connect( "changed::applet-icon-size", self.reloadSettings )
|
|
self.settings.connect( "changed::hot-key", self.hotkeyChanged )
|
|
self.loadSettings()
|
|
|
|
self.mate_settings = Gio.Settings.new("org.mate.interface")
|
|
self.mate_settings.connect( "changed::gtk-theme", self.changeTheme )
|
|
|
|
self.createPanelButton()
|
|
|
|
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.keybinder )
|
|
self.mainwin.window.connect( "map-event", lambda *args: self.applet.set_state( Gtk.StateType.SELECTED ) )
|
|
self.mainwin.window.connect( "unmap-event", lambda *args: self.applet.set_state( Gtk.StateType.NORMAL ) )
|
|
self.mainwin.window.connect( "size-allocate", lambda *args: self.positionMenu() )
|
|
|
|
self.mainwin.window.set_name("mintmenu") # Name used in Gtk RC files
|
|
|
|
if self.mainwin.icon:
|
|
Gtk.Window.set_default_icon_name( self.mainwin.icon )
|
|
|
|
self.bind_hot_key()
|
|
|
|
def onBindingPress(self, binder):
|
|
try:
|
|
if self.mainwin.window.get_visible():
|
|
self.mainwin.window.hide()
|
|
self.mainwin.toggle.set_active(False)
|
|
else:
|
|
MenuWin.showMenu(self,self.mainwin.toggle)
|
|
self.mainwin.window.show()
|
|
#self.mainwin.wTree.get_widget( 'PluginTabs' ).set_curremenu_editor = SetGconf( self.client, "string", "/apps/usp/menu_editor", "mozo" )
|
|
except Exception, cause:
|
|
print cause
|
|
|
|
def enter_notify(self, applet, event):
|
|
self.do_image(self.buttonIcon, True)
|
|
|
|
def leave_notify(self, applet, event):
|
|
self.do_image(self.buttonIcon, False)
|
|
|
|
def do_image(self, image_file, saturate):
|
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file(image_file)
|
|
if saturate:
|
|
GdkPixbuf.Pixbuf.saturate_and_pixelate(pixbuf, pixbuf, 1.5, False)
|
|
self.button_icon.set_from_pixbuf(pixbuf)
|
|
|
|
def createPanelButton( self ):
|
|
self.button_icon = Gtk.Image.new_from_file( self.buttonIcon )
|
|
self.systemlabel = Gtk.Label(label= self.buttonText )
|
|
if os.path.exists("/etc/linuxmint/info"):
|
|
import commands
|
|
tooltip = commands.getoutput("cat /etc/linuxmint/info | grep DESCRIPTION")
|
|
tooltip = tooltip.replace("DESCRIPTION", "")
|
|
tooltip = tooltip.replace("=", "")
|
|
tooltip = tooltip.replace("\"", "")
|
|
self.systemlabel.set_tooltip_text(tooltip)
|
|
self.button_icon.set_tooltip_text(tooltip)
|
|
if self.applet.get_orient() == MatePanelApplet.AppletOrient.UP or self.applet.get_orient() == MatePanelApplet.AppletOrient.DOWN:
|
|
self.button_box = Gtk.HBox()
|
|
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.VBox()
|
|
self.systemlabel.set_angle( 270 )
|
|
self.button_box.pack_start( self.systemlabel , True, True, 0)
|
|
self.button_box.pack_start( self.button_icon , True, True, 0)
|
|
self.button_icon.set_padding( 5, 0 )
|
|
elif self.applet.get_orient() == MatePanelApplet.AppletOrient.RIGHT:
|
|
self.button_box = Gtk.VBox()
|
|
self.systemlabel.set_angle( 90 )
|
|
self.button_box.pack_start( self.button_icon , True, True, 0)
|
|
self.button_box.pack_start( self.systemlabel , True, True, 0)
|
|
self.button_icon.set_padding( 0, 5 )
|
|
|
|
self.button_box.set_homogeneous( False )
|
|
self.button_box.show_all()
|
|
self.sizeButton()
|
|
|
|
self.applet.add( self.button_box )
|
|
self.applet.set_background_widget( self.applet )
|
|
|
|
|
|
def loadSettings( self, *args, **kargs ):
|
|
self.hideIcon = self.settings.get_boolean( "hide-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" )
|
|
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()
|
|
self.mainwin.loadTheme()
|
|
|
|
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.HBox()
|
|
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.VBox()
|
|
self.systemlabel.set_angle( 270 )
|
|
self.button_box.reorder_child( self.button_icon, 1 )
|
|
self.button_icon.set_padding( 0, 5 )
|
|
elif self.applet.get_orient() == MatePanelApplet.AppletOrient.RIGHT:
|
|
tmpbox = Gtk.VBox()
|
|
self.systemlabel.set_angle( 90 )
|
|
self.button_box.reorder_child( self.button_icon, 0 )
|
|
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.button_icon.set_from_file( self.buttonIcon )
|
|
self.sizeButton()
|
|
|
|
def bind_hot_key (self):
|
|
try:
|
|
if self.hotkeyText != "":
|
|
self.keybinder.grab( self.hotkeyText )
|
|
self.keybinder.connect("activate", self.onBindingPress)
|
|
self.keybinder.start()
|
|
# Binding menu to hotkey
|
|
print "Binding to Hot Key: " + self.hotkeyText
|
|
|
|
except Exception, cause:
|
|
print "** WARNING ** - Menu Hotkey Binding Error"
|
|
print "Error Report :\n", str(cause)
|
|
pass
|
|
|
|
def hotkeyChanged (self, schema, key):
|
|
self.keybinder.ungrab()
|
|
self.hotkeyText = self.settings.get_string( "hot-key" )
|
|
if self.hotkeyText != "":
|
|
self.keybinder.grab(self.hotkeyText)
|
|
|
|
def sizeButton( self ):
|
|
if self.hideIcon:
|
|
self.button_icon.hide()
|
|
else:
|
|
self.button_icon.show()
|
|
# This code calculates width and height for the button_box
|
|
# and takes the orientation in account
|
|
sl_req = Gtk.Requisition()
|
|
bi_req = Gtk.Requisition()
|
|
self.button_icon.size_request(bi_req)
|
|
self.systemlabel.size_request(sl_req)
|
|
if self.applet.get_orient() == MatePanelApplet.AppletOrient.UP or self.applet.get_orient() == MatePanelApplet.AppletOrient.DOWN:
|
|
if self.hideIcon:
|
|
self.systemlabel.size_request(sl_req)
|
|
self.applet.set_size_request( sl_req.width + 2, -1 )
|
|
else:
|
|
self.applet.set_size_request( sl_req.width + bi_req.width + 5, bi_req.height )
|
|
else:
|
|
if self.hideIcon:
|
|
self.applet.set_size_request( bi_req.width, sl_req.height + 2 )
|
|
else:
|
|
self.applet.set_size_request( bi_req.width, sl_req.height + bi_req.height + 5 )
|
|
|
|
def reloadSettings( self, *args ):
|
|
self.loadSettings()
|
|
self.updateButton()
|
|
|
|
def showAboutDialog( self, action, userdata = None ):
|
|
|
|
about = Gtk.AboutDialog()
|
|
about.set_name("mintMenu")
|
|
import commands
|
|
version = commands.getoutput("/usr/lib/linuxmint/common/version.py mintmenu")
|
|
about.set_version(version)
|
|
try:
|
|
h = open('/usr/share/common-licenses/GPL','r')
|
|
s = h.readlines()
|
|
gpl = ""
|
|
for line in s:
|
|
gpl += line
|
|
h.close()
|
|
about.set_license(gpl)
|
|
except Exception, detail:
|
|
print detail
|
|
about.set_comments( _("Advanced Gnome 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( "mateconf-editor /apps/mintMenu" )
|
|
Execute( os.path.join( PATH, "mintMenuConfig.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( True )
|
|
|
|
def toggleMenu( self ):
|
|
if self.applet.state & Gtk.StateType.SELECTED:
|
|
self.mainwin.hide( True )
|
|
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
|
|
|
|
x = c_int()
|
|
y = c_int()
|
|
# Get the dimensions/position of the widgetToAlignWith
|
|
gdk.gdk_window_get_origin(hash(self.applet.window), byref(x), byref(y))
|
|
entryX = x.value
|
|
entryY = y.value
|
|
|
|
entryWidth, entryHeight = self.applet.get_allocation().width, self.applet.get_allocation().height
|
|
entryHeight = entryHeight + self.mainwin.offset
|
|
|
|
# Get the screen dimensions
|
|
screenHeight = Gdk.Screen.height()
|
|
screenWidth = Gdk.Screen.width()
|
|
if self.applet.get_orient() == MatePanelApplet.AppletOrient.UP or self.applet.get_orient() == MatePanelApplet.AppletOrient.DOWN:
|
|
if entryX + ourWidth < screenWidth or entryX + entryWidth / 2 < screenWidth / 2:
|
|
# Align to the left of the entry
|
|
newX = entryX
|
|
else:
|
|
# Align to the right of the entry
|
|
newX = entryX + entryWidth - ourWidth
|
|
|
|
if entryY + entryHeight / 2 < screenHeight / 2:
|
|
# Align to the bottom of the entry
|
|
newY = entryY + entryHeight
|
|
else:
|
|
newY = entryY - ourHeight
|
|
else:
|
|
if entryX + entryWidth / 2 < screenWidth / 2:
|
|
# Align to the left of the entry
|
|
newX = entryX + entryWidth
|
|
else:
|
|
# Align to the right of the entry
|
|
newX = entryX - ourWidth
|
|
|
|
if entryY + ourHeight < screenHeight or entryY + entryHeight / 2 < screenHeight / 2:
|
|
# Align to the bottom of the entry
|
|
newY = entryY
|
|
else:
|
|
newY = entryY - ourHeight + 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("context-menu")
|
|
action = Gtk.Action("MintMenuPrefs", _("Preferences"), None, "gtk-preferences")
|
|
action.connect("activate", self.showPreferences)
|
|
action_group.add_action(action)
|
|
action = Gtk.Action("MintMenuEdit", _("Edit menu"), None, "gtk-edit")
|
|
action.connect("activate", self.showMenuEditor)
|
|
action_group.add_action(action)
|
|
action = Gtk.Action("MintMenuReload", _("Reload plugins"), None, "gtk-refresh")
|
|
action.connect("activate", self.mainwin.RegenPlugins)
|
|
action_group.add_action(action)
|
|
action = Gtk.Action("MintMenuAbout", _("About"), None, "gtk-about")
|
|
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 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)
|
|
|