glwindow/win32: Fix possible deadlock around key/mouse event handling
authorSeungha Yang <seungha@centricular.com>
Thu, 2 Jul 2020 13:33:44 +0000 (22:33 +0900)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Wed, 8 Jul 2020 13:41:07 +0000 (13:41 +0000)
Calling gst_gl_window_send_{key,mouse}_event() from GstGLContext
thread might cause a deadlock. Instead, use the dedicated event handling
thread in GstGLDisplay.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/721>

gst-libs/gst/gl/win32/gstglwindow_win32.c

index ab472218ceef41520a8b7da9bffd19de7f9e56ed..29849d4691633a2c59d3ab58afacbdbb91762856 100644 (file)
@@ -407,27 +407,74 @@ gst_gl_window_win32_draw (GstGLWindow * window)
       RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE);
 }
 
+typedef struct
+{
+  GstGLWindow *window;
+  const gchar *event_type;
+  gchar *key_string;
+} GstGLWindowWin32KeyEvent;
+
+static gboolean
+gst_gl_window_win32_handle_key_event_func (GstGLWindowWin32KeyEvent * event)
+{
+  gst_gl_window_send_key_event (event->window,
+      event->event_type, event->key_string);
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+gst_gl_window_win32_key_event_free (GstGLWindowWin32KeyEvent * event)
+{
+  g_free (event->key_string);
+  g_free (event);
+}
+
 static void
 gst_gl_window_win32_handle_key_event (GstGLWindow * window, UINT uMsg,
     LPARAM lParam)
 {
   gunichar2 wcrep[128];
-  const gchar *event;
 
   if (GetKeyNameTextW (lParam, (LPWSTR) wcrep, 128)) {
     gchar *utfrep = g_utf16_to_utf8 (wcrep, 128, NULL, NULL, NULL);
     if (utfrep) {
+      GstGLDisplay *display = window->display;
+      GstGLWindowWin32KeyEvent *key_event;
+
+      key_event = g_new0 (GstGLWindowWin32KeyEvent, 1);
+      key_event->window = window;
       if (uMsg == WM_KEYDOWN)
-        event = "key-press";
+        key_event->event_type = "key-press";
       else
-        event = "key-release";
+        key_event->event_type = "key-release";
+      key_event->key_string = utfrep;
 
-      gst_gl_window_send_key_event (window, event, utfrep);
-      g_free (utfrep);
+      g_main_context_invoke_full (display->main_context, G_PRIORITY_DEFAULT,
+          (GSourceFunc) gst_gl_window_win32_handle_key_event_func,
+          key_event, (GDestroyNotify) gst_gl_window_win32_key_event_free);
     }
   }
 }
 
+typedef struct
+{
+  GstGLWindow *window;
+  const gchar *event_type;
+  gint button;
+  gdouble pos_x;
+  gdouble pos_y;
+} GstGLWindowWin32MouseEvent;
+
+static gboolean
+gst_gl_window_win32_handle_mouse_event_func (GstGLWindowWin32MouseEvent * event)
+{
+  gst_gl_window_send_mouse_event (event->window,
+      event->event_type, event->button, event->pos_x, event->pos_y);
+
+  return G_SOURCE_REMOVE;
+}
+
 static void
 gst_gl_window_win32_handle_mouse_event (GstGLWindow * window, UINT uMsg,
     LPARAM lParam)
@@ -468,9 +515,21 @@ gst_gl_window_win32_handle_mouse_event (GstGLWindow * window, UINT uMsg,
       break;
   }
 
-  if (event)
-    gst_gl_window_send_mouse_event (window, event, button,
-        (double) LOWORD (lParam), (double) HIWORD (lParam));
+  if (event) {
+    GstGLDisplay *display = window->display;
+    GstGLWindowWin32MouseEvent *mouse_event;
+
+    mouse_event = g_new0 (GstGLWindowWin32MouseEvent, 1);
+    mouse_event->window = window;
+    mouse_event->event_type = event;
+    mouse_event->button = button;
+    mouse_event->pos_x = (gdouble) LOWORD (lParam);
+    mouse_event->pos_y = (gdouble) HIWORD (lParam);
+
+    g_main_context_invoke_full (display->main_context, G_PRIORITY_DEFAULT,
+        (GSourceFunc) gst_gl_window_win32_handle_mouse_event_func,
+        mouse_event, (GDestroyNotify) g_free);
+  }
 }
 
 /* PRIVATE */