diff options
-rw-r--r-- | browser.py | 55 | ||||
-rw-r--r-- | icons/save-to-journal.svg | 109 | ||||
-rw-r--r-- | pdfviewer.py | 420 | ||||
-rw-r--r-- | viewtoolbar.py | 23 | ||||
-rw-r--r-- | webtoolbar.py | 12 |
5 files changed, 613 insertions, 6 deletions
@@ -36,6 +36,7 @@ from sugar3.graphics.icon import Icon from widgets import BrowserNotebook import globalhistory import downloadmanager +from pdfviewer import PDFTabPage _ZOOM_AMOUNT = 0.1 _LIBRARY_PATH = '/usr/share/library-common/index.html' @@ -164,9 +165,25 @@ class TabbedView(BrowserNotebook): new_browser.load_uri(url) new_browser.grab_focus() + def __open_pdf_in_new_tab_cb(self, browser, url): + tab_page = PDFTabPage() + tab_page.browser.connect('new-tab', self.__new_tab_cb) + tab_page.browser.connect('tab-close', self.__tab_close_cb) + + label = TabLabel(tab_page.browser) + label.connect('tab-close', self.__tab_close_cb, tab_page) + + next_index = self.get_current_page() + 1 + self.insert_page(tab_page, label, next_index) + tab_page.show() + label.show() + self.set_current_page(next_index) + tab_page.setup(url) + def add_tab(self, next_to_current=False): browser = Browser() browser.connect('new-tab', self.__new_tab_cb) + browser.connect('open-pdf', self.__open_pdf_in_new_tab_cb) if next_to_current: self._insert_tab_next(browser) @@ -271,11 +288,31 @@ class TabbedView(BrowserNotebook): while self.get_n_pages(): self.remove_page(self.get_n_pages() - 1) + def is_pdf_history(tab_history): + return (len(tab_history) == 1 and + tab_history[0]['url'].lower().endswith('pdf')) + for tab_history in tab_histories: - browser = Browser() - browser.connect('new-tab', self.__new_tab_cb) - self._append_tab(browser) - browser.set_history(tab_history) + if is_pdf_history(tab_history): + url = tab_history[0]['url'] + tab_page = PDFTabPage() + tab_page.browser.connect('new-tab', self.__new_tab_cb) + tab_page.browser.connect('tab-close', self.__tab_close_cb) + + label = TabLabel(tab_page.browser) + label.connect('tab-close', self.__tab_close_cb, tab_page) + + self.append_page(tab_page, label) + tab_page.show() + label.show() + tab_page.setup(url, title=tab_history[0]['title']) + + else: + browser = Browser() + browser.connect('new-tab', self.__new_tab_cb) + browser.connect('open-pdf', self.__open_pdf_in_new_tab_cb) + self._append_tab(browser) + browser.set_history(tab_history) Gtk.rc_parse_string(''' @@ -418,6 +455,9 @@ class Browser(WebKit.WebView): 'new-tab': (GObject.SignalFlags.RUN_FIRST, None, ([str])), + 'open-pdf': (GObject.SignalFlags.RUN_FIRST, + None, + ([str])), } CURRENT_SUGAR_VERSION = '0.96' @@ -529,7 +569,12 @@ class Browser(WebKit.WebView): def __mime_type_policy_cb(self, webview, frame, request, mimetype, policy_decision): - if not self.can_show_mime_type(mimetype): + if mimetype == 'application/pdf': + self.emit('open-pdf', request.get_uri()) + return False + elif self.can_show_mime_type(mimetype): + return True + else: policy_decision.download() return True diff --git a/icons/save-to-journal.svg b/icons/save-to-journal.svg new file mode 100644 index 0000000..a42436c --- /dev/null +++ b/icons/save-to-journal.svg @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.1" + width="55" + height="55" + viewBox="0 0 55 55" + id="svg2" + xml:space="preserve"><metadata + id="metadata25"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs33"> +</defs><g + transform="matrix(0.75578519,0,0,0.75578519,-4.9396196,-1.2911009)" + id="clipping-text" + style="fill:none;stroke:#ffffff;stroke-opacity:1;display:block"> + <g + id="g3152" + style="fill:none;stroke:#ffffff;stroke-opacity:1;display:inline"> + <g + id="g3154" + style="fill:none;stroke:#ffffff;stroke-opacity:1"> + <polygon + points="31.874,6.088 43.818,18.027 43.818,48.914 10.932,48.914 10.932,6.088 " + id="polygon3156" + style="fill:none;stroke:#ffffff;stroke-width:3.5;stroke-opacity:1" /> + <polyline + id="polyline3158" + points="43.818,18.027 31.874,18.027 31.874,6.088 " + style="fill:none;stroke:#ffffff;stroke-width:3.5;stroke-opacity:1" /> + </g> + </g> + <line + id="line3160" + y2="26.25" + y1="26.25" + x2="36.875" + x1="17.875" + display="inline" + style="fill:none;stroke:#ffffff;stroke-width:3.5;stroke-opacity:1;display:inline" /> + <line + id="line3162" + y2="33.25" + y1="33.25" + x2="36.875" + x1="17.875" + display="inline" + style="fill:none;stroke:#ffffff;stroke-width:3.5;stroke-opacity:1;display:inline" /> + <line + id="line3164" + y2="40.25" + y1="40.25" + x2="36.875" + x1="17.875" + display="inline" + style="fill:none;stroke:#ffffff;stroke-width:3.5;stroke-opacity:1;display:inline" /> +</g><g + id="g3830"><g + transform="matrix(0.55205508,0,0,0.55205508,75.618464,18.235971)" + id="g4382"><g + transform="translate(-80.093659,12.220029)" + id="g4308" + style="fill:none;stroke:#ffffff;stroke-opacity:1"><g + id="g4310" + style="fill:none;stroke:#ffffff;stroke-opacity:1"><path + d="m 6.736,49.002 h 24.52 c 2.225,0 3.439,-1.447 3.439,-3.441 v -27.28 c 0,-1.73 -1.732,-3.441 -3.439,-3.441 h -4.389" + id="path4312" + style="fill:none;stroke:#ffffff;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /></g></g><g + transform="translate(-80.093659,12.220029)" + id="g4314" + style="fill:none;stroke:#ffffff;stroke-opacity:1"><g + id="g4316" + style="fill:none;stroke:#ffffff;stroke-opacity:1"><path + d="m 26.867,38.592 c 0,1.836 -1.345,3.201 -3.441,4.047 L 6.736,49.002 V 14.84 l 16.69,-8.599 c 2.228,-0.394 3.441,0.84 3.441,2.834 v 29.517 z" + id="path4318" + style="fill:none;stroke:#ffffff;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /></g></g><path + d="m -70.669659,54.827029 c 0,0 -1.351,-0.543 -2.702,-0.543 -1.351,0 -2.703,0.543 -2.703,0.543" + id="path4320" + style="fill:none;stroke:#ffffff;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /><path + d="m -70.669659,44.226029 c 0,0 -1.239,-0.543 -2.815,-0.543 -1.577,0 -2.59,0.543 -2.59,0.543" + id="path4322" + style="fill:none;stroke:#ffffff;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /><path + d="m -70.669659,33.898029 c 0,0 -1.125,-0.544 -2.927,-0.544 -1.802,0 -2.478,0.544 -2.478,0.544" + id="path4324" + style="fill:none;stroke:#ffffff;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /><line + id="line4326" + y2="23.725029" + y1="58.753029" + x2="-66.884659" + x1="-66.884659" + style="fill:none;stroke:#ffffff;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /></g><g + transform="matrix(1,0,0,-1,-30.386573,49.171266)" + id="g4770"><g + transform="translate(34.0803,-1006.42)" + id="g4772"><polyline + id="polyline4774" + points="51.562,15.306 41.17,16.188 42.053,5.794" + style="fill:none;stroke:#ffffff;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round" + transform="matrix(-0.469241,0.469241,-0.469241,-0.469241,66.2906,1019.03)" /><path + d="m 39.363241,1033.1291 -0.05636,9.9115 -8.750608,0.067" + id="path4776" + style="fill:none;stroke:#ffffff;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /></g></g></g></svg> diff --git a/pdfviewer.py b/pdfviewer.py new file mode 100644 index 0000000..c7e2452 --- /dev/null +++ b/pdfviewer.py @@ -0,0 +1,420 @@ +# Copyright (C) 2012, One Laptop Per Child +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import os +import logging +import tempfile +import threading +from gettext import gettext as _ + +from gi.repository import GObject +from gi.repository import Gtk +from gi.repository import GLib +from gi.repository import EvinceDocument +from gi.repository import EvinceView +from gi.repository import WebKit + +from sugar3.graphics.toolbarbox import ToolbarBox +from sugar3.graphics.toolbutton import ToolButton +from sugar3.datastore import datastore +from sugar3.activity import activity + + +class EvinceViewer(Gtk.Overlay): + """PDF viewer with a toolbar overlay for basic navigation and an + option to save to Journal. + + """ + __gsignals__ = { + 'save-to-journal': (GObject.SignalFlags.RUN_FIRST, + None, + ([])), + 'open-link': (GObject.SignalFlags.RUN_FIRST, + None, + ([str])), + } + + def __init__(self, uri): + GObject.GObject.__init__(self) + + self._uri = uri + + # Create Evince objects to handle the PDF in the URI: + EvinceDocument.init() + self._doc = EvinceDocument.Document.factory_get_document(uri) + self._view = EvinceView.View() + self._model = EvinceView.DocumentModel() + self._model.set_document(self._doc) + self._view.set_model(self._model) + + self._view.connect('external-link', self.__handle_link_cb) + self._model.connect('page-changed', self.__page_changed_cb) + + self._back_page_button = None + self._forward_page_button = None + self._toolbar_box = self._create_toolbar() + self._update_nav_buttons() + + self._toolbar_box.set_halign(Gtk.Align.FILL) + self._toolbar_box.set_valign(Gtk.Align.END) + self.add_overlay(self._toolbar_box) + self._toolbar_box.show() + + scrolled_window = Gtk.ScrolledWindow() + self.add(scrolled_window) + scrolled_window.show() + + scrolled_window.add(self._view) + self._view.show() + + def _create_toolbar(self): + toolbar_box = ToolbarBox() + + zoom_out_button = ToolButton('zoom-out') + zoom_out_button.set_tooltip(_('Zoom out')) + zoom_out_button.connect('clicked', self.__zoom_out_cb) + toolbar_box.toolbar.insert(zoom_out_button, -1) + zoom_out_button.show() + + zoom_in_button = ToolButton('zoom-in') + zoom_in_button.set_tooltip(_('Zoom in')) + zoom_in_button.connect('clicked', self.__zoom_in_cb) + toolbar_box.toolbar.insert(zoom_in_button, -1) + zoom_in_button.show() + + separator = Gtk.SeparatorToolItem() + separator.props.draw = True + toolbar_box.toolbar.insert(separator, -1) + separator.show() + + self._back_page_button = ToolButton('go-previous-paired') + self._back_page_button.set_tooltip(_('Previous page')) + self._back_page_button.props.sensitive = False + self._back_page_button.connect('clicked', self.__go_back_page_cb) + toolbar_box.toolbar.insert(self._back_page_button, -1) + self._back_page_button.show() + + self._forward_page_button = ToolButton('go-next-paired') + self._forward_page_button.set_tooltip(_('Next page')) + self._forward_page_button.props.sensitive = False + self._forward_page_button.connect('clicked', self.__go_forward_page_cb) + toolbar_box.toolbar.insert(self._forward_page_button, -1) + self._forward_page_button.show() + + separator = Gtk.SeparatorToolItem() + separator.props.draw = True + toolbar_box.toolbar.insert(separator, -1) + separator.show() + + self._save_to_journal_button = ToolButton('save-to-journal') + self._save_to_journal_button.set_tooltip(_('Save PDF to Journal')) + self._save_to_journal_button.connect('clicked', + self.__save_to_journal_button_cb) + toolbar_box.toolbar.insert(self._save_to_journal_button, -1) + self._save_to_journal_button.show() + + return toolbar_box + + def disable_journal_button(self): + self._save_to_journal_button.props.sensitive = False + + def __handle_link_cb(self, widget, url): + self.emit('open-link', url.get_uri()) + + def __page_changed_cb(self, model, page_from, page_to): + self._update_nav_buttons() + + def __zoom_out_cb(self, widget): + self.zoom_out() + + def __zoom_in_cb(self, widget): + self.zoom_in() + + def __go_back_page_cb(self, widget): + self._view.previous_page() + + def __go_forward_page_cb(self, widget): + self._view.next_page() + + def __save_to_journal_button_cb(self, widget): + self.emit('save-to-journal') + self._save_to_journal_button.props.sensitive = False + + def _update_nav_buttons(self): + current_page = self._model.props.page + self._back_page_button.props.sensitive = current_page > 0 + self._forward_page_button.props.sensitive = \ + current_page < self._doc.get_n_pages() - 1 + + def zoom_in(self): + self._model.props.sizing_mode = EvinceView.SizingMode.FREE + self._view.zoom_in() + + def zoom_out(self): + self._model.props.sizing_mode = EvinceView.SizingMode.FREE + self._view.zoom_out() + + def get_pdf_title(self): + return self._doc.get_title() + + +class DummyBrowser(GObject.GObject): + """Has the same interface as browser.Browser .""" + __gsignals__ = { + 'new-tab': (GObject.SignalFlags.RUN_FIRST, None, ([str])), + 'tab-close': (GObject.SignalFlags.RUN_FIRST, None, ([object])), + 'selection-changed': (GObject.SignalFlags.RUN_FIRST, None, ([])), + } + + __gproperties__ = { + "title": (object, "title", "Title", GObject.PARAM_READWRITE), + "uri": (object, "uri", "URI", GObject.PARAM_READWRITE), + "progress": (object, "progress", "Progress", GObject.PARAM_READWRITE), + "load-status": (object, "load status", "a WebKit LoadStatus", + GObject.PARAM_READWRITE), + } + + def __init__(self, tab): + GObject.GObject.__init__(self) + self._tab = tab + self._title = "" + self._uri = "" + self._progress = 0.0 + self._load_status = WebKit.LoadStatus.PROVISIONAL + + def do_get_property(self, prop): + if prop.name == 'title': + return self._title + elif prop.name == 'uri': + return self._uri + elif prop.name == 'progress': + return self._progress + elif prop.name == 'load-status': + return self._load_status + else: + raise AttributeError, 'Unknown property %s' % prop.name + + def do_set_property(self, prop, value): + if prop.name == 'title': + self._title = value + elif prop.name == 'uri': + self._uri = value + elif prop.name == 'progress': + self._progress = value + elif prop.name == 'load-status': + self._load_status = value + else: + raise AttributeError, 'Unknown property %s' % prop.name + + def get_title(self): + return self._title + + def get_uri(self): + return self._uri + + def get_progress(self): + return self._progress + + def get_load_status(self): + return self._load_status + + def emit_new_tab(self, uri): + self.emit('new-tab', uri) + + def emit_close_tab(self): + self.emit('tab-close', self._tab) + + def get_history(self): + return [{'url': self.props.uri, 'title': self.props.title}] + + def can_undo(self): + return False + + def can_redo(self): + return False + + def can_go_back(self): + return False + + def can_go_forward(self): + return False + + def can_copy_clipboard(self): + return False + + def can_paste_clipboard(self): + return False + + def set_history_index(self, index): + pass + + def get_history_index(self): + return 0 + + def stop_loading(self): + self._tab.cancel_download() + + def reload(self): + pass + + +class PDFTabPage(Gtk.HBox): + """Shows a basic PDF viewer, download the file first if the PDF is + in a remote location. + + """ + def __init__(self): + GObject.GObject.__init__(self) + self._browser = DummyBrowser(self) + self._evince_viewer = None + self._pdf_uri = None + self._requested_uri = None + + def setup(self, requested_uri, title=None): + self._requested_uri = requested_uri + + # The title may be given from the Journal: + if title is not None: + self._browser.props.title = title + else: + self._browser.props.title = os.path.basename(requested_uri) + + self._browser.props.uri = requested_uri + self._browser.props.load_status = WebKit.LoadStatus.PROVISIONAL + + # show PDF directly if the file is local (from the system tree + # or from the journal) + + if requested_uri.startswith('file://'): + self._pdf_uri = requested_uri + self._show_pdf() + + elif requested_uri.startswith('journal://'): + self._pdf_uri = self._get_path_from_journal(requested_uri) + self._show_pdf(from_journal=True) + + # download first if file is remote + + elif requested_uri.startswith('http://'): + self._download_from_http(requested_uri) + + def _get_browser(self): + return self._browser + + browser = GObject.property(type=object, getter=_get_browser) + + def _show_pdf(self, from_journal=False): + self._evince_viewer = EvinceViewer(self._pdf_uri) + self._evince_viewer.connect('save-to-journal', + self.__save_to_journal_cb) + self._evince_viewer.connect('open-link', + self.__open_link_cb) + + # disable save to journal if the PDF is already loaded from + # the journal: + if from_journal: + self._evince_viewer.disable_journal_button() + + self._evince_viewer.show() + self.pack_start(self._evince_viewer, True, True, 0) + + # if the PDF has a title, show it instead of the URI: + pdf_title = self._evince_viewer.get_pdf_title() + if pdf_title is not None: + self._browser.props.title = pdf_title + + def _get_path_from_journal(self, journal_uri): + """Get the system tree URI of the file for the Journal object.""" + journal_id = self.__journal_id_from_uri(journal_uri) + jobject = datastore.get(journal_id) + return 'file://' + jobject.file_path + + def _download_from_http(self, remote_uri): + """Download the PDF from a remote location to a temporal file.""" + + # Figure out download URI + temp_path = os.path.join(activity.get_activity_root(), 'instance') + if not os.path.exists(temp_path): + os.makedirs(temp_path) + + fd, dest_path = tempfile.mkstemp(dir=temp_path) + + self._pdf_uri = 'file://' + dest_path + + network_request = WebKit.NetworkRequest.new(remote_uri) + self._download = WebKit.Download.new(network_request) + self._download.set_destination_uri('file://' + dest_path) + + self._download.connect('notify::progress', self.__download_progress_cb) + self._download.connect('notify::status', self.__download_status_cb) + self._download.connect('error', self.__download_error_cb) + + self._download.start() + + def __download_progress_cb(self, download, data): + progress = download.get_progress() + self._browser.props.load_status = WebKit.LoadStatus.PROVISIONAL + self._browser.props.progress = progress + + def __download_status_cb(self, download, data): + status = download.get_status() + if status == WebKit.DownloadStatus.STARTED: + self._browser.props.load_status = WebKit.LoadStatus.PROVISIONAL + elif status == WebKit.DownloadStatus.FINISHED: + self._browser.props.load_status = WebKit.LoadStatus.FINISHED + self._show_pdf() + elif status == WebKit.DownloadStatus.CANCELLED: + logging.debug('Download PDF canceled') + + def __download_error_cb(self, download, err_code, err_detail, reason): + logging.debug('Download error! code %s, detail %s: %s' % \ + (err_code, err_detail, reason)) + + def cancel_download(self): + self._download.cancel() + self._browser.emit_close_tab() + + def __journal_id_to_uri(self, journal_id): + """Return an URI for a Journal object ID.""" + return "journal://" + journal_id + ".pdf" + + def __journal_id_from_uri(self, journal_uri): + """Return a Journal object ID from an URI.""" + return journal_uri[len("journal://"):-len(".pdf")] + + def __save_to_journal_cb(self, widget): + """Save the PDF in the Journal. + + Put the PDF title as the title, or if the PDF doesn't have + one, use the filename instead. Put the requested uri as the + description. + + """ + jobject = datastore.create() + + jobject.metadata['title'] = self._browser.props.title + jobject.metadata['description'] = _('From: %s') % self._requested_uri + + jobject.metadata['mime_type'] = "application/pdf" + jobject.file_path = self._pdf_uri[len("file://"):] + datastore.write(jobject) + + # display the new URI: + self._browser.props.uri = self.__journal_id_to_uri(jobject.object_id) + + def __open_link_cb(self, widget, uri): + """Open the external link of a PDF in a new tab.""" + self._browser.emit_new_tab(uri) diff --git a/viewtoolbar.py b/viewtoolbar.py index 7daadc9..0226df8 100644 --- a/viewtoolbar.py +++ b/viewtoolbar.py @@ -22,11 +22,15 @@ from gi.repository import GObject from sugar3.graphics.toolbutton import ToolButton +from browser import Browser + class ViewToolbar(Gtk.Toolbar): def __init__(self, activity): GObject.GObject.__init__(self) + self._browser = None + self._activity = activity self._activity.tray.connect('unmap', self.__unmap_cb) self._activity.tray.connect('map', self.__map_cb) @@ -60,6 +64,25 @@ class ViewToolbar(Gtk.Toolbar): self.insert(self.traybutton, -1) self.traybutton.show() + tabbed_view = self._activity.get_canvas() + + if tabbed_view.get_n_pages(): + self._connect_to_browser(tabbed_view.props.current_browser) + + tabbed_view.connect_after('switch-page', self.__switch_page_cb) + + def __switch_page_cb(self, tabbed_view, page, page_num): + self._connect_to_browser(tabbed_view.props.current_browser) + + def _connect_to_browser(self, browser): + self._browser = browser + self._update_zoom_buttons() + + def _update_zoom_buttons(self): + is_webkit_browser = isinstance(self._browser, Browser) + self.zoomin.set_sensitive(is_webkit_browser) + self.zoomout.set_sensitive(is_webkit_browser) + def __zoomin_clicked_cb(self, button): tabbed_view = self._activity.get_canvas() tabbed_view.props.current_browser.zoom_in() diff --git a/webtoolbar.py b/webtoolbar.py index 098f832..7525053 100644 --- a/webtoolbar.py +++ b/webtoolbar.py @@ -34,6 +34,7 @@ from sugar3.activity.widgets import StopButton # import filepicker import places from sugarmenuitem import SugarMenuItem +from browser import Browser _MAX_HISTORY_ENTRIES = 15 @@ -331,6 +332,11 @@ class PrimaryToolbar(ToolbarBase): self._set_title(_('Untitled')) self._set_address(self._browser.props.uri) + if isinstance(self._browser, Browser): + self.entry.props.editable = True + else: + self.entry.props.editable = False + self._title_changed_hid = self._browser.connect( 'notify::title', self._title_changed_cb) self._uri_changed_hid = self._browser.connect( @@ -379,7 +385,11 @@ class PrimaryToolbar(ToolbarBase): can_go_forward = self._browser.can_go_forward() self._forward.props.sensitive = can_go_forward - self._reload_session_history() + is_webkit_browser = isinstance(self._browser, Browser) + self._link_add.props.sensitive = is_webkit_browser + self._go_home.props.sensitive = is_webkit_browser + if is_webkit_browser: + self._reload_session_history() def _entry_activate_cb(self, entry): url = entry.props.text |