Source

gevent-gtkloop / gtkloop.py

Full commit
import sys
import glib, gtk

class GtkLoop(object):
    def __init__(self, flags=None, default=True):
        assert default

    def handle_error(self, context, type, value, tb):
        error_handler = self.error_handler
        if error_handler is not None:
            # we do want to do getattr every time so that setting Hub.handle_error property just works
            handle_error = getattr(error_handler, 'handle_error', error_handler)
            handle_error(context, type, value, tb)
        else:
            self._default_handle_error(context, type, value, tb)

    def _default_handle_error(self, context, type, value, tb):
        import traceback
        traceback.print_exception(type, value, tb)
        raise AssertionError

    def io(self, fd, events, ref=None):
        return io(self, fd, events)

    def timer(self, after, repeat=0, ref=None):
        return timer(self, after, repeat)

    def idle(self):
        # XXX not exactly right!
        return timer(self, 0, 0)

    def callback(self, ref=None):
        return callback(self)

    def run_callback(self, callback, *args):
        result = callback(self)
        result.start(callback, *args)
        return result

    def fork(self, ref=None):
        return noop(self)

    def async(self, ref=None):
        return async(self)

    def run(self):
        gtk.main()


class io(object):
    def __init__(self, loop, fd, events):
        self.loop = loop
        self.fd = fd
        self.events = events
        self.callback = None
        self.args = None
        self.source_id = None

    def start(self, callback, *args, **kw):
        self.callback = callback
        self.args = args
        self.pass_events = kw.pop('pass_events', None)
        assert not kw #XXX

        must_read = self.events & 1
        must_write = self.events & 2

        # we ignore prio io

        #XXX: this base may be wrong, check the semantics
        flags = glib.IO_ERR|glib.IO_HUP
        if must_read:
            flags |= glib.IO_IN
        if must_write:
            flags |= glib.IO_OUT

        self.source_id = glib.io_add_watch(
            self.fd, flags, self._callback)

    def _callback(self, source, condition):
        if self.pass_events:
            args = (condition,) + self.args
        else:
            args = self.args
        try:
            self.callback(*args)
        except:
            self.loop.handle_error(callback, *sys.exc_info())
        return False

    def stop(self):
        self.callback = None
        self.args = None
        #XXX: check this never raises
        if self.source_id is not None:
            glib.source_remove(self.source_id)
            self.source_id = None


class timer(object):
    def __init__(self, loop, after, repeat=0):
        self.loop = loop
        self.after = after
        self.repeat = repeat
        self.source_id = None
        self.callback = None
        self.args = None

    @property
    def pending(self):
        return False  # XXX TODO

    @property
    def active(self):
        # proper implementation should ask gtkloop is this timer is active
        return self.callback is not None

    def first_callback(self):
        try:
            self.callback(*self.args)
            return True
        except:
            self.loop.handle_error(callback, *sys.exc_info())
            self.stop()
            return False

    def start(self, callback, *args):
        self.callback = callback
        self.args = args

        self.source_id = glib.timeout_add(
            int(self.after*1000),
            self.first_callback)

    def stop(self):
        self.callback = None
        self.args = None
        #XXX: check this never raises
        if self.source_id is not None:
            glib.source_remove(self.source_id)
            self.source_id = None


class callback(object):
    def __init__(self, loop):
        self.callback = None
        self.args = None

    def run_once(self):
        self.callback(*self.args)

    def start(self, callback, *args):
        self.callback = callback
        self.args = args
        glib.idle_add(self.run_once)

    def stop(self):
        pass

    @property
    def active(self):
        return self.callback is not None


class noop(object):

    def __init__(self, loop):
        pass

    def start(self, *args):
        pass

    def stop(self, *args):
        pass

    @property
    def active(self):
        return False


class async(object):

    def __init__(self, loop):
        pass

    def start(self,callback, *args):
        self.callback = callback
        self.args = args

    def stop(self, *args):
        pass

    def run_once(self):
        self.callback(*self.args)
        return False

    def send(self):
        glib.idle_add(self.run_once)
        
    @property
    def active(self):
        return False