PageRenderTime 187ms CodeModel.GetById 165ms app.highlight 9ms RepoModel.GetById 9ms app.codeStats 0ms

/wimpiggy/util.py

https://code.google.com/p/partiwm/
Python | 126 lines | 106 code | 8 blank | 12 comment | 2 complexity | f6c9355c416c361109901405d997c8c8 MD5 | raw file
Possible License(s): GPL-2.0
  1# This file is part of Parti.
  2# Copyright (C) 2008, 2009 Nathaniel Smith <njs@pobox.com>
  3# Parti is released under the terms of the GNU GPL v2, or, at your option, any
  4# later version. See the file COPYING for details.
  5
  6import traceback
  7import sys
  8import gobject
  9
 10class AutoPropGObjectMixin(object):
 11    """Mixin for automagic property support in GObjects.
 12
 13    Make sure this is the first entry on your parent list, so super().__init__
 14    will work right."""
 15    def __init__(self):
 16        super(AutoPropGObjectMixin, self).__init__()
 17        self._gproperties = {}
 18
 19    def _munge_property_name(self, name):
 20        return name.replace("-", "_")
 21
 22    def do_get_property(self, pspec):
 23        getter = "do_get_property_" + self._munge_property_name(pspec.name)
 24        if hasattr(self, getter):
 25            return getattr(self, getter)(pspec.name)
 26        return self._gproperties.get(pspec.name)
 27
 28    def do_set_property(self, pspec, value):
 29        self._internal_set_property(pspec.name, value)
 30
 31    # Exposed for subclasses that wish to set readonly properties --
 32    # .set_property (the public api) will fail, but the property can still be
 33    # modified via this method.
 34    def _internal_set_property(self, name, value):
 35        setter = "do_set_property_" + self._munge_property_name(name)
 36        if hasattr(self, setter):
 37            getattr(self, setter)(name, value)
 38        else:
 39            self._gproperties[name] = value
 40        self.notify(name)
 41
 42
 43def dump_exc():
 44    """Call this from a except: clause to print a nice traceback."""
 45    print "".join(traceback.format_exception(*sys.exc_info()))
 46
 47
 48# A simple little class whose instances we can stick random bags of attributes
 49# on.
 50class AdHocStruct(object):
 51    def __repr__(self):
 52        return ("<%s object, contents: %r>"
 53                % (type(self).__name__, self.__dict__))
 54
 55def n_arg_signal(n):
 56    return (gobject.SIGNAL_RUN_LAST,
 57            gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,) * n)
 58no_arg_signal = n_arg_signal(0)
 59one_arg_signal = n_arg_signal(1)
 60
 61
 62# Collects the results from signal handlers for a given signal into a list,
 63# ignoring all handlers that return None.  (This filtering is useful because
 64# the intended use of this method is to "poll" all connected objects, so it's
 65# pretty useless to call a default do_* method... but even if such a method is
 66# not defined, a default implementation will still be called automatically,
 67# and that implementation simply returns None.)
 68def non_none_list_accumulator(ihint, return_accu, handler_return):
 69    if return_accu is None:
 70        return_accu = []
 71    if handler_return is not None:
 72        return_accu += [handler_return]
 73    return True, return_accu
 74
 75
 76# *Fully* exits the gtk main loop, even in the presence of recursive calls to
 77# gtk.main().  Useful when you really just want to quit, and don't want to
 78# care if you're inside a recursive mainloop.
 79def gtk_main_quit_really():
 80    # We used to call gtk.main_quit() repeatedly, but this doesn't actually
 81    # work -- gtk.main_quit() always marks the *current* level of main loop
 82    # for destruction, so it's actually idempotent. We have to call
 83    # gtk.main_quit once, and then return to the main loop, and then call it
 84    # again, and then return to the main loop, etc. So we use a trick: We
 85    # register a function that gtk should call 'forever' (i.e., as long as the
 86    # main loop is running!)
 87    def gtk_main_quit_forever():
 88        # We import gtk inside here, rather than at the top of the file,
 89        # because importing gtk has the side-effect of trying to connect to
 90        # the X server (and this process may block, may cause us to later be
 91        # killed if the X server goes away, etc.), and we don't want to impose
 92        # that on every user of wimpiggy.util.
 93        import gtk
 94        gtk.main_quit()
 95        # So long as there are more nested main loops, re-register ourselves
 96        # to be called again:
 97        if gtk.main_level() > 1:
 98            return True
 99        else:
100            # But when we've just quit the outermost main loop, then
101            # unregister ourselves so that it's possible to start the
102            # main-loop again if desired:
103            return False
104    gobject.timeout_add(0, gtk_main_quit_forever)
105
106# If a user hits control-C, and we are currently executing Python code below
107# the main loop, then the exception will get swallowed up. (If we're just
108# idling in the main loop, then it will pass the exception along, but it won't
109# propagate it from Python code. Sigh.) But sys.excepthook will still get
110# called with such exceptions.
111def gtk_main_quit_on_fatal_exceptions_enable():
112    oldhook = sys.excepthook
113    def gtk_main_quit_on_fatal_exception(type, val, tb):
114        if issubclass(type, (KeyboardInterrupt, SystemExit)):
115            print "Shutting down main-loop"
116            gtk_main_quit_really()
117        if issubclass(type, RuntimeError) and "recursion" in val.message:
118            # We weren't getting tracebacks from this -- maybe calling oldhook
119            # was hitting the limit again or something? -- so try this
120            # instead. (I don't know why print_exception wouldn't trigger the
121            # same problem as calling oldhook, though.)
122            print traceback.print_exception(type, val, tb)
123            print "Maximum recursion depth exceeded"
124        else:
125            return oldhook(type, val, tb)
126    sys.excepthook = gtk_main_quit_on_fatal_exception