2009-07-27 11:45:34 +01:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
try:
|
|
|
|
import sys
|
|
|
|
import gtk
|
|
|
|
import gtk.glade
|
|
|
|
import pango
|
|
|
|
import os
|
|
|
|
import gnomeapplet
|
|
|
|
import gettext
|
|
|
|
import gnomevfs
|
|
|
|
import traceback
|
|
|
|
import time
|
|
|
|
import gc
|
|
|
|
import xdg.Config
|
|
|
|
import pygtk
|
|
|
|
pygtk.require( "2.0" )
|
|
|
|
except Exception, e:
|
|
|
|
print e
|
|
|
|
sys.exit( 1 )
|
|
|
|
|
|
|
|
global mbindkey
|
|
|
|
# Load the key binding lib (developped by deskbar-applet, copied into mintMenu so we don't end up with an unnecessary dependency)
|
|
|
|
try:
|
|
|
|
sys.path.append('/usr/lib/python2.5/site-packages/deskbar/core/keybinder')
|
|
|
|
from _keybinder import tomboy_keybinder_bind as bind_key
|
|
|
|
except Exception, cause:
|
|
|
|
print "*********** Keybind Driver Load Failure **************"
|
|
|
|
print "Error Report : ", str(cause)
|
|
|
|
pass
|
|
|
|
|
|
|
|
# Rename the process
|
|
|
|
try:
|
|
|
|
import dl
|
|
|
|
libc = dl.open( "/lib/libc.so.6" )
|
2009-07-29 21:50:43 +01:00
|
|
|
libc.call( "prctl", 15, "mintmenu", 0, 0, 0 )
|
2009-07-27 11:45:34 +01:00
|
|
|
libc.close()
|
|
|
|
except ImportError:
|
|
|
|
pass
|
|
|
|
|
2009-07-29 21:50:43 +01:00
|
|
|
# i18n
|
|
|
|
gettext.install("messages", "/usr/lib/linuxmint/mintMenu/locale")
|
2009-07-27 11:45:34 +01:00
|
|
|
|
2009-07-29 21:50:43 +01:00
|
|
|
NAME = _("Menu")
|
|
|
|
ICON = "/usr/lib/linuxmint/mintMenu/icon.svg"
|
2009-07-27 11:45:34 +01:00
|
|
|
PATH = os.path.abspath( os.path.dirname( sys.argv[0] ) )
|
|
|
|
|
|
|
|
sys.path.append( os.path.join( PATH , "plugins") )
|
|
|
|
|
|
|
|
# FIXME: Get the windowmanager from somewhere, don't take GNOME for granted
|
|
|
|
xdg.Config.setWindowManager( "GNOME" )
|
|
|
|
|
|
|
|
from easybuttons import iconManager
|
|
|
|
from easygconf import EasyGConf
|
|
|
|
from execute import *
|
|
|
|
|
2009-07-29 21:50:43 +01:00
|
|
|
|
2009-07-27 11:45:34 +01:00
|
|
|
|
|
|
|
class MainWindow( object ):
|
|
|
|
"""This is the main class for the application"""
|
|
|
|
|
|
|
|
def __init__( self, toggleButton ):
|
|
|
|
|
|
|
|
self.path = os.path.abspath( os.path.dirname( sys.argv[0] ) )
|
|
|
|
sys.path.append( os.path.join( self.path, "plugins") )
|
|
|
|
|
|
|
|
self.icon = ICON
|
|
|
|
|
|
|
|
self.toggle = toggleButton
|
|
|
|
# Load glade file and extract widgets
|
|
|
|
gladefile = os.path.join( self.path, "mintMenu.glade" )
|
|
|
|
wTree = gtk.glade.XML( gladefile, "mainWindow" )
|
|
|
|
self.window = wTree.get_widget( "mainWindow" )
|
|
|
|
self.paneholder = wTree.get_widget( "paneholder" )
|
|
|
|
self.sidepane = wTree.get_widget( "sidepane" )
|
|
|
|
self.pinbutton = wTree.get_widget( "pin_button" )
|
|
|
|
self.pinholder = wTree.get_widget( "pinholder" )
|
|
|
|
self.border = wTree.get_widget( "border" )
|
|
|
|
|
|
|
|
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 )
|
|
|
|
|
|
|
|
dic = {"on_window1_destroy" : self.quit_cb,
|
|
|
|
"on_pin_button_toggled" : self.PinMenu}
|
|
|
|
wTree.signal_autoconnect( dic )
|
|
|
|
|
|
|
|
self.gconf = EasyGConf( "/apps/mintMenu/" )
|
|
|
|
self.gconftheme = EasyGConf ( "/desktop/gnome/interface/" )
|
|
|
|
|
|
|
|
self.getSetGconfEntries()
|
|
|
|
self.SetupMintMenuBorder()
|
|
|
|
|
|
|
|
self.tooltips = gtk.Tooltips()
|
|
|
|
if self.globalEnableTooltips and self.enableTooltips:
|
|
|
|
self.tooltips.enable()
|
|
|
|
else:
|
|
|
|
self.tooltips.disable()
|
|
|
|
|
|
|
|
self.PopulatePlugins();
|
|
|
|
|
|
|
|
self.gconf.notifyAdd( "plugins_list", self.RegenPlugins )
|
|
|
|
self.gconftheme.notifyAdd( "gtk_theme", self.RegenPlugins )
|
|
|
|
self.gconf.notifyAdd( "show_side_pane", self.toggleShowSidepane )
|
|
|
|
self.gconf.notifyAdd( "/apps/panel/global/tooltips_enabled", self.toggleTooltipsEnabled )
|
|
|
|
self.gconf.notifyAdd( "tooltips_enabled", self.toggleTooltipsEnabled )
|
|
|
|
|
|
|
|
self.gconf.notifyAdd( "use_custom_color", self.toggleUseCustomColor )
|
|
|
|
self.gconf.notifyAdd( "custom_border_color", self.toggleCustomBorderColor )
|
|
|
|
self.gconf.notifyAdd( "custom_heading_color", self.toggleCustomHeadingColor )
|
|
|
|
self.gconf.notifyAdd( "custom_color", self.toggleCustomBackgroundColor )
|
|
|
|
self.gconf.notifyAdd( "border_width", self.toggleBorderWidth )
|
|
|
|
|
|
|
|
def quit_cb (self):
|
|
|
|
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, "destroy" ):
|
|
|
|
plugin.wake()
|
|
|
|
|
|
|
|
def toggleTooltipsEnabled( self, client, connection_id, entry, args ):
|
|
|
|
if entry.get_key() == "/apps/panel/global/tooltips_enabled":
|
|
|
|
self.globalEnableTooltips = entry.get_value().get_bool()
|
|
|
|
else:
|
|
|
|
self.enableTooltips = entry.get_value().get_bool()
|
|
|
|
|
|
|
|
if self.globalEnableTooltips and self.enableTooltips:
|
|
|
|
self.tooltips.enable()
|
|
|
|
else:
|
|
|
|
self.tooltips.disable()
|
|
|
|
|
|
|
|
def toggleShowSidepane( self, client, connection_id, entry, args ):
|
|
|
|
self.sidepanevisible = entry.get_value().get_bool()
|
|
|
|
if self.sidepanevisible == False and self.pinmenu == False:
|
|
|
|
self.sidepane.hide()
|
|
|
|
else:
|
|
|
|
self.sidepane.show()
|
|
|
|
|
|
|
|
def toggleBorderWidth( self, client, connection_id, entry, args ):
|
|
|
|
self.borderwidth = entry.get_value().get_int()
|
|
|
|
self.SetupMintMenuBorder()
|
|
|
|
|
|
|
|
def toggleUseCustomColor( self, client, connection_id, entry, args ):
|
|
|
|
self.usecustomcolor = entry.get_value().get_bool()
|
|
|
|
self.SetupMintMenuBorder()
|
|
|
|
self.SetPaneColors( self.panesToColor )
|
|
|
|
self.SetHeadingStyle( self.headingsToColor )
|
|
|
|
|
|
|
|
|
|
|
|
def toggleCustomBorderColor( self, client, connection_id, entry, args ):
|
|
|
|
self.custombordercolor = entry.get_value().get_string()
|
|
|
|
self.SetupMintMenuBorder()
|
|
|
|
|
|
|
|
def toggleCustomBackgroundColor( self, client, connection_id, entry, args ):
|
|
|
|
self.customcolor = entry.get_value().get_string()
|
|
|
|
self.SetPaneColors( self.panesToColor )
|
|
|
|
|
|
|
|
def toggleCustomHeadingColor( self, client, connection_id, entry, args ):
|
|
|
|
self.customheadingcolor = entry.get_value().get_string()
|
|
|
|
self.SetHeadingStyle( self.headingsToColor )
|
|
|
|
|
|
|
|
|
|
|
|
def getSetGconfEntries( self ):
|
|
|
|
self.pluginlist = self.gconf.get( "list-string", "plugins_list",['newpane','places', 'system_management', 'newpane', 'applications'] )
|
|
|
|
self.dottedfile = os.path.join( self.path, "dotted.png")
|
|
|
|
|
|
|
|
self.usecustomcolor = self.gconf.get( "bool", "use_custom_color", False )
|
|
|
|
self.customcolor = self.gconf.get( "color", "custom_color", "#EEEEEE" )
|
|
|
|
self.customheadingcolor = self.gconf.get( "color", "custom_heading_color", "#001155" )
|
|
|
|
self.custombordercolor = self.gconf.get( "color", "custom_border_color", "#001155" )
|
|
|
|
|
|
|
|
self.borderwidth = self.gconf.get( "int", "border_width", 1 )
|
|
|
|
self.offset = self.gconf.get( "int", "mintMenu_offset", 0 )
|
|
|
|
self.pinmenu = self.gconf.get( "bool", "pin_menu", False )
|
|
|
|
self.enableTooltips = self.gconf.get( "bool", "tooltips_enabled", True )
|
|
|
|
self.globalEnableTooltips = self.gconf.get( "bool", "/apps/panel/global/tooltips_enabled", True )
|
|
|
|
self.sidepanevisible = self.gconf.get( "bool", "show_side_pane", False )
|
|
|
|
|
|
|
|
|
|
|
|
def PinMenu(self, *args, **kargs):
|
|
|
|
self.pinmenu = self.pinbutton.get_active()
|
|
|
|
self.gconf.set("bool", "pin_menu", self.pinmenu)
|
|
|
|
|
|
|
|
if self.pinmenu == True:
|
|
|
|
self.sidepane.show()
|
|
|
|
elif not self.sidepanevisible:
|
|
|
|
self.sidepane.hide()
|
|
|
|
|
|
|
|
|
|
|
|
def SetupMintMenuBorder( self ):
|
|
|
|
if self.usecustomcolor:
|
|
|
|
self.window.modify_bg( gtk.STATE_NORMAL, gtk.gdk.color_parse( self.custombordercolor ) )
|
|
|
|
else:
|
|
|
|
self.window.modify_bg( gtk.STATE_NORMAL, self.window.rc_get_style().bg[ gtk.STATE_SELECTED ] )
|
|
|
|
self.border.set_padding( self.borderwidth, self.borderwidth, self.borderwidth, self.borderwidth )
|
|
|
|
self.SetPaneColors( [ self.sidepane ] )
|
|
|
|
|
|
|
|
self.pinbutton.set_active( self.pinmenu )
|
|
|
|
|
|
|
|
if self.sidepanevisible == False and self.pinmenu == False:
|
|
|
|
self.sidepane.hide()
|
|
|
|
else:
|
|
|
|
self.sidepane.show()
|
|
|
|
|
|
|
|
|
|
|
|
def PopulatePlugins( self ):
|
|
|
|
self.panesToColor = [ ]
|
|
|
|
self.headingsToColor = [ ]
|
|
|
|
start = time.time()
|
|
|
|
PluginPane = gtk.EventBox()
|
|
|
|
PluginPane.show()
|
|
|
|
PaneLadder = gtk.VBox( False, 0 )
|
|
|
|
PluginPane.add( PaneLadder )
|
|
|
|
self.SetPaneColors( [ PluginPane ] )
|
|
|
|
ImageBox = gtk.EventBox()
|
|
|
|
self.SetPaneColors( [ ImageBox ] )
|
|
|
|
ImageBox.show()
|
|
|
|
|
|
|
|
seperatorImage = gtk.gdk.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 )
|
|
|
|
|
|
|
|
if not MyPlugin.icon:
|
|
|
|
MyPlugin.icon = "gnome-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 = 'gnome-logo-icon.png'
|
|
|
|
print u"Unable to load " + plugin + " plugin :-("
|
|
|
|
|
|
|
|
|
|
|
|
self.SetPaneColors( [MyPlugin.content_holder] )
|
|
|
|
|
|
|
|
|
|
|
|
MyPlugin.content_holder.show()
|
|
|
|
|
|
|
|
if MyPlugin.heading != "":
|
|
|
|
VBox1 = gtk.VBox( False, 0 )
|
|
|
|
Label1 = gtk.Label( MyPlugin.heading )
|
|
|
|
Align1 = gtk.Alignment( 0, 0.5, 0, 0 )
|
|
|
|
Align1.set_padding( 0, 0, 0, 0 )
|
|
|
|
Align1.add( Label1 )
|
|
|
|
self.SetHeadingStyle( [Label1] )
|
|
|
|
Align1.show()
|
|
|
|
Label1.show()
|
|
|
|
|
|
|
|
if not hasattr( MyPlugin, 'sticky' ) or MyPlugin.sticky == True:
|
|
|
|
heading = gtk.EventBox()
|
|
|
|
Align1.set_padding( 0, 0, 10, 0 )
|
|
|
|
self.SetPaneColors( [heading] )
|
|
|
|
heading.set_size_request( MyPlugin.width, 30 )
|
|
|
|
else:
|
|
|
|
heading = gtk.Button()
|
|
|
|
heading.set_relief( gtk.RELIEF_NONE )
|
|
|
|
heading.set_size_request( MyPlugin.width, -1 )
|
|
|
|
heading.connect( "button_press_event", self.TogglePluginView, VBox1, MyPlugin.icon, MyPlugin.heading, MyPlugin )
|
|
|
|
|
|
|
|
heading.add( Align1 )
|
|
|
|
heading.show()
|
|
|
|
VBox1.pack_start( heading, False )
|
|
|
|
VBox1.show()
|
|
|
|
MyPlugin.container = VBox1
|
|
|
|
#Add plugin to Plugin Box under heading button
|
|
|
|
MyPlugin.content_holder.reparent( VBox1 )
|
|
|
|
|
|
|
|
#Add plugin to main window
|
|
|
|
PaneLadder.pack_start( VBox1 )
|
|
|
|
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.SetPaneColors( MyPlugin.itemstocolor )
|
|
|
|
if hasattr( MyPlugin, 'minimized' ) and MyPlugin.minimized:
|
|
|
|
self.HidePlugin( MyPlugin.container, MyPlugin.icon, MyPlugin.heading, MyPlugin )
|
|
|
|
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.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_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 )
|
|
|
|
self.SetPaneColors( [PluginPane] )
|
|
|
|
ImageBox = gtk.EventBox()
|
|
|
|
self.SetPaneColors( [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 )
|
|
|
|
|
|
|
|
|
|
|
|
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"
|
|
|
|
|
|
|
|
|
|
|
|
def HidePlugin( self , PluginData, icon, tooltip, plugin ):
|
|
|
|
if PluginData.flags() & gtk.VISIBLE:
|
|
|
|
PluginData.hide()
|
|
|
|
Button1 = gtk.Button()
|
|
|
|
Image1 = gtk.Image()
|
|
|
|
Image1.set_from_pixbuf( iconManager.getIcon( icon, gtk.ICON_SIZE_MENU ) )
|
|
|
|
Button1.add( Image1 )
|
|
|
|
Button1.show()
|
|
|
|
self.setTooltip( Button1, tooltip )
|
|
|
|
Image1.show()
|
|
|
|
|
|
|
|
#Show side pane if it is hidden
|
|
|
|
self.sidepane.show()
|
|
|
|
Button1.connect( "button_press_event", self.TogglePluginView, PluginData, icon, tooltip, plugin )
|
|
|
|
self.pinholder.pack_start( Button1, False, False, 0 )
|
|
|
|
|
|
|
|
|
|
|
|
def TogglePluginView( self, widget, event, PluginData, icon, tooltip, plugin ):
|
|
|
|
if event.button == 1:
|
|
|
|
if PluginData.flags() & gtk.VISIBLE:
|
|
|
|
PluginData.hide()
|
|
|
|
if hasattr( plugin, 'SetHidden' ):
|
|
|
|
plugin.SetHidden(True)
|
|
|
|
Button1 = gtk.Button()
|
|
|
|
Image1 = gtk.Image()
|
|
|
|
Image1.set_from_pixbuf( iconManager.getIcon( icon, gtk.ICON_SIZE_MENU ) )
|
|
|
|
Button1.add( Image1 )
|
|
|
|
Button1.show()
|
|
|
|
self.setTooltip( Button1, tooltip )
|
|
|
|
Image1.show()
|
|
|
|
|
|
|
|
#Show side pane if it is hidden
|
|
|
|
self.sidepane.show()
|
|
|
|
Button1.connect( "button_press_event", self.TogglePluginView, PluginData, icon, tooltip, plugin )
|
|
|
|
self.pinholder.pack_start( Button1, False, False, 0 )
|
|
|
|
|
|
|
|
else:
|
|
|
|
PluginData.show()
|
|
|
|
if hasattr( plugin, 'SetHidden' ):
|
|
|
|
plugin.SetHidden(False)
|
|
|
|
widget.destroy()
|
|
|
|
if len( self.pinholder.get_children() ) == 1:
|
|
|
|
if self.sidepanevisible == False and self.pinmenu == False:
|
|
|
|
self.sidepane.hide()
|
|
|
|
else:
|
|
|
|
self.sidepane.show()
|
|
|
|
|
|
|
|
def SetPaneColors( self, items ):
|
|
|
|
for item in items:
|
|
|
|
if item not in self.panesToColor:
|
|
|
|
self.panesToColor.append( item )
|
|
|
|
|
|
|
|
if self.usecustomcolor:
|
|
|
|
for item in items:
|
|
|
|
item.modify_bg( gtk.STATE_NORMAL, gtk.gdk.color_parse( self.customcolor ) )
|
|
|
|
else:
|
|
|
|
for item in items:
|
|
|
|
item.modify_bg( gtk.STATE_NORMAL, self.paneholder.rc_get_style().bg[ gtk.STATE_NORMAL ] )
|
|
|
|
|
|
|
|
|
|
|
|
def SetHeadingStyle( self, items ):
|
|
|
|
for item in items:
|
|
|
|
if item not in self.headingsToColor:
|
|
|
|
self.headingsToColor.append( item )
|
|
|
|
|
|
|
|
HeadingStyle = pango.AttrList()
|
|
|
|
attr = pango.AttrSize( 12000, 0, -1 )
|
|
|
|
HeadingStyle.insert( attr )
|
|
|
|
|
|
|
|
if self.usecustomcolor:
|
|
|
|
headingcolor = gtk.gdk.color_parse( self.customheadingcolor )
|
|
|
|
attr = pango.AttrForeground( headingcolor.red, headingcolor.green, headingcolor.blue, 0, -1 )
|
|
|
|
HeadingStyle.insert( attr )
|
|
|
|
# else:
|
|
|
|
# headingcolor = self.window.rc_get_style().bg[ gtk.STATE_SELECTED ]
|
|
|
|
|
|
|
|
attr = pango.AttrWeight( pango.WEIGHT_BOLD, 0, -1 )
|
|
|
|
HeadingStyle.insert( attr )
|
|
|
|
|
|
|
|
for item in items:
|
|
|
|
item.set_attributes( HeadingStyle )
|
|
|
|
|
|
|
|
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:
|
|
|
|
if item.name != "sidepane":
|
|
|
|
item.destroy()
|
|
|
|
|
|
|
|
for plugin in self.plugins.values():
|
|
|
|
if hasattr( plugin, "destroy" ):
|
|
|
|
plugin.destroy()
|
|
|
|
|
|
|
|
del plugin
|
|
|
|
del self.plugins
|
|
|
|
|
|
|
|
gc.collect()
|
|
|
|
|
|
|
|
self.getSetGconfEntries()
|
|
|
|
self.PopulatePlugins()
|
|
|
|
|
|
|
|
#print NAME+u" reloaded"
|
|
|
|
|
|
|
|
|
|
|
|
def show( self ):
|
|
|
|
self.window.present()
|
|
|
|
|
|
|
|
if ( "applications" in self.plugins ) and ( hasattr( self.plugins["applications"], "focusSearchEntry" ) ):
|
|
|
|
self.plugins["applications"].focusSearchEntry()
|
|
|
|
|
|
|
|
def grab( self ):
|
|
|
|
gtk.gdk.pointer_grab( self.window.window, True, gtk.gdk.BUTTON_PRESS_MASK )
|
|
|
|
gtk.gdk.keyboard_grab( self.window.window, False )
|
|
|
|
self.window.grab_add()
|
|
|
|
|
|
|
|
def ungrab( self ):
|
|
|
|
self.window.grab_remove()
|
|
|
|
gtk.gdk.pointer_ungrab()
|
|
|
|
gtk.gdk.keyboard_ungrab()
|
|
|
|
|
|
|
|
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 == gtk.keysyms.Escape or event.keyval == gtk.keysyms.Super_L:
|
|
|
|
self.hide()
|
|
|
|
return False
|
|
|
|
|
|
|
|
def onButtonPress( self, widget, event ):
|
|
|
|
# Check if the pointer is within the menu, else hide the menu
|
|
|
|
winatptr = gtk.gdk.window_at_pointer()
|
|
|
|
|
|
|
|
if winatptr:
|
|
|
|
win = winatptr[0]
|
|
|
|
while win:
|
|
|
|
if win == self.window.window:
|
|
|
|
break
|
|
|
|
win = win.get_parent()
|
|
|
|
if not win:
|
|
|
|
self.hide( True )
|
|
|
|
else:
|
|
|
|
self.hide( True )
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
def onGrabBroken( self, widget, event ):
|
|
|
|
if event.grab_window:
|
|
|
|
try:
|
|
|
|
theft = event.grab_window.get_user_data()
|
|
|
|
theft.connect( "event", self.onGrabTheftEvent )
|
|
|
|
except:
|
|
|
|
self.window.hide( True )
|
|
|
|
|
|
|
|
def onGrabTheftEvent( self, widget, event ):
|
|
|
|
if event.type == gtk.gdk.UNMAP or event.type == gtk.gdk.SELECTION_CLEAR:
|
|
|
|
self.grab()
|
|
|
|
|
|
|
|
def hide( self, forceHide = False ):
|
|
|
|
if not self.pinmenu or forceHide:
|
|
|
|
self.window.hide()
|
|
|
|
|
|
|
|
class MenuWin( object ):
|
|
|
|
def __init__( self, applet, iid ):
|
|
|
|
self.applet = applet
|
|
|
|
|
|
|
|
self.gconf = EasyGConf( "/apps/mintMenu/" )
|
|
|
|
self.gconf.notifyAdd( "applet_text", self.gconfEntriesChanged )
|
|
|
|
self.gconf.notifyAdd( "hot_key", self.gconfEntriesChanged )
|
|
|
|
self.gconf.notifyAdd( "applet_icon", self.gconfEntriesChanged )
|
|
|
|
self.gconf.notifyAdd( "hide_applet_icon", self.gconfEntriesChanged )
|
|
|
|
self.gconf.notifyAdd( "applet_icon_size", self.gconfEntriesChanged )
|
|
|
|
self.getGconfEntries()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.createPanelButton()
|
|
|
|
|
|
|
|
self.applet.set_applet_flags( gnomeapplet.EXPAND_MINOR )
|
|
|
|
self.applet.connect( "button-press-event", self.showMenu )
|
|
|
|
self.applet.connect( "change-orient", self.changeOrientation )
|
|
|
|
self.applet.connect( "change-background", self.changeBackground )
|
|
|
|
self.mainwin = MainWindow( self.button_box )
|
|
|
|
self.mainwin.window.connect( "map-event", lambda *args: self.applet.set_state( gtk.STATE_SELECTED ) )
|
|
|
|
self.mainwin.window.connect( "unmap-event", lambda *args: self.applet.set_state( gtk.STATE_NORMAL ) )
|
|
|
|
self.mainwin.window.connect( "size-allocate", lambda *args: self.positionMenu() )
|
|
|
|
|
|
|
|
icon = iconManager.getIcon( self.mainwin.icon, 1 )
|
|
|
|
if icon:
|
|
|
|
gtk.window_set_default_icon( icon )
|
|
|
|
|
|
|
|
self.propxml = """
|
|
|
|
<popup name="button3">
|
|
|
|
<menuitem name="Item 1" verb="Preferences" label="%s" pixtype="stock" pixname="gtk-preferences" />
|
|
|
|
<menuitem name="Item 1" verb="Edit" label="%s" pixtype="stock" pixname="gtk-edit" />
|
|
|
|
<menuitem name="Item 2" verb="Reload" label="%s" pixtype="stock" pixname="gtk-refresh" />
|
|
|
|
<menuitem name="Item 3" verb="About" label="%s" pixtype="stock" pixname="gtk-about" />
|
|
|
|
</popup>
|
|
|
|
""" % ( _("Preferences"), _("Edit menu"), _("Reload plugins"), _("About") )
|
|
|
|
self.verbs = [ ("Preferences", self.showPreferences), ("Edit", self.showMenuEditor), ("About", self.showAboutDialog), ("Reload",self.mainwin.RegenPlugins) ]
|
|
|
|
self.bind_hot_key()
|
|
|
|
|
|
|
|
def onBindingPress(self):
|
|
|
|
try:
|
|
|
|
if self.mainwin.window.flags() & gtk.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", "alacarte" )
|
|
|
|
except Exception, cause:
|
|
|
|
print cause
|
|
|
|
|
|
|
|
def createPanelButton( self ):
|
|
|
|
self.button_icon = gtk.image_new_from_file( self.buttonIcon )
|
|
|
|
self.systemlabel = gtk.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() == gnomeapplet.ORIENT_UP or self.applet.get_orient() == gnomeapplet.ORIENT_DOWN:
|
|
|
|
self.button_box = gtk.HBox()
|
|
|
|
self.button_box.pack_start( self.button_icon, False, False )
|
|
|
|
self.button_box.pack_start( self.systemlabel, False, False )
|
|
|
|
|
|
|
|
self.button_icon.set_padding( 5, 0 )
|
|
|
|
# if we have a vertical panel
|
|
|
|
elif self.applet.get_orient() == gnomeapplet.ORIENT_LEFT:
|
|
|
|
self.button_box = gtk.VBox()
|
|
|
|
self.systemlabel.set_angle( 90 )
|
|
|
|
self.button_box.pack_start( self.systemlabel )
|
|
|
|
self.button_box.pack_start( self.button_icon )
|
|
|
|
self.button_icon.set_padding( 5, 0 )
|
|
|
|
elif self.applet.get_orient() == gnomeapplet.ORIENT_RIGHT:
|
|
|
|
self.button_box = gtk.VBox()
|
|
|
|
self.systemlabel.set_angle( 270 )
|
|
|
|
self.button_box.pack_start( self.button_icon )
|
|
|
|
self.button_box.pack_start( self.systemlabel )
|
|
|
|
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 )
|
|
|
|
|
|
|
|
|
|
|
|
def getGconfEntries( self, *args, **kargs ):
|
|
|
|
self.hideIcon = self.gconf.get( "bool", "hide_applet_icon", False )
|
|
|
|
self.buttonText = self.gconf.get( "string", "applet_text", "Menu" )
|
|
|
|
self.hotkeyText = self.gconf.get( "string", "hot_key", "<Control>Super_L" )
|
2009-07-29 21:50:43 +01:00
|
|
|
self.buttonIcon = self.gconf.get( "string", "applet_icon", "/usr/lib/linuxmint/mintMenu/icon.png" )
|
2009-07-27 11:45:34 +01:00
|
|
|
self.setIconSize( self.gconf.get( "int", "applet_icon_size", 2 ) )
|
|
|
|
|
|
|
|
def setIconSize( self, icon_size):
|
|
|
|
if icon_size >= 4:
|
|
|
|
self.iconSize = gtk.ICON_SIZE_DIALOG
|
|
|
|
elif icon_size == 3:
|
|
|
|
self.iconSize = gtk.ICON_SIZE_DND
|
|
|
|
elif icon_size == 2:
|
|
|
|
self.iconSize = gtk.ICON_SIZE_BUTTON
|
|
|
|
else:
|
|
|
|
self.iconSize = gtk.ICON_SIZE_MENU
|
|
|
|
|
|
|
|
def changeBackground( self, applet, type, color, pixmap ):
|
|
|
|
# get reset style
|
|
|
|
self.applet.set_style(None)
|
|
|
|
rc_style = gtk.RcStyle()
|
|
|
|
self.applet.modify_style(rc_style)
|
|
|
|
|
|
|
|
if gnomeapplet.COLOR_BACKGROUND == type:
|
|
|
|
applet.modify_bg( gtk.STATE_NORMAL, color )
|
|
|
|
elif gnomeapplet.PIXMAP_BACKGROUND == type:
|
|
|
|
style = applet.style
|
|
|
|
style.bg_pixmap[ gtk.STATE_NORMAL ] = pixmap
|
|
|
|
applet.set_style( style )
|
|
|
|
|
|
|
|
|
|
|
|
def changeOrientation( self, *args, **kargs ):
|
|
|
|
|
|
|
|
if self.applet.get_orient() == gnomeapplet.ORIENT_UP or self.applet.get_orient() == gnomeapplet.ORIENT_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() == gnomeapplet.ORIENT_LEFT:
|
|
|
|
tmpbox = gtk.VBox()
|
|
|
|
self.systemlabel.set_angle( 90 )
|
|
|
|
self.button_box.reorder_child( self.button_icon, 1 )
|
|
|
|
self.button_icon.set_padding( 0, 5 )
|
|
|
|
elif self.applet.get_orient() == gnomeapplet.ORIENT_RIGHT:
|
|
|
|
tmpbox = gtk.VBox()
|
|
|
|
self.systemlabel.set_angle( 270 )
|
|
|
|
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:
|
|
|
|
# Binding menu to hotkey
|
|
|
|
print "Binding to Hot Key: " + self.hotkeyText
|
|
|
|
bind_key( self.hotkeyText, self.onBindingPress )
|
|
|
|
except Exception, cause:
|
|
|
|
print "** WARNING ** - Menu Hotkey Binding Error"
|
|
|
|
print "Error Report :\n", str(cause)
|
|
|
|
pass
|
|
|
|
|
|
|
|
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
|
|
|
|
if self.applet.get_orient() == gnomeapplet.ORIENT_UP or self.applet.get_orient() == gnomeapplet.ORIENT_DOWN:
|
|
|
|
if self.hideIcon:
|
|
|
|
self.applet.set_size_request( self.systemlabel.size_request()[0] + 2, -1 )
|
|
|
|
else:
|
|
|
|
self.applet.set_size_request( self.systemlabel.size_request()[0] + self.button_icon.size_request()[0] + 5, self.button_icon.size_request()[1] )
|
|
|
|
else:
|
|
|
|
if self.hideIcon:
|
|
|
|
self.applet.set_size_request( self.button_icon.size_request()[0], self.systemlabel.size_request()[1] + 2 )
|
|
|
|
else:
|
|
|
|
self.applet.set_size_request( self.button_icon.size_request()[0], self.systemlabel.size_request()[1] + self.button_icon.size_request()[1] + 5 )
|
|
|
|
|
|
|
|
def gconfEntriesChanged( self, *args ):
|
|
|
|
self.getGconfEntries()
|
|
|
|
self.updateButton()
|
|
|
|
|
|
|
|
|
|
|
|
def showAboutDialog( self, uicomponent, verb ):
|
|
|
|
|
|
|
|
gtk.about_dialog_set_email_hook( lambda dialog, mail: gnomevfs.url_show( "mailto:" + mail ) )
|
|
|
|
gtk.about_dialog_set_url_hook( lambda dialog, url: gnomevfs.url_show( url ) )
|
|
|
|
about = gtk.AboutDialog()
|
2009-07-29 21:50:43 +01:00
|
|
|
about.set_name("mintMenu")
|
2009-07-27 11:45:34 +01:00
|
|
|
import commands
|
2009-07-29 21:50:43 +01:00
|
|
|
version = commands.getoutput("/usr/lib/linuxmint/mintMenu/version.py")
|
2009-07-27 11:45:34 +01:00
|
|
|
about.set_version(version)
|
|
|
|
try:
|
2009-07-29 21:50:43 +01:00
|
|
|
h = open('/usr/share/common-licenses/GPL','r')
|
2009-07-27 11:45:34 +01:00
|
|
|
s = h.readlines()
|
|
|
|
gpl = ""
|
|
|
|
for line in s:
|
|
|
|
gpl += line
|
|
|
|
h.close()
|
|
|
|
about.set_license(gpl)
|
|
|
|
except Exception, detail:
|
|
|
|
print detail
|
2009-07-29 21:50:43 +01:00
|
|
|
about.set_comments( _("Advanced Gnome Menu") )
|
2009-07-27 11:45:34 +01:00
|
|
|
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") )
|
2009-07-29 21:50:43 +01:00
|
|
|
about.set_logo( gtk.gdk.pixbuf_new_from_file("/usr/lib/linuxmint/mintMenu/icon.svg") )
|
2009-07-27 11:45:34 +01:00
|
|
|
about.connect( "response", lambda dialog, r: dialog.destroy() )
|
|
|
|
about.show()
|
|
|
|
|
|
|
|
|
|
|
|
def showPreferences( self, uicomponent, verb ):
|
|
|
|
# Execute( "gconf-editor /apps/mintMenu" )
|
|
|
|
Execute( os.path.join( PATH, "mintMenuConfig.py" ) )
|
|
|
|
|
|
|
|
def showMenuEditor( self, uicomponent, verb ):
|
|
|
|
Execute( "alacarte" )
|
|
|
|
|
|
|
|
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.STATE_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
|
|
|
|
|
|
|
|
# Get the dimensions/position of the widgetToAlignWith
|
|
|
|
entryX, entryY = self.applet.window.get_origin()
|
|
|
|
entryWidth, entryHeight = self.applet.get_allocation().width, self.applet.get_allocation().height
|
|
|
|
entryHeight = entryHeight + self.mainwin.offset
|
|
|
|
|
|
|
|
# Get the screen dimensions
|
|
|
|
screenHeight = gtk.gdk.screen_height()
|
|
|
|
screenWidth = gtk.gdk.screen_width()
|
|
|
|
|
|
|
|
if self.applet.get_orient() == gnomeapplet.ORIENT_UP or self.applet.get_orient() == gnomeapplet.ORIENT_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):
|
|
|
|
self.applet.setup_menu(self.propxml, self.verbs, None)
|
|
|
|
|
|
|
|
def menu_factory( applet, iid ):
|
|
|
|
MenuWin( applet, iid )
|
|
|
|
applet.show()
|
|
|
|
return True
|
|
|
|
|
|
|
|
def quit_all(widget):
|
|
|
|
gtk.main_quit()
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
if len(sys.argv) == 2 and sys.argv[1] == "run-in-window":
|
|
|
|
gtk.gdk.threads_init()
|
|
|
|
main_window = gtk.Window( gtk.WINDOW_TOPLEVEL )
|
|
|
|
main_window.set_title( NAME )
|
|
|
|
main_window.connect( "destroy", quit_all )
|
|
|
|
app = gnomeapplet.Applet()
|
|
|
|
menu_factory( app, None )
|
|
|
|
app.reparent( main_window )
|
|
|
|
main_window.show()
|
|
|
|
gtk.gdk.threads_enter()
|
|
|
|
gtk.main()
|
|
|
|
gtk.gdk.threads_leave()
|
|
|
|
else:
|
|
|
|
gnomeapplet.bonobo_factory("OAFIID:GNOME_mintMenu_Factory",
|
|
|
|
gnomeapplet.Applet.__gtype__,
|
|
|
|
"mintMenu", "0", menu_factory)
|
|
|
|
|
|
|
|
|