def __init__(self, *args, **kwargs): kwargs['type'] = Gtk.WindowType.POPUP super(Gtk.ApplicationWindow, self).__init__(*args, **kwargs) self.app = kwargs['application'] self.seat = Gdk.Display.get_default().get_default_seat() self.set_size_request(-1, -1) self.set_keep_above(True) self.set_resizable(False) self.set_type_hint(Gdk.WindowTypeHint.UTILITY) self.set_position(Gtk.WindowPosition.CENTER) self.set_custom_position() self.set_skip_pager_hint(True) self.set_skip_taskbar_hint(True) self.set_destroy_with_parent(True) self.my_menu_bar = Gtk.MenuBar() self.accel_group = Gtk.AccelGroup() self.main_box = Gtk.VBox() self.main_box.add(self.my_menu_bar) self.add(self.main_box) # self.set_dark_variation() self.set_custom_styles() Gdk.event_handler_set(self.on_gdk_event) self.connect('show', self.on_window_show) self.connect('button-press-event', self.on_button_press_event)
def __init__(self, *args, **kwargs): if backend == 'x11': kwargs['type'] = Gtk.WindowType.POPUP super(Gtk.ApplicationWindow, self).__init__(*args, **kwargs) self.set_size_request(750, -1) self.set_keep_above(True) self.set_resizable(False) self.set_type_hint(Gdk.WindowTypeHint.UTILITY) self.set_position(Gtk.WindowPosition.CENTER) self.set_custom_position() self.set_skip_pager_hint(True) self.set_skip_taskbar_hint(True) self.set_destroy_with_parent(True) self.empty_label = Gtk.Label(margin=12) self.empty_label.set_label('No menu actions available!') self.empty_box = Gtk.Box(sensitive=False) self.empty_box.set_size_request(750, -1) self.empty_box.add(self.empty_label) self.command_list = CommandList() self.command_list.invalidate_selection() self.search_entry = Gtk.SearchEntry(hexpand=True, margin=2) self.search_entry.connect('search-changed', self.on_search_entry_changed) self.search_entry.set_has_frame(False) self.scrolled_window = Gtk.ScrolledWindow(hadjustment=None, vadjustment=None) self.scrolled_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.scrolled_window.set_size_request(750, 210) self.scrolled_window.add(self.command_list) self.header_bar = Gtk.HeaderBar(spacing=0) self.header_bar.set_custom_title(self.search_entry) self.main_box = Gtk.Box() self.main_box.add(self.empty_box) self.main_box.add(self.scrolled_window) self.set_titlebar(self.header_bar) self.add(self.main_box) self.set_dark_variation() self.set_custom_styles() Gdk.event_handler_set(self.on_gdk_event) self.connect('show', self.on_window_show) self.connect('button-press-event', self.on_button_press_event)
def _setup_gtk(self): from gi.repository import Gtk, Gdk from kiwi.environ import environ from stoqlib.lib.template import render_template_string # Total madness to make sure we can draw treeview lines, # this affects the GtkTreeView::grid-line-pattern style property # # Two bytes are sent in, see gtk_tree_view_set_grid_lines in gtktreeview.c # Byte 1 should be as high as possible, gtk+ 0x7F appears to be # the highest allowed for Gtk+ 2.22 while 0xFF worked in # earlier versions # Byte 2 should ideally be allowed to be 0, but neither C nor Python # allows that. # data = environ.get_resource_string("stoq", "misc", "stoq.css") data = render_template_string(data) style_provider = Gtk.CssProvider() style_provider.load_from_data(data) Gtk.StyleContext.add_provider_for_screen( Gdk.Screen.get_default(), style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) settings = Gtk.Settings.get_default() settings.props.gtk_button_images = True from stoqlib.lib.environment import is_developer_mode if is_developer_mode(): # Install a Control-Q handler that forcefully exits # the program without saving any kind of state def event_handler(event): state = event.get_state() if isinstance(state, tuple): state = state[1] if (event.type == Gdk.EventType.KEY_PRESS and state & Gdk.ModifierType.CONTROL_MASK and event.keyval == Gdk.KEY_q): os._exit(0) Gtk.main_do_event(event) Gdk.event_handler_set(event_handler)
def _init_delayed(self): # Release pressed keys when onboard is killed. # Don't keep enter key stuck when being killed by lightdm. self._osk_util = osk.Util() self._osk_util.set_unix_signal_handler(signal.SIGTERM, self.on_sigterm) self._osk_util.set_unix_signal_handler(signal.SIGINT, self.on_sigint) sys.path.append(os.path.join(config.install_dir, 'scripts')) # Create the central keyboard model self.keyboard = Keyboard(self) # Create the initial keyboard widget # Care for toolkit independence only once there is another # supported one besides GTK. self.keyboard_widget = KeyboardWidget(self.keyboard) # create the main window if config.xid_mode: # XEmbed mode for gnome-screensaver? # no icp, don't flash the icon palette in lightdm self._window = KbdPlugWindow(self.keyboard_widget) # write xid to stdout sys.stdout.write('%d\n' % self._window.get_id()) sys.stdout.flush() else: icp = IconPalette(self.keyboard) icp.set_layout_view(self.keyboard_widget) icp.connect("activated", self._on_icon_palette_acticated) self.do_connect(icp.get_menu(), "quit-onboard", lambda x: self.do_quit_onboard()) self._window = KbdWindow(self.keyboard_widget, icp) self.do_connect(self._window, "quit-onboard", lambda x: self.do_quit_onboard()) # config.xid_mode = True self._window.application = self # need this to access screen properties config.main_window = self._window # load the initial layout _logger.info("Loading initial layout") self.reload_layout() # Handle command line options x, y, size after window creation # because the rotation code needs the window's screen. if not config.xid_mode: rect = self._window.get_rect().copy() options = config.options if options.size: size = options.size.split("x") rect.w = int(size[0]) rect.h = int(size[1]) if options.x is not None: rect.x = options.x if options.y is not None: rect.y = options.y # Make sure the keyboard fits on screen rect = self._window.limit_size(rect) if not rect.is_empty() and \ rect != self._window.get_rect(): _logger.debug("limiting window size: {} to {}" .format(self._window.get_rect(), rect)) orientation = self._window.get_screen_orientation() self._window.write_window_rect(orientation, rect) self._window.restore_window_rect() # move/resize early else: _logger.debug("not limiting window size: {} to {}" .format(self._window.get_rect(), rect)) # export dbus service if not config.xid_mode and \ has_dbus: self.service_keyboard = ServiceOnboardKeyboard(self) # show/hide the window self.keyboard_widget.set_startup_visibility() # keep keyboard window and icon palette on top of dash self._keep_windows_on_top() # connect notifications for keyboard map and group changes self.keymap = Gdk.Keymap.get_default() # map changes self.do_connect(self.keymap, "keys-changed", self.cb_keys_changed) self.do_connect(self.keymap, "state-changed", self.cb_state_changed) # group changes Gdk.event_handler_set(cb_any_event, self) # connect config notifications here to keep config from holding # references to keyboard objects. once = CallOnce(50).enqueue # delay callbacks by 50ms reload_layout = lambda x: once(self.reload_layout_and_present) update_ui = lambda x: once(self._update_ui) update_ui_no_resize = lambda x: once(self._update_ui_no_resize) update_transparency = \ lambda x: once(self.keyboard_widget.update_transparency) update_inactive_transparency = \ lambda x: once(self.keyboard_widget.update_inactive_transparency) # general # keyboard config.keyboard.key_synth_notify_add(reload_layout) config.keyboard.input_event_source_notify_add(lambda x: self.keyboard.update_input_event_source()) config.keyboard.touch_input_notify_add(lambda x: self.keyboard.update_touch_input_mode()) config.keyboard.show_secondary_labels_notify_add(update_ui) # window config.window.window_state_sticky_notify_add( lambda x: self._window.update_sticky_state()) config.window.window_decoration_notify_add( self._on_window_options_changed) config.window.force_to_top_notify_add(self._on_window_options_changed) config.window.keep_aspect_ratio_notify_add(update_ui) config.window.transparency_notify_add(update_transparency) config.window.background_transparency_notify_add(update_transparency) config.window.transparent_background_notify_add(update_ui) config.window.enable_inactive_transparency_notify_add(update_transparency) config.window.inactive_transparency_notify_add(update_inactive_transparency) config.window.docking_notify_add(self._update_docking) config.window.docking_aspect_change_range_notify_add( lambda x: self.keyboard_widget .update_docking_aspect_change_range()) # layout config.layout_filename_notify_add(reload_layout) # theme # config.gdi.gtk_theme_notify_add(self.on_gtk_theme_changed) config.theme_notify_add(self.on_theme_changed) config.key_label_font_notify_add(reload_layout) config.key_label_overrides_notify_add(reload_layout) config.theme_settings.color_scheme_filename_notify_add(reload_layout) config.theme_settings.key_label_font_notify_add(reload_layout) config.theme_settings.key_label_overrides_notify_add(reload_layout) config.theme_settings.theme_attributes_notify_add(update_ui) # snippets config.snippets_notify_add(reload_layout) # auto-show config.auto_show.enabled_notify_add( lambda x: self.keyboard.update_auto_show()) config.auto_show.hide_on_key_press_notify_add( lambda x: self.keyboard.update_auto_hide()) config.auto_show.tablet_mode_detection_notify_add( lambda x: self.keyboard.update_tablet_mode_detection()) config.auto_show.keyboard_device_detection_enabled_notify_add( lambda x: self.keyboard.update_keyboard_device_detection()) # word suggestions config.word_suggestions.show_context_line_notify_add(update_ui) config.word_suggestions.enabled_notify_add(lambda x: self.keyboard.on_word_suggestions_enabled(x)) config.word_suggestions.auto_learn_notify_add( update_ui_no_resize) config.typing_assistance.active_language_notify_add(lambda x: \ self.keyboard.on_active_lang_id_changed()) config.typing_assistance.spell_check_backend_notify_add(lambda x: \ self.keyboard.on_spell_checker_changed()) config.typing_assistance.auto_capitalization_notify_add(lambda x: \ self.keyboard.on_word_suggestions_enabled(x)) config.word_suggestions.spelling_suggestions_enabled_notify_add(lambda x: \ self.keyboard.on_spell_checker_changed()) config.word_suggestions.delayed_word_separators_enabled_notify_add(lambda x: \ self.keyboard.on_punctuator_changed()) config.word_suggestions.wordlist_buttons_notify_add( update_ui_no_resize) # universal access config.scanner.enabled_notify_add(self.keyboard._on_scanner_enabled) config.window.window_handles_notify_add(self._on_window_handles_changed) # misc config.keyboard.show_click_buttons_notify_add(update_ui) config.lockdown.lockdown_notify_add(update_ui) if config.mousetweaks: config.mousetweaks.state_notify_add(update_ui_no_resize) # create status icon self.status_icon = Indicator() self.status_icon.set_keyboard(self.keyboard) self.do_connect(self.status_icon.get_menu(), "quit-onboard", lambda x: self.do_quit_onboard()) # Callbacks to use when icp or status icon is toggled config.show_status_icon_notify_add(self.show_hide_status_icon) config.icp.in_use_notify_add(self.cb_icp_in_use_toggled) self.show_hide_status_icon(config.show_status_icon) # Minimize to IconPalette if running under GDM if 'RUNNING_UNDER_GDM' in os.environ: _logger.info("RUNNING_UNDER_GDM set, turning on icon palette") config.icp.in_use = True _logger.info("RUNNING_UNDER_GDM set, turning off indicator") config.show_status_icon = False # For some reason the new values don't arrive in gsettings when # running the unit test "test_running_in_live_cd_environment". # -> Force gsettings to apply them, that seems to do the trick. config.icp.apply() config.apply() # unity-2d needs the skip-task-bar hint set before the first mapping. self.show_hide_taskbar() # Check gnome-screen-saver integration # onboard_xembed_enabled False True True True # config.gss.embedded_keyboard_enabled any False any False # config.gss.embedded_keyboard_command any empty !=onboard ==onboard # Action: nop enable Question1 Question2 # silently if not config.xid_mode and \ config.onboard_xembed_enabled: # If it appears, that nothing has touched the gss keys before, # silently enable gss integration with onboard. if not config.gss.embedded_keyboard_enabled and \ not config.gss.embedded_keyboard_command: config.enable_gss_embedding(True) # If onboard is configured to be embedded into the unlock screen # dialog, and the embedding command is different from onboard, ask # the user what to do elif not config.is_onboard_in_xembed_command_string(): question = _("Onboard is configured to appear with the dialog to " "unlock the screen; for example to dismiss the " "password-protected screensaver.\n\n" "However the system is not configured anymore to use " "Onboard to unlock the screen. A possible reason can " "be that another application configured the system to " "use something else.\n\n" "Would you like to reconfigure the system to show " "Onboard when unlocking the screen?") _logger.warning("showing dialog: '{}'".format(question)) reply = show_confirmation_dialog(question, self._window, config.is_force_to_top()) if reply == True: config.enable_gss_embedding(True) else: config.onboard_xembed_enabled = False else: if not config.gss.embedded_keyboard_enabled: question = _("Onboard is configured to appear with the dialog " "to unlock the screen; for example to dismiss " "the password-protected screensaver.\n\n" "However this function is disabled in the system.\n\n" "Would you like to activate it?") _logger.warning("showing dialog: '{}'".format(question)) reply = show_confirmation_dialog(question, self._window, config.is_force_to_top()) if reply == True: config.enable_gss_embedding(True) else: config.onboard_xembed_enabled = False # check if gnome accessibility is enabled for auto-show if (config.is_auto_show_enabled() or \ config.are_word_suggestions_enabled()) and \ not config.check_gnome_accessibility(self._window): config.auto_show.enabled = False
def register_event_handler(self): if not Gdk.event_handler_set: raise NotImplementedError Gdk.event_handler_set(self._event_handler)
def __init__(self, open_path: list = None): super().__init__(type=Gtk.WindowType.TOPLEVEL) # ---------------------------------------------------------------- # Attributes # ---------------------------------------------------------------- # Load configuration. self.__preference_manager = PreferenceManager() self.__preference_manager.load_config_file() self.bookmark_backend = BookmarkBackend() # Used to detect window fullscreen state transitions. self.was_fullscreen = False self.is_manga_mode = config['DEFAULT_MANGA_MODE'] self.__page_orientation = self.page_orientation() self.previous_size = (None, None) # Remember last scroll destination. self.__last_scroll_destination = Constants.SCROLL_TO['START'] self.__dummy_layout = FiniteLayout([(1, 1)], (1, 1), [1, 1], 0, 0, 0) self.__layout = self.__dummy_layout self.__spacing = 2 self.__waiting_for_redraw = False self.__main_layout = Gtk.Layout() self.__main_scrolled_window = Gtk.ScrolledWindow() self.__main_scrolled_window.add(self.__main_layout) self.event_handler = EventHandler(self) self.__vadjust = self.__main_scrolled_window.get_vadjustment() self.__hadjust = self.__main_scrolled_window.get_hadjustment() self.icons = Icons() self.filehandler = FileHandler(self) self.filehandler.file_closed += self._on_file_closed self.filehandler.file_opened += self._on_file_opened self.imagehandler = ImageHandler(self) self.imagehandler.page_available += self._page_available self.thumbnailsidebar = ThumbnailSidebar(self) self.statusbar = Statusbar() self.cursor_handler = CursorHandler(self) self.enhancer = ImageEnhancer(self) self.lens = MagnifyingLens(self) self.zoom = ZoomModel() self.menubar = Menubar(self) self.keybindings_map = KeyBindingsMap(self).BINDINGS self.keybindings = KeybindingManager(self) self.images = [Gtk.Image(), Gtk.Image()] # XXX limited to at most 2 pages # ---------------------------------------------------------------- # Setup # ---------------------------------------------------------------- self.set_title(Constants.APPNAME) self.restore_window_geometry() # Hook up keyboard shortcuts self.event_handler.event_handler_init() self.event_handler.register_key_events() for img in self.images: self.__main_layout.put(img, 0, 0) grid = Gtk.Grid() grid.attach(self.menubar, 0, 0, 2, 1) grid.attach(self.thumbnailsidebar, 0, 1, 1, 1) grid.attach_next_to(self.__main_scrolled_window, self.thumbnailsidebar, Gtk.PositionType.RIGHT, 1, 1) self.__main_scrolled_window.set_hexpand(True) self.__main_scrolled_window.set_vexpand(True) grid.attach(self.statusbar, 0, 2, 2, 1) self.add(grid) self.change_zoom_mode() if not config['KEEP_TRANSFORMATION']: config['ROTATION'] = 0 config['VERTICAL_FLIP'] = False config['HORIZONTAL_FLIP'] = False # Each widget "eats" part of the main layout visible area. self.__toggle_axis = { self.thumbnailsidebar: Constants.AXIS['WIDTH'], self.statusbar: Constants.AXIS['HEIGHT'], self.menubar: Constants.AXIS['HEIGHT'], } self.__main_layout.set_events(Gdk.EventMask.BUTTON1_MOTION_MASK | Gdk.EventMask.BUTTON2_MOTION_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK) self.__main_layout.drag_dest_set( Gtk.DestDefaults.ALL, [Gtk.TargetEntry.new('text/uri-list', 0, 0)], Gdk.DragAction.COPY | Gdk.DragAction.MOVE) self.connect('delete_event', self.terminate_program) self.connect('key_press_event', self.event_handler.key_press_event) self.connect('configure_event', self.event_handler.resize_event) self.connect('window-state-event', self.event_handler.window_state_event) self.__main_layout.connect('button_release_event', self.event_handler.mouse_release_event) self.__main_layout.connect('scroll_event', self.event_handler.scroll_wheel_event) self.__main_layout.connect('button_press_event', self.event_handler.mouse_press_event) self.__main_layout.connect('motion_notify_event', self.event_handler.mouse_move_event) self.__main_layout.connect('drag_data_received', self.event_handler.drag_n_drop_event) self.show_all() if open_path: self.filehandler.initialize_fileprovider(path=open_path) self.filehandler.open_file(Path(open_path[0])) if config['HIDE_CURSOR']: self.cursor_handler.auto_hide_on() # Make sure we receive *all* mouse motion events, # even if a modal dialog is being shown. def _on_event(event): if Gdk.EventType.MOTION_NOTIFY == event.type: self.cursor_handler.refresh() Gtk.main_do_event(event) Gdk.event_handler_set(_on_event)
def init(self): self.keyboard_state = None self.vk_timer = None self.reset_vk() self._connections = [] self._window = None self.status_icon = None # finish config initialization config.init() sys.path.append(os.path.join(config.install_dir, 'scripts')) # load the initial layout _logger.info("Loading initial layout") self.reload_layout() # create the main window if config.xid_mode: # XEmbed mode for gnome-screensaver? self._window = KbdPlugWindow() # write xid to stdout sys.stdout.write('%d\n' % self._window.get_id()) sys.stdout.flush() else: self._window = KbdWindow() self.do_connect(self._window, "quit-onboard", lambda x: self.do_quit_onboard()) self._window.application = self self._window.set_keyboard(self.keyboard) # Handle command line options x, y, size after window creation # because the rotation code needs the window's screen. if not config.xid_mode: rect = self._window.get_rect().copy() options = config.options if options.size: size = options.size.split("x") rect.w = int(size[0]) rect.h = int(size[1]) if not options.x is None: rect.x = options.x if not options.y is None: rect.y = options.y if rect != self._window.get_rect(): orientation = self._window.get_screen_orientation() self._window.write_window_rect(orientation, rect) self._window.restore_window_rect() # move/resize early # show/hide the window self.keyboard.set_startup_visibility() # connect notifications for keyboard map and group changes self.keymap = Gdk.Keymap.get_default() self.do_connect(self.keymap, "keys-changed", self.cb_keys_changed) # map changes Gdk.event_handler_set(cb_any_event, self) # group changes # connect config notifications here to keep config from holding # references to keyboard objects. once = CallOnce(50).enqueue # delay callbacks by 50ms reload_layout = lambda x: once(self.reload_layout_and_present) update_ui = lambda x: once(self._update_ui) redraw = lambda x: once(self.keyboard.redraw) update_transparency = lambda x: once(self.keyboard.update_transparency) update_inactive_transparency = \ lambda x: once(self.keyboard.update_inactive_transparency) # general config.auto_show.enabled_notify_add(lambda x: \ self.keyboard.update_auto_show()) # window config.window.window_state_sticky_notify_add(lambda x: \ self._window.update_sticky_state()) config.window.window_decoration_notify_add(self._update_window_options) config.window.force_to_top_notify_add(self._update_window_options) config.window.keep_aspect_ratio_notify_add(update_ui) config.window.transparency_notify_add(update_transparency) config.window.background_transparency_notify_add(update_transparency) config.window.transparent_background_notify_add(update_ui) config.window.enable_inactive_transparency_notify_add(update_transparency) config.window.inactive_transparency_notify_add(update_inactive_transparency) # layout config.layout_filename_notify_add(reload_layout) # theme #config.gdi.gtk_theme_notify_add(self.on_gtk_theme_changed) config.theme_notify_add(self.on_theme_changed) config.key_label_font_notify_add(reload_layout) config.key_label_overrides_notify_add(reload_layout) config.theme_settings.color_scheme_filename_notify_add(reload_layout) config.theme_settings.key_label_font_notify_add(reload_layout) config.theme_settings.key_label_overrides_notify_add(reload_layout) config.theme_settings.key_size_notify_add(update_ui) # for label size config.theme_settings.theme_attributes_notify_add(redraw) # snippets config.snippets_notify_add(reload_layout) # universal access config.scanner.enabled_notify_add(self.keyboard._on_scanner_enabled) GObject.idle_add(self.keyboard.enable_scanner, config.scanner.enabled) config.window.resize_handles_notify_add(lambda x: \ self.keyboard.update_resize_handles()) # misc config.keyboard.show_click_buttons_notify_add(update_ui) config.lockdown.lockdown_notify_add(update_ui) config.clickmapper.state_notify_add(update_ui) if config.mousetweaks: config.mousetweaks.state_notify_add(update_ui) # create status icon # Indicator is a singleton to allow recreating the keyboard # window on changes to the "force_to_top" setting. self.status_icon = Indicator() self.status_icon.set_keyboard_window(self._window) self.do_connect(self.status_icon, "quit-onboard", lambda x: self.do_quit_onboard()) # Callbacks to use when icp or status icon is toggled config.show_status_icon_notify_add(self.show_hide_status_icon) config.icp.in_use_notify_add(self.cb_icp_in_use_toggled) self.show_hide_status_icon(config.show_status_icon) # Minimize to IconPalette if running under GDM if 'RUNNING_UNDER_GDM' in os.environ: config.icp.in_use = True config.show_status_icon = False # unity-2d needs the skip-task-bar hint set before the first mapping. self.show_hide_taskbar() # Check gnome-screen-saver integration # onboard_xembed_enabled False True True True # config.gss.embedded_keyboard_enabled any False any False # config.gss.embedded_keyboard_command any empty !=onboard ==onboard # Action: nop enable Question1 Question2 # silently if not config.xid_mode and \ config.onboard_xembed_enabled: # If it appears, that nothing has touched the gss keys before, # silently enable gss integration with onboard. if not config.gss.embedded_keyboard_enabled and \ not config.gss.embedded_keyboard_command: config.enable_gss_embedding(True) # If onboard is configured to be embedded into the unlock screen # dialog, and the embedding command is different from onboard, ask # the user what to do elif not config.is_onboard_in_xembed_command_string(): question = _("Onboard is configured to appear with the dialog to " "unlock the screen; for example to dismiss the " "password-protected screensaver.\n\n" "However the system is not configured anymore to use " "Onboard to unlock the screen. A possible reason can " "be that another application configured the system to " "use something else.\n\n" "Would you like to reconfigure the system to show " "Onboard when unlocking the screen?") reply = show_confirmation_dialog(question) if reply == True: config.enable_gss_embedding(True) else: config.onboard_xembed_enabled = False else: if not config.gss.embedded_keyboard_enabled: question = _("Onboard is configured to appear with the dialog " "to unlock the screen; for example to dismiss " "the password-protected screensaver.\n\n" "However this function is disabled in the system.\n\n" "Would you like to activate it?") reply = show_confirmation_dialog(question) if reply == True: config.enable_gss_embedding(True) else: config.onboard_xembed_enabled = False # check if gnome accessibility is enabled for auto-show if config.auto_show.enabled and \ not config.check_gnome_accessibility(self._window): config.auto_show.enabled = False
def __init__(self, filename=None, selection=False, xid=None, delay=None, selection_delay=250, countdown=False, use_clipboard=False, command=None, record=False): super(Escrotum, self).__init__(type=gtk.WindowType.POPUP) self.started = False gdk.event_handler_set(self.event_handler) self.command = command self.clipboard_owner = None self.use_clipboard = use_clipboard screen = self.get_screen() self.display = gdk.Display.get_default() self.visual = screen.get_rgba_visual() self.rgba_support = False if (self.visual is not None and screen.is_composited()): self.rgba_support = True self.set_visual(self.visual) self.filename = filename if not filename: ext = "webm" if record else "png" self.filename = f"%Y-%m-%d-%H%M%S_$wx$h_escrotum.{ext}" if record and not self.filename.endswith(".webm"): print("Video recording only supports webm") exit(EXIT_FFMPEG_ERROR) self.delay = delay self.selection_delay = selection_delay self.selection = selection self.xid = xid self.countdown = countdown self.record = record if not xid: self.root = gdk.get_default_root_window() else: self.root = get_window_from_xid(xid) self.root.show() self.x = self.y = 0 self.start_x = self.start_y = 0 self.height = self.width = 0 self.set_app_paintable(True) self.set_keep_above(True) self.connect("draw", self.on_expose) if delay: if countdown: sys.stdout.write("Taking shot in ..%s" % delay) sys.stdout.flush() glib.timeout_add(1000, self.start) else: self.start() self.painted = False
def init(self): self.keyboard_state = None self.vk_timer = None self.reset_vk() self._connections = [] self._window = None self.status_icon = None self.service_keyboard = None self._reload_layout_timer = Timer() # finish config initialization config.init() # Release pressed keys when onboard is killed. # Don't keep enter key stuck when being killed by lightdm. self._osk_util = osk.Util() self._osk_util.set_unix_signal_handler(signal.SIGTERM, self.on_sigterm) self._osk_util.set_unix_signal_handler(signal.SIGINT, self.on_sigint) sys.path.append(os.path.join(config.install_dir, 'scripts')) # Create the central keyboard model self.keyboard = Keyboard(self) # Create the initial keyboard widget # Care for toolkit independence only once there is another # supported one besides GTK. self.keyboard_widget = KeyboardWidget(self.keyboard) # create the main window if config.xid_mode: # XEmbed mode for gnome-screensaver? # no icp, don't flash the icon palette in lightdm self._window = KbdPlugWindow(self.keyboard_widget) # write xid to stdout sys.stdout.write('%d\n' % self._window.get_id()) sys.stdout.flush() else: icp = IconPalette(self.keyboard) icp.set_layout_view(self.keyboard_widget) icp.connect("activated", self._on_icon_palette_acticated) self.do_connect(icp.get_menu(), "quit-onboard", lambda x: self.do_quit_onboard()) self._window = KbdWindow(self.keyboard_widget, icp) self.do_connect(self._window, "quit-onboard", lambda x: self.do_quit_onboard()) # config.xid_mode = True self._window.application = self # need this to access screen properties config.main_window = self._window # load the initial layout _logger.info("Loading initial layout") self.reload_layout() # Handle command line options x, y, size after window creation # because the rotation code needs the window's screen. if not config.xid_mode: rect = self._window.get_rect().copy() options = config.options if options.size: size = options.size.split("x") rect.w = int(size[0]) rect.h = int(size[1]) if options.x is not None: rect.x = options.x if options.y is not None: rect.y = options.y # Make sure the keyboard fits on screen rect = self._window.limit_size(rect) if rect != self._window.get_rect(): orientation = self._window.get_screen_orientation() self._window.write_window_rect(orientation, rect) self._window.restore_window_rect() # move/resize early # export dbus service if not config.xid_mode and \ "dbus" in globals(): self.service_keyboard = ServiceOnboardKeyboard(self) # show/hide the window self.keyboard_widget.set_startup_visibility() # keep keyboard window and icon palette on top of dash self._keep_windows_on_top() # connect notifications for keyboard map and group changes self.keymap = Gdk.Keymap.get_default() # map changes self.do_connect(self.keymap, "keys-changed", self.cb_keys_changed) self.do_connect(self.keymap, "state-changed", self.cb_state_changed) # group changes Gdk.event_handler_set(cb_any_event, self) # connect config notifications here to keep config from holding # references to keyboard objects. once = CallOnce(50).enqueue # delay callbacks by 50ms reload_layout = lambda x: once(self.reload_layout_and_present) update_ui = lambda x: once(self._update_ui) update_ui_no_resize = lambda x: once(self._update_ui_no_resize) update_transparency = \ lambda x: once(self.keyboard_widget.update_transparency) update_inactive_transparency = \ lambda x: once(self.keyboard_widget.update_inactive_transparency) # general config.auto_show.enabled_notify_add(lambda x: self.keyboard.update_auto_show()) config.auto_show.hide_on_key_press_notify_add(lambda x: self.keyboard.update_auto_hide()) # keyboard config.keyboard.key_synth_notify_add(reload_layout) config.keyboard.input_event_source_notify_add(lambda x: self.keyboard.update_input_event_source()) config.keyboard.touch_input_notify_add(lambda x: self.keyboard.update_touch_input_mode()) config.keyboard.show_secondary_labels_notify_add(update_ui) # window config.window.window_state_sticky_notify_add( lambda x: self._window.update_sticky_state()) config.window.window_decoration_notify_add( self._on_window_options_changed) config.window.force_to_top_notify_add(self._on_window_options_changed) config.window.keep_aspect_ratio_notify_add(update_ui) config.window.transparency_notify_add(update_transparency) config.window.background_transparency_notify_add(update_transparency) config.window.transparent_background_notify_add(update_ui) config.window.enable_inactive_transparency_notify_add(update_transparency) config.window.inactive_transparency_notify_add(update_inactive_transparency) config.window.docking_notify_add(self._update_docking) # layout config.layout_filename_notify_add(reload_layout) # theme # config.gdi.gtk_theme_notify_add(self.on_gtk_theme_changed) config.theme_notify_add(self.on_theme_changed) config.key_label_font_notify_add(reload_layout) config.key_label_overrides_notify_add(reload_layout) config.theme_settings.color_scheme_filename_notify_add(reload_layout) config.theme_settings.key_label_font_notify_add(reload_layout) config.theme_settings.key_label_overrides_notify_add(reload_layout) config.theme_settings.theme_attributes_notify_add(update_ui) # snippets config.snippets_notify_add(reload_layout) # word suggestions config.word_suggestions.show_context_line_notify_add(update_ui) config.word_suggestions.enabled_notify_add(lambda x: self.keyboard.on_word_suggestions_enabled(x)) config.word_suggestions.auto_learn_notify_add( update_ui_no_resize) config.typing_assistance.active_language_notify_add(lambda x: \ self.keyboard.on_active_lang_id_changed()) config.typing_assistance.spell_check_backend_notify_add(lambda x: \ self.keyboard.on_spell_checker_changed()) config.typing_assistance.auto_capitalization_notify_add(lambda x: \ self.keyboard.on_word_suggestions_enabled(x)) config.word_suggestions.spelling_suggestions_enabled_notify_add(lambda x: \ self.keyboard.on_spell_checker_changed()) config.word_suggestions.delayed_word_separators_enabled_notify_add(lambda x: \ self.keyboard.on_punctuator_changed()) config.word_suggestions.wordlist_buttons_notify_add( update_ui_no_resize) # universal access config.scanner.enabled_notify_add(self.keyboard._on_scanner_enabled) config.window.window_handles_notify_add(self._on_window_handles_changed) # misc config.keyboard.show_click_buttons_notify_add(update_ui) config.lockdown.lockdown_notify_add(update_ui) if config.mousetweaks: config.mousetweaks.state_notify_add(update_ui_no_resize) # create status icon self.status_icon = Indicator() self.status_icon.set_keyboard(self.keyboard) self.do_connect(self.status_icon.get_menu(), "quit-onboard", lambda x: self.do_quit_onboard()) # Callbacks to use when icp or status icon is toggled config.show_status_icon_notify_add(self.show_hide_status_icon) config.icp.in_use_notify_add(self.cb_icp_in_use_toggled) self.show_hide_status_icon(config.show_status_icon) # Minimize to IconPalette if running under GDM if 'RUNNING_UNDER_GDM' in os.environ: _logger.info("RUNNING_UNDER_GDM set, turning on icon palette") config.icp.in_use = True _logger.info("RUNNING_UNDER_GDM set, turning off indicator") config.show_status_icon = False # For some reason the new values don't arrive in gsettings when # running the unit test "test_running_in_live_cd_environment". # -> Force gsettings to apply them, that seems to do the trick. config.icp.apply() config.apply() # unity-2d needs the skip-task-bar hint set before the first mapping. self.show_hide_taskbar() # Check gnome-screen-saver integration # onboard_xembed_enabled False True True True # config.gss.embedded_keyboard_enabled any False any False # config.gss.embedded_keyboard_command any empty !=onboard ==onboard # Action: nop enable Question1 Question2 # silently if not config.xid_mode and \ config.onboard_xembed_enabled: # If it appears, that nothing has touched the gss keys before, # silently enable gss integration with onboard. if not config.gss.embedded_keyboard_enabled and \ not config.gss.embedded_keyboard_command: config.enable_gss_embedding(True) # If onboard is configured to be embedded into the unlock screen # dialog, and the embedding command is different from onboard, ask # the user what to do elif not config.is_onboard_in_xembed_command_string(): question = _("Onboard is configured to appear with the dialog to " "unlock the screen; for example to dismiss the " "password-protected screensaver.\n\n" "However the system is not configured anymore to use " "Onboard to unlock the screen. A possible reason can " "be that another application configured the system to " "use something else.\n\n" "Would you like to reconfigure the system to show " "Onboard when unlocking the screen?") _logger.warning("showing dialog: '{}'".format(question)) reply = show_confirmation_dialog(question, self._window, config.is_force_to_top()) if reply == True: config.enable_gss_embedding(True) else: config.onboard_xembed_enabled = False else: if not config.gss.embedded_keyboard_enabled: question = _("Onboard is configured to appear with the dialog " "to unlock the screen; for example to dismiss " "the password-protected screensaver.\n\n" "However this function is disabled in the system.\n\n" "Would you like to activate it?") _logger.warning("showing dialog: '{}'".format(question)) reply = show_confirmation_dialog(question, self._window, config.is_force_to_top()) if reply == True: config.enable_gss_embedding(True) else: config.onboard_xembed_enabled = False # check if gnome accessibility is enabled for auto-show if (config.is_auto_show_enabled() or \ config.are_word_suggestions_enabled()) and \ not config.check_gnome_accessibility(self._window): config.auto_show.enabled = False
def __init__(self, fullscreen=False, is_slideshow=slideshow, show_library=False, manga_mode=False, double_page=False, zoom_mode=None, open_path=None, open_page=1): super(MainWindow, self).__init__(type=Gtk.WindowType.TOPLEVEL) # ---------------------------------------------------------------- # Attributes # ---------------------------------------------------------------- # Used to detect window fullscreen state transitions. self.was_fullscreen = False self.is_manga_mode = False self.previous_size = (None, None) self.was_out_of_focus = False #: Used to remember if changing to fullscreen enabled 'Hide all' self.hide_all_forced = False # Remember last scroll destination. self._last_scroll_destination = constants.SCROLL_TO_START self.layout = _dummy_layout() self._spacing = 2 self._waiting_for_redraw = False self._image_box = Gtk.HBox( homogeneous=False, spacing=2) # XXX transitional(kept for osd.py) self._main_layout = Gtk.Layout() # Wrap main layout into an event box so # we can change its background color. self._event_box = Gtk.EventBox() self._event_box.add(self._main_layout) self._event_handler = event.EventHandler(self) self._vadjust = self._main_layout.get_vadjustment() self._hadjust = self._main_layout.get_hadjustment() self._scroll = ( Gtk.Scrollbar.new(Gtk.Orientation.HORIZONTAL, self._hadjust), Gtk.Scrollbar.new(Gtk.Orientation.VERTICAL, self._vadjust), ) self.filehandler = file_handler.FileHandler(self) self.filehandler.file_closed += self._on_file_closed self.filehandler.file_opened += self._on_file_opened self.imagehandler = image_handler.ImageHandler(self) self.imagehandler.page_available += self._page_available self.thumbnailsidebar = thumbbar.ThumbnailSidebar(self) self.statusbar = status.Statusbar() self.clipboard = clipboard.Clipboard(self) self.slideshow = slideshow.Slideshow(self) self.cursor_handler = cursor_handler.CursorHandler(self) self.enhancer = enhance_backend.ImageEnhancer(self) self.lens = lens.MagnifyingLens(self) self.osd = osd.OnScreenDisplay(self) self.zoom = zoom.ZoomModel() self.uimanager = ui.MainUI(self) self.menubar = self.uimanager.get_widget('/Menu') self.toolbar = self.uimanager.get_widget('/Tool') self.popup = self.uimanager.get_widget('/Popup') self.actiongroup = self.uimanager.get_action_groups()[0] self.images = [Gtk.Image(), Gtk.Image()] # XXX limited to at most 2 pages # ---------------------------------------------------------------- # Setup # ---------------------------------------------------------------- self.set_title(constants.APPNAME) self.set_size_request(300, 300) # Avoid making the window *too* small self.restore_window_geometry() # Hook up keyboard shortcuts self._event_handler.register_key_events() # This is a hack to get the focus away from the toolbar so that # we don't activate it with space or some other key (alternative?) self.toolbar.set_focus_child( self.uimanager.get_widget('/Tool/expander')) self.toolbar.set_style(Gtk.ToolbarStyle.ICONS) self.toolbar.set_icon_size(Gtk.IconSize.LARGE_TOOLBAR) for img in self.images: self._main_layout.put(img, 0, 0) self.set_bg_color(prefs['bg colour']) self._vadjust.step_increment = 15 self._vadjust.page_increment = 1 self._hadjust.step_increment = 15 self._hadjust.page_increment = 1 table = Gtk.Table(n_rows=2, n_columns=2, homogeneous=False) table.attach(self.thumbnailsidebar, 0, 1, 2, 5, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL | Gtk.AttachOptions.EXPAND, 0, 0) table.attach(self._event_box, 1, 2, 2, 3, Gtk.AttachOptions.FILL | Gtk.AttachOptions.EXPAND, Gtk.AttachOptions.FILL | Gtk.AttachOptions.EXPAND, 0, 0) table.attach(self._scroll[constants.HEIGHT_AXIS], 2, 3, 2, 3, Gtk.AttachOptions.FILL | Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.FILL | Gtk.AttachOptions.SHRINK, 0, 0) table.attach(self._scroll[constants.WIDTH_AXIS], 1, 2, 4, 5, Gtk.AttachOptions.FILL | Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.FILL, 0, 0) table.attach(self.menubar, 0, 3, 0, 1, Gtk.AttachOptions.FILL | Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.FILL, 0, 0) table.attach(self.toolbar, 0, 3, 1, 2, Gtk.AttachOptions.FILL | Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.FILL, 0, 0) table.attach(self.statusbar, 0, 3, 5, 6, Gtk.AttachOptions.FILL | Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.FILL, 0, 0) if prefs['default double page'] or double_page: self.actiongroup.get_action('double_page').activate() if prefs['default manga mode'] or manga_mode: self.actiongroup.get_action('manga_mode').activate() # Determine zoom mode. If zoom_mode is passed, it overrides # the zoom mode preference. zoom_actions = { constants.ZOOM_MODE_BEST: 'best_fit_mode', constants.ZOOM_MODE_WIDTH: 'fit_width_mode', constants.ZOOM_MODE_HEIGHT: 'fit_height_mode', constants.ZOOM_MODE_SIZE: 'fit_size_mode', constants.ZOOM_MODE_MANUAL: 'fit_manual_mode' } if zoom_mode is not None: zoom_action = zoom_actions[zoom_mode] else: zoom_action = zoom_actions[prefs['zoom mode']] if zoom_action == 'fit_manual_mode': # This little ugly hack is to get the activate call on # 'fit_manual_mode' to actually create an event (and callback). # Since manual mode is the default selected radio button action # it won't send an event if we activate it when it is already # the selected one. self.actiongroup.get_action('best_fit_mode').activate() self.actiongroup.get_action(zoom_action).activate() if prefs['stretch']: self.actiongroup.get_action('stretch').activate() if prefs['invert smart scroll']: self.actiongroup.get_action('invert_scroll').activate() if prefs['keep transformation']: prefs['keep transformation'] = False self.actiongroup.get_action('keep_transformation').activate() else: prefs['rotation'] = 0 prefs['vertical flip'] = False prefs['horizontal flip'] = False # List of "toggles" than can be shown/hidden by the user. self._toggle_list = ( # Preference Action Widget(s) ('show menubar', 'menubar', (self.menubar, )), ('show scrollbar', 'scrollbar', self._scroll), ('show statusbar', 'statusbar', (self.statusbar, )), ('show thumbnails', 'thumbnails', (self.thumbnailsidebar, )), ('show toolbar', 'toolbar', (self.toolbar, )), ) # Each "toggle" widget "eats" part of the main layout visible area. self._toggle_axis = { self.thumbnailsidebar: constants.WIDTH_AXIS, self._scroll[constants.HEIGHT_AXIS]: constants.WIDTH_AXIS, self._scroll[constants.WIDTH_AXIS]: constants.HEIGHT_AXIS, self.statusbar: constants.HEIGHT_AXIS, self.toolbar: constants.HEIGHT_AXIS, self.menubar: constants.HEIGHT_AXIS, } # Start with all "toggle" widgets hidden to avoid ugly transitions. for preference, action, widget_list in self._toggle_list: for widget in widget_list: widget.hide() toggleaction = self.actiongroup.get_action('hide_all') toggleaction.set_active(prefs['hide all']) # Sync each "toggle" widget active state with its preference. for preference, action, widget_list in self._toggle_list: self.actiongroup.get_action(action).set_active(prefs[preference]) self.actiongroup.get_action('menu_autorotate_width').set_sensitive( False) self.actiongroup.get_action('menu_autorotate_height').set_sensitive( False) self.add(table) table.show() self._event_box.show_all() self._main_layout.set_events(Gdk.EventMask.BUTTON1_MOTION_MASK | Gdk.EventMask.BUTTON2_MOTION_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK) self._main_layout.drag_dest_set( Gtk.DestDefaults.ALL, [Gtk.TargetEntry.new('text/uri-list', 0, 0)], Gdk.DragAction.COPY | Gdk.DragAction.MOVE) self.connect('focus-in-event', self.gained_focus) self.connect('focus-out-event', self.lost_focus) self.connect('delete_event', self.close_program) self.connect('key_press_event', self._event_handler.key_press_event) self.connect('key_release_event', self._event_handler.key_release_event) self.connect('configure_event', self._event_handler.resize_event) self.connect('window-state-event', self._event_handler.window_state_event) self._main_layout.connect('button_release_event', self._event_handler.mouse_release_event) self._main_layout.connect('scroll_event', self._event_handler.scroll_wheel_event) self._main_layout.connect('button_press_event', self._event_handler.mouse_press_event) self._main_layout.connect('motion_notify_event', self._event_handler.mouse_move_event) self._main_layout.connect('drag_data_received', self._event_handler.drag_n_drop_event) self.uimanager.set_sensitivities() self.show() if prefs['default fullscreen'] or fullscreen: toggleaction = self.actiongroup.get_action('fullscreen') toggleaction.set_active(True) if prefs['previous quit was quit and save']: fileinfo = self.filehandler.read_fileinfo_file() if fileinfo != None: open_path = fileinfo[0] open_page = fileinfo[1] + 1 prefs['previous quit was quit and save'] = False if open_path is not None: self.filehandler.open_file(open_path) if is_slideshow: self.actiongroup.get_action('slideshow').activate() if show_library: self.actiongroup.get_action('library').activate() self.cursor_handler.auto_hide_on() # Make sure we receive *all* mouse motion events, # even if a modal dialog is being shown. def _on_event(event): if Gdk.EventType.MOTION_NOTIFY == event.type: self.cursor_handler.refresh() Gtk.main_do_event(event) Gdk.event_handler_set(_on_event) self.styleprovider = None self.load_style(prefs['userstyle'])
def __init__(self): Gdk.event_handler_set(self._filter_callback) GLib.timeout_add_seconds(1, self._increase_idle) self._idle = 0
def __init__(self, filename=None, selection=False, xid=None, delay=None, selection_delay=250, countdown=False, use_clipboard=False, command=None, record=False): super(PyXOSnip, self).__init__(type=gtk.WindowType.POPUP) self.started = False gdk.event_handler_set(self.event_handler) self.command = command self.clipboard_owner = None self.use_clipboard = use_clipboard screen = self.get_screen() self.display = gdk.Display.get_default() self.visual = screen.get_rgba_visual() self.rgba_support = False if (self.visual is not None and screen.is_composited()): self.rgba_support = True self.set_visual(self.visual) self.filename = filename if not filename: ext = 'mkv' if record else 'png' self.filename = f'pyxosnip_$wx$h_%Y-%m-%d-%H%M%S.{ext}' self.delay = delay self.selection_delay = selection_delay self.selection = selection self.xid = xid self.countdown = countdown self.record = record if not xid: self.root = gdk.get_default_root_window() else: self.root = get_window_from_xid(xid) self.root.show() self.x = self.y = 0 self.start_x = self.start_y = 0 self.height = self.width = 0 self.set_app_paintable(True) self.set_keep_above(True) self.connect('draw', self.on_expose) if delay: if countdown: sys.stdout.write(f'Taking shot in ... {self.delay}') sys.stdout.flush() glib.timeout_add(1000, self.start) else: self.start() self.painted = False