[gtk/event-types] Restructure the GdkEvent type hierarchy



commit f28aa1ba026dad82c4d3a128f99d4e99615a5a52
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Thu Apr 16 17:23:36 2020 +0100

    Restructure the GdkEvent type hierarchy
    
    GdkEvent has been a "I-can't-believe-this-is-not-OOP" type for ages,
    using a union of sub-types. This has always been problematic when it
    comes to implementing accessor functions: either you get generic API
    that takes a GdkEvent and uses a massive switch() to determine which
    event types have the data you're looking for; or you create namespaced
    accessors, but break language bindings horribly, as boxed types cannot
    have derived types.
    
    The recent conversion of GskRenderNode (which had similar issues) to
    GTypeInstance, and the fact that GdkEvent is now a completely opaque
    type, provide us with the chance of moving GdkEvent to GTypeInstance,
    and have sub-types for GdkEvent.
    
    The change from boxed type to GTypeInstance is pretty small, all things
    considered, but ends up cascading to a larger commit, as we still have
    backends and code in GTK trying to access GdkEvent structures directly.
    Additionally, the naming of the public getter functions requires
    renaming all the data structures to conform to the namespace/type-name
    pattern.

 docs/reference/gtk/migrating-3to4.xml |   11 +-
 gdk/broadway/gdkeventsource.c         |   20 +-
 gdk/gdkdisplay.c                      |    2 +-
 gdk/gdkdrop.c                         |   48 +-
 gdk/gdkevents.c                       | 3505 ++++++++++++++++++++-------------
 gdk/gdkevents.h                       |   95 +-
 gdk/gdkeventsprivate.h                |  492 ++---
 gdk/gdksurface.c                      |   11 +-
 gdk/wayland/gdkdevice-wayland.c       |   58 +-
 gdk/wayland/gdksurface-wayland.c      |    7 +-
 gdk/win32/gdkdevicemanager-win32.c    |   14 +-
 gdk/win32/gdkdrag-win32.c             |    3 +-
 gdk/win32/gdkevents-win32.c           |   34 +-
 gdk/win32/gdksurface-win32.c          |    2 +-
 gdk/x11/gdkdevicemanager-xi2.c        |   18 +-
 gdk/x11/gdkdisplay-x11.c              |   29 +-
 gdk/x11/gdkdrag-x11.c                 |   59 +-
 gdk/x11/gdkeventsource.c              |    6 +-
 gdk/x11/gdksurface-x11.c              |    4 +-
 gtk/gtkdroptarget.c                   |    4 +-
 gtk/gtkdroptargetasync.c              |    4 +-
 gtk/gtkeventcontrollerlegacy.c        |    4 +-
 gtk/gtkgesturerotate.c                |    2 +-
 gtk/gtkgesturestylus.c                |    4 +-
 gtk/gtkgesturezoom.c                  |    2 +-
 gtk/gtkiconview.c                     |    7 +-
 gtk/gtkimcontextsimple.c              |    2 +-
 gtk/gtkmain.c                         |   33 +-
 gtk/gtkmarshalers.list                |    1 +
 gtk/gtkpadcontroller.c                |    4 +-
 gtk/gtkwidget.c                       |    6 +-
 gtk/gtkwindow.c                       |   14 +-
 testsuite/gtk/gestures.c              |   14 +-
 testsuite/gtk/shortcuts.c             |  124 +-
 34 files changed, 2685 insertions(+), 1958 deletions(-)
---
diff --git a/docs/reference/gtk/migrating-3to4.xml b/docs/reference/gtk/migrating-3to4.xml
index bb44f1a8a4..65bd1a1443 100644
--- a/docs/reference/gtk/migrating-3to4.xml
+++ b/docs/reference/gtk/migrating-3to4.xml
@@ -299,8 +299,9 @@
         in GTK 4.
       </para>
       <para>
-        GdkEvent is now a strictly read-only boxed type, and you
-        can no longer change any of its fields.
+        GdkEvent is now a strictly read-only type, and you
+        can no longer change any of its fields, or construct new
+        events.
       </para>
     </section>
 
@@ -308,7 +309,7 @@
       <title>Stop using gdk_surface_set_event_compression</title>
       <para>
         Event compression is now always enabled. If you need to see the uncoalesced
-        motion history, use gdk_event_get_motion_history().
+        motion history, use gdk_motion_event_get_history() on the latest motion event.
       </para>
     </section>
 
@@ -318,8 +319,8 @@
         Warping the pointer is disorienting and unfriendly to users.
         GTK 4 does not support it. In special circumstances (such as when
         implementing remote connection UIs) it can be necessary to
-        warp the pointer; in this case, use platform APIs such as XWarpPointer
-        directly.
+        warp the pointer; in this case, use platform APIs such as
+        <function>XWarpPointer()</function> directly.
       </para>
     </section>
 
diff --git a/gdk/broadway/gdkeventsource.c b/gdk/broadway/gdkeventsource.c
index 86e19af155..bfeac00369 100644
--- a/gdk/broadway/gdkeventsource.c
+++ b/gdk/broadway/gdkeventsource.c
@@ -100,7 +100,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
     surface = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER 
(message->pointer.event_surface_id));
     if (surface)
       {
-        event = gdk_event_crossing_new (GDK_ENTER_NOTIFY,
+        event = gdk_crossing_event_new (GDK_ENTER_NOTIFY,
                                         surface,
                                         gdk_seat_get_pointer (seat),
                                         gdk_seat_get_pointer (seat),
@@ -119,7 +119,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
     surface = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER 
(message->pointer.event_surface_id));
     if (surface)
       {
-        event = gdk_event_crossing_new (GDK_LEAVE_NOTIFY,
+        event = gdk_crossing_event_new (GDK_LEAVE_NOTIFY,
                                         surface,
                                         gdk_seat_get_pointer (seat),
                                         gdk_seat_get_pointer (seat),
@@ -141,7 +141,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
     surface = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER 
(message->pointer.event_surface_id));
     if (surface)
       {
-        event = gdk_event_motion_new (surface,
+        event = gdk_motion_event_new (surface,
                                       gdk_seat_get_pointer (seat),
                                       gdk_seat_get_pointer (seat),
                                       NULL,
@@ -165,7 +165,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
     surface = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER 
(message->pointer.event_surface_id));
     if (surface)
       {
-        event = gdk_event_button_new (message->base.type == BROADWAY_EVENT_BUTTON_PRESS
+        event = gdk_button_event_new (message->base.type == BROADWAY_EVENT_BUTTON_PRESS
                                         ? GDK_BUTTON_PRESS
                                         : GDK_BUTTON_RELEASE,
                                       surface,
@@ -188,7 +188,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
     surface = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER 
(message->pointer.event_surface_id));
     if (surface)
       {
-        event = gdk_event_discrete_scroll_new (surface,
+        event = gdk_scroll_event_new_discrete (surface,
                                                gdk_seat_get_pointer (seat),
                                                gdk_seat_get_pointer (seat),
                                                NULL,
@@ -243,7 +243,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
         if (event_type == GDK_TOUCH_BEGIN || event_type == GDK_TOUCH_UPDATE)
           state |= GDK_BUTTON1_MASK;
 
-        event = gdk_event_touch_new (event_type,
+        event = gdk_touch_event_new (event_type,
                                      GUINT_TO_POINTER (message->touch.sequence_id),
                                      surface,
                                      gdk_seat_get_pointer (seat),
@@ -271,7 +271,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
         translated.consumed = 0;
         translated.layout = 0;
         translated.level = 0;
-        event = gdk_event_key_new (message->base.type == BROADWAY_EVENT_KEY_PRESS
+        event = gdk_key_event_new (message->base.type == BROADWAY_EVENT_KEY_PRESS
                                      ? GDK_KEY_PRESS
                                      : GDK_KEY_RELEASE,
                                    surface,
@@ -298,7 +298,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
     surface = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->configure_notify.id));
     if (surface)
       {
-        event = gdk_event_configure_new (surface,
+        event = gdk_configure_event_new (surface,
                                          message->configure_notify.width,
                                          message->configure_notify.height);
 
@@ -329,7 +329,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
     surface = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->focus.old_id));
     if (surface)
       {
-        event = gdk_event_focus_new (surface,
+        event = gdk_focus_event_new (surface,
                                      gdk_seat_get_keyboard (seat),
                                      gdk_seat_get_keyboard (seat),
                                      FALSE);
@@ -340,7 +340,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
     surface = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->focus.new_id));
     if (surface)
       {
-        event = gdk_event_focus_new (surface,
+        event = gdk_focus_event_new (surface,
                                      gdk_seat_get_keyboard (seat),
                                      gdk_seat_get_keyboard (seat),
                                      TRUE);
diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c
index 4e209672fc..9274ca1318 100644
--- a/gdk/gdkdisplay.c
+++ b/gdk/gdkdisplay.c
@@ -505,7 +505,7 @@ generate_grab_broken_event (GdkDisplay *display,
     {
       GdkEvent *event;
 
-      event = gdk_event_grab_broken_new (surface,
+      event = gdk_grab_broken_event_new (surface,
                                          device,
                                          device,
                                          grab_surface,
diff --git a/gdk/gdkdrop.c b/gdk/gdkdrop.c
index 1df4a4ffdb..3ee92a9ecb 100644
--- a/gdk/gdkdrop.c
+++ b/gdk/gdkdrop.c
@@ -915,12 +915,12 @@ gdk_drop_emit_enter_event (GdkDrop  *self,
 
   g_warn_if_fail (!priv->entered);
 
-  event = gdk_event_drag_new (GDK_DRAG_ENTER,
-                              priv->surface,
-                              priv->device,
-                              self,
-                              time,
-                              0, 0);
+  event = gdk_dnd_event_new (GDK_DRAG_ENTER,
+                             priv->surface,
+                             priv->device,
+                             self,
+                             time,
+                             0, 0);
 
   priv->entered = TRUE;
 
@@ -939,12 +939,12 @@ gdk_drop_emit_motion_event (GdkDrop  *self,
 
   g_warn_if_fail (priv->entered);
 
-  event = gdk_event_drag_new (GDK_DRAG_MOTION,
-                              priv->surface,
-                              priv->device,
-                              self,
-                              time,
-                              x, y);
+  event = gdk_dnd_event_new (GDK_DRAG_MOTION,
+                             priv->surface,
+                             priv->device,
+                             self,
+                             time,
+                             x, y);
 
   gdk_drop_do_emit_event (event, dont_queue);
 }
@@ -959,12 +959,12 @@ gdk_drop_emit_leave_event (GdkDrop  *self,
 
   g_warn_if_fail (priv->entered);
 
-  event = gdk_event_drag_new (GDK_DRAG_LEAVE,
-                              priv->surface,
-                              priv->device,
-                              self,
-                              time,
-                              0, 0);
+  event = gdk_dnd_event_new (GDK_DRAG_LEAVE,
+                             priv->surface,
+                             priv->device,
+                             self,
+                             time,
+                             0, 0);
 
   priv->entered = FALSE;
 
@@ -984,12 +984,12 @@ gdk_drop_emit_drop_event (GdkDrop  *self,
   g_warn_if_fail (priv->entered);
   g_warn_if_fail (priv->state == GDK_DROP_STATE_NONE);
 
-  event = gdk_event_drag_new (GDK_DROP_START,
-                              priv->surface,
-                              priv->device,
-                              self,
-                              time,
-                              x, y);
+  event = gdk_dnd_event_new (GDK_DROP_START,
+                             priv->surface,
+                             priv->device,
+                             self,
+                             time,
+                             x, y);
 
   priv->state = GDK_DROP_STATE_DROPPING;
 
diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c
index e99b95a3cd..41706885af 100644
--- a/gdk/gdkevents.c
+++ b/gdk/gdkevents.c
@@ -33,10 +33,11 @@
 #include "gdkkeysprivate.h"
 #include "gdk-private.h"
 
+#include <gobject/gvaluecollector.h>
+
 #include <string.h>
 #include <math.h>
 
-
 /**
  * SECTION:events
  * @Short_description: Functions for handling events from the window system
@@ -51,7 +52,7 @@
  */
 
 /**
- * GdkEvent:
+ * GdkEvent: (ref-func gdk_event_ref) (unref-func gdk_event_unref)
  *
  * The GdkEvent struct contains only private fields and
  * should not be accessed directly.
@@ -64,27 +65,432 @@
  * of related touch events.
  */
 
+static void
+value_event_init (GValue *value)
+{
+  value->data[0].v_pointer = NULL;
+}
+
+static void
+value_event_free_value (GValue *value)
+{
+  if (value->data[0].v_pointer != NULL)
+    gdk_event_unref (value->data[0].v_pointer);
+}
+
+static void
+value_event_copy_value (const GValue *src,
+                        GValue       *dst)
+{
+  if (src->data[0].v_pointer != NULL)
+    dst->data[0].v_pointer = gdk_event_ref (src->data[0].v_pointer);
+  else
+    dst->data[0].v_pointer = NULL;
+}
+
+static gpointer
+value_event_peek_pointer (const GValue *value)
+{
+  return value->data[0].v_pointer;
+}
+
+static char *
+value_event_collect_value (GValue      *value,
+                           guint        n_collect_values,
+                           GTypeCValue *collect_values,
+                           guint        collect_flags)
+{
+  GdkEvent *event = collect_values[0].v_pointer;
+
+  if (event == NULL)
+    {
+      value->data[0].v_pointer = NULL;
+      return NULL;
+    }
+
+  if (event->parent_instance.g_class == NULL)
+    return g_strconcat ("invalid unclassed GdkEvent pointer for "
+                        "value type '",
+                        G_VALUE_TYPE_NAME (value),
+                        "'",
+                        NULL);
+
+  value->data[0].v_pointer = gdk_event_ref (event);
+
+  return NULL;
+}
+
+static gchar *
+value_event_lcopy_value (const GValue *value,
+                         guint         n_collect_values,
+                         GTypeCValue  *collect_values,
+                         guint         collect_flags)
+{
+  GdkEvent **event_p = collect_values[0].v_pointer;
+
+  if (event_p == NULL)
+    return g_strconcat ("value location for '",
+                        G_VALUE_TYPE_NAME (value),
+                        "' passed as NULL",
+                        NULL);
+
+  if (value->data[0].v_pointer == NULL)
+    *event_p = NULL;
+  else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
+    *event_p = value->data[0].v_pointer;
+  else
+    *event_p = gdk_event_ref (value->data[0].v_pointer);
+
+  return NULL;
+}
+
+static void
+gdk_event_finalize (GdkEvent *self)
+{
+  GdkDisplay *display = gdk_event_get_display (self);
+  if (display != NULL)
+    _gdk_display_event_data_free (display, self);
+
+  g_clear_object (&self->surface);
+  g_clear_object (&self->device);
+  g_clear_object (&self->source_device);
+
+  g_type_free_instance ((GTypeInstance *) self);
+}
+
+static GdkModifierType
+gdk_event_real_get_state (GdkEvent *self)
+{
+  return 0;
+}
+
+static gboolean
+gdk_event_real_get_position (GdkEvent *self,
+                             double   *x,
+                             double   *y)
+{
+  *x = NAN;
+  *y = NAN;
+
+  return FALSE;
+}
+
+static GdkEventSequence *
+gdk_event_real_get_sequence (GdkEvent *self)
+{
+  return NULL;
+}
+
+static GdkDeviceTool *
+gdk_event_real_get_tool (GdkEvent *self)
+{
+  return NULL;
+}
+
+static gboolean
+gdk_event_real_get_axes (GdkEvent  *self,
+                         double   **axes,
+                         guint     *n_axes)
+{
+  return FALSE;
+}
+
+static void
+gdk_event_class_init (GdkEventClass *klass)
+{
+  klass->finalize = gdk_event_finalize;
+  klass->get_state = gdk_event_real_get_state;
+  klass->get_position = gdk_event_real_get_position;
+  klass->get_sequence = gdk_event_real_get_sequence;
+  klass->get_tool = gdk_event_real_get_tool;
+  klass->get_axes = gdk_event_real_get_axes;
+}
+
+static void
+gdk_event_init (GdkEvent *self)
+{
+  g_ref_count_init (&self->ref_count);
+}
+
+GType
+gdk_event_get_type (void)
+{
+  static volatile gsize event_type__volatile;
+
+  if (g_once_init_enter (&event_type__volatile))
+    {
+      static const GTypeFundamentalInfo finfo = {
+        (G_TYPE_FLAG_CLASSED |
+         G_TYPE_FLAG_INSTANTIATABLE |
+         G_TYPE_FLAG_DERIVABLE |
+         G_TYPE_FLAG_DEEP_DERIVABLE),
+      };
+
+      static const GTypeValueTable value_table = {
+        value_event_init,
+        value_event_free_value,
+        value_event_copy_value,
+        value_event_peek_pointer,
+        "p",
+        value_event_collect_value,
+        "p",
+        value_event_lcopy_value,
+      };
+
+      const GTypeInfo event_info = {
+        /* Class */
+        sizeof (GdkEventClass),
+        (GBaseInitFunc) NULL,
+        (GBaseFinalizeFunc) NULL,
+        (GClassInitFunc) gdk_event_class_init,
+        (GClassFinalizeFunc) NULL,
+        NULL,
+
+        /* Instance */
+        sizeof (GdkEvent),
+        0,
+        (GInstanceInitFunc) gdk_event_init,
+
+        /* GValue */
+        &value_table,
+      };
+
+      GType event_type =
+        g_type_register_fundamental (g_type_fundamental_next (),
+                                     g_intern_static_string ("GdkEvent"),
+                                     &event_info, &finfo,
+                                     G_TYPE_FLAG_ABSTRACT);
+
+      g_once_init_leave (&event_type__volatile, event_type);
+    }
+
+  return event_type__volatile;
+}
+
+/*< private >
+ * GdkEventTypeInfo:
+ * @instance_size: the size of the instance of a GdkEvent subclass
+ * @instance_init: (nullable): the function to initialize the instance data
+ * @finalize: (nullable): the function to free the instance data
+ * @get_state: (nullable): the function to retrieve the #GdkModifierType
+ *   associated to the event
+ * @get_position: (nullable): the function to retrieve the event coordinates
+ * @get_sequence: (nullable): the function to retrieve the event sequence
+ * @get_tool: (nullable): the function to retrieve the event's device tool
+ * @get_axes: (nullable): the function to retrieve the event's axes
+ *
+ * A structure used when registering a new GdkEvent type.
+ */
+typedef struct {
+  gsize instance_size;
+
+  void (* instance_init) (GdkEvent *event);
+  void (* finalize) (GdkEvent *event);
+
+  GdkModifierType (* get_state) (GdkEvent *event);
+
+  gboolean (* get_position) (GdkEvent *event,
+                             double *x,
+                             double *y);
+
+  GdkEventSequence *(* get_sequence) (GdkEvent *event);
+
+  GdkDeviceTool *(* get_tool) (GdkEvent *event);
+
+  gboolean (* get_axes) (GdkEvent  *event,
+                         double   **axes,
+                         guint     *n_axes);
+} GdkEventTypeInfo;
+
+static void
+gdk_event_generic_class_init (gpointer g_class,
+                              gpointer class_data)
+{
+  GdkEventTypeInfo *info = class_data;
+  GdkEventClass *event_class = g_class;
+
+  /* Optional */
+  if (info->finalize != NULL)
+    event_class->finalize = info->finalize;
+  if (info->get_state != NULL)
+    event_class->get_state = info->get_state;
+  if (info->get_position != NULL)
+    event_class->get_position = info->get_position;
+  if (info->get_sequence != NULL)
+    event_class->get_sequence = info->get_sequence;
+  if (info->get_tool != NULL)
+    event_class->get_tool = info->get_tool;
+  if (info->get_axes != NULL)
+    event_class->get_axes = info->get_axes;
+
+  g_free (info);
+}
+
+static GType
+gdk_event_type_register_static (const char             *type_name,
+                                const GdkEventTypeInfo *type_info)
+{
+  GTypeInfo info;
+
+  info.class_size = sizeof (GdkEventClass);
+  info.base_init = NULL;
+  info.base_finalize = NULL;
+  info.class_init = gdk_event_generic_class_init;
+  info.class_finalize = NULL;
+  info.class_data = g_memdup (type_info, sizeof (GdkEventTypeInfo));
+
+  info.instance_size = type_info->instance_size;
+  info.n_preallocs = 0;
+  info.instance_init = (GInstanceInitFunc) type_info->instance_init;
+  info.value_table = NULL;
+
+  return g_type_register_static (GDK_TYPE_EVENT, type_name, &info, 0);
+}
+
+/* Map GdkEventType to the appropriate GType */
+static GType gdk_event_types[GDK_EVENT_LAST];
+
+/*< private >
+ * GDK_EVENT_TYPE_SLOT:
+ * @ETYPE: a #GdkEventType
+ *
+ * Associates a #GdkEvent type with the given #GdkEventType enumeration.
+ *
+ * This macro can only be used with %GDK_DEFINE_EVENT_TYPE.
+ */
+#define GDK_EVENT_TYPE_SLOT(ETYPE) { gdk_event_types[ETYPE] = gdk_define_event_type_id; }
+
+/*< private >
+ * GDK_DEFINE_EVENT_TYPE:
+ * @TypeName: the type name, in camel case
+ * @type_name: the type name, in snake case
+ * @type_info: the address of the #GdkEventTypeInfo for the event type
+ * @_C_: custom code to call after registering the event type
+ *
+ * Registers a new #GdkEvent subclass with the given @TypeName and @type_info.
+ *
+ * Similarly to %G_DEFINE_TYPE_WITH_CODE, this macro will generate a `get_type()`
+ * function that registers the event type.
+ *
+ * You can specify code to be run after the type registration; the #GType of
+ * the event is available in the `gdk_define_event_type_id` variable.
+ */
+#define GDK_DEFINE_EVENT_TYPE(TypeName, type_name, type_info, _C_) \
+GType \
+type_name ## _get_type (void) \
+{ \
+  static volatile gsize gdk_define_event_type_id__volatile; \
+  if (g_once_init_enter (&gdk_define_event_type_id__volatile)) \
+    { \
+      GType gdk_define_event_type_id = \
+        gdk_event_type_register_static (g_intern_static_string (#TypeName), type_info); \
+      { _C_ } \
+      g_once_init_leave (&gdk_define_event_type_id__volatile, gdk_define_event_type_id); \
+    } \
+  return gdk_define_event_type_id__volatile; \
+}
+
+#define GDK_EVENT_SUPER(event) \
+  ((GdkEventClass *) g_type_class_peek (g_type_parent (G_TYPE_FROM_INSTANCE (event))))
+
+/*< private >
+ * gdk_event_alloc:
+ * @event_type: the #GdkEventType to allocate
+ * @surface: (nullable): the #GdkSurface of the event
+ * @device: (nullable): the #GdkDevice of the event
+ * @source_device: (nullable): the source #GdkDevice of the event
+ * @time_: the event serial
+ *
+ * Allocates a #GdkEvent for the given @event_type, and sets its
+ * common fields with the given parameters.
+ *
+ * Returns: (transfer full): the newly allocated #GdkEvent instance
+ */
+static gpointer
+gdk_event_alloc (GdkEventType event_type,
+                 GdkSurface   *surface,
+                 GdkDevice    *device,
+                 GdkDevice    *source_device,
+                 guint32       time_)
+{
+  g_assert (event_type >= GDK_DELETE && event_type < GDK_EVENT_LAST);
+  g_assert (gdk_event_types[event_type] != G_TYPE_INVALID);
+
+  GdkEvent *event = (GdkEvent *) g_type_create_instance (gdk_event_types[event_type]);
+
+  GDK_NOTE (EVENTS, {
+            char *str = g_enum_to_string (GDK_TYPE_EVENT_TYPE, event_type);
+            g_message ("Allocating a new %s for event type %s",
+                       g_type_name (gdk_event_types[event_type]), str);
+            g_free (str);
+            });
+
+  event->event_type = event_type;
+  event->surface = surface != NULL ? g_object_ref (surface) : NULL;
+  event->device = device != NULL ? g_object_ref (device) : NULL;
+  event->source_device = source_device != NULL ? g_object_ref (source_device) : NULL;
+  event->time = time_;
+
+  return event;
+}
+
+static void
+gdk_event_init_types_once (void)
+{
+  g_type_ensure (GDK_TYPE_BUTTON_EVENT);
+  g_type_ensure (GDK_TYPE_CONFIGURE_EVENT);
+  g_type_ensure (GDK_TYPE_CROSSING_EVENT);
+  g_type_ensure (GDK_TYPE_DELETE_EVENT);
+  g_type_ensure (GDK_TYPE_DND_EVENT);
+  g_type_ensure (GDK_TYPE_FOCUS_EVENT);
+  g_type_ensure (GDK_TYPE_GRAB_BROKEN_EVENT);
+  g_type_ensure (GDK_TYPE_KEY_EVENT);
+  g_type_ensure (GDK_TYPE_MOTION_EVENT);
+  g_type_ensure (GDK_TYPE_PAD_EVENT);
+  g_type_ensure (GDK_TYPE_PROXIMITY_EVENT);
+  g_type_ensure (GDK_TYPE_SCROLL_EVENT);
+  g_type_ensure (GDK_TYPE_TOUCH_EVENT);
+  g_type_ensure (GDK_TYPE_TOUCHPAD_EVENT);
+}
+
+/*< private >
+ * gdk_event_init_types:
+ *
+ * Initializes all GdkEvent types.
+ */
+void
+gdk_event_init_types (void)
+{
+  static volatile gsize event_types__volatile;
+
+  if (g_once_init_enter (&event_types__volatile))
+    {
+      gboolean initialized = FALSE;
+
+      gdk_event_init_types_once ();
+      initialized = TRUE;
 
-G_DEFINE_BOXED_TYPE (GdkEvent, gdk_event,
-                     gdk_event_ref,
-                     gdk_event_unref)
+      g_once_init_leave (&event_types__volatile, initialized);
+    }
+}
 
+#ifdef G_ENABLE_DEBUG
 static gboolean
 check_event_sanity (GdkEvent *event)
 {
-  if (event->any.device != NULL &&
-      gdk_surface_get_display (event->any.surface) != gdk_device_get_display (event->any.device))
+  if (event->device != NULL &&
+      gdk_surface_get_display (event->surface) != gdk_device_get_display (event->device))
     {
-      char *type = g_enum_to_string (GDK_TYPE_EVENT_TYPE, event->any.type);
+      char *type = g_enum_to_string (GDK_TYPE_EVENT_TYPE, event->event_type);
       g_warning ("Event of type %s with mismatched device display", type);
       g_free (type);
       return FALSE;
     }
 
-  if (event->any.source_device != NULL &&
-      gdk_surface_get_display (event->any.surface) != gdk_device_get_display (event->any.source_device))
+  if (event->source_device != NULL &&
+      gdk_surface_get_display (event->surface) != gdk_device_get_display (event->source_device))
     {
-      char *type = g_enum_to_string (GDK_TYPE_EVENT_TYPE, event->any.type);
+      char *type = g_enum_to_string (GDK_TYPE_EVENT_TYPE, event->event_type);
       g_warning ("Event of type %s with mismatched source device display", type);
       g_free (type);
       return FALSE;
@@ -92,12 +498,15 @@ check_event_sanity (GdkEvent *event)
 
   return TRUE;
 }
+#endif
 
 void
 _gdk_event_emit (GdkEvent *event)
 {
+#ifdef G_ENABLE_DEBUG
   if (!check_event_sanity (event))
     return;
+#endif
 
   if (gdk_drag_handle_source_event (event))
     return;
@@ -132,13 +541,13 @@ _gdk_event_queue_find_first (GdkDisplay *display)
     {
       GdkEvent *event = tmp_list->data;
 
-      if ((event->any.flags & GDK_EVENT_PENDING) == 0 &&
-         (!paused || (event->any.flags & GDK_EVENT_FLUSHED) != 0))
+      if ((event->flags & GDK_EVENT_PENDING) == 0 &&
+         (!paused || (event->flags & GDK_EVENT_FLUSHED) != 0))
         {
           if (pending_motion)
             return pending_motion;
 
-          if (event->any.type == GDK_MOTION_NOTIFY && (event->any.flags & GDK_EVENT_FLUSHED) == 0)
+          if (event->event_type == GDK_MOTION_NOTIFY && (event->flags & GDK_EVENT_FLUSHED) == 0)
             pending_motion = tmp_list;
           else
             return tmp_list;
@@ -258,15 +667,16 @@ _gdk_event_unqueue (GdkDisplay *display)
 }
 
 static void
-gdk_event_push_history (GdkEvent *event,
-                        GdkEvent *history_event)
+gdk_motion_event_push_history (GdkEvent *event,
+                               GdkEvent *history_event)
 {
+  GdkMotionEvent *self = (GdkMotionEvent *) event;
   GdkTimeCoord *hist;
   GdkDevice *device;
   gint i, n_axes;
 
-  g_assert (event->any.type == GDK_MOTION_NOTIFY);
-  g_assert (history_event->any.type == GDK_MOTION_NOTIFY);
+  g_assert (GDK_IS_EVENT_TYPE (event, GDK_MOTION_NOTIFY));
+  g_assert (GDK_IS_EVENT_TYPE (history_event, GDK_MOTION_NOTIFY));
 
   hist = g_new0 (GdkTimeCoord, 1);
 
@@ -276,7 +686,7 @@ gdk_event_push_history (GdkEvent *event,
   for (i = 0; i <= MIN (n_axes, GDK_MAX_TIMECOORD_AXES); i++)
     gdk_event_get_axis (history_event, i, &hist->axes[i]);
 
-  event->motion.history = g_list_prepend (event->motion.history, hist);
+  self->history = g_list_prepend (self->history, hist);
 }
 
 void
@@ -297,25 +707,25 @@ _gdk_event_queue_handle_motion_compression (GdkDisplay *display)
     {
       GdkEvent *event = tmp_list->data;
 
-      if (event->any.flags & GDK_EVENT_PENDING)
+      if (event->flags & GDK_EVENT_PENDING)
         break;
 
-      if (event->any.type != GDK_MOTION_NOTIFY)
+      if (event->event_type != GDK_MOTION_NOTIFY)
         break;
 
       if (pending_motion_surface != NULL &&
-          pending_motion_surface != event->any.surface)
+          pending_motion_surface != event->surface)
         break;
 
       if (pending_motion_device != NULL &&
-          pending_motion_device != event->any.device)
+          pending_motion_device != event->device)
         break;
 
       if (!last_motion)
         last_motion = event;
 
-      pending_motion_surface = event->any.surface;
-      pending_motion_device = event->any.device;
+      pending_motion_surface = event->surface;
+      pending_motion_device = event->device;
       pending_motions = tmp_list;
 
       tmp_list = tmp_list->prev;
@@ -325,11 +735,15 @@ _gdk_event_queue_handle_motion_compression (GdkDisplay *display)
     {
       GList *next = pending_motions->next;
 
-      if (last_motion &&
-          (last_motion->motion.state &
-           (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK |
-            GDK_BUTTON4_MASK | GDK_BUTTON5_MASK)))
-        gdk_event_push_history (last_motion, pending_motions->data);
+      if (last_motion != NULL)
+        {
+          GdkModifierType state = gdk_event_get_modifier_state (last_motion);
+
+          if (state &
+              (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK |
+               GDK_BUTTON4_MASK | GDK_BUTTON5_MASK))
+           gdk_motion_event_push_history (last_motion, pending_motions->data);
+        }
 
       gdk_event_unref (pending_motions->data);
       g_queue_delete_link (&display->queued_events, pending_motions);
@@ -353,7 +767,7 @@ _gdk_event_queue_flush (GdkDisplay *display)
   for (tmp_list = display->queued_events.head; tmp_list; tmp_list = tmp_list->next)
     {
       GdkEvent *event = tmp_list->data;
-      event->any.flags |= GDK_EVENT_FLUSHED;
+      event->flags |= GDK_EVENT_FLUSHED;
     }
 }
 
@@ -363,20 +777,21 @@ _gdk_event_queue_flush (GdkDisplay *display)
  *
  * Increase the ref count of @event.
  *
- * Returns: @event
+ * Returns: (transfer full): @event
  */
 GdkEvent *
 gdk_event_ref (GdkEvent *event)
 {
-  event->any.ref_count++;
+  g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
+
+  g_ref_count_inc (&event->ref_count);
+
   return event;
 }
 
-static void gdk_event_free (GdkEvent *event);
-
 /**
  * gdk_event_unref:
- * @event: a #GdkEvent
+ * @event: (transfer full): a #GdkEvent
  *
  * Decrease the ref count of @event, and free it
  * if the last reference is dropped.
@@ -384,9 +799,10 @@ static void gdk_event_free (GdkEvent *event);
 void
 gdk_event_unref (GdkEvent *event)
 {
-  event->any.ref_count--;
-  if (event->any.ref_count == 0)
-    gdk_event_free (event);
+  g_return_if_fail (GDK_IS_EVENT (event));
+
+  if (g_ref_count_dec (&event->ref_count))
+    GDK_EVENT_GET_CLASS (event)->finalize (event);
 }
 
 /**
@@ -401,71 +817,31 @@ gdk_event_unref (GdkEvent *event)
 gboolean
 gdk_event_get_pointer_emulated (GdkEvent *event)
 {
-  return event->any.pointer_emulated;
-}
-
-static void
-gdk_event_free (GdkEvent *event)
-{
-  GdkDisplay *display;
-
-  switch ((guint) event->any.type)
+  switch ((int) event->event_type)
     {
-    case GDK_ENTER_NOTIFY:
-    case GDK_LEAVE_NOTIFY:
-      g_clear_object (&event->crossing.child_surface);
-      break;
-
-    case GDK_DRAG_ENTER:
-    case GDK_DRAG_LEAVE:
-    case GDK_DRAG_MOTION:
-    case GDK_DROP_START:
-      g_clear_object (&event->dnd.drop);
-      break;
-
-    case GDK_BUTTON_PRESS:
-    case GDK_BUTTON_RELEASE:
-      g_clear_object (&event->button.tool);
-      g_free (event->button.axes);
-      break;
-
     case GDK_TOUCH_BEGIN:
-    case GDK_TOUCH_UPDATE:
     case GDK_TOUCH_END:
+    case GDK_TOUCH_UPDATE:
     case GDK_TOUCH_CANCEL:
-      g_free (event->touch.axes);
-      break;
-
-    case GDK_MOTION_NOTIFY:
-      g_clear_object (&event->motion.tool);
-      g_free (event->motion.axes);
-      g_list_free_full (event->motion.history, g_free);
-      break;
+      {
+        GdkTouchEvent *tevent = (GdkTouchEvent *) event;
 
-    case GDK_PROXIMITY_IN:
-    case GDK_PROXIMITY_OUT:
-      g_clear_object (&event->proximity.tool);
-      break;
+        return tevent->pointer_emulated;
+      }
 
     case GDK_SCROLL:
-      g_clear_object (&event->scroll.tool);
-      break;
+    case GDK_SCROLL_SMOOTH:
+      {
+        GdkScrollEvent *sevent = (GdkScrollEvent *) event;
+
+        return sevent->pointer_emulated;
+      }
 
     default:
       break;
     }
 
-  display = gdk_event_get_display (event);
-  if (display)
-    _gdk_display_event_data_free (display, event);
-
-  if (event->any.surface)
-    g_object_unref (event->any.surface);
-
-  g_clear_object (&event->any.device);
-  g_clear_object (&event->any.source_device);
-
-  g_free (event);
+  return FALSE;
 }
 
 /**
@@ -485,65 +861,32 @@ gdk_event_get_axis (GdkEvent   *event,
                    double     *value)
 {
   double *axes;
+  guint n_axes;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
 
   if (axis_use == GDK_AXIS_X || axis_use == GDK_AXIS_Y)
     {
-      gdouble x, y;
-
-      switch ((guint) event->any.type)
-       {
-        case GDK_MOTION_NOTIFY:
-         x = event->motion.x;
-         y = event->motion.y;
-         break;
-       case GDK_BUTTON_PRESS:
-       case GDK_BUTTON_RELEASE:
-         x = event->button.x;
-         y = event->button.y;
-         break;
-        case GDK_TOUCH_BEGIN:
-        case GDK_TOUCH_UPDATE:
-        case GDK_TOUCH_END:
-        case GDK_TOUCH_CANCEL:
-         x = event->touch.x;
-         y = event->touch.y;
-         break;
-       case GDK_ENTER_NOTIFY:
-       case GDK_LEAVE_NOTIFY:
-         x = event->crossing.x;
-         y = event->crossing.y;
-         break;
-       default:
-         return FALSE;
-       }
-
-      if (axis_use == GDK_AXIS_X && value)
+      double x, y;
+
+      if (!gdk_event_get_position (event, &x, &y))
+        return FALSE;
+
+      if (axis_use == GDK_AXIS_X && value != NULL)
        *value = x;
-      if (axis_use == GDK_AXIS_Y && value)
+      if (axis_use == GDK_AXIS_Y && value != NULL)
        *value = y;
 
       return TRUE;
     }
-  else if (event->any.type == GDK_BUTTON_PRESS ||
-          event->any.type == GDK_BUTTON_RELEASE)
-    {
-      axes = event->button.axes;
-    }
-  else if (event->any.type == GDK_TOUCH_BEGIN ||
-           event->any.type == GDK_TOUCH_UPDATE ||
-           event->any.type == GDK_TOUCH_END ||
-           event->any.type == GDK_TOUCH_CANCEL)
-    {
-      axes = event->touch.axes;
-    }
-  else if (event->any.type == GDK_MOTION_NOTIFY)
-    {
-      axes = event->motion.axes;
-    }
-  else
+
+  if (!gdk_event_get_axes (event, &axes, &n_axes))
+    return FALSE;
+
+  if (axis_use >= gdk_device_get_n_axes (event->device))
     return FALSE;
 
-  return gdk_device_get_axis (event->any.device, axes, axis_use, value);
+  return gdk_device_get_axis (event->device, axes, axis_use, value);
 }
 
 /**
@@ -564,11 +907,11 @@ gdk_event_triggers_context_menu (GdkEvent *event)
 {
   g_return_val_if_fail (event != NULL, FALSE);
 
-  if (event->any.type == GDK_BUTTON_PRESS)
+  if (event->event_type == GDK_BUTTON_PRESS)
     {
-      GdkEventButton *bevent = (GdkEventButton *) event;
+      GdkButtonEvent *bevent = (GdkButtonEvent *) event;
 
-      g_return_val_if_fail (GDK_IS_SURFACE (bevent->any.surface), FALSE);
+      g_return_val_if_fail (GDK_IS_SURFACE (event->surface), FALSE);
 
       if (bevent->button == GDK_BUTTON_SECONDARY &&
           ! (bevent->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK)))
@@ -736,1368 +1079,1963 @@ gdk_event_get_axes (GdkEvent  *event,
                     double   **axes,
                     guint     *n_axes)
 {
-  GdkDevice *source_device;
+  g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
 
-  if (!event)
-    return FALSE;
+  return GDK_EVENT_GET_CLASS (event)->get_axes (event, axes, n_axes);
+}
 
-  source_device = gdk_event_get_source_device (event);
+/**
+ * gdk_event_get_event_type:
+ * @event: a #GdkEvent
+ *
+ * Retrieves the type of the event.
+ *
+ * Returns: a #GdkEventType
+ */
+GdkEventType
+gdk_event_get_event_type (GdkEvent *event)
+{
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
 
-  if (!source_device)
-    return FALSE;
+  return event->event_type;
+}
 
-  if (event->any.type == GDK_MOTION_NOTIFY)
-    {
-      *axes = event->motion.axes;
-      *n_axes = gdk_device_get_n_axes (source_device);
-      return TRUE;
-    }
-  else if (event->any.type == GDK_BUTTON_PRESS ||
-           event->any.type == GDK_BUTTON_RELEASE)
-    {
-      *axes = event->button.axes;
-      *n_axes = gdk_device_get_n_axes (source_device);
-      return TRUE;
-    }
-  else if (event->any.type == GDK_TOUCH_BEGIN ||
-           event->any.type == GDK_TOUCH_UPDATE ||
-           event->any.type == GDK_TOUCH_END ||
-           event->any.type == GDK_TOUCH_CANCEL)
-    {
-      *axes = event->touch.axes;
-      *n_axes = gdk_device_get_n_axes (source_device);
-      return TRUE;
-    }
+/**
+ * gdk_event_get_surface:
+ * @event: a #GdkEvent
+ *
+ * Extracts the #GdkSurface associated with an event.
+ *
+ * Returns: (transfer none): The #GdkSurface associated with the event
+ */
+GdkSurface *
+gdk_event_get_surface (GdkEvent *event)
+{
+  g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
 
-  return FALSE;
+  return event->surface;
 }
 
 /**
- * gdk_event_get_motion_history:
- * @event: a #GdkEvent of type %GDK_MOTION_NOTIFY
+ * gdk_event_get_device:
+ * @event: a #GdkEvent.
  *
- * Retrieves the history of the @event motion, as a list of time and
- * coordinates.
+ * Returns the device of an event.
  *
- * Returns: (transfer container) (element-type GdkTimeCoord) (nullable): a list
- *   of time and coordinates
+ * Returns: (nullable) (transfer none): a #GdkDevice.
  */
-GList *
-gdk_event_get_motion_history (GdkEvent       *event)
+GdkDevice *
+gdk_event_get_device (GdkEvent *event)
 {
-  if (event->any.type != GDK_MOTION_NOTIFY)
-    return NULL;
-  return g_list_reverse (g_list_copy (event->motion.history));
+  g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
+
+  return event->device;
 }
 
-GdkEvent *
-gdk_event_button_new (GdkEventType     type,
-                      GdkSurface      *surface,
-                      GdkDevice       *device,
-                      GdkDevice       *source_device,
-                      GdkDeviceTool   *tool,
-                      guint32          time,
-                      GdkModifierType  state,
-                      guint            button,
-                      double           x,
-                      double           y,
-                      double          *axes)
+/**
+ * gdk_event_get_source_device:
+ * @event: a #GdkEvent
+ *
+ * This function returns the hardware (slave) #GdkDevice that has
+ * triggered the event, falling back to the virtual (master) device
+ * (as in gdk_event_get_device()) if the event wasn’t caused by
+ * interaction with a hardware device. This may happen for example
+ * in synthesized crossing events after a #GdkSurface updates its
+ * geometry or a grab is acquired/released.
+ *
+ * If the event does not contain a device field, this function will
+ * return %NULL.
+ *
+ * Returns: (nullable) (transfer none): a #GdkDevice, or %NULL.
+ **/
+GdkDevice *
+gdk_event_get_source_device (GdkEvent *event)
 {
-  GdkEventButton *event;
+  g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
 
-  g_return_val_if_fail (type == GDK_BUTTON_PRESS || 
-                        type == GDK_BUTTON_RELEASE, NULL);
-
-  event = g_new0 (GdkEventButton, 1);
-  event->any.ref_count = 1;
-  event->any.type = type;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->tool = tool ? g_object_ref (tool) : NULL;
-  event->axes = NULL;
-  event->state = state;
-  event->button = button;
-  event->x = x;
-  event->y = y;
-  event->axes = axes;
+  if (event->source_device)
+    return event->source_device;
 
-  return (GdkEvent *)event;
+  return event->device;
 }
 
-GdkEvent *
-gdk_event_motion_new (GdkSurface      *surface,
-                      GdkDevice       *device,
-                      GdkDevice       *source_device,
-                      GdkDeviceTool   *tool,
-                      guint32          time,
-                      GdkModifierType  state,
-                      double           x,
-                      double           y,
-                      double          *axes)
+/**
+ * gdk_event_get_device_tool:
+ * @event: a #GdkEvent
+ *
+ * If the event was generated by a device that supports
+ * different tools (eg. a tablet), this function will
+ * return a #GdkDeviceTool representing the tool that
+ * caused the event. Otherwise, %NULL will be returned.
+ *
+ * Note: the #GdkDeviceTools will be constant during
+ * the application lifetime, if settings must be stored
+ * persistently across runs, see gdk_device_tool_get_serial()
+ *
+ * Returns: (transfer none) (nullable): The current device tool, or %NULL
+ **/
+GdkDeviceTool *
+gdk_event_get_device_tool (GdkEvent *event)
 {
-  GdkEventMotion *event = g_new0 (GdkEventMotion, 1);
-
-  event->any.ref_count = 1;
-  event->any.type = GDK_MOTION_NOTIFY;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->tool = tool ? g_object_ref (tool) : NULL;
-  event->state = state;
-  event->x = x;
-  event->y = y;
-  event->axes = axes;
-  event->state = state;
+  g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
 
-  return (GdkEvent *)event;
+  return GDK_EVENT_GET_CLASS (event)->get_tool (event);
 }
 
-GdkEvent *
-gdk_event_crossing_new (GdkEventType     type,
-                        GdkSurface      *surface,
-                        GdkDevice       *device,
-                        GdkDevice       *source_device,
-                        guint32          time,
-                        GdkModifierType  state,
-                        double           x,
-                        double           y,
-                        GdkCrossingMode  mode,
-                        GdkNotifyType    detail)
+/**
+ * gdk_event_get_time:
+ * @event: a #GdkEvent
+ *
+ * Returns the time stamp from @event, if there is one; otherwise
+ * returns #GDK_CURRENT_TIME.
+ *
+ * Returns: time stamp field from @event
+ **/
+guint32
+gdk_event_get_time (GdkEvent *event)
 {
-  GdkEventCrossing *event;
+  g_return_val_if_fail (GDK_IS_EVENT (event), GDK_CURRENT_TIME);
 
-  g_return_val_if_fail (type == GDK_ENTER_NOTIFY ||
-                        type == GDK_LEAVE_NOTIFY, NULL);
+  return event->time;
+}
 
-  event = g_new0 (GdkEventCrossing, 1);
+/**
+ * gdk_event_get_display:
+ * @event: a #GdkEvent
+ *
+ * Retrieves the #GdkDisplay associated to the @event.
+ *
+ * Returns: (transfer none) (nullable): a #GdkDisplay
+ */
+GdkDisplay *
+gdk_event_get_display (GdkEvent *event)
+{
+  g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
 
-  event->any.ref_count = 1;
-  event->any.type = type;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->state = state;
-  event->x = x;
-  event->y = y;
-  event->mode = mode;
-  event->detail = detail;
+  if (event->surface)
+    return gdk_surface_get_display (event->surface);
 
-  return (GdkEvent *)event;
+  return NULL;
 }
 
-GdkEvent *
-gdk_event_proximity_new (GdkEventType   type,
-                         GdkSurface    *surface,
-                         GdkDevice     *device,
-                         GdkDevice     *source_device,
-                         GdkDeviceTool *tool,
-                         guint32        time)
+/**
+ * gdk_event_get_event_sequence:
+ * @event: a #GdkEvent
+ *
+ * If @event is a touch event, returns the #GdkEventSequence
+ * to which the event belongs. Otherwise, return %NULL.
+ *
+ * Returns: (transfer none): the event sequence that the event belongs to
+ */
+GdkEventSequence *
+gdk_event_get_event_sequence (GdkEvent *event)
 {
-  GdkEventProximity *event;
+  g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
 
-  g_return_val_if_fail (type == GDK_PROXIMITY_IN ||
-                        type == GDK_PROXIMITY_OUT, NULL);
+  return GDK_EVENT_GET_CLASS (event)->get_sequence (event);
+}
+
+/**
+ * gdk_event_get_modifier_state:
+ * @event: a #GdkEvent
+ *
+ * Returns the modifier state field of an event.
+ *
+ * Returns: the modifier state of @event
+ **/
+GdkModifierType
+gdk_event_get_modifier_state (GdkEvent *event)
+{
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
 
-  event = g_new0 (GdkEventProximity, 1);
+  return GDK_EVENT_GET_CLASS (event)->get_state (event);
+}
 
-  event->any.ref_count = 1;
-  event->any.type = type;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->tool = tool ? g_object_ref (tool) : NULL;
+/**
+ * gdk_event_get_position:
+ * @event: a #GdkEvent
+ * @x: (out): location to put event surface x coordinate
+ * @y: (out): location to put event surface y coordinate
+ *
+ * Extract the event surface relative x/y coordinates from an event.
+ **/
+gboolean
+gdk_event_get_position (GdkEvent *event,
+                        double   *x,
+                        double   *y)
+{
+  g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
 
-  return (GdkEvent *)event;
+  return GDK_EVENT_GET_CLASS (event)->get_position (event, x, y);
 }
 
-GdkEvent *
-gdk_event_key_new (GdkEventType      type,
-                   GdkSurface       *surface,
-                   GdkDevice        *device,
-                   GdkDevice        *source_device,
-                   guint32           time,
-                   guint             keycode,
-                   GdkModifierType   state,
-                   gboolean          is_modifier,
-                   GdkTranslatedKey *translated,
-                   GdkTranslatedKey *no_lock)
+/* {{{ GdkButtonEvent */
+
+static void
+gdk_button_event_finalize (GdkEvent *event)
 {
-  GdkEventKey *event;
+  GdkButtonEvent *self = (GdkButtonEvent *) event;
 
-  g_return_val_if_fail (type == GDK_KEY_PRESS ||
-                        type == GDK_KEY_RELEASE, NULL);
+  g_clear_object (&self->tool);
+  g_clear_pointer (&self->axes, g_free);
 
-  event = g_new0 (GdkEventKey, 1);
-  
-  event->any.ref_count = 1;
-  event->any.type = type;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->keycode = keycode;
-  event->state = state;
-  event->any.key_is_modifier = is_modifier;
-  event->translated[0] = *translated;
-  event->translated[1] = *no_lock;
+  GDK_EVENT_SUPER (event)->finalize (event);
+}
+
+static GdkModifierType
+gdk_button_event_get_state (GdkEvent *event)
+{
+  GdkButtonEvent *self = (GdkButtonEvent *) event;
 
-  return (GdkEvent *)event;
+  return self->state;
 }
 
-GdkEvent *
-gdk_event_configure_new (GdkSurface *surface,
-                         int         width,
-                         int         height)
+static gboolean
+gdk_button_event_get_position (GdkEvent *event,
+                               double   *x,
+                               double   *y)
 {
-  GdkEventConfigure *event = g_new0 (GdkEventConfigure, 1);
+  GdkButtonEvent *self = (GdkButtonEvent *) event;
 
-  event->any.ref_count = 1;
-  event->any.type = GDK_CONFIGURE;
-  event->any.time = GDK_CURRENT_TIME;
-  event->any.surface = g_object_ref (surface);
-  event->width = width;
-  event->height = height;
+  *x = self->x;
+  *y = self->y;
 
-  return (GdkEvent *)event;
+  return TRUE;
 }
 
-GdkEvent *
-gdk_event_delete_new (GdkSurface *surface)
+static GdkDeviceTool *
+gdk_button_event_get_tool (GdkEvent *event)
 {
-  GdkEventAny *event = g_new0 (GdkEventAny, 1);
-
-  event->ref_count = 1;
-  event->type = GDK_DELETE;
-  event->time = GDK_CURRENT_TIME;
-  event->surface = g_object_ref (surface);
+  GdkButtonEvent *self = (GdkButtonEvent *) event;
 
-  return (GdkEvent *)event;
+  return self->tool;
 }
 
-GdkEvent *
-gdk_event_focus_new (GdkSurface *surface,
-                     GdkDevice  *device,
-                     GdkDevice  *source_device,
-                     gboolean    focus_in)
+static gboolean
+gdk_button_event_get_axes (GdkEvent  *event,
+                           double   **axes,
+                           guint     *n_axes)
 {
-  GdkEventFocus *event = g_new0 (GdkEventFocus, 1);
+  GdkButtonEvent *self = (GdkButtonEvent *) event;
+  GdkDevice *source_device = gdk_event_get_source_device (event);
+
+  if (source_device == NULL)
+    return FALSE;
 
-  event->any.ref_count = 1;
-  event->any.type = GDK_FOCUS_CHANGE;
-  event->any.time = GDK_CURRENT_TIME;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->any.focus_in = focus_in;
+  *axes = self->axes;
+  *n_axes = gdk_device_get_n_axes (source_device);
 
-  return  (GdkEvent *)event;
+  return TRUE;
 }
 
+static const GdkEventTypeInfo gdk_button_event_info = {
+  sizeof (GdkButtonEvent),
+  NULL,
+  gdk_button_event_finalize,
+  gdk_button_event_get_state,
+  gdk_button_event_get_position,
+  NULL,
+  gdk_button_event_get_tool,
+  gdk_button_event_get_axes,
+};
+
+GDK_DEFINE_EVENT_TYPE (GdkButtonEvent, gdk_button_event,
+                       &gdk_button_event_info,
+                       GDK_EVENT_TYPE_SLOT (GDK_BUTTON_PRESS)
+                       GDK_EVENT_TYPE_SLOT (GDK_BUTTON_RELEASE))
+
 GdkEvent *
-gdk_event_scroll_new (GdkSurface      *surface,
+gdk_button_event_new (GdkEventType     type,
+                      GdkSurface      *surface,
                       GdkDevice       *device,
                       GdkDevice       *source_device,
                       GdkDeviceTool   *tool,
                       guint32          time,
                       GdkModifierType  state,
-                      double           delta_x,
-                      double           delta_y,
-                      gboolean         is_stop)
+                      guint            button,
+                      double           x,
+                      double           y,
+                      double          *axes)
 {
-  GdkEventScroll *event = g_new0 (GdkEventScroll, 1);
+  g_return_val_if_fail (type == GDK_BUTTON_PRESS ||
+                        type == GDK_BUTTON_RELEASE, NULL);
+
+  GdkButtonEvent *self = gdk_event_alloc (type, surface, device, source_device, time);
 
-  event->any.ref_count = 1;
-  event->any.type = GDK_SCROLL;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->tool = tool ? g_object_ref (tool) : NULL;
-  event->state = state;
-  event->x = NAN;
-  event->y = NAN;
-  event->direction = GDK_SCROLL_SMOOTH;
-  event->delta_x = delta_x;
-  event->delta_y = delta_y;
-  event->any.scroll_is_stop = is_stop;
+  self->tool = tool != NULL ? g_object_ref (tool) : NULL;
+  self->axes = axes;
+  self->state = state;
+  self->button = button;
+  self->x = x;
+  self->y = y;
 
-  return (GdkEvent *)event;
+  return (GdkEvent *) self;
 }
 
-GdkEvent *
-gdk_event_discrete_scroll_new (GdkSurface         *surface,
-                               GdkDevice          *device,
-                               GdkDevice          *source_device,
-                               GdkDeviceTool      *tool,
-                               guint32             time,
-                               GdkModifierType     state,
-                               GdkScrollDirection  direction,
-                               gboolean            emulated)
+/**
+ * gdk_button_event_get_button:
+ * @event: (type GdkButtonEvent): a button event
+ *
+ * Extract the button number from a button event.
+ *
+ * Returns: the button of @event
+ **/
+guint
+gdk_button_event_get_button (GdkEvent *event)
 {
-  GdkEventScroll *event = g_new0 (GdkEventScroll, 1);
+  GdkButtonEvent *self = (GdkButtonEvent *) event;
 
-  event->any.ref_count = 1;
-  event->any.type = GDK_SCROLL;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->tool = tool ? g_object_ref (tool) : NULL;
-  event->state = state;
-  event->x = NAN;
-  event->y = NAN;
-  event->direction = direction;
-  event->any.pointer_emulated = emulated;
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_BUTTON_PRESS) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_BUTTON_RELEASE), 0);
 
-  return (GdkEvent *)event;
+  return self->button;
 }
 
-GdkEvent *
-gdk_event_touch_new (GdkEventType      type,
-                     GdkEventSequence *sequence,
-                     GdkSurface       *surface,
-                     GdkDevice        *device,
-                     GdkDevice        *source_device,
-                     guint32           time,
-                     GdkModifierType   state,
-                     double            x,
-                     double            y,
-                     double           *axes,
-                     gboolean          emulating)
-{
-  GdkEventTouch *event;
-
-  g_return_val_if_fail (type == GDK_TOUCH_BEGIN ||
-                        type == GDK_TOUCH_END ||
-                        type == GDK_TOUCH_UPDATE ||
-                        type == GDK_TOUCH_CANCEL, NULL);
+/* }}} */
 
-  event = g_new0 (GdkEventTouch, 1);
+/* {{{ GdkKeyEvent */
 
-  event->any.ref_count = 1;
-  event->any.type = type;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->sequence = sequence;
-  event->state = state;
-  event->x = x;
-  event->y = y;
-  event->axes = axes;
-  event->any.touch_emulating = emulating;
-  event->any.pointer_emulated = emulating;
+static GdkModifierType
+gdk_key_event_get_state (GdkEvent *event)
+{
+  GdkKeyEvent *self = (GdkKeyEvent *) event;
 
-  return (GdkEvent *)event;
+  return self->state;
 }
 
+static const GdkEventTypeInfo gdk_key_event_info = {
+  sizeof (GdkKeyEvent),
+  NULL,
+  NULL,
+  gdk_key_event_get_state,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+};
+
+GDK_DEFINE_EVENT_TYPE (GdkKeyEvent, gdk_key_event,
+                       &gdk_key_event_info,
+                       GDK_EVENT_TYPE_SLOT (GDK_KEY_PRESS)
+                       GDK_EVENT_TYPE_SLOT (GDK_KEY_RELEASE))
+
+/*< private >
+ * gdk_key_event_new:
+ * @type: the event type, either %GDK_KEY_PRESS or %GDK_KEY_RELEASE
+ * @surface: the #GdkSurface of the event
+ * @device: the #GdkDevice related to the event
+ * @source_device: the source #GdkDevice related to the event
+ * @time: the event's timestamp
+ * @keycode: the keycode of the event
+ * @state: the modifiers state
+ * @is_modifier: whether the event is a modifiers only event
+ * @translated: the translated key data for the given @state
+ * @no_lock: the translated key data without the given @state
+ *
+ * Creates a new #GdkKeyEvent.
+ *
+ * Returns: (transfer full) (type GdkKeyEvent): the newly created #GdkEvent
+ */
 GdkEvent *
-gdk_event_touchpad_swipe_new (GdkSurface *surface,
-                              GdkDevice  *device,
-                              GdkDevice  *source_device,
-                              guint32     time,
-                              GdkModifierType state,
-                              GdkTouchpadGesturePhase phase,
-                              double      x,
-                              double      y,
-                              int         n_fingers,
-                              double      dx,
-                              double      dy)
+gdk_key_event_new (GdkEventType      type,
+                   GdkSurface       *surface,
+                   GdkDevice        *device,
+                   GdkDevice        *source_device,
+                   guint32           time,
+                   guint             keycode,
+                   GdkModifierType   state,
+                   gboolean          is_modifier,
+                   GdkTranslatedKey *translated,
+                   GdkTranslatedKey *no_lock)
 {
-  GdkEventTouchpadSwipe *event = g_new0 (GdkEventTouchpadSwipe, 1);
+  g_return_val_if_fail (type == GDK_KEY_PRESS ||
+                        type == GDK_KEY_RELEASE, NULL);
+
+  GdkKeyEvent *self = gdk_event_alloc (type, surface, device, source_device, time);
+  GdkEvent *event = (GdkEvent *) self;
 
-  event->any.ref_count = 1;
-  event->any.type = GDK_TOUCHPAD_SWIPE;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->state = state;
-  event->phase = phase;
-  event->x = x;
-  event->y = y;
-  event->dx = dx;
-  event->dy = dy;
-  event->n_fingers = n_fingers;
+  self->keycode = keycode;
+  self->state = state;
+  self->key_is_modifier = is_modifier;
+  self->translated[0] = *translated;
+  self->translated[1] = *no_lock;
 
-  return (GdkEvent *)event;
+  return event;
 }
 
-GdkEvent *
-gdk_event_touchpad_pinch_new (GdkSurface *surface,
-                              GdkDevice  *device,
-                              GdkDevice  *source_device,
-                              guint32     time,
-                              GdkModifierType state,
-                              GdkTouchpadGesturePhase phase,
-                              double      x,
-                              double      y,
-                              int         n_fingers,
-                              double      dx,
-                              double      dy,
-                              double      scale,
-                              double      angle_delta)
+/**
+ * gdk_key_event_get_keyval:
+ * @event: (type GdkKeyEvent): a key event
+ *
+ * Extracts the keyval from a key event.
+ *
+ * Returns: the keyval of @event
+ */
+guint
+gdk_key_event_get_keyval (GdkEvent *event)
 {
-  GdkEventTouchpadPinch *event = g_new0 (GdkEventTouchpadPinch, 1);
+  GdkKeyEvent *self = (GdkKeyEvent *) event;
 
-  event->any.ref_count = 1;
-  event->any.type = GDK_TOUCHPAD_PINCH;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->state = state;
-  event->phase = phase;
-  event->x = x;
-  event->y = y;
-  event->dx = dx;
-  event->dy = dy;
-  event->n_fingers = n_fingers;
-  event->scale = scale;
-  event->angle_delta = angle_delta;
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), 0);
 
-  return (GdkEvent *)event;
+  return self->translated[0].keyval;
 }
 
-GdkEvent *
-gdk_event_pad_ring_new (GdkSurface *surface,
-                        GdkDevice  *device,
-                        GdkDevice  *source_device,
-                        guint32     time,
-                        guint       group,
-                        guint       index,
-                        guint       mode,
-                        double      value)
+/**
+ * gdk_key_event_get_keycode:
+ * @event: (type GdkKeyEvent): a key event
+ *
+ * Extracts the keycode from a key event.
+ *
+ * Returns: the keycode of @event
+ */
+guint
+gdk_key_event_get_keycode (GdkEvent *event)
 {
-  GdkEventPadAxis *event = g_new0 (GdkEventPadAxis, 1);
+  GdkKeyEvent *self = (GdkKeyEvent *) event;
 
-  event->any.ref_count = 1;
-  event->any.type = GDK_PAD_RING;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->group = group;
-  event->index = index;
-  event->mode = mode;
-  event->value = value;
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), 0);
 
-  return (GdkEvent *)event;
+  return self->keycode;
 }
 
-GdkEvent *
-gdk_event_pad_strip_new (GdkSurface *surface,
-                         GdkDevice  *device,
-                         GdkDevice  *source_device,
-                         guint32     time,
-                         guint       group,
-                         guint       index,
-                         guint       mode,
-                         double      value)
+/**
+ * gdk_key_event_get_level:
+ * @event: (type GdkKeyEvent): a key event
+ *
+ * Extracts the shift level from a key event.
+ *
+ * Returns: the shift level of @event
+ */
+guint
+gdk_key_event_get_level (GdkEvent *event)
+{
+  GdkKeyEvent *self = (GdkKeyEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), 0);
+
+  return self->translated[0].level;
+}
+
+/**
+ * gdk_key_event_get_layout:
+ * @event: (type GdkKeyEvent): a key event
+ *
+ * Extracts the layout from a key event.
+ *
+ * Returns: the layout of @event
+ */
+guint
+gdk_key_event_get_layout (GdkEvent *event)
+{
+  GdkKeyEvent *self = (GdkKeyEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), 0);
+
+  return self->translated[0].layout;
+}
+
+/**
+ * gdk_key_event_get_consumed_modifiers:
+ * @event: (type GdkKeyEvent): a key event
+ *
+ * Extracts the consumed modifiers from a key event.
+ *
+ * Returns: the consumed modifiers or @event
+ */
+GdkModifierType
+gdk_key_event_get_consumed_modifiers (GdkEvent *event)
+{
+  GdkKeyEvent *self = (GdkKeyEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), 0);
+
+  return self->translated[0].consumed;
+}
+
+/**
+ * gdk_key_event_is_modifier:
+ * @event: (type GdkKeyEvent): a key event
+ *
+ * Extracts whether the key event is for a modifier key.
+ *
+ * Returns: %TRUE if the @event is for a modifier key
+ */
+gboolean
+gdk_key_event_is_modifier (GdkEvent *event)
+{
+  GdkKeyEvent *self = (GdkKeyEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), FALSE);
+
+  return self->key_is_modifier;
+}
+
+/**
+ * gdk_key_event_matches:
+ * @event: (type GdkKeyEvent): a key #GdkEvent
+ * @keyval: the keyval to match
+ * @modifiers: the modifiers to match
+ *
+ * Matches a key event against a keyboard shortcut that is specified
+ * as a keyval and modifiers. Partial matches are possible where the
+ * combination matches if the currently active group is ignored.
+ *
+ * Note that we ignore Caps Lock for matching.
+ *
+ * Returns: a GdkKeyMatch value describing whether @event matches
+ */
+GdkKeyMatch
+gdk_key_event_matches (GdkEvent        *event,
+                       guint            keyval,
+                       GdkModifierType  modifiers)
+{
+  GdkKeyEvent *self = (GdkKeyEvent *) event;
+  guint keycode;
+  GdkModifierType state;
+  guint ev_keyval;
+  int layout;
+  int level;
+  GdkModifierType consumed_modifiers;
+  GdkModifierType shift_group_mask;
+  gboolean group_mod_is_accel_mod = FALSE;
+  const GdkModifierType mask = GDK_CONTROL_MASK |
+                               GDK_SHIFT_MASK |
+                               GDK_ALT_MASK |
+                               GDK_SUPER_MASK |
+                               GDK_HYPER_MASK |
+                               GDK_META_MASK;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), GDK_KEY_MATCH_NONE);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), GDK_KEY_MATCH_NONE);
+
+  keycode = self->keycode;
+  state = self->state & ~GDK_LOCK_MASK;
+  ev_keyval = self->translated[1].keyval;
+  layout = self->translated[1].layout;
+  level = self->translated[1].level;
+  consumed_modifiers = self->translated[1].consumed;
+
+  /* if the group-toggling modifier is part of the default accel mod
+   * mask, and it is active, disable it for matching
+   *
+   * FIXME: get shift group mask from backends
+   */
+  shift_group_mask = 0;
+
+  if (mask & shift_group_mask)
+    group_mod_is_accel_mod = TRUE;
+
+  if ((modifiers & ~consumed_modifiers & mask) == (state & ~consumed_modifiers & mask))
+    {
+      /* modifier match */
+      GdkKeymapKey *keys;
+      int n_keys;
+      int i;
+      guint key;
+
+      /* Shift gets consumed and applied for the event,
+       * so apply it to our keyval to match
+       */
+      key = keyval;
+      if (modifiers & GDK_SHIFT_MASK)
+        {
+          if (key == GDK_KEY_Tab)
+            key = GDK_KEY_ISO_Left_Tab;
+          else
+            key = gdk_keyval_to_upper (key);
+        }
+
+      if (ev_keyval == key && /* exact match */
+          (!group_mod_is_accel_mod ||
+           (state & shift_group_mask) == (modifiers & shift_group_mask)))
+        {
+          return GDK_KEY_MATCH_EXACT;
+        }
+
+      gdk_display_map_keyval (gdk_event_get_display (event), keyval, &keys, &n_keys);
+
+      for (i = 0; i < n_keys; i++)
+        {
+          if (keys[i].keycode == keycode &&
+              keys[i].level == level &&
+              /* Only match for group if it's an accel mod */
+              (!group_mod_is_accel_mod || keys[i].group == layout))
+            {
+              /* partial match */
+              g_free (keys);
+
+              return GDK_KEY_MATCH_PARTIAL;
+            }
+        }
+
+      g_free (keys);
+    }
+
+  return GDK_KEY_MATCH_NONE;
+}
+
+/**
+ * gdk_key_event_get_match:
+ * @event: (type GdkKeyEvent): a key #GdkEvent
+ * @keyval: (out): return location for a keyval
+ * @modifiers: (out): return location for modifiers
+ *
+ * Gets a keyval and modifier combination that will cause
+ * gdk_event_match() to successfully match the given event.
+ *
+ * Returns: %TRUE on success
+ */
+gboolean
+gdk_key_event_get_match (GdkEvent        *event,
+                         guint           *keyval,
+                         GdkModifierType *modifiers)
 {
-  GdkEventPadAxis *event = g_new0 (GdkEventPadAxis, 1);
+  GdkKeyEvent *self = (GdkKeyEvent *) event;
+  guint key;
+  guint accel_key;
+  GdkModifierType accel_mods;
+  GdkModifierType consumed_modifiers;
+  const GdkModifierType mask = GDK_CONTROL_MASK |
+                               GDK_SHIFT_MASK |
+                               GDK_ALT_MASK |
+                               GDK_SUPER_MASK |
+                               GDK_HYPER_MASK |
+                               GDK_META_MASK;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), FALSE);
+
+  accel_key = self->translated[1].keyval;
+  accel_mods = self->state;
+  consumed_modifiers = self->translated[1].consumed;
+
+  if (accel_key == GDK_KEY_Sys_Req &&
+      (accel_mods & GDK_ALT_MASK) != 0)
+    {
+      /* HACK: we don't want to use SysRq as a keybinding (but we do
+       * want Alt+Print), so we avoid translation from Alt+Print to SysRq
+       */
+      *keyval = GDK_KEY_Print;
+      *modifiers = accel_mods & mask;
+      return TRUE;
+    }
+
+  key = gdk_keyval_to_lower (accel_key);
+
+  if (key == GDK_KEY_ISO_Left_Tab)
+    key = GDK_KEY_Tab;
+
+  accel_mods &= mask & ~consumed_modifiers;
+
+  if (accel_key != key)
+    accel_mods |= GDK_SHIFT_MASK;
+
+  *keyval = key;
+  *modifiers = accel_mods;
+
+  return TRUE;
+}
 
-  event->any.ref_count = 1;
-  event->any.type = GDK_PAD_STRIP;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->group = group;
-  event->index = index;
-  event->mode = mode;
-  event->value = value;
+/* }}} */
 
-  return (GdkEvent *)event;
+/* {{{ GdkConfigureEvent */
+
+static gboolean
+gdk_configure_event_get_position (GdkEvent *event,
+                                  double   *x,
+                                  double   *y)
+{
+  GdkConfigureEvent *self = (GdkConfigureEvent *) event;
+
+  *x = self->x;
+  *y = self->y;
+
+  return TRUE;
 }
 
+static const GdkEventTypeInfo gdk_configure_event_info = {
+  sizeof (GdkConfigureEvent),
+  NULL,
+  NULL,
+  NULL,
+  gdk_configure_event_get_position,
+  NULL,
+  NULL,
+  NULL,
+};
+
+GDK_DEFINE_EVENT_TYPE (GdkConfigureEvent, gdk_configure_event,
+                       &gdk_configure_event_info,
+                       GDK_EVENT_TYPE_SLOT (GDK_CONFIGURE))
+
 GdkEvent *
-gdk_event_pad_button_new (GdkEventType  type,
-                          GdkSurface   *surface,
-                          GdkDevice    *device,
-                          GdkDevice    *source_device,
-                          guint32       time,
-                          guint         group,
-                          guint         button,
-                          guint         mode)
+gdk_configure_event_new (GdkSurface *surface,
+                         int         width,
+                         int         height)
+{
+  GdkConfigureEvent *self;
+
+  g_return_val_if_fail (width >= 0 && height >= 0, NULL);
+
+  self = gdk_event_alloc (GDK_CONFIGURE, surface, NULL, NULL, GDK_CURRENT_TIME);
+  self->width = width;
+  self->height = height;
+
+  return (GdkEvent *) self;
+}
+
+/**
+ * gdk_configure_event_get_size:
+ * @event: (type GdkConfigureEvent): a configure event
+ * @width: (out): return location for surface width
+ * @height: (out): return location for surface height
+ *
+ * Extracts the surface size from a configure event.
+ */
+void
+gdk_configure_event_get_size (GdkEvent *event,
+                              int      *width,
+                              int      *height)
+{
+  GdkConfigureEvent *self = (GdkConfigureEvent *) event;
+
+  g_return_if_fail (GDK_IS_EVENT (event));
+  g_return_if_fail (GDK_IS_EVENT_TYPE (event, GDK_CONFIGURE));
+
+  *width = self->width;
+  *height = self->height;
+}
+
+/* }}} */
+
+/* {{{ GdkTouchEvent */
+
+static void
+gdk_touch_event_finalize (GdkEvent *event)
+{
+  GdkTouchEvent *self = (GdkTouchEvent *) event;
+
+  g_clear_pointer (&self->axes, g_free);
+
+  GDK_EVENT_SUPER (event)->finalize (event);
+}
+
+static GdkModifierType
+gdk_touch_event_get_state (GdkEvent *event)
+{
+  GdkTouchEvent *self = (GdkTouchEvent *) event;
+
+  return self->state;
+}
+
+static gboolean
+gdk_touch_event_get_position (GdkEvent *event,
+                              double   *x,
+                              double   *y)
+{
+  GdkTouchEvent *self = (GdkTouchEvent *) event;
+
+  *x = self->x;
+  *y = self->y;
+
+  return TRUE;
+}
+
+static GdkEventSequence *
+gdk_touch_event_get_sequence (GdkEvent *event)
+{
+  GdkTouchEvent *self = (GdkTouchEvent *) event;
+
+  return self->sequence;
+}
+
+static gboolean
+gdk_touch_event_get_axes (GdkEvent  *event,
+                          double   **axes,
+                          guint     *n_axes)
+{
+  GdkTouchEvent *self = (GdkTouchEvent *) event;
+  GdkDevice *source_device = gdk_event_get_source_device (event);
+
+  if (source_device == NULL)
+    return FALSE;
+
+  *axes = self->axes;
+  *n_axes = gdk_device_get_n_axes (source_device);
+
+  return TRUE;
+}
+
+static const GdkEventTypeInfo gdk_touch_event_info = {
+  sizeof (GdkTouchEvent),
+  NULL,
+  gdk_touch_event_finalize,
+  gdk_touch_event_get_state,
+  gdk_touch_event_get_position,
+  gdk_touch_event_get_sequence,
+  NULL,
+  gdk_touch_event_get_axes,
+};
+
+GDK_DEFINE_EVENT_TYPE (GdkTouchEvent, gdk_touch_event,
+                       &gdk_touch_event_info,
+                       GDK_EVENT_TYPE_SLOT (GDK_TOUCH_BEGIN)
+                       GDK_EVENT_TYPE_SLOT (GDK_TOUCH_END)
+                       GDK_EVENT_TYPE_SLOT (GDK_TOUCH_UPDATE)
+                       GDK_EVENT_TYPE_SLOT (GDK_TOUCH_CANCEL))
+
+GdkEvent *
+gdk_touch_event_new (GdkEventType      type,
+                     GdkEventSequence *sequence,
+                     GdkSurface       *surface,
+                     GdkDevice        *device,
+                     GdkDevice        *source_device,
+                     guint32           time,
+                     GdkModifierType   state,
+                     double            x,
+                     double            y,
+                     double           *axes,
+                     gboolean          emulating)
+{
+  GdkTouchEvent *self;
+
+  g_return_val_if_fail (type == GDK_TOUCH_BEGIN ||
+                        type == GDK_TOUCH_END ||
+                        type == GDK_TOUCH_UPDATE ||
+                        type == GDK_TOUCH_CANCEL, NULL);
+
+  self = gdk_event_alloc (type, surface, device, source_device, time);
+  self->sequence = sequence;
+  self->state = state;
+  self->x = x;
+  self->y = y;
+  self->axes = axes;
+  self->touch_emulating = emulating;
+  self->pointer_emulated = emulating;
+
+  return (GdkEvent *) self;
+}
+
+/**
+ * gdk_touch_event_get_emulating_pointer:
+ * @event: (type GdkTouchEvent): a touch event
+ *
+ * Extracts whether a touch event is emulating a pointer event.
+ *
+ * Returns: %TRUE if @event is emulating
+ **/
+gboolean
+gdk_touch_event_get_emulating_pointer (GdkEvent *event)
+{
+  GdkTouchEvent *self = (GdkTouchEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCH_BEGIN) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_TOUCH_UPDATE) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_TOUCH_END) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_TOUCH_CANCEL), FALSE);
+
+  return self->touch_emulating;
+}
+
+/* }}} */
+
+/* {{{ GdkCrossingEvent */
+
+static void
+gdk_crossing_event_finalize (GdkEvent *event)
+{
+  GdkCrossingEvent *self = (GdkCrossingEvent *) event;
+
+  g_clear_object (&self->child_surface);
+
+  GDK_EVENT_SUPER (self)->finalize (event);
+}
+
+static GdkModifierType
+gdk_crossing_event_get_state (GdkEvent *event)
+{
+  GdkCrossingEvent *self = (GdkCrossingEvent *) event;
+
+  return self->state;
+}
+
+static gboolean
+gdk_crossing_event_get_position (GdkEvent *event,
+                                 double   *x,
+                                 double   *y)
+{
+  GdkCrossingEvent *self = (GdkCrossingEvent *) event;
+
+  *x = self->x;
+  *y = self->y;
+
+  return TRUE;
+}
+
+static const GdkEventTypeInfo gdk_crossing_event_info = {
+  sizeof (GdkCrossingEvent),
+  NULL,
+  gdk_crossing_event_finalize,
+  gdk_crossing_event_get_state,
+  gdk_crossing_event_get_position,
+  NULL,
+  NULL,
+  NULL,
+};
+
+GDK_DEFINE_EVENT_TYPE (GdkCrossingEvent, gdk_crossing_event,
+                       &gdk_crossing_event_info,
+                       GDK_EVENT_TYPE_SLOT (GDK_ENTER_NOTIFY)
+                       GDK_EVENT_TYPE_SLOT (GDK_LEAVE_NOTIFY))
+
+GdkEvent *
+gdk_crossing_event_new (GdkEventType     type,
+                        GdkSurface      *surface,
+                        GdkDevice       *device,
+                        GdkDevice       *source_device,
+                        guint32          time,
+                        GdkModifierType  state,
+                        double           x,
+                        double           y,
+                        GdkCrossingMode  mode,
+                        GdkNotifyType    detail)
+{
+  GdkCrossingEvent *self;
+
+  g_return_val_if_fail (type == GDK_ENTER_NOTIFY ||
+                        type == GDK_LEAVE_NOTIFY, NULL);
+
+  self = gdk_event_alloc (type, surface, device, source_device, time);
+
+  self->state = state;
+  self->x = x;
+  self->y = y;
+  self->mode = mode;
+  self->detail = detail;
+
+  return (GdkEvent *) self;
+}
+
+/**
+ * gdk_crossing_event_get_mode:
+ * @event: (type GdkCrossingEvent): a crossing event
+ *
+ * Extracts the crossing mode from a crossing event.
+ *
+ * Returns: the mode of @event
+ */
+GdkCrossingMode
+gdk_crossing_event_get_mode (GdkEvent *event)
+{
+  GdkCrossingEvent *self = (GdkCrossingEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_ENTER_NOTIFY) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_LEAVE_NOTIFY), 0);
+
+  return self->mode;
+}
+
+/**
+ * gdk_crossing_event_get_focus:
+ * @event: (type GdkCrossingEvent): a crossing event
+ *
+ * Checks if the @event surface is the focus surface.
+ *
+ * Returns: %TRUE if the surface is the focus surface
+ */
+gboolean
+gdk_crossing_event_get_focus (GdkEvent *event)
+{
+  GdkCrossingEvent *self = (GdkCrossingEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_ENTER_NOTIFY) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_LEAVE_NOTIFY), FALSE);
+
+  return self->focus;
+}
+
+/**
+ * gdk_crossing_event_get_detail:
+ * @event: (type GdkCrossingEvent): a crossing event
+ *
+ * Extracts the notify detail from a crossing event.
+ *
+ * Returns: the notify detail of @event
+ */
+GdkNotifyType
+gdk_crossing_event_get_detail (GdkEvent *event)
+{
+  GdkCrossingEvent *self = (GdkCrossingEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_ENTER_NOTIFY) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_LEAVE_NOTIFY), 0);
+
+  return self->detail;
+}
+
+/* }}} */
+
+/* {{{ GdkDeleteEvent */
+
+static const GdkEventTypeInfo gdk_delete_event_info = {
+  sizeof (GdkDeleteEvent),
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+};
+
+GDK_DEFINE_EVENT_TYPE (GdkDeleteEvent, gdk_delete_event,
+                       &gdk_delete_event_info,
+                       GDK_EVENT_TYPE_SLOT (GDK_DELETE))
+
+GdkEvent *
+gdk_delete_event_new (GdkSurface *surface)
+{
+  return gdk_event_alloc (GDK_DELETE, surface, NULL, NULL, GDK_CURRENT_TIME);
+}
+
+/* }}} */
+
+/* {{{ GdkFocusEvent */
+
+static const GdkEventTypeInfo gdk_focus_event_info = {
+  sizeof (GdkFocusEvent),
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+};
+
+GDK_DEFINE_EVENT_TYPE (GdkFocusEvent, gdk_focus_event,
+                       &gdk_focus_event_info,
+                       GDK_EVENT_TYPE_SLOT (GDK_FOCUS_CHANGE))
+
+GdkEvent *
+gdk_focus_event_new (GdkSurface *surface,
+                     GdkDevice  *device,
+                     GdkDevice  *source_device,
+                     gboolean    focus_in)
+{
+  GdkFocusEvent *self = gdk_event_alloc (GDK_FOCUS_CHANGE, surface, device, source_device, GDK_CURRENT_TIME);
+
+  self->focus_in = focus_in;
+
+  return (GdkEvent *) self;
+}
+
+/**
+ * gdk_focus_event_get_in:
+ * @event: (type GdkScrollEvent): a focus change event
+ *
+ * Extracts whether this event is about focus entering or
+ * leaving the surface.
+ *
+ * Returns: %TRUE of the focus is entering
+ */
+gboolean
+gdk_focus_event_get_in (GdkEvent *event)
+{
+  GdkFocusEvent *self = (GdkFocusEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_FOCUS_CHANGE), FALSE);
+
+  return self->focus_in;
+}
+
+/* }}} */
+
+/* {{{ GdkScrollEvent */
+
+static void
+gdk_scroll_event_init (GdkEvent *event)
+{
+  GdkScrollEvent *self = (GdkScrollEvent *) event;
+
+  self->x = NAN;
+  self->y = NAN;
+}
+
+static void
+gdk_scroll_event_finalize (GdkEvent *event)
 {
-  GdkEventPadButton *event;
+  GdkScrollEvent *self = (GdkScrollEvent *) event;
 
-  g_return_val_if_fail (type == GDK_PAD_BUTTON_PRESS ||
-                        type == GDK_PAD_BUTTON_RELEASE, NULL);
+  g_clear_object (&self->tool);
 
-  event = g_new0 (GdkEventPadButton, 1);
+  GDK_EVENT_SUPER (self)->finalize (event);
+}
 
-  event->any.ref_count = 1;
-  event->any.type = type;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->group = group;
-  event->button = button;
-  event->mode = mode;
+static GdkModifierType
+gdk_scroll_event_get_state (GdkEvent *event)
+{
+  GdkScrollEvent *self = (GdkScrollEvent *) event;
 
-  return (GdkEvent *)event;
+  return self->state;
 }
 
-GdkEvent *
-gdk_event_pad_group_mode_new (GdkSurface *surface,
-                              GdkDevice  *device,
-                              GdkDevice  *source_device,
-                              guint32     time,
-                              guint       group,
-                              guint       mode)
+static gboolean
+gdk_scroll_event_get_position (GdkEvent *event,
+                               double   *x,
+                               double   *y)
 {
-  GdkEventPadGroupMode *event = g_new0 (GdkEventPadGroupMode, 1);
+  GdkScrollEvent *self = (GdkScrollEvent *) event;
 
-  event->any.ref_count = 1;
-  event->any.type = GDK_PAD_GROUP_MODE;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->group = group;
-  event->mode = mode;
+  *x = self->x;
+  *y = self->y;
 
-  return (GdkEvent *)event;
+  return TRUE;
 }
 
-GdkEvent *
-gdk_event_drag_new (GdkEventType  type,
-                    GdkSurface   *surface,
-                    GdkDevice    *device,
-                    GdkDrop      *drop,
-                    guint32       time,
-                    double        x,
-                    double        y)
+static GdkDeviceTool *
+gdk_scroll_event_get_tool (GdkEvent *event)
 {
-  GdkEventDND *event;
+  GdkScrollEvent *self = (GdkScrollEvent *) event;
 
-  g_return_val_if_fail (type == GDK_DRAG_ENTER ||
-                        type == GDK_DRAG_MOTION ||
-                        type == GDK_DRAG_LEAVE ||
-                        type == GDK_DROP_START, NULL);
+  return self->tool;
+}
+
+static const GdkEventTypeInfo gdk_scroll_event_info = {
+  sizeof (GdkScrollEvent),
+  gdk_scroll_event_init,
+  gdk_scroll_event_finalize,
+  gdk_scroll_event_get_state,
+  gdk_scroll_event_get_position,
+  NULL,
+  gdk_scroll_event_get_tool,
+  NULL,
+};
+
+GDK_DEFINE_EVENT_TYPE (GdkScrollEvent, gdk_scroll_event,
+                       &gdk_scroll_event_info,
+                       GDK_EVENT_TYPE_SLOT (GDK_SCROLL))
 
-  event = g_new0 (GdkEventDND, 1);
+GdkEvent *
+gdk_scroll_event_new (GdkSurface      *surface,
+                      GdkDevice       *device,
+                      GdkDevice       *source_device,
+                      GdkDeviceTool   *tool,
+                      guint32          time,
+                      GdkModifierType  state,
+                      double           delta_x,
+                      double           delta_y,
+                      gboolean         is_stop)
+{
+  GdkScrollEvent *self = gdk_event_alloc (GDK_SCROLL, surface, device, source_device, time);
 
-  event->any.ref_count = 1;
-  event->any.type = type;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->drop = g_object_ref (drop);
-  event->x = x;
-  event->y = y;
+  self->tool = tool != NULL ? g_object_ref (tool) : NULL;
+  self->state = state;
+  self->direction = GDK_SCROLL_SMOOTH;
+  self->delta_x = delta_x;
+  self->delta_y = delta_y;
+  self->is_stop = is_stop;
 
-  return (GdkEvent *)event;
+  return (GdkEvent *) self;
 }
 
 GdkEvent *
-gdk_event_grab_broken_new (GdkSurface *surface,
-                           GdkDevice  *device,
-                           GdkDevice  *source_device,
-                           GdkSurface *grab_surface,
-                           gboolean    implicit)
+gdk_scroll_event_new_discrete (GdkSurface         *surface,
+                               GdkDevice          *device,
+                               GdkDevice          *source_device,
+                               GdkDeviceTool      *tool,
+                               guint32             time,
+                               GdkModifierType     state,
+                               GdkScrollDirection  direction,
+                               gboolean            emulated)
 {
-  GdkEventGrabBroken *event = g_new0 (GdkEventGrabBroken, 1);
+  GdkScrollEvent *self = gdk_event_alloc (GDK_SCROLL, surface, device, source_device, time);
 
-  event->any.ref_count = 1;
-  event->any.type = GDK_GRAB_BROKEN;
-  event->any.time = GDK_CURRENT_TIME;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->grab_surface = grab_surface;
-  event->implicit = implicit;
-  event->keyboard = gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD;
+  self->tool = tool != NULL ? g_object_ref (tool) : NULL;
+  self->state = state;
+  self->direction = direction;
+  self->pointer_emulated = emulated;
 
-  return (GdkEvent *)event;
+  return (GdkEvent *) self;
 }
 
 /**
- * gdk_event_get_event_type:
- * @event: a #GdkEvent
+ * gdk_scroll_event_get_direction:
+ * @event: (type GdkScrollEvent): a scroll event
  *
- * Retrieves the type of the event.
+ * Extracts the direction of a scroll event.
  *
- * Returns: a #GdkEventType
+ * Returns: the scroll direction of @event
  */
-GdkEventType
-gdk_event_get_event_type (GdkEvent *event)
+GdkScrollDirection
+gdk_scroll_event_get_direction (GdkEvent *event)
 {
-  return event->any.type;
+  GdkScrollEvent *self = (GdkScrollEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_SCROLL), 0);
+
+  return self->direction;
 }
 
 /**
- * gdk_event_get_surface:
- * @event: a #GdkEvent
+ * gdk_scroll_event_get_deltas:
+ * @event: (type GdkScrollEvent): a scroll event
+ * @delta_x: (out): return location for x scroll delta
+ * @delta_y: (out): return location for y scroll delta
  *
- * Extracts the #GdkSurface associated with an event.
+ * Extracts the scroll deltas of a scroll event.
  *
- * Returns: (transfer none): The #GdkSurface associated with the event
+ * The deltas will be zero unless the scroll direction
+ * is %GDK_SCROLL_SMOOTH.
  */
-GdkSurface *
-gdk_event_get_surface (GdkEvent *event)
+void
+gdk_scroll_event_get_deltas (GdkEvent *event,
+                             double   *delta_x,
+                             double   *delta_y)
 {
-  return event->any.surface;
-}
+  GdkScrollEvent *self = (GdkScrollEvent *) event;
 
-/**
- * gdk_event_get_device:
- * @event: a #GdkEvent.
- *
- * Returns the device of an event.
- *
- * Returns: (nullable) (transfer none): a #GdkDevice, or %NULL.
- **/
-GdkDevice *
-gdk_event_get_device (GdkEvent *event)
-{
-  return event->any.device;
+  g_return_if_fail (GDK_IS_EVENT (event));
+  g_return_if_fail (GDK_IS_EVENT_TYPE (event, GDK_SCROLL));
+
+  *delta_x = self->delta_x;
+  *delta_y = self->delta_y;
 }
 
 /**
- * gdk_event_get_source_device:
- * @event: a #GdkEvent
+ * gdk_scroll_event_is_stop:
+ * @event: (type GdkScrollEvent): a scroll event
  *
- * This function returns the hardware (slave) #GdkDevice that has
- * triggered the event, falling back to the virtual (master) device
- * (as in gdk_event_get_device()) if the event wasn’t caused by
- * interaction with a hardware device. This may happen for example
- * in synthesized crossing events after a #GdkSurface updates its
- * geometry or a grab is acquired/released.
+ * Check whether a scroll event is a stop scroll event. Scroll sequences
+ * with smooth scroll information may provide a stop scroll event once the
+ * interaction with the device finishes, e.g. by lifting a finger. This
+ * stop scroll event is the signal that a widget may trigger kinetic
+ * scrolling based on the current velocity.
  *
- * If the event does not contain a device field, this function will
- * return %NULL.
+ * Stop scroll events always have a delta of 0/0.
  *
- * Returns: (nullable) (transfer none): a #GdkDevice, or %NULL.
- **/
-GdkDevice *
-gdk_event_get_source_device (GdkEvent *event)
+ * Returns: %TRUE if the event is a scroll stop event
+ */
+gboolean
+gdk_scroll_event_is_stop (GdkEvent *event)
 {
-  if (event->any.source_device)
-    return event->any.source_device;
+  GdkScrollEvent *self = (GdkScrollEvent *) event;
 
-  return event->any.device;
+  g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_SCROLL), FALSE);
+
+  return self->is_stop;
 }
 
-/**
- * gdk_event_get_device_tool:
- * @event: a #GdkEvent
- *
- * If the event was generated by a device that supports
- * different tools (eg. a tablet), this function will
- * return a #GdkDeviceTool representing the tool that
- * caused the event. Otherwise, %NULL will be returned.
- *
- * Note: the #GdkDeviceTools will be constant during
- * the application lifetime, if settings must be stored
- * persistently across runs, see gdk_device_tool_get_serial()
- *
- * Returns: (transfer none): The current device tool, or %NULL
- **/
-GdkDeviceTool *
-gdk_event_get_device_tool (GdkEvent *event)
-{
-  if (event->any.type == GDK_BUTTON_PRESS ||
-      event->any.type == GDK_BUTTON_RELEASE)
-    return event->button.tool;
-  else if (event->any.type == GDK_MOTION_NOTIFY)
-    return event->motion.tool;
-  else if (event->any.type == GDK_PROXIMITY_IN ||
-           event->any.type == GDK_PROXIMITY_OUT)
-    return event->proximity.tool;
-  else if (event->any.type == GDK_SCROLL)
-    return event->scroll.tool;
+/* }}} */
 
-  return NULL;
-}
+/* {{{ GdkTouchpadEvent */
 
-/**
- * gdk_event_get_time:
- * @event: a #GdkEvent
- * 
- * Returns the time stamp from @event, if there is one; otherwise
- * returns #GDK_CURRENT_TIME.
- * 
- * Returns: time stamp field from @event
- **/
-guint32
-gdk_event_get_time (GdkEvent *event)
+static GdkModifierType
+gdk_touchpad_event_get_state (GdkEvent *event)
 {
-  return event->any.time;
+  GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
+
+  return self->state;
 }
 
-/**
- * gdk_event_get_display:
- * @event: a #GdkEvent
- *
- * Retrieves the #GdkDisplay associated to the @event.
- *
- * Returns: (transfer none) (nullable): a #GdkDisplay
- */
-GdkDisplay *
-gdk_event_get_display (GdkEvent *event)
+static gboolean
+gdk_touchpad_event_get_position (GdkEvent *event,
+                                 double   *x,
+                                 double   *y)
 {
-  if (event->any.surface)
-    return gdk_surface_get_display (event->any.surface);
+  GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
 
-  return NULL;
+  *x = self->x;
+  *y = self->y;
+
+  return TRUE;
 }
 
-/**
- * gdk_event_get_event_sequence:
- * @event: a #GdkEvent
- *
- * If @event is a touch event, returns the #GdkEventSequence
- * to which the event belongs. Otherwise, return %NULL.
- *
- * Returns: (transfer none): the event sequence that the event belongs to
- */
-GdkEventSequence *
-gdk_event_get_event_sequence (GdkEvent *event)
+static const GdkEventTypeInfo gdk_touchpad_event_info = {
+  sizeof (GdkTouchpadEvent),
+  NULL,
+  NULL,
+  gdk_touchpad_event_get_state,
+  gdk_touchpad_event_get_position,
+  NULL,
+  NULL,
+  NULL,
+};
+
+GDK_DEFINE_EVENT_TYPE (GdkTouchpadEvent, gdk_touchpad_event,
+                       &gdk_touchpad_event_info,
+                       GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_SWIPE)
+                       GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_PINCH))
+
+GdkEvent *
+gdk_touchpad_event_new_swipe (GdkSurface *surface,
+                              GdkDevice  *device,
+                              GdkDevice  *source_device,
+                              guint32     time,
+                              GdkModifierType state,
+                              GdkTouchpadGesturePhase phase,
+                              double      x,
+                              double      y,
+                              int         n_fingers,
+                              double      dx,
+                              double      dy)
 {
-  switch ((int) event->any.type)
-    {
-    case GDK_TOUCH_BEGIN:
-    case GDK_TOUCH_UPDATE:
-    case GDK_TOUCH_END:
-    case GDK_TOUCH_CANCEL:
-      return event->touch.sequence;
+  GdkTouchpadEvent *self = gdk_event_alloc (GDK_TOUCHPAD_SWIPE, surface, device, source_device, time);
 
-    case GDK_DRAG_ENTER:
-    case GDK_DRAG_LEAVE:
-    case GDK_DRAG_MOTION:
-    case GDK_DROP_START:
-      return (GdkEventSequence *) event->dnd.drop;
+  self->state = state;
+  self->phase = phase;
+  self->x = x;
+  self->y = y;
+  self->dx = dx;
+  self->dy = dy;
+  self->n_fingers = n_fingers;
 
-    default:
-      return NULL;
-    }
+  return (GdkEvent *) self;
 }
 
-/**
- * gdk_event_get_modifier_state:
- * @event: a #GdkEvent
- *
- * Returns the modifier state field of an event.
- *
- * Returns: the modifier state of @event
- **/
-GdkModifierType
-gdk_event_get_modifier_state (GdkEvent *event)
+GdkEvent *
+gdk_touchpad_event_new_pinch (GdkSurface *surface,
+                              GdkDevice  *device,
+                              GdkDevice  *source_device,
+                              guint32     time,
+                              GdkModifierType state,
+                              GdkTouchpadGesturePhase phase,
+                              double      x,
+                              double      y,
+                              int         n_fingers,
+                              double      dx,
+                              double      dy,
+                              double      scale,
+                              double      angle_delta)
 {
-#if 0
-  g_return_val_if_fail (event->any.type == GDK_ENTER_NOTIFY ||
-                        event->any.type == GDK_LEAVE_NOTIFY ||
-                        event->any.type == GDK_BUTTON_PRESS ||
-                        event->any.type == GDK_BUTTON_RELEASE ||
-                        event->any.type == GDK_MOTION_NOTIFY ||
-                        event->any.type == GDK_TOUCH_BEGIN ||
-                        event->any.type == GDK_TOUCH_UPDATE ||
-                        event->any.type == GDK_TOUCH_END ||
-                        event->any.type == GDK_TOUCH_CANCEL ||
-                        event->any.type == GDK_TOUCHPAD_SWIPE ||
-                        event->any.type == GDK_TOUCHPAD_PINCH||
-                        event->any.type == GDK_SCROLL ||
-                        event->any.type == GDK_KEY_PRESS ||
-                        event->any.type == GDK_KEY_RELEASE, 0);
-#endif
+  GdkTouchpadEvent *self = gdk_event_alloc (GDK_TOUCHPAD_PINCH, surface, device, source_device, time);
 
-  switch ((int)event->any.type)
-    {
-    case GDK_ENTER_NOTIFY:
-    case GDK_LEAVE_NOTIFY:
-      return event->crossing.state;
-    case GDK_BUTTON_PRESS:
-    case GDK_BUTTON_RELEASE:
-      return event->button.state;
-    case GDK_MOTION_NOTIFY:
-      return event->motion.state;
-    case GDK_TOUCH_BEGIN:
-    case GDK_TOUCH_UPDATE:
-    case GDK_TOUCH_END:
-    case GDK_TOUCH_CANCEL:
-      return event->touch.state;
-    case GDK_TOUCHPAD_SWIPE:
-      return event->touchpad_swipe.state;
-    case GDK_TOUCHPAD_PINCH:
-      return event->touchpad_pinch.state;
-    case GDK_SCROLL:
-      return event->scroll.state;
-    case GDK_KEY_PRESS:
-    case GDK_KEY_RELEASE:
-      return event->key.state;
-    default:
-      /* no state field */
-      break;
-    }
+  self->state = state;
+  self->phase = phase;
+  self->x = x;
+  self->y = y;
+  self->dx = dx;
+  self->dy = dy;
+  self->n_fingers = n_fingers;
+  self->scale = scale;
+  self->angle_delta = angle_delta;
 
-  return 0;
+  return (GdkEvent *) self;
 }
 
 /**
- * gdk_event_get_position:
- * @event: a #GdkEvent
- * @x: (out): location to put event surface x coordinate
- * @y: (out): location to put event surface y coordinate
+ * gdk_touchpad_event_get_gesture_phase:
+ * @event: (type GdkTouchpadEvent): a touchpad #GdkEvent
  *
- * Extract the event surface relative x/y coordinates from an event.
+ * Extracts the touchpad gesture phase from a touchpad event.
+ *
+ * Returns: the gesture phase of @event
  **/
-gboolean
-gdk_event_get_position (GdkEvent *event,
-                        double   *x,
-                        double   *y)
+GdkTouchpadGesturePhase
+gdk_touchpad_event_get_gesture_phase (GdkEvent *event)
 {
-#if 0
-  g_return_if_fail (event->any.type == GDK_ENTER_NOTIFY ||
-                    event->any.type == GDK_LEAVE_NOTIFY ||
-                    event->any.type == GDK_BUTTON_PRESS ||
-                    event->any.type == GDK_BUTTON_RELEASE ||
-                    event->any.type == GDK_MOTION_NOTIFY ||
-                    event->any.type == GDK_TOUCH_BEGIN ||
-                    event->any.type == GDK_TOUCH_UPDATE ||
-                    event->any.type == GDK_TOUCH_END ||
-                    event->any.type == GDK_TOUCH_CANCEL ||
-                    event->any.type == GDK_TOUCHPAD_SWIPE ||
-                    event->any.type == GDK_TOUCHPAD_PINCH||
-                    event->any.type == GDK_DRAG_ENTER ||
-                    event->any.type == GDK_DRAG_LEAVE ||
-                    event->any.type == GDK_DRAG_MOTION ||
-                    event->any.type == GDK_DROP_START);
-#endif
-
-  switch ((int)event->any.type)
-    {
-    case GDK_ENTER_NOTIFY:
-    case GDK_LEAVE_NOTIFY:
-      *x = event->crossing.x;
-      *y = event->crossing.y;
-      break;
-    case GDK_BUTTON_PRESS:
-    case GDK_BUTTON_RELEASE:
-      *x = event->button.x;
-      *y = event->button.y;
-      break;
-    case GDK_MOTION_NOTIFY:
-      *x = event->motion.x;
-      *y = event->motion.y;
-      break;
-    case GDK_TOUCH_BEGIN:
-    case GDK_TOUCH_UPDATE:
-    case GDK_TOUCH_END:
-    case GDK_TOUCH_CANCEL:
-      *x = event->touch.x;
-      *y = event->touch.y;
-      break;
-    case GDK_TOUCHPAD_SWIPE:
-      *x = event->touchpad_swipe.x;
-      *y = event->touchpad_swipe.y;
-      break;
-    case GDK_TOUCHPAD_PINCH:
-      *x = event->touchpad_pinch.x;
-      *y = event->touchpad_pinch.y;
-      break;
-    case GDK_DRAG_ENTER:
-    case GDK_DRAG_LEAVE:
-    case GDK_DRAG_MOTION:
-    case GDK_DROP_START:
-      *x = event->dnd.x;
-      *y = event->dnd.y;
-      break;
-    default:
-      /* no position */
-      *x = NAN;
-      *y = NAN;
-      return FALSE;
-    }
+  GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
 
-  return TRUE;
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_PINCH) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_SWIPE), 0);
+
+  return self->phase;
 }
 
 /**
- * gdk_button_event_get_button:
- * @event: a button event
+ * gdk_touchpad_event_get_n_fingers:
+ * @event: (type GdkTouchpadEvent): a touchpad event
  *
- * Extract the button number from a button event.
+ * Extracts the number of fingers from a touchpad event.
  *
- * Returns: the button of @event
+ * Returns: the number of fingers for @event
  **/
 guint
-gdk_button_event_get_button (GdkEvent *event)
+gdk_touchpad_event_get_n_fingers (GdkEvent *event)
 {
-  g_return_val_if_fail (event->any.type == GDK_BUTTON_PRESS ||
-                        event->any.type == GDK_BUTTON_RELEASE, 0);
-  
-  return event->button.button;
+  GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_PINCH) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_SWIPE), 0);
+
+  return self->n_fingers;
 }
 
 /**
- * gdk_key_event_get_keyval:
- * @event: a key event
- *
- * Extracts the keyval from a key event.
+ * gdk_touchpad_event_get_deltas:
+ * @event: (type GdkTouchpadEvent): a touchpad event
+ * @dx: (out): return location for x
+ * @dy: (out): return location for y
  *
- * Returns: the keyval of @event
- */
-guint
-gdk_key_event_get_keyval (GdkEvent *event)
+ * Extracts delta information from a touchpad event.
+ **/
+void
+gdk_touchpad_event_get_deltas (GdkEvent *event,
+                               double   *dx,
+                               double   *dy)
 {
-  g_return_val_if_fail (event->any.type == GDK_KEY_PRESS ||
-                        event->any.type == GDK_KEY_RELEASE, 0);
+  GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
 
-  return event->key.translated[0].keyval;
+  g_return_if_fail (GDK_IS_EVENT (event));
+  g_return_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_PINCH) ||
+                    GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_SWIPE));
+
+  *dx = self->dx;
+  *dy = self->dy;
 }
 
 /**
- * gdk_key_event_get_keycode:
- * @event: a key event
+ * gdk_touchpad_event_get_pinch_angle_delta:
+ * @event: (type GdkTouchpadEvent): a touchpad pinch event
  *
- * Extracts the keycode from a key event.
+ * Extracts the angle delta from a touchpad pinch event.
  *
- * Returns: the keycode of @event
+ * Returns: the angle delta of @event
  */
-guint
-gdk_key_event_get_keycode (GdkEvent *event)
+double
+gdk_touchpad_event_get_pinch_angle_delta (GdkEvent *event)
 {
-  g_return_val_if_fail (event->any.type == GDK_KEY_PRESS ||
-                        event->any.type == GDK_KEY_RELEASE, 0);
+  GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0.0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_PINCH), 0.0);
 
-  return event->key.keycode;
+  return self->angle_delta;
 }
 
 /**
- * gdk_key_event_get_level:
- * @event: a key event
+ * gdk_touchpad_event_get_pinch_scale:
+ * @event: (type GdkTouchpadEvent): a touchpad pinch event
  *
- * Extracts the shift level from a key event.
+ * Extracts the scale from a touchpad pinch event.
  *
- * Returns: the shift level of @event
- */
-guint
-gdk_key_event_get_level (GdkEvent *event)
+ * Returns: the scale of @event
+ **/
+double
+gdk_touchpad_event_get_pinch_scale (GdkEvent *event)
 {
-  g_return_val_if_fail (event->any.type == GDK_KEY_PRESS ||
-                        event->any.type == GDK_KEY_RELEASE, 0);
+  GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
 
-  return event->key.translated[0].level;
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0.0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_PINCH), 0.0);
+
+  return self->scale;
 }
 
-/**
- * gdk_key_event_get_layout:
- * @event: a key event
- *
- * Extracts the layout from a key event.
- *
- * Returns: the layout of @event
- */
-guint
-gdk_key_event_get_layout (GdkEvent *event)
+/* }}} */
+
+/* {{{ GdkPadEvent */
+
+static const GdkEventTypeInfo gdk_pad_event_info = {
+  sizeof (GdkPadEvent),
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+};
+
+GDK_DEFINE_EVENT_TYPE (GdkPadEvent, gdk_pad_event,
+                       &gdk_pad_event_info,
+                       GDK_EVENT_TYPE_SLOT (GDK_PAD_BUTTON_PRESS)
+                       GDK_EVENT_TYPE_SLOT (GDK_PAD_BUTTON_RELEASE)
+                       GDK_EVENT_TYPE_SLOT (GDK_PAD_RING)
+                       GDK_EVENT_TYPE_SLOT (GDK_PAD_STRIP)
+                       GDK_EVENT_TYPE_SLOT (GDK_PAD_GROUP_MODE))
+
+GdkEvent *
+gdk_pad_event_new_ring (GdkSurface *surface,
+                        GdkDevice  *device,
+                        GdkDevice  *source_device,
+                        guint32     time,
+                        guint       group,
+                        guint       index,
+                        guint       mode,
+                        double      value)
 {
-  g_return_val_if_fail (event->any.type == GDK_KEY_PRESS ||
-                        event->any.type == GDK_KEY_RELEASE, 0);
+  GdkPadEvent *self = gdk_event_alloc (GDK_PAD_RING, surface, device, source_device, time);
 
-  return event->key.translated[0].layout;
+  self->group = group;
+  self->index = index;
+  self->mode = mode;
+  self->value = value;
+
+  return (GdkEvent *) self;
 }
 
-/**
- * gdk_key_event_get_consumed_modifiers:
- * @event: a key event
- *
- * Extracts the consumed modifiers from a key event.
- *
- * Returns: the consumed modifiers or @event
- */
-GdkModifierType
-gdk_key_event_get_consumed_modifiers (GdkEvent *event)
+GdkEvent *
+gdk_pad_event_new_strip (GdkSurface *surface,
+                         GdkDevice  *device,
+                         GdkDevice  *source_device,
+                         guint32     time,
+                         guint       group,
+                         guint       index,
+                         guint       mode,
+                         double      value)
+{
+  GdkPadEvent *self = gdk_event_alloc (GDK_PAD_STRIP, surface, device, source_device, time);
+
+  self->group = group;
+  self->index = index;
+  self->mode = mode;
+  self->value = value;
+
+  return (GdkEvent *) self;
+}
+
+GdkEvent *
+gdk_pad_event_new_button (GdkEventType  type,
+                          GdkSurface   *surface,
+                          GdkDevice    *device,
+                          GdkDevice    *source_device,
+                          guint32       time,
+                          guint         group,
+                          guint         button,
+                          guint         mode)
 {
-  g_return_val_if_fail (event->any.type == GDK_KEY_PRESS ||
-                        event->any.type == GDK_KEY_RELEASE, 0);
+  GdkPadEvent *self;
+
+  g_return_val_if_fail (type == GDK_PAD_BUTTON_PRESS ||
+                        type == GDK_PAD_BUTTON_RELEASE, NULL);
 
-  return event->key.translated[0].consumed;
+  self = gdk_event_alloc (type, surface, device, source_device, time);
+
+  self->group = group;
+  self->button = button;
+  self->mode = mode;
+
+  return (GdkEvent *) self;
 }
 
+GdkEvent *
+gdk_pad_event_new_group_mode (GdkSurface *surface,
+                              GdkDevice  *device,
+                              GdkDevice  *source_device,
+                              guint32     time,
+                              guint       group,
+                              guint       mode)
+{
+  GdkPadEvent *self = gdk_event_alloc (GDK_PAD_GROUP_MODE, surface, device, source_device, time);
+
+  self->group = group;
+  self->mode = mode;
+
+  return (GdkEvent *) self;
+}
 /**
- * gdk_key_event_is_modifier:
- * @event: a key event
+ * gdk_pad_event_get_button:
+ * @event: (type GdkPadEvent): a pad button event
  *
- * Extracts whether the key event is for a modifier key.
+ * Extracts information about the pressed button from
+ * a pad event.
  *
- * Returns: %TRUE if the @event is for a modifier key
- */
-gboolean
-gdk_key_event_is_modifier (GdkEvent *event)
+ * Returns: the button of @event
+ **/
+guint
+gdk_pad_event_get_button (GdkEvent *event)
 {
-  g_return_val_if_fail (event->any.type == GDK_KEY_PRESS ||
-                        event->any.type == GDK_KEY_RELEASE, FALSE);
+  GdkPadEvent *self = (GdkPadEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), 0);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_PAD_BUTTON_PRESS) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_PAD_BUTTON_RELEASE), 0);
 
-  return event->any.key_is_modifier;
+  return self->button;
 }
 
 /**
- * gdk_configure_event_get_size:
- * @event: a configure event
- * @width: (out): return location for surface width
- * @height: (out): return location for surface height
+ * gdk_pad_event_get_axis_value:
+ * @event: (type GdkPadEvent): a pad strip or ring event
+ * @index: (out): Return location for the axis index
+ * @value: (out): Return location for the axis value
  *
- * Extracts the surface size from a configure event.
- */
+ * Extracts the information from a pad strip or ring event.
+ **/
 void
-gdk_configure_event_get_size (GdkEvent *event,
-                              int      *width,
-                              int      *height)
+gdk_pad_event_get_axis_value (GdkEvent *event,
+                              guint    *index,
+                              double   *value)
 {
-  g_return_if_fail (event->any.type == GDK_CONFIGURE);
+  GdkPadEvent *self = (GdkPadEvent *) event;
 
-  *width = event->configure.width;
-  *height = event->configure.height;
+  g_return_if_fail (GDK_IS_EVENT (event));
+  g_return_if_fail (GDK_IS_EVENT_TYPE (event, GDK_PAD_RING) ||
+                    GDK_IS_EVENT_TYPE (event, GDK_PAD_STRIP));
+
+  *index = self->index;
+  *value = self->value;
 }
 
 /**
- * gdk_touch_event_get_emulating_pointer:
- * @event: a touch event
- *
- * Extracts whether a touch event is emulating a pointer event.
+ * gdk_pad_event_get_group_mode:
+ * @event: (type GdkPadEvent): a pad event
+ * @group: (out): return location for the group
+ * @mode: (out): return location for the mode
  *
- * Returns: %TRUE if @event is emulating
+ * Extracts group and mode information from a pad event.
  **/
-gboolean
-gdk_touch_event_get_emulating_pointer (GdkEvent *event)
+void
+gdk_pad_event_get_group_mode (GdkEvent *event,
+                              guint    *group,
+                              guint    *mode)
 {
-  g_return_val_if_fail (event->any.type == GDK_TOUCH_BEGIN ||
-                        event->any.type == GDK_TOUCH_UPDATE ||
-                        event->any.type == GDK_TOUCH_END ||
-                        event->any.type == GDK_TOUCH_CANCEL, FALSE);
+  GdkPadEvent *self = (GdkPadEvent *) event;
+
+  g_return_if_fail (GDK_IS_EVENT (event));
+  g_return_if_fail (GDK_IS_EVENT_TYPE (event, GDK_PAD_GROUP_MODE) ||
+                    GDK_IS_EVENT_TYPE (event, GDK_PAD_BUTTON_PRESS) ||
+                    GDK_IS_EVENT_TYPE (event, GDK_PAD_BUTTON_RELEASE) ||
+                    GDK_IS_EVENT_TYPE (event, GDK_PAD_RING) ||
+                    GDK_IS_EVENT_TYPE (event, GDK_PAD_STRIP));
 
-  return event->any.touch_emulating;
+  *group = self->group;
+  *mode = self->mode;
 }
 
-/**
- * gdk_crossing_event_get_mode:
- * @event: a crossing event
- *
- * Extracts the crossing mode from a crossing event.
- *
- * Returns: the mode of @event
- */
-GdkCrossingMode
-gdk_crossing_event_get_mode (GdkEvent *event)
+/* }}} */
+
+/* {{{ GdkMotionEvent */
+
+static void
+gdk_motion_event_finalize (GdkEvent *event)
 {
-  g_return_val_if_fail (event->any.type == GDK_ENTER_NOTIFY ||
-                        event->any.type == GDK_LEAVE_NOTIFY, 0);
+  GdkMotionEvent *self = (GdkMotionEvent *) event;
 
-  return event->crossing.mode;
+  g_clear_object (&self->tool);
+  g_clear_pointer (&self->axes, g_free);
+  g_list_free_full (self->history, g_free);
+
+  GDK_EVENT_SUPER (event)->finalize (event);
 }
 
-/**
- * gdk_crossing_event_get_detail:
- * @event: a crossing event
- *
- * Extracts the notify detail from a crossing event.
- *
- * Returns: the notify detail of @event
- */
-GdkNotifyType
-gdk_crossing_event_get_detail (GdkEvent *event)
+static GdkModifierType
+gdk_motion_event_get_state (GdkEvent *event)
 {
-  g_return_val_if_fail (event->any.type == GDK_ENTER_NOTIFY ||
-                        event->any.type == GDK_LEAVE_NOTIFY, 0);
+  GdkMotionEvent *self = (GdkMotionEvent *) event;
 
-  return event->crossing.detail;
+  return self->state;
 }
 
-/**
- * gdk_focus_event_get_in:
- * @event: a focus change event
- *
- * Extracts whether this event is about focus entering or
- * leaving the surface.
- *
- * Returns: %TRUE of the focus is entering
- */
-gboolean
-gdk_focus_event_get_in (GdkEvent *event)
+static gboolean
+gdk_motion_event_get_position (GdkEvent *event,
+                               double   *x,
+                               double   *y)
 {
-  g_return_val_if_fail (event->any.type == GDK_FOCUS_CHANGE, FALSE);
+  GdkMotionEvent *self = (GdkMotionEvent *) event;
+
+  *x = self->x;
+  *y = self->y;
 
-  return event->any.focus_in;
+  return TRUE;
 }
 
-/**
- * gdk_scroll_event_get_direction:
- * @event: a scroll event
- *
- * Extracts the direction of a scroll event.
- *
- * Returns: the scroll direction of @event
- */
-GdkScrollDirection
-gdk_scroll_event_get_direction (GdkEvent *event)
+static GdkDeviceTool *
+gdk_motion_event_get_tool (GdkEvent *event)
 {
-  g_return_val_if_fail (event->any.type == GDK_SCROLL, 0);
+  GdkMotionEvent *self = (GdkMotionEvent *) event;
 
-  return event->scroll.direction;
+  return self->tool;
 }
 
-/**
- * gdk_scroll_event_get_deltas:
- * @event: a scroll event
- * @delta_x: (out): return location for x scroll delta
- * @delta_y: (out): return location for y scroll delta
- *
- * Extracts the scroll deltas of a scroll event.
- *
- * The deltas will be zero unless the scroll direction
- * is %GDK_SCROLL_SMOOTH.
- */
-void
-gdk_scroll_event_get_deltas (GdkEvent *event,
-                             double   *delta_x,
-                             double   *delta_y)
+static gboolean
+gdk_motion_event_get_axes (GdkEvent  *event,
+                           double   **axes,
+                           guint     *n_axes)
 {
-  g_return_if_fail (event->any.type == GDK_SCROLL);
+  GdkMotionEvent *self = (GdkMotionEvent *) event;
+  GdkDevice *source_device = gdk_event_get_source_device (event);
+
+  if (source_device == NULL)
+    return FALSE;
+
+  *axes = self->axes;
+  *n_axes = gdk_device_get_n_axes (source_device);
 
-  *delta_x = event->scroll.delta_x;
-  *delta_y = event->scroll.delta_y;
+  return TRUE;
 }
 
-/**
- * gdk_scroll_event_is_stop:
- * @event: a scroll event
- *
- * Check whether a scroll event is a stop scroll event. Scroll sequences
- * with smooth scroll information may provide a stop scroll event once the
- * interaction with the device finishes, e.g. by lifting a finger. This
- * stop scroll event is the signal that a widget may trigger kinetic
- * scrolling based on the current velocity.
- *
- * Stop scroll events always have a delta of 0/0.
- *
- * Returns: %TRUE if the event is a scroll stop event
- */
-gboolean
-gdk_scroll_event_is_stop (GdkEvent *event)
+static const GdkEventTypeInfo gdk_motion_event_info = {
+  sizeof (GdkMotionEvent),
+  NULL,
+  gdk_motion_event_finalize,
+  gdk_motion_event_get_state,
+  gdk_motion_event_get_position,
+  NULL,
+  gdk_motion_event_get_tool,
+  gdk_motion_event_get_axes,
+};
+
+GDK_DEFINE_EVENT_TYPE (GdkMotionEvent, gdk_motion_event,
+                       &gdk_motion_event_info,
+                       GDK_EVENT_TYPE_SLOT (GDK_MOTION_NOTIFY))
+
+GdkEvent *
+gdk_motion_event_new (GdkSurface      *surface,
+                      GdkDevice       *device,
+                      GdkDevice       *source_device,
+                      GdkDeviceTool   *tool,
+                      guint32          time,
+                      GdkModifierType  state,
+                      double           x,
+                      double           y,
+                      double          *axes)
 {
-  g_return_val_if_fail (event->any.type == GDK_SCROLL, FALSE);
+  GdkMotionEvent *self = gdk_event_alloc (GDK_MOTION_NOTIFY, surface, device, source_device, time);
+
+  self->tool = tool ? g_object_ref (tool) : NULL;
+  self->state = state;
+  self->x = x;
+  self->y = y;
+  self->axes = axes;
+  self->state = state;
 
-  return event->any.scroll_is_stop;
+  return (GdkEvent *) self;
 }
 
 /**
- * gdk_touchpad_event_get_gesture_phase:
- * @event: a touchpad #GdkEvent
+ * gdk_motion_event_get_history:
+ * @event: (type GdkMotionEvent): a motion #GdkEvent
  *
- * Extracts the touchpad gesture phase from a touchpad event.
+ * Retrieves the history of the @event motion, as a list of time and
+ * coordinates.
  *
- * Returns: the gesture phase of @event
- **/
-GdkTouchpadGesturePhase
-gdk_touchpad_event_get_gesture_phase (GdkEvent *event)
+ * Returns: (transfer container) (element-type GdkTimeCoord) (nullable): a list
+ *   of time and coordinates
+ */
+GList *
+gdk_motion_event_get_history (GdkEvent *event)
 {
-  g_return_val_if_fail (event->any.type == GDK_TOUCHPAD_PINCH ||
-                        event->any.type == GDK_TOUCHPAD_SWIPE, 0);
+  GdkMotionEvent *self = (GdkMotionEvent *) event;
 
-  if (event->any.type == GDK_TOUCHPAD_PINCH)
-    return event->touchpad_pinch.phase;
-  else if (event->any.type == GDK_TOUCHPAD_SWIPE)
-    return event->touchpad_swipe.phase;
+  g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_MOTION_NOTIFY), NULL);
 
-  return 0;
+  return g_list_reverse (g_list_copy (self->history));
 }
 
-/**
- * gdk_touchpad_event_get_n_fingers:
- * @event: a touchpad event
- *
- * Extracts the number of fingers from a touchpad event.
- *
- * Returns: the number of fingers for @event
- **/
-guint
-gdk_touchpad_event_get_n_fingers (GdkEvent *event)
+/* }}} */
+
+/* {{{ GdkProximityEvent */
+
+static void
+gdk_proximity_event_finalize (GdkEvent *event)
 {
-  g_return_val_if_fail (event->any.type == GDK_TOUCHPAD_PINCH ||
-                        event->any.type == GDK_TOUCHPAD_SWIPE, 0);
+  GdkProximityEvent *self = (GdkProximityEvent *) event;
 
-  if (event->any.type == GDK_TOUCHPAD_PINCH)
-    return event->touchpad_pinch.n_fingers;
-  else if (event->any.type == GDK_TOUCHPAD_SWIPE)
-    return event->touchpad_swipe.n_fingers;
+  g_clear_object (&self->tool);
 
-  return 0;
+  GDK_EVENT_SUPER (event)->finalize (event);
 }
 
-/**
- * gdk_touchpad_event_get_deltas:
- * @event: a touchpad event
- * @dx: (out): return location for x
- * @dy: (out): return location for y
- *
- * Extracts delta information from a touchpad event.
- **/
-void
-gdk_touchpad_event_get_deltas (GdkEvent *event,
-                               double   *dx,
-                               double   *dy)
+static GdkDeviceTool *
+gdk_proximity_event_get_tool (GdkEvent *event)
 {
-  g_return_if_fail (event->any.type == GDK_TOUCHPAD_PINCH ||
-                    event->any.type == GDK_TOUCHPAD_SWIPE);
+  GdkProximityEvent *self = (GdkProximityEvent *) event;
 
-  if (event->any.type == GDK_TOUCHPAD_PINCH)
-    {
-      *dx = event->touchpad_pinch.dx;
-      *dy = event->touchpad_pinch.dy;
-    }
-  else if (event->any.type == GDK_TOUCHPAD_SWIPE)
-    {
-      *dx = event->touchpad_swipe.dx;
-      *dy = event->touchpad_swipe.dy;
-    }
-  else
-    {
-      *dx = NAN;
-      *dy = NAN;
-    }
+  return self->tool;
 }
 
-/**
- * gdk_touchpad_pinch_event_get_angle_delta:
- * @event: a touchpad pinch event
- *
- * Extracts the angle delta from a touchpad pinch event.
- *
- * Returns: the angle delta of @event
- */
-double
-gdk_touchpad_pinch_event_get_angle_delta (GdkEvent *event)
+static const GdkEventTypeInfo gdk_proximity_event_info = {
+  sizeof (GdkProximityEvent),
+  NULL,
+  gdk_proximity_event_finalize,
+  NULL,
+  NULL,
+  NULL,
+  gdk_proximity_event_get_tool,
+  NULL,
+};
+
+GDK_DEFINE_EVENT_TYPE (GdkProximityEvent, gdk_proximity_event,
+                       &gdk_proximity_event_info,
+                       GDK_EVENT_TYPE_SLOT (GDK_PROXIMITY_IN)
+                       GDK_EVENT_TYPE_SLOT (GDK_PROXIMITY_OUT))
+
+GdkEvent *
+gdk_proximity_event_new (GdkEventType   type,
+                         GdkSurface    *surface,
+                         GdkDevice     *device,
+                         GdkDevice     *source_device,
+                         GdkDeviceTool *tool,
+                         guint32        time)
 {
-  g_return_val_if_fail (event->any.type == GDK_TOUCHPAD_PINCH, 0);
+  GdkProximityEvent *self;
+
+  g_return_val_if_fail (type == GDK_PROXIMITY_IN ||
+                        type == GDK_PROXIMITY_OUT, NULL);
 
-  return event->touchpad_pinch.angle_delta;
+  self = gdk_event_alloc (type, surface, device, source_device, time);
+
+  self->tool = tool ? g_object_ref (tool) : NULL;
+
+  return (GdkEvent *) self;
 }
 
-/**
- * gdk_touchpad_pinch_event_get_scale:
- * @event: a touchpad pinch event
- *
- * Extracts the scale from a touchpad pinch event.
- *
- * Returns: the scale of @event
- **/
-double
-gdk_touchpad_pinch_event_get_scale (GdkEvent *event)
+/* }}} */
+
+/* {{{ GdkDNDEvent */
+
+static void
+gdk_dnd_event_finalize (GdkEvent *event)
 {
-  g_return_val_if_fail (event->any.type == GDK_TOUCHPAD_PINCH, 0);
+  GdkDNDEvent *self = (GdkDNDEvent *) event;
 
-  return event->touchpad_pinch.scale;
+  g_clear_object (&self->drop);
+
+  GDK_EVENT_SUPER (event)->finalize (event);
 }
 
-/**
- * gdk_pad_button_event_get_button:
- * @event: a pad button event
- *
- * Extracts information about the pressed button from
- * a pad event.
- *
- * Returns: the button of @event
- **/
-guint
-gdk_pad_button_event_get_button (GdkEvent *event)
+static gboolean
+gdk_dnd_event_get_position (GdkEvent *event,
+                            double   *x,
+                            double   *y)
 {
-  g_return_val_if_fail (event->any.type == GDK_PAD_BUTTON_PRESS ||
-                        event->any.type == GDK_PAD_BUTTON_RELEASE, 0);
+  GdkDNDEvent *self = (GdkDNDEvent *) event;
 
-  return  event->pad_button.button;
+  *x = self->x;
+  *y = self->y;
+
+  return TRUE;
 }
 
-/**
- * gdk_pad_axis_event_get_value:
- * @event: a pad strip or ring event
- * @index: (out): Return location for the axis index
- * @value: (out): Return location for the axis value
- *
- * Extracts the information from a pad strip or ring event.
- **/
-void
-gdk_pad_axis_event_get_value (GdkEvent       *event,
-                              guint          *index,
-                              gdouble        *value)
+static GdkEventSequence *
+gdk_dnd_event_get_sequence (GdkEvent *event)
 {
-  g_return_if_fail (event->any.type == GDK_PAD_RING ||
-                    event->any.type == GDK_PAD_STRIP);
+  GdkDNDEvent *self = (GdkDNDEvent *) event;
 
-  *index = event->pad_axis.index;
-  *value = event->pad_axis.value;
+  return (GdkEventSequence *) self->drop;
 }
 
-/**
- * gdk_pad_event_get_group_mode:
- * @event: a pad event
- * @group: (out): return location for the group
- * @mode: (out): return location for the mode
- *
- * Extracts group and mode information from a pad event.
- **/
-void
-gdk_pad_event_get_group_mode (GdkEvent *event,
-                              guint    *group,
-                              guint    *mode)
+static const GdkEventTypeInfo gdk_dnd_event_info = {
+  sizeof (GdkDNDEvent),
+  NULL,
+  gdk_dnd_event_finalize,
+  NULL,
+  gdk_dnd_event_get_position,
+  gdk_dnd_event_get_sequence,
+  NULL,
+  NULL,
+};
+
+GDK_DEFINE_EVENT_TYPE (GdkDNDEvent, gdk_dnd_event,
+                       &gdk_dnd_event_info,
+                       GDK_EVENT_TYPE_SLOT (GDK_DRAG_ENTER)
+                       GDK_EVENT_TYPE_SLOT (GDK_DRAG_MOTION)
+                       GDK_EVENT_TYPE_SLOT (GDK_DRAG_LEAVE)
+                       GDK_EVENT_TYPE_SLOT (GDK_DROP_START))
+
+GdkEvent *
+gdk_dnd_event_new (GdkEventType  type,
+                   GdkSurface   *surface,
+                   GdkDevice    *device,
+                   GdkDrop      *drop,
+                   guint32       time,
+                   double        x,
+                   double        y)
 {
-  g_return_if_fail (event->any.type == GDK_PAD_GROUP_MODE ||
-                    event->any.type == GDK_PAD_BUTTON_PRESS ||
-                    event->any.type == GDK_PAD_BUTTON_RELEASE ||
-                    event->any.type == GDK_PAD_RING ||
-                    event->any.type == GDK_PAD_STRIP);
+  GdkDNDEvent *self;
 
-  switch ((guint)event->any.type)
-    {
-    case GDK_PAD_GROUP_MODE:
-      *group = event->pad_group_mode.group;
-      *mode = event->pad_group_mode.mode;
-      break;
-    case GDK_PAD_BUTTON_PRESS:
-    case GDK_PAD_BUTTON_RELEASE:
-      *group = event->pad_button.group;
-      *mode = event->pad_button.mode;
-      break;
-    case GDK_PAD_RING:
-    case GDK_PAD_STRIP:
-      *group = event->pad_axis.group;
-      *mode = event->pad_axis.mode;
-      break;
-    default:
-      g_assert_not_reached ();
-    }
+  g_return_val_if_fail (type == GDK_DRAG_ENTER ||
+                        type == GDK_DRAG_MOTION ||
+                        type == GDK_DRAG_LEAVE ||
+                        type == GDK_DROP_START, NULL);
+
+  self = gdk_event_alloc (type, surface, device, NULL, time);
+
+  self->drop = drop != NULL ? g_object_ref (drop) : NULL;
+  self->x = x;
+  self->y = y;
+
+  return (GdkEvent *) self;
 }
 
 /**
- * gdk_drag_event_get_drop:
- * @event: a DND event
+ * gdk_dnd_event_get_drop:
+ * @event: (type GdkDNDEvent): a DND event
  *
  * Gets the #GdkDrop from a DND event.
  *
  * Returns: (transfer none) (nullable): the drop
  **/
 GdkDrop *
-gdk_drag_event_get_drop (GdkEvent *event)
+gdk_dnd_event_get_drop (GdkEvent *event)
+{
+  GdkDNDEvent *self = (GdkDNDEvent *) event;
+
+  g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_DRAG_ENTER) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_DRAG_MOTION) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_DRAG_LEAVE) ||
+                        GDK_IS_EVENT_TYPE (event, GDK_DROP_START), NULL);
+
+  return self->drop;
+}
+
+/* }}} */
+
+/* {{{ GdkGrabBrokenEvent */
+
+static const GdkEventTypeInfo gdk_grab_broken_event_info = {
+  sizeof (GdkGrabBrokenEvent),
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+};
+
+GDK_DEFINE_EVENT_TYPE (GdkGrabBrokenEvent, gdk_grab_broken_event,
+                       &gdk_grab_broken_event_info,
+                       GDK_EVENT_TYPE_SLOT (GDK_GRAB_BROKEN))
+
+GdkEvent *
+gdk_grab_broken_event_new (GdkSurface *surface,
+                           GdkDevice  *device,
+                           GdkDevice  *source_device,
+                           GdkSurface *grab_surface,
+                           gboolean    implicit)
 {
-  g_return_val_if_fail (event->any.type == GDK_DRAG_ENTER ||
-                        event->any.type == GDK_DRAG_LEAVE ||
-                        event->any.type == GDK_DRAG_MOTION ||
-                        event->any.type == GDK_DROP_START, NULL);
+  GdkGrabBrokenEvent *self = gdk_event_alloc (GDK_GRAB_BROKEN, surface, device, source_device, 
GDK_CURRENT_TIME);
+
+  self->grab_surface = grab_surface;
+  self->implicit = implicit;
+  self->keyboard = gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD;
 
-  return event->dnd.drop;
+  return (GdkEvent *) self;
 }
 
 /**
  * gdk_grab_broken_event_get_grab_surface:
- * @event: a grab broken event
+ * @event: (type GdkGrabBrokenEvent): a grab broken event
  *
  * Extracts the grab surface from a grab broken event.
  *
@@ -2106,168 +3044,31 @@ gdk_drag_event_get_drop (GdkEvent *event)
 GdkSurface *
 gdk_grab_broken_event_get_grab_surface (GdkEvent *event)
 {
-  g_return_val_if_fail (event->any.type == GDK_GRAB_BROKEN, NULL);
-
-  return event->grab_broken.grab_surface;
-}
-
-/**
- * gdk_key_event_matches:
- * @event: a key #GdkEvent
- * @keyval: the keyval to match
- * @modifiers: the modifiers to match
- *
- * Matches a key event against a keyboard shortcut that is specified
- * as a keyval and modifiers. Partial matches are possible where the
- * combination matches if the currently active group is ignored.
- *
- * Note that we ignore Caps Lock for matching.
- *
- * Returns: a GdkKeyMatch value describing whether @event matches
- */
-GdkKeyMatch
-gdk_key_event_matches (GdkEvent        *event,
-                       guint            keyval,
-                       GdkModifierType  modifiers)
-{
-  guint keycode;
-  GdkModifierType state;
-  GdkModifierType mask;
-  guint ev_keyval;
-  int layout;
-  int level;
-  GdkModifierType consumed_modifiers;
-  GdkModifierType shift_group_mask;
-  gboolean group_mod_is_accel_mod = FALSE;
-
-  g_return_val_if_fail (event->any.type == GDK_KEY_PRESS ||
-                        event->any.type == GDK_KEY_RELEASE, GDK_KEY_MATCH_NONE);
-
-  keycode = event->key.keycode;
-  state = event->key.state & ~GDK_LOCK_MASK;
-  ev_keyval = event->key.translated[1].keyval;
-  layout = event->key.translated[1].layout;
-  level = event->key.translated[1].level;
-  consumed_modifiers = event->key.translated[1].consumed;
-
-  mask = GDK_CONTROL_MASK|GDK_SHIFT_MASK|GDK_ALT_MASK|
-         GDK_SUPER_MASK|GDK_HYPER_MASK|GDK_META_MASK;
-
-  /* if the group-toggling modifier is part of the default accel mod
-   * mask, and it is active, disable it for matching
-   *
-   * FIXME: get shift group mask from backends
-   */
-  shift_group_mask = 0;
-
-  if (mask & shift_group_mask)
-    group_mod_is_accel_mod = TRUE;
-
-  if ((modifiers & ~consumed_modifiers & mask) == (state & ~consumed_modifiers & mask))
-    {
-      /* modifier match */
-      GdkKeymapKey *keys;
-      int n_keys;
-      int i;
-      guint key;
-
-      /* Shift gets consumed and applied for the event,
-       * so apply it to our keyval to match
-       */
-      key = keyval;
-      if (modifiers & GDK_SHIFT_MASK)
-        {
-          if (key == GDK_KEY_Tab)
-            key = GDK_KEY_ISO_Left_Tab;
-          else
-            key = gdk_keyval_to_upper (key);
-        }
-
-      if (ev_keyval == key && /* exact match */
-          (!group_mod_is_accel_mod ||
-           (state & shift_group_mask) == (modifiers & shift_group_mask)))
-        {
-          return GDK_KEY_MATCH_EXACT;
-        }
-
-      gdk_display_map_keyval (gdk_event_get_display (event), keyval, &keys, &n_keys);
-
-      for (i = 0; i < n_keys; i++)
-        {
-          if (keys[i].keycode == keycode &&
-              keys[i].level == level &&
-              /* Only match for group if it's an accel mod */
-              (!group_mod_is_accel_mod || keys[i].group == layout))
-            {
-              /* partial match */
-              g_free (keys);
-
-              return GDK_KEY_MATCH_PARTIAL;
-            }
-        }
-
-      g_free (keys);
-    }
+  GdkGrabBrokenEvent *self = (GdkGrabBrokenEvent *) event;
 
+  g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_GRAB_BROKEN), NULL);
 
-  return GDK_KEY_MATCH_NONE;
+  return self->grab_surface;
 }
 
 /**
- * gdk_key_event_get_match:
- * @event: a key #GdkEvent
- * @keyval: (out): return location for a keyval
- * @modifiers: (out): return location for modifiers
+ * gdk_grab_broken_event_get_implicit:
+ * @event: (type GdkGrabBrokenEvent): a grab broken event
  *
- * Gets a keyval and modifier combination that will cause
- * gdk_event_match() to successfully match the given event.
+ * Checks whether the grab broken event is for an implicit grab.
  *
- * Returns: %TRUE on success
+ * Returns: %TRUE if the an implicit grab was broken
  */
 gboolean
-gdk_key_event_get_match (GdkEvent        *event,
-                         guint           *keyval,
-                         GdkModifierType *modifiers)
+gdk_grab_broken_event_get_implicit (GdkEvent *event)
 {
-  GdkModifierType mask;
-  guint key;
-  guint accel_key;
-  GdkModifierType accel_mods;
-  GdkModifierType consumed_modifiers;
-
-  g_return_val_if_fail (event->any.type == GDK_KEY_PRESS ||
-                        event->any.type == GDK_KEY_RELEASE, FALSE);
-
-  mask = GDK_CONTROL_MASK|GDK_SHIFT_MASK|GDK_ALT_MASK|
-         GDK_SUPER_MASK|GDK_HYPER_MASK|GDK_META_MASK;
-
-  accel_key = event->key.translated[1].keyval;
-  accel_mods = event->key.state;
-  consumed_modifiers = event->key.translated[1].consumed;
-
-  if (accel_key == GDK_KEY_Sys_Req &&
-      (accel_mods & GDK_ALT_MASK) != 0)
-    {
-      /* HACK: we don't want to use SysRq as a keybinding (but we do
-       * want Alt+Print), so we avoid translation from Alt+Print to SysRq
-       */
-      *keyval = GDK_KEY_Print;
-      *modifiers = accel_mods & mask;
-      return TRUE;
-    }
-
-  key = gdk_keyval_to_lower (accel_key);
-
-  if (key == GDK_KEY_ISO_Left_Tab)
-    key = GDK_KEY_Tab;
-
-  accel_mods &= mask & ~consumed_modifiers;
-
-  if (accel_key != key)
-    accel_mods |= GDK_SHIFT_MASK;
+  GdkGrabBrokenEvent *self = (GdkGrabBrokenEvent *) event;
 
-  *keyval = key;
-  *modifiers = accel_mods;
+  g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
+  g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_GRAB_BROKEN), FALSE);
 
-  return TRUE;
+  return self->implicit;
 }
+
+/* }}} */
diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h
index d697cb8c20..cd4a46d4d2 100644
--- a/gdk/gdkevents.h
+++ b/gdk/gdkevents.h
@@ -41,6 +41,10 @@ G_BEGIN_DECLS
 #define GDK_TYPE_EVENT          (gdk_event_get_type ())
 #define GDK_TYPE_EVENT_SEQUENCE (gdk_event_sequence_get_type ())
 
+#define GDK_IS_EVENT(obj)       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_EVENT))
+#define GDK_EVENT(obj)          (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_EVENT, GdkEvent))
+
+#define GDK_IS_EVENT_TYPE(event, type)  (gdk_event_get_event_type ((event)) == (type))
 
 /**
  * GDK_PRIORITY_EVENTS:
@@ -98,9 +102,38 @@ G_BEGIN_DECLS
  */
 #define GDK_BUTTON_SECONDARY    (3)
 
-
-typedef struct _GdkEventSequence    GdkEventSequence;
-typedef union  _GdkEvent           GdkEvent;
+typedef struct _GdkEventSequence        GdkEventSequence;
+typedef struct _GdkEvent                GdkEvent;
+
+#define GDK_TYPE_BUTTON_EVENT (gdk_button_event_get_type())
+#define GDK_TYPE_CONFIGURE_EVENT (gdk_configure_event_get_type())
+#define GDK_TYPE_CROSSING_EVENT (gdk_crossing_event_get_type())
+#define GDK_TYPE_DELETE_EVENT (gdk_delete_event_get_type())
+#define GDK_TYPE_DND_EVENT (gdk_dnd_event_get_type())
+#define GDK_TYPE_FOCUS_EVENT (gdk_focus_event_get_type())
+#define GDK_TYPE_GRAB_BROKEN_EVENT (gdk_grab_broken_event_get_type())
+#define GDK_TYPE_KEY_EVENT (gdk_key_event_get_type())
+#define GDK_TYPE_MOTION_EVENT (gdk_motion_event_get_type())
+#define GDK_TYPE_PAD_EVENT (gdk_pad_event_get_type())
+#define GDK_TYPE_PROXIMITY_EVENT (gdk_proximity_event_get_type())
+#define GDK_TYPE_SCROLL_EVENT (gdk_scroll_event_get_type())
+#define GDK_TYPE_TOUCH_EVENT (gdk_touch_event_get_type())
+#define GDK_TYPE_TOUCHPAD_EVENT (gdk_touchpad_event_get_type())
+
+typedef struct _GdkButtonEvent          GdkButtonEvent;
+typedef struct _GdkConfigureEvent       GdkConfigureEvent;
+typedef struct _GdkCrossingEvent        GdkCrossingEvent;
+typedef struct _GdkDeleteEvent          GdkDeleteEvent;
+typedef struct _GdkDNDEvent             GdkDNDEvent;
+typedef struct _GdkFocusEvent           GdkFocusEvent;
+typedef struct _GdkGrabBrokenEvent      GdkGrabBrokenEvent;
+typedef struct _GdkKeyEvent             GdkKeyEvent;
+typedef struct _GdkMotionEvent          GdkMotionEvent;
+typedef struct _GdkPadEvent             GdkPadEvent;
+typedef struct _GdkProximityEvent       GdkProximityEvent;
+typedef struct _GdkScrollEvent          GdkScrollEvent;
+typedef struct _GdkTouchEvent           GdkTouchEvent;
+typedef struct _GdkTouchpadEvent        GdkTouchpadEvent;
 
 /**
  * GdkEventType:
@@ -297,7 +330,6 @@ typedef enum
 
 GDK_AVAILABLE_IN_ALL
 GType                   gdk_event_get_type              (void) G_GNUC_CONST;
-
 GDK_AVAILABLE_IN_ALL
 GType                   gdk_event_sequence_get_type     (void) G_GNUC_CONST;
 
@@ -348,9 +380,13 @@ gboolean                gdk_event_get_axis              (GdkEvent   *event,
 GDK_AVAILABLE_IN_ALL
 gboolean                gdk_event_get_pointer_emulated (GdkEvent *event);
 
+GDK_AVAILABLE_IN_ALL
+GType                   gdk_button_event_get_type       (void) G_GNUC_CONST;
 GDK_AVAILABLE_IN_ALL
 guint                   gdk_button_event_get_button     (GdkEvent *event);
 GDK_AVAILABLE_IN_ALL
+GType                   gdk_scroll_event_get_type       (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_ALL
 GdkScrollDirection      gdk_scroll_event_get_direction  (GdkEvent *event);
 GDK_AVAILABLE_IN_ALL
 void                    gdk_scroll_event_get_deltas     (GdkEvent *event,
@@ -359,6 +395,8 @@ void                    gdk_scroll_event_get_deltas     (GdkEvent *event,
 GDK_AVAILABLE_IN_ALL
 gboolean                gdk_scroll_event_is_stop        (GdkEvent *event);
 GDK_AVAILABLE_IN_ALL
+GType                   gdk_key_event_get_type          (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_ALL
 guint                   gdk_key_event_get_keyval        (GdkEvent *event);
 GDK_AVAILABLE_IN_ALL
 guint                   gdk_key_event_get_keycode       (GdkEvent *event);
@@ -371,18 +409,30 @@ guint                   gdk_key_event_get_level         (GdkEvent *event);
 GDK_AVAILABLE_IN_ALL
 gboolean                gdk_key_event_is_modifier       (GdkEvent *event);
 GDK_AVAILABLE_IN_ALL
+GType                   gdk_focus_event_get_type        (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_ALL
 gboolean                gdk_focus_event_get_in          (GdkEvent *event);
 GDK_AVAILABLE_IN_ALL
+GType                   gdk_touch_event_get_type        (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_ALL
 gboolean                gdk_touch_event_get_emulating_pointer (GdkEvent *event);
 GDK_AVAILABLE_IN_ALL
+GType                   gdk_crossing_event_get_type     (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_ALL
 GdkCrossingMode         gdk_crossing_event_get_mode     (GdkEvent *event);
 GDK_AVAILABLE_IN_ALL
 GdkNotifyType           gdk_crossing_event_get_detail   (GdkEvent *event);
 GDK_AVAILABLE_IN_ALL
+gboolean                gdk_crossing_event_get_focus    (GdkEvent *event);
+GDK_AVAILABLE_IN_ALL
+GType                   gdk_configure_event_get_type    (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_ALL
 void                    gdk_configure_event_get_size    (GdkEvent *event,
                                                          int      *width,
                                                          int      *height);
 GDK_AVAILABLE_IN_ALL
+GType                   gdk_touchpad_event_get_type     (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_ALL
 GdkTouchpadGesturePhase
                         gdk_touchpad_event_get_gesture_phase (GdkEvent *event);
 GDK_AVAILABLE_IN_ALL
@@ -392,26 +442,41 @@ void                    gdk_touchpad_event_get_deltas        (GdkEvent *event,
                                                               double   *dx,
                                                               double   *dy);
 GDK_AVAILABLE_IN_ALL
-double                  gdk_touchpad_pinch_event_get_angle_delta (GdkEvent *event);
+double                  gdk_touchpad_event_get_pinch_angle_delta (GdkEvent *event);
+GDK_AVAILABLE_IN_ALL
+double                  gdk_touchpad_event_get_pinch_scale       (GdkEvent *event);
+GDK_AVAILABLE_IN_ALL
+GType                   gdk_pad_event_get_type          (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_ALL
+guint                   gdk_pad_event_get_button        (GdkEvent *event);
 GDK_AVAILABLE_IN_ALL
-double                  gdk_touchpad_pinch_event_get_scale       (GdkEvent *event);
+void                    gdk_pad_event_get_axis_value    (GdkEvent *event,
+                                                         guint    *index,
+                                                         double   *value);
 GDK_AVAILABLE_IN_ALL
-guint                   gdk_pad_button_event_get_button  (GdkEvent *event);
+void                    gdk_pad_event_get_group_mode    (GdkEvent *event,
+                                                         guint    *group,
+                                                         guint    *mode);
 GDK_AVAILABLE_IN_ALL
-void                    gdk_pad_axis_event_get_value     (GdkEvent *event,
-                                                          guint    *index,
-                                                          double   *value);
+GType                   gdk_dnd_event_get_type          (void) G_GNUC_CONST;
 GDK_AVAILABLE_IN_ALL
-void                    gdk_pad_event_get_group_mode (GdkEvent *event,
-                                                      guint    *group,
-                                                      guint    *mode);
+GdkDrop *               gdk_dnd_event_get_drop          (GdkEvent *event);
 GDK_AVAILABLE_IN_ALL
-GdkDrop *               gdk_drag_event_get_drop (GdkEvent *event);
+GType                   gdk_grab_broken_event_get_type  (void) G_GNUC_CONST;
 GDK_AVAILABLE_IN_ALL
 GdkSurface *            gdk_grab_broken_event_get_grab_surface (GdkEvent *event);
+GDK_AVAILABLE_IN_ALL
+gboolean                gdk_grab_broken_event_get_implicit     (GdkEvent *event);
 
 GDK_AVAILABLE_IN_ALL
-GList *                 gdk_event_get_motion_history    (GdkEvent *event);
+GType                   gdk_motion_event_get_type       (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_ALL
+GList *                 gdk_motion_event_get_history    (GdkEvent *event);
+
+GDK_AVAILABLE_IN_ALL
+GType                   gdk_delete_event_get_type       (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_ALL
+GType                   gdk_proximity_event_get_type    (void) G_GNUC_CONST;
 
 GDK_AVAILABLE_IN_ALL
 gboolean                gdk_event_triggers_context_menu (GdkEvent *event);
diff --git a/gdk/gdkeventsprivate.h b/gdk/gdkeventsprivate.h
index 3977be170a..c45df7cc61 100644
--- a/gdk/gdkeventsprivate.h
+++ b/gdk/gdkeventsprivate.h
@@ -30,74 +30,98 @@
 #include <gdk/gdkdevice.h>
 #include <gdk/gdkdevicetool.h>
 
+G_BEGIN_DECLS
 
-typedef struct _GdkEventAny         GdkEventAny;
-typedef struct _GdkEventMotion      GdkEventMotion;
-typedef struct _GdkEventButton      GdkEventButton;
-typedef struct _GdkEventTouch       GdkEventTouch;
-typedef struct _GdkEventScroll      GdkEventScroll;
-typedef struct _GdkEventKey         GdkEventKey;
-typedef struct _GdkEventFocus       GdkEventFocus;
-typedef struct _GdkEventCrossing    GdkEventCrossing;
-typedef struct _GdkEventConfigure   GdkEventConfigure;
-typedef struct _GdkEventProximity   GdkEventProximity;
-typedef struct _GdkEventDND         GdkEventDND;
-typedef struct _GdkEventSetting     GdkEventSetting;
-typedef struct _GdkEventGrabBroken  GdkEventGrabBroken;
-typedef struct _GdkEventTouchpadSwipe GdkEventTouchpadSwipe;
-typedef struct _GdkEventTouchpadPinch GdkEventTouchpadPinch;
-typedef struct _GdkEventPadButton   GdkEventPadButton;
-typedef struct _GdkEventPadAxis     GdkEventPadAxis;
-typedef struct _GdkEventPadGroupMode GdkEventPadGroupMode;
+#define GDK_EVENT_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_EVENT, GdkEventClass))
 
-/*
- * GdkEventAny:
- * @type: the type of the event.
- * @surface: the surface which received the event.
- * @send_event: %TRUE if the event was sent explicitly.
+typedef struct _GdkEventClass   GdkEventClass;
+
+/*< private >
+ * GdkEvent:
+ * @ref_count: the reference count of the event
+ * @event_type: the specialized event type
+ * @surface: the surface of the event
+ * @device: the device of the event
+ * @source_device: the source device
+ * @time: a serial identifier of the event that can be used to order
+ *   two events
+ * @flags: event flags
  *
- * Contains the fields which are common to all event structs.
- * Any event pointer can safely be cast to a pointer to a #GdkEventAny to
- * access these fields.
+ * The abstract type for all windowing system events.
  */
-struct _GdkEventAny
+struct _GdkEvent
 {
-  int ref_count;
-  GdkEventType type;
+  GTypeInstance parent_instance;
+
+  grefcount ref_count;
+
+  /* Specialised event type */
+  GdkEventType event_type;
+
+  /* The surface of the event */
   GdkSurface *surface;
-  guint32 time;
-  guint16 flags;
-  guint pointer_emulated  : 1;
-  guint touch_emulating   : 1;
-  guint scroll_is_stop    : 1;
-  guint key_is_modifier   : 1;
-  guint focus_in          : 1;
+
+  /* The devices associated to the event */
   GdkDevice *device;
   GdkDevice *source_device;
+
+  guint32 time;
+  guint16 flags;
+};
+
+/*< private >
+ * GdkEventClass:
+ * @finalize: a function called when the last reference held on an event is
+ *   released; implementations of GdkEvent must chain up to the parent class
+ *
+ * The base class for events.
+ */
+struct _GdkEventClass
+{
+  GTypeClass parent_class;
+
+  void                  (* finalize)            (GdkEvent *event);
+
+  GdkModifierType       (* get_state)           (GdkEvent *event);
+  gboolean              (* get_position)        (GdkEvent *event,
+                                                 double   *x,
+                                                 double   *y);
+  GdkEventSequence *    (* get_sequence)        (GdkEvent *event);
+  GdkDeviceTool *       (* get_tool)            (GdkEvent *event);
+  gboolean              (* get_axes)            (GdkEvent *event,
+                                                 double  **axes,
+                                                 guint    *n_axes);
+};
+
+/*
+ * GdkDeleteEvent:
+ *
+ * Generated when a surface is deleted.
+ */
+struct _GdkDeleteEvent
+{
+  GdkEvent parent_instance;
 };
 
 /*
- * GdkEventMotion:
- * @type: the type of the event.
- * @surface: the surface which received the event.
- * @send_event: %TRUE if the event was sent explicitly.
- * @time: the time of the event in milliseconds.
+ * GdkMotionEvent:
+ * @state: (type GdkModifierType): a bit-mask representing the state of
+ *   the modifier keys (e.g. Control, Shift and Alt) set during the motion
+ *   event. See #GdkModifierType.
  * @x: the x coordinate of the pointer relative to the surface.
  * @y: the y coordinate of the pointer relative to the surface.
  * @axes: @x, @y translated to the axes of @device, or %NULL if @device is
  *   the mouse.
- * @state: (type GdkModifierType): a bit-mask representing the state of
- *   the modifier keys (e.g. Control, Shift and Alt) and the pointer
- *   buttons. See #GdkModifierType.
- * @device: the master device that the event originated from. Use
- * gdk_event_get_source_device() to get the slave device.
- *   screen.
+ * @history: (element-type GdkTimeCoord): a list of time and coordinates
+ *   for other motion events that were compressed before delivering the
+ *   current event
  *
  * Generated when the pointer moves.
  */
-struct _GdkEventMotion
+struct _GdkMotionEvent
 {
-  GdkEventAny any;
+  GdkEvent parent_instance;
+
   GdkModifierType state;
   double x;
   double y;
@@ -107,15 +131,7 @@ struct _GdkEventMotion
 };
 
 /*
- * GdkEventButton:
- * @type: the type of the event (%GDK_BUTTON_PRESS or %GDK_BUTTON_RELEASE).
- * @surface: the surface which received the event.
- * @send_event: %TRUE if the event was sent explicitly.
- * @time: the time of the event in milliseconds.
- * @x: the x coordinate of the pointer relative to the surface.
- * @y: the y coordinate of the pointer relative to the surface.
- * @axes: @x, @y translated to the axes of @device, or %NULL if @device is
- *   the mouse.
+ * GdkButtonEvent:
  * @state: (type GdkModifierType): a bit-mask representing the state of
  *   the modifier keys (e.g. Control, Shift and Alt) and the pointer
  *   buttons. See #GdkModifierType.
@@ -123,16 +139,19 @@ struct _GdkEventMotion
  *   Normally button 1 is the left mouse button, 2 is the middle button,
  *   and 3 is the right button. On 2-button mice, the middle button can
  *   often be simulated by pressing both mouse buttons together.
- * @device: the master device that the event originated from. Use
- * gdk_event_get_source_device() to get the slave device.
- *   screen.
+ * @x: the x coordinate of the pointer relative to the surface.
+ * @y: the y coordinate of the pointer relative to the surface.
+ * @axes: @x, @y translated to the axes of @device, or %NULL if @device is
+ *   the mouse.
+ * @tool: a #GdkDeviceTool
  *
  * Used for button press and button release events. The
  * @type field will be one of %GDK_BUTTON_PRESS or %GDK_BUTTON_RELEASE,
  */
-struct _GdkEventButton
+struct _GdkButtonEvent
 {
-  GdkEventAny any;
+  GdkEvent parent_instance;
+
   GdkModifierType state;
   guint button;
   double x;
@@ -142,25 +161,16 @@ struct _GdkEventButton
 };
 
 /*
- * GdkEventTouch:
- * @type: the type of the event (%GDK_TOUCH_BEGIN, %GDK_TOUCH_UPDATE,
- *   %GDK_TOUCH_END, %GDK_TOUCH_CANCEL)
- * @surface: the surface which received the event
- * @send_event: %TRUE if the event was sent explicitly.
- * @time: the time of the event in milliseconds.
- * @x: the x coordinate of the pointer relative to the surface
- * @y: the y coordinate of the pointer relative to the surface
- * @axes: @x, @y translated to the axes of @device, or %NULL if @device is
- *   the mouse
+ * GdkTouchEvent:
  * @state: (type GdkModifierType): a bit-mask representing the state of
  *   the modifier keys (e.g. Control, Shift and Alt) and the pointer
  *   buttons. See #GdkModifierType
+ * @x: the x coordinate of the pointer relative to the surface
+ * @y: the y coordinate of the pointer relative to the surface
+ * @axes: @x, @y translated to the axes of the event's device, or %NULL
+ *   if @device is the mouse
  * @sequence: the event sequence that the event belongs to
- * @emulating_pointer: whether the event should be used for emulating
- *   pointer event
- * @device: the master device that the event originated from. Use
- * gdk_event_get_source_device() to get the slave device.
- *   screen
+ * @emulated: whether the event is the result of a pointer emulation
  *
  * Used for touch events.
  * @type field will be one of %GDK_TOUCH_BEGIN, %GDK_TOUCH_UPDATE,
@@ -173,22 +183,21 @@ struct _GdkEventButton
  * (or %GDK_TOUCH_CANCEL) event. With multitouch devices, there may be
  * several active sequences at the same time.
  */
-struct _GdkEventTouch
+struct _GdkTouchEvent
 {
-  GdkEventAny any;
+  GdkEvent parent_instance;
+
   GdkModifierType state;
   double x;
   double y;
   double *axes;
   GdkEventSequence *sequence;
+  gboolean touch_emulating;
+  gboolean pointer_emulated;
 };
 
 /*
- * GdkEventScroll:
- * @type: the type of the event (%GDK_SCROLL).
- * @surface: the surface which received the event.
- * @send_event: %TRUE if the event was sent explicitly.
- * @time: the time of the event in milliseconds.
+ * GdkScrollEvent:
  * @x: the x coordinate of the pointer relative to the surface.
  * @y: the y coordinate of the pointer relative to the surface.
  * @state: (type GdkModifierType): a bit-mask representing the state of
@@ -197,10 +206,11 @@ struct _GdkEventTouch
  * @direction: the direction to scroll to (one of %GDK_SCROLL_UP,
  *   %GDK_SCROLL_DOWN, %GDK_SCROLL_LEFT, %GDK_SCROLL_RIGHT or
  *   %GDK_SCROLL_SMOOTH).
- * @device: the master device that the event originated from. Use
- * gdk_event_get_source_device() to get the slave device.
  * @delta_x: the x coordinate of the scroll delta
  * @delta_y: the y coordinate of the scroll delta
+ * @pointer_emulated: whether the scroll event was the result of
+ *   a pointer emulation
+ * @tool: a #GdkDeviceTool
  *
  * Generated from button presses for the buttons 4 to 7. Wheel mice are
  * usually configured to generate button press events for buttons 4 and 5
@@ -211,18 +221,30 @@ struct _GdkEventTouch
  * these, the scroll deltas can be obtained with
  * gdk_event_get_scroll_deltas().
  */
-struct _GdkEventScroll
+struct _GdkScrollEvent
 {
-  GdkEventAny any;
+  GdkEvent parent_instance;
+
   double x;
   double y;
   GdkModifierType state;
   GdkScrollDirection direction;
   double delta_x;
   double delta_y;
+  gboolean pointer_emulated;
+  gboolean is_stop;
   GdkDeviceTool *tool;
 };
 
+/*
+ * GdkTranslatedKey:
+ * @keyval: the translated key symbol
+ * @consumed: the consumed modifiers
+ * @layout: the keyboard layout
+ * @level: the layout level
+ *
+ * Describes a translated key code.
+ */
 typedef struct {
   guint keyval;
   GdkModifierType consumed;
@@ -231,11 +253,7 @@ typedef struct {
 } GdkTranslatedKey;
 
 /*
- * GdkEventKey:
- * @type: the type of the event (%GDK_KEY_PRESS or %GDK_KEY_RELEASE).
- * @surface: the surface which received the event.
- * @send_event: %TRUE if the event was sent explicitly.
- * @time: the time of the event in milliseconds.
+ * GdkKeyEvent:
  * @state: (type GdkModifierType): a bit-mask representing the state of
  *   the modifier keys (e.g. Control, Shift and Alt) and the pointer
  *   buttons. See #GdkModifierType.
@@ -245,41 +263,40 @@ typedef struct {
  *
  * Describes a key press or key release event.
  */
-struct _GdkEventKey
+struct _GdkKeyEvent
 {
-  GdkEventAny any;
+  GdkEvent parent_instance;
+
   GdkModifierType state;
   guint32 keycode;
+  gboolean key_is_modifier;
   GdkTranslatedKey translated[2];
 };
 
 /*
- * GdkEventCrossing:
- * @type: the type of the event (%GDK_ENTER_NOTIFY or %GDK_LEAVE_NOTIFY).
- * @surface: the surface which received the event.
- * @send_event: %TRUE if the event was sent explicitly.
- * @child_surface: the surface that was entered or left.
- * @time: the time of the event in milliseconds.
- * @x: the x coordinate of the pointer relative to the surface.
- * @y: the y coordinate of the pointer relative to the surface.
+ * GdkCrossingEvent:
+ * @state: (type GdkModifierType): a bit-mask representing the state of
+ *   the modifier keys (e.g. Control, Shift and Alt) and the pointer
+ *   buttons. See #GdkModifierType.
  * @mode: the crossing mode (%GDK_CROSSING_NORMAL, %GDK_CROSSING_GRAB,
  *  %GDK_CROSSING_UNGRAB, %GDK_CROSSING_GTK_GRAB, %GDK_CROSSING_GTK_UNGRAB or
  *  %GDK_CROSSING_STATE_CHANGED).  %GDK_CROSSING_GTK_GRAB, %GDK_CROSSING_GTK_UNGRAB,
  *  and %GDK_CROSSING_STATE_CHANGED were added in 2.14 and are always synthesized,
  *  never native.
+ * @x: the x coordinate of the pointer relative to the surface.
+ * @y: the y coordinate of the pointer relative to the surface.
  * @detail: the kind of crossing that happened (%GDK_NOTIFY_INFERIOR,
  *  %GDK_NOTIFY_ANCESTOR, %GDK_NOTIFY_VIRTUAL, %GDK_NOTIFY_NONLINEAR or
  *  %GDK_NOTIFY_NONLINEAR_VIRTUAL).
  * @focus: %TRUE if @surface is the focus surface or an inferior.
- * @state: (type GdkModifierType): a bit-mask representing the state of
- *   the modifier keys (e.g. Control, Shift and Alt) and the pointer
- *   buttons. See #GdkModifierType.
+ * @child_surface: the surface that was entered or left.
  *
  * Generated when the pointer enters or leaves a surface.
  */
-struct _GdkEventCrossing
+struct _GdkCrossingEvent
 {
-  GdkEventAny any;
+  GdkEvent parent_instance;
+
   GdkModifierType state;
   GdkCrossingMode mode;
   double x;
@@ -290,10 +307,7 @@ struct _GdkEventCrossing
 };
 
 /*
- * GdkEventFocus:
- * @type: the type of the event (%GDK_FOCUS_CHANGE).
- * @surface: the surface which received the event.
- * @send_event: %TRUE if the event was sent explicitly.
+ * GdkFocusEvent:
  * @in: %TRUE if the surface has gained the keyboard focus, %FALSE if
  *   it has lost the focus.
  * @mode: the crossing mode
@@ -301,19 +315,15 @@ struct _GdkEventCrossing
  *
  * Describes a change of keyboard focus.
  */
-struct _GdkEventFocus
+struct _GdkFocusEvent
 {
-  GdkEventAny any;
-  gint16 in;
-  GdkCrossingMode mode;
-  GdkNotifyType detail;
+  GdkEvent parent_instance;
+
+  gboolean focus_in;
 };
 
 /*
- * GdkEventConfigure:
- * @type: the type of the event (%GDK_CONFIGURE).
- * @surface: the surface which received the event.
- * @send_event: %TRUE if the event was sent explicitly.
+ * GdkConfigureEvent:
  * @x: the new x coordinate of the surface, relative to its parent.
  * @y: the new y coordinate of the surface, relative to its parent.
  * @width: the new width of the surface.
@@ -321,9 +331,10 @@ struct _GdkEventFocus
  *
  * Generated when a surface size or position has changed.
  */
-struct _GdkEventConfigure
+struct _GdkConfigureEvent
 {
-  GdkEventAny any;
+  GdkEvent parent_instance;
+
   int x;
   int y;
   int width;
@@ -331,36 +342,23 @@ struct _GdkEventConfigure
 };
 
 /*
- * GdkEventProximity:
- * @type: the type of the event (%GDK_PROXIMITY_IN or %GDK_PROXIMITY_OUT).
- * @surface: the surface which received the event.
- * @send_event: %TRUE if the event was sent explicitly.
- * @time: the time of the event in milliseconds.
- * @device: the master device that the event originated from. Use
- * gdk_event_get_source_device() to get the slave device.
+ * GdkProximityEvent:
+ * @tool: the #GdkDeviceTool associated to the event 
  *
- * Proximity events are generated when using GDK’s wrapper for the
- * XInput extension. The XInput extension is an add-on for standard X
- * that allows you to use nonstandard devices such as graphics tablets.
- * A proximity event indicates that the stylus has moved in or out of
- * contact with the tablet, or perhaps that the user’s finger has moved
- * in or out of contact with a touch screen.
- *
- * This event type will be used pretty rarely. It only is important for
- * XInput aware programs that are drawing their own cursor.
+ * A proximity event indicates that a tool of a graphic tablet, or similar
+ * devices that report proximity, has moved in or out of contact with the
+ * tablet, or perhaps that the user’s finger has moved in or out of contact
+ * with a touch screen.
  */
-struct _GdkEventProximity
+struct _GdkProximityEvent
 {
-  GdkEventAny any;
+  GdkEvent parent_instance;
+
   GdkDeviceTool *tool;
 };
 
 /*
- * GdkEventGrabBroken:
- * @type: the type of the event (%GDK_GRAB_BROKEN)
- * @surface: the surface which received the event, i.e. the surface
- *   that previously owned the grab
- * @send_event: %TRUE if the event was sent explicitly.
+ * GdkGrabBrokenEvent:
  * @keyboard: %TRUE if a keyboard grab was broken, %FALSE if a pointer
  *   grab was broken
  * @implicit: %TRUE if the broken grab was implicit
@@ -372,67 +370,39 @@ struct _GdkEventProximity
  * when the grab surface becomes unviewable (i.e. it or one of its ancestors
  * is unmapped), or if the same application grabs the pointer or keyboard
  * again. Note that implicit grabs (which are initiated by button presses)
- * can also cause #GdkEventGrabBroken events.
+ * can also cause #GdkGrabBrokenEvent events.
  */
-struct _GdkEventGrabBroken {
-  GdkEventAny any;
+struct _GdkGrabBrokenEvent
+{
+  GdkEvent parent_instance;
+
   gboolean keyboard;
   gboolean implicit;
   GdkSurface *grab_surface;
 };
 
 /*
- * GdkEventDND:
- * @type: the type of the event (%GDK_DRAG_ENTER, %GDK_DRAG_LEAVE,
- *   %GDK_DRAG_MOTION or %GDK_DROP_START)
- * @surface: the surface which received the event.
- * @send_event: %TRUE if the event was sent explicitly.
+ * GdkDNDEvent:
  * @drop: the #GdkDrop for the current DND operation.
- * @time: the time of the event in milliseconds.
+ * @x: the X coordinate of the pointer
+ * @y: the Y coordinate of the pointer
  *
  * Generated during DND operations.
  */
-struct _GdkEventDND {
-  GdkEventAny any;
+struct _GdkDNDEvent
+{
+  GdkEvent parent_instance;
+
   GdkDrop *drop;
   double x;
   double y;
 };
 
 /*
- * GdkEventTouchpadSwipe:
- * @type: the type of the event (%GDK_TOUCHPAD_SWIPE)
- * @surface: the surface which received the event
- * @send_event: %TRUE if the event was sent explicitly
- * @phase: (type GdkTouchpadGesturePhase): the current phase of the gesture
- * @n_fingers: The number of fingers triggering the swipe
- * @time: the time of the event in milliseconds
- * @x: The X coordinate of the pointer
- * @y: The Y coordinate of the pointer
- * @dx: Movement delta in the X axis of the swipe focal point
- * @dy: Movement delta in the Y axis of the swipe focal point
+ * GdkTouchpadEvent:
  * @state: (type GdkModifierType): a bit-mask representing the state of
  *   the modifier keys (e.g. Control, Shift and Alt) and the pointer
  *   buttons. See #GdkModifierType.
- *
- * Generated during touchpad swipe gestures.
- */
-struct _GdkEventTouchpadSwipe {
-  GdkEventAny any;
-  GdkModifierType state;
-  gint8 phase;
-  gint8 n_fingers;
-  double x;
-  double y;
-  double dx;
-  double dy;
-};
-
-/*
- * GdkEventTouchpadPinch:
- * @type: the type of the event (%GDK_TOUCHPAD_PINCH)
- * @surface: the surface which received the event
- * @send_event: %TRUE if the event was sent explicitly
  * @phase: (type GdkTouchpadGesturePhase): the current phase of the gesture
  * @n_fingers: The number of fingers triggering the pinch
  * @time: the time of the event in milliseconds
@@ -440,18 +410,17 @@ struct _GdkEventTouchpadSwipe {
  * @y: The Y coordinate of the pointer
  * @dx: Movement delta in the X axis of the swipe focal point
  * @dy: Movement delta in the Y axis of the swipe focal point
- * @angle_delta: The angle change in radians, negative angles
+ * @angle_delta: For pinch events, the angle change in radians, negative angles
  *   denote counter-clockwise movements
- * @scale: The current scale, relative to that at the time of
+ * @scale: For pinch events, the current scale, relative to that at the time of
  *   the corresponding %GDK_TOUCHPAD_GESTURE_PHASE_BEGIN event
- * @state: (type GdkModifierType): a bit-mask representing the state of
- *   the modifier keys (e.g. Control, Shift and Alt) and the pointer
- *   buttons. See #GdkModifierType.
  *
- * Generated during touchpad swipe gestures.
+ * Generated during touchpad gestures.
  */
-struct _GdkEventTouchpadPinch {
-  GdkEventAny any;
+struct _GdkTouchpadEvent
+{
+  GdkEvent parent_instance;
+
   GdkModifierType state;
   gint8 phase;
   gint8 n_fingers;
@@ -463,99 +432,20 @@ struct _GdkEventTouchpadPinch {
   double scale;
 };
 
-/*
- * GdkEventPadButton:
- * @type: the type of the event (%GDK_PAD_BUTTON_PRESS or %GDK_PAD_BUTTON_RELEASE).
- * @surface: the surface which received the event.
- * @send_event: %TRUE if the event was sent explicitly.
- * @time: the time of the event in milliseconds.
- * @group: the pad group the button belongs to. A %GDK_SOURCE_TABLET_PAD device
- *   may have one or more groups containing a set of buttons/rings/strips each.
- * @button: The pad button that was pressed.
- * @mode: The current mode of @group. Different groups in a %GDK_SOURCE_TABLET_PAD
- *   device may have different current modes.
- *
- * Generated during %GDK_SOURCE_TABLET_PAD button presses and releases.
- */
-struct _GdkEventPadButton {
-  GdkEventAny any;
-  guint group;
-  guint button;
-  guint mode;
-};
+struct _GdkPadEvent
+{
+  GdkEvent parent_instance;
 
-/*
- * GdkEventPadAxis:
- * @type: the type of the event (%GDK_PAD_RING or %GDK_PAD_STRIP).
- * @surface: the surface which received the event.
- * @send_event: %TRUE if the event was sent explicitly.
- * @time: the time of the event in milliseconds.
- * @group: the pad group the ring/strip belongs to. A %GDK_SOURCE_TABLET_PAD
- *   device may have one or more groups containing a set of buttons/rings/strips
- *   each.
- * @index: number of strip/ring that was interacted. This number is 0-indexed.
- * @mode: The current mode of @group. Different groups in a %GDK_SOURCE_TABLET_PAD
- *   device may have different current modes.
- * @value: The current value for the given axis.
- *
- * Generated during %GDK_SOURCE_TABLET_PAD interaction with tactile sensors.
- */
-struct _GdkEventPadAxis {
-  GdkEventAny any;
   guint group;
-  guint index;
   guint mode;
+  guint button;
+  guint index;
   double value;
 };
 
-/*
- * GdkEventPadGroupMode:
- * @type: the type of the event (%GDK_PAD_GROUP_MODE).
- * @surface: the surface which received the event.
- * @send_event: %TRUE if the event was sent explicitly.
- * @time: the time of the event in milliseconds.
- * @group: the pad group that is switching mode. A %GDK_SOURCE_TABLET_PAD
- *   device may have one or more groups containing a set of buttons/rings/strips
- *   each.
- * @mode: The new mode of @group. Different groups in a %GDK_SOURCE_TABLET_PAD
- *   device may have different current modes.
- *
- * Generated during %GDK_SOURCE_TABLET_PAD mode switches in a group.
- */
-struct _GdkEventPadGroupMode {
-  GdkEventAny any;
-  guint group;
-  guint mode;
-};
+void gdk_event_init_types (void);
 
-/*
- * GdkEvent:
- *
- * The GdkEvent struct is private and should only be accessed
- * using the accessor functions.
- */
-union _GdkEvent
-{
-  GdkEventAny              any;
-  GdkEventMotion           motion;
-  GdkEventButton           button;
-  GdkEventTouch             touch;
-  GdkEventScroll            scroll;
-  GdkEventKey              key;
-  GdkEventCrossing         crossing;
-  GdkEventFocus                    focus_change;
-  GdkEventConfigure        configure;
-  GdkEventProximity        proximity;
-  GdkEventDND               dnd;
-  GdkEventGrabBroken        grab_broken;
-  GdkEventTouchpadSwipe     touchpad_swipe;
-  GdkEventTouchpadPinch     touchpad_pinch;
-  GdkEventPadButton         pad_button;
-  GdkEventPadAxis           pad_axis;
-  GdkEventPadGroupMode      pad_group_mode;
-};
-
-GdkEvent * gdk_event_button_new         (GdkEventType     type,
+GdkEvent * gdk_button_event_new         (GdkEventType     type,
                                          GdkSurface      *surface,
                                          GdkDevice       *device,
                                          GdkDevice       *source_device,
@@ -567,7 +457,7 @@ GdkEvent * gdk_event_button_new         (GdkEventType     type,
                                          double           y,
                                          double          *axes);
                              
-GdkEvent * gdk_event_motion_new         (GdkSurface      *surface,
+GdkEvent * gdk_motion_event_new         (GdkSurface      *surface,
                                          GdkDevice       *device,
                                          GdkDevice       *source_device,
                                          GdkDeviceTool   *tool,
@@ -577,7 +467,7 @@ GdkEvent * gdk_event_motion_new         (GdkSurface      *surface,
                                          double           y,
                                          double          *axes);
 
-GdkEvent * gdk_event_crossing_new       (GdkEventType     type,
+GdkEvent * gdk_crossing_event_new       (GdkEventType     type,
                                          GdkSurface      *surface,
                                          GdkDevice       *device,
                                          GdkDevice       *source_device,
@@ -588,14 +478,14 @@ GdkEvent * gdk_event_crossing_new       (GdkEventType     type,
                                          GdkCrossingMode  mode,
                                          GdkNotifyType    notify);
                                           
-GdkEvent * gdk_event_proximity_new      (GdkEventType     type,
+GdkEvent * gdk_proximity_event_new      (GdkEventType     type,
                                          GdkSurface      *surface,
                                          GdkDevice       *device,
                                          GdkDevice       *source_device,
                                          GdkDeviceTool   *tool,
                                          guint32          time);
 
-GdkEvent * gdk_event_key_new            (GdkEventType      type,
+GdkEvent * gdk_key_event_new            (GdkEventType      type,
                                          GdkSurface       *surface,
                                          GdkDevice        *device,
                                          GdkDevice        *source_device,
@@ -606,18 +496,18 @@ GdkEvent * gdk_event_key_new            (GdkEventType      type,
                                          GdkTranslatedKey *translated,
                                          GdkTranslatedKey *no_lock);
 
-GdkEvent * gdk_event_focus_new          (GdkSurface      *surface,
+GdkEvent * gdk_focus_event_new          (GdkSurface      *surface,
                                          GdkDevice       *device,
                                          GdkDevice       *source_device,
                                          gboolean         focus_in);
 
-GdkEvent * gdk_event_configure_new      (GdkSurface      *surface,
+GdkEvent * gdk_configure_event_new      (GdkSurface      *surface,
                                          int              width,
                                          int              height);
 
-GdkEvent * gdk_event_delete_new         (GdkSurface      *surface);
+GdkEvent * gdk_delete_event_new         (GdkSurface      *surface);
 
-GdkEvent * gdk_event_scroll_new         (GdkSurface      *surface,
+GdkEvent * gdk_scroll_event_new         (GdkSurface      *surface,
                                          GdkDevice       *device,
                                          GdkDevice       *source_device,
                                          GdkDeviceTool   *tool,
@@ -627,7 +517,7 @@ GdkEvent * gdk_event_scroll_new         (GdkSurface      *surface,
                                          double           delta_y,
                                          gboolean         is_stop);
 
-GdkEvent * gdk_event_discrete_scroll_new (GdkSurface         *surface,
+GdkEvent * gdk_scroll_event_new_discrete (GdkSurface         *surface,
                                           GdkDevice          *device,
                                           GdkDevice          *source_device,
                                           GdkDeviceTool      *tool,
@@ -636,7 +526,7 @@ GdkEvent * gdk_event_discrete_scroll_new (GdkSurface         *surface,
                                           GdkScrollDirection  direction,
                                           gboolean            emulated);
 
-GdkEvent * gdk_event_touch_new          (GdkEventType      type,
+GdkEvent * gdk_touch_event_new          (GdkEventType      type,
                                          GdkEventSequence *sequence,
                                          GdkSurface       *surface,
                                          GdkDevice        *device,
@@ -648,7 +538,7 @@ GdkEvent * gdk_event_touch_new          (GdkEventType      type,
                                          double           *axes,
                                          gboolean          emulating);
  
-GdkEvent * gdk_event_touchpad_swipe_new (GdkSurface      *surface,
+GdkEvent * gdk_touchpad_event_new_swipe (GdkSurface      *surface,
                                          GdkDevice       *device,
                                          GdkDevice       *source_device,
                                          guint32          time,
@@ -660,7 +550,7 @@ GdkEvent * gdk_event_touchpad_swipe_new (GdkSurface      *surface,
                                          double           dx,
                                          double           dy);
 
-GdkEvent * gdk_event_touchpad_pinch_new (GdkSurface              *surface,
+GdkEvent * gdk_touchpad_event_new_pinch (GdkSurface              *surface,
                                          GdkDevice               *device,
                                          GdkDevice               *source_device,
                                          guint32                  time,
@@ -674,7 +564,7 @@ GdkEvent * gdk_event_touchpad_pinch_new (GdkSurface              *surface,
                                          double                   scale,
                                          double                   angle_delta);
 
-GdkEvent * gdk_event_pad_ring_new       (GdkSurface      *surface,
+GdkEvent * gdk_pad_event_new_ring       (GdkSurface      *surface,
                                          GdkDevice       *device,
                                          GdkDevice       *source_device,
                                          guint32          time,
@@ -683,7 +573,7 @@ GdkEvent * gdk_event_pad_ring_new       (GdkSurface      *surface,
                                          guint            mode,
                                          double           value);
 
-GdkEvent * gdk_event_pad_strip_new      (GdkSurface      *surface,
+GdkEvent * gdk_pad_event_new_strip      (GdkSurface      *surface,
                                          GdkDevice       *device,
                                          GdkDevice       *source_device,
                                          guint32          time,
@@ -692,7 +582,7 @@ GdkEvent * gdk_event_pad_strip_new      (GdkSurface      *surface,
                                          guint            mode,
                                          double           value);
 
-GdkEvent * gdk_event_pad_button_new     (GdkEventType     type,
+GdkEvent * gdk_pad_event_new_button     (GdkEventType     type,
                                          GdkSurface      *surface,
                                          GdkDevice       *device,
                                          GdkDevice       *source_device,
@@ -701,14 +591,14 @@ GdkEvent * gdk_event_pad_button_new     (GdkEventType     type,
                                          guint            button,
                                          guint            mode);
 
-GdkEvent * gdk_event_pad_group_mode_new (GdkSurface      *surface,
+GdkEvent * gdk_pad_event_new_group_mode (GdkSurface      *surface,
                                          GdkDevice       *device,
                                          GdkDevice       *source_device,
                                          guint32          time,
                                          guint            group,
                                          guint            mode);
 
-GdkEvent * gdk_event_drag_new           (GdkEventType     type,
+GdkEvent * gdk_dnd_event_new            (GdkEventType     type,
                                          GdkSurface      *surface,
                                          GdkDevice       *device,
                                          GdkDrop         *drop,
@@ -716,12 +606,12 @@ GdkEvent * gdk_event_drag_new           (GdkEventType     type,
                                          double           x,
                                          double           y);
 
-GdkEvent * gdk_event_grab_broken_new    (GdkSurface      *surface,
+GdkEvent * gdk_grab_broken_event_new    (GdkSurface      *surface,
                                          GdkDevice       *device,
                                          GdkDevice       *source_device,
                                          GdkSurface      *grab_surface,
                                          gboolean         implicit);
 
+G_END_DECLS
 
 #endif /* __GDK_EVENTS_PRIVATE_H__ */
-
diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c
index 037fca0e40..9f26ff828d 100644
--- a/gdk/gdksurface.c
+++ b/gdk/gdksurface.c
@@ -530,13 +530,13 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
                   0,
                   g_signal_accumulator_true_handled,
                   NULL,
-                  _gdk_marshal_BOOLEAN__BOXED,
+                  _gdk_marshal_BOOLEAN__POINTER,
                   G_TYPE_BOOLEAN,
                   1,
                   GDK_TYPE_EVENT);
   g_signal_set_va_marshaller (signals[EVENT],
                               G_OBJECT_CLASS_TYPE (object_class),
-                              _gdk_marshal_BOOLEAN__BOXEDv);
+                              _gdk_marshal_BOOLEAN__POINTERv);
 
   /**
    * GdkSurface::enter-montor:
@@ -2840,7 +2840,7 @@ add_event_mark (GdkEvent *event,
   g_type_class_unref (class);
   kind = value ? value->value_nick : "event";
 
-  switch (event_type)
+  switch ((int) event_type)
     {
     case GDK_MOTION_NOTIFY:
       {
@@ -2932,8 +2932,11 @@ gdk_surface_handle_event (GdkEvent *event)
 
   if (gdk_event_get_event_type (event) == GDK_CONFIGURE)
     {
+      int width, height;
+
+      gdk_configure_event_get_size (event, &width, &height);
       g_signal_emit (gdk_event_get_surface (event), signals[SIZE_CHANGED], 0,
-                     event->configure.width, event->configure.height);
+                     width, height);
       handled = TRUE;
     }
   else
diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c
index e29541c108..075a2a7c36 100644
--- a/gdk/wayland/gdkdevice-wayland.c
+++ b/gdk/wayland/gdkdevice-wayland.c
@@ -589,7 +589,7 @@ emulate_crossing (GdkSurface       *surface,
   double x, y;
 
   gdk_surface_get_device_position (surface, device, &x, &y, &state);
-  event = gdk_event_crossing_new (type,
+  event = gdk_crossing_event_new (type,
                                   surface,
                                   device,
                                   device,
@@ -614,7 +614,7 @@ emulate_touch_crossing (GdkSurface           *surface,
 {
   GdkEvent *event;
 
-  event = gdk_event_crossing_new (type,
+  event = gdk_crossing_event_new (type,
                                   surface,
                                   device,
                                   source,
@@ -633,7 +633,7 @@ emulate_focus (GdkSurface *surface,
                gboolean   focus_in,
                guint32    time_)
 {
-  GdkEvent *event = gdk_event_focus_new (surface, device, device, focus_in);
+  GdkEvent *event = gdk_focus_event_new (surface, device, device, focus_in);
 
   _gdk_wayland_display_deliver_event (gdk_surface_get_display (surface), event);
 }
@@ -1360,7 +1360,7 @@ flush_discrete_scroll_event (GdkWaylandSeat     *seat,
   GdkDevice *source;
 
   source = get_scroll_device (seat, seat->pointer_info.frame.source);
-  event = gdk_event_discrete_scroll_new (seat->pointer_info.focus,
+  event = gdk_scroll_event_new_discrete (seat->pointer_info.focus,
                                          seat->master_pointer,
                                          source,
                                          NULL,
@@ -1382,7 +1382,7 @@ flush_smooth_scroll_event (GdkWaylandSeat *seat,
   GdkDevice *source;
 
   source = get_scroll_device (seat, seat->pointer_info.frame.source);
-  event = gdk_event_scroll_new (seat->pointer_info.focus,
+  event = gdk_scroll_event_new (seat->pointer_info.focus,
                                 seat->master_pointer,
                                 source,
                                 NULL,
@@ -1498,7 +1498,7 @@ pointer_handle_enter (void              *data,
   seat->pointer_info.surface_y = wl_fixed_to_double (sy);
   seat->pointer_info.enter_serial = serial;
 
-  event = gdk_event_crossing_new (GDK_ENTER_NOTIFY,
+  event = gdk_crossing_event_new (GDK_ENTER_NOTIFY,
                                   seat->pointer_info.focus,
                                   seat->master_pointer,
                                   seat->pointer,
@@ -1541,7 +1541,7 @@ pointer_handle_leave (void              *data,
 
   _gdk_wayland_display_update_serial (display_wayland, serial);
 
-  event = gdk_event_crossing_new (GDK_LEAVE_NOTIFY,
+  event = gdk_crossing_event_new (GDK_LEAVE_NOTIFY,
                                   seat->pointer_info.focus,
                                   seat->master_pointer,
                                   seat->pointer,
@@ -1586,7 +1586,7 @@ pointer_handle_motion (void              *data,
   seat->pointer_info.surface_x = wl_fixed_to_double (sx);
   seat->pointer_info.surface_y = wl_fixed_to_double (sy);
 
-  event = gdk_event_motion_new (seat->pointer_info.focus,
+  event = gdk_motion_event_new (seat->pointer_info.focus,
                                 seat->master_pointer,
                                 seat->pointer,
                                 NULL,
@@ -1649,7 +1649,7 @@ pointer_handle_button (void              *data,
   if (state)
     seat->pointer_info.press_serial = serial;
 
-  event = gdk_event_button_new (state ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE,
+  event = gdk_button_event_new (state ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE,
                                 seat->pointer_info.focus,
                                 seat->master_pointer,
                                 seat->pointer,
@@ -1914,7 +1914,7 @@ keyboard_handle_enter (void               *data,
   g_object_ref (seat->keyboard_focus);
   seat->repeat_key = 0;
 
-  event = gdk_event_focus_new (seat->keyboard_focus,
+  event = gdk_focus_event_new (seat->keyboard_focus,
                                seat->master_keyboard,
                                seat->keyboard,
                                TRUE);
@@ -1949,7 +1949,7 @@ keyboard_handle_leave (void               *data,
 
   _gdk_wayland_display_update_serial (display, serial);
 
-  event = gdk_event_focus_new (seat->keyboard_focus,
+  event = gdk_focus_event_new (seat->keyboard_focus,
                                seat->master_keyboard,
                                seat->keyboard,
                                FALSE);
@@ -2075,7 +2075,7 @@ deliver_key_event (GdkWaylandSeat *seat,
       no_lock = translated;
     }
 
-  event = gdk_event_key_new (state ? GDK_KEY_PRESS : GDK_KEY_RELEASE,
+  event = gdk_key_event_new (state ? GDK_KEY_PRESS : GDK_KEY_RELEASE,
                              seat->keyboard_focus,
                              seat->master_keyboard,
                              seat->keyboard,
@@ -2375,7 +2375,7 @@ touch_handle_down (void              *data,
   touch->y = wl_fixed_to_double (y);
   touch->touch_down_serial = serial;
 
-  event = gdk_event_touch_new (GDK_TOUCH_BEGIN,
+  event = gdk_touch_event_new (GDK_TOUCH_BEGIN,
                                GDK_SLOT_TO_EVENT_SEQUENCE (touch->id),
                                touch->surface,
                                seat->touch_master,
@@ -2418,7 +2418,7 @@ touch_handle_up (void            *data,
   _gdk_wayland_display_update_serial (display, serial);
 
   touch = gdk_wayland_seat_get_touch (seat, id);
-  event = gdk_event_touch_new (GDK_TOUCH_END,
+  event = gdk_touch_event_new (GDK_TOUCH_END,
                                GDK_SLOT_TO_EVENT_SEQUENCE (touch->id),
                                touch->surface,
                                seat->touch_master,
@@ -2463,7 +2463,7 @@ touch_handle_motion (void            *data,
   if (touch->initial_touch)
     mimic_pointer_emulating_touch_info (seat->touch_master, touch);
 
-  event = gdk_event_touch_new (GDK_TOUCH_UPDATE,
+  event = gdk_touch_event_new (GDK_TOUCH_UPDATE,
                                GDK_SLOT_TO_EVENT_SEQUENCE (touch->id),
                                touch->surface,
                                seat->touch_master,
@@ -2509,7 +2509,7 @@ touch_handle_cancel (void            *data,
 
   while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &touch))
     {
-      event = gdk_event_touch_new (GDK_TOUCH_CANCEL,
+      event = gdk_touch_event_new (GDK_TOUCH_CANCEL,
                                    GDK_SLOT_TO_EVENT_SEQUENCE (touch->id),
                                    touch->surface,
                                    seat->touch_master,
@@ -2541,7 +2541,7 @@ emit_gesture_swipe_event (GdkWaylandSeat          *seat,
 
   seat->pointer_info.time = _time;
 
-  event = gdk_event_touchpad_swipe_new (seat->pointer_info.focus,
+  event = gdk_touchpad_event_new_swipe (seat->pointer_info.focus,
                                         seat->master_pointer,
                                         seat->pointer,
                                         _time,
@@ -2638,7 +2638,7 @@ emit_gesture_pinch_event (GdkWaylandSeat          *seat,
 
   seat->pointer_info.time = _time;
 
-  event = gdk_event_touchpad_pinch_new (seat->pointer_info.focus,
+  event = gdk_touchpad_event_new_pinch (seat->pointer_info.focus,
                                         seat->master_pointer,
                                         seat->pointer,
                                         _time,
@@ -3469,7 +3469,7 @@ tablet_tool_handle_proximity_in (void                      *data,
   gdk_wayland_device_tablet_clone_tool_axes (tablet, tool->tool);
   gdk_wayland_mimic_device_axes (tablet->master, tablet->current_device);
 
-  event = gdk_event_proximity_new (GDK_PROXIMITY_IN,
+  event = gdk_proximity_event_new (GDK_PROXIMITY_IN,
                                    tablet->pointer_info.focus,
                                    tablet->master,
                                    tablet->current_device,
@@ -3500,7 +3500,7 @@ tablet_tool_handle_proximity_out (void                      *data,
             g_message ("proximity out, seat %p, tool %d", tool->seat,
                        gdk_device_tool_get_tool_type (tool->tool)));
 
-  event = gdk_event_proximity_new (GDK_PROXIMITY_OUT,
+  event = gdk_proximity_event_new (GDK_PROXIMITY_OUT,
                                    tablet->pointer_info.focus,
                                    tablet->master,
                                    tablet->current_device,
@@ -3537,7 +3537,7 @@ tablet_create_button_event_frame (GdkWaylandTabletData *tablet,
   GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tablet->seat);
   GdkEvent *event;
 
-  event = gdk_event_button_new (evtype,
+  event = gdk_button_event_new (evtype,
                                 tablet->pointer_info.focus,
                                 tablet->master,
                                 tablet->current_device,
@@ -3603,7 +3603,7 @@ tablet_tool_handle_motion (void                      *data,
                        tablet->pointer_info.surface_x,
                        tablet->pointer_info.surface_y));
 
-  event = gdk_event_motion_new (tablet->pointer_info.focus,
+  event = gdk_motion_event_new (tablet->pointer_info.focus,
                                 tablet->master,
                                 tablet->current_device,
                                 tool->tool,
@@ -3765,7 +3765,7 @@ tablet_tool_handle_wheel (void                      *data,
     return;
 
   /* Send smooth event */
-  event = gdk_event_scroll_new (tablet->pointer_info.focus,
+  event = gdk_scroll_event_new (tablet->pointer_info.focus,
                                 tablet->master,
                                 tablet->current_device,
                                 tablet->current_tool->tool,
@@ -3777,7 +3777,7 @@ tablet_tool_handle_wheel (void                      *data,
   _gdk_wayland_display_deliver_event (seat->display, event);
 
   /* Send discrete event */
-  event = gdk_event_discrete_scroll_new (tablet->pointer_info.focus,
+  event = gdk_scroll_event_new_discrete (tablet->pointer_info.focus,
                                          tablet->master,
                                          tablet->current_device,
                                          tablet->current_tool->tool,
@@ -3888,7 +3888,7 @@ tablet_pad_ring_handle_frame (void                          *data,
   GDK_SEAT_NOTE (seat, EVENTS,
             g_message ("tablet pad ring handle frame, ring = %p", wp_tablet_pad_ring));
 
-  event = gdk_event_pad_ring_new (seat->keyboard_focus,
+  event = gdk_pad_event_new_ring (seat->keyboard_focus,
                                   pad->device,
                                   pad->device,
                                   time,
@@ -3963,7 +3963,7 @@ tablet_pad_strip_handle_frame (void                           *data,
             g_message ("tablet pad strip handle frame, strip = %p",
                        wp_tablet_pad_strip));
 
-  event = gdk_event_pad_strip_new (seat->keyboard_focus,
+  event = gdk_pad_event_new_strip (seat->keyboard_focus,
                                    pad->device,
                                    pad->device,
                                    time,
@@ -4089,7 +4089,7 @@ tablet_pad_group_handle_mode (void                           *data,
   group->current_mode = mode;
   n_group = g_list_index (pad->mode_groups, group);
 
-  event = gdk_event_pad_group_mode_new (seat->keyboard_focus,
+  event = gdk_pad_event_new_group_mode (seat->keyboard_focus,
                                         pad->device,
                                         pad->device,
                                         time,
@@ -4201,7 +4201,7 @@ tablet_pad_handle_button (void                     *data,
   g_assert (group != NULL);
   n_group = g_list_index (pad->mode_groups, group);
 
-  event = gdk_event_pad_button_new (state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED
+  event = gdk_pad_event_new_button (state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED
                                        ? GDK_PAD_BUTTON_PRESS
                                        : GDK_PAD_BUTTON_RELEASE,
                                     GDK_WAYLAND_SEAT (pad->seat)->keyboard_focus,
@@ -5031,7 +5031,7 @@ gdk_wayland_device_unset_touch_grab (GdkDevice        *gdk_device,
                               GDK_CURRENT_TIME);
     }
 
-  event = gdk_event_touch_new (GDK_TOUCH_CANCEL,
+  event = gdk_touch_event_new (GDK_TOUCH_CANCEL,
                                GDK_SLOT_TO_EVENT_SEQUENCE (touch->id),
                                touch->surface,
                                seat->touch_master,
diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c
index 82fae79e8e..5b6c08a5fe 100644
--- a/gdk/wayland/gdksurface-wayland.c
+++ b/gdk/wayland/gdksurface-wayland.c
@@ -891,7 +891,7 @@ gdk_wayland_surface_resize (GdkSurface *surface,
   GdkDisplay *display;
   GdkEvent *event;
 
-  event = gdk_event_configure_new (surface, width, height);
+  event = gdk_configure_event_new (surface, width, height);
 
   gdk_wayland_surface_update_size (surface, width, height, scale);
   _gdk_surface_update_size (surface);
@@ -1461,7 +1461,7 @@ gdk_wayland_surface_handle_close (GdkSurface *surface)
 
   GDK_DISPLAY_NOTE (display, EVENTS, g_message ("close %p", surface));
 
-  event = gdk_event_delete_new (surface);
+  event = gdk_delete_event_new (surface);
 
   _gdk_wayland_display_deliver_event (display, event);
 }
@@ -3817,7 +3817,8 @@ gdk_wayland_surface_show_window_menu (GdkSurface *surface,
   double x, y;
   uint32_t serial;
 
-  switch ((guint) event->any.type)
+  GdkEventType event_type = gdk_event_get_event_type (event);
+  switch ((guint) event_type)
     {
     case GDK_BUTTON_PRESS:
     case GDK_BUTTON_RELEASE:
diff --git a/gdk/win32/gdkdevicemanager-win32.c b/gdk/win32/gdkdevicemanager-win32.c
index 592b52a8d4..cfab1f18f5 100644
--- a/gdk/win32/gdkdevicemanager-win32.c
+++ b/gdk/win32/gdkdevicemanager-win32.c
@@ -1063,7 +1063,7 @@ gdk_input_other_event (GdkDisplay *display,
                             | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
                             | GDK_BUTTON5_MASK));
 
-          event = gdk_event_button_new (event_type,
+          event = gdk_button_event_new (event_type,
                                         window,
                                         device_manager->core_pointer,
                                         GDK_DEVICE (source_device),
@@ -1077,10 +1077,11 @@ gdk_input_other_event (GdkDisplay *display,
                                           
           GDK_NOTE (EVENTS_OR_INPUT,
                     g_print ("WINTAB button %s:%d %g,%g\n",
-                             (event->any.type == GDK_BUTTON_PRESS ?
+                             (event->event_type == GDK_BUTTON_PRESS ?
                               "press" : "release"),
-                             event->button.button,
-                             event->button.x, event->button.y));
+                             ((GdkButtonEvent *) event)->button,
+                             ((GdkButtonEvent *) event)->x,
+                             ((GdkButtonEvent *) event)->y));
         }
       else
         {
@@ -1097,7 +1098,7 @@ gdk_input_other_event (GdkDisplay *display,
                             | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
                             | GDK_BUTTON5_MASK));
 
-          event = gdk_event_motion_new (window,
+          event = gdk_motion_event_new (window,
                                         device_manager->core_pointer,
                                         GDK_DEVICE (source_device),
                                         NULL,
@@ -1108,7 +1109,8 @@ gdk_input_other_event (GdkDisplay *display,
                                         axes);
           GDK_NOTE (EVENTS_OR_INPUT,
                     g_print ("WINTAB motion: %g,%g\n",
-                             event->motion.x, event->motion.y));
+                             ((GdkMotionEvent *) event)->x,
+                             ((GdkMotionEvent *) event)->y));
         }
       return event;
 
diff --git a/gdk/win32/gdkdrag-win32.c b/gdk/win32/gdkdrag-win32.c
index a42a497152..c8074444dc 100644
--- a/gdk/win32/gdkdrag-win32.c
+++ b/gdk/win32/gdkdrag-win32.c
@@ -2515,7 +2515,8 @@ gdk_win32_drag_handle_event (GdkDrag  *drag,
   if (!drag_win32->handle_events)
     {
       /* FIXME: remove this functionality once gtk no longer calls DnD after drag_done() */
-      g_warning ("Got an event %d for drag context %p, even though it's done!", event->any.type, drag);
+      g_warning ("Got an event %d for drag context %p, even though it's done!",
+                 event->event_type, drag);
       return FALSE;
     }
 
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index 86e3ccec0f..409f03dfd2 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -207,7 +207,7 @@ generate_focus_event (GdkDeviceManagerWin32 *device_manager,
   device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard;
   source_device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->system_keyboard;
 
-  event = gdk_event_focus_new (window, device, source_device, in);
+  event = gdk_focus_event_new (window, device, source_device, in);
 
   _gdk_win32_append_event (event);
 }
@@ -233,7 +233,7 @@ generate_grab_broken_event (GdkDeviceManagerWin32 *device_manager,
       source_device = device_manager->system_pointer;
     }
 
-  event = gdk_event_grab_broken_new (window,
+  event = gdk_grab_broken_event_new (window,
                                      device,
                                      source_device,
                                      grab_window,
@@ -885,12 +885,8 @@ decode_key_lparam (LPARAM lParam)
 static void
 fixup_event (GdkEvent *event)
 {
-  if (event->any.surface)
-    g_object_ref (event->any.surface);
-  if (((event->any.type == GDK_ENTER_NOTIFY) ||
-       (event->any.type == GDK_LEAVE_NOTIFY)) &&
-      (event->crossing.child_surface != NULL))
-    g_object_ref (event->crossing.child_surface);
+  if (event->surface)
+    g_object_ref (event->surface);
 }
 
 void
@@ -1080,7 +1076,7 @@ send_crossing_event (GdkDisplay                 *display,
   pt = *screen_pt;
   ScreenToClient (GDK_SURFACE_HWND (window), &pt);
 
-  event = gdk_event_crossing_new (type,
+  event = gdk_crossing_event_new (type,
                                   window,
                                   device_manager->core_pointer,
                                   device_manager->system_pointer,
@@ -1589,7 +1585,7 @@ generate_button_event (GdkEventType      type,
   current_x = (gint16) GET_X_LPARAM (msg->lParam) / impl->surface_scale;
   current_y = (gint16) GET_Y_LPARAM (msg->lParam) / impl->surface_scale;
 
-  event = gdk_event_button_new (type,
+  event = gdk_button_event_new (type,
                                 window,
                                 device_manager->core_pointer,
                                 device_manager->system_pointer,
@@ -2133,7 +2129,7 @@ gdk_event_translate (MSG  *msg,
       translated.consumed = 0;
       translated.layout = 0;
       translated.level = 0;
-      event = gdk_event_key_new (GDK_KEY_PRESS,
+      event = gdk_key_event_new (GDK_KEY_PRESS,
                                  window,
                                  device_manager_win32->core_keyboard,
                                  device_manager_win32->system_keyboard,
@@ -2336,7 +2332,7 @@ gdk_event_translate (MSG  *msg,
       translated.consumed = 0;
       translated.layout = group;
       translated.level = 0;
-      event = gdk_event_key_new ((msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN)
+      event = gdk_key_event_new ((msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN)
                                    ? GDK_KEY_PRESS
                                    : GDK_KEY_RELEASE,
                                  window,
@@ -2413,7 +2409,7 @@ gdk_event_translate (MSG  *msg,
           translated.consumed = 0;
           translated.layout = get_active_group ();
           translated.level = 0;
-          event = gdk_event_key_new (GDK_KEY_PRESS,
+          event = gdk_key_event_new (GDK_KEY_PRESS,
                                      window,
                                      device_manager_win32->core_keyboard,
                                      device_manager_win32->system_keyboard,
@@ -2427,7 +2423,7 @@ gdk_event_translate (MSG  *msg,
           _gdk_win32_append_event (event);
 
           /* Build a key release event.  */
-          event = gdk_event_key_new (GDK_KEY_RELEASE,
+          event = gdk_key_event_new (GDK_KEY_RELEASE,
                                      window,
                                      device_manager_win32->core_keyboard,
                                      device_manager_win32->system_keyboard,
@@ -2641,7 +2637,7 @@ gdk_event_translate (MSG  *msg,
          current_x = (gint16) GET_X_LPARAM (msg->lParam) / impl->surface_scale;
          current_y = (gint16) GET_Y_LPARAM (msg->lParam) / impl->surface_scale;
 
-         event = gdk_event_motion_new (window,
+         event = gdk_motion_event_new (window,
                                        device_manager_win32->core_pointer,
                                        device_manager_win32->system_pointer,
                                         NULL,
@@ -2767,7 +2763,7 @@ gdk_event_translate (MSG  *msg,
        */
       delta_y *= -1.0;
 
-      event = gdk_event_scroll_new (window,
+      event = gdk_scroll_event_new (window,
                                     device_manager_win32->core_pointer,
                                     device_manager_win32->system_pointer,
                                     NULL,
@@ -2790,7 +2786,7 @@ gdk_event_translate (MSG  *msg,
                       ? GDK_SCROLL_RIGHT
                       : GDK_SCROLL_LEFT;
 
-      event = gdk_event_discrete_scroll_new (window,
+      event = gdk_scroll_event_new_discrete (window,
                                              device_manager_win32->core_pointer,
                                              device_manager_win32->system_pointer,
                                              NULL,
@@ -3425,7 +3421,7 @@ gdk_event_translate (MSG  *msg,
       if (GDK_SURFACE_DESTROYED (window))
        break;
 
-      event = gdk_event_delete_new (window);
+      event = gdk_delete_event_new (window);
 
       _gdk_win32_append_event (event);
 
@@ -3459,7 +3455,7 @@ gdk_event_translate (MSG  *msg,
       if (window == NULL || GDK_SURFACE_DESTROYED (window))
        break;
 
-      event = gdk_event_delete_new (window);
+      event = gdk_delete_event_new (window);
 
       _gdk_win32_append_event (event);
 
diff --git a/gdk/win32/gdksurface-win32.c b/gdk/win32/gdksurface-win32.c
index 49d88987dd..196fd2a775 100644
--- a/gdk/win32/gdksurface-win32.c
+++ b/gdk/win32/gdksurface-win32.c
@@ -4462,7 +4462,7 @@ gdk_win32_surface_show_window_menu (GdkSurface *window,
   gint x, y;
   GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
 
-  switch (event->any.type)
+  switch ((int) event->event_type)
     {
     case GDK_BUTTON_PRESS:
     case GDK_BUTTON_RELEASE:
diff --git a/gdk/x11/gdkdevicemanager-xi2.c b/gdk/x11/gdkdevicemanager-xi2.c
index d6a80ba96b..2fa6a749c5 100644
--- a/gdk/x11/gdkdevicemanager-xi2.c
+++ b/gdk/x11/gdkdevicemanager-xi2.c
@@ -1448,7 +1448,7 @@ _gdk_device_manager_xi2_handle_focus (GdkSurface *surface,
     {
       GdkEvent *event;
 
-      event = gdk_event_focus_new (surface, device, source_device, focus_in);
+      event = gdk_focus_event_new (surface, device, source_device, focus_in);
       gdk_display_put_event (gdk_surface_get_display (surface), event);
       gdk_event_unref (event);
     }
@@ -1584,7 +1584,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
           {
             no_lock = translated;
           }
-        event = gdk_event_key_new (xev->evtype == XI_KeyPress
+        event = gdk_key_event_new (xev->evtype == XI_KeyPress
                                      ? GDK_KEY_PRESS
                                      : GDK_KEY_RELEASE,
                                    surface,
@@ -1654,7 +1654,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
             source_device = g_hash_table_lookup (device_manager->id_table,
                                                  GUINT_TO_POINTER (xev->sourceid));
 
-            event = gdk_event_discrete_scroll_new (surface,
+            event = gdk_scroll_event_new_discrete (surface,
                                                    device,
                                                    source_device,
                                                    NULL,
@@ -1684,7 +1684,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
              x = (double) xev->event_x / scale;
              y = (double) xev->event_y / scale;
 
-            event = gdk_event_button_new (ev->evtype == XI_ButtonPress
+            event = gdk_button_event_new (ev->evtype == XI_ButtonPress
                                             ? GDK_BUTTON_PRESS
                                             : GDK_BUTTON_RELEASE,
                                           surface,
@@ -1739,7 +1739,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
                                 xev->deviceid, xev->sourceid,
                                 xev->event, delta_x, delta_y));
 
-            event = gdk_event_scroll_new (surface,
+            event = gdk_scroll_event_new (surface,
                                           device,
                                           source_device,
                                           NULL,
@@ -1760,7 +1760,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
         x = (double) xev->event_x / scale;
         y = (double) xev->event_y / scale;
 
-        event = gdk_event_motion_new (surface,
+        event = gdk_motion_event_new (surface,
                                       device,
                                       source_device,
                                       source_device->last_tool,
@@ -1808,7 +1808,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
         x = (double) xev->event_x / scale;
         y = (double) xev->event_y / scale;
  
-        event = gdk_event_touch_new (ev->evtype == XI_TouchBegin
+        event = gdk_touch_event_new (ev->evtype == XI_TouchBegin
                                        ? GDK_TOUCH_BEGIN
                                        : GDK_TOUCH_END,
                                      GUINT_TO_POINTER (xev->detail),
@@ -1858,7 +1858,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
         x = (double) xev->event_x / scale;
         y = (double) xev->event_y / scale;
 
-        event = gdk_event_touch_new (GDK_TOUCH_UPDATE,
+        event = gdk_touch_event_new (GDK_TOUCH_UPDATE,
                                      GUINT_TO_POINTER (xev->detail),
                                      surface,
                                      device,
@@ -1911,7 +1911,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
               }
           }
 
-        event = gdk_event_crossing_new (ev->evtype == XI_Enter
+        event = gdk_crossing_event_new (ev->evtype == XI_Enter
                                           ? GDK_ENTER_NOTIFY
                                           : GDK_LEAVE_NOTIFY,
                                         surface,
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 7da3255687..ee129b8086 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -799,7 +799,7 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
 
       if (!is_substructure)
        {
-          event = gdk_event_delete_new (surface);
+          event = gdk_delete_event_new (surface);
 
          if (surface && GDK_SURFACE_XID (surface) != x11_screen->xroot_window)
            gdk_surface_destroy_notify (surface);
@@ -918,10 +918,10 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
        xevent->xconfigure.event == xevent->xconfigure.window)
         {
           int x, y;
+          int c_w = (xevent->xconfigure.width + surface_impl->surface_scale - 1) / 
surface_impl->surface_scale;
+          int c_h = (xevent->xconfigure.height + surface_impl->surface_scale - 1) / 
surface_impl->surface_scale;
 
-          event = gdk_event_configure_new (surface,
-                                          (xevent->xconfigure.width + surface_impl->surface_scale - 1) / 
surface_impl->surface_scale,
-                                          (xevent->xconfigure.height + surface_impl->surface_scale - 1) / 
surface_impl->surface_scale);
+          event = gdk_configure_event_new (surface, c_w, c_h);
 
          if (!xevent->xconfigure.send_event &&
              !xevent->xconfigure.override_redirect &&
@@ -974,8 +974,7 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
                 {
                   surface_impl->unscaled_width = xevent->xconfigure.width;
                   surface_impl->unscaled_height = xevent->xconfigure.height;
-                  surface->width = event->configure.width;
-                  surface->height = event->configure.height;
+                  gdk_configure_event_get_size (event, &surface->width, &surface->height);
 
                   _gdk_surface_update_size (surface);
                   _gdk_x11_surface_update_size (surface_impl);
@@ -1252,19 +1251,19 @@ _gdk_wm_protocols_filter (const XEvent  *xevent,
 
   if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW"))
     {
-  /* The delete window request specifies a window
-   *  to delete. We don't actually destroy the
-   *  window because "it is only a request". (The
-   *  window might contain vital data that the
-   *  program does not want destroyed). Instead
-   *  the event is passed along to the program,
-   *  which should then destroy the window.
-   */
+      /* The delete window request specifies a window
+       *  to delete. We don't actually destroy the
+       *  window because "it is only a request". (The
+       *  window might contain vital data that the
+       *  program does not want destroyed). Instead
+       *  the event is passed along to the program,
+       *  which should then destroy the window.
+       */
       GDK_DISPLAY_NOTE (display, EVENTS,
                g_message ("delete window:\t\twindow: %ld",
                           xevent->xclient.window));
 
-      *event = gdk_event_delete_new (win);
+      *event = gdk_delete_event_new (win);
 
       gdk_x11_surface_set_user_time (win, xevent->xclient.data.l[1]);
 
diff --git a/gdk/x11/gdkdrag-x11.c b/gdk/x11/gdkdrag-x11.c
index da0c516796..3ae250c965 100644
--- a/gdk/x11/gdkdrag-x11.c
+++ b/gdk/x11/gdkdrag-x11.c
@@ -1023,7 +1023,7 @@ send_client_message_async (GdkDrag      *drag,
 
 static void
 xdnd_send_xevent (GdkX11Drag *drag_x11,
-                  XEvent            *event_send)
+                  XEvent     *event_send)
 {
   GdkDrag *drag = GDK_DRAG (drag_x11);
   GdkDisplay *display = gdk_drag_get_display (drag);
@@ -2184,15 +2184,15 @@ gdk_drag_update (GdkDrag         *drag,
 }
 
 static gboolean
-gdk_dnd_handle_motion_event (GdkDrag        *drag,
-                             GdkEvent       *event)
+gdk_dnd_handle_motion_event (GdkDrag  *drag,
+                             GdkEvent *event)
 {
   double x, y;
   int x_root, y_root;
 
   gdk_event_get_position (event, &x, &y);
-  x_root = event->any.surface->x + x;
-  y_root = event->any.surface->y + y;
+  x_root = event->surface->x + x;
+  y_root = event->surface->y + y;
   gdk_drag_update (drag, x_root, y_root,
                    gdk_event_get_modifier_state (event),
                    gdk_event_get_time (event));
@@ -2200,8 +2200,8 @@ gdk_dnd_handle_motion_event (GdkDrag        *drag,
 }
 
 static gboolean
-gdk_dnd_handle_key_event (GdkDrag           *drag,
-                          GdkEventKey       *event)
+gdk_dnd_handle_key_event (GdkDrag  *drag,
+                          GdkEvent *event)
 {
   GdkX11Drag *x11_drag = GDK_X11_DRAG (drag);
   GdkModifierType state;
@@ -2209,12 +2209,14 @@ gdk_dnd_handle_key_event (GdkDrag           *drag,
   gint dx, dy;
 
   dx = dy = 0;
-  state = event->state;
-  pointer = gdk_device_get_associated_device (gdk_event_get_device ((GdkEvent *) event));
+  state = gdk_event_get_modifier_state (event);
+  pointer = gdk_device_get_associated_device (gdk_event_get_device (event));
 
-  if (event->any.type == GDK_KEY_PRESS)
+  if (event->event_type == GDK_KEY_PRESS)
     {
-      switch (event->translated[0].keyval)
+      guint keyval = gdk_key_event_get_keyval (event);
+
+      switch (keyval)
         {
         case GDK_KEY_Escape:
           gdk_drag_cancel (drag, GDK_DRAG_CANCEL_USER_CANCELLED);
@@ -2287,37 +2289,40 @@ gdk_dnd_handle_key_event (GdkDrag           *drag,
     }
 
   gdk_drag_update (drag, x11_drag->last_x, x11_drag->last_y, state,
-                   gdk_event_get_time ((GdkEvent *) event));
+                   gdk_event_get_time (event));
 
   return TRUE;
 }
 
 static gboolean
-gdk_dnd_handle_grab_broken_event (GdkDrag                  *drag,
-                                  GdkEventGrabBroken       *event)
+gdk_dnd_handle_grab_broken_event (GdkDrag  *drag,
+                                  GdkEvent *event)
 {
   GdkX11Drag *x11_drag = GDK_X11_DRAG (drag);
 
+  gboolean is_implicit = gdk_grab_broken_event_get_implicit (event);
+  GdkSurface *grab_surface = gdk_grab_broken_event_get_grab_surface (event);
+
   /* Don't cancel if we break the implicit grab from the initial button_press.
    * Also, don't cancel if we re-grab on the widget or on our IPC window, for
    * example, when changing the drag cursor.
    */
-  if (event->implicit ||
-      event->grab_surface == x11_drag->drag_surface ||
-      event->grab_surface == x11_drag->ipc_surface)
+  if (is_implicit ||
+      grab_surface == x11_drag->drag_surface ||
+      grab_surface == x11_drag->ipc_surface)
     return FALSE;
 
-  if (gdk_event_get_device ((GdkEvent *) event) !=
-      gdk_drag_get_device (drag))
+  if (gdk_event_get_device (event) != gdk_drag_get_device (drag))
     return FALSE;
 
   gdk_drag_cancel (drag, GDK_DRAG_CANCEL_ERROR);
+
   return TRUE;
 }
 
 static gboolean
-gdk_dnd_handle_button_event (GdkDrag              *drag,
-                             GdkEventButton       *event)
+gdk_dnd_handle_button_event (GdkDrag  *drag,
+                             GdkEvent *event)
 {
   GdkX11Drag *x11_drag = GDK_X11_DRAG (drag);
 
@@ -2347,17 +2352,21 @@ gdk_x11_drag_handle_event (GdkDrag        *drag,
   if (!x11_drag->grab_seat)
     return FALSE;
 
-  switch ((guint) event->any.type)
+  switch ((guint) event->event_type)
     {
     case GDK_MOTION_NOTIFY:
       return gdk_dnd_handle_motion_event (drag, event);
+
     case GDK_BUTTON_RELEASE:
-      return gdk_dnd_handle_button_event (drag, &event->button);
+      return gdk_dnd_handle_button_event (drag, event);
+
     case GDK_KEY_PRESS:
     case GDK_KEY_RELEASE:
-      return gdk_dnd_handle_key_event (drag, &event->key);
+      return gdk_dnd_handle_key_event (drag, event);
+
     case GDK_GRAB_BROKEN:
-      return gdk_dnd_handle_grab_broken_event (drag, &event->grab_broken);
+      return gdk_dnd_handle_grab_broken_event (drag, event);
+
     default:
       break;
     }
diff --git a/gdk/x11/gdkeventsource.c b/gdk/x11/gdkeventsource.c
index 3e4523077f..25338b4581 100644
--- a/gdk/x11/gdkeventsource.c
+++ b/gdk/x11/gdkeventsource.c
@@ -105,7 +105,7 @@ handle_focus_change (GdkEvent *event)
 
   toplevel->has_pointer = focus_in;
 
-  if (!event->crossing.focus || toplevel->has_focus_window)
+  if (!gdk_crossing_event_get_focus (event) || toplevel->has_focus_window)
     return;
 
   had_focus = HAS_FOCUS (toplevel);
@@ -115,7 +115,7 @@ handle_focus_change (GdkEvent *event)
     {
       GdkEvent *focus_event;
 
-      focus_event = gdk_event_focus_new (gdk_event_get_surface (event),
+      focus_event = gdk_focus_event_new (gdk_event_get_surface (event),
                                          gdk_event_get_device (event),
                                          gdk_event_get_source_device (event),
                                          focus_in);
@@ -135,7 +135,7 @@ create_synth_crossing_event (GdkEventType     evtype,
   g_assert (evtype == GDK_ENTER_NOTIFY || evtype == GDK_LEAVE_NOTIFY);
 
   gdk_event_get_position (real_event, &x, &y);
-  event = gdk_event_crossing_new (evtype,
+  event = gdk_crossing_event_new (evtype,
                                   gdk_event_get_surface (real_event),
                                   gdk_event_get_device (real_event),
                                   gdk_event_get_source_device (real_event),
diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c
index 01708cbc85..19f8911f91 100644
--- a/gdk/x11/gdksurface-x11.c
+++ b/gdk/x11/gdksurface-x11.c
@@ -4574,7 +4574,9 @@ gdk_x11_surface_show_window_menu (GdkSurface *surface,
   int x_root, y_root;
   XClientMessageEvent xclient = { 0 };
 
-  switch ((guint) event->any.type)
+  GdkEventType event_type = gdk_event_get_event_type (event);
+
+  switch ((guint) event_type)
     {
     case GDK_BUTTON_PRESS:
     case GDK_BUTTON_RELEASE:
diff --git a/gtk/gtkdroptarget.c b/gtk/gtkdroptarget.c
index 632a8699a3..dac70c7da5 100644
--- a/gtk/gtkdroptarget.c
+++ b/gtk/gtkdroptarget.c
@@ -384,7 +384,7 @@ gtk_drop_target_handle_event (GtkEventController *controller,
         GdkDragAction preferred;
 
         /* sanity check */
-        g_return_val_if_fail (self->drop == gdk_drag_event_get_drop (event), FALSE);
+        g_return_val_if_fail (self->drop == gdk_dnd_event_get_drop (event), FALSE);
 
         graphene_point_init (&self->coords, x, y);
         g_signal_emit (self, signals[MOTION], 0, x, y, &preferred);
@@ -403,7 +403,7 @@ gtk_drop_target_handle_event (GtkEventController *controller,
     case GDK_DROP_START:
       {
         /* sanity check */
-        g_return_val_if_fail (self->drop == gdk_drag_event_get_drop (event), FALSE);
+        g_return_val_if_fail (self->drop == gdk_dnd_event_get_drop (event), FALSE);
 
         graphene_point_init (&self->coords, x, y);
         self->dropping = TRUE;
diff --git a/gtk/gtkdroptargetasync.c b/gtk/gtkdroptargetasync.c
index 0c2061927a..4eb2ec0622 100644
--- a/gtk/gtkdroptargetasync.c
+++ b/gtk/gtkdroptargetasync.c
@@ -220,7 +220,7 @@ gtk_drop_target_async_handle_event (GtkEventController *controller,
         GtkWidget *widget = gtk_event_controller_get_widget (controller);
         GdkDragAction preferred_action;
 
-        drop = gdk_drag_event_get_drop (event);
+        drop = gdk_dnd_event_get_drop (event);
         /* sanity check */
         g_return_val_if_fail (self->drop == drop, FALSE);
         if (self->rejected)
@@ -243,7 +243,7 @@ gtk_drop_target_async_handle_event (GtkEventController *controller,
       {
         gboolean handled;
 
-        drop = gdk_drag_event_get_drop (event);
+        drop = gdk_dnd_event_get_drop (event);
         /* sanity check */
         g_return_val_if_fail (self->drop == drop, FALSE);
         if (self->rejected)
diff --git a/gtk/gtkeventcontrollerlegacy.c b/gtk/gtkeventcontrollerlegacy.c
index 8b4d69693f..406e6a6ff2 100644
--- a/gtk/gtkeventcontrollerlegacy.c
+++ b/gtk/gtkeventcontrollerlegacy.c
@@ -92,12 +92,12 @@ gtk_event_controller_legacy_class_init (GtkEventControllerLegacyClass *klass)
                   G_TYPE_FROM_CLASS (klass),
                   G_SIGNAL_RUN_LAST,
                   0, _gtk_boolean_handled_accumulator, NULL,
-                  _gtk_marshal_BOOLEAN__BOXED,
+                  _gtk_marshal_BOOLEAN__POINTER,
                   G_TYPE_BOOLEAN, 1,
                   GDK_TYPE_EVENT);
 
   g_signal_set_va_marshaller (signals[EVENT], G_TYPE_FROM_CLASS (klass),
-                              _gtk_marshal_BOOLEAN__BOXEDv);
+                              _gtk_marshal_BOOLEAN__POINTERv);
 }
 
 static void
diff --git a/gtk/gtkgesturerotate.c b/gtk/gtkgesturerotate.c
index 2f0541ab78..5498244d77 100644
--- a/gtk/gtkgesturerotate.c
+++ b/gtk/gtkgesturerotate.c
@@ -206,7 +206,7 @@ gtk_gesture_rotate_handle_event (GtkEventController *controller,
   if (gdk_event_get_event_type (event) == GDK_TOUCHPAD_PINCH)
     {
       phase = gdk_touchpad_event_get_gesture_phase (event);
-      delta = gdk_touchpad_pinch_event_get_angle_delta (event);
+      delta = gdk_touchpad_event_get_pinch_angle_delta (event);
       if (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN ||
           phase == GDK_TOUCHPAD_GESTURE_PHASE_END)
         priv->accum_touchpad_angle = 0;
diff --git a/gtk/gtkgesturestylus.c b/gtk/gtkgesturestylus.c
index 5d98a08b24..5944f0252e 100644
--- a/gtk/gtkgesturestylus.c
+++ b/gtk/gtkgesturestylus.c
@@ -290,8 +290,8 @@ gtk_gesture_stylus_get_backlog (GtkGestureStylus  *gesture,
 
   event = gesture_get_current_event (gesture);
 
-  if (event)
-    history = gdk_event_get_motion_history (event);
+  if (event && GDK_IS_EVENT_TYPE (event, GDK_MOTION_NOTIFY))
+    history = gdk_motion_event_get_history (event);
   if (!history)
     return FALSE;
 
diff --git a/gtk/gtkgesturezoom.c b/gtk/gtkgesturezoom.c
index 3eefa3f60a..83f8e3a276 100644
--- a/gtk/gtkgesturezoom.c
+++ b/gtk/gtkgesturezoom.c
@@ -104,7 +104,7 @@ _gtk_gesture_zoom_get_distance (GtkGestureZoom *zoom,
       double scale;
       /* Touchpad pinch */
 
-      scale = gdk_touchpad_pinch_event_get_scale (last_event);
+      scale = gdk_touchpad_event_get_pinch_scale (last_event);
       *distance = scale;
     }
   else
diff --git a/gtk/gtkiconview.c b/gtk/gtkiconview.c
index b078d69531..0bb039517c 100644
--- a/gtk/gtkiconview.c
+++ b/gtk/gtkiconview.c
@@ -2275,11 +2275,10 @@ gtk_icon_view_button_press (GtkGestureClick *gesture,
 }
 
 static gboolean
-button_event_modifies_selection (GdkEventButton *event)
+button_event_modifies_selection (GdkEvent *event)
 {
-  guint state;
+  guint state = gdk_event_get_modifier_state (event);
 
-  state = gdk_event_get_modifier_state ((GdkEvent *) event);
   return (state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0;
 }
 
@@ -2293,7 +2292,7 @@ gtk_icon_view_button_release (GtkGestureClick *gesture,
   GtkIconView *icon_view = user_data;
   int button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
   GdkEventSequence *sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
-  GdkEventButton *event = (GdkEventButton *)gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
+  GdkEvent *event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
 
   if (icon_view->priv->pressed_button == button)
     icon_view->priv->pressed_button = -1;
diff --git a/gtk/gtkimcontextsimple.c b/gtk/gtkimcontextsimple.c
index da85eee183..17e8f68505 100644
--- a/gtk/gtkimcontextsimple.c
+++ b/gtk/gtkimcontextsimple.c
@@ -806,7 +806,7 @@ no_sequence_matches (GtkIMContextSimple *context_simple,
           translated.consumed = 0;
           translated.layout = 0;
           translated.level = 0;
-          GdkEvent *tmp_event = gdk_event_key_new (GDK_KEY_PRESS,
+          GdkEvent *tmp_event = gdk_key_event_new (GDK_KEY_PRESS,
                                                    gdk_event_get_surface (event),
                                                    gdk_event_get_device (event),
                                                    gdk_event_get_source_device (event),
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 59af57fb7d..6b80dbf817 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -660,6 +660,7 @@ do_post_parse_initialization (void)
 
   gtk_widget_set_default_direction (gtk_get_locale_direction ());
 
+  gdk_event_init_types ();
   gsk_ensure_resources ();
   gsk_render_node_init_types ();
   _gtk_ensure_resources ();
@@ -1109,7 +1110,7 @@ rewrite_event_for_surface (GdkEvent  *event,
     {
     case GDK_BUTTON_PRESS:
     case GDK_BUTTON_RELEASE:
-      return gdk_event_button_new (type,
+      return gdk_button_event_new (type,
                                    new_surface,
                                    gdk_event_get_device (event),
                                    gdk_event_get_source_device (event),
@@ -1120,7 +1121,7 @@ rewrite_event_for_surface (GdkEvent  *event,
                                    x, y,
                                    NULL); // FIXME copy axes
     case GDK_MOTION_NOTIFY:
-      return gdk_event_motion_new (new_surface,
+      return gdk_motion_event_new (new_surface,
                                    gdk_event_get_device (event),
                                    gdk_event_get_source_device (event),
                                    gdk_event_get_device_tool (event),
@@ -1132,7 +1133,7 @@ rewrite_event_for_surface (GdkEvent  *event,
     case GDK_TOUCH_UPDATE:
     case GDK_TOUCH_END:
     case GDK_TOUCH_CANCEL:
-      return gdk_event_touch_new (type,
+      return gdk_touch_event_new (type,
                                   gdk_event_get_event_sequence (event),
                                   new_surface,
                                   gdk_event_get_device (event),
@@ -1144,7 +1145,7 @@ rewrite_event_for_surface (GdkEvent  *event,
                                   gdk_touch_event_get_emulating_pointer (event));
     case GDK_TOUCHPAD_SWIPE:
       gdk_touchpad_event_get_deltas (event, &dx, &dy);
-      return gdk_event_touchpad_swipe_new (new_surface,
+      return gdk_touchpad_event_new_swipe (new_surface,
                                            gdk_event_get_device (event),
                                            gdk_event_get_source_device (event),
                                            gdk_event_get_time (event),
@@ -1155,7 +1156,7 @@ rewrite_event_for_surface (GdkEvent  *event,
                                            dx, dy);
     case GDK_TOUCHPAD_PINCH:
       gdk_touchpad_event_get_deltas (event, &dx, &dy);
-      return gdk_event_touchpad_pinch_new (new_surface,
+      return gdk_touchpad_event_new_pinch (new_surface,
                                            gdk_event_get_device (event),
                                            gdk_event_get_source_device (event),
                                            gdk_event_get_time (event),
@@ -1164,8 +1165,8 @@ rewrite_event_for_surface (GdkEvent  *event,
                                            x, y,
                                            gdk_touchpad_event_get_n_fingers (event),
                                            dx, dy,
-                                           gdk_touchpad_pinch_event_get_scale (event),
-                                           gdk_touchpad_pinch_event_get_angle_delta (event));
+                                           gdk_touchpad_event_get_pinch_scale (event),
+                                           gdk_touchpad_event_get_pinch_angle_delta (event));
     default:
       break;
     }
@@ -1230,6 +1231,7 @@ static GdkEvent *
 rewrite_event_for_toplevel (GdkEvent *event)
 {
   GdkSurface *surface;
+  GdkKeyEvent *key_event;
 
   surface = gdk_event_get_surface (event);
   if (!surface->parent)
@@ -1238,7 +1240,10 @@ rewrite_event_for_toplevel (GdkEvent *event)
   while (surface->parent)
     surface = surface->parent;
 
-  return gdk_event_key_new (gdk_event_get_event_type (event),
+  key_event = (GdkKeyEvent *) event;
+
+  /* FIXME: Avoid direct access to the translated[] field */
+  return gdk_key_event_new (gdk_event_get_event_type (event),
                             surface,
                             gdk_event_get_device (event),
                             gdk_event_get_source_device (event),
@@ -1246,8 +1251,8 @@ rewrite_event_for_toplevel (GdkEvent *event)
                             gdk_key_event_get_keycode (event),
                             gdk_event_get_modifier_state (event),
                             gdk_key_event_is_modifier (event),
-                            &event->key.translated[0],
-                            &event->key.translated[1]);
+                            &key_event->translated[0],
+                            &key_event->translated[1]);
 }
 
 static gboolean
@@ -1505,7 +1510,7 @@ handle_pointing_event (GdkEvent *event)
       break;
     case GDK_DRAG_LEAVE:
       {
-        GdkDrop *drop = gdk_drag_event_get_drop (event);
+        GdkDrop *drop = gdk_dnd_event_get_drop (event);
         old_target = update_pointer_focus_state (toplevel, event, NULL);
         gtk_drop_begin_event (drop, GDK_DRAG_LEAVE);
         gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_DROP, old_target, NULL,
@@ -1544,10 +1549,10 @@ handle_pointing_event (GdkEvent *event)
       else if ((old_target != target) &&
                (type == GDK_DRAG_ENTER || type == GDK_DRAG_MOTION || type == GDK_DROP_START))
         {
-          GdkDrop *drop = gdk_drag_event_get_drop (event);
+          GdkDrop *drop = gdk_dnd_event_get_drop (event);
           gtk_drop_begin_event (drop, type);
           gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_DROP, old_target, target,
-                                          event, GDK_CROSSING_NORMAL, gdk_drag_event_get_drop (event));
+                                          event, GDK_CROSSING_NORMAL, gdk_dnd_event_get_drop (event));
           gtk_drop_end_event (drop);
         }
       else if (type == GDK_TOUCH_BEGIN)
@@ -1740,7 +1745,7 @@ gtk_main_do_event (GdkEvent *event)
     case GDK_DRAG_MOTION:
     case GDK_DROP_START:
       {
-        GdkDrop *drop = gdk_drag_event_get_drop (event);
+        GdkDrop *drop = gdk_dnd_event_get_drop (event);
         gtk_drop_begin_event (drop, gdk_event_get_event_type (event));
         gtk_propagate_event (target_widget, event);
         gtk_drop_end_event (drop);
diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list
index 6e91f452b5..e6c2606c50 100644
--- a/gtk/gtkmarshalers.list
+++ b/gtk/gtkmarshalers.list
@@ -50,6 +50,7 @@ BOOLEAN:VOID
 BOOLEAN:BOOLEAN
 BOOLEAN:BOOLEAN,BOOLEAN,BOOLEAN
 BOOLEAN:STRING
+BOOLEAN:POINTER
 ENUM:ENUM
 ENUM:VOID
 INT:POINTER
diff --git a/gtk/gtkpadcontroller.c b/gtk/gtkpadcontroller.c
index ef86f8c76a..833bf42338 100644
--- a/gtk/gtkpadcontroller.c
+++ b/gtk/gtkpadcontroller.c
@@ -243,13 +243,13 @@ gtk_pad_controller_handle_event (GtkEventController *controller,
     {
     case GDK_PAD_BUTTON_PRESS:
       type = GTK_PAD_ACTION_BUTTON;
-      index = gdk_pad_button_event_get_button (event);
+      index = gdk_pad_event_get_button (event);
       break;
     case GDK_PAD_RING:
     case GDK_PAD_STRIP:
       type = event_type == GDK_PAD_RING ?
         GTK_PAD_ACTION_RING : GTK_PAD_ACTION_STRIP;
-      gdk_pad_axis_event_get_value (event, &index, &value);
+      gdk_pad_event_get_axis_value (event, &index, &value);
       break;
     default:
       return GDK_EVENT_PROPAGATE;
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 50cdc28caf..91527f8d28 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -1963,7 +1963,7 @@ _gtk_widget_emulate_press (GtkWidget      *widget,
     case GDK_TOUCH_BEGIN:
     case GDK_TOUCH_UPDATE:
     case GDK_TOUCH_END:
-      press = gdk_event_touch_new (GDK_TOUCH_BEGIN,
+      press = gdk_touch_event_new (GDK_TOUCH_BEGIN,
                                    gdk_event_get_event_sequence (event),
                                    gdk_event_get_surface (event),
                                    gdk_event_get_device (event),
@@ -1976,7 +1976,7 @@ _gtk_widget_emulate_press (GtkWidget      *widget,
       break;
     case GDK_BUTTON_PRESS:
     case GDK_BUTTON_RELEASE:
-      press = gdk_event_button_new (GDK_BUTTON_PRESS,
+      press = gdk_button_event_new (GDK_BUTTON_PRESS,
                                     gdk_event_get_surface (event),
                                     gdk_event_get_device (event),
                                     gdk_event_get_source_device (event),
@@ -2002,7 +2002,7 @@ _gtk_widget_emulate_press (GtkWidget      *widget,
             button = 1;
           }
 
-        press = gdk_event_button_new (GDK_BUTTON_PRESS,
+        press = gdk_button_event_new (GDK_BUTTON_PRESS,
                                       gdk_event_get_surface (event),
                                       gdk_event_get_device (event),
                                       gdk_event_get_source_device (event),
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 3bd8d30e9f..fdc0cf8f1b 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -476,7 +476,7 @@ static void gtk_window_activate_default_activate (GtkWidget *widget,
                                                   GVariant *parameter);
 
 static void        gtk_window_do_popup                  (GtkWindow      *window,
-                                                         GdkEventButton *event);
+                                                         GdkEvent       *event);
 static void        gtk_window_css_changed               (GtkWidget      *widget,
                                                          GtkCssStyleChange *change);
 static void gtk_window_state_flags_changed (GtkWidget     *widget,
@@ -1211,7 +1211,7 @@ gtk_window_titlebar_action (GtkWindow      *window,
   else if (g_str_equal (action, "minimize"))
     gdk_toplevel_minimize (GDK_TOPLEVEL (priv->surface));
   else if (g_str_equal (action, "menu"))
-    gtk_window_do_popup (window, (GdkEventButton*) event);
+    gtk_window_do_popup (window, event);
   else
     {
       g_warning ("Unsupported titlebar action %s", action);
@@ -5895,8 +5895,8 @@ close_window_clicked (GtkModelButton *button,
 }
 
 static void
-gtk_window_do_popup_fallback (GtkWindow      *window,
-                              GdkEventButton *event)
+gtk_window_do_popup_fallback (GtkWindow *window,
+                              GdkEvent  *event)
 {
   GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
   GtkWidget *menuitem;
@@ -6005,12 +6005,12 @@ gtk_window_do_popup_fallback (GtkWindow      *window,
 }
 
 static void
-gtk_window_do_popup (GtkWindow      *window,
-                     GdkEventButton *event)
+gtk_window_do_popup (GtkWindow *window,
+                     GdkEvent  *event)
 {
   GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
 
-  if (!gdk_toplevel_show_window_menu (GDK_TOPLEVEL (priv->surface), (GdkEvent *) event))
+  if (!gdk_toplevel_show_window_menu (GDK_TOPLEVEL (priv->surface), event))
     gtk_window_do_popup_fallback (window, event);
 }
 
diff --git a/testsuite/gtk/gestures.c b/testsuite/gtk/gestures.c
index e510092aed..b515470697 100644
--- a/testsuite/gtk/gestures.c
+++ b/testsuite/gtk/gestures.c
@@ -23,7 +23,7 @@ inject_event (GdkEvent *event)
 {
   gboolean handled;
 
-  g_signal_emit_by_name (event->any.surface, "event", event, &handled);
+  g_signal_emit_by_name (event->surface, "event", event, &handled);
 }
 
 static void
@@ -44,7 +44,7 @@ point_press (PointState *point,
 
   if (point == &mouse_state)
     {
-      ev = gdk_event_button_new (GDK_BUTTON_PRESS,
+      ev = gdk_button_event_new (GDK_BUTTON_PRESS,
                                  surface,
                                  device,
                                  device,
@@ -59,7 +59,7 @@ point_press (PointState *point,
     }
   else
     {
-      ev = gdk_event_touch_new (GDK_TOUCH_BEGIN,
+      ev = gdk_touch_event_new (GDK_TOUCH_BEGIN,
                                 EVENT_SEQUENCE (point),
                                 surface,
                                 device,
@@ -100,7 +100,7 @@ point_update (PointState *point,
 
   if (point == &mouse_state)
     {
-      ev = gdk_event_motion_new (surface,
+      ev = gdk_motion_event_new (surface,
                                  device,
                                  device,
                                  NULL,
@@ -114,7 +114,7 @@ point_update (PointState *point,
       if (!point->widget || widget != point->widget)
         return;
 
-      ev = gdk_event_touch_new (GDK_TOUCH_UPDATE,
+      ev = gdk_touch_event_new (GDK_TOUCH_UPDATE,
                                 EVENT_SEQUENCE (point),
                                 surface,
                                 device,
@@ -157,7 +157,7 @@ point_release (PointState *point,
       if ((point->state & (GDK_BUTTON1_MASK << (button - 1))) == 0)
         return;
 
-      ev = gdk_event_button_new (GDK_BUTTON_RELEASE,
+      ev = gdk_button_event_new (GDK_BUTTON_RELEASE,
                                  surface,
                                  device,
                                  device,
@@ -172,7 +172,7 @@ point_release (PointState *point,
     }
   else
     {
-      ev = gdk_event_touch_new (GDK_TOUCH_END,
+      ev = gdk_touch_event_new (GDK_TOUCH_END,
                                 EVENT_SEQUENCE (point),
                                 surface,
                                 device,
diff --git a/testsuite/gtk/shortcuts.c b/testsuite/gtk/shortcuts.c
index a1b93afca2..9b24b907bc 100644
--- a/testsuite/gtk/shortcuts.c
+++ b/testsuite/gtk/shortcuts.c
@@ -1,84 +1,36 @@
 #include <gtk/gtk.h>
 
-typedef struct _GdkEventAny GdkEventAny;
-typedef struct _GdkEventKey GdkEventKey;
-
-struct _GdkEventAny
-{
-  int ref_count;
-  GdkEventType type;
-  GdkSurface *surface;
-  guint32 time;
-  guint16 flags;
-  guint pointer_emulated  : 1;
-  guint touch_emulating   : 1;
-  guint scroll_is_stop    : 1;
-  guint key_is_modifier   : 1;
-  guint focus_in          : 1;
-  GdkDevice *device;
-  GdkDevice *source_device;
-};
-
-typedef struct {
-  guint keyval;
-  GdkModifierType consumed;
-  guint layout;
-  guint level;
-} GdkTranslatedKey;
-
-struct _GdkEventKey
-{
-  GdkEventAny any;
-  GdkModifierType state;
-  guint32 keycode;
-  GdkTranslatedKey translated[2];
-};
-
-
-static GdkEvent *
-gdk_event_key_new (GdkEventType     type,
-                   GdkSurface      *surface,
-                   GdkDevice       *device,
-                   GdkDevice       *source_device,
-                   guint32          time,
-                   guint            keycode,
-                   GdkModifierType  state,
-                   gboolean         is_modifier,
-                   GdkTranslatedKey *translated,
-                   GdkTranslatedKey *no_lock);
+#define GTK_COMPILATION
+#include "gdk/gdkeventsprivate.h"
 
 static GdkEvent *
-gdk_event_key_new (GdkEventType     type,
-                   GdkSurface      *surface,
-                   GdkDevice       *device,
-                   GdkDevice       *source_device,
-                   guint32          time,
-                   guint            keycode,
-                   GdkModifierType  state,
-                   gboolean         is_modifier,
-                   GdkTranslatedKey *translated,
-                   GdkTranslatedKey *no_lock)
+key_event_new (GdkEventType      event_type,
+               GdkSurface       *surface,
+               GdkDevice        *device,
+               GdkDevice        *source_device,
+               guint32           time_,
+               guint             keycode,
+               GdkModifierType   state,
+               gboolean          is_modifier,
+               GdkTranslatedKey *translated,
+               GdkTranslatedKey *no_lock)
 {
-  GdkEventKey *event;
-
-  g_return_val_if_fail (type == GDK_KEY_PRESS ||
-                        type == GDK_KEY_RELEASE, NULL);
-
-  event = g_new0 (GdkEventKey, 1);
-
-  event->any.ref_count = 1;
-  event->any.type = type;
-  event->any.time = time;
-  event->any.surface = g_object_ref (surface);
-  event->any.device = g_object_ref (device);
-  event->any.source_device = g_object_ref (source_device);
-  event->keycode = keycode;
-  event->state = state;
-  event->any.key_is_modifier = is_modifier;
-  event->translated[0] = *translated;
-  event->translated[1] = *no_lock;
-
-  return (GdkEvent *)event;
+  GdkKeyEvent *key_event = (GdkKeyEvent *) g_type_create_instance (GDK_TYPE_KEY_EVENT);
+  GdkEvent *event = (GdkEvent *) key_event;
+
+  event->event_type = event_type;
+  event->surface = g_object_ref (surface);
+  event->device = g_object_ref (device);
+  event->source_device = g_object_ref (source_device);
+  event->time = time_;
+
+  key_event->keycode = keycode;
+  key_event->state = state;
+  key_event->key_is_modifier = is_modifier;
+  key_event->translated[0] = *translated;
+  key_event->translated[1] = *no_lock;
+
+  return event;
 }
 
 static void
@@ -378,16 +330,16 @@ test_trigger_trigger (void)
       translated.consumed = 0;
       translated.layout = keys[0].group;
       translated.level = keys[0].level;
-      event = gdk_event_key_new (GDK_KEY_PRESS,
-                                 surface,
-                                 device,
-                                 device,
-                                 GDK_CURRENT_TIME,
-                                 keys[0].keycode,
-                                 tests[i].state,
-                                 FALSE,
-                                 &translated,
-                                 &translated);
+      event = key_event_new (GDK_KEY_PRESS,
+                             surface,
+                             device,
+                             device,
+                             GDK_CURRENT_TIME,
+                             keys[0].keycode,
+                             tests[i].state,
+                             FALSE,
+                             &translated,
+                             &translated);
       for (j = 0; j < 4; j++)
         {
           g_assert_cmpint (gtk_shortcut_trigger_trigger (trigger[j], event, tests[i].mnemonic), ==, 
tests[i].result[j]);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]