After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 620593 - Events are missing the attributes
Events are missing the attributes
Status: RESOLVED FIXED
Product: pygobject
Classification: Bindings
Component: introspection
unspecified
Other Linux
: Normal normal
: ---
Assigned To: Nobody's working on this now (help wanted and appreciated)
Python bindings maintainers
Depends on:
Blocks:
 
 
Reported: 2010-06-04 19:03 UTC by Toms Bauģis
Modified: 2010-07-30 13:53 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
proxying getter to proper object, v1 (2.62 KB, patch)
2010-06-15 13:43 UTC, Toms Bauģis
none Details | Review
override gdk.Event to return attribute from the proper event object. (2.40 KB, patch)
2010-07-27 19:39 UTC, Tomeu Vizoso
committed Details | Review
override gdk.Event to return attribute from the proper event object (3.94 KB, patch)
2010-07-30 13:45 UTC, Tomeu Vizoso
committed Details | Review

Description Toms Bauģis 2010-06-04 19:03:28 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()
Comment 1 Steve Frécinaux 2010-06-09 09:02:09 UTC
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.
Comment 2 Steve Frécinaux 2010-06-09 09:42:55 UTC
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().
Comment 3 Toms Bauģis 2010-06-09 11:02:41 UTC
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
Comment 4 Steve Frécinaux 2010-06-15 08:44:59 UTC
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)
Comment 5 Toms Bauģis 2010-06-15 13:43:36 UTC
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 6 johnp 2010-06-21 18:59:53 UTC
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.
Comment 7 Steve Frécinaux 2010-06-22 07:15:26 UTC
> 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.
Comment 8 Tomeu Vizoso 2010-07-27 19:39:05 UTC
Created attachment 166664 [details] [review]
override gdk.Event to return attribute from the proper event object.

Rebased
Comment 9 Tomeu Vizoso 2010-07-30 08:32:20 UTC
Thanks!

Attachment 166664 [details] pushed as e7bb395 - override gdk.Event to return attribute from the proper event object.
Comment 10 Tomeu Vizoso 2010-07-30 13:01:00 UTC
Sorry, pushed it by mistake, looking at it now.
Comment 11 Tomeu Vizoso 2010-07-30 13:45:26 UTC
Created attachment 166836 [details] [review]
override gdk.Event to return attribute from the proper event object
Comment 12 Tomeu Vizoso 2010-07-30 13:53:07 UTC
Thanks!

Attachment 166836 [details] pushed as 99c7322 - override gdk.Event to return attribute from the proper event object