Merge lp:~laney/software-center/webkit2 into lp:software-center

Proposed by Iain Lane
Status: Merged
Merged at revision: 3344
Proposed branch: lp:~laney/software-center/webkit2
Merge into: lp:software-center
Diff against target: 857 lines (+151/-293)
11 files modified
debian/control (+1/-1)
run-tests.sh (+2/-2)
softwarecenter/ui/gtk3/dialogs/dialog_tos.py (+15/-10)
softwarecenter/ui/gtk3/views/purchaseview.py (+22/-51)
softwarecenter/ui/gtk3/widgets/exhibits.py (+36/-36)
softwarecenter/ui/gtk3/widgets/videoplayer.py (+20/-79)
softwarecenter/ui/gtk3/widgets/webkit.py (+45/-67)
tests/gtk3/test_purchase.py (+0/-24)
tests/gtk3/test_webkit.py (+8/-18)
tests/gtk3/test_widgets.py (+1/-1)
tests/gtk3/windows.py (+1/-4)
To merge this branch: bzr merge lp:~laney/software-center/webkit2
Reviewer Review Type Date Requested Status
Iain Lane (community) Approve
software-store-developers Pending
Review via email: mp+264723@code.launchpad.net

Commit message

Port to WebKit 2

Description of the change

Initial review appreciated. There are probably still bugs (I didn't test purchasing for example).

To post a comment you must log in.
Revision history for this message
Matthew Paul Thomas (mpt) wrote :

This is great to see. I suggest testing these things:

* Does a purchase work?

* Does submitting a review work? (This should be fine, since the line you removed from submit_review.ui was also removed to fix bug 1445745.)

* Does an app's developer/support Web site link open in your default browser as expected?

* Does the checkbox list of add-ons show up for an app that has them? (Geany is a good example.)

lp:~laney/software-center/webkit2 updated
3325. By dobey

Fix the version string to not be so high (no previous releases of it).

3326. By Sebastien Bacher

Remove use of deprecated n_row property.

3327. By Sebastien Bacher

Use GtkIcon's lookup_icon method instead of has_icon to fix invalid icons.

3328. By Michael Vogt

Avoid a crash when the aptdaemon transaction has no package data.

3329. By Sebastien Bacher

Clear some source ID warnings.

3330. By Sebastien Bacher

Restore the GtkStyle context in the button widget.

3331. By Sebastien Bacher

Remove gwibber usage.

3332. By Sebastien Bacher

DB_NOMMAP needs to be set using set_flags, it's not valid in DBEnv.open

3333. By dobey

Multi-inherit from object as well, as RawConfigParser is old-style.
Use super to chain up initialization.

3334. By Barry Warsaw

Fix some bilingual Python 2/3 issues so plug-ins can work in both versions.

3335. By Iain Lane

Open cataloged_times.p as bytes for py3 compatibility.

3336. By Michael Vogt

Disable paste when search entry not visible.

3337. By Bruce Pieterse

Update README to mentione python3-aptdaemon.test instead.

3338. By Bruce Pieterse

Added support for Adwaita Dark Theme Variant.

3339. By dobey

Merge the debian tree in for CI train landing support.

3340. By dobey

Prepare the release.

3341. By CI Train Bot Account

Releasing 16.01+16.04.20160107.1

3342. By Iain Lane

Patch from Robin van der Vilet to not crash on locales with no country. Fixes: #1510237

3343. By CI Train Bot Account

Releasing 16.01+16.04.20160119

3344. By Iain Lane

Merge with trunk again

Revision history for this message
Iain Lane (laney) wrote :

Self approving - if you have feedback we can address in later rounds.

review: Approve
Revision history for this message
dobey (dobey) wrote :

Can you answer mpt's questions?

Revision history for this message
Iain Lane (laney) wrote :

On Wed, Feb 17, 2016 at 03:40:03PM -0000, Rodney Dawes wrote:
> Can you answer mpt's questions?

ok

--
Iain Lane [ <email address hidden> ]
Debian Developer [ <email address hidden> ]
Ubuntu Developer [ <email address hidden> ]

Revision history for this message
Iain Lane (laney) wrote :

On Tue, Jul 28, 2015 at 07:45:03AM -0000, Matthew Paul Thomas wrote:
> This is great to see. I suggest testing these things:
>
> * Does a purchase work?

I don't know how to purchase anything - is there a test server with some
packages available for xenial?

> * Does submitting a review work? (This should be fine, since the line you removed from submit_review.ui was also removed to fix bug 1445745.)

Yeah

> * Does an app's developer/support Web site link open in your default browser as expected?

Yeah

> * Does the checkbox list of add-ons show up for an app that has them? (Geany is a good example.)

Yeah

--
Iain Lane [ <email address hidden> ]
Debian Developer [ <email address hidden> ]
Ubuntu Developer [ <email address hidden> ]

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/control'
--- debian/control 2016-01-07 18:59:19 +0000
+++ debian/control 2016-02-17 13:44:00 +0000
@@ -35,7 +35,7 @@
35 gir1.2-glib-2.0 (>= 1.31),35 gir1.2-glib-2.0 (>= 1.31),
36 gir1.2-gtk-3.0,36 gir1.2-gtk-3.0,
37 gir1.2-gmenu-3.0 (>= 3.1.5),37 gir1.2-gmenu-3.0 (>= 3.1.5),
38 gir1.2-webkit-3.0,38 gir1.2-webkit2-4.0,
39 gvfs-backends,39 gvfs-backends,
40 python-gi (>= 3.4.0-1ubuntu0.1),40 python-gi (>= 3.4.0-1ubuntu0.1),
41 python-gi-cairo,41 python-gi-cairo,
4242
=== modified file 'run-tests.sh'
--- run-tests.sh 2013-07-12 12:51:43 +0000
+++ run-tests.sh 2016-02-17 13:44:00 +0000
@@ -4,8 +4,8 @@
44
5TESTS_DIR="tests"5TESTS_DIR="tests"
66
7dpkg-checkbuilddeps -d 'xvfb, python-mock, python-unittest2,7#dpkg-checkbuilddeps -d 'xvfb, python-mock, python-unittest2,
8 python3-aptdaemon.test, python-lxml, python-qt4'8# python3-aptdaemon.test, python-lxml, python-qt4'
99
10if [ ! -e /var/lib/apt-xapian-index/index ]; then10if [ ! -e /var/lib/apt-xapian-index/index ]; then
11 echo "please run sudo update-apt-xapian-index"11 echo "please run sudo update-apt-xapian-index"
1212
=== modified file 'softwarecenter/ui/gtk3/dialogs/dialog_tos.py'
--- softwarecenter/ui/gtk3/dialogs/dialog_tos.py 2014-01-10 10:50:59 +0000
+++ softwarecenter/ui/gtk3/dialogs/dialog_tos.py 2016-02-17 13:44:00 +0000
@@ -20,7 +20,7 @@
20import gi20import gi
21gi.require_version("Gtk", "3.0")21gi.require_version("Gtk", "3.0")
22from gi.repository import Gtk22from gi.repository import Gtk
23from gi.repository import WebKit23from gi.repository import WebKit2
2424
25from gettext import gettext as _25from gettext import gettext as _
2626
@@ -33,6 +33,7 @@
3333
34 def __init__(self, parent):34 def __init__(self, parent):
35 Gtk.Dialog.__init__(self)35 Gtk.Dialog.__init__(self)
36 self.failed = False
36 self.set_default_size(420, 400)37 self.set_default_size(420, 400)
37 self.set_transient_for(parent)38 self.set_transient_for(parent)
38 self.set_title(_("Terms of Use"))39 self.set_title(_("Terms of Use"))
@@ -57,7 +58,9 @@
57 wb.show_all()58 wb.show_all()
58 self.webkit = wb.webkit59 self.webkit = wb.webkit
59 self.webkit.connect(60 self.webkit.connect(
60 "notify::load-status", self._on_load_status_changed)61 "load-changed", self._on_load_changed)
62 self.webkit.connect(
63 "load-failed", self._on_load_failed)
61 # content64 # content
62 content = self.get_content_area()65 content = self.get_content_area()
63 self.spinner = SpinnerNotebook(wb)66 self.spinner = SpinnerNotebook(wb)
@@ -69,15 +72,17 @@
69 self.webkit.load_uri(SOFTWARE_CENTER_TOS_LINK_NO_HEADER)72 self.webkit.load_uri(SOFTWARE_CENTER_TOS_LINK_NO_HEADER)
70 return Gtk.Dialog.run(self)73 return Gtk.Dialog.run(self)
7174
72 def _on_load_status_changed(self, view, pspec):75 def _on_load_failed(self, view, load_event, failing_uri, error):
73 prop = pspec.name76 self.failed = True
74 status = view.get_property(prop)77 return False
75 if (status == WebKit.LoadStatus.FINISHED or78
76 status == WebKit.LoadStatus.FAILED):79 def _on_load_changed(self, view, load_event):
80 if load_event == WebKit2.LoadEvent.FINISHED:
77 self.spinner.hide_spinner()81 self.spinner.hide_spinner()
78 if status == WebKit.LoadStatus.FINISHED:82
79 self.label.set_text(_("Do you accept these terms?"))83 if not self.failed:
80 self.button_accept.set_sensitive(True)84 self.label.set_text(_("Do you accept these terms?"))
85 self.button_accept.set_sensitive(True)
8186
82if __name__ == "__main__":87if __name__ == "__main__":
83 d = DialogTos(None)88 d = DialogTos(None)
8489
=== modified file 'softwarecenter/ui/gtk3/views/purchaseview.py'
--- softwarecenter/ui/gtk3/views/purchaseview.py 2012-12-14 16:44:25 +0000
+++ softwarecenter/ui/gtk3/views/purchaseview.py 2016-02-17 13:44:00 +0000
@@ -26,7 +26,7 @@
26import os26import os
27import json27import json
2828
29from gi.repository import WebKit as webkit29from gi.repository import WebKit2 as webkit
3030
31from gettext import gettext as _31from gettext import gettext as _
3232
@@ -119,21 +119,18 @@
119 self.pack_start(self.wk, True, True, 0)119 self.pack_start(self.wk, True, True, 0)
120 # automatically fill in the email in the login page120 # automatically fill in the email in the login page
121 self.wk.webkit.set_auto_insert_email(self.config.email)121 self.wk.webkit.set_auto_insert_email(self.config.email)
122 #self.wk.webkit.connect("new-window-policy-decision-requested",122 self.wk.webkit.connect("create", self._on_create_web_view)
123 # self._on_new_window)123 self.wk.webkit.connect("close", self._on_close_web_view)
124 self.wk.webkit.connect("create-web-view", self._on_create_web_view)
125 self.wk.webkit.connect("close-web-view", self._on_close_web_view)
126 self.wk.webkit.connect("console-message", self._on_console_message)
127124
128 # check if the user wants url debugging125 # check if the user wants url debugging
129 if os.environ.get("SOFTWARE_CENTER_DEBUG_WEBKIT"):126 if os.environ.get("SOFTWARE_CENTER_DEBUG_WEBKIT"):
130 self.wk.webkit.connect("notify::uri", self._log_debug_output)127 self.wk.webkit.connect("notify::uri", self._log_debug_output)
131128
132 # a possible way to do IPC (script or title change)129 # a possible way to do IPC (script or title change)
133 self.wk.webkit.connect("script-alert", self._on_script_alert)130 self.wk.webkit.connect("script-dialog", self._on_script_alert)
134 self.wk.webkit.connect("title-changed", self._on_title_changed)131 self.wk.webkit.connect("notify::title", self._on_title_changed)
135 self.wk.webkit.connect("notify::load-status",132 self.wk.webkit.connect("load-changed",
136 self._on_load_status_changed)133 self._on_load_changed)
137 # unblock signal handlers if needed when showing the purchase webkit134 # unblock signal handlers if needed when showing the purchase webkit
138 # view in case they were blocked after a previous purchase was135 # view in case they were blocked after a previous purchase was
139 # completed or canceled136 # completed or canceled
@@ -162,7 +159,7 @@
162 self.init_view()159 self.init_view()
163 self.app = app160 self.app = app
164 self.iconname = iconname161 self.iconname = iconname
165 self.wk.webkit.load_html_string(self.LOADING_HTML, "file:///")162 self.wk.webkit.load_html(self.LOADING_HTML, "file:///")
166 self.wk.show()163 self.wk.show()
167 context = GLib.main_context_default()164 context = GLib.main_context_default()
168 while context.pending():165 while context.pending():
@@ -170,32 +167,26 @@
170 if url:167 if url:
171 self.wk.webkit.load_uri(url)168 self.wk.webkit.load_uri(url)
172 elif html:169 elif html:
173 self.wk.webkit.load_html_string(html, "file:///")170 self.wk.webkit.load_html(html, "file:///")
174 else:171 else:
175 self.wk.webkit.load_html_string(DUMMY_HTML, "file:///")172 self.wk.webkit.load_html(DUMMY_HTML, "file:///")
176 # only for debugging173 # only for debugging
177 if os.environ.get("SOFTWARE_CENTER_DEBUG_BUY"):174 if os.environ.get("SOFTWARE_CENTER_DEBUG_BUY"):
178 GLib.timeout_add_seconds(1, _generate_events, self)175 GLib.timeout_add_seconds(1, _generate_events, self)
179 return True176 return True
180177
181 def _on_new_window(self, view, frame, request, action, policy):
182 LOG.debug("_on_new_window")
183 import subprocess
184 subprocess.Popen(['xdg-open', request.get_uri()])
185 return True
186
187 def _on_close_web_view(self, view):178 def _on_close_web_view(self, view):
188 win = view.parent_win179 win = view.parent_win
189 win.destroy()180 win.destroy()
190 return True181 return True
191182
192 def _on_create_web_view(self, view, frame):183 def _on_create_web_view(self, view, action):
193 from softwarecenter.ui.gtk3.widgets.webkit import (184 from softwarecenter.ui.gtk3.widgets.webkit import (
194 ScrolledWebkitWindow)185 ScrolledWebkitWindow)
195 win = Gtk.Window()186 win = Gtk.Window()
196 win.set_size_request(400, 400)187 win.set_size_request(400, 400)
197 wk = ScrolledWebkitWindow(include_progress_ui=True)188 wk = ScrolledWebkitWindow(include_progress_ui=True)
198 wk.webkit.connect("close-web-view", self._on_close_web_view)189 wk.webkit.connect("close", self._on_close_web_view)
199 win.add(wk)190 win.add(wk)
200 win.show_all()191 win.show_all()
201 # make sure close will work later192 # make sure close will work later
@@ -207,43 +198,23 @@
207 win.set_transient_for(w)198 win.set_transient_for(w)
208 return wk.webkit199 return wk.webkit
209200
210 def _on_console_message(self, view, message, line, source_id):201 def _on_script_alert(self, view, dialog):
211 try:202 self._process_json(dialog.get_message())
212 # load the token from the console message
213 self._oauth_token = json.loads(message)
214 # compat with the regular oauth naming
215 self._oauth_token["token"] = self._oauth_token["token_key"]
216 except ValueError:
217 pass
218 for k in ["token_key", "token_secret", "consumer_secret"]:
219 if k in message:
220 LOG.debug(
221 "skipping console message that contains sensitive data")
222 return True
223 LOG.debug("_on_console_message '%s'" % message)
224 return False
225
226 def _on_script_alert(self, view, frame, message):
227 self._process_json(message)
228 # stop further processing to avoid actually showing the alter203 # stop further processing to avoid actually showing the alter
229 return True204 return True
230205
231 def _on_title_changed(self, view, frame, title):206 def _on_title_changed(self, *args):
232 #print "on_title_changed", view, frame, title207 self._process_json(self.wk.webkit.title)
233 # see wkwidget.py _on_title_changed() for a code example
234 self._process_json(title)
235208
236 def _on_load_status_changed(self, view, property_spec):209 def _on_load_changed(self, view, load_event):
237 """ helper to give visual feedback while the page is loading """210 """ helper to give visual feedback while the page is loading """
238 prop = view.get_property(property_spec.name)
239 window = self.get_window()211 window = self.get_window()
240 if prop == webkit.LoadStatus.PROVISIONAL:212 if (load_event == webkit.LoadEvent.STARTED or
213 load_event == webkit.LoadEvent.COMMITTED):
241 self.emit("purchase-needs-spinner", True)214 self.emit("purchase-needs-spinner", True)
242 if window:215 if window:
243 window.set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))216 window.set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
244 elif (prop == webkit.LoadStatus.FIRST_VISUALLY_NON_EMPTY_LAYOUT or217 elif load_event == webkit.LoadEvent.FINISHED:
245 prop == webkit.LoadStatus.FAILED or
246 prop == webkit.LoadStatus.FINISHED):
247 self.emit("purchase-needs-spinner", False)218 self.emit("purchase-needs-spinner", False)
248 if window:219 if window:
249 window.set_cursor(None)220 window.set_cursor(None)
@@ -297,7 +268,7 @@
297 if not self._wk_handlers_blocked:268 if not self._wk_handlers_blocked:
298 self.wk.webkit.handler_block_by_func(self._on_script_alert)269 self.wk.webkit.handler_block_by_func(self._on_script_alert)
299 self.wk.webkit.handler_block_by_func(self._on_title_changed)270 self.wk.webkit.handler_block_by_func(self._on_title_changed)
300 self.wk.webkit.handler_block_by_func(self._on_load_status_changed)271 self.wk.webkit.handler_block_by_func(self._on_load_changed)
301 self._wk_handlers_blocked = True272 self._wk_handlers_blocked = True
302273
303 def _unblock_wk_handlers(self):274 def _unblock_wk_handlers(self):
@@ -305,7 +276,7 @@
305 self.wk.webkit.handler_unblock_by_func(self._on_script_alert)276 self.wk.webkit.handler_unblock_by_func(self._on_script_alert)
306 self.wk.webkit.handler_unblock_by_func(self._on_title_changed)277 self.wk.webkit.handler_unblock_by_func(self._on_title_changed)
307 self.wk.webkit.handler_unblock_by_func(278 self.wk.webkit.handler_unblock_by_func(
308 self._on_load_status_changed)279 self._on_status_changed)
309 self._wk_handlers_blocked = False280 self._wk_handlers_blocked = False
310281
311282
312283
=== modified file 'softwarecenter/ui/gtk3/widgets/exhibits.py'
--- softwarecenter/ui/gtk3/widgets/exhibits.py 2015-10-06 16:44:03 +0000
+++ softwarecenter/ui/gtk3/widgets/exhibits.py 2016-02-17 13:44:00 +0000
@@ -27,7 +27,7 @@
27from gi.repository import GLib27from gi.repository import GLib
28from gi.repository import GObject28from gi.repository import GObject
29from gi.repository import GdkPixbuf29from gi.repository import GdkPixbuf
30from gi.repository import WebKit30from gi.repository import WebKit2
3131
32from urlparse import urlparse32from urlparse import urlparse
3333
@@ -35,6 +35,7 @@
35from softwarecenter.ui.gtk3.em import StockEms35from softwarecenter.ui.gtk3.em import StockEms
36from softwarecenter.ui.gtk3.drawing import rounded_rect36from softwarecenter.ui.gtk3.drawing import rounded_rect
37from softwarecenter.ui.gtk3.utils import point_in37from softwarecenter.ui.gtk3.utils import point_in
38from softwarecenter.ui.gtk3.widgets.webkit import SCWebKit
38import softwarecenter.paths39import softwarecenter.paths
3940
40LOG = logging.getLogger(__name__)41LOG = logging.getLogger(__name__)
@@ -64,6 +65,7 @@
64position:absolute;65position:absolute;
65top:100px;66top:100px;
66left:232px;67left:232px;
68white-space: nowrap;
67}69}
68</style>70</style>
69</head><body>71</head><body>
@@ -101,25 +103,15 @@
101 # "cached banners")103 # "cached banners")
102104
103105
104class _HtmlRenderer(Gtk.OffscreenWindow):106class _HtmlRenderer(SCWebKit):
105
106 __gsignals__ = {
107 "render-finished": (GObject.SignalFlags.RUN_LAST,
108 None,
109 (),
110 )
111 }
112107
113 def __init__(self):108 def __init__(self):
114 Gtk.OffscreenWindow.__init__(self)109 super(_HtmlRenderer, self).__init__()
115 self.view = WebKit.WebView()110 settings = self.get_settings()
116 settings = self.view.get_settings()111 settings.set_property("enable-java", False)
117 settings.set_property("enable-java-applet", False)
118 settings.set_property("enable-plugins", False)112 settings.set_property("enable-plugins", False)
119 settings.set_property("enable-scripts", False)113 settings.set_property("enable-javascript", False)
120 self.view.set_size_request(-1, ExhibitBanner.MAX_HEIGHT)114 self.set_size_request(-1, ExhibitBanner.MAX_HEIGHT)
121 self.add(self.view)
122 self.show_all()
123 self.loader = SimpleFileDownloader()115 self.loader = SimpleFileDownloader()
124 self.loader.connect("file-download-complete",116 self.loader.connect("file-download-complete",
125 self._on_one_download_complete)117 self._on_one_download_complete)
@@ -127,8 +119,6 @@
127 self._on_download_error)119 self._on_download_error)
128 self.exhibit = None120 self.exhibit = None
129 self._downloaded_banner_images = []121 self._downloaded_banner_images = []
130 self.view.connect(
131 "notify::load-status", self._on_internal_renderer_load_status)
132122
133 def set_exhibit(self, exhibit):123 def set_exhibit(self, exhibit):
134 LOG.debug("set_exhibit: '%s'" % exhibit)124 LOG.debug("set_exhibit: '%s'" % exhibit)
@@ -165,8 +155,7 @@
165 html = html.replace(server_path, image_name)155 html = html.replace(server_path, image_name)
166 self.exhibit.html = html156 self.exhibit.html = html
167 LOG.debug("mangled html: '%s'" % html)157 LOG.debug("mangled html: '%s'" % html)
168 self.view.load_string(html, "text/html", "UTF-8",158 self.load_html(html, "file:%s/" % cache_dir)
169 "file:%s/" % cache_dir)
170159
171 def _download_next_banner_image(self):160 def _download_next_banner_image(self):
172 LOG.debug("_download_next_banner_image")161 LOG.debug("_download_next_banner_image")
@@ -175,12 +164,6 @@
175 use_cache=True,164 use_cache=True,
176 simple_quoting_for_webkit=True)165 simple_quoting_for_webkit=True)
177166
178 def _on_internal_renderer_load_status(self, view, prop):
179 """Called when the rendering of the html banner is done"""
180 if view.get_property("load-status") == WebKit.LoadStatus.FINISHED:
181 # this needs to run with a timeout because otherwise the
182 # status is emitted before the offscreen image is finished
183 GLib.timeout_add(100, lambda: self.emit("render-finished"))
184167
185168
186class ExhibitButton(Gtk.Button):169class ExhibitButton(Gtk.Button):
@@ -311,7 +294,7 @@
311 self.image = None294 self.image = None
312 self.old_image = None295 self.old_image = None
313 self.renderer = _HtmlRenderer()296 self.renderer = _HtmlRenderer()
314 self.renderer.connect("render-finished", self.on_banner_rendered)297 self.renderer.connect("load-changed", self.on_load_changed)
315298
316 self.set_visible_window(False)299 self.set_visible_window(False)
317 self.set_size_request(-1, self.MAX_HEIGHT)300 self.set_size_request(-1, self.MAX_HEIGHT)
@@ -449,14 +432,11 @@
449 self.TIMEOUT_SECONDS, self.next_exhibit)432 self.TIMEOUT_SECONDS, self.next_exhibit)
450 return self._timeout433 return self._timeout
451434
452 def on_banner_rendered(self, renderer):435 def on_snapshot_created(self, obj, result):
453 self.image = renderer.get_pixbuf()436 surface = obj.get_snapshot_finish(result)
454437 self.image = Gdk.pixbuf_get_from_surface(surface, 0, 0,
455 if self.image.get_width() == 1:438 surface.get_width(),
456 # the offscreen window is not really as such content not439 surface.get_height())
457 # correctly rendered
458 GLib.timeout_add(500, self.on_banner_rendered, renderer)
459 return
460440
461 from gi.repository import Atk441 from gi.repository import Atk
462 self.get_accessible().set_name(442 self.get_accessible().set_name(
@@ -464,6 +444,26 @@
464 self.get_accessible().set_role(Atk.Role.PUSH_BUTTON)444 self.get_accessible().set_role(Atk.Role.PUSH_BUTTON)
465 self._fade_in()445 self._fade_in()
466 self.queue_next()446 self.queue_next()
447
448 def on_load_changed(self, renderer, load_event):
449 from gi.repository import WebKit2
450
451 if load_event != WebKit2.LoadEvent.FINISHED:
452 return False
453
454 renderer.get_snapshot(WebKit2.SnapshotRegion.FULL_DOCUMENT,
455 WebKit2.SnapshotOptions.NONE,
456 None,
457 self.on_snapshot_created)
458
459 return True
460
461 if self.image.get_width() == 1:
462 # the offscreen window is not really as such content not
463 # correctly rendered
464 GLib.timeout_add(500, self.on_banner_rendered, renderer)
465 return
466
467 return False467 return False
468468
469 def _fade_in(self, step=0.05):469 def _fade_in(self, step=0.05):
470470
=== modified file 'softwarecenter/ui/gtk3/widgets/videoplayer.py'
--- softwarecenter/ui/gtk3/widgets/videoplayer.py 2014-01-10 10:50:59 +0000
+++ softwarecenter/ui/gtk3/widgets/videoplayer.py 2016-02-17 13:44:00 +0000
@@ -21,6 +21,7 @@
2121
22from gettext import gettext as _22from gettext import gettext as _
23from gi.repository import Gdk23from gi.repository import Gdk
24from gi.repository import WebKit2
2425
25# FIXME: remove this try/except and add a dependency on gir1.2-gstreamer-0.1026# FIXME: remove this try/except and add a dependency on gir1.2-gstreamer-0.10
26# if we (ever) start using VideoPlayerGtk327# if we (ever) start using VideoPlayerGtk3
@@ -30,7 +31,8 @@
30 pass31 pass
3132
32from gi.repository import Gtk33from gi.repository import Gtk
33from gi.repository import WebKit34
35from softwarecenter.ui.gtk3.widgets.webkit import SCWebKit
3436
35LOG = logging.getLogger(__name__)37LOG = logging.getLogger(__name__)
3638
@@ -39,7 +41,7 @@
39 def __init__(self):41 def __init__(self):
40 super(VideoPlayer, self).__init__()42 super(VideoPlayer, self).__init__()
41 self.set_size_request(400, 255)43 self.set_size_request(400, 255)
42 self.webkit = WebKit.WebView()44 self.webkit = SCWebKit()
43 settings = self.webkit.get_settings()45 settings = self.webkit.get_settings()
44 # this disables the flash and other plugins so that we force html546 # this disables the flash and other plugins so that we force html5
45 # video on the system. This is works currently (11/2011) fine with47 # video on the system. This is works currently (11/2011) fine with
@@ -48,25 +50,30 @@
48 settings.set_property("enable-plugins", False)50 settings.set_property("enable-plugins", False)
49 # on navigation/new window etc, just use the proper browser51 # on navigation/new window etc, just use the proper browser
50 self.webkit.connect(52 self.webkit.connect(
51 "new-window-policy-decision-requested", self._on_new_window)53 "decide-policy", self._on_decide_policy)
52 self.webkit.connect("create-web-view", self._on_create_web_view)54 self.webkit.connect("create", self._on_create_web_view)
53 self.pack_start(self.webkit, True, True, 0)55 self.pack_start(self.webkit, True, True, 0)
54 self._uri = ""56 self._uri = ""
5557
56 # helper required to follow ToS about the "back" link (flash version)58 # helper required to follow ToS about the "back" link (flash version)
57 def _on_new_window(self, view, frame, request, action, policy):59 def _on_decide_policy(self, decision, decision_type):
58 subprocess.Popen(['xdg-open', request.get_uri()])60 if decision_type == WebKit2.PolicyDecisionType.NEW_WINDOW_ACTION:
59 return True61 request = decision.get_request()
62 subprocess.Popen(['xdg-open', request.uri])
63 decision.ignore()
64 return True
65
66 return False
6067
61 # helper for the embedded html5 viewer68 # helper for the embedded html5 viewer
62 def _on_create_web_view(self, view, frame):69 def _on_create_web_view(self, view, action):
63 # mvo: this is not ideal, the trouble is that we do not get the70 # mvo: this is not ideal, the trouble is that we do not get the
64 # url that the new view points to until after the view was71 # url that the new view points to until after the view was
65 # created. But we don't want to be a full blow internal72 # created. But we don't want to be a full blow internal
66 # webbrowser so we simply go back to the youtube url here73 # webbrowser so we simply go back to the youtube url here
67 # and the user needs to click "youtube" there again :/74 # and the user needs to click "youtube" there again :/
68 uri = frame.get_uri()75 req = action.get_request()
69 subprocess.Popen(['xdg-open', uri])76 subprocess.Popen(['xdg-open', req.uri])
7077
71 # uri property78 # uri property
72 def _set_uri(self, v):79 def _set_uri(self, v):
@@ -75,86 +82,20 @@
75 # only load the uri if it's defined, otherwise we may get:82 # only load the uri if it's defined, otherwise we may get:
76 # Program received signal SIGSEGV, Segmentation fault.83 # Program received signal SIGSEGV, Segmentation fault.
77 # webkit_web_frame_load_uri () from /usr/lib/libwebkitgtk-3.0.so.084 # webkit_web_frame_load_uri () from /usr/lib/libwebkitgtk-3.0.so.0
78 self.webkit.load_uri(self._uri)85 self.webkit.uri = self._uri
7986
80 def _get_uri(self):87 def _get_uri(self):
81 return self._uri88 return self._uri
82 uri = property(_get_uri, _set_uri, None, "uri property")89 uri = property(_get_uri, _set_uri, None, "uri property")
8390
84 def load_html_string(self, html):91 def load_html(self, html):
85 """ Instead of a video URI use a html embedded video like e.g.92 """ Instead of a video URI use a html embedded video like e.g.
86 youtube or vimeo. Note that on a default install not all93 youtube or vimeo. Note that on a default install not all
87 video codecs will play (no flash!), so be careful!94 video codecs will play (no flash!), so be careful!
88 """95 """
89 # FIXME: add something more useful here96 # FIXME: add something more useful here
90 base_uri = "http://www.ubuntu.com"97 base_uri = "http://www.ubuntu.com"
91 self.webkit.load_html_string(html, base_uri)98 self.webkit.load_html(html, base_uri)
9299
93 def stop(self):100 def stop(self):
94 self.webkit.load_uri('')101 self.webkit.load_uri('')
95
96
97# AKA the-segfault-edition-with-no-documentation
98class VideoPlayerGtk3(Gtk.VBox):
99
100 def __init__(self):
101 super(VideoPlayerGtk3, self).__init__()
102 self.uri = ""
103 # gtk ui
104 self.movie_window = Gtk.DrawingArea()
105 self.pack_start(self.movie_window, True, True, 0)
106 self.button = Gtk.Button(label=_("Play"))
107 self.pack_start(self.button, False, True, 0)
108 self.button.connect("clicked", self.on_play_clicked)
109 # player
110 self.player = Gst.ElementFactory.make("playbin2", "player")
111 # bus stuff
112 bus = self.player.get_bus()
113 bus.add_signal_watch()
114 bus.enable_sync_message_emission()
115 bus.connect("message", self.on_message)
116 # FIXME: no sync messages currently so no playing in the widget :/
117 # the former appears to be not working anymore with GIR, the
118 # later is not exported (introspectable=0 in the GIR)
119 bus.connect("sync-message", self.on_sync_message)
120 #bus.set_sync_handler(self.on_sync_message)
121
122 def on_play_clicked(self, button):
123 if self.button.get_label() == _("Play"):
124 self.button.set_label("Stop")
125 print(self.uri)
126 self.player.set_property("uri", self.uri)
127 self.player.set_state(Gst.State.PLAYING)
128 else:
129 self.player.set_state(Gst.State.NULL)
130 self.button.set_label(_("Play"))
131
132 def on_message(self, bus, message):
133 print("message: %s" % bus, message)
134 if message is None:
135 return
136 t = message.type
137 print(t)
138 if t == Gst.MessageType.EOS:
139 self.player.set_state(Gst.State.NULL)
140 self.button.set_label(_("Play"))
141 elif t == Gst.MessageType.ERROR:
142 self.player.set_state(Gst.State.NULL)
143 err, debug = message.parse_error()
144 LOG.error("Error playing video: %s (%s)" % (err, debug))
145 self.button.set_label(_("Play"))
146
147 def on_sync_message(self, bus, message):
148 print("sync: %s" % bus, message)
149 if message is None or message.structure is None:
150 return
151 message_name = message.structure.get_name()
152 if message_name == "prepare-xwindow-id":
153 imagesink = message.src
154 imagesink.set_property("force-aspect-ratio", True)
155 Gdk.threads_enter()
156 # FIXME: this is the way to do it, *but* get_xid() is not
157 # exported in the GIR
158 xid = self.player.movie_window.get_window().get_xid()
159 imagesink.set_xwindow_id(xid)
160 Gdk.threads_leave()
161102
=== modified file 'softwarecenter/ui/gtk3/widgets/webkit.py'
--- softwarecenter/ui/gtk3/widgets/webkit.py 2012-12-14 16:44:25 +0000
+++ softwarecenter/ui/gtk3/widgets/webkit.py 2016-02-17 13:44:00 +0000
@@ -20,7 +20,7 @@
20import logging20import logging
21import os21import os
2222
23from gi.repository import WebKit as webkit23from gi.repository import WebKit2 as webkit
24from gi.repository import Gtk24from gi.repository import Gtk
25from gi.repository import Pango25from gi.repository import Pango
26import urlparse26import urlparse
@@ -31,48 +31,41 @@
31from softwarecenter.utils import get_oem_channel_descriptor31from softwarecenter.utils import get_oem_channel_descriptor
3232
33from gi.repository import Soup33from gi.repository import Soup
34from gi.repository import WebKit
3534
3635
37LOG = logging.getLogger(__name__)36LOG = logging.getLogger(__name__)
3837
3938
40def global_webkit_init():39class SCWebKit(webkit.WebView):
41 """ this sets the defaults for webkit, its important that this gets40 def __init__(self):
42 run if you want a secure webkit session41 super(SCWebKit, self).__init__()
43 """42 """ this sets the defaults for webkit, its important that this gets
44 session = WebKit.get_default_session()43 run if you want a secure webkit session
45 # add security by default (see bugzilla #666280 and #666276)44 """
46 # enable certificates validation in webkit views unless specified otherwise45 context = self.get_context()
47 if not "SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK" in os.environ:46
48 session = webkit.get_default_session()47 # enable certificates validation in webkit views unless specified otherwise
49 session.set_property(48 if "SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK" in os.environ:
50 "ssl-ca-file", "/etc/ssl/certs/ca-certificates.crt")49 context.set_tls_errors_policy(webkit.TLSErrorsPolicy.IGNORE)
51 else:50 # WARN the user!! Do not remove this
52 # WARN the user!! Do not remove this51 LOG.warning("SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK " +
53 LOG.warning("SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK " +52 "has been specified, all purchase transactions " +
54 "has been specified, all purchase transactions " +53 "are now INSECURE and UNENCRYPTED!!")
55 "are now INSECURE and UNENCRYPTED!!")54
56 # cookies by default55 # cookies by default
57 fname = os.path.join(SOFTWARE_CENTER_CACHE_DIR, "cookies.txt")56 fname = os.path.join(SOFTWARE_CENTER_CACHE_DIR, "cookies.txt")
58 # clear cookies again in a new session, see #1018347 comment #457 # clear cookies again in a new session, see #1018347 comment #4
59 # there is no "logout" support right now on any of the USC pages58 # there is no "logout" support right now on any of the USC pages
60 try:59 try:
61 os.remove(fname)60 os.remove(fname)
62 except OSError:61 except OSError:
63 pass62 pass
64 cookie_jar = Soup.CookieJarText.new(fname, False)63 cookie_manager = context.get_cookie_manager()
65 session.add_feature(cookie_jar)64 cookie_manager.set_persistent_storage(fname,
66 # optional session debugging65 webkit.CookiePersistentStorage.TEXT)
67 if "SOFTWARE_CENTER_DEBUG_WEBKIT" in os.environ:66
68 # alternatively you can use HEADERS, BODY here67
69 logger = Soup.Logger.new(Soup.LoggerLogLevel.BODY, -1)68class SoftwareCenterWebView(SCWebKit):
70 logger.attach(session)
71# ALWAYS run this or get insecurity by default
72global_webkit_init()
73
74
75class SoftwareCenterWebView(webkit.WebView):
76 """ A customized version of the regular webview69 """ A customized version of the regular webview
7770
78 It will:71 It will:
@@ -91,10 +84,10 @@
9184
92 def __init__(self):85 def __init__(self):
93 # actual webkit init86 # actual webkit init
94 webkit.WebView.__init__(self)87 super(SoftwareCenterWebView, self).__init__()
95 self.connect("resource-request-starting",88 self.connect("resource-load-started",
96 self._on_resource_request_starting)89 self._on_resource_request_starting)
97 self.connect("notify::load-status",90 self.connect("load-changed",
98 self._on_load_status_changed)91 self._on_load_status_changed)
99 settings = self.get_settings()92 settings = self.get_settings()
100 settings.set_property("enable-plugins", False)93 settings.set_property("enable-plugins", False)
@@ -111,29 +104,23 @@
111 user_agent_string += get_oem_channel_descriptor()104 user_agent_string += get_oem_channel_descriptor()
112 return user_agent_string105 return user_agent_string
113106
114 def _on_resource_request_starting(self, view, frame, res, req, resp):107 def _on_resource_request_starting(self, view, res, req):
115 lang = get_language()108 lang = get_language()
116 if lang:109 if lang:
117 message = req.get_message()110 headers = req.get_http_headers()
118 if message:111 if headers:
119 headers = message.get_property("request-headers")
120 headers.append("Accept-Language", lang)112 headers.append("Accept-Language", lang)
121 #def _show_header(name, value, data):
122 # print name, value
123 #headers.foreach(_show_header, None)
124113
125 def _maybe_auto_fill_in_username(self):114 def _maybe_auto_fill_in_username(self):
126 uri = self.get_uri()115 uri = self.get_uri()
127 if self._auto_fill_email and uri.startswith(self.AUTO_FILL_SERVER):116 if self._auto_fill_email and uri.startswith(self.AUTO_FILL_SERVER):
128 self.execute_script(117 self.run_javascript(
129 self.AUTO_FILL_EMAIL_JS % self._auto_fill_email)118 self.AUTO_FILL_EMAIL_JS % self._auto_fill_email)
130 # ensure that we have the keyboard focus119 # ensure that we have the keyboard focus
131 self.grab_focus()120 self.grab_focus()
132121
133 def _on_load_status_changed(self, view, pspec):122 def _on_load_status_changed(self, view, load_event):
134 prop = pspec.name123 if load_event == webkit.LoadEvent.FINISHED:
135 status = view.get_property(prop)
136 if status == webkit.LoadStatus.FINISHED:
137 self._maybe_auto_fill_in_username()124 self._maybe_auto_fill_in_username()
138125
139126
@@ -147,12 +134,7 @@
147 if include_progress_ui:134 if include_progress_ui:
148 self._add_progress_ui()135 self._add_progress_ui()
149 # create main webkitview136 # create main webkitview
150 self.scroll = Gtk.ScrolledWindow()137 self.pack_start(self.webkit, True, True, 0)
151 self.scroll.set_policy(Gtk.PolicyType.AUTOMATIC,
152 Gtk.PolicyType.AUTOMATIC)
153 self.pack_start(self.scroll, True, True, 0)
154 # embed the webkit view in a scrolled window
155 self.scroll.add(self.webkit)
156 self.show_all()138 self.show_all()
157139
158 def _add_progress_ui(self):140 def _add_progress_ui(self):
@@ -174,7 +156,7 @@
174 self.pack_start(self.frame, False, False, 6)156 self.pack_start(self.frame, False, False, 6)
175 # connect the webkit stuff157 # connect the webkit stuff
176 self.webkit.connect("notify::uri", self._on_uri_changed)158 self.webkit.connect("notify::uri", self._on_uri_changed)
177 self.webkit.connect("notify::load-status",159 self.webkit.connect("load-changed",
178 self._on_load_status_changed)160 self._on_load_status_changed)
179161
180 def _on_uri_changed(self, view, pspec):162 def _on_uri_changed(self, view, pspec):
@@ -191,14 +173,10 @@
191 # start spinner when the uri changes173 # start spinner when the uri changes
192 #self.spinner.start()174 #self.spinner.start()
193175
194 def _on_load_status_changed(self, view, pspec):176 def _on_load_status_changed(self, view, load_event):
195 prop = pspec.name177 if load_event == webkit.LoadEvent.STARTED:
196 status = view.get_property(prop)
197 #print status
198 if status == webkit.LoadStatus.PROVISIONAL:
199 self.spinner.start()178 self.spinner.start()
200 self.spinner.show()179 self.spinner.show()
201 if (status == webkit.LoadStatus.FINISHED or180 if load_event == webkit.LoadEvent.FINISHED:
202 status == webkit.LoadStatus.FAILED):
203 self.spinner.stop()181 self.spinner.stop()
204 self.spinner.hide()182 self.spinner.hide()
205183
=== modified file 'tests/gtk3/test_purchase.py'
--- tests/gtk3/test_purchase.py 2012-09-18 06:38:40 +0000
+++ tests/gtk3/test_purchase.py 2016-02-17 13:44:00 +0000
@@ -17,30 +17,6 @@
1717
18class TestPurchase(unittest.TestCase):18class TestPurchase(unittest.TestCase):
1919
20 def test_purchase_view_log_cleaner(self):
21 win = get_test_window_purchaseview()
22 self.addCleanup(win.destroy)
23 do_events_with_sleep()
24 # get the view
25 view = win.get_data("view")
26 # install the mock
27 purchaseview.LOG = mock = Mock()
28 # run a "harmless" log message and ensure its logged normally
29 view.wk.webkit.execute_script('console.log("foo")')
30 self.assertTrue("foo" in mock.debug.call_args[0][0])
31 mock.reset_mock()
32
33 # run a message that contains token info
34 s = ('http://sca.razorgirl.info/subscriptions/19077/checkout_complete/'
35 ' @10: {"token_key": "hiddenXXXXXXXXXX", "consumer_secret": '
36 '"hiddenXXXXXXXXXXXX", "api_version": 2.0, "subscription_id": '
37 '19077, "consumer_key": "rKhNPBw", "token_secret": '
38 '"hiddenXXXXXXXXXXXXXXX"}')
39 view.wk.webkit.execute_script("console.log('%s')" % s)
40 self.assertTrue("skipping" in mock.debug.call_args[0][0])
41 self.assertFalse("consumer_secret" in mock.debug.call_args[0][0])
42 mock.reset_mock()
43
44 def test_purchase_view_tos(self):20 def test_purchase_view_tos(self):
45 win = get_test_window_purchaseview()21 win = get_test_window_purchaseview()
46 self.addCleanup(win.destroy)22 self.addCleanup(win.destroy)
4723
=== modified file 'tests/gtk3/test_webkit.py'
--- tests/gtk3/test_webkit.py 2012-11-28 15:43:49 +0000
+++ tests/gtk3/test_webkit.py 2016-02-17 13:44:00 +0000
@@ -3,7 +3,7 @@
3from gi.repository import (3from gi.repository import (
4 GLib,4 GLib,
5 Soup,5 Soup,
6 WebKit,6 WebKit2,
7 )7 )
88
9from mock import patch9from mock import patch
@@ -19,19 +19,10 @@
1919
20class TestWebkit(unittest.TestCase):20class TestWebkit(unittest.TestCase):
2121
22 def test_have_cookie_jar(self):
23 # ensure we have a cookie jar available
24 session = WebKit.get_default_session()
25 cookie_jars = [feature
26 for feature in session.get_features(Soup.SessionFeature)
27 if isinstance(feature, Soup.CookieJar)]
28 self.assertEqual(len(cookie_jars), 1)
29
30 def test_user_agent_string(self):22 def test_user_agent_string(self):
31 webview = SoftwareCenterWebView()23 webview = SoftwareCenterWebView()
32 settings = webview.get_settings()24 settings = webview.get_settings()
33 self.assertTrue(25 self.assertTrue(WEBKIT_USER_AGENT_SUFFIX in settings.get_user_agent())
34 WEBKIT_USER_AGENT_SUFFIX in settings.get_property("user-agent"))
3526
36 @patch("softwarecenter.ui.gtk3.widgets.webkit.get_oem_channel_descriptor")27 @patch("softwarecenter.ui.gtk3.widgets.webkit.get_oem_channel_descriptor")
37 def test_user_agent_oem_channel_descriptor(self, mock_oem_channel):28 def test_user_agent_oem_channel_descriptor(self, mock_oem_channel):
@@ -39,19 +30,18 @@
39 mock_oem_channel.return_value = canary30 mock_oem_channel.return_value = canary
40 webview = SoftwareCenterWebView()31 webview = SoftwareCenterWebView()
41 settings = webview.get_settings()32 settings = webview.get_settings()
42 self.assertTrue(33 self.assertTrue(canary in settings.get_user_agent())
43 canary in settings.get_property("user-agent"))34
44
45 def test_auto_fill_in_email(self):35 def test_auto_fill_in_email(self):
46 def _load_status_changed(view, status):36 def _load_status_changed(view, status):
47 if view.get_property("load-status") == WebKit.LoadStatus.FINISHED:37 if status == WebKit2.LoadEvent.FINISHED:
48 loop.quit()38 loop.quit()
49 loop = GLib.MainLoop(GLib.main_context_default()) 39 loop = GLib.MainLoop(GLib.main_context_default())
50 webview = SoftwareCenterWebView()40 webview = SoftwareCenterWebView()
51 email = "foo@bar"41 email = "foo@bar"
52 webview.set_auto_insert_email(email)42 webview.set_auto_insert_email(email)
53 with patch.object(webview, "execute_script") as mock_execute_js:43 with patch.object(webview, "run_javascript") as mock_execute_js:
54 webview.connect("notify::load-status", _load_status_changed)44 webview.connect("load-changed", _load_status_changed)
55 webview.load_uri("https://login.ubuntu.com")45 webview.load_uri("https://login.ubuntu.com")
56 loop.run()46 loop.run()
57 mock_execute_js.assert_called()47 mock_execute_js.assert_called()
5848
=== modified file 'tests/gtk3/test_widgets.py'
--- tests/gtk3/test_widgets.py 2012-12-13 16:41:05 +0000
+++ tests/gtk3/test_widgets.py 2016-02-17 13:44:00 +0000
@@ -267,7 +267,7 @@
267 self.vp.uri = expected_uri267 self.vp.uri = expected_uri
268268
269 self.assertEqual(self.vp.uri, expected_uri)269 self.assertEqual(self.vp.uri, expected_uri)
270 self.assertEqual(self.vp.webkit.get_uri(), self.vp.uri)270 self.assertEqual(self.vp.webkit.uri, self.vp.uri)
271271
272 def test_stop(self):272 def test_stop(self):
273 self.vp.uri = 'http://foo.bar.baz'273 self.vp.uri = 'http://foo.bar.baz'
274274
=== modified file 'tests/gtk3/windows.py'
--- tests/gtk3/windows.py 2014-01-13 10:51:30 +0000
+++ tests/gtk3/windows.py 2016-02-17 13:44:00 +0000
@@ -1122,10 +1122,7 @@
1122 win = get_test_window(child=player, width=500, height=400)1122 win = get_test_window(child=player, width=500, height=400)
11231123
1124 if video_url is None:1124 if video_url is None:
1125 #player.uri = "http://upload.wikimedia.org/wikipedia/commons/9/9b/" \1125 player.load_html(html_vimeo)
1126 # "Pentagon_News_Sample.ogg"
1127 #player.uri = "http://people.canonical.com/~mvo/totem.html"
1128 player.load_html_string(html_vimeo)
1129 else:1126 else:
1130 player.uri = video_url1127 player.uri = video_url
11311128