From 21f589b653096d699d25c67face0269fca8c6f92 Mon Sep 17 00:00:00 2001 From: C Anthony Risinger Date: Thu, 23 Aug 2012 04:19:45 -0500 Subject: [PATCH] giwebkit: refactor Timers to use GObject native ... seems to work correctly + much cleaner --- library/pyjamas/Timer.giwebkit.py | 59 +++++-------------------------- pyjs/runners/giwebkit.py | 31 ++++++++++++++++ pyjs/runners/imputil.py | 10 +++--- 3 files changed, 45 insertions(+), 55 deletions(-) diff --git a/library/pyjamas/Timer.giwebkit.py b/library/pyjamas/Timer.giwebkit.py index eb0a1a2d1..2c8ec826d 100644 --- a/library/pyjamas/Timer.giwebkit.py +++ b/library/pyjamas/Timer.giwebkit.py @@ -1,57 +1,14 @@ class Timer(object): - def __setTimeout(self, periodMillis, impl='Timeout'): - ''' - Coordinate with JavaScript and realize a new Timer. - - A private communication channel is established by both sides - acquiring a ref to the same TextNode; once linked, the node is - removed from the DOM tree, but can still recieve all events. - It also serves as a nucleus for adding more nodes to the link -- eg. - wrapping in
[TextNode]
-- for whatever reason, and - without limit. - - Here we just use the private node to trigger Python callbacks; - Python registers listeners and JavaScript synthesizes events. - PyGObject is capable of clearing Timers, but is unable to create - new ones (upstream bug?). - ''' - # TODO: Timers/Intervals in JS will not queue for safety reasons; - # if we're unable to process the first event before another - # fires, we end up with an unbounded backlog of Timer events. - # For this reason, JS will only queue one event of this type - # at-a-time ... we MUST ensure this same behaviour! - code = r''' - (function(buf, ms){ - var wnd = window; - var doc = wnd.document; - var evt = doc.createEvent('UIEvent'); - var run = function(){buf.dispatchEvent(evt)}; - var tid = wnd.set%s(run, ms); - doc.head.removeChild(buf); - tid = buf.data = Number(tid); - evt.initUIEvent('Timer', true, true, wnd, tid); - }(document.head.lastChild, %s)); - ''' % (impl, int(periodMillis)) + def __setTimeout(self, delayMillis): mf = get_main_frame() - vw = mf._view - doc = mf.getDomDocument() - run = lambda *a: self.__fire() - buf = doc.createTextNode('') - doc.head.appendChild(buf) - mf.addEventListener(buf, 'Timer', run) - vw.execute_script(code) - return int(buf.data) + return mf.create_timer(delayMillis, self.__fire, __loop=False) - def __clearTimeout(self, tid, impl='Timeout'): - '''Cancel a running Timer.''' - wnd = get_main_frame().getDomWindow() - return getattr(wnd, 'clear%s' % impl)(int(tid)) + def __setInterval(self, periodMillis): + mf = get_main_frame() + return mf.create_timer(periodMillis, self.__fire, __loop=True) - def __setInterval(self, periodMillis, impl='Interval'): - '''Passthru to setTimeout(), but call setInterval().''' - return self.__setTimeout(periodMillis, impl=impl) + def __clearTimeout(self, tid): + return get_main_frame().cancel_timer(tid) - def __clearInterval(self, tid, impl='Interval'): - '''Passthru to clearTimeout(), but call clearInterval().''' - return self.__clearTimeout(tid, impl=impl) + __clearInterval = __clearTimeout diff --git a/pyjs/runners/giwebkit.py b/pyjs/runners/giwebkit.py index 1cd5b0dae..4ffeaf3b6 100644 --- a/pyjs/runners/giwebkit.py +++ b/pyjs/runners/giwebkit.py @@ -14,7 +14,9 @@ from urlparse import urljoin import gi +gi.require_version('Gtk', '3.0') gi.require_version('WebKit', '3.0') +from gi.repository import GObject from gi.repository import Gtk from gi.repository import Soup from gi.repository import WebKit @@ -383,6 +385,26 @@ def _key_gi(self, key): return self._uppercase_re.sub(r'_\1', key).lower() +class GITimer(object): + + def __init__(self, args, kwds): + args = list(args) + self.args = args + self.kwds = kwds + self.loop = kwds.pop('__loop', False) + self.ms = args.pop(0) + self.cb = args.pop(0) + self.tid = GObject.timeout_add(self.ms, self) + + def __call__(self): + try: + self.cb(*self.args) + except: + print_exc() + finally: + return self.loop + + class Callback(object): def __init__(self, sender, cb, boolparam): @@ -556,6 +578,15 @@ def _populate_popup_cb(self, view, menu): menu.append(entry) menu.show_all() + def create_timer(self, *args, **kwds): + return GITimer(args, kwds).tid + + def cancel_timer(self, tid): + return GObject.source_remove(tid) + + def get_view(self): + return self._view + def getDomWindow(self): return self._wnd diff --git a/pyjs/runners/imputil.py b/pyjs/runners/imputil.py index 137086f87..bbb84908a 100644 --- a/pyjs/runners/imputil.py +++ b/pyjs/runners/imputil.py @@ -86,10 +86,12 @@ def _import_hook(self, fqname, globals=None, locals=None, fromlist=None, parts = fqname.split('.') - #print "_import_hook", parts - # pyjamas-gtk hack - if parts[0] in ['gtk', 'gdk', 'pygtk', 'gobject']: - parts = ['pygtkweb'] + parts + #TODO: all of this hacky import stuff MUST GO! + # from now on, we will only proceed for namespaces that *may* + # need merging -- drop this ASAP for pretty much anything else + if parts[0] not in ('pyjamas',): + return self.previous_importer(fqname, globals, locals, + fromlist, level) # determine the context of this import parent = self._determine_import_context(globals)