[kupfer: 5/51] Support Relaying Keyboard events from a different $DISPLAY (!!)



commit 6352747c9c29beb0040db8f450583e1f2d9721e6
Author: Ulrik Sverdrup <ulrik sverdrup gmail com>
Date:   Mon Mar 28 16:51:41 2011 +0200

    Support Relaying Keyboard events from a different $DISPLAY (!!)
    
    libkeybinder at the moment can only work with one root window "the
    default display and screen for the process".
    
    To circum-hack this we provide a small little tool "kupferrelay.py"
    that relays global keyboard events (only the ones that are configured
    in Kupfer) to the main instance. All the kupfer instances have to be
    on separate $DISPLAYS but the same Dbus session bus.
    
    Note that not all actions in Kupfer support launching on the correct
    display. In fact, "Launch Application" is almost the only one working.

 kupfer/plugin/triggers.py |    4 +-
 kupfer/ui/browser.py      |   16 +++++++-----
 kupfer/ui/keybindings.py  |   10 ++++++-
 kupfer/ui/listen.py       |    9 +++++++
 kupfer/ui/uievents.py     |   21 ++++++++++++++++
 kupferrelay.py            |   57 +++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 106 insertions(+), 11 deletions(-)
---
diff --git a/kupfer/plugin/triggers.py b/kupfer/plugin/triggers.py
index e372737..f911f2d 100644
--- a/kupfer/plugin/triggers.py
+++ b/kupfer/plugin/triggers.py
@@ -72,10 +72,10 @@ class Triggers (Source):
 		for target, (keystr, name, id_) in self.trigger_table.iteritems():
 			keybindings.bind_key(None, target)
 
-	def keybinding_callback(self, keyobj, target, event_time):
+	def keybinding_callback(self, keyobj, target, event_time, display):
 		if not self.has_trigger(target):
 			return
-		ui_ctx = uievents.gui_context_from_timestamp(event_time)
+		ui_ctx = uievents.gui_context_from_keyevent(event_time, display)
 		ctx = commandexec.DefaultActionExecutionContext()
 		exec_token = ctx.make_execution_token(ui_ctx)
 		self.perform_trigger(exec_token, target)
diff --git a/kupfer/ui/browser.py b/kupfer/ui/browser.py
index 0a515c4..b84c12e 100644
--- a/kupfer/ui/browser.py
+++ b/kupfer/ui/browser.py
@@ -2013,10 +2013,10 @@ class WindowController (pretty.OutputMixin):
 	def activate(self, sender=None, time=0):
 		self.present_on_display(None, "")
 
-	def present_on_display(self, sender, displayname):
+	def present_on_display(self, sender, display):
 		time = uievents.current_event_time()
 		self._window_hide_timer.invalidate()
-		self._center_window(displayname)
+		self._center_window(display)
 		self.window.stick()
 		self.window.present_with_time(time)
 		self.window.window.focus(timestamp=time)
@@ -2029,21 +2029,21 @@ class WindowController (pretty.OutputMixin):
 	def _cancelled(self, widget):
 		self.put_away()
 
-	def show_hide(self, sender=None, time=0):
+	def show_hide(self, sender=None, time=0, display=None):
 		"""
 		Toggle activate/put-away
 		"""
 		if self.window.get_property("visible"):
 			self.put_away()
 		else:
-			self.activate(time=time)
+			self.present_on_display(None, display)
 
-	def _key_binding(self, keyobj, keybinding_number, event_time):
+	def _key_binding(self, keyobj, keybinding_number, event_time, display):
 		"""Keybinding activation callback"""
 		if keybinding_number == keybindings.KEYBINDING_DEFAULT:
-			self.show_hide(time=event_time)
+			self.show_hide(time=event_time, display=display)
 		elif keybinding_number == keybindings.KEYBINDING_MAGIC:
-			self.activate(time=event_time)
+			self.present_on_display(keyobj, display=display)
 			self.interface.select_selected_text()
 			self.interface.select_selected_file()
 
@@ -2165,6 +2165,8 @@ class WindowController (pretty.OutputMixin):
 			kserv.connect("put-files", self._put_files_received)
 			kserv.connect("execute-file", self._execute_file_received)
 			kserv.connect("quit", self.quit)
+			keyobj = keybindings.GetKeyboundObject()
+			kserv.connect("relay-keys", keyobj.relayed_keys)
 
 		# Load data and present UI
 		sch = scheduler.GetScheduler()
diff --git a/kupfer/ui/keybindings.py b/kupfer/ui/keybindings.py
index dd40ae7..f33beea 100644
--- a/kupfer/ui/keybindings.py
+++ b/kupfer/ui/keybindings.py
@@ -31,10 +31,16 @@ class KeyboundObject (gobject.GObject):
 	def _keybinding(self, target):
 		import keybinder
 		time = keybinder.get_current_event_time()
-		self.emit("keybinding", target, time)
+		self.emit("keybinding", target, time, "")
+	def relayed_keys(self, sender, keystring, display):
+		for target, key in _currently_bound.iteritems():
+			if keystring == key:
+				self.emit("keybinding", target, 0, display)
 
+# Arguments: Target, Timestamp, Display
 gobject.signal_new("keybinding", KeyboundObject, gobject.SIGNAL_RUN_LAST,
-		gobject.TYPE_BOOLEAN, (gobject.TYPE_INT, gobject.TYPE_INT64))
+		gobject.TYPE_BOOLEAN,
+		(gobject.TYPE_INT, gobject.TYPE_INT64, gobject.TYPE_STRING))
 
 _currently_bound = {}
 
diff --git a/kupfer/ui/listen.py b/kupfer/ui/listen.py
index 563c285..f68de12 100644
--- a/kupfer/ui/listen.py
+++ b/kupfer/ui/listen.py
@@ -97,6 +97,12 @@ class Service (ExportedGObject):
 		with uievents.using_startup_notify_id(notify_id):
 			self.emit("execute-file", filepath)
 
+	@dbus.service.method(interface_name, in_signature="ayayay",
+	                     byte_arrays=True)
+	def RelayKeysFromDisplay(self, keystring, display, notify_id):
+		with uievents.using_startup_notify_id(notify_id):
+			self.emit("relay-keys", keystring, display)
+
 	@dbus.service.method(interface_name)
 	def Quit(self):
 		self.emit("quit")
@@ -119,3 +125,6 @@ gobject.signal_new("execute-file", Service, gobject.SIGNAL_RUN_LAST,
 gobject.signal_new("quit", Service, gobject.SIGNAL_RUN_LAST,
 		gobject.TYPE_BOOLEAN, ())
 
+gobject.signal_new("relay-keys", Service, gobject.SIGNAL_RUN_LAST,
+		gobject.TYPE_BOOLEAN, (gobject.TYPE_STRING, gobject.TYPE_STRING, ))
+
diff --git a/kupfer/ui/uievents.py b/kupfer/ui/uievents.py
index 665cfe7..336bb98 100644
--- a/kupfer/ui/uievents.py
+++ b/kupfer/ui/uievents.py
@@ -12,6 +12,27 @@ def gui_context_from_toplevel(timestamp, toplevel):
 def gui_context_from_timestamp(timestamp):
 	return GUIEnvironmentContext(timestamp, None)
 
+def gui_context_from_keyevent(timestamp, display):
+	def norm_name(name):
+		if name[-2] == ":":
+			return name+".0"
+		return name
+	dm = gtk.gdk.display_manager_get()
+	if display:
+		new_display = None
+		for disp in dm.list_displays():
+			if norm_name(disp.get_name()) == norm_name(display):
+				new_display = disp
+				break
+		if new_display is None:
+			new_display = gtk.gdk.Display(display)
+	else:
+		new_display = gtk.gdk.display_get_default()
+	screen, x, y, modifiers = new_display.get_pointer()
+	gctx = GUIEnvironmentContext(timestamp, screen)
+	gctx.display = new_display
+	return gctx
+
 class GUIEnvironmentContext (object):
 	"""
 	Context object for action execution
diff --git a/kupferrelay.py b/kupferrelay.py
new file mode 100644
index 0000000..0e72cf9
--- /dev/null
+++ b/kupferrelay.py
@@ -0,0 +1,57 @@
+import os
+
+import gtk
+import keybinder
+import dbus
+import pickle
+
+import kupfer.puid
+import kupfer.config
+import kupfer.core.settings
+
+
+SERV = "se.kaizer.kupfer"
+OBJ = "/interface"
+IFACE = "se.kaizer.kupfer.Listener"
+
+
+def get_core_keys():
+	""" Get configured keys """
+	sc = kupfer.core.settings.SettingsController()
+	return [sc.get_keybinding(), sc.get_magic_keybinding()]
+
+def get_trigger_keys():
+	""" Get configured keys """
+	c = kupfer.config.get_config_file("config-kupfer.plugin.triggers-v1.pickle")
+	if not c:
+		print "No triggers configured"
+		return
+	with open(c, "rb") as f:
+		data_dic = pickle.load(f)
+	if not data_dic:
+		print "Triggers not configured"
+		return
+	for target in data_dic['triggers']:
+		keystr, name, puid = data_dic['triggers'][target]
+		yield keystr
+
+def relay_key(key):
+	print "Relaying", key
+	time = keybinder.get_current_event_time()
+	s_id = "kupfer-%d_TIME%s" % (os.getpid(), time)
+	bus = dbus.Bus()
+	obj = bus.get_object(SERV, OBJ)
+	iface = dbus.Interface(obj, IFACE)
+	iface.RelayKeysFromDisplay(key, os.getenv("DISPLAY"), s_id)
+
+def main():
+	relayed_keys = []
+	relayed_keys.extend(get_core_keys())
+	relayed_keys.extend(get_trigger_keys())
+	for key in relayed_keys:
+		keybinder.bind(key, relay_key, key)
+
+	gtk.main()
+
+if __name__ == '__main__':
+	main()



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]