Skip to content
Permalink
Browse files
View Help - Backport to WebKit and WebKit2
Always we see a warning about JavaScriptCore not being right version,
caused by main.py requiring WebKit yet viewhelp.py requiring WebKit2.

Seems to be no reason not to support WebKit in addition to WebKit2 in
the same code base.  Toolkit already supports both.

- remove gi.require_version from main.py,

- strip browser specific code from viewhelp.py,

- add new Browser base classes, one for WebKit, one for WebKit2,

- avoid GdkX11.X11Window.foreign_new_for_display if xid unknown,

- recognise which browser class to use based on OLPC OS release.
  • Loading branch information
quozl authored and i5o committed Feb 5, 2017
1 parent f140d04 commit 568888f
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 98 deletions.
@@ -58,7 +58,6 @@
gi.require_version('Wnck', '3.0')
gi.require_version('SugarExt', '1.0')
gi.require_version('GdkX11', '3.0')
gi.require_version('WebKit', '3.0')

from gi.repository import GObject
from gi.repository import Gio
@@ -14,4 +14,6 @@ sugar_PYTHON = \
service.py \
tabbinghandler.py \
viewsource.py \
viewhelp.py
viewhelp.py \
viewhelp_webkit1.py \
viewhelp_webkit2.py
@@ -1,5 +1,6 @@
# Copyright (C) 2013 Kalpa Welivitigoda
# Copyright (C) 2015-2016 Sam Parkinson
# Copyright (C) 2016 James Cameron <quozl@laptop.org>
#
# 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
@@ -19,25 +20,32 @@
import os
import json

import gi
gi.require_version('SoupGNOME', '2.4')
from gi.repository import Gtk
from gi.repository import GObject
from gi.repository import Gdk
from gi.repository import WebKit2
from gi.repository import GdkX11
from gi.repository import Gio

from sugar3 import env
from sugar3.graphics import style
from sugar3.graphics.icon import Icon
from sugar3.graphics.toolbutton import ToolButton
from sugar3.graphics.icon import get_icon_file_name
from sugar3.graphics.radiotoolbutton import RadioToolButton
from sugar3.bundle.activitybundle import get_bundle_instance
from jarabe.model import shell


try:
olpc_build = file('/boot/olpc_build', 'r').readline()
except:
olpc_build = ''

if olpc_build.startswith('13'):
from jarabe.view.viewhelp_webkit1 import Browser
else:
from jarabe.view.viewhelp_webkit2 import Browser


_logger = logging.getLogger('ViewHelp')

_MODE_HELP = 0
@@ -46,6 +54,11 @@
_LOADING_ICON = 'toolbar-social-help-animated'


def _get_current_language():
locale = os.environ.get('LANG')
return locale.split('.')[0].split('_')[0].lower()


def _get_help_activity_path():
path = os.path.join(env.get_user_activities_path(), 'Help.activity')
if os.path.exists(path):
@@ -176,46 +189,26 @@ def __init__(self, activity, window_xid):
self._toolbar.connect('stop-clicked', self.__stop_clicked_cb)
self._toolbar.connect('mode-changed', self.__mode_changed_cb)

context = WebKit2.WebContext.get_default()
cookie_manager = context.get_cookie_manager()
cookie_manager.set_persistent_storage(
os.path.join(env.get_profile_path(), 'social-help.cookies'),
WebKit2.CookiePersistentStorage.SQLITE)
self._browser = Browser(self._toolbar)

self._webview = WebKit2.WebView()
self._webview.get_context().register_uri_scheme(
'help', self.__app_scheme_cb, None)
self._toolbar.bind_webview(self._webview)
scrolled_window = Gtk.ScrolledWindow()
scrolled_window.add(self._browser.get_widget())
scrolled_window.show()

box.pack_start(self._webview, True, True, 0)
self._webview.show()
box.pack_start(scrolled_window, True, True, 0)

language = self._get_current_language()
language = _get_current_language()
self._help_state = None
if has_local_help:
self._help_url = 'help://' + self._get_help_file(language, url)
self._help_url = self._browser.get_local_method() + \
self._get_help_file(language, url)

self._social_help_uri = '{}/goto/{}'.format(
get_social_help_server(), activity.get_bundle_id())
self._social_help_state = None

self._webview.connect(
'load-changed', self.__load_changed_cb)
self._load_mode(self._mode)

def __app_scheme_cb(self, request, user_data):
path = request.get_path()
if path.find('_images') > -1:
if path.find('/%s/_images/' % self._get_current_language()) > -1:
path = path.replace('/html/%s/_images/' %
self._get_current_language(),
'/images/')
else:
path = path.replace('/html/_images/', '/images/')

request.finish(Gio.File.new_for_path(path).read(None),
-1, Gio.content_type_guess(path, None)[0])

def __stop_clicked_cb(self, widget):
self.destroy()

@@ -225,74 +218,34 @@ def __key_press_event_cb(self, window, event):

def __mode_changed_cb(self, toolbar, mode):
if mode == _MODE_HELP:
self._social_help_state = self._webview.get_session_state()
self._social_help_state = self._browser.save_state()
else:
self._help_state = self._webview.get_session_state()
self._help_state = self._browser.save_state()

self._mode = mode
self._load_mode(self._mode)

def _load_mode(self, mode):
if mode == _MODE_HELP:
if self._help_state is None:
self._webview.load_uri(self._help_url)
else:
self._webview.restore_session_state(self._help_state)
self._after_restore_session()
self._browser.load_state(self._help_state, self._help_url)
else:
# Loading any content for the social help page can take a
# very long time (eg. the site is behind a redirector).
# Loading the animation forces webkit to re-render the
# page instead of keeping the previous page (so the user
# sees that it is loading)
path = get_icon_file_name(_LOADING_ICON)
if path:
self._webview.load_uri('file://' + path)
# Social help is loaded after the icon is loaded
else:
if self._social_help_state is None:
self._webview.load_uri(self._social_help_uri)
else:
self._webview.restore_session_state(
self._social_help_state)
self._after_restore_session()

def _after_restore_session(self):
# this is what epiphany does:
# https://github.com/GNOME/epiphany/blob/
# 04e7811c32ba8a2c980a77aac1316b77f0969057/src/ephy-session.c#L280
bf_list = self._webview.get_back_forward_list()
item = bf_list.get_current_item()
if item is not None:
self._webview.go_to_back_forward_list_item(item)

def __load_changed_cb(self, webview, event):
if event == WebKit2.LoadEvent.FINISHED \
and _LOADING_ICON in self._webview.props.uri:
if self._social_help_state is None:
self._webview.load_uri(self._social_help_uri)
else:
self._webview.restore_session_state(
self._social_help_state)
self._after_restore_session()
self._browser.load_state(self._social_help_state,
self._social_help_uri)

def __realize_cb(self, widget):
self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
window = self.get_window()
window.set_accept_focus(True)
display = Gdk.Display.get_default()
parent = GdkX11.X11Window.foreign_new_for_display(
display, self.parent_window_xid)
window.set_transient_for(parent)
if self.parent_window_xid > 0:
display = Gdk.Display.get_default()
parent = GdkX11.X11Window.foreign_new_for_display(
display, self.parent_window_xid)
window.set_transient_for(parent)
shell.get_model().push_modal()

def __hide_cb(self, widget):
shell.get_model().pop_modal()

def _get_current_language(self):
locale = os.environ.get('LANG')
return locale.split('.')[0].split('_')[0].lower()

def _get_help_file(self, language, help_file):
activity_path = _get_help_activity_path()
# check if exist a page for the language selected
@@ -307,13 +260,14 @@ def _get_help_file(self, language, help_file):
class Toolbar(Gtk.Toolbar):

__gsignals__ = {
'back-clicked': (GObject.SignalFlags.RUN_FIRST, None, ([])),
'forward-clicked': (GObject.SignalFlags.RUN_FIRST, None, ([])),
'stop-clicked': (GObject.SignalFlags.RUN_FIRST, None, ([])),
'mode-changed': (GObject.SignalFlags.RUN_FIRST, None, ([int])),
}

def __init__(self, activity_name, has_local_help):
Gtk.Toolbar.__init__(self)
self._webview = None

self._add_separator(False)

@@ -396,20 +350,12 @@ def _add_separator(self, expand=False):
self.insert(separator, -1)
separator.show()

def bind_webview(self, webview):
self._webview = webview
self._webview.connect('load-changed', self.__load_changed_cb)
self.update_back_forward()

def __load_changed_cb(self, widget, event):
self.update_back_forward()

def update_back_forward(self):
self._back_button.props.sensitive = self._webview.can_go_back()
self._forward_button.props.sensitive = self._webview.can_go_forward()
def update_back_forward(self, can_go_back, can_go_forward):
self._back_button.props.sensitive = can_go_back
self._forward_button.props.sensitive = can_go_forward

def __back_clicked_cb(self, button):
self._webview.go_back()
self.emit('back-clicked')

def __forward_clicked_cb(self, button):
self._webview.go_forward()
self.emit('forward-clicked')
@@ -0,0 +1,124 @@
# Copyright (C) 2013 Kalpa Welivitigoda
# Copyright (C) 2015-2016 Sam Parkinson
# Copyright (C) 2016 James Cameron <quozl@laptop.org>
#
# 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 3 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, see <http://www.gnu.org/licenses/>.

import os

import gi
gi.require_version('WebKit', '3.0')
gi.require_version('SoupGNOME', '2.4')

from gi.repository import WebKit
from gi.repository import SoupGNOME

from sugar3 import env


def _get_current_language():
locale = os.environ.get('LANG')
return locale.split('.')[0].split('_')[0].lower()


class Browser():

def __init__(self, toolbar):
self._toolbar = toolbar

session = WebKit.get_default_session()
cookie_jar = SoupGNOME.CookieJarSqlite(
filename=os.path.join(env.get_profile_path(),
'social-help.cookies'),
read_only=False)
session.add_feature(cookie_jar)

self._webview = WebKit.WebView()
self._webview.set_full_content_zoom(True)
self._webview.connect('resource-request-starting',
self.__resource_request_starting_cb)

self._webview.connect('notify::uri', self.__load_changed_cb)
toolbar.update_back_forward(False, False)
toolbar.connect('back-clicked', self.__back_cb)
toolbar.connect('forward-clicked', self.__forward_cb)
self._webview.show()

def __resource_request_starting_cb(self, webview, web_frame, web_resource,
request, response):
uri = web_resource.get_uri()
if uri.startswith('file://') and uri.find('_images') > -1:
if uri.find('/%s/_images/' % _get_current_language()) > -1:
new_uri = uri.replace('/html/%s/_images/' %
_get_current_language(),
'/images/')
else:
new_uri = uri.replace('/html/_images/', '/images/')
request.set_uri(new_uri)

def __load_changed_cb(self, widget, event):
self._toolbar.update_back_forward(self._webview.can_go_back(),
self._webview.can_go_forward())

def __back_cb(self, widget):
self._webview.go_back()

def __forward_cb(self, widget):
self._webview.go_forward()

def save_state(self):
back_forward_list = self._webview.get_back_forward_list()
items_list = self._items_history_as_list(back_forward_list)
curr = back_forward_list.get_current_item()

return ([item.get_uri() for item in items_list],
items_list.index(curr))

def load_state(self, state, url):
if state is None:
state = ([url], 0)
history, index = state

back_forward_list = self._webview.get_back_forward_list()
back_forward_list.clear()
for i, uri in enumerate(history):
history_item = WebKit.WebHistoryItem.new_with_data(uri, '')
back_forward_list.add_item(history_item)
if i == index:
self._webview.go_to_back_forward_item(history_item)

self._toolbar.update_back_forward(self._webview.can_go_back(),
self._webview.can_go_forward())

def _items_history_as_list(self, history):
back_items = []
for n in reversed(range(1, history.get_back_length() + 1)):
item = history.get_nth_item(n * -1)
back_items.append(item)

current_item = [history.get_current_item()]

forward_items = []
for n in range(1, history.get_forward_length() + 1):
item = history.get_nth_item(n)
forward_items.append(item)

all_items = back_items + current_item + forward_items
return all_items

def get_widget(self):
return self._webview

def get_local_method(self):
return 'file://'

0 comments on commit 568888f

Please sign in to comment.