Skip to content

Commit

Permalink
giwebkit: refactor Timers to use GObject native ... seems to work cor…
Browse files Browse the repository at this point in the history
…rectly + much cleaner
  • Loading branch information
C Anthony Risinger committed Aug 23, 2012
1 parent 32565b7 commit 21f589b
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 55 deletions.
59 changes: 8 additions & 51 deletions 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 <div>[TextNode]</div> -- 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
31 changes: 31 additions & 0 deletions pyjs/runners/giwebkit.py
Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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

Expand Down
10 changes: 6 additions & 4 deletions pyjs/runners/imputil.py
Expand Up @@ -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)
Expand Down

0 comments on commit 21f589b

Please sign in to comment.