diff --git a/usr/lib/linuxmint/mintMenu/keybinding.py b/usr/lib/linuxmint/mintMenu/keybinding.py index 80f19c0..2a8eec3 100644 --- a/usr/lib/linuxmint/mintMenu/keybinding.py +++ b/usr/lib/linuxmint/mintMenu/keybinding.py @@ -58,10 +58,11 @@ class GlobalKeyBinding(GObject.GObject, threading.Thread): self.keymap = capi.get_widget (gdk.gdk_keymap_get_default()) self.display = Display() self.screen = self.display.screen() - self.root = self.screen.root + self.window = self.screen.root self.ignored_masks = self.get_mask_combinations(X.LockMask | X.Mod2Mask | X.Mod5Mask) self.map_modifiers() self.raw_keyval = None + self.keytext = "" def is_hotkey(self, key, modifier): keymatch = False @@ -101,21 +102,39 @@ class GlobalKeyBinding(GObject.GObject, threading.Thread): self.modifiers = None return False + self.keytext = key self.keycode = self.get_keycode(keyval) self.modifiers = int(modifiers) catch = error.CatchError(error.BadAccess) for ignored_mask in self.ignored_masks: mod = modifiers | ignored_mask - result = self.root.grab_key(self.keycode, mod, True, X.GrabModeAsync, X.GrabModeSync, onerror=catch) - self.display.sync() + result = self.window.grab_key(self.keycode, mod, True, X.GrabModeAsync, X.GrabModeSync, onerror=catch) + self.display.flush() + # sync has been blocking. Don't know why. + #self.display.sync() if catch.get_error(): return False return True def ungrab(self): if self.keycode: - self.root.ungrab_key(self.keycode, X.AnyModifier, self.root) + self.window.ungrab_key(self.keycode, X.AnyModifier, self.window) + + def rebind(self, key): + self.ungrab() + if key != "": + self.grab(key) + else: + self.keytext = "" + + def set_focus_window(self, window = None): + self.ungrab() + if window is None: + self.window = self.screen.root + else: + self.window = self.display.create_resource_object("window", gdk.gdk_x11_drawable_get_xid(hash(window))) + self.grab(self.keytext) def get_mask_combinations(self, mask): return [x for x in xrange(mask+1) if not (x & ~mask)] diff --git a/usr/lib/linuxmint/mintMenu/mintMenu.glade b/usr/lib/linuxmint/mintMenu/mintMenu.glade index 641a9b8..c8ef20d 100644 --- a/usr/lib/linuxmint/mintMenu/mintMenu.glade +++ b/usr/lib/linuxmint/mintMenu/mintMenu.glade @@ -4,7 +4,7 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK - popup + toplevel False menu True diff --git a/usr/lib/linuxmint/mintMenu/mintMenu.py b/usr/lib/linuxmint/mintMenu/mintMenu.py index 0fd119e..2c1eb59 100755 --- a/usr/lib/linuxmint/mintMenu/mintMenu.py +++ b/usr/lib/linuxmint/mintMenu/mintMenu.py @@ -21,6 +21,7 @@ try: import capi import xdg.Config import keybinding + import pointerMonitor except Exception, e: print e sys.exit( 1 ) @@ -87,21 +88,29 @@ class MainWindow( object ): 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.connect( "focus-in-event", self.onFocusIn ) + self.loseFocusId = self.window.connect( "focus-out-event", self.onFocusOut ) 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.SetupMintMenuBorder() - self.SetupMintMenuOpacity() self.tooltips = Gtk.Tooltips() if self.globalEnableTooltips and self.enableTooltips: @@ -110,20 +119,8 @@ class MainWindow( object ): self.tooltips.disable() self.PopulatePlugins(); - - self.settings.connect( "changed::plugins-list", self.RegenPlugins ) - - self.settings.connect( "changed::start-with-favorites", self.toggleStartWithFavorites ) - globalsettings = Gio.Settings.new("org.mate.panel") - globalsettings.connect( "changed::tooltips-enabled", self.toggleTooltipsEnabled ) - 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.loadTheme() + self.firstTime = True; def on_window1_destroy (self, widget, data=None): Gtk.main_quit() @@ -159,9 +156,7 @@ class MainWindow( object ): def toggleUseCustomColor( self, settings, key, args = None ): self.usecustomcolor = settings.get_boolean(key) - self.SetupMintMenuBorder() - self.SetPaneColors( self.panesToColor ) - self.SetHeadingStyle( self.headingsToColor ) + self.loadTheme() def toggleCustomBorderColor( self, settings, key, args = None ): self.custombordercolor = settings.get_string(key) @@ -189,14 +184,13 @@ class MainWindow( object ): self.enableTooltips = self.settings.get_boolean( "tooltips-enabled" ) self.startWithFavorites = self.settings.get_boolean( "start-with-favorites" ) - mate_settings = Gio.Settings.new("org.mate.panel") - self.globalEnableTooltips = mate_settings.get_boolean( "tooltips-enabled" ) + self.globalEnableTooltips = self.panelSettings.get_boolean( "tooltips-enabled" ) - def SetupMintMenuBorder( self ): + def SetupMintMenuBorder( self, defaultStyle = None ): if self.usecustomcolor: self.window.modify_bg( Gtk.StateType.NORMAL, Gdk.color_parse( self.custombordercolor ) ) - # else: - # self.window.modify_bg( Gtk.StateType.NORMAL, self.window.rc_get_style().bg[ Gtk.StateType.SELECTED ] ) + 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 ): @@ -227,10 +221,9 @@ class MainWindow( object ): PluginPane.show() PaneLadder = Gtk.VBox( False, 0 ) PluginPane.add( PaneLadder ) - self.SetPaneColors( [ PluginPane ] ) ImageBox = Gtk.EventBox() - self.SetPaneColors( [ ImageBox ] ) ImageBox.show() + self.panesToColor.extend( [ PluginPane, ImageBox ] ) seperatorImage = GdkPixbuf.Pixbuf.new_from_file( self.dottedfile ) @@ -284,9 +277,7 @@ class MainWindow( object ): print u"Unable to load " + plugin + " plugin :-(" - self.SetPaneColors( [MyPlugin.content_holder] ) - - + self.panesToColor.append( MyPlugin.content_holder ) MyPlugin.content_holder.show() VBox1 = Gtk.VBox( False, 0 ) @@ -295,14 +286,14 @@ class MainWindow( object ): Align1 = Gtk.Alignment.new( 0, 0, 0, 0 ) Align1.set_padding( 10, 5, 10, 0 ) Align1.add( Label1 ) - self.SetHeadingStyle( [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 ) - self.SetPaneColors( [heading] ) + heading.set_visible_window( False ) heading.set_size_request( MyPlugin.width, 30 ) else: heading = Gtk.HBox() @@ -331,7 +322,9 @@ class MainWindow( object ): if hasattr( MyPlugin, 'height' ): MyPlugin.content_holder.set_size_request( -1, MyPlugin.height ) if hasattr( MyPlugin, 'itemstocolor' ): - self.SetPaneColors( MyPlugin.itemstocolor ) + self.panesToColor.extend( MyPlugin.itemstocolor ) + if hasattr( MyPlugin, 'headingstocolor' ): + self.headingsToColor.extend( MyPlugin.headingstocolor ) except: # create traceback info = sys.exc_info() @@ -349,9 +342,8 @@ class MainWindow( object ): PluginPane = Gtk.EventBox() PaneLadder = Gtk.VBox( False, 0 ) PluginPane.add( PaneLadder ) - self.SetPaneColors( [PluginPane] ) ImageBox = Gtk.EventBox() - self.SetPaneColors( [ImageBox] ) + self.panesToColor.extend( [ PluginPane, ImageBox ] ) ImageBox.show() PluginPane.show_all() @@ -373,22 +365,30 @@ class MainWindow( object ): self.tooltips.disable() #print u"Loading", (time.time() - start), "s" - def SetPaneColors( self, items ): - for item in items: - if item not in self.panesToColor: - self.panesToColor.append( item ) + # 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 ) ) - # else: - # for item in items: - # item.modify_bg( Gtk.StateType.NORMAL, self.paneholder.rc_get_style().bg[ Gtk.StateType.NORMAL ] ) + # 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 ): - for item in items: - if item not in self.headingsToColor: - self.headingsToColor.append( item ) - if self.usecustomcolor: color = self.customheadingcolor else: @@ -430,84 +430,63 @@ class MainWindow( object ): self.getSetGSettingEntries() self.PopulatePlugins() + self.loadTheme() #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() + self.window.window.focus( Gdk.CURRENT_TIME ) + + # Hack for opacity not showing on first composited draw + if self.firstTime: + self.firstTime = False + self.SetupMintMenuOpacity() + + 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 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() - + def hide( self, forceHide = False ): 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() + + def onFocusIn( self, *args ): + def dummy( *args ): pass + + signalId = GObject.signal_lookup( "focus-out-event", self.window ) + while True: + result = GObject.signal_handler_find( self.window, + GObject.SignalMatchType.ID | GObject.SignalMatchType.UNBLOCKED, + signalId, 0, None, dummy, dummy ) + if result == 0: + self.window.handler_unblock( self.loseFocusId ) + else: + break + + return False + + def onFocusOut( self, *args): + if self.window.get_visible(): + self.hide() + return False + + def stopHiding( self ): + self.window.handler_block( self.loseFocusId ) class MenuWin( object ): def __init__( self, applet, iid ): @@ -523,8 +502,8 @@ class MenuWin( object ): self.settings.connect( "changed::hot-key", self.hotkeyChanged ) self.loadSettings() - mate_settings = Gio.Settings.new("org.mate.interface") - mate_settings.connect( "changed::gtk-theme", self.changeTheme ) + self.mate_settings = Gio.Settings.new("org.mate.interface") + self.mate_settings.connect( "changed::gtk-theme", self.changeTheme ) self.createPanelButton() @@ -534,8 +513,9 @@ class MenuWin( object ): 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( "map-event", self.onWindowMap ) + self.mainwin.window.connect( "unmap-event", self.onWindowUnmap ) + self.mainwin.window.connect( "realize", self.onRealize ) self.mainwin.window.connect( "size-allocate", lambda *args: self.positionMenu() ) self.mainwin.window.set_name("mintmenu") # Name used in Gtk RC files @@ -544,29 +524,52 @@ class MenuWin( object ): Gtk.Window.set_default_icon_name( self.mainwin.icon ) self.bind_hot_key() + self.applet.set_can_focus(False) + + self.pointerMonitor = pointerMonitor.PointerMonitor() + self.pointerMonitor.connect("activate", self.onPointerOutside) + + def onWindowMap( self, *args ): + self.applet.set_state( Gtk.StateType.SELECTED ) + self.keybinder.set_focus_window( self.mainwin.window.window ) + self.pointerMonitor.grabPointer() + return False + + def onWindowUnmap( self, *args ): + self.applet.set_state( Gtk.StateType.NORMAL ) + self.keybinder.set_focus_window() + self.pointerMonitor.ungrabPointer() + return False + + def onRealize( self, *args): + self.pointerMonitor.addWindowToMonitor( self.mainwin.window.window ) + self.pointerMonitor.addWindowToMonitor( self.applet.window ) + self.pointerMonitor.start() + return False + + def onPointerOutside(self, *args): + self.mainwin.hide() + return True 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 + self.toggleMenu() + return True def enter_notify(self, applet, event): self.do_image(self.buttonIcon, 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.state & Gtk.StateType.SELECTED: + if event.x >= 0 and event.y >= 0 and event.x < applet.window.get_width() and event.y < applet.window.get_height(): + self.mainwin.stopHiding() + 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) + pixbuf.saturate_and_pixelate(pixbuf, 50.0, False) self.button_icon.set_from_pixbuf(pixbuf) def createPanelButton( self ): @@ -584,20 +587,19 @@ class MenuWin( object ): 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 ) + 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.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_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 ) @@ -619,12 +621,11 @@ class MenuWin( object ): def changeTheme(self, *args): self.reloadSettings() self.applyTheme() - self.mainwin.RegenPlugins() + self.mainwin.loadTheme() def applyTheme(self): style_settings = Gtk.Settings.get_default() - mate_settings = Gio.Settings.new("org.mate.interface") - desktop_theme = mate_settings.get_string('gtk-theme') + desktop_theme = self.mate_settings.get_string('gtk-theme') if self.theme_name == "default": style_settings.set_property("gtk-theme-name", desktop_theme) else: @@ -643,12 +644,12 @@ class MenuWin( object ): 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_box.reorder_child( self.button_icon, 0 ) 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_box.reorder_child( self.button_icon, 1 ) self.button_icon.set_padding( 0, 5 ) tmpbox.set_homogeneous( False ) @@ -688,10 +689,8 @@ class MenuWin( object ): 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) + self.keybinder.rebind(self.hotkeyText) def sizeButton( self ): if self.hideIcon: @@ -706,8 +705,7 @@ class MenuWin( object ): 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 ) + self.applet.set_size_request( sl_req.width + 2, bi_req.height ) else: self.applet.set_size_request( sl_req.width + bi_req.width + 5, bi_req.height ) else: diff --git a/usr/lib/linuxmint/mintMenu/plugins/applications.py b/usr/lib/linuxmint/mintMenu/plugins/applications.py index c41ebcf..b8d7b80 100755 --- a/usr/lib/linuxmint/mintMenu/plugins/applications.py +++ b/usr/lib/linuxmint/mintMenu/plugins/applications.py @@ -253,7 +253,7 @@ class pluginclass( object ): self.builder.get_object("label7").set_text(_("All applications")) self.builder.get_object("label2").set_text(_("Applications")) - self.mintMenuWin.SetHeadingStyle( [self.builder.get_object("label6"),self.builder.get_object("label2")] ) + self.headingstocolor = [self.builder.get_object("label6"),self.builder.get_object("label2")] self.numApps = 0 # These properties are NECESSARY to maintain consistency @@ -268,7 +268,7 @@ class pluginclass( object ): self.content_holder =self.builder.get_object( "Applications" ) # Items to get custom colors - self.itemstocolor = [self.builder.get_object( "viewport1" ),self.builder.get_object( "viewport2" ),self.builder.get_object( "viewport3" ),self.builder.get_object( "notebook2" ) ] + self.itemstocolor = [self.builder.get_object( "viewport1" ),self.builder.get_object( "viewport2" ),self.builder.get_object( "viewport3" ) ] # Unset all timers self.filterTimer = None @@ -341,7 +341,7 @@ class pluginclass( object ): self.panel = "top" self.panel_position = -1 - self.builder.get_object("searchButton").connect( "button-release-event", self.searchPopup ) + self.builder.get_object("searchButton").connect( "button-press-event", self.searchPopup ) def refresh_apt_cache(self): if self.useAPT: @@ -571,16 +571,27 @@ class pluginclass( object ): elif tabNum == 1: notebook.set_current_page( 1 ) - self.lastActiveTab = tabNum self.focusSearchEntry() + self.lastActiveTab = tabNum + def Todos( self ): - + self.searchEntry.connect( "popup-menu", self.blockOnPopup ) + self.searchEntry.connect( "button-press-event", self.blockOnRightPress ) self.searchEntry.connect( "changed", self.Filter ) self.searchEntry.connect( "activate", self.Search ) self.showAllAppsButton.connect( "clicked", lambda widget: self.changeTab( 1 ) ) self.showFavoritesButton.connect( "clicked", lambda widget: self.changeTab( 0 ) ) self.buildButtonList() + + def blockOnPopup( self, *args ): + self.mintMenuWin.stopHiding() + return False + + def blockOnRightPress( self, widget, event ): + if event.button == 3: + self.mintMenuWin.stopHiding() + return False def focusSearchEntry( self ): # grab_focus() does select all text, @@ -639,8 +650,7 @@ class pluginclass( object ): separator.add(Gtk.HSeparator()) separator.set_visible_window(False) separator.set_size_request(-1, 20) - separator.type = "separator" - self.mintMenuWin.SetPaneColors( [ separator ] ) + separator.type = "separator" separator.show_all() self.applicationsBox.add(separator) self.suggestions.append(separator) @@ -718,8 +728,7 @@ class pluginclass( object ): last_separator.add(Gtk.HSeparator()) last_separator.set_visible_window(False) last_separator.set_size_request(-1, 20) - last_separator.type = "separator" - self.mintMenuWin.SetPaneColors( [ last_separator ] ) + last_separator.type = "separator" last_separator.show_all() self.applicationsBox.add(last_separator) self.suggestions.append(last_separator) @@ -774,8 +783,7 @@ class pluginclass( object ): last_separator.add(Gtk.HSeparator()) last_separator.set_visible_window(False) last_separator.set_size_request(-1, 20) - last_separator.type = "separator" - self.mintMenuWin.SetPaneColors( [ last_separator ] ) + last_separator.type = "separator" last_separator.show_all() self.applicationsBox.add(last_separator) self.suggestions.append(last_separator) @@ -878,15 +886,18 @@ class pluginclass( object ): i.released() i.set_relief( Gtk.ReliefStyle.NONE ) widget.set_relief( Gtk.ReliefStyle.HALF ) - widget.grab_focus() - - self.searchEntry.set_text( "" ) self.applicationsScrolledWindow.get_vadjustment().set_value( 0 ) + + def FilterAndClear( self, widget, category = None ): + self.searchEntry.set_text( "" ) + self.Filter( widget, category ) # Forward all text to the search box def keyPress( self, widget, event ): if event.string.strip() != "" or event.keyval == Gdk.KEY_BackSpace: + self.searchEntry.grab_focus() + gtk.gtk_editable_set_position(hash(self.searchEntry), -1) self.searchEntry.event( event ) return True @@ -950,10 +961,8 @@ class pluginclass( object ): mTree.append(propsMenuItem) mTree.show_all() + self.mintMenuWin.stopHiding() gtk.gtk_menu_popup(hash(mTree), None, None, None, None, ev.button, ev.time) - #self.mintMenuWin.grab() - mTree.connect( 'deactivate', self.onMenuPopupDeactivate) - else: mTree = Gtk.Menu() mTree.set_events(Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.POINTER_MOTION_HINT_MASK | @@ -971,9 +980,8 @@ class pluginclass( object ): removeMenuItem.connect( "activate", self.onFavoritesRemove, widget ) insertSpaceMenuItem.connect( "activate", self.onFavoritesInsertSpace, widget, insertBefore ) insertSeparatorMenuItem.connect( "activate", self.onFavoritesInsertSeparator, widget, insertBefore ) + self.mintMenuWin.stopHiding() gtk.gtk_menu_popup(hash(mTree), None, None, None, None, ev.button, ev.time) - #self.mintMenuWin.grab() - mTree.connect( 'deactivate', self.onMenuPopupDeactivate) def menuPopup( self, widget, event ): if event.button == 3: @@ -1034,11 +1042,8 @@ class pluginclass( object ): startupMenuItem.set_active( False ) startupMenuItem.connect( "toggled", self.onAddToStartup, widget ) - mTree.connect( 'deactivate', self.onMenuPopupDeactivate) - gtk.gtk_menu_popup(hash(mTree), None, None, None, None, 0, 0) - - def onMenuPopupDeactivate( self, widget): - self.mintMenuWin.grab() + self.mintMenuWin.stopHiding() + gtk.gtk_menu_popup(hash(mTree), None, None, None, None, event.button, event.time) def searchPopup( self, widget=None, event=None ): menu = Gtk.Menu() @@ -1113,15 +1118,13 @@ class pluginclass( object ): menu.append(menuItem) menu.show_all() - - gtk.gtk_menu_popup(hash(menu), None, None, None, None, 3, 0) + + self.mintMenuWin.stopHiding() + gtk.gtk_menu_popup(hash(menu), None, None, None, None, event.button, event.time) #menu.attach_to_widget(self.searchButton, None) #menu.reposition() #menu.reposition() - #self.mintMenuWin.grab() - menu.connect( 'deactivate', self.onMenuPopupDeactivate) - self.focusSearchEntry() return True def pos_func(self, menu=None): @@ -1348,10 +1351,9 @@ class pluginclass( object ): space = Gtk.EventBox() space.set_size_request( -1, 20 ) space.set_visible_window(False) - space.connect( "button_release_event", self.favPopup ) + space.connect( "button-press-event", self.favPopup ) space.type = "space" - self.mintMenuWin.SetPaneColors( [ space ] ) space.show() return space @@ -1361,13 +1363,12 @@ class pluginclass( object ): separator.set_size_request( -1, 20 ) separator.type = "separator" - self.mintMenuWin.SetPaneColors( [ separator ] ) separator.show_all() box = Gtk.EventBox() box.type = "separator" box.add(separator) box.set_visible_window(False) - box.connect( "button_release_event", self.favPopup ) + box.connect( "button-press-event", self.favPopup ) box.show_all() return box @@ -1405,7 +1406,7 @@ class pluginclass( object ): if favButton.appExec: favButton.show() favButton.connect( "popup-menu", self.favPopup ) - favButton.connect( "button_release_event", self.favPopup ) + favButton.connect( "button-press-event", self.favPopup ) favButton.connect( "focus-in-event", self.scrollItemIntoView ) favButton.connect( "clicked", lambda w: self.mintMenuWin.hide() ) @@ -1677,7 +1678,7 @@ class pluginclass( object ): else: item["button"].mouseOverHandlerIds = None - item["button"].connect( "clicked", self.Filter, item["filter"] ) + item["button"].connect( "clicked", self.FilterAndClear, item["filter"] ) item["button"].connect( "focus-in-event", self.categoryBtnFocus, item["filter"] ) item["button"].show() diff --git a/usr/lib/linuxmint/mintMenu/plugins/easybuttons.py b/usr/lib/linuxmint/mintMenu/plugins/easybuttons.py index 2d0d90d..1f1d799 100755 --- a/usr/lib/linuxmint/mintMenu/plugins/easybuttons.py +++ b/usr/lib/linuxmint/mintMenu/plugins/easybuttons.py @@ -283,7 +283,6 @@ class ApplicationLauncher( easyButton ): self.connectSelf( "focus-in-event", self.onFocusIn ) self.connectSelf( "focus-out-event", self.onFocusOut ) - self.connectSelf( "enter-notify-event", self.onEnterNotify ) self.connectSelf( "clicked", self.execute ) @@ -332,9 +331,6 @@ class ApplicationLauncher( easyButton ): def onFocusOut( self, widget, event ): self.set_relief( Gtk.ReliefStyle.NONE ) - def onEnterNotify( self, widget, event ): - self.grab_focus() - def setupLabels( self ): self.addLabel( self.appName ) diff --git a/usr/lib/linuxmint/mintMenu/plugins/recent.py b/usr/lib/linuxmint/mintMenu/plugins/recent.py index a1eefa0..9733bfd 100755 --- a/usr/lib/linuxmint/mintMenu/plugins/recent.py +++ b/usr/lib/linuxmint/mintMenu/plugins/recent.py @@ -4,7 +4,6 @@ gi.require_version("Gtk", "2.0") from gi.repository import Gtk, Pango import sys import os -import gobject import datetime import fcntl from easygsettings import EasyGSettings diff --git a/usr/lib/linuxmint/mintMenu/pointerMonitor.py b/usr/lib/linuxmint/mintMenu/pointerMonitor.py new file mode 100644 index 0000000..1a0a071 --- /dev/null +++ b/usr/lib/linuxmint/mintMenu/pointerMonitor.py @@ -0,0 +1,84 @@ +import gi +gi.require_version("Gtk", "2.0") + +from Xlib.display import Display +from Xlib import X, error +from gi.repository import Gtk, Gdk, GObject, GLib +import threading +import ctypes +from ctypes import * + +gdk = CDLL("libgdk-x11-2.0.so.0") +gtk = CDLL("libgtk-x11-2.0.so.0") + +class PointerMonitor(GObject.GObject, threading.Thread): + __gsignals__ = { + 'activate': (GObject.SignalFlags.RUN_LAST, None, ()), + } + + def __init__(self): + GObject.GObject.__init__ (self) + threading.Thread.__init__ (self) + self.setDaemon (True) + self.display = Display() + self.root = self.display.screen().root + self.windows = [] + self.topWindows = [] + + # Receives GDK windows + def addWindowToMonitor(self, window): + xWindow = self.display.create_resource_object("window", gdk.gdk_x11_drawable_get_xid(hash(window))) + self.windows.append(xWindow) + self.topWindows.append(self.getToplevelParent(xWindow)) + + def getToplevelParent(self, window): + parent = window.query_tree().parent + if parent == self.root: + return window + else: + return self.getToplevelParent(parent) + + def grabPointer(self): + self.root.grab_button(X.AnyButton, X.AnyModifier, True, X.ButtonPressMask, X.GrabModeSync, X.GrabModeAsync, 0, 0) + self.display.flush() + + def ungrabPointer(self): + self.root.ungrab_button(X.AnyButton, X.AnyModifier) + self.display.flush() + + def idle(self): + self.emit("activate") + return False + + def activate(self): + GLib.idle_add(self.run) + + def run(self): + self.running = True + while self.running: + event = self.display.next_event() + try: + if event.type == X.ButtonPress: + # Check if pointer is inside monitored windows + for w, topW in zip(self.windows, self.topWindows): + if event.child == topW: + if topW == w: + break + else: + p = w.query_pointer() + g = w.get_geometry() + if p.win_x >= 0 and p.win_y >= 0 and p.win_x <= g.width and p.win_y <= g.height: + break + else: + # Is outside, so activate + GLib.idle_add(self.idle) + + self.display.allow_events(X.ReplayPointer, event.time) + except Exception as e: + print "Unexpected error: " + str(e) + + def stop(self): + self.running = False + self.root.ungrab_button(X.AnyButton, X.AnyModifier) + self.display.close() +