Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Gtk UI: Fix submenu activation/focus issues (bug 1778)

This fixes the same problem as outlined in bug 1778, but also
makes sure that keyboard navigation still works.
  • Loading branch information...
commit a09b204ad67c2ef1f95c5858f5bdf48a77815bc0 1 parent 7fcbb39
@thp thp authored
Showing with 26 additions and 5 deletions.
  1. +26 −5 src/gpodder/gtkui/main.py
View
31 src/gpodder/gtkui/main.py
@@ -29,6 +29,7 @@
import subprocess
import glob
import time
+import threading
import tempfile
import collections
import urllib
@@ -1675,6 +1676,27 @@ def _add_sub_menu(self, menu, label):
root_item.set_submenu(sub_menu)
return sub_menu
+ def _submenu_item_activate_hack(self, item, callback, *args):
+ # See http://stackoverflow.com/questions/5221326/submenu-item-does-not-call-function-with-working-solution
+ # Note that we can't just call the callback on button-press-event, as
+ # it might be blocking (see http://gpodder.org/bug/1778), so we run
+ # this in the GUI thread at a later point in time (util.idle_add).
+ # Also, we also have to connect to the activate signal, as this is the
+ # only signal that is fired when keyboard navigation is used.
+
+ # It can happen that both (button-release-event and activate) signals
+ # are fired, and we must avoid calling the callback twice. We do this
+ # using a semaphore and only acquiring (but never releasing) it, making
+ # sure that the util.idle_add() call below is only ever called once.
+ only_once = threading.Semaphore(1)
+
+ def handle_event(item, event=None):
+ if only_once.acquire(False):
+ util.idle_add(callback, *args)
+
+ item.connect('button-press-event', handle_event)
+ item.connect('activate', handle_event)
+
def treeview_available_show_context_menu(self, treeview, event=None):
model, paths = self.treeview_handle_context_menu_click(treeview, event)
if not paths:
@@ -1732,9 +1754,8 @@ def treeview_available_show_context_menu(self, treeview, event=None):
submenus = {}
for label, callback in result:
key, sep, title = label.rpartition('/')
- item = gtk.MenuItem(title)
- item.connect('activate', lambda item, callback:
- callback(episodes), callback)
+ item = gtk.ImageMenuItem(title)
+ self._submenu_item_activate_hack(item, callback, episodes)
if key:
if key not in submenus:
sub_menu = self._add_sub_menu(menu, key)
@@ -1752,12 +1773,12 @@ def treeview_available_show_context_menu(self, treeview, event=None):
item = gtk.ImageMenuItem(_('Local folder'))
item.set_image(gtk.image_new_from_stock(gtk.STOCK_DIRECTORY, gtk.ICON_SIZE_MENU))
- item.connect('button-press-event', lambda w, ee: self.save_episodes_as_file(episodes))
+ self._submenu_item_activate_hack(item, self.save_episodes_as_file, episodes)
share_menu.append(item)
if self.bluetooth_available:
item = gtk.ImageMenuItem(_('Bluetooth device'))
item.set_image(gtk.image_new_from_icon_name('bluetooth', gtk.ICON_SIZE_MENU))
- item.connect('button-press-event', lambda w, ee: self.copy_episodes_bluetooth(episodes))
+ self._submenu_item_activate_hack(item, self.copy_episodes_bluetooth, episodes)
share_menu.append(item)
menu.append(gtk.SeparatorMenuItem())
Please sign in to comment.
Something went wrong with that request. Please try again.