GNOME Bugzilla – Bug 620593
Events are missing the attributes
Last modified: 2010-07-30 13:53:10 UTC
Sample code below yields to "AttributeError: 'Event' object has no attribute 'width' ". event.type reveals that it is indeed the configure event and thus should have the width attribute (http://library.gnome.org/devel/gdk/stable/gdk-Event-Structures.html#GdkEventConfigure). from gi.repository import Gtk def on_configure(window, event): print event.type print event.width window = Gtk.Window() window.connect("configure_event", on_configure) window.show_all() Gtk.main()
Actually, events are there but as GdkEvent is an union, you need to first get the GdkEventConfigure inside it, by using event.configure. Hence you should be able to do print event.configure.width The real bug here is that pygi should be able to somehow do the conversion from GdkEvent to GdkEventConfigure by itself. Annotations were added yesterday in the GtkWidget signals to give the right type information, but unfortunately it still doesn't work within pygi because all the event types share the same gtype, and pygi relies on a { gtype -> python class } mapping.
I expected to be able to fix this by writing a simple override looking like this: class Event(Gdk.Event): def __new__(cls, *args, **kwargs): event = Gdk.Event.__new__(cls) if event.type == Gdk.EventType.KEY_PRESS: return event.key ... return event Event = override(Event) But it's actually not possible because when creating the wrapper from an existing GdkEvent, pygobject calls tp_alloc() but doesn't call tp_new().
well it can be overridden this this way: class Event(Gdk.Event): def __getattr__(self, name): if self.type == Gdk.EventType.KEY_PRESS: return getattr(self.key, name) elif self.type == Gdk.EventType.EXPOSE: return getattr(self.expose, name) elif self.type == Gdk.EventType.MOTION_NOTIFY: return getattr(self.motion, name) return None if that looks fine then the only problem is to figure out automated way to map event proper placeholder by event type so that one would not have to define 30 if/elses
You could have something like this: class Event(Gdk.Event): _union_members = { Gdk.EventType.KEY_PRESS: 'key', Gdk.EventType.EXPOSE: 'expose', ... } def __getattr__(self, name): real_event = getattr(self, self._union_members[self.type]) return getattr(real_event, name)
Created attachment 163676 [details] [review] proxying getter to proper object, v1 mapping as per this fine document: http://developer.gnome.org/doc/GGAD/sec-gdkevent.html * missing tests as i am not sure how to trigger all the events properly. * was not sure what 2BUTTON_PRESS and 3BUTTON_PRESS map to as i don't think those are valid python variables
Comment on attachment 163676 [details] [review] proxying getter to proper object, v1 >From 4734d61ef6889cfc4e946491553785e561c7a64b Mon Sep 17 00:00:00 2001 >From: =?UTF-8?q?Toms=20Bau=C4=A3is?= <toms.baugis@gmail.com> >Date: Tue, 15 Jun 2010 14:40:19 +0100 >Subject: [PATCH] override gdk.Event to return attribute from the proper event object. fixes bug 620593 > >--- > gi/overrides/Gdk.py | 47 ++++++++++++++++++++++++++++++++++++++++++++++- > 1 files changed, 46 insertions(+), 1 deletions(-) > >diff --git a/gi/overrides/Gdk.py b/gi/overrides/Gdk.py >index ac735c6..04422d5 100644 >--- a/gi/overrides/Gdk.py >+++ b/gi/overrides/Gdk.py This part of the patch is not relevant. >@@ -39,11 +39,56 @@ class Rectangle(Gdk.Rectangle): > > def __repr__(self): > return '<Gdk.Rectangle(x=%d, y=%d, width=%d, height=%d)>' % ( >- self.x, self.y, self.width, self.height) >+ self.x, self.y, self.width, self.height) > > Rectangle = override(Rectangle) > > >+class Event(Gdk.Event): Yikes, we have to maintain this? Can it be grabbed from the typelib? If not perhaps we should add union mapping to the gobject-introspection annotations. >+ _union_members = { >+ Gdk.EventType.DELETE: 'any', >+ Gdk.EventType.DESTROY: 'any', >+ Gdk.EventType.EXPOSE: 'expose', >+ Gdk.EventType.MOTION_NOTIFY: 'motion', >+ Gdk.EventType.BUTTON_PRESS: 'button', getattr(Gdk.EventType, '3BUTTON_PRESS'): 'button', # though we should fix this to alias to _3BUTTON_PRESS >+ #Gdk.EventType.2BUTTON_PRESS: 'button', >+ #Gdk.EventType.3BUTTON_PRESS: 'button', >+ Gdk.EventType.BUTTON_RELEASE: 'button', >+ Gdk.EventType.KEY_PRESS: 'key', >+ Gdk.EventType.KEY_RELEASE: 'key', >+ Gdk.EventType.ENTER_NOTIFY: 'crossing', >+ Gdk.EventType.LEAVE_NOTIFY: 'crossing', >+ Gdk.EventType.FOCUS_CHANGE: 'focus_change', >+ Gdk.EventType.CONFIGURE: 'configure', >+ Gdk.EventType.MAP: 'any', >+ Gdk.EventType.UNMAP: 'any', >+ Gdk.EventType.PROPERTY_NOTIFY: 'property', >+ Gdk.EventType.SELECTION_CLEAR: 'selection', >+ Gdk.EventType.SELECTION_REQUEST: 'selection', >+ Gdk.EventType.SELECTION_NOTIFY: 'selection', >+ Gdk.EventType.PROXIMITY_IN: 'proximity', >+ Gdk.EventType.PROXIMITY_OUT: 'proximity', >+ Gdk.EventType.DRAG_ENTER: 'dnd', >+ Gdk.EventType.DRAG_LEAVE: 'dnd', >+ Gdk.EventType.DRAG_MOTION: 'dnd', >+ Gdk.EventType.DRAG_STATUS: 'dnd', >+ Gdk.EventType.DROP_START: 'dnd', >+ Gdk.EventType.DROP_FINISHED: 'dnd', >+ Gdk.EventType.CLIENT_EVENT: 'client', >+ Gdk.EventType.VISIBILITY_NOTIFY: 'visibility', >+ Gdk.EventType.NO_EXPOSE: 'no_expose' >+ } >+ >+ def __getattr__(self, name): Can't we cache the lookup for subsequent calls (my suggestions inline) ? if not self._real_event: >+ real_event = getattr(self, '_union_members').get(self.type) >+ if real_event: self._real_event = getattr(self, real_event) else: self._real_event = self >+ return getattr(self._real_event, name) >+ >+ >+Event = override(Event) >+ > class Color(Gdk.Color): > > def __init__(self, red, green, blue): >-- >1.7.0.4 > Overall it is an elegant solution but would we be better served to make this a part of pygi instead of an override? E.g. whenever an event comes in we analyse the type and send in the correct event object to the callback. Tests are also needed. Ask the Gtk guys how they test events. There should be a way of generating fake events.
> Yikes, we have to maintain this? Can it be grabbed from the typelib? If not > perhaps we should add union mapping to the gobject-introspection annotations. An idea I've thought about was to support some kind of <union type-field="type" mapping-callbacks="gdk_event_get_field_name_for_event_type"> or so, but I'm not sure such practices is very gobject-introspection-friendly. This would fix the very few cases where we use unions. I can think about GdkEvent and ClutterEvent... Other uses are either deprecated or use another C layout, like { type, union { a, b }} instead of { type, a, b } (I can think of GValue or GArgument for those cases) > Overall it is an elegant solution but would we be better served to make this a > part of pygi instead of an override? E.g. whenever an event comes in we > analyse the type and send in the correct event object to the callback. It would be nice but would basically mean that you make pygi depend on Gdk.
Created attachment 166664 [details] [review] override gdk.Event to return attribute from the proper event object. Rebased
Thanks! Attachment 166664 [details] pushed as e7bb395 - override gdk.Event to return attribute from the proper event object.
Sorry, pushed it by mistake, looking at it now.
Created attachment 166836 [details] [review] override gdk.Event to return attribute from the proper event object
Thanks! Attachment 166836 [details] pushed as 99c7322 - override gdk.Event to return attribute from the proper event object