Use the right types for the GdkSurface::event arguments
authorEmmanuele Bassi <ebassi@gnome.org>
Tue, 19 May 2020 11:18:24 +0000 (12:18 +0100)
committerEmmanuele Bassi <ebassi@gnome.org>
Tue, 19 May 2020 11:21:22 +0000 (12:21 +0100)
We pass the GdkEvent as a pointer, because the autogenerated marshallers
don't know how to handle GTypeInstance-derived classes.

Since the GValue box that we use in the marshaller passes the GdkEvent
instance as is, we also need to acquire a reference before invoking the
closure, and release it afterwards, to ensure that the GdkEvent instance
survices the invocation.

gdk/gdksurface.c

index 31fcf9659f8e95fc4e57a22bf53b1ea5680c7fe9..5fcb20de9a1cb609a341e3891f189efa108f2aaa 100644 (file)
@@ -380,6 +380,64 @@ gdk_surface_layout_popup_helper (GdkSurface     *surface,
   *out_final_rect = final_rect;
 }
 
+/* Since GdkEvent is a GTypeInstance, GValue can only store it as a pointer,
+ * and GClosure does not know how to handle its memory management. To avoid
+ * the event going away in the middle of the signal emission, we provide a
+ * marshaller that keeps the event alive for the duration of the closure.
+ */
+static void
+gdk_surface_event_marshaller (GClosure     *closure,
+                              GValue       *return_value,
+                              guint         n_param_values,
+                              const GValue *param_values,
+                              gpointer      invocation_hint,
+                              gpointer      marshal_data)
+{
+  GdkEvent *event = g_value_get_pointer (&param_values[1]);
+
+  gdk_event_ref (event);
+
+  _gdk_marshal_BOOLEAN__POINTER (closure,
+                                 return_value,
+                                 n_param_values,
+                                 param_values,
+                                 invocation_hint,
+                                 marshal_data);
+
+
+  gdk_event_unref (event);
+}
+
+static void
+gdk_surface_event_marshallerv (GClosure *closure,
+                               GValue   *return_value,
+                               gpointer  instance,
+                               va_list   args,
+                               gpointer  marshal_data,
+                               int       n_params,
+                               GType    *param_types)
+{
+  va_list args_copy;
+  GdkEvent *event;
+
+  G_VA_COPY (args_copy, args);
+  event = va_arg (args_copy, gpointer);
+
+  gdk_event_ref (event);
+
+  _gdk_marshal_BOOLEAN__POINTERv (closure,
+                                  return_value,
+                                  instance,
+                                  args,
+                                  marshal_data,
+                                  n_params,
+                                  param_types);
+
+  gdk_event_unref (event);
+
+  va_end (args_copy);
+}
+
 static void
 gdk_surface_init (GdkSurface *surface)
 {
@@ -533,13 +591,13 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
                   0,
                   g_signal_accumulator_true_handled,
                   NULL,
-                  _gdk_marshal_BOOLEAN__POINTER,
+                  gdk_surface_event_marshaller,
                   G_TYPE_BOOLEAN,
                   1,
-                  GDK_TYPE_EVENT);
+                  G_TYPE_POINTER);
   g_signal_set_va_marshaller (signals[EVENT],
                               G_OBJECT_CLASS_TYPE (object_class),
-                              _gdk_marshal_BOOLEAN__POINTERv);
+                              gdk_surface_event_marshallerv);
 
   /**
    * GdkSurface::enter-montor: