Esempio n. 1
0
def set_unity_property(window):
    """
    Set custom X window property to tell unity 3D this is an on-screen
    keyboard that wants to be raised on top of dash. See LP 739812, 915250.
    Since onboard started detecting dash itself this isn't really needed
    for unity anymore. Leave it anyway, it may come in handy in the future.
    """
    gdk_win = window.get_window()
    if gdk_win:
        if hasattr(gdk_win, "get_xid"):  # not on wayland
            xid = gdk_win.get_xid()
            osk.Util().set_x_property(xid, "ONSCREEN_KEYBOARD", 1)
Esempio n. 2
0
    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
Esempio n. 3
0
    def __init__(self):
        MouseController.__init__(self)

        self._osk_util = osk.Util()
        self._click_done_notify_callbacks = []
        self._exclusion_rects = []
Esempio n. 4
0
class LabelPopup(KeyboardPopup):
    """ Ephemeral popup displaying a key label without user interaction. """

    ARROW_HEIGHT = 0.13
    ARROW_WIDTH = 0.3
    LABEL_MARGIN = 0.1

    _pango_layout = None
    _osk_util = osk.Util()

    def __init__(self):
        KeyboardPopup.__init__(self)
        self._key = None
        self.connect("realize", self._on_realize_event)
        self.connect("draw", self._on_draw)

    def _on_realize_event(self, user_data):
        self.set_override_redirect(True)

        # set minimal input shape for the popup to become click-through
        win = self.get_window()
        self._osk_util.set_input_rect(win, 0, 0, 1, 1)

    def _on_draw(self, widget, context):

        if not LabelPopup._pango_layout:
            LabelPopup._pango_layout = Pango.Layout(
                context=Gdk.pango_context_get())

        rect = Rect(0, 0, self.get_allocated_width(),
                    self.get_allocated_height())
        content_rect = Rect(rect.x, rect.y, rect.w,
                            rect.h - rect.h * self.ARROW_HEIGHT)
        arrow_rect   = Rect(rect.x, content_rect.bottom(), rect.w,
                            rect.h * self.ARROW_HEIGHT) \
                       .deflate((rect.w - rect.w * self.ARROW_WIDTH) / 2.0, 0)

        label_rect = content_rect.deflate(rect.w * self.LABEL_MARGIN)

        # background
        fill = self._key.get_fill_color()
        context.save()
        context.set_operator(cairo.OPERATOR_CLEAR)
        context.paint()
        context.restore()

        context.set_source_rgba(*fill)
        roundrect_arc(context, content_rect, config.CORNER_RADIUS)
        context.fill()

        l, t, r, b = arrow_rect.to_extents()
        t -= 1
        context.move_to(l, t)
        context.line_to(r, t)
        context.line_to((l + r) / 2, b)
        context.fill()

        # draw label/image
        label_color = self._key.get_label_color()
        pixbuf = self._key.get_image(label_rect.w, label_rect.h)
        if pixbuf:
            pixbuf.draw(context, label_rect, label_color)
        else:
            label = self._key.get_label()
            if label:
                if label == " ":
                    label = "␣"
                self._draw_text(context, label, label_rect, label_color)

    def _draw_text(self, context, text, rect, rgba):
        layout = self._pango_layout
        layout.set_text(text, -1)

        # find text extents
        font_description = Pango.FontDescription( \
                                        config.theme_settings.key_label_font)
        base_extents = self._calc_base_layout_extents(layout, font_description)

        # scale label to the available rect
        font_size = self._calc_font_size(rect, base_extents)
        font_description.set_size(max(1, font_size))
        layout.set_font_description(font_description)

        # center
        w, h = layout.get_size()
        w /= Pango.SCALE
        h /= Pango.SCALE
        offset = rect.align_rect(Rect(0, 0, w, h)).get_position()

        # draw
        context.move_to(*offset)
        context.set_source_rgba(*rgba)
        PangoCairo.show_layout(context, layout)

    @staticmethod
    def _calc_font_size(rect, base_extents):
        size_for_maximum_width = rect.w / base_extents[0]
        size_for_maximum_height = rect.h / base_extents[1]
        if size_for_maximum_width < size_for_maximum_height:
            return int(size_for_maximum_width)
        else:
            return int(size_for_maximum_height)

    @staticmethod
    def _calc_base_layout_extents(layout, font_description):
        BASE_FONTDESCRIPTION_SIZE = 10000000

        font_description.set_size(BASE_FONTDESCRIPTION_SIZE)
        layout.set_font_description(font_description)

        w, h = layout.get_size()  # In Pango units
        w = w or 1.0
        h = h or 1.0
        extents = (w / (Pango.SCALE * BASE_FONTDESCRIPTION_SIZE),
                   h / (Pango.SCALE * BASE_FONTDESCRIPTION_SIZE))
        return extents

    def get_key(self):
        return self._key

    def set_key(self, key):
        self._key = key
Esempio n. 5
0
class PendingSeparatorPopup(KeyboardPopup):
    """ Ephemeral popup displaying the pending word separator. """

    _osk_util = osk.Util()

    def __init__(self):
        KeyboardPopup.__init__(self)
        self.connect("realize", self._on_realize_event)
        self._visible = False

    def show_at(self, view, character_rect):
        toplevel = view.get_toplevel()

        self.set_transient_for(toplevel)
        self.realize()

        x, y, w, h = character_rect
        self.set_default_size(w, h)
        self.resize(w, h)
        self.move(x, y)

        self.supports_alpha = view.supports_alpha
        if self.supports_alpha:
            self.set_opacity(toplevel.get_opacity())
        self.show_all()
        self._visible = True

    def hide(self):
        KeyboardPopup.hide(self)
        self._visible = False

    def is_visible(self):
        return self._visible

    def _on_realize_event(self, user_data):
        self.set_override_redirect(True)

        # set minimal input shape for the popup to become click-through
        win = self.get_window()
        self._osk_util.set_input_rect(win, 0, 0, 1, 1)

    def on_draw(self, widget, cr):
        rect = Rect(0, 0, self.get_allocated_width(),
                    self.get_allocated_height())

        fill_rgba = (1.0, 0.5, 0.5, 0.2)
        stroke_rgba = (1.0, 0.5, 0.5, 0.7)

        cr.set_source_rgba(*fill_rgba)
        cr.rectangle(*rect)
        cr.fill()

        r = rect
        top = r.y + r.h * 0.75
        bottom = r.bottom()
        cr.set_source_rgba(*stroke_rgba)
        cr.set_line_width(max(1, r.h / 6))
        cr.move_to(r.left(), top)
        cr.line_to(r.left(), bottom)
        cr.line_to(r.right(), bottom)
        cr.line_to(r.right(), top)
        cr.stroke()
Esempio n. 6
0
    def __init__(self, keyboard_widget, icp):
        _logger.debug("Entered in __init__")

        self._osk_util = osk.Util()
        self._osk_struts = osk.Struts()

        self.application = None
        self.keyboard_widget = keyboard_widget
        self.icp = icp

        self.supports_alpha = False

        self._visible = False
        self._sticky = False
        self._iconified = False
        self._maximized = False

        self._screen_resizing = False

        self._docking_enabled = False
        self._docking_edge = None
        self._docking_rect = Rect()
        self._shrink_work_area = False
        self._dock_expand = False
        self._current_struts = None
        self._monitor_workarea = {}

        self._opacity = 1.0
        self._default_resize_grip = self.get_has_resize_grip()
        self._override_redirect = False
        self._type_hint = None

        self._known_window_rects = []
        self._written_window_rects = {}
        self._written_dock_sizes = {}
        self._wm_quirks = None

        self._desktop_switch_count = 0
        self._moved_desktop_switch_count = 0

        self.set_accept_focus(False)
        self.set_app_paintable(True)
        self.set_keep_above(True)
        #Gtk.Settings.get_default().set_property("gtk-touchscreen-mode", True)

        Gtk.Window.set_default_icon_name("onboard")
        self.set_title(_("Onboard"))

        self.connect("window-state-event", self._cb_window_state_event)
        self.connect("visibility-notify-event", self._cb_visibility_notify)
        self.connect('screen-changed', self._cb_screen_changed)
        self.connect('composited-changed', self._cb_composited_changed)
        self.connect("realize", self._cb_realize_event)
        self.connect("unrealize", self._cb_unrealize_event)

        self.detect_window_manager()
        self.check_alpha_support()
        self.update_unrealize_options()

        self.add(self.keyboard_widget)

        _logger.debug("Leaving __init__")