def on_unknown_message(self, daemon, message): if not message.startswith("OSD:"): return if message.startswith("OSD: message"): args = split(message)[1:] m = Message() m.parse_argumets(args) m.show() elif message.startswith("OSD: keyboard"): if self._window: log.warning( "Another OSD is already visible - refusing to show keyboard" ) else: args = split(message)[1:] self._window = Keyboard() self._window.connect('destroy', self.on_keyboard_closed) # self._window.parse_argumets(args) # TODO: No arguments so far self._window.show() self._window.use_daemon(self.daemon) elif message.startswith("OSD: menu") or message.startswith( "OSD: gridmenu"): args = split(message)[1:] if self._window: log.warning( "Another OSD is already visible - refusing to show menu") else: self._window = GridMenu() if "gridmenu" in message else Menu() self._window.connect('destroy', self.on_menu_closed) self._window.use_config(self.config) if self._window.parse_argumets(args): self._window.show() self._window.use_daemon(self.daemon) else: log.error("Failed to show menu") self._window = None elif message.startswith("OSD: area"): args = split(message)[1:] if self._window: log.warning( "Another OSD is already visible - refusing to show area") else: args = split(message)[1:] self._window = Area() self._window.connect('destroy', self.on_keyboard_closed) if self._window.parse_argumets(args): self._window.show() else: self._window.quit() self._window = None elif message.startswith("OSD: clear"): # Clears active OSD window (if any) if self._window: self._window.quit() self._window = None else: log.warning("Unknown command from daemon: '%s'", message)
def on_unknown_message(self, daemon, message): if not message.startswith("OSD:"): return if message.startswith("OSD: message"): args = shsplit(message)[1:] m = Message() m.parse_argumets(args) m.show() elif message.startswith("OSD: keyboard"): if self._window: log.warning("Another OSD is already visible - refusing to show keyboard") else: args = shsplit(message)[1:] self._window = Keyboard(self.config) self._window.connect('destroy', self.on_keyboard_closed) self._window.parse_argumets(args) self._window.show() self._window.use_daemon(self.daemon) elif self._is_menu_message(message): args = shsplit(message)[1:] if self._window: log.warning("Another OSD is already visible - refusing to show menu") else: if message.startswith("OSD: gridmenu"): self._window = GridMenu() elif message.startswith("OSD: radialmenu"): self._window = RadialMenu() else: self._window = Menu() self._window.connect('destroy', self.on_menu_closed) self._window.use_config(self.config) if self._window.parse_argumets(args): self._window.show() self._window.use_daemon(self.daemon) else: log.error("Failed to show menu") self._window = None elif message.startswith("OSD: area"): args = shsplit(message)[1:] if self._window: log.warning("Another OSD is already visible - refusing to show area") else: args = shsplit(message)[1:] self._window = Area() self._window.connect('destroy', self.on_keyboard_closed) if self._window.parse_argumets(args): self._window.show() else: self._window.quit() self._window = None elif message.startswith("OSD: clear"): # Clears active OSD window (if any) if self._window: self._window.quit() self._window = None else: log.warning("Unknown command from daemon: '%s'", message)
def update_osd_area(self, action): """ Updates preview area displayed on screen """ if action: if self.osd_area_instance is None: self.osd_area_instance = Area() self.osd_area_instance.show() action.update_osd_area(self.osd_area_instance, FakeMapper(self.editor)) self.timer("area", 0.5, self.update_osd_area, action) elif self.osd_area_instance: self.osd_area_instance.quit() self.osd_area_instance = None self.cancel_timer("area")
def update_osd_area(self, action): """ Updates preview area displayed on screen """ if action: if self.osd_area_instance is None: if self.on_wayland: # Cannot display preview with non-X11 backends return self.osd_area_instance = Area() self.osd_area_instance.show() action.update_osd_area(self.osd_area_instance, FakeMapper(self.editor)) self.timer("area", 0.5, self.update_osd_area, action) elif self.osd_area_instance: self.osd_area_instance.quit() self.osd_area_instance = None self.cancel_timer("area")
class OSDDaemon(object): def __init__(self): self.exit_code = -1 self.mainloop = GLib.MainLoop() self.config = None # hash_of_colors is used to determine if css needs to be reapplied # after configuration change self._hash_of_colors = -1 self._window = None self._registered = False self._last_profile_change = 0 self._recent_profiles_undo = None def quit(self, code=-1): self.exit_code = code self.mainloop.quit() def get_exit_code(self): return self.exit_code def on_daemon_reconfigured(self, *a): log.debug("Reloading config...") self.config.reload() self._check_colorconfig_change() def on_profile_changed(self, daemon, profile): name = os.path.split(profile)[-1] if name.endswith(".sccprofile") and not name.startswith("."): # Ignore .mod and hidden files name = name[0:-11] recents = self.config['recent_profiles'] if len(recents) and recents[0] == name: # Already first in recent list return if time.time() - self._last_profile_change < 2.0: # Profiles are changing too fast, probably because user # is using scroll wheel over profile combobox if self._recent_profiles_undo: recents = [] + self._recent_profiles_undo self._last_profile_change = time.time() self._recent_profiles_undo = [] + recents while name in recents: recents.remove(name) recents.insert(0, name) if len(recents) > self.config['recent_max']: recents = recents[0:self.config['recent_max']] self.config['recent_profiles'] = recents self.config.save() log.debug("Updated recent profile list") def on_daemon_died(self, *a): log.error("Connection to daemon lost") self.quit(2) def on_daemon_connected(self, *a): def success(*a): log.info("Sucessfully registered as scc-osd-daemon") self._registered = True def failure(why): log.error("Failed to registered as scc-osd-daemon: %s", why) self.quit(1) if not self._registered: self.daemon.request('Register: osd', success, failure) def on_menu_closed(self, m): """ Called after OSD menu is hidden from screen """ self._window = None if m.get_exit_code() == 0: # 0 means that user selected item and confirmed selection self.daemon.request( 'Selected: %s' % (shjoin( [m.get_menuid(), m.get_selected_item_id()])), lambda *a: False, lambda *a: False) def on_keyboard_closed(self, *a): """ Called after on-screen keyboard is hidden from the screen """ self._window = None def on_gesture_recognized(self, gd): """ Called after on-screen keyboard is hidden from the screen """ self._window = None if gd.get_exit_code() == 0: self.daemon.request('Gestured: %s' % (gd.get_gesture(), ), lambda *a: False, lambda *a: False) else: self.daemon.request('Gestured: x', lambda *a: False, lambda *a: False) @staticmethod def _is_menu_message(m): """ Returns True if m starts with 'OSD: [grid|radial]menu' or "OSD: dialog" """ return (m.startswith("OSD: menu") or m.startswith("OSD: radialmenu") or m.startswith("OSD: quickmenu") or m.startswith("OSD: gridmenu") or m.startswith("OSD: dialog") or m.startswith("OSD: hmenu")) def on_unknown_message(self, daemon, message): if not message.startswith("OSD:"): return if message.startswith("OSD: message"): args = shsplit(message)[1:] m = Message() m.parse_argumets(args) m.show() elif message.startswith("OSD: keyboard"): if self._window: log.warning( "Another OSD is already visible - refusing to show keyboard" ) else: args = shsplit(message)[1:] self._window = Keyboard(self.config) self._window.connect('destroy', self.on_keyboard_closed) self._window.parse_argumets(args) self._window.show() self._window.use_daemon(self.daemon) elif message.startswith("OSD: gesture"): if self._window: log.warning( "Another OSD is already visible - refusing to show keyboard" ) else: args = shsplit(message)[1:] self._window = GestureDisplay(self.config) self._window.parse_argumets(args) self._window.use_daemon(self.daemon) self._window.show() self._window.connect('destroy', self.on_gesture_recognized) elif self._is_menu_message(message): args = shsplit(message)[1:] if self._window: log.warning( "Another OSD is already visible - refusing to show menu") else: if message.startswith("OSD: hmenu"): self._window = HorizontalMenu() elif message.startswith("OSD: radialmenu"): self._window = RadialMenu() elif message.startswith("OSD: quickmenu"): self._window = QuickMenu() elif message.startswith("OSD: gridmenu"): self._window = GridMenu() elif message.startswith("OSD: dialog"): self._window = Dialog() else: self._window = Menu() self._window.connect('destroy', self.on_menu_closed) self._window.use_config(self.config) if self._window.parse_argumets(args): self._window.show() self._window.use_daemon(self.daemon) else: log.error("Failed to show menu") self._window = None elif message.startswith("OSD: area"): args = shsplit(message)[1:] if self._window: log.warning( "Another OSD is already visible - refusing to show area") else: args = shsplit(message)[1:] self._window = Area() self._window.connect('destroy', self.on_keyboard_closed) if self._window.parse_argumets(args): self._window.show() else: self._window.quit() self._window = None elif message.startswith("OSD: clear"): # Clears active OSD window (if any) if self._window: self._window.quit() self._window = None else: log.warning("Unknown command from daemon: '%s'", message) def _check_colorconfig_change(self): """ Checks if OSD color configuration is changed and re-applies CSS if needed. """ h = sum([ hash(self.config['osd_colors'][x]) for x in self.config['osd_colors'] ]) h += sum([ hash(self.config['osk_colors'][x]) for x in self.config['osk_colors'] ]) if self._hash_of_colors != h: self._hash_of_colors = h OSDWindow._apply_css(self.config) if self._window and isinstance(self._window, Keyboard): self._window.recolor() self._window.update_labels() self._window.redraw_background() def run(self): on_wayland = "WAYLAND_DISPLAY" in os.environ or not isinstance( Gdk.Display.get_default(), GdkX11.X11Display) if on_wayland: log.error("Cannot run on Wayland") self.exit_code = 8 return self.daemon = DaemonManager() self.config = Config() self._check_colorconfig_change() self.daemon.connect('alive', self.on_daemon_connected) self.daemon.connect('dead', self.on_daemon_died) self.daemon.connect('profile-changed', self.on_profile_changed) self.daemon.connect('reconfigured', self.on_daemon_reconfigured) self.daemon.connect('unknown-msg', self.on_unknown_message) self.mainloop.run()
def on_unknown_message(self, daemon, message): if not message.startswith("OSD:"): return if message.startswith("OSD: message"): args = shsplit(message)[1:] m = Message() m.parse_argumets(args) m.show() elif message.startswith("OSD: keyboard"): if self._window: log.warning( "Another OSD is already visible - refusing to show keyboard" ) else: args = shsplit(message)[1:] self._window = Keyboard(self.config) self._window.connect('destroy', self.on_keyboard_closed) self._window.parse_argumets(args) self._window.show() self._window.use_daemon(self.daemon) elif message.startswith("OSD: gesture"): if self._window: log.warning( "Another OSD is already visible - refusing to show keyboard" ) else: args = shsplit(message)[1:] self._window = GestureDisplay(self.config) self._window.parse_argumets(args) self._window.use_daemon(self.daemon) self._window.show() self._window.connect('destroy', self.on_gesture_recognized) elif self._is_menu_message(message): args = shsplit(message)[1:] if self._window: log.warning( "Another OSD is already visible - refusing to show menu") else: if message.startswith("OSD: hmenu"): self._window = HorizontalMenu() elif message.startswith("OSD: radialmenu"): self._window = RadialMenu() elif message.startswith("OSD: quickmenu"): self._window = QuickMenu() elif message.startswith("OSD: gridmenu"): self._window = GridMenu() elif message.startswith("OSD: dialog"): self._window = Dialog() else: self._window = Menu() self._window.connect('destroy', self.on_menu_closed) self._window.use_config(self.config) if self._window.parse_argumets(args): self._window.show() self._window.use_daemon(self.daemon) else: log.error("Failed to show menu") self._window = None elif message.startswith("OSD: area"): args = shsplit(message)[1:] if self._window: log.warning( "Another OSD is already visible - refusing to show area") else: args = shsplit(message)[1:] self._window = Area() self._window.connect('destroy', self.on_keyboard_closed) if self._window.parse_argumets(args): self._window.show() else: self._window.quit() self._window = None elif message.startswith("OSD: clear"): # Clears active OSD window (if any) if self._window: self._window.quit() self._window = None else: log.warning("Unknown command from daemon: '%s'", message)
class OSDDaemon(object): def __init__(self): self.exit_code = -1 self.mainloop = GLib.MainLoop() self._window = None self._registered = False OSDWindow._apply_css() def quit(self, code=-1): self.exit_code = code self.mainloop.quit() def get_exit_code(self): return self.exit_code def on_daemon_died(self, *a): log.error("Daemon died") self.quit(2) def on_daemon_connected(self, *a): def success(*a): log.info("Sucessfully registered as scc-osd-daemon") self._registered = True def failure(why): log.error("Failed to registered as scc-osd-daemon: %s", why) self.quit(1) if not self._registered: self.daemon.request('Register: osd', success, failure) def on_menu_closed(self, m): """ Called after OSD menu is hidden from screen """ self._window = None if m.get_exit_code() == 0: # 0 means that user selected item and confirmed selection self.daemon.request( 'Selected: %s %s' % (m.get_menuid(), m.get_selected_item_id()), lambda *a : False, lambda *a : False) def on_keyboard_closed(self, *a): """ Called after on-screen keyboard is hidden from the screen """ self._window = None def on_unknown_message(self, daemon, message): if not message.startswith("OSD:"): return if message.startswith("OSD: message"): args = split(message)[1:] m = Message() m.parse_argumets(args) m.show() elif message.startswith("OSD: keyboard"): if self._window: log.warning("Another OSD is already visible - refusing to show keyboard") else: args = split(message)[1:] self._window = Keyboard() self._window.connect('destroy', self.on_keyboard_closed) # self._window.parse_argumets(args) # TODO: No arguments so far self._window.show() self._window.use_daemon(self.daemon) elif message.startswith("OSD: menu") or message.startswith("OSD: gridmenu"): args = split(message)[1:] if self._window: log.warning("Another OSD is already visible - refusing to show menu") else: self._window = GridMenu() if "gridmenu" in message else Menu() self._window.connect('destroy', self.on_menu_closed) if self._window.parse_argumets(args): self._window.show() self._window.use_daemon(self.daemon) else: log.error("Failed to show menu") self._window = None elif message.startswith("OSD: area"): args = split(message)[1:] if self._window: log.warning("Another OSD is already visible - refusing to show area") else: args = split(message)[1:] self._window = Area() self._window.connect('destroy', self.on_keyboard_closed) if self._window.parse_argumets(args): self._window.show() else: self._window.quit() self._window = None elif message.startswith("OSD: clear"): # Clears active OSD window (if any) if self._window: self._window.quit() self._window = None else: log.warning("Unknown command from daemon: '%s'", message) def run(self): self.daemon = DaemonManager() self.daemon.connect('dead', self.on_daemon_died) self.daemon.connect('alive', self.on_daemon_connected) self.daemon.connect('unknown-msg', self.on_unknown_message) self.mainloop.run()
class OSDDaemon(object): def __init__(self): self.exit_code = -1 self.mainloop = GLib.MainLoop() self.config = None # hash_of_colors is used to determine if css needs to be reapplied # after configuration change self._hash_of_colors = -1 self._window = None self._registered = False self._last_profile_change = 0 self._recent_profiles_undo = None def quit(self, code=-1): self.exit_code = code self.mainloop.quit() def get_exit_code(self): return self.exit_code def on_daemon_reconfigured(self, *a): log.debug("Reloading config...") self.config.reload() self._check_colorconfig_change() def on_profile_changed(self, daemon, profile): name = os.path.split(profile)[-1] if name.endswith(".sccprofile") and not name.startswith("."): # Ignore .mod and hidden files name = name[0:-11] recents = self.config['recent_profiles'] if len(recents) and recents[0] == name: # Already first in recent list return if time.time() - self._last_profile_change < 2.0: # Profiles are changing too fast, probably because user # is using scroll wheel over profile combobox if self._recent_profiles_undo: recents = [] + self._recent_profiles_undo self._last_profile_change = time.time() self._recent_profiles_undo = [] + recents while name in recents: recents.remove(name) recents.insert(0, name) if len(recents) > self.config['recent_max']: recents = recents[0:self.config['recent_max']] self.config['recent_profiles'] = recents self.config.save() log.debug("Updated recent profile list") def on_daemon_died(self, *a): log.error("Connection to daemon lost") self.quit(2) def on_daemon_connected(self, *a): def success(*a): log.info("Sucessfully registered as scc-osd-daemon") self._registered = True def failure(why): log.error("Failed to registered as scc-osd-daemon: %s", why) self.quit(1) if not self._registered: self.daemon.request('Register: osd', success, failure) def on_menu_closed(self, m): """ Called after OSD menu is hidden from screen """ self._window = None if m.get_exit_code() == 0: # 0 means that user selected item and confirmed selection self.daemon.request( 'Selected: %s' % ( shjoin([ m.get_menuid(), m.get_selected_item_id() ])), lambda *a : False, lambda *a : False) def on_keyboard_closed(self, *a): """ Called after on-screen keyboard is hidden from the screen """ self._window = None @staticmethod def _is_menu_message(m): """ Returns True if m starts with 'OSD: [grid|radial]menu' """ return ( m.startswith("OSD: menu") or m.startswith("OSD: gridmenu") or m.startswith("OSD: radialmenu") ) def on_unknown_message(self, daemon, message): if not message.startswith("OSD:"): return if message.startswith("OSD: message"): args = shsplit(message)[1:] m = Message() m.parse_argumets(args) m.show() elif message.startswith("OSD: keyboard"): if self._window: log.warning("Another OSD is already visible - refusing to show keyboard") else: args = shsplit(message)[1:] self._window = Keyboard(self.config) self._window.connect('destroy', self.on_keyboard_closed) self._window.parse_argumets(args) self._window.show() self._window.use_daemon(self.daemon) elif self._is_menu_message(message): args = shsplit(message)[1:] if self._window: log.warning("Another OSD is already visible - refusing to show menu") else: if message.startswith("OSD: gridmenu"): self._window = GridMenu() elif message.startswith("OSD: radialmenu"): self._window = RadialMenu() else: self._window = Menu() self._window.connect('destroy', self.on_menu_closed) self._window.use_config(self.config) if self._window.parse_argumets(args): self._window.show() self._window.use_daemon(self.daemon) else: log.error("Failed to show menu") self._window = None elif message.startswith("OSD: area"): args = shsplit(message)[1:] if self._window: log.warning("Another OSD is already visible - refusing to show area") else: args = shsplit(message)[1:] self._window = Area() self._window.connect('destroy', self.on_keyboard_closed) if self._window.parse_argumets(args): self._window.show() else: self._window.quit() self._window = None elif message.startswith("OSD: clear"): # Clears active OSD window (if any) if self._window: self._window.quit() self._window = None else: log.warning("Unknown command from daemon: '%s'", message) def _check_colorconfig_change(self): """ Checks if OSD color configuration is changed and re-applies CSS if needed. """ h = sum([ hash(self.config['osd_colors'][x]) for x in self.config['osd_colors'] ]) h += sum([ hash(self.config['osk_colors'][x]) for x in self.config['osk_colors'] ]) if self._hash_of_colors != h: self._hash_of_colors = h OSDWindow._apply_css(self.config) if self._window and isinstance(self._window, Keyboard): self._window.recolor() self._window.update_labels() self._window.redraw_background() def run(self): self.daemon = DaemonManager() self.config = Config() self._check_colorconfig_change() self.daemon.connect('alive', self.on_daemon_connected) self.daemon.connect('dead', self.on_daemon_died) self.daemon.connect('profile-changed', self.on_profile_changed) self.daemon.connect('reconfigured', self.on_daemon_reconfigured) self.daemon.connect('unknown-msg', self.on_unknown_message) self.mainloop.run()
class OSDDaemon(object): def __init__(self): self.exit_code = -1 self.mainloop = GLib.MainLoop() self.config = None # hash_of_colors is used to determine if css needs to be reapplied # after configuration change self._hash_of_colors = -1 self._visible_messages = {} self._window = None self._registered = False self._last_profile_change = 0 self._recent_profiles_undo = None def quit(self, code=-1): self.exit_code = code self.mainloop.quit() def get_exit_code(self): return self.exit_code def on_daemon_reconfigured(self, *a): log.debug("Reloading config...") self.config.reload() self._check_colorconfig_change() def on_profile_changed(self, daemon, profile): name = os.path.split(profile)[-1] if name.endswith(".sccprofile") and not name.startswith("."): # Ignore .mod and hidden files name = name[0:-11] recents = self.config['recent_profiles'] if len(recents) and recents[0] == name: # Already first in recent list return if time.time() - self._last_profile_change < 2.0: # Profiles are changing too fast, probably because user # is using scroll wheel over profile combobox if self._recent_profiles_undo: recents = [] + self._recent_profiles_undo self._last_profile_change = time.time() self._recent_profiles_undo = [] + recents while name in recents: recents.remove(name) recents.insert(0, name) if len(recents) > self.config['recent_max']: recents = recents[0:self.config['recent_max']] self.config['recent_profiles'] = recents self.config.save() log.debug("Updated recent profile list") self.clear_messages() def on_daemon_died(self, *a): log.error("Connection to daemon lost") self.quit(2) def on_daemon_connected(self, *a): def success(*a): log.info("Sucessfully registered as scc-osd-daemon") self._registered = True def failure(why): log.error("Failed to registered as scc-osd-daemon: %s", why) self.quit(1) if not self._registered: self.daemon.request('Register: osd', success, failure) def on_menu_closed(self, m): """ Called after OSD menu is hidden from screen """ self._window = None if m.get_exit_code() == 0: # 0 means that user selected item and confirmed selection self.daemon.request( 'Selected: %s' % ( shjoin([ m.get_menuid(), m.get_selected_item_id() ])), lambda *a : False, lambda *a : False) def on_message_closed(self, m): hsh = m.hash() if hsh in self._visible_messages: del self._visible_messages[hsh] def on_keyboard_closed(self, *a): """ Called after on-screen keyboard is hidden from the screen """ self._window = None def on_gesture_recognized(self, gd): """ Called after on-screen keyboard is hidden from the screen """ self._window = None if gd.get_exit_code() == 0: self.daemon.request('Gestured: %s' % ( gd.get_gesture(), ), lambda *a : False, lambda *a : False) else: self.daemon.request('Gestured: x', lambda *a : False, lambda *a : False) @staticmethod def _is_menu_message(m): """ Returns True if m starts with 'OSD: [grid|radial]menu' or "OSD: dialog" """ return ( m.startswith("OSD: menu") or m.startswith("OSD: radialmenu") or m.startswith("OSD: quickmenu") or m.startswith("OSD: gridmenu") or m.startswith("OSD: dialog") or m.startswith("OSD: hmenu") ) def on_unknown_message(self, daemon, message): if not message.startswith("OSD:"): return if message.startswith("OSD: message"): args = shsplit(message)[1:] m = Message() m.parse_argumets(args) hsh = m.hash() if hsh in self._visible_messages: self._visible_messages[hsh].extend() m.destroy() else: # TODO: Do this only for default position once changing # TODO: is allowed if len(self._visible_messages): height = self._visible_messages.values()[0].get_size().height x, y = m.position while y in [ i.position[1] for i in self._visible_messages.values() ]: y -= height + 5 m.position = x, y m.show() self._visible_messages[hsh] = m m.connect("destroy", self.on_message_closed) elif message.startswith("OSD: keyboard"): if self._window: log.warning("Another OSD is already visible - refusing to show keyboard") else: args = shsplit(message)[1:] self._window = Keyboard(self.config) self._window.connect('destroy', self.on_keyboard_closed) self._window.parse_argumets(args) self._window.show() self._window.use_daemon(self.daemon) elif message.startswith("OSD: gesture"): if self._window: log.warning("Another OSD is already visible - refusing to show keyboard") else: args = shsplit(message)[1:] self._window = GestureDisplay(self.config) self._window.parse_argumets(args) self._window.use_daemon(self.daemon) self._window.show() self._window.connect('destroy', self.on_gesture_recognized) elif self._is_menu_message(message): args = shsplit(message)[1:] if self._window: log.warning("Another OSD is already visible - refusing to show menu") else: if message.startswith("OSD: hmenu"): self._window = HorizontalMenu() elif message.startswith("OSD: radialmenu"): self._window = RadialMenu() elif message.startswith("OSD: quickmenu"): self._window = QuickMenu() elif message.startswith("OSD: gridmenu"): self._window = GridMenu() elif message.startswith("OSD: dialog"): self._window = Dialog() else: self._window = Menu() self._window.connect('destroy', self.on_menu_closed) self._window.use_config(self.config) try: if self._window.parse_argumets(args): self._window.show() self._window.use_daemon(self.daemon) else: log.error("Failed to show menu") self._window = None except: log.error(traceback.format_exc()) log.error("Failed to show menu") self._window = None elif message.startswith("OSD: area"): args = shsplit(message)[1:] if self._window: log.warning("Another OSD is already visible - refusing to show area") else: args = shsplit(message)[1:] self._window = Area() self._window.connect('destroy', self.on_keyboard_closed) if self._window.parse_argumets(args): self._window.show() else: self._window.quit() self._window = None elif message.startswith("OSD: clear"): # Clears active OSD windows self.clear_windows() else: log.warning("Unknown command from daemon: '%s'", message) def clear_windows(self): if self._window: self._window.quit() self._window = None self.clear_messages(only_long_lasting=False) def clear_messages(self, only_long_lasting=True): """ Clears all OSD messages from screen. If only_long_lasting is True, which is default behaviour on profile change, only messages set to last more than 10s are hidden. """ to_destroy = [] + self._visible_messages.values() for m in to_destroy: if not only_long_lasting or m.timeout <= 0 or m.timeout > OSDAction.DEFAULT_TIMEOUT * 2: m.destroy() def _check_colorconfig_change(self): """ Checks if OSD color configuration is changed and re-applies CSS if needed. """ h = sum([ hash(self.config['osd_colors'][x]) for x in self.config['osd_colors'] ]) h += sum([ hash(self.config['osk_colors'][x]) for x in self.config['osk_colors'] ]) h += hash(self.config['osd_style']) if self._hash_of_colors != h: self._hash_of_colors = h OSDWindow._apply_css(self.config) if self._window and isinstance(self._window, Keyboard): self._window.recolor() self._window.update_labels() self._window.redraw_background() def run(self): on_wayland = "WAYLAND_DISPLAY" in os.environ or not isinstance(Gdk.Display.get_default(), GdkX11.X11Display) if on_wayland: log.error("Cannot run on Wayland") self.exit_code = 8 return self.daemon = DaemonManager() self.config = Config() self._check_colorconfig_change() self.daemon.connect('alive', self.on_daemon_connected) self.daemon.connect('dead', self.on_daemon_died) self.daemon.connect('profile-changed', self.on_profile_changed) self.daemon.connect('reconfigured', self.on_daemon_reconfigured) self.daemon.connect('unknown-msg', self.on_unknown_message) self.mainloop.run()
class OSDDaemon(object): def __init__(self): self.exit_code = -1 self.mainloop = GLib.MainLoop() self.config = None self._window = None self._registered = False self._last_profile_change = 0 self._recent_profiles_undo = None OSDWindow._apply_css() def quit(self, code=-1): self.exit_code = code self.mainloop.quit() def get_exit_code(self): return self.exit_code def on_daemon_reconfigured(self, *a): log.debug("Reloading config...") self.config.reload() def on_profile_changed(self, daemon, profile): name = os.path.split(profile)[-1] if name.endswith(".sccprofile") and not name.startswith("."): # Ignore .mod and hidden files name = name[0:-11] recents = self.config['recent_profiles'] if len(recents) and recents[0] == name: # Already first in recent list return if time.time() - self._last_profile_change < 2.0: # Profiles are changing too fast, probably because user # is using scroll wheel over profile combobox if self._recent_profiles_undo: recents = [] + self._recent_profiles_undo self._last_profile_change = time.time() self._recent_profiles_undo = [] + recents while name in recents: recents.remove(name) recents.insert(0, name) if len(recents) > self.config['recent_max']: recents = recents[0:self.config['recent_max']] self.config['recent_profiles'] = recents self.config.save() log.debug("Updated recent profile list") def on_daemon_died(self, *a): log.error("Connection to daemon lost") self.quit(2) def on_daemon_connected(self, *a): def success(*a): log.info("Sucessfully registered as scc-osd-daemon") self._registered = True def failure(why): log.error("Failed to registered as scc-osd-daemon: %s", why) self.quit(1) if not self._registered: self.daemon.request('Register: osd', success, failure) def on_menu_closed(self, m): """ Called after OSD menu is hidden from screen """ self._window = None if m.get_exit_code() == 0: # 0 means that user selected item and confirmed selection self.daemon.request( 'Selected: %s %s' % (m.get_menuid(), m.get_selected_item_id()), lambda *a: False, lambda *a: False) def on_keyboard_closed(self, *a): """ Called after on-screen keyboard is hidden from the screen """ self._window = None def on_unknown_message(self, daemon, message): if not message.startswith("OSD:"): return if message.startswith("OSD: message"): args = split(message)[1:] m = Message() m.parse_argumets(args) m.show() elif message.startswith("OSD: keyboard"): if self._window: log.warning( "Another OSD is already visible - refusing to show keyboard" ) else: args = split(message)[1:] self._window = Keyboard() self._window.connect('destroy', self.on_keyboard_closed) # self._window.parse_argumets(args) # TODO: No arguments so far self._window.show() self._window.use_daemon(self.daemon) elif message.startswith("OSD: menu") or message.startswith( "OSD: gridmenu"): args = split(message)[1:] if self._window: log.warning( "Another OSD is already visible - refusing to show menu") else: self._window = GridMenu() if "gridmenu" in message else Menu() self._window.connect('destroy', self.on_menu_closed) self._window.use_config(self.config) if self._window.parse_argumets(args): self._window.show() self._window.use_daemon(self.daemon) else: log.error("Failed to show menu") self._window = None elif message.startswith("OSD: area"): args = split(message)[1:] if self._window: log.warning( "Another OSD is already visible - refusing to show area") else: args = split(message)[1:] self._window = Area() self._window.connect('destroy', self.on_keyboard_closed) if self._window.parse_argumets(args): self._window.show() else: self._window.quit() self._window = None elif message.startswith("OSD: clear"): # Clears active OSD window (if any) if self._window: self._window.quit() self._window = None else: log.warning("Unknown command from daemon: '%s'", message) def run(self): self.daemon = DaemonManager() self.config = Config() self.daemon.connect('alive', self.on_daemon_connected) self.daemon.connect('dead', self.on_daemon_died) self.daemon.connect('profile-changed', self.on_profile_changed) self.daemon.connect('reconfigured', self.on_daemon_reconfigured) self.daemon.connect('unknown-msg', self.on_unknown_message) self.mainloop.run()
class AxisActionComponent(AEComponent, TimerManager): GLADE = "ae/axis_action.glade" NAME = "axis_action" CTXS = Action.AC_STICK, Action.AC_PAD, PRIORITY = 3 def __init__(self, app, editor): AEComponent.__init__(self, app, editor) TimerManager.__init__(self) self._recursing = False self.relative_area = False self.osd_area_instance = None self.parser = GuiActionParser() def load(self): if self.loaded : return AEComponent.load(self) cbAreaType = self.builder.get_object("cbAreaType") cbAreaType.set_row_separator_func( lambda model, iter : model.get_value(iter, 0) == "-" ) def hidden(self): self.update_osd_area(None) def set_action(self, mode, action): if self.handles(mode, action): cb = self.builder.get_object("cbAxisOutput") if isinstance(action, AreaAction): self.load_area_action(action) self.set_cb(cb, "area", 2) self.update_osd_area(action) return self.update_osd_area(None) if isinstance(action, TrackpadAction): self.set_cb(cb, "trackpad", 2) elif isinstance(action, TrackballAction): self.set_cb(cb, "trackball", 2) elif isinstance(action, CircularAction): self.set_cb(cb, "circular", 2) elif isinstance(action, XYAction): p = [ None, None ] for x in (0, 1): if len(action.actions[0].strip().parameters) >= x: if len(action.actions[x].strip().parameters) > 0: p[x] = action.actions[x].strip().parameters[0] if p[0] == Axes.ABS_X and p[1] == Axes.ABS_Y: self.set_cb(cb, "lstick", 2) elif p[0] == Axes.ABS_RX and p[1] == Axes.ABS_RY: self.set_cb(cb, "rstick", 2) elif p[0] == Axes.ABS_HAT0X and p[1] == Axes.ABS_HAT0Y: self.set_cb(cb, "dpad", 2) elif p[0] == Rels.REL_HWHEEL and p[1] == Rels.REL_WHEEL: self.set_cb(cb, "wheel", 2) else: self.set_cb(cb, "none", 2) def update_osd_area(self, action): """ Updates preview area displayed on screen """ if action: if self.osd_area_instance is None: self.osd_area_instance = Area() self.osd_area_instance.show() action.update_osd_area(self.osd_area_instance, FakeMapper(self.editor)) self.timer("area", 0.5, self.update_osd_area, action) elif self.osd_area_instance: self.osd_area_instance.quit() self.osd_area_instance = None self.cancel_timer("area") def load_area_action(self, action): """ Load AreaAction values into UI. """ cbAreaType = self.builder.get_object("cbAreaType") x1, y1, x2, y2 = action.coords self.relative_area = False if isinstance(action, RelAreaAction): key = "screensize" self.relative_area = True x1, y1, x2, y2 = x1 * 100.0, y1 * 100.0, x2 * 100.0, y2 * 100.0 elif isinstance(action, RelWinAreaAction): key = "windowsize" self.relative_area = True x1, y1, x2, y2 = x1 * 100.0, y1 * 100.0, x2 * 100.0, y2 * 100.0 else: t1 = "1" if x1 < 0 and x2 < 0 else "0" t2 = "1" if y1 < 0 and y2 < 0 else "0" x1, y1, x2, y2 = abs(x1), abs(y1), abs(x2), abs(y2) if x2 < x1 : x1, x2 = x2, x1 if y2 < y1 : y1, y2 = y2, y1 if isinstance(action, WinAreaAction): key = "window-%s%s" % (t1, t2) else: key = "screen-%s%s" % (t1, t2) self._recursing = True self.builder.get_object("sbAreaX1").set_value(x1) self.builder.get_object("sbAreaY1").set_value(y1) self.builder.get_object("sbAreaX2").set_value(x2) self.builder.get_object("sbAreaY2").set_value(y2) self.builder.get_object("cbAreaOSDEnabled").set_active(self.editor.osd) self.builder.get_object("cbAreaClickEnabled").set_active(self.pressing_pad_clicks()) for row in cbAreaType.get_model(): if key == row[1]: cbAreaType.set_active_iter(row.iter) break self._recursing = False def on_cbAreaOSDEnabled_toggled(self, *a): self.editor.builder.get_object("cbOSD").set_active( self.builder.get_object("cbAreaOSDEnabled").get_active()) def pressing_pad_clicks(self): """ Returns True if currently edited pad is set to press left mouse button when pressed. (yes, this is used somewhere) """ side = getattr(SCButtons, self.editor.get_id()) c_action = self.app.current.buttons[side] if isinstance(c_action, ButtonAction): return c_action.button == Keys.BTN_LEFT return False def on_ok(self, action): if isinstance(action.strip(), AreaAction): # Kinda hacky way to set action on LPAD press or RPAD press # when user selects Mouse Area as ouput and checks # 'Pressing the Pad Clicks' checkbox side = getattr(SCButtons, self.editor.get_id()) clicks = self.pressing_pad_clicks() if self.builder.get_object("cbAreaClickEnabled").get_active(): if not clicks: # Turn pad press into mouse clicks self.app.set_action(side, ButtonAction(Keys.BTN_LEFT)) else: if clicks: # Clear action created above if checkbox is uncheck self.app.set_action(side, NoAction()) def make_area_action(self): """ Loads values from UI into new AreaAction or subclass. """ # Prepare cbAreaType = self.builder.get_object("cbAreaType") # Read numbers x1 = self.builder.get_object("sbAreaX1").get_value() y1 = self.builder.get_object("sbAreaY1").get_value() x2 = self.builder.get_object("sbAreaX2").get_value() y2 = self.builder.get_object("sbAreaY2").get_value() # Determine exact action type by looking into Area Type checkbox # (this part may seem little crazy) # ... numbers key = cbAreaType.get_model().get_value(cbAreaType.get_active_iter(), 1) if "-" in key: if key[-2] == "1": # Before-last character ius "1", that means that X coords are # counted from other side and has to be negated x1, x2 = -x1, -x2 if key[-1] == "1": # Key ends with "1". Same thing as above but for Y coordinate y1, y2 = -y1, -y2 if "size" in key: x1, y1, x2, y2 = x1 / 100.0, y1 / 100.0, x2 / 100.0, y2 / 100.0 # ... class if "window-" in key: cls = WinAreaAction self.relative_area = False elif "screensize" == key: cls = RelAreaAction self.relative_area = True elif "windowsize" == key: cls = RelWinAreaAction self.relative_area = True else: # "screen" in key cls = AreaAction self.relative_area = False if not self.relative_area: x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2) return cls(x1, y1, x2, y2) def get_button_title(self): return _("Joystick or Mouse") def handles(self, mode, action): if isinstance(action, (NoAction, TrackballAction, CircularAction, InvalidAction, AreaAction)): return True if isinstance(action, XYAction): p = [ None, None ] for x in (0, 1): if len(action.actions[0].strip().parameters) >= x: if len(action.actions[x].strip().parameters) > 0: p[x] = action.actions[x].strip().parameters[0] if p[0] == Axes.ABS_X and p[1] == Axes.ABS_Y: return True elif p[0] == Axes.ABS_RX and p[1] == Axes.ABS_RY: return True elif p[0] == Axes.ABS_HAT0X and p[1] == Axes.ABS_HAT0Y: return True elif p[0] == Rels.REL_HWHEEL and p[1] == Rels.REL_WHEEL: return True return False def on_area_options_changed(self, *a): if self._recursing : return action = self.make_area_action() self.editor.set_action(action) self.update_osd_area(action) for x in ('sbAreaX1', 'sbAreaX2', 'sbAreaY1', 'sbAreaY2'): spin = self.builder.get_object(x) if self.relative_area: spin.get_adjustment().set_upper(100) else: spin.get_adjustment().set_upper(1000) self.on_sbArea_output(spin) def on_sbArea_output(self, button, *a): if self.relative_area: button.set_text("%s %%" % (button.get_value())) else: button.set_text("%s px" % (int(button.get_value()))) def on_sbArea_focus_out_event(self, button, *a): GLib.idle_add(self.on_sbArea_output, button) def on_sbArea_changed(self, button, *a): self.on_sbArea_output(button) self.on_area_options_changed(button) def on_cbAxisOutput_changed(self, *a): cbAxisOutput = self.builder.get_object("cbAxisOutput") stActionData = self.builder.get_object("stActionData") key = cbAxisOutput.get_model().get_value(cbAxisOutput.get_active_iter(), 2) if key == 'area': stActionData.set_visible_child(self.builder.get_object("grArea")) action = self.make_area_action() self.update_osd_area(action) else: stActionData.set_visible_child(self.builder.get_object("nothing")) action = cbAxisOutput.get_model().get_value(cbAxisOutput.get_active_iter(), 0) action = self.parser.restart(action).parse() self.update_osd_area(None) self.editor.set_action(action)
class AxisActionComponent(AEComponent, TimerManager): GLADE = "ae/axis_action.glade" NAME = "axis_action" CTXS = Action.AC_STICK, Action.AC_PAD, PRIORITY = 3 def __init__(self, app, editor): AEComponent.__init__(self, app, editor) TimerManager.__init__(self) self._recursing = False self.relative_area = False self.osd_area_instance = None self.parser = GuiActionParser() def load(self): if self.loaded: return AEComponent.load(self) cbAreaType = self.builder.get_object("cbAreaType") cbAreaType.set_row_separator_func( lambda model, iter: model.get_value(iter, 0) == "-") def hidden(self): self.update_osd_area(None) def set_action(self, mode, action): if self.handles(mode, action): cb = self.builder.get_object("cbAxisOutput") if isinstance(action, AreaAction): self.load_area_action(action) self.set_cb(cb, "area", 2) self.update_osd_area(action) return self.update_osd_area(None) if isinstance(action, TrackpadAction): self.set_cb(cb, "trackpad", 2) elif isinstance(action, TrackballAction): self.set_cb(cb, "trackball", 2) elif isinstance(action, CircularAction): self.set_cb(cb, "circular", 2) elif isinstance(action, XYAction): p = [None, None] for x in (0, 1): if len(action.actions[0].strip().parameters) >= x: if len(action.actions[x].strip().parameters) > 0: p[x] = action.actions[x].strip().parameters[0] if p[0] == Axes.ABS_X and p[1] == Axes.ABS_Y: self.set_cb(cb, "lstick", 2) elif p[0] == Axes.ABS_RX and p[1] == Axes.ABS_RY: self.set_cb(cb, "rstick", 2) elif p[0] == Axes.ABS_HAT0X and p[1] == Axes.ABS_HAT0Y: self.set_cb(cb, "dpad", 2) elif p[0] == Rels.REL_HWHEEL and p[1] == Rels.REL_WHEEL: self.set_cb(cb, "wheel", 2) else: self.set_cb(cb, "none", 2) def update_osd_area(self, action): """ Updates preview area displayed on screen """ if action: if self.osd_area_instance is None: self.osd_area_instance = Area() self.osd_area_instance.show() action.update_osd_area(self.osd_area_instance, FakeMapper(self.editor)) self.timer("area", 0.5, self.update_osd_area, action) elif self.osd_area_instance: self.osd_area_instance.quit() self.osd_area_instance = None self.cancel_timer("area") def load_area_action(self, action): """ Load AreaAction values into UI. """ cbAreaType = self.builder.get_object("cbAreaType") x1, y1, x2, y2 = action.coords self.relative_area = False if isinstance(action, RelAreaAction): key = "screensize" self.relative_area = True x1, y1, x2, y2 = x1 * 100.0, y1 * 100.0, x2 * 100.0, y2 * 100.0 elif isinstance(action, RelWinAreaAction): key = "windowsize" self.relative_area = True x1, y1, x2, y2 = x1 * 100.0, y1 * 100.0, x2 * 100.0, y2 * 100.0 else: t1 = "1" if x1 < 0 and x2 < 0 else "0" t2 = "1" if y1 < 0 and y2 < 0 else "0" x1, y1, x2, y2 = abs(x1), abs(y1), abs(x2), abs(y2) if x2 < x1: x1, x2 = x2, x1 if y2 < y1: y1, y2 = y2, y1 if isinstance(action, WinAreaAction): key = "window-%s%s" % (t1, t2) else: key = "screen-%s%s" % (t1, t2) self._recursing = True self.builder.get_object("sbAreaX1").set_value(x1) self.builder.get_object("sbAreaY1").set_value(y1) self.builder.get_object("sbAreaX2").set_value(x2) self.builder.get_object("sbAreaY2").set_value(y2) self.builder.get_object("cbAreaOSDEnabled").set_active(self.editor.osd) self.builder.get_object("cbAreaClickEnabled").set_active( self.pressing_pad_clicks()) for row in cbAreaType.get_model(): if key == row[1]: cbAreaType.set_active_iter(row.iter) break self._recursing = False def on_cbAreaOSDEnabled_toggled(self, *a): self.editor.builder.get_object("cbOSD").set_active( self.builder.get_object("cbAreaOSDEnabled").get_active()) def pressing_pad_clicks(self): """ Returns True if currently edited pad is set to press left mouse button when pressed. (yes, this is used somewhere) """ side = getattr(SCButtons, self.editor.get_id()) c_action = self.app.current.buttons[side] if isinstance(c_action, ButtonAction): return c_action.button == Keys.BTN_LEFT return False def on_ok(self, action): if isinstance(action.strip(), AreaAction): # Kinda hacky way to set action on LPAD press or RPAD press # when user selects Mouse Area as ouput and checks # 'Pressing the Pad Clicks' checkbox side = getattr(SCButtons, self.editor.get_id()) clicks = self.pressing_pad_clicks() if self.builder.get_object("cbAreaClickEnabled").get_active(): if not clicks: # Turn pad press into mouse clicks self.app.set_action(side, ButtonAction(Keys.BTN_LEFT)) else: if clicks: # Clear action created above if checkbox is uncheck self.app.set_action(side, NoAction()) def make_area_action(self): """ Loads values from UI into new AreaAction or subclass. """ # Prepare cbAreaType = self.builder.get_object("cbAreaType") # Read numbers x1 = self.builder.get_object("sbAreaX1").get_value() y1 = self.builder.get_object("sbAreaY1").get_value() x2 = self.builder.get_object("sbAreaX2").get_value() y2 = self.builder.get_object("sbAreaY2").get_value() # Determine exact action type by looking into Area Type checkbox # (this part may seem little crazy) # ... numbers key = cbAreaType.get_model().get_value(cbAreaType.get_active_iter(), 1) if "-" in key: if key[-2] == "1": # Before-last character ius "1", that means that X coords are # counted from other side and has to be negated x1, x2 = -x1, -x2 if key[-1] == "1": # Key ends with "1". Same thing as above but for Y coordinate y1, y2 = -y1, -y2 if "size" in key: x1, y1, x2, y2 = x1 / 100.0, y1 / 100.0, x2 / 100.0, y2 / 100.0 # ... class if "window-" in key: cls = WinAreaAction self.relative_area = False elif "screensize" == key: cls = RelAreaAction self.relative_area = True elif "windowsize" == key: cls = RelWinAreaAction self.relative_area = True else: # "screen" in key cls = AreaAction self.relative_area = False if not self.relative_area: x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2) return cls(x1, y1, x2, y2) def get_button_title(self): return _("Joystick or Mouse") def handles(self, mode, action): if isinstance(action, (NoAction, TrackballAction, CircularAction, InvalidAction, AreaAction)): return True if isinstance(action, XYAction): p = [None, None] for x in (0, 1): if len(action.actions[0].strip().parameters) >= x: if len(action.actions[x].strip().parameters) > 0: p[x] = action.actions[x].strip().parameters[0] if p[0] == Axes.ABS_X and p[1] == Axes.ABS_Y: return True elif p[0] == Axes.ABS_RX and p[1] == Axes.ABS_RY: return True elif p[0] == Axes.ABS_HAT0X and p[1] == Axes.ABS_HAT0Y: return True elif p[0] == Rels.REL_HWHEEL and p[1] == Rels.REL_WHEEL: return True return False def on_area_options_changed(self, *a): if self._recursing: return action = self.make_area_action() self.editor.set_action(action) self.update_osd_area(action) for x in ('sbAreaX1', 'sbAreaX2', 'sbAreaY1', 'sbAreaY2'): spin = self.builder.get_object(x) if self.relative_area: spin.get_adjustment().set_upper(100) else: spin.get_adjustment().set_upper(1000) self.on_sbArea_output(spin) def on_sbArea_output(self, button, *a): if self.relative_area: button.set_text("%s %%" % (button.get_value())) else: button.set_text("%s px" % (int(button.get_value()))) def on_sbArea_focus_out_event(self, button, *a): GLib.idle_add(self.on_sbArea_output, button) def on_sbArea_changed(self, button, *a): self.on_sbArea_output(button) self.on_area_options_changed(button) def on_cbAxisOutput_changed(self, *a): cbAxisOutput = self.builder.get_object("cbAxisOutput") stActionData = self.builder.get_object("stActionData") key = cbAxisOutput.get_model().get_value( cbAxisOutput.get_active_iter(), 2) if key == 'area': stActionData.set_visible_child(self.builder.get_object("grArea")) action = self.make_area_action() self.update_osd_area(action) else: stActionData.set_visible_child(self.builder.get_object("nothing")) action = cbAxisOutput.get_model().get_value( cbAxisOutput.get_active_iter(), 0) action = self.parser.restart(action).parse() self.update_osd_area(None) self.editor.set_action(action)
class AxisActionComponent(AEComponent, TimerManager): GLADE = "ae/axis_action.glade" NAME = "axis_action" CTXS = Action.AC_STICK | Action.AC_PAD PRIORITY = 3 def __init__(self, app, editor): AEComponent.__init__(self, app, editor) TimerManager.__init__(self) self._recursing = False self.relative_area = False self.osd_area_instance = None self.on_wayland = False self.circular_axis = MouseAction(Rels.REL_WHEEL) self.circular_buttons = [ None, None ] self.button = None self.parser = GuiActionParser() def load(self): if self.loaded : return AEComponent.load(self) cbAreaType = self.builder.get_object("cbAreaType") cbAreaType.set_row_separator_func( lambda model, iter : model.get_value(iter, 0) == "-" ) self.on_wayland = "WAYLAND_DISPLAY" in os.environ or not isinstance(Gdk.Display.get_default(), GdkX11.X11Display) if self.on_wayland: self.builder.get_object("lblArea").set_text(_("Note: Mouse Region option is not available with Wayland-based display server")) self.builder.get_object("grArea").set_sensitive(False) # Remove options that are not applicable to currently editted input if self.editor.get_id() in STICKS: # Remove "Mouse Region", "Mouse" and "Mouse (Emulate Stick)" options # when editing stick bindings cb = self.builder.get_object("cbAxisOutput") for row in cb.get_model(): if row[2] in ("wheel_pad", "area", "mouse", "mouse_pad"): cb.get_model().remove(row.iter) else: # Remove "Mouse" option when editing pads # (it's effectivelly same as Trackpad) cb = self.builder.get_object("cbAxisOutput") for row in cb.get_model(): if row[2] in ("wheel_stick", "mouse_stick"): cb.get_model().remove(row.iter) def hidden(self): self.update_osd_area(None) def set_action(self, mode, action): if self.handles(mode, action): cb = self.builder.get_object("cbAxisOutput") if isinstance(action, AreaAction): self.load_area_action(action) self.set_cb(cb, "area", 2) self.update_osd_area(action) return self.update_osd_area(None) if isinstance(action, MouseAction): self.load_mouse_action(action) elif isinstance(action, CircularModifier): self.load_circular_action(action) elif isinstance(action, ButtonAction): self.load_button_action(action) elif isinstance(action, XYAction): if self.editor.friction > 0: self.load_mouse_action(action) else: p = [ None, None ] for x in (0, 1): if len(action.actions[0].strip().parameters) >= x: if len(action.actions[x].strip().parameters) > 0: p[x] = action.actions[x].strip().parameters[0] if p[0] == Axes.ABS_X and p[1] == Axes.ABS_Y: self.set_cb(cb, "lstick", 2) elif p[0] == Axes.ABS_RX and p[1] == Axes.ABS_RY: if isinstance(action, RelXYAction): self.set_cb(cb, "rstick_rel", 2) else: self.set_cb(cb, "rstick", 2) elif p[0] == Rels.REL_HWHEEL and p[1] == Rels.REL_WHEEL: self.set_cb(cb, "wheel_pad", 2) self.set_cb(cb, "wheel_stick", 2) else: self.set_cb(cb, "none", 2) def update_osd_area(self, action): """ Updates preview area displayed on screen """ if action: if self.osd_area_instance is None: if self.on_wayland: # Cannot display preview with non-X11 backends return self.osd_area_instance = Area() self.osd_area_instance.show() action.update_osd_area(self.osd_area_instance, FakeMapper(self.editor)) self.timer("area", 0.5, self.update_osd_area, action) elif self.osd_area_instance: self.osd_area_instance.quit() self.osd_area_instance = None self.cancel_timer("area") def load_circular_action(self, action): cbAxisOutput = self.builder.get_object("cbAxisOutput") btCircularAxis = self.builder.get_object("btCircularAxis") btCircularButton0 = self.builder.get_object("btCircularButton0") btCircularButton1 = self.builder.get_object("btCircularButton1") # Turn action into list of subactions (even if it's just single action) if isinstance(action.action, MultiAction): actions = action.action.actions else: actions = [ action.action ] # Parse that list self.circular_axis, self.circular_buttons = NoAction(), [ None, None ] for action in actions: if isinstance(action, ButtonAction): self.circular_buttons = [ action.button, action.button2 ] else: self.circular_axis = action # Set labels b0, b1 = self.circular_buttons btCircularButton0.set_label(ButtonAction.describe_button(b0)) btCircularButton1.set_label(ButtonAction.describe_button(b1)) btCircularAxis.set_label(self.circular_axis.describe(Action.AC_PAD)) self.set_cb(cbAxisOutput, "circular", 2) def load_button_action(self, action): self.button = action cbAxisOutput = self.builder.get_object("cbAxisOutput") btSingleButton = self.builder.get_object("btSingleButton") btSingleButton.set_label(self.button.describe(Action.AC_PAD)) self.set_cb(cbAxisOutput, "button", 2) def load_mouse_action(self, action): cbMouseOutput = self.builder.get_object("cbMouseOutput") cbAxisOutput = self.builder.get_object("cbAxisOutput") self._recursing = True if isinstance(action, MouseAction): self.set_cb(cbMouseOutput, "mouse", 1) self.set_cb(cbAxisOutput, "mouse", 2) elif isinstance(action, XYAction): if isinstance(action.x, AxisAction): if action.x.parameters[0] == Axes.ABS_X: self.set_cb(cbMouseOutput, "left", 1) else: self.set_cb(cbMouseOutput, "right", 1) self.set_cb(cbAxisOutput, "mouse", 2) elif isinstance(action.x, MouseAction): if self.editor.get_id() in STICKS: self.set_cb(cbAxisOutput, "wheel_stick", 2) else: self.set_cb(cbAxisOutput, "wheel_pad", 2) self._recursing = False def load_area_action(self, action): """ Load AreaAction values into UI. """ cbAreaType = self.builder.get_object("cbAreaType") x1, y1, x2, y2 = action.coords self.relative_area = False if isinstance(action, RelAreaAction): key = "screensize" self.relative_area = True x1, y1, x2, y2 = x1 * 100.0, y1 * 100.0, x2 * 100.0, y2 * 100.0 elif isinstance(action, RelWinAreaAction): key = "windowsize" self.relative_area = True x1, y1, x2, y2 = x1 * 100.0, y1 * 100.0, x2 * 100.0, y2 * 100.0 else: t1 = "1" if x1 < 0 and x2 < 0 else "0" t2 = "1" if y1 < 0 and y2 < 0 else "0" x1, y1, x2, y2 = abs(x1), abs(y1), abs(x2), abs(y2) if x2 < x1 : x1, x2 = x2, x1 if y2 < y1 : y1, y2 = y2, y1 if isinstance(action, WinAreaAction): key = "window-%s%s" % (t1, t2) else: key = "screen-%s%s" % (t1, t2) self._recursing = True self.builder.get_object("sbAreaX1").set_value(x1) self.builder.get_object("sbAreaY1").set_value(y1) self.builder.get_object("sbAreaX2").set_value(x2) self.builder.get_object("sbAreaY2").set_value(y2) self.builder.get_object("cbAreaOSDEnabled").set_active(self.editor.osd) self.builder.get_object("cbAreaClickEnabled").set_active(self.pressing_pad_clicks()) for row in cbAreaType.get_model(): if key == row[1]: cbAreaType.set_active_iter(row.iter) break self._recursing = False def on_btCircularAxis_clicked(self, *a): def cb(action): self.circular_axis = action btCircularAxis = self.builder.get_object("btCircularAxis") btCircularAxis.set_label(action.describe(Action.AC_PAD)) self.editor.set_action(self.make_circular_action()) b = SimpleChooser(self.app, "axis", cb) b.set_title(_("Select Axis")) b.display_action(Action.AC_STICK, self.circular_axis) b.show(self.editor.window) def on_btCircularButton_clicked(self, button, *a): index = 0 if button == self.builder.get_object("btCircularButton0") else 1 def cb(action): self.circular_buttons[index] = action.button btCircularButton = self.builder.get_object("btCircularButton%s" % (index, )) btCircularButton.set_label(action.describe(Action.AC_PAD)) self.editor.set_action(self.make_circular_action()) b = SimpleChooser(self.app, "buttons", cb) b.set_title(_("Select Button")) b.display_action(Action.AC_STICK, self.circular_axis) b.show(self.editor.window) def on_btClearCircularAxis_clicked(self, *a): btCircularAxis = self.builder.get_object("btCircularAxis") self.circular_axis = NoAction() btCircularAxis.set_label(self.circular_axis.describe(Action.AC_PAD)) self.editor.set_action(self.make_circular_action()) def on_btClearCircularButtons_clicked(self, *a): btCircularButton0 = self.builder.get_object("btCircularButton0") btCircularButton1 = self.builder.get_object("btCircularButton1") self.circular_buttons = [ None, None ] btCircularButton0.set_label(NoAction().describe(Action.AC_PAD)) btCircularButton1.set_label(NoAction().describe(Action.AC_PAD)) self.editor.set_action(self.make_circular_action()) def on_btSingleButton_clicked(self, *a): def cb(action): self.button = action btSingleButton = self.builder.get_object("btSingleButton") btSingleButton.set_label(self.button.describe(Action.AC_PAD)) self.editor.set_action(self.button) b = SimpleChooser(self.app, "buttons", cb) b.set_title(_("Select Button")) b.display_action(Action.AC_STICK, self.circular_axis) b.show(self.editor.window) def on_cbAreaOSDEnabled_toggled(self, *a): self.editor.builder.get_object("cbOSD").set_active( self.builder.get_object("cbAreaOSDEnabled").get_active()) def pressing_pad_clicks(self): """ Returns True if currently edited pad is set to press left mouse button when pressed. (yes, this is used somewhere) """ side = getattr(SCButtons, self.editor.get_id()) c_action = self.app.current.buttons[side] if isinstance(c_action, ButtonAction): return c_action.button == Keys.BTN_LEFT return False def on_ok(self, action): if isinstance(action.strip(), AreaAction): # Kinda hacky way to set action on LPAD press or RPAD press # when user selects Mouse Area as ouput and checks # 'Pressing the Pad Clicks' checkbox side = getattr(SCButtons, self.editor.get_id()) clicks = self.pressing_pad_clicks() if self.builder.get_object("cbAreaClickEnabled").get_active(): if not clicks: # Turn pad press into mouse clicks self.app.set_action(self.app.current, side, ButtonAction(Keys.BTN_LEFT)) else: if clicks: # Clear action created above if checkbox is uncheck self.app.set_action(self.app.current, side, NoAction()) def on_mouse_options_changed(self, *a): if self._recursing : return action = self.make_mouse_action() self.editor.set_action(action) def make_mouse_action(self): """ Loads values from UI into trackball-related action """ cbMouseOutput = self.builder.get_object("cbMouseOutput") a_str = cbMouseOutput.get_model().get_value(cbMouseOutput.get_active_iter(), 2) return self.parser.restart(a_str).parse() def make_circular_action(self): """ Constructs Circular Modifier """ if self.circular_axis and any(self.circular_buttons): return CircularModifier(MultiAction( self.circular_axis, ButtonAction(*self.circular_buttons))) elif any(self.circular_buttons): return CircularModifier(ButtonAction(*self.circular_buttons)) else: return CircularModifier(self.circular_axis) def make_area_action(self): """ Loads values from UI into new AreaAction or subclass. """ # Prepare cbAreaType = self.builder.get_object("cbAreaType") # Read numbers x1 = self.builder.get_object("sbAreaX1").get_value() y1 = self.builder.get_object("sbAreaY1").get_value() x2 = self.builder.get_object("sbAreaX2").get_value() y2 = self.builder.get_object("sbAreaY2").get_value() # Determine exact action type by looking into Area Type checkbox # (this part may seem little crazy) # ... numbers key = cbAreaType.get_model().get_value(cbAreaType.get_active_iter(), 1) if "-" in key: if key[-2] == "1": # Before-last character ius "1", that means that X coords are # counted from other side and has to be negated x1, x2 = -x1, -x2 if key[-1] == "1": # Key ends with "1". Same thing as above but for Y coordinate y1, y2 = -y1, -y2 if "size" in key: x1, y1, x2, y2 = x1 / 100.0, y1 / 100.0, x2 / 100.0, y2 / 100.0 # ... class if "window-" in key: cls = WinAreaAction self.relative_area = False elif "screensize" == key: cls = RelAreaAction self.relative_area = True elif "windowsize" == key: cls = RelWinAreaAction self.relative_area = True else: # "screen" in key cls = AreaAction self.relative_area = False if not self.relative_area: x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2) return cls(x1, y1, x2, y2) def get_button_title(self): return _("Joystick / Mouse") def handles(self, mode, action): if isinstance(action, (NoAction, MouseAction, CircularModifier, InvalidAction, AreaAction, ButtonAction)): return True if isinstance(action, BallModifier): if isinstance(action.action, XYAction): return ( isinstance(action.action.x, (AxisAction, MouseAction)) and isinstance(action.action.x, (AxisAction, MouseAction)) ) return isinstance(action.action, MouseAction) if isinstance(action, XYAction): p = [ None, None ] for x in (0, 1): if len(action.actions[0].strip().parameters) >= x: if len(action.actions[x].strip().parameters) > 0: p[x] = action.actions[x].strip().parameters[0] if p[0] == Axes.ABS_X and p[1] == Axes.ABS_Y: return True elif p[0] == Axes.ABS_RX and p[1] == Axes.ABS_RY: return True elif p[0] == Axes.ABS_HAT0X and p[1] == Axes.ABS_HAT0Y: return True elif p[0] == Rels.REL_HWHEEL and p[1] == Rels.REL_WHEEL: return True return False def on_area_options_changed(self, *a): if self._recursing : return action = self.make_area_action() self.editor.set_action(action) self.update_osd_area(action) for x in ('sbAreaX1', 'sbAreaX2', 'sbAreaY1', 'sbAreaY2'): spin = self.builder.get_object(x) if self.relative_area: spin.get_adjustment().set_upper(100) else: spin.get_adjustment().set_upper(1000) self.on_sbArea_output(spin) def on_sbArea_output(self, button, *a): if self.relative_area: button.set_text("%s %%" % (button.get_value())) else: button.set_text("%s px" % (int(button.get_value()))) def on_sbArea_focus_out_event(self, button, *a): GLib.idle_add(self.on_sbArea_output, button) def on_sbArea_changed(self, button, *a): self.on_sbArea_output(button) self.on_area_options_changed(button) def on_lblSetupTrackball_activate_link(self, trash, link): self.editor.on_link(link) def on_cbAxisOutput_changed(self, *a): cbAxisOutput = self.builder.get_object("cbAxisOutput") stActionData = self.builder.get_object("stActionData") key = cbAxisOutput.get_model().get_value(cbAxisOutput.get_active_iter(), 2) if key == 'area': stActionData.set_visible_child(self.builder.get_object("grArea")) action = self.make_area_action() self.update_osd_area(action) elif key == "button": stActionData.set_visible_child(self.builder.get_object("vbButton")) self.button = self.button or ButtonAction(Keys.BTN_GAMEPAD) action = self.button elif key == "circular": stActionData.set_visible_child(self.builder.get_object("grCircular")) action = self.make_circular_action() elif key == 'mouse': stActionData.set_visible_child(self.builder.get_object("vbMose")) if self.editor.friction == 0: # When switching to mouse, enable trackball by default self.editor.friction = 10 action = self.make_mouse_action() else: stActionData.set_visible_child(self.builder.get_object("nothing")) action = cbAxisOutput.get_model().get_value(cbAxisOutput.get_active_iter(), 0) action = self.parser.restart(action).parse() self.update_osd_area(None) self.editor.set_action(action)
class AxisActionComponent(AEComponent, TimerManager): GLADE = "ae/axis_action.glade" NAME = "axis_action" CTXS = Action.AC_STICK | Action.AC_PAD PRIORITY = 3 def __init__(self, app, editor): AEComponent.__init__(self, app, editor) TimerManager.__init__(self) self._recursing = False self.relative_area = False self.osd_area_instance = None self.on_wayland = False self.circular = MouseAction(Rels.REL_WHEEL) self.parser = GuiActionParser() def load(self): if self.loaded : return AEComponent.load(self) cbAreaType = self.builder.get_object("cbAreaType") cbAreaType.set_row_separator_func( lambda model, iter : model.get_value(iter, 0) == "-" ) self.on_wayland = "WAYLAND_DISPLAY" in os.environ or not isinstance(Gdk.Display.get_default(), GdkX11.X11Display) if self.on_wayland: self.builder.get_object("lblArea").set_text(_("Note: Mouse Region option is not available with Wayland-based display server")) self.builder.get_object("grArea").set_sensitive(False) # Remove options that are not applicable to currently editted input if self.editor.get_id() in STICKS: # Remove "Mouse Region", "Trackball", "Trackpad" # and "Mouse (Emulate Stick)" options when editing stick bindings cb = self.builder.get_object("cbAxisOutput") for row in cb.get_model(): if row[2] in ("wheel_pad", "area", "mouse_pad", "trackpad", "trackball"): cb.get_model().remove(row.iter) else: # Remove "Mouse" option when editing pads # (it's effectivelly same as Trackpad) cb = self.builder.get_object("cbAxisOutput") for row in cb.get_model(): if row[2] in ("wheel_stick", "mouse_stick", ): cb.get_model().remove(row.iter) def hidden(self): self.update_osd_area(None) def set_action(self, mode, action): if self.handles(mode, action): cb = self.builder.get_object("cbAxisOutput") if isinstance(action, AreaAction): self.load_area_action(action) self.set_cb(cb, "area", 2) self.update_osd_area(action) return self.update_osd_area(None) if isinstance(action, MouseAction): self.set_cb(cb, "trackpad", 2) elif isinstance(action, BallModifier): self.load_trackball_action(action) elif isinstance(action, CircularModifier): self.load_circular_action(action) elif isinstance(action, XYAction): p = [ None, None ] for x in (0, 1): if len(action.actions[0].strip().parameters) >= x: if len(action.actions[x].strip().parameters) > 0: p[x] = action.actions[x].strip().parameters[0] if p[0] == Axes.ABS_X and p[1] == Axes.ABS_Y: self.set_cb(cb, "lstick", 2) elif p[0] == Axes.ABS_RX and p[1] == Axes.ABS_RY: self.set_cb(cb, "rstick", 2) elif p[0] == Rels.REL_HWHEEL and p[1] == Rels.REL_WHEEL: self.set_cb(cb, "wheel", 2) else: self.set_cb(cb, "none", 2) def update_osd_area(self, action): """ Updates preview area displayed on screen """ if action: if self.osd_area_instance is None: if self.on_wayland: # Cannot display preview with non-X11 backends return self.osd_area_instance = Area() self.osd_area_instance.show() action.update_osd_area(self.osd_area_instance, FakeMapper(self.editor)) self.timer("area", 0.5, self.update_osd_area, action) elif self.osd_area_instance: self.osd_area_instance.quit() self.osd_area_instance = None self.cancel_timer("area") def load_circular_action(self, action): self.circular = action.action cbAxisOutput = self.builder.get_object("cbAxisOutput") btCircularAxis = self.builder.get_object("btCircularAxis") btCircularAxis.set_label(self.circular.describe(Action.AC_PAD)) self.set_cb(cbAxisOutput, "circular", 2) def load_trackball_action(self, action): cbTracballOutput = self.builder.get_object("cbTracballOutput") cbAxisOutput = self.builder.get_object("cbAxisOutput") sclFriction = self.builder.get_object("sclFriction") self._recursing = True if isinstance(action.action, MouseAction): self.set_cb(cbTracballOutput, "mouse", 1) self.set_cb(cbAxisOutput, "trackball", 2) elif isinstance(action.action, XYAction): if isinstance(action.action.x, AxisAction): if action.action.x.parameters[0] == Axes.ABS_X: self.set_cb(cbTracballOutput, "left", 1) else: self.set_cb(cbTracballOutput, "right", 1) self.set_cb(cbAxisOutput, "trackball", 2) elif isinstance(action.action.x, MouseAction): self.set_cb(cbAxisOutput, "wheel", 2) if action.friction <= 0: sclFriction.set_value(0) else: sclFriction.set_value(math.log(action.friction * 1000.0, 10)) self._recursing = False def load_area_action(self, action): """ Load AreaAction values into UI. """ cbAreaType = self.builder.get_object("cbAreaType") x1, y1, x2, y2 = action.coords self.relative_area = False if isinstance(action, RelAreaAction): key = "screensize" self.relative_area = True x1, y1, x2, y2 = x1 * 100.0, y1 * 100.0, x2 * 100.0, y2 * 100.0 elif isinstance(action, RelWinAreaAction): key = "windowsize" self.relative_area = True x1, y1, x2, y2 = x1 * 100.0, y1 * 100.0, x2 * 100.0, y2 * 100.0 else: t1 = "1" if x1 < 0 and x2 < 0 else "0" t2 = "1" if y1 < 0 and y2 < 0 else "0" x1, y1, x2, y2 = abs(x1), abs(y1), abs(x2), abs(y2) if x2 < x1 : x1, x2 = x2, x1 if y2 < y1 : y1, y2 = y2, y1 if isinstance(action, WinAreaAction): key = "window-%s%s" % (t1, t2) else: key = "screen-%s%s" % (t1, t2) self._recursing = True self.builder.get_object("sbAreaX1").set_value(x1) self.builder.get_object("sbAreaY1").set_value(y1) self.builder.get_object("sbAreaX2").set_value(x2) self.builder.get_object("sbAreaY2").set_value(y2) self.builder.get_object("cbAreaOSDEnabled").set_active(self.editor.osd) self.builder.get_object("cbAreaClickEnabled").set_active(self.pressing_pad_clicks()) for row in cbAreaType.get_model(): if key == row[1]: cbAreaType.set_active_iter(row.iter) break self._recursing = False def on_btCircularAxis_clicked(self, *a): def cb(action): self.circular = action btCircularAxis = self.builder.get_object("btCircularAxis") btCircularAxis.set_label(action.describe(Action.AC_PAD)) self.editor.set_action(self.make_circular_action()) b = SimpleChooser(self.app, "axis", cb) b.set_title(_("Select Axis")) b.display_action(Action.AC_STICK, self.circular) b.show(self.editor.window) def on_cbAreaOSDEnabled_toggled(self, *a): self.editor.builder.get_object("cbOSD").set_active( self.builder.get_object("cbAreaOSDEnabled").get_active()) def pressing_pad_clicks(self): """ Returns True if currently edited pad is set to press left mouse button when pressed. (yes, this is used somewhere) """ side = getattr(SCButtons, self.editor.get_id()) c_action = self.app.current.buttons[side] if isinstance(c_action, ButtonAction): return c_action.button == Keys.BTN_LEFT return False def on_ok(self, action): if isinstance(action.strip(), AreaAction): # Kinda hacky way to set action on LPAD press or RPAD press # when user selects Mouse Area as ouput and checks # 'Pressing the Pad Clicks' checkbox side = getattr(SCButtons, self.editor.get_id()) clicks = self.pressing_pad_clicks() if self.builder.get_object("cbAreaClickEnabled").get_active(): if not clicks: # Turn pad press into mouse clicks self.app.set_action(self.app.current, side, ButtonAction(Keys.BTN_LEFT)) else: if clicks: # Clear action created above if checkbox is uncheck self.app.set_action(self.app.current, side, NoAction()) def make_trackball_action(self): """ Loads values from UI into trackball-related action """ sclFriction = self.builder.get_object("sclFriction") cbTracballOutput = self.builder.get_object("cbTracballOutput") a_str = cbTracballOutput.get_model().get_value(cbTracballOutput.get_active_iter(), 2) a = self.parser.restart(a_str).parse() if sclFriction.get_value() <= 0: friction = 0 else: friction = ((10.0**sclFriction.get_value())/1000.0) return BallModifier(round(friction, 3), a) def make_circular_action(self): """ Constructs Circular Modifier """ return CircularModifier(self.circular) def make_area_action(self): """ Loads values from UI into new AreaAction or subclass. """ # Prepare cbAreaType = self.builder.get_object("cbAreaType") # Read numbers x1 = self.builder.get_object("sbAreaX1").get_value() y1 = self.builder.get_object("sbAreaY1").get_value() x2 = self.builder.get_object("sbAreaX2").get_value() y2 = self.builder.get_object("sbAreaY2").get_value() # Determine exact action type by looking into Area Type checkbox # (this part may seem little crazy) # ... numbers key = cbAreaType.get_model().get_value(cbAreaType.get_active_iter(), 1) if "-" in key: if key[-2] == "1": # Before-last character ius "1", that means that X coords are # counted from other side and has to be negated x1, x2 = -x1, -x2 if key[-1] == "1": # Key ends with "1". Same thing as above but for Y coordinate y1, y2 = -y1, -y2 if "size" in key: x1, y1, x2, y2 = x1 / 100.0, y1 / 100.0, x2 / 100.0, y2 / 100.0 # ... class if "window-" in key: cls = WinAreaAction self.relative_area = False elif "screensize" == key: cls = RelAreaAction self.relative_area = True elif "windowsize" == key: cls = RelWinAreaAction self.relative_area = True else: # "screen" in key cls = AreaAction self.relative_area = False if not self.relative_area: x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2) return cls(x1, y1, x2, y2) def get_button_title(self): return _("Joystick / Mouse") def handles(self, mode, action): if isinstance(action, (NoAction, MouseAction, CircularModifier, InvalidAction, AreaAction)): return True if isinstance(action, BallModifier): if isinstance(action.action, XYAction): return ( isinstance(action.action.x, (AxisAction, MouseAction)) and isinstance(action.action.x, (AxisAction, MouseAction)) ) return isinstance(action.action, MouseAction) if isinstance(action, XYAction): p = [ None, None ] for x in (0, 1): if len(action.actions[0].strip().parameters) >= x: if len(action.actions[x].strip().parameters) > 0: p[x] = action.actions[x].strip().parameters[0] if p[0] == Axes.ABS_X and p[1] == Axes.ABS_Y: return True elif p[0] == Axes.ABS_RX and p[1] == Axes.ABS_RY: return True elif p[0] == Axes.ABS_HAT0X and p[1] == Axes.ABS_HAT0Y: return True elif p[0] == Rels.REL_HWHEEL and p[1] == Rels.REL_WHEEL: return True return False def on_area_options_changed(self, *a): if self._recursing : return action = self.make_area_action() self.editor.set_action(action) self.update_osd_area(action) for x in ('sbAreaX1', 'sbAreaX2', 'sbAreaY1', 'sbAreaY2'): spin = self.builder.get_object(x) if self.relative_area: spin.get_adjustment().set_upper(100) else: spin.get_adjustment().set_upper(1000) self.on_sbArea_output(spin) def on_trackball_options_changed(self, *a): if self._recursing : return action = self.make_trackball_action() self.editor.set_action(action) def on_sbArea_output(self, button, *a): if self.relative_area: button.set_text("%s %%" % (button.get_value())) else: button.set_text("%s px" % (int(button.get_value()))) def on_sbArea_focus_out_event(self, button, *a): GLib.idle_add(self.on_sbArea_output, button) def on_sbArea_changed(self, button, *a): self.on_sbArea_output(button) self.on_area_options_changed(button) def on_btClearFriction_clicked(self, *a): sclFriction = self.builder.get_object("sclFriction") sclFriction.set_value(math.log(10 * 1000.0, 10)) def on_sclFriction_format_value(self, scale, value): if value <= 0: return "0.000" elif value >= 6: return "1000.00" else: return "%0.3f" % ((10.0**value)/1000.0) def on_cbAxisOutput_changed(self, *a): cbAxisOutput = self.builder.get_object("cbAxisOutput") stActionData = self.builder.get_object("stActionData") key = cbAxisOutput.get_model().get_value(cbAxisOutput.get_active_iter(), 2) if key == 'area': stActionData.set_visible_child(self.builder.get_object("grArea")) action = self.make_area_action() self.update_osd_area(action) elif key == "circular": stActionData.set_visible_child(self.builder.get_object("vbCircular")) action = self.make_circular_action() elif key == 'trackball': stActionData.set_visible_child(self.builder.get_object("vbTrackball")) action = self.make_trackball_action() else: stActionData.set_visible_child(self.builder.get_object("nothing")) action = cbAxisOutput.get_model().get_value(cbAxisOutput.get_active_iter(), 0) action = self.parser.restart(action).parse() self.update_osd_area(None) self.editor.set_action(action)
def on_unknown_message(self, daemon, message): if not message.startswith("OSD:"): return if message.startswith("OSD: message"): args = shsplit(message)[1:] m = Message() m.parse_argumets(args) hsh = m.hash() if hsh in self._visible_messages: self._visible_messages[hsh].extend() m.destroy() else: # TODO: Do this only for default position once changing # TODO: is allowed if len(self._visible_messages): height = self._visible_messages.values()[0].get_size().height x, y = m.position while y in [ i.position[1] for i in self._visible_messages.values() ]: y -= height + 5 m.position = x, y m.show() self._visible_messages[hsh] = m m.connect("destroy", self.on_message_closed) elif message.startswith("OSD: keyboard"): if self._window: log.warning("Another OSD is already visible - refusing to show keyboard") else: args = shsplit(message)[1:] self._window = Keyboard(self.config) self._window.connect('destroy', self.on_keyboard_closed) self._window.parse_argumets(args) self._window.show() self._window.use_daemon(self.daemon) elif message.startswith("OSD: gesture"): if self._window: log.warning("Another OSD is already visible - refusing to show keyboard") else: args = shsplit(message)[1:] self._window = GestureDisplay(self.config) self._window.parse_argumets(args) self._window.use_daemon(self.daemon) self._window.show() self._window.connect('destroy', self.on_gesture_recognized) elif self._is_menu_message(message): args = shsplit(message)[1:] if self._window: log.warning("Another OSD is already visible - refusing to show menu") else: if message.startswith("OSD: hmenu"): self._window = HorizontalMenu() elif message.startswith("OSD: radialmenu"): self._window = RadialMenu() elif message.startswith("OSD: quickmenu"): self._window = QuickMenu() elif message.startswith("OSD: gridmenu"): self._window = GridMenu() elif message.startswith("OSD: dialog"): self._window = Dialog() else: self._window = Menu() self._window.connect('destroy', self.on_menu_closed) self._window.use_config(self.config) try: if self._window.parse_argumets(args): self._window.show() self._window.use_daemon(self.daemon) else: log.error("Failed to show menu") self._window = None except: log.error(traceback.format_exc()) log.error("Failed to show menu") self._window = None elif message.startswith("OSD: area"): args = shsplit(message)[1:] if self._window: log.warning("Another OSD is already visible - refusing to show area") else: args = shsplit(message)[1:] self._window = Area() self._window.connect('destroy', self.on_keyboard_closed) if self._window.parse_argumets(args): self._window.show() else: self._window.quit() self._window = None elif message.startswith("OSD: clear"): # Clears active OSD windows self.clear_windows() else: log.warning("Unknown command from daemon: '%s'", message)