Пример #1
0
 def SetPreviousForm(self):
     """
         Set focused form to previous value
     """
     if self.__focused is None:
         return
     try:
         if self.__focused in self.__form_history.keys():
             current_value = self.__focused.get_value()
             item = self.__form_history[self.__focused]
             # User added some text, keep it
             if item.value != current_value:
                 next = LinkedList(current_value.rstrip(" "), None, item)
                 if item is not None:
                     item.set_next(next)
                 item = next
             if item.prev:
                 self.__form_history[self.__focused] = item.prev
                 self.__focused.set_value(item.prev.value)
         else:
             new_value = self.__focused.get_value().rstrip(" ")
             if new_value:
                 item = LinkedList(new_value, None, None)
                 next = LinkedList("", item, None)
                 self.__form_history[self.__focused] = next
                 self.__focused.set_value("")
     except Exception as e:
         print("ProxyExtension::SetPreviousForm():", e)
Пример #2
0
    def __on_input(self, form, event):
        """
            Send input signal
            @param form as WebKit2WebExtension.DOMElement
            @param event as WebKit2WebExtension.DOMUIEvent
        """
        # Clear history if nothing and return
        new_value = form.get_value()
        if not new_value:
            if form in self.__form_history.keys():
                del self.__form_history[form]
            return

        previous_value = ""
        item = LinkedList("", None, None)
        if form in self.__form_history.keys():
            item = self.__form_history[form]
            previous_value = item.value
        # Here we try to get words
        # If we are LTR then add words on space
        if len(new_value) > len(previous_value):
            if new_value.endswith(" "):
                next = LinkedList(new_value.rstrip(" "), None, item)
                if item is not None:
                    item.set_next(next)
                self.__form_history[form] = next
Пример #3
0
 def __on_input_timeout(self, element):
     """
         Save buffer to history
         @param element as WebKit2WebExtension.DOMElement
     """
     self.__on_input_timeout_id = None
     new_value = element.get_value()
     item = LinkedList("", None, None)
     if element in self.__elements_history.keys():
         item = self.__elements_history[element]
     next = LinkedList(new_value.rstrip(" "), None, item)
     if item is not None:
         item.set_next(next)
     self.__elements_history[element] = next
Пример #4
0
 def add_text_entry(self, text):
     """
         Add an uri to text entry list
         @param text as str
     """
     if text and text != self.__text_entry.value:
         item = LinkedList(text, None, self.__text_entry)
         self.__text_entry = item
Пример #5
0
 def SetPreviousElementValue(self):
     """
         Set focused form to previous value
     """
     if self.__focused is None:
         return
     try:
         value = self.__focused.get_value().rstrip(" ")
         if self.__focused in self.__elements_history.keys():
             current = self.__elements_history[self.__focused]
             if current.prev is not None:
                 self.__elements_history[self.__focused] = current.prev
                 self.__focused.set_value(current.prev.value)
         elif value:
             next = LinkedList(value, None, None)
             current = LinkedList("", next, None)
             next.set_prev(current)
             self.__elements_history[self.__focused] = current
             self.__focused.set_value("")
     except Exception as e:
         print("ProxyExtension::SetPreviousForm():", e)
Пример #6
0
 def get_prev_text_entry(self, current_value=None):
     """
         Get previous text entry value
         @param current_value as str
         @return text as str
     """
     previous = None
     if self.__text_entry.prev is not None:
         # Append current to list as it is missing
         if current_value != self.__text_entry.value:
             item = LinkedList(current_value, None, self.__text_entry)
             self.__text_entry.set_next(item)
             previous = self.__text_entry.value
         else:
             current = self.__text_entry
             previous = self.__text_entry.prev.value
             if previous is not None:
                 self.__text_entry = self.__text_entry.prev
                 self.__text_entry.set_next(current)
     return previous
Пример #7
0
class WebView(WebKit2.WebView):
    """
        WebKit view
    """
    def new(window, view):
        """
            New webview
            @param window as Window
            @param view as View
        """
        context = WebKit2.WebContext.new()
        Context(context)
        webview = WebKit2.WebView.new_with_context(context)
        content_manager = webview.get_property("user-content-manager")
        webview.__class__ = WebViewMeta
        webview.__init(None, context, content_manager, window, view)
        return webview

    def new_ephemeral(window, view):
        """
            New ephemeral webview
            @param window as Window
            @param view as View
        """
        context = WebKit2.WebContext.new_ephemeral()
        Context(context)
        webview = WebKit2.WebView.new_with_context(context)
        webview.__class__ = WebViewMeta
        content_manager = webview.get_property("user-content-manager")
        webview.__init(None, context, content_manager, window, view)
        return webview

    def new_with_related_view(related, window):
        """
            Create a new WebView related to view
            @param related as WebView
            @param window as Window
            @return WebView
        """
        webview = WebKit2.WebView.new_with_related_view(related)
        webview.__class__ = WebViewMeta
        webview.__init(related, related.context, related.content_manager,
                       window, None)
        return webview

    def set_setting(self, key, value):
        """
            Set setting to value
            @param key as str
            @param value as GLib.Variant
        """
        settings = self.get_settings()
        if key == 'use-system-fonts':
            self.__set_system_fonts(settings)
        else:
            settings.set_property(key, value)

    def update_zoom_level(self):
        """
            Update zoom level
        """
        try:
            zoom_level = El().websettings.get_zoom(self.uri)
            if zoom_level is None:
                zoom_level = 100
            if self.__related_view is None:
                zoom_level *= self._window.zoom_level
            else:
                window = self.__related_view.get_ancestor(Gtk.Window)
                if window is not None and hasattr(window, "zoom-level"):
                    zoom_level *= window.zoom_level
        except Exception as e:
            print("WebView::update_zoom_level()", e)
        debug("Update zoom level: %s" % zoom_level)
        self.set_zoom_level(zoom_level / 100)

    def print(self):
        """
            Show print dialog for current page
        """
        p = WebKit2.PrintOperation.new(self)
        p.run_dialog()

    def zoom_in(self):
        """
            Zoom in view
            @return current zoom after zoom in
        """
        current = El().websettings.get_zoom(self.uri)
        if current is None:
            current = 100
        current += 10
        El().websettings.set_zoom(current, self.uri)
        self.update_zoom_level()
        return current

    def zoom_out(self):
        """
            Zoom out view
            @return current zoom after zoom out
        """
        current = El().websettings.get_zoom(self.uri)
        if current is None:
            current = 100
        current -= 10
        if current == 0:
            return 10
        El().websettings.set_zoom(current, self.uri)
        self.update_zoom_level()
        return current

    def zoom_default(self):
        """
            Reset zoom level
            @return current zoom after zoom out
        """
        El().websettings.set_zoom(100, self.uri)
        self.update_zoom_level()

    def set_title(self, title):
        """
            Set title, will be returned by title property until title is set
            by WebView
            @param title as str
        """
        self._title = title
        self.emit("title-changed", title)

    def set_uri(self, uri):
        """
            Set delayed uri
            @param uri as str
        """
        self._uri = uri
        self.emit("uri-changed", uri)

    def update_spell_checking(self):
        """
            Update spell checking
        """
        codes = El().websettings.get_languages(self.uri)
        # If None, default user language
        if codes is not None:
            self.get_context().set_spell_checking_languages(codes)

    def add_text_entry(self, text):
        """
            Add an uri to text entry list
            @param text as str
        """
        if text and text != self.__text_entry.value:
            item = LinkedList(text, None, self.__text_entry)
            self.__text_entry = item

    def clear_text_entry(self):
        """
            Clear text entry history
        """
        self.__text_entry = LinkedList("", None, None)

    def get_current_text_entry(self):
        """
            Get currnet text entry value
            @return text as str
        """
        current = None
        if self.__text_entry is not None:
            current = self.__text_entry.value
        return current

    def get_prev_text_entry(self, current_value=None):
        """
            Get previous text entry value
            @param current_value as str
            @return text as str
        """
        previous = None
        if self.__text_entry.prev is not None:
            # Append current to list as it is missing
            if current_value != self.__text_entry.value:
                item = LinkedList(current_value, None, self.__text_entry)
                self.__text_entry.set_next(item)
                previous = self.__text_entry.value
            else:
                current = self.__text_entry
                previous = self.__text_entry.prev.value
                if previous is not None:
                    self.__text_entry = self.__text_entry.prev
                    self.__text_entry.set_next(current)
        return previous

    def get_next_text_entry(self):
        """
            Get next text entry value
            @return text as str
        """
        next = None
        if self.__text_entry.next is not None:
            next = self.__text_entry.next.value
            if next is not None:
                self.__text_entry = self.__text_entry.next
        return next

    def stop_loading(self):
        """
            Keep stop loading state
        """
        self._cancelled = True
        WebKit2.WebView.stop_loading(self)

    def new_page(self, loading_type):
        """
            Open a new page
            @param loading_type as Gdk.LoadingType
        """
        if loading_type == LoadingType.POPOVER:
            if self.ephemeral:
                webview = WebView.new_ephemeral(self._window, None)
            else:
                webview = WebView.new(self._window, None)
            self._window.container.popup_webview(webview, True)
            GLib.idle_add(webview.load_uri, self._navigation_uri)
        else:
            # parent.gtime = child.gtime + 1
            # Set child atime lower that current atime for sorting next
            # Used to search for best matching webview
            self._new_pages_opened += 1
            self._window.container.add_webview(
                self._navigation_uri, loading_type, self.ephemeral, None,
                self.gtime - 1, self.atime - self._new_pages_opened)

    def set_atime(self, atime):
        """
            Update access time
            @param atime as int
        """
        self.__atime = atime

    def set_gtime(self, gtime):
        """
            Update group time
            @param atime as int
        """
        self.__gtime = gtime

    def set_view(self, view):
        """
            Set webview view
            @param view as View
        """
        self.__view = view

    def set_window(self, window):
        """
            Set webview window
            @param window as Window
        """
        self._window = window

    @property
    def content_manager(self):
        """
            Get content manager
            @return WebKit2.UserContentManager
        """
        return self.__content_manager

    @property
    def context(self):
        """
            Get context
            @return WebKit2.WebContext
        """
        return self.__context

    @property
    def atime(self):
        """
            Get access time
            @return int
        """
        return self.__atime

    @property
    def gtime(self):
        """
            Get group time
            @return int
        """
        return self.__gtime

    @property
    def view(self):
        """
            Get view
            @return View
        """
        return self.__view

    @property
    def shown(self):
        """
            True if page already shown on screen (one time)
        """
        return self._shown

    @property
    def cancelled(self):
        """
            True if last loading was cancelled
            @return bool
        """
        return self._cancelled

    @property
    def title(self):
        """
            Get title (loaded or unloaded)
            @return str
        """
        title = self.get_title()
        if title is None:
            title = self._title
        if title is None:
            title = self.uri
        return title

    @property
    def uri(self):
        """
            Get uri (loaded or unloaded)
            @return str
        """
        uri = self.get_uri()
        if uri is None:
            uri = self._uri
        return uri

    @property
    def ephemeral(self):
        """
            True if view is private/ephemeral
            @return bool
        """
        return self.get_property("is-ephemeral")

    @property
    def selection(self):
        """
            Get current selection
            @return str
        """
        return self.__selection

    @property
    def readable_content(self):
        """
            Readable content
            @return content as str
        """
        return self._readable_content


#######################
# PRIVATE             #
#######################

    def __init(self, related_view, context, content_manager, window, view):
        """
            Init WebView
            @param related_view as WebView
            @param context as WebKit2.WebContext
            @param content_manager as WebKit2.UserContentManager
            @param window as Window
            @param view as View
        """
        WebViewErrors.__init__(self)
        WebViewNavigation.__init__(self, related_view)
        WebViewSignals.__init__(self)
        WebViewArtwork.__init__(self)
        self._window = window
        self.__view = view
        self.__context = context
        self.__content_manager = content_manager
        self.__atime = 0
        self.__gtime = int(time())
        self._new_pages_opened = 0
        # WebKitGTK doesn't provide an API to get selection, so try to guess
        # it from clipboard FIXME Get it from extensions
        self.__selection = ""
        self._readable_content = ""
        self._uri = None
        self._title = None
        self._navigation_uri = None
        self.__related_view = related_view
        self.__input_source = Gdk.InputSource.MOUSE
        self._cancelled = False
        self._shown = False
        self.set_hexpand(True)
        self.set_vexpand(True)
        self.clear_text_entry()
        # Set settings
        settings = self.get_settings()
        system = Gio.Settings.new("org.gnome.desktop.interface")
        animations = system.get_value("enable-animations")
        settings.set_property("enable-java",
                              El().settings.get_value('enable-plugins'))
        settings.set_property("enable-plugins",
                              El().settings.get_value('enable-plugins'))
        settings.set_property(
            "minimum-font-size",
            El().settings.get_value("min-font-size").get_int32())
        if El().settings.get_value("use-system-fonts"):
            self.__set_system_fonts(settings, system)
        else:
            settings.set_property(
                "monospace-font-family",
                El().settings.get_value("font-monospace").get_string())
            settings.set_property(
                "sans-serif-font-family",
                El().settings.get_value("font-sans-serif").get_string())
            settings.set_property(
                "serif-font-family",
                El().settings.get_value("font-serif").get_string())
        settings.set_property("auto-load-images", True)
        settings.set_property("enable-mediasource", True)
        settings.set_property("enable-media-stream", True)
        settings.set_property("enable-site-specific-quirks", True)
        settings.set_property("allow-universal-access-from-file-urls", False)
        settings.set_property("allow-file-access-from-file-urls", False)
        settings.set_property("enable-javascript", True)
        settings.set_property("enable-media-stream", True)
        settings.set_property("enable-mediasource", True)
        settings.set_property("enable-developer-extras",
                              El().settings.get_value("developer-extras"))
        settings.set_property("enable-offline-web-application-cache", True)
        settings.set_property("enable-page-cache", True)
        settings.set_property("enable-resizable-text-areas", True)
        settings.set_property("enable-smooth-scrolling", animations)
        settings.set_property("enable-webaudio", True)
        settings.set_property("enable-webgl", True)
        settings.set_property("javascript-can-access-clipboard", True)
        settings.set_property("javascript-can-open-windows-automatically",
                              True)
        settings.set_property("media-playback-allows-inline", True)
        self.connect("create", self.__on_create)
        self.connect("load-changed", self._on_load_changed)

    def __set_system_fonts(self, settings, system=None):
        """
            Set system font
            @param settings as WebKit2.Settings
            @param system as Gio.Settings("org.gnome.desktop.interface")
        """
        if system is None:
            system = Gio.Settings.new("org.gnome.desktop.interface")
        settings.set_property(
            "monospace-font-family",
            system.get_value("monospace-font-name").get_string())
        settings.set_property(
            "sans-serif-font-family",
            system.get_value("document-font-name").get_string())
        settings.set_property("serif-font-family",
                              system.get_value("font-name").get_string())

    def __set_smooth_scrolling(self, source):
        """
            Set smooth scrolling based on source
            @param source as Gdk.InputSource
        """
        settings = self.get_settings()
        settings.set_property("enable-smooth-scrolling",
                              source != Gdk.InputSource.MOUSE)

    def __on_create(self, related, navigation_action):
        """
            Create a new view for action
            @param related as WebView
            @param navigation_action as WebKit2.NavigationAction
        """
        webview = WebView.new_with_related_view(related, self._window)
        webview.set_atime(related.atime - 1)
        webview.connect("ready-to-show", self.__on_ready_to_show, related,
                        navigation_action)
        return webview

    def __on_ready_to_show(self, webview, related, navigation_action):
        """
            Add a new webview with related
            @param webview as WebView
            @param related as WebView
            @param navigation_action as WebKit2.NavigationAction
        """
        # Do not block if we get a click on view
        elapsed = time() - related._last_click_time
        popup_block = El().settings.get_value("popupblock")
        parsed_related = urlparse(related.uri)
        exception = El().popup_exceptions.find_parsed(parsed_related) or\
            elapsed < 0.5
        if not exception and popup_block and\
                navigation_action.get_navigation_type() in [
                               WebKit2.NavigationType.OTHER,
                               WebKit2.NavigationType.RELOAD,
                               WebKit2.NavigationType.BACK_FORWARD]:
            related.add_popup(webview)
            webview.connect("close", self.__on_popup_close, related)
            if related == self._window.container.current.webview:
                self._window.toolbar.title.show_indicator(Indicator.POPUPS)
            return
        properties = webview.get_window_properties()
        if properties.get_locationbar_visible() and\
                properties.get_toolbar_visible() and\
                not navigation_action.get_modifiers() &\
                Gdk.ModifierType.SHIFT_MASK:
            self._window.container.add_webview_with_new_view(
                webview, LoadingType.FOREGROUND)

        else:
            self._window.container.popup_webview(webview, True)

    def __on_popup_close(self, webview, related):
        """
            Remove webview from popups
            @param webview as WebView
            @param related as WebView
        """
        related.remove_popup(webview)
        if self._window.container.current.webview == related and\
                not related.popups:
            self._window.toolbar.title.show_indicator(Indicator.NONE)
Пример #8
0
 def clear_text_entry(self):
     """
         Clear text entry history
     """
     self.__text_entry = LinkedList("", None, None)
Пример #9
0
class WebView(WebKit2.WebView):
    """
        WebKit view
    """
    def new(window):
        """
            New webview
            @param window as Window
        """
        view = WebKit2.WebView.new()
        view.__class__ = WebViewMeta
        view.__init(None, window)
        return view

    def new_ephemeral(window):
        """
            New ephemeral webview
            @param window as Window
        """
        view = WebKit2.WebView.new_with_context(El().ephemeral_context)
        view.__class__ = WebViewMeta
        view.__init(None, window)
        return view

    def new_with_related_view(related, window):
        """
            Create a new WebView related to view
            @param related as WebView
            @param window as Window
            @return WebView
        """
        view = WebKit2.WebView.new_with_related_view(related)
        view.__class__ = WebViewMeta
        view.__init(related, window)
        return view

    def set_setting(self, key, value):
        """
            Set setting to value
            @param key as str
            @param value as GLib.Variant
        """
        settings = self.get_settings()
        if key == 'use-system-fonts':
            self.__set_system_fonts(settings)
        else:
            settings.set_property(key, value)

    def update_zoom_level(self):
        """
            Update zoom level
        """
        try:
            zoom_level = El().websettings.get_zoom(self.get_uri())
            if zoom_level is None:
                zoom_level = 100
            if self.__related_view is None:
                zoom_level *= self.get_ancestor(Gtk.Window).zoom_level
            else:
                zoom_level *= self.__related_view.get_ancestor(
                    Gtk.Window).zoom_level
        except Exception as e:
            print("WebView::update_zoom_level()", e)
        debug("Update zoom level: %s" % zoom_level)
        self.set_zoom_level(zoom_level / 100)

    def print(self):
        """
            Show print dialog for current page
        """
        p = WebKit2.PrintOperation.new(self)
        p.run_dialog()

    def zoom_in(self):
        """
            Zoom in view
            @return current zoom after zoom in
        """
        current = El().websettings.get_zoom(self.get_uri())
        if current is None:
            current = 100
        current += 10
        El().websettings.set_zoom(current, self.get_uri())
        self.update_zoom_level()
        return current

    def zoom_out(self):
        """
            Zoom out view
            @return current zoom after zoom out
        """
        current = El().websettings.get_zoom(self.get_uri())
        if current is None:
            current = 100
        current -= 10
        if current == 0:
            return 10
        El().websettings.set_zoom(current, self.get_uri())
        self.update_zoom_level()
        return current

    def zoom_default(self):
        """
            Reset zoom level
            @return current zoom after zoom out
        """
        El().websettings.set_zoom(100, self.get_uri())
        self.update_zoom_level()

    def set_delayed_uri(self, uri):
        """
            Set delayed uri
            @param uri as str
        """
        self.__delayed_uri = uri

    def update_spell_checking(self):
        """
            Update spell checking
        """
        codes = El().websettings.get_languages(self.get_uri())
        # If None, default user language
        if codes is not None:
            self.get_context().set_spell_checking_languages(codes)

    def add_text_entry(self, text):
        """
            Add an uri to text entry list
            @param text as str
        """
        if text and text != self.__text_entry.value:
            item = LinkedList(text, None, self.__text_entry)
            self.__text_entry = item

    def clear_text_entry(self):
        """
            Clear text entry history
        """
        self.__text_entry = LinkedList("", None, None)

    def get_current_text_entry(self):
        """
            Get currnet text entry value
            @return text as str
        """
        current = None
        if self.__text_entry is not None:
            current = self.__text_entry.value
        return current

    def get_prev_text_entry(self, current_value=None):
        """
            Get previous text entry value
            @param current_value as str
            @return text as str
        """
        previous = None
        if self.__text_entry.prev is not None:
            # Append current to list as it is missing
            if current_value != self.__text_entry.value:
                item = LinkedList(current_value, None, self.__text_entry)
                self.__text_entry.set_next(item)
                previous = self.__text_entry.value
            else:
                current = self.__text_entry
                previous = self.__text_entry.prev.value
                if previous is not None:
                    self.__text_entry = self.__text_entry.prev
                    self.__text_entry.set_next(current)
        return previous

    def get_next_text_entry(self):
        """
            Get next text entry value
            @return text as str
        """
        next = None
        if self.__text_entry.next is not None:
            next = self.__text_entry.next.value
            if next is not None:
                self.__text_entry = self.__text_entry.next
        return next

    def stop_loading(self):
        """
            Keep stop loading state
        """
        self._cancelled = True
        WebKit2.WebView.stop_loading(self)

    def update_access_time(self):
        """
            Update access time
        """
        self.__atime = int(time())

    @property
    def access_time(self):
        """
            Get access time
            @return int
        """
        return self.__atime

    @property
    def cancelled(self):
        """
            True if last loading was cancelled
            @return bool
        """
        return self._cancelled

    @property
    def delayed_uri(self):
        """
            Get delayed uri (one time)
            @return str
        """
        try:
            return self.__delayed_uri
        finally:
            self.__delayed_uri = None

    @property
    def ephemeral(self):
        """
            True if view is private/ephemeral
            @return bool
        """
        return self.get_property("is-ephemeral")

    @property
    def selection(self):
        """
            Get current selection
            @return str
        """
        return self.__selection

    @property
    def last_click_time(self):
        """
            Get last click time
            @return float
        """
        if self.__last_click_event:
            return self.__last_click_event["time"]
        else:
            return 0

    @property
    def readable_content(self):
        """
            Readable content
            @return content as str
        """
        return self._readable_content


#######################
# PRIVATE             #
#######################

    def __init(self, related_view, window):
        """
            Init WebView
            @param related_view as WebView
            @param window as Window
        """
        WebViewErrors.__init__(self)
        WebViewNavigation.__init__(self)
        self._window = window
        self.__atime = 0
        # WebKitGTK doesn't provide an API to get selection, so try to guess
        # it from clipboard FIXME Get it from extensions
        self.__selection = ""
        self._readable_content = ""
        self.__last_click_event = {}
        self.__delayed_uri = None
        self._navigation_uri = None
        self.__related_view = related_view
        self.__input_source = Gdk.InputSource.MOUSE
        self._cancelled = False
        self.set_hexpand(True)
        self.set_vexpand(True)
        self.clear_text_entry()
        # Set settings
        settings = self.get_settings()
        settings.set_property("enable-java",
                              El().settings.get_value('enable-plugins'))
        settings.set_property("enable-plugins",
                              El().settings.get_value('enable-plugins'))
        settings.set_property(
            "minimum-font-size",
            El().settings.get_value("min-font-size").get_int32())
        if El().settings.get_value("use-system-fonts"):
            self.__set_system_fonts(settings)
        else:
            settings.set_property(
                "monospace-font-family",
                El().settings.get_value("font-monospace").get_string())
            settings.set_property(
                "sans-serif-font-family",
                El().settings.get_value("font-sans-serif").get_string())
            settings.set_property(
                "serif-font-family",
                El().settings.get_value("font-serif").get_string())
        settings.set_property("auto-load-images", True)
        settings.set_property("enable-site-specific-quirks", True)
        settings.set_property("allow-universal-access-from-file-urls", False)
        settings.set_property("allow-file-access-from-file-urls", False)
        settings.set_property("enable-javascript", True)
        settings.set_property("enable-media-stream", True)
        settings.set_property("enable-mediasource", True)
        settings.set_property("enable-developer-extras",
                              El().settings.get_value("developer-extras"))
        settings.set_property("enable-offline-web-application-cache", True)
        settings.set_property("enable-page-cache", True)
        settings.set_property("enable-resizable-text-areas", True)
        settings.set_property("enable-smooth-scrolling", False)
        settings.set_property("enable-webaudio", True)
        settings.set_property("enable-webgl", True)
        settings.set_property("javascript-can-access-clipboard", True)
        settings.set_property("javascript-can-open-windows-automatically",
                              True)
        settings.set_property("media-playback-allows-inline", True)
        self.connect("scroll-event", self.__on_scroll_event)
        self.connect("context-menu", self.__on_context_menu)
        self.connect("run-file-chooser", self.__on_run_file_chooser)
        self.connect("script-dialog", self.__on_script_dialog)
        self.connect("submit-form", self.__on_submit_form)
        self.connect("map", self.__on_map)
        self.connect("unmap", self.__on_unmap)
        self.connect("button-press-event", self.__on_button_press_event)

    def __set_system_fonts(self, settings):
        """
            Set system font
            @param settings as WebKit2.Settings
        """
        system = Gio.Settings.new("org.gnome.desktop.interface")
        settings.set_property(
            "monospace-font-family",
            system.get_value("monospace-font-name").get_string())
        settings.set_property(
            "sans-serif-font-family",
            system.get_value("document-font-name").get_string())
        settings.set_property("serif-font-family",
                              system.get_value("font-name").get_string())

    def __set_smooth_scrolling(self, source):
        """
            Set smooth scrolling based on source
            @param source as Gdk.InputSource
        """
        settings = self.get_settings()
        settings.set_property("enable-smooth-scrolling",
                              source != Gdk.InputSource.MOUSE)

    def __on_button_press_event(self, widget, event):
        """
            Store last press event
            @param widget as WebView
            @param event as Gdk.EventButton
        """
        self.__last_click_event = {"x": event.x, "y": event.y, "time": time()}

    def __on_get_forms(self, source, result, request, uri):
        """
            Set forms value
            @param source as GObject.Object
            @param result as Gio.AsyncResult
            @param request as WebKit2.FormSubmissionRequest
            @param uri as str
        """
        try:
            (user_form_name, user_form_value, pass_form_name,
             pass_form_value) = source.call_finish(result)[0]
            if user_form_name and pass_form_name:
                self._window.close_popovers()
                self.emit("save-password", user_form_name, user_form_value,
                          pass_form_name, pass_form_value, self.get_uri(), uri)
            request.submit()
        except Exception as e:
            print("WebView::__on_get_forms():", e)

    def __on_submit_form(self, webview, request):
        """
            Check for auth forms
            @param webview as WebKit2.WebView
            @param request as WebKit2.FormSubmissionRequest
        """
        uri = self._navigation_uri
        if self.ephemeral or not El().settings.get_value("remember-passwords"):
            return
        fields = request.get_text_fields()
        if fields is None:
            return
        forms = []
        for k, v in fields.items():
            name = string_at(k).decode("utf-8")
            value = string_at(v).decode("utf-8")
            forms.append((name, value))
        page_id = webview.get_page_id()
        El().helper.call("GetAuthForms",
                         GLib.Variant("(aasi)", (forms, page_id)),
                         self.__on_get_forms, page_id, request, uri)

    def __on_context_menu(self, view, context_menu, event, hit):
        """
            Add custom items to menu
            @param view as WebView
            @param context_menu as WebKit2.ContextMenu
            @param event as Gdk.Event
            @param hit as WebKit2.HitTestResult
        """
        parsed = urlparse(view.get_uri())
        if hit.context_is_link():
            # Add an item for open in a new page
            # FIXME https://bugs.webkit.org/show_bug.cgi?id=159631
            # Introspection missing, Gtk.Action deprecated
            action = Gtk.Action.new("open_new_page",
                                    _("Open link in a new page"), None, None)
            action.connect("activate", self.__on_open_new_page_activate,
                           hit.get_link_uri())
            item = WebKit2.ContextMenuItem.new(action)
            context_menu.insert(item, 1)

        selection = context_menu.get_user_data().get_string()
        if selection:
            if hit.context_is_selection():
                # Add an item for open words in search
                # FIXME https://bugs.webkit.org/show_bug.cgi?id=159631
                # Introspection missing, Gtk.Action deprecated
                action = Gtk.Action.new("search_words", _("Search on the Web"),
                                        None, None)
                action.connect("activate", self.__on_search_words_activate,
                               selection)
                item = WebKit2.ContextMenuItem.new(action)
                context_menu.insert(item, 1)
            if hit.context_is_link():
                # Add an item for open words in search
                # FIXME https://bugs.webkit.org/show_bug.cgi?id=159631
                # Introspection missing, Gtk.Action deprecated
                action = Gtk.Action.new("copy_text", _("Copy"), None, None)
                action.connect("activate", self.__on_copy_text_activate,
                               selection)
                item = WebKit2.ContextMenuItem.new(action)
                context_menu.insert(item, 2)
        else:
            # Add an item for open all images
            if view.is_loading() or parsed.scheme not in ["http", "https"]:
                return
            # FIXME https://bugs.webkit.org/show_bug.cgi?id=159631
            # Introspection missing, Gtk.Action deprecated
            action = Gtk.Action.new("save_imgs", _("Save images"), None, None)
            action.connect(
                "activate",
                self.__on_save_images_activate,
            )
            item = WebKit2.ContextMenuItem.new(action)
            n_items = context_menu.get_n_items()
            if El().settings.get_value("developer-extras"):
                context_menu.insert(item, n_items - 2)
            else:
                context_menu.insert(item, n_items)

    def __on_open_new_page_activate(self, action, uri):
        """
            Open link in a new page
            @param action as Gtk.Action
            @param uri as str
        """
        self._window.container.add_webview(uri, Gdk.WindowType.CHILD,
                                           self.ephemeral)

    def __on_search_words_activate(self, action, selection):
        """
            Open link in a new page
            @param action as Gtk.Action
            @param selection as str
        """
        search = Search()
        uri = search.get_search_uri(selection)
        self._window.container.add_webview(uri, Gdk.WindowType.CHILD)

    def __on_copy_text_activate(self, action, selection):
        """
            Open link in a new page
            @param action as Gtk.Action
            @param selection as str
        """
        Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD).set_text(selection, -1)

    def __on_save_images_activate(self, action):
        """
            Show images filtering popover
            @param action as Gtk.Action
        """
        self._window.toolbar.end.save_images(self.get_uri(),
                                             self.get_page_id())

    def __on_scroll_event(self, webview, event):
        """
            Adapt scroll speed to device
            @param webview as WebView
            @param event as Gdk.EventScroll
        """
        source = event.get_source_device().get_source()
        if event.state & Gdk.ModifierType.CONTROL_MASK:
            if source == Gdk.InputSource.MOUSE:
                if event.delta_y < 0.5:
                    webview.zoom_in()
                elif event.delta_y > 0.5:
                    webview.zoom_out()
            else:
                if event.delta_y > 0.5:
                    webview.zoom_in()
                elif event.delta_y < -0.5:
                    webview.zoom_out()
            return True
        elif source == Gdk.InputSource.MOUSE:
            event.delta_x *= 2
            event.delta_y *= 2
        # if self.__input_source != source:
        #    self.__input_source = source
        #    self.__set_smooth_scrolling(source)

    def __on_run_file_chooser(self, webview, request):
        """
            Run own file chooser
            @param webview as WebView
            @param request as WebKit2.FileChooserRequest
        """
        uri = webview.get_uri()
        dialog = Gtk.FileChooserNative.new(_("Select files to upload"),
                                           self._window,
                                           Gtk.FileChooserAction.OPEN,
                                           _("Open"), _("Cancel"))
        dialog.set_select_multiple(request.get_select_multiple())
        chooser_uri = El().websettings.get_chooser_uri(uri)
        if chooser_uri is not None:
            dialog.set_current_folder_uri(chooser_uri)
        response = dialog.run()
        if response in [
                Gtk.ResponseType.DELETE_EVENT, Gtk.ResponseType.CANCEL
        ]:
            request.cancel()
        else:
            request.select_files(dialog.get_filenames())
            El().websettings.set_chooser_uri(dialog.get_current_folder_uri(),
                                             uri)
        return True

    def __on_script_dialog(self, webview, dialog):
        """
            Show message to user
            @param webview as WebView
            @param dialog as WebKit2.ScriptDialog
        """
        if dialog.get_message().startswith("@&$%ù²"):
            self._readable_content = dialog.get_message().replace("@&$%ù²", "")
            self.emit("readable")
            return True

    def __on_map(self, webview):
        """
            Connect signals
            @parma webview as WebView
        """
        page_id = webview.get_page_id()
        El().helper.connect(None, self.__on_signal, page_id)

    def __on_unmap(self, webview):
        """
            Disconnect signals
            @parma webview as WebView
        """
        page_id = webview.get_page_id()
        El().helper.disconnect(page_id)

    def __on_password(self, attributes, password, uri, index, count, popover,
                      model):
        """
            Show form popover
            @param attributes as {}
            @param password as str
            @param uri as str
            @param index as int
            @param count as int
            @param popover as Gtk.Popover
            @param model as Gio.MenuModel
        """
        parsed = urlparse(uri)
        self.__last_click_event = {}
        if attributes is not None and (count > 1 or parsed.scheme == "http"):
            parsed = urlparse(uri)
            submit_uri = "%s://%s" % (parsed.scheme, parsed.netloc)
            if submit_uri == attributes["formSubmitURL"]:
                model.add_attributes(attributes, uri)
                if index == 0:
                    popover.popup()

    def __on_signal(self, connection, sender, path, interface, signal, params):
        """
            Add video to download manager
            @param connection as Gio.DBusConnection
            @param sender as str
            @param path as str
            @param interface as str
            @param signal as str
            @param parameters as GLib.Variant
        """
        if signal == "VideoInPage":
            uri = params[0]
            title = params[1]
            page_id = params[2]
            El().download_manager.add_video(uri, title, page_id)
        elif signal == "UnsecureFormFocused":
            self._window.toolbar.title.show_input_warning(self)
        elif signal == "InputMouseDown":
            if self.__last_click_event:
                model = FormMenu(params[0], self.get_page_id())
                popover = Gtk.Popover.new_from_model(self, model)
                popover.set_modal(False)
                self._window.register(popover)
                rect = Gdk.Rectangle()
                rect.x = self.__last_click_event["x"]
                rect.y = self.__last_click_event["y"] - 10
                rect.width = rect.height = 1
                popover.set_pointing_to(rect)
                helper = PasswordsHelper()
                helper.get(self.get_uri(), self.__on_password, popover, model)
Пример #10
0
class WebView(WebKit2.WebView):
    """
        WebKit view
    """

    def new(window, view):
        """
            New webview
            @param window as Window
            @param view as View
        """
        context = WebKit2.WebContext.new()
        Context(context)
        webview = WebKit2.WebView.new_with_context(context)
        content_manager = webview.get_property("user-content-manager")
        webview.__class__ = WebViewMeta
        webview.__init(None, context, content_manager, window, view)
        return webview

    def new_ephemeral(window, view):
        """
            New ephemeral webview
            @param window as Window
            @param view as View
        """
        context = WebKit2.WebContext.new_ephemeral()
        Context(context)
        webview = WebKit2.WebView.new_with_context(context)
        webview.__class__ = WebViewMeta
        content_manager = webview.get_property("user-content-manager")
        webview.__init(None, context, content_manager, window, view)
        return webview

    def new_with_related_view(related, window):
        """
            Create a new WebView related to view
            @param related as WebView
            @param window as Window
            @return WebView
        """
        webview = WebKit2.WebView.new_with_related_view(related)
        webview.__class__ = WebViewMeta
        # Related view are linked to related context, can't do anything about
        # this
        webview.__init(related, related.context,
                       related.content_manager, window, None)
        return webview

    def set_setting(self, key, value):
        """
            Set setting to value
            @param key as str
            @param value as GLib.Variant
        """
        settings = self.get_settings()
        if key == 'use-system-fonts':
            self.__set_system_fonts(settings)
        else:
            settings.set_property(key, value)

    def update_zoom_level(self):
        """
            Update zoom level
        """
        try:
            zoom_level = App().websettings.get_zoom(self.uri)
            if zoom_level is None:
                zoom_level = 100
            if self.__related_view is None:
                zoom_level *= self._window.zoom_level
            else:
                window = self.__related_view.get_ancestor(Gtk.Window)
                if window is not None and hasattr(window, "zoom_level"):
                    zoom_level *= window.zoom_level
        except Exception as e:
            Logger.error("WebView::update_zoom_level(): %s", e)
        Logger.debug("Update zoom level: %s", zoom_level)
        self.set_zoom_level(zoom_level / 100)

    def print(self):
        """
            Show print dialog for current page
        """
        p = WebKit2.PrintOperation.new(self)
        p.run_dialog()

    def zoom_in(self):
        """
            Zoom in view
            @return current zoom after zoom in
        """
        current = App().websettings.get_zoom(self.uri)
        if current is None:
            current = 100
        current += 10
        App().websettings.set_zoom(current, self.uri)
        self.update_zoom_level()
        return current

    def zoom_out(self):
        """
            Zoom out view
            @return current zoom after zoom out
        """
        current = App().websettings.get_zoom(self.uri)
        if current is None:
            current = 100
        current -= 10
        if current == 0:
            return 10
        App().websettings.set_zoom(current, self.uri)
        self.update_zoom_level()
        return current

    def zoom_default(self):
        """
            Reset zoom level
            @return current zoom after zoom out
        """
        App().websettings.set_zoom(100, self.uri)
        self.update_zoom_level()

    def set_title(self, title):
        """
            Set title, will be returned by title property until title is set
            by WebView
            @param title as str
        """
        self._title = title
        self.emit("title-changed", title)

    def set_uri(self, uri):
        """
            Set delayed uri
            @param uri as str
        """
        self.__uri = uri
        self.emit("uri-changed", uri)

    def update_spell_checking(self, uri):
        """
            Update spell checking
        """
        context = self.get_context()
        codes = App().websettings.get_languages(uri)
        # If None, default user language
        if codes is None:
            locales = GLib.get_language_names()
            try:
                codes = [locales[0].split(".")[0]]
            except:
                codes = None
        if context.get_spell_checking_languages() != codes:
            context.set_spell_checking_languages(codes)

    def add_text_entry(self, text):
        """
            Add an uri to text entry list
            @param text as str
        """
        if text and text != self.__text_entry.value:
            item = LinkedList(text, None, self.__text_entry)
            self.__text_entry = item

    def clear_text_entry(self):
        """
            Clear text entry history
        """
        self.__text_entry = LinkedList("", None, None)

    def get_current_text_entry(self):
        """
            Get currnet text entry value
            @return text as str
        """
        current = None
        if self.__text_entry is not None:
            current = self.__text_entry.value
        return current

    def get_prev_text_entry(self, current_value=None):
        """
            Get previous text entry value
            @param current_value as str
            @return text as str
        """
        previous = None
        if self.__text_entry.prev is not None:
            # Append current to list as it is missing
            if current_value != self.__text_entry.value:
                item = LinkedList(current_value, None, self.__text_entry)
                self.__text_entry.set_next(item)
                previous = self.__text_entry.value
            else:
                current = self.__text_entry
                previous = self.__text_entry.prev.value
                if previous is not None:
                    self.__text_entry = self.__text_entry.prev
                    self.__text_entry.set_next(current)
        return previous

    def get_next_text_entry(self):
        """
            Get next text entry value
            @return text as str
        """
        next = None
        if self.__text_entry.next is not None:
            next = self.__text_entry.next.value
            if next is not None:
                self.__text_entry = self.__text_entry.next
        return next

    def new_page(self, uri, loading_type):
        """
            Open a new page
            @param uri as uri
            @param loading_type as Gdk.LoadingType
        """
        parsed = urlparse(uri)
        if App().settings.get_value("adblock") and\
                parsed.scheme in ["http", "https"] and\
                not App().adblock_exceptions.find_parsed(parsed):
            if App().adblock.is_netloc_blocked(parsed.netloc) or\
                    App().adblock.is_uri_blocked(uri,
                                                 parsed.netloc):
                Logger.debug("WebView::new_page(): blocking %s ->%s",
                             uri, self.uri)
                return True
        if loading_type == LoadingType.POPOVER:
            if self.ephemeral:
                webview = WebView.new_ephemeral(self._window, None)
            else:
                webview = WebView.new(self._window, None)
            self._window.container.popup_webview(webview, True)
            GLib.idle_add(webview.load_uri, uri)
        else:
            self.__new_pages_opened += 1
            webview = self._window.container.add_webview(
                uri,
                loading_type,
                self.ephemeral,
                None,
                self.atime -
                self.__new_pages_opened)
            webview.set_parent(self)
            self.add_child(webview)

    def set_parent(self, parent):
        """
            Set webview parent
            @param parent as WebView
        """
        self.__parent = parent

    def set_atime(self, atime):
        """
            Update access time
            @param atime as int
        """
        self.__atime = atime

    def set_view(self, view):
        """
            Set webview view
            @param view as View
        """
        self.__view = view

    def set_window(self, window):
        """
            Set webview window
            @param window as Window
        """
        self._window = window

    def add_child(self, child):
        """
            Add a child to webview
            @param child as WebView
        """
        if child not in self.__children:
            self.__children.insert(0, child)

    def remove_child(self, child):
        """
            Remove child from webview
            @param child as WebView
        """
        if child in self.__children:
            self.__children.remove(child)

    @property
    def content_manager(self):
        """
            Get content manager
            @return WebKit2.UserContentManager
        """
        return self.__content_manager

    @property
    def context(self):
        """
            Get context
            @return WebKit2.WebContext
        """
        return self.__context

    @property
    def atime(self):
        """
            Get access time
            @return int
        """
        return self.__atime

    @property
    def children(self):
        """
            Get page children
            @return [WebView]
        """
        return self.__children

    @property
    def parent(self):
        """
            Get page parent
            @return WebView/None
        """
        return self.__parent

    @property
    def view(self):
        """
            Get view
            @return View
        """
        return self.__view

    @property
    def shown(self):
        """
            True if page already shown on screen (one time)
        """
        return self._shown

    @property
    def title(self):
        """
            Get title (loaded or unloaded)
            @return str
        """
        title = self.get_title()
        if title is None:
            title = self._title
        if title is None:
            title = self.uri
        return title

    @property
    def uri(self):
        """
            Get uri (loaded or unloaded)
            @return str
        """
        uri = self.get_uri()
        if uri is None:
            uri = self.__uri
        return uri

    @property
    def netloc(self):
        """
            Get netloc
            @return str
        """
        uri = self.uri
        parsed = urlparse(uri)
        return parsed.netloc or ""

    @property
    def ephemeral(self):
        """
            True if view is private/ephemeral
            @return bool
        """
        return self.get_property("is-ephemeral")

    @property
    def selection(self):
        """
            Get current selection
            @return str
        """
        return self.__selection

    @property
    def readable_content(self):
        """
            Readable content
            @return content as str
        """
        return self._readable_content

#######################
# PRIVATE             #
#######################
    def __init(self, related_view, context, content_manager, window, view):
        """
            Init WebView
            @param related_view as WebView
            @param context as WebKit2.WebContext
            @param content_manager as WebKit2.UserContentManager
            @param window as Window
            @param view as View
        """
        WebViewErrors.__init__(self)
        WebViewNavigation.__init__(self, related_view)
        WebViewSignals.__init__(self)
        WebViewArtwork.__init__(self)
        self._window = window
        self.__view = view
        self.__context = context
        self.__content_manager = content_manager
        self.__atime = 0
        self.__children = []
        self.__parent = None
        self.__new_pages_opened = 0
        # WebKitGTK doesn't provide an API to get selection, so try to guess
        # it from clipboard FIXME Get it from extensions
        self.__selection = ""
        self._readable_content = ""
        self.__uri = None
        self._title = None
        self.__related_view = related_view
        self._shown = False
        self.set_hexpand(True)
        self.set_vexpand(True)
        self.clear_text_entry()
        # Set settings
        settings = self.get_settings()
        system = Gio.Settings.new("org.gnome.desktop.interface")
        animations = system.get_value("enable-animations")
        settings.set_property("enable-java",
                              App().settings.get_value('enable-plugins'))
        settings.set_property("enable-plugins",
                              App().settings.get_value('enable-plugins'))
        settings.set_property("minimum-font-size",
                              App().settings.get_value(
                                  "min-font-size").get_int32())
        if App().settings.get_value("use-system-fonts"):
            self.__set_system_fonts(settings, system)
        else:
            settings.set_property("monospace-font-family",
                                  App().settings.get_value(
                                      "font-monospace").get_string())
            settings.set_property("sans-serif-font-family",
                                  App().settings.get_value(
                                      "font-sans-serif").get_string())
            settings.set_property("serif-font-family",
                                  App().settings.get_value(
                                      "font-serif").get_string())
        settings.set_property("auto-load-images", True)
        settings.set_property("enable-site-specific-quirks", True)
        settings.set_property("allow-universal-access-from-file-urls", False)
        settings.set_property("allow-file-access-from-file-urls", False)
        settings.set_property("enable-javascript", True)
        settings.set_property("enable-media-stream", True)
        settings.set_property("enable-mediasource", False)
        settings.set_property("enable-developer-extras",
                              App().settings.get_value("developer-extras"))
        settings.set_property("enable-offline-web-application-cache", True)
        settings.set_property("enable-page-cache", True)
        settings.set_property("enable-resizable-text-areas", True)
        settings.set_property("enable-smooth-scrolling", animations)
        settings.set_property("enable-webaudio", True)
        settings.set_property("enable-webgl", True)
        settings.set_property("javascript-can-access-clipboard", True)
        settings.set_property("javascript-can-open-windows-automatically",
                              True)
        settings.set_property("media-playback-allows-inline", True)
        self.connect("create", self.__on_create)
        self.connect("load-changed", self._on_load_changed)

    def __set_system_fonts(self, settings, system=None):
        """
            Set system font
            @param settings as WebKit2.Settings
            @param system as Gio.Settings("org.gnome.desktop.interface")
        """
        if system is None:
            system = Gio.Settings.new("org.gnome.desktop.interface")
        settings.set_property(
            "monospace-font-family",
            system.get_value("monospace-font-name").get_string())
        settings.set_property(
            "sans-serif-font-family",
            system.get_value("document-font-name").get_string())
        settings.set_property(
            "serif-font-family",
            system.get_value("font-name").get_string())

    def __on_create(self, related, navigation_action):
        """
            Create a new view for action
            @param related as WebView
            @param navigation_action as WebKit2.NavigationAction
        """
        webview = WebView.new_with_related_view(related, self._window)
        webview.set_atime(related.atime - 1)
        elapsed = time() - related._last_click_time
        webview.connect("ready-to-show",
                        self.__on_ready_to_show,
                        related,
                        navigation_action,
                        elapsed)
        webview.set_parent(self)
        self.add_child(webview)
        return webview

    def __on_ready_to_show(self, webview, related, navigation_action, elapsed):
        """
            Add a new webview with related
            @param webview as WebView
            @param related as WebView
            @param navigation_action as WebKit2.NavigationAction
            @param elapsed as float
        """
        def on_load_changed(webview, event):
            parsed = urlparse(webview.uri)
            # First, adblocking
            if not parsed.netloc:
                return
            if App().settings.get_value("adblock") and\
                    parsed.scheme in ["http", "https"] and\
                    not App().adblock_exceptions.find_parsed(parsed):
                if App().adblock.is_netloc_blocked(parsed.netloc) or\
                        App().adblock.is_uri_blocked(webview.uri,
                                                     parsed.netloc):
                    webview.destroy()
                    return
            if event != WebKit2.LoadEvent.FINISHED:
                return
            else:
                webview.disconnect_by_func(on_load_changed)

            # Then popup blocking
            popup_block = App().settings.get_value("popupblock")
            if related.uri is not None:
                parsed_related = urlparse(related.uri)
                exception = elapsed < 1.0 or\
                    App().popup_exceptions.find_parsed(parsed_related)
            else:
                exception = False

            properties = webview.get_window_properties()
            if not exception and popup_block and\
                    navigation_action.get_navigation_type() in [
                        WebKit2.NavigationType.OTHER,
                        WebKit2.NavigationType.RELOAD,
                        WebKit2.NavigationType.BACK_FORWARD]:
                related.add_popup(webview)
                webview.connect("close", self.__on_popup_close, related)
                if related == self._window.container.current.webview:
                    self._window.toolbar.title.show_indicator(
                        Indicator.POPUPS)
            elif (properties.get_toolbar_visible() or
                    properties.get_scrollbars_visible()) and\
                    not self._window.modifiers == Gdk.KEY_Shift_L:
                self._window.container.add_webview_with_new_view(
                    webview,
                    LoadingType.FOREGROUND)
            else:
                self._window.container.popup_webview(webview, True)

        webview.connect("load-changed", on_load_changed)

    def __on_popup_close(self, webview, related):
        """
            Remove webview from popups
            @param webview as WebView
            @param related as WebView
        """
        related.remove_popup(webview)
        if self._window.container.current.webview == related and\
                not related.popups:
            self._window.toolbar.title.show_indicator(Indicator.NONE)