gl: win32: use a GMainContext to dispatch win32 messages
authorXavier Claessens <xavier.claessens@collabora.com>
Wed, 20 May 2015 19:29:50 +0000 (15:29 -0400)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:32:02 +0000 (19:32 +0000)
gst_gl_window_win32_send_message_async() could be called before the
internal window is created so we cannot use PostMessage there.

x11 and wayland backends both create a custom GSource for this,
so there is no reason to not do that for win32.

https://bugzilla.gnome.org/show_bug.cgi?id=749601

gst-libs/gst/gl/win32/Makefile.am
gst-libs/gst/gl/win32/gstglwindow_win32.c
gst-libs/gst/gl/win32/gstglwindow_win32.h
gst-libs/gst/gl/win32/win32_message_source.c [new file with mode: 0644]
gst-libs/gst/gl/win32/win32_message_source.h [new file with mode: 0644]

index aaea0d7..80da958 100644 (file)
@@ -3,10 +3,12 @@
 noinst_LTLIBRARIES = libgstgl-win32.la
 
 libgstgl_win32_la_SOURCES = \
-       gstglwindow_win32.c
+       gstglwindow_win32.c \
+       win32_message_source.c
 
 noinst_HEADERS = \
-       gstglwindow_win32.h
+       gstglwindow_win32.h \
+       win32_message_source.h
 
 if USE_WGL
 libgstgl_win32_la_SOURCES += gstglcontext_wgl.c
index 4191b07..6ee70d0 100644 (file)
@@ -24,9 +24,9 @@
 #endif
 
 #include "gstglwindow_win32.h"
+#include "win32_message_source.h"
 
-#define WM_GST_GL_WINDOW_CUSTOM (WM_APP+1)
-#define WM_GST_GL_WINDOW_QUIT (WM_APP+2)
+#define WM_GST_GL_WINDOW_QUIT (WM_APP+1)
 
 LRESULT CALLBACK window_proc (HWND hWnd, UINT uMsg, WPARAM wParam,
     LPARAM lParam);
@@ -69,14 +69,36 @@ static void gst_gl_window_win32_run (GstGLWindow * window);
 static void gst_gl_window_win32_quit (GstGLWindow * window);
 static void gst_gl_window_win32_send_message_async (GstGLWindow * window,
     GstGLWindowCB callback, gpointer data, GDestroyNotify destroy);
+gboolean gst_gl_window_win32_open (GstGLWindow * window, GError ** error);
+void gst_gl_window_win32_close (GstGLWindow * window);
+
+static void
+gst_gl_window_win32_finalize (GObject * object)
+{
+  GstGLWindowWin32 *window_win32 = GST_GL_WINDOW_WIN32 (object);
+
+  if (window_win32->loop) {
+    g_main_loop_unref (window_win32->loop);
+    window_win32->loop = NULL;
+  }
+  if (window_win32->main_context) {
+    g_main_context_unref (window_win32->main_context);
+    window_win32->main_context = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
 
 static void
 gst_gl_window_win32_class_init (GstGLWindowWin32Class * klass)
 {
+  GObjectClass *obj_class = G_OBJECT_CLASS (klass);
   GstGLWindowClass *window_class = (GstGLWindowClass *) klass;
 
   g_type_class_add_private (klass, sizeof (GstGLWindowWin32Private));
 
+  obj_class->finalize = gst_gl_window_win32_finalize;
+
   window_class->set_window_handle =
       GST_DEBUG_FUNCPTR (gst_gl_window_win32_set_window_handle);
   window_class->draw_unlocked = GST_DEBUG_FUNCPTR (gst_gl_window_win32_draw);
@@ -90,6 +112,8 @@ gst_gl_window_win32_class_init (GstGLWindowWin32Class * klass)
   window_class->set_preferred_size =
       GST_DEBUG_FUNCPTR (gst_gl_window_win32_set_preferred_size);
   window_class->show = GST_DEBUG_FUNCPTR (gst_gl_window_win32_show);
+  window_class->open = GST_DEBUG_FUNCPTR (gst_gl_window_win32_open);
+  window_class->close = GST_DEBUG_FUNCPTR (gst_gl_window_win32_close);
 }
 
 static void
@@ -97,6 +121,9 @@ gst_gl_window_win32_init (GstGLWindowWin32 * window)
 {
   window->priv = GST_GL_WINDOW_WIN32_GET_PRIVATE (window);
   window->priv->thread = NULL;
+
+  window->main_context = g_main_context_new ();
+  window->loop = g_main_loop_new (window->main_context, FALSE);
 }
 
 /* Must be called in the gl thread */
@@ -108,6 +135,37 @@ gst_gl_window_win32_new (void)
   return window;
 }
 
+static void
+msg_cb (GstGLWindowWin32 * window_win32, MSG * msg, gpointer user_data)
+{
+  GST_TRACE ("handle message");
+  TranslateMessage (msg);
+  DispatchMessage (msg);
+}
+
+gboolean
+gst_gl_window_win32_open (GstGLWindow * window, GError ** error)
+{
+  GstGLWindowWin32 *window_win32 = GST_GL_WINDOW_WIN32 (window);
+
+  window_win32->msg_source = win32_message_source_new (window_win32);
+  g_source_set_callback (window_win32->msg_source, (GSourceFunc) msg_cb,
+      NULL, NULL);
+  g_source_attach (window_win32->msg_source, window_win32->main_context);
+
+  return TRUE;
+}
+
+void
+gst_gl_window_win32_close (GstGLWindow * window)
+{
+  GstGLWindowWin32 *window_win32 = GST_GL_WINDOW_WIN32 (window);
+
+  g_source_destroy (window_win32->msg_source);
+  g_source_unref (window_win32->msg_source);
+  window_win32->msg_source = NULL;
+}
+
 gboolean
 gst_gl_window_win32_create_window (GstGLWindowWin32 * window_win32,
     GError ** error)
@@ -316,29 +374,8 @@ static void
 gst_gl_window_win32_run (GstGLWindow * window)
 {
   GstGLWindowWin32 *window_win32 = GST_GL_WINDOW_WIN32 (window);
-  gint bRet;
-  MSG msg;
-
-  GST_INFO ("begin message loop");
-
-  window_win32->priv->thread = g_thread_self ();
-
-  while (TRUE) {
-    bRet = GetMessage (&msg, NULL, 0, 0);
-    if (bRet == 0)
-      break;
-    else if (bRet == -1) {
-      GST_WARNING ("Failed to get message 0x%x",
-          (unsigned int) GetLastError ());
-      break;
-    } else {
-      GST_TRACE ("handle message");
-      TranslateMessage (&msg);
-      DispatchMessage (&msg);
-    }
-  }
 
-  GST_INFO ("end message loop");
+  g_main_loop_run (window_win32->loop);
 }
 
 /* Thread safe */
@@ -389,29 +426,14 @@ gst_gl_window_win32_send_message_async (GstGLWindow * window,
   GstGLMessage *message;
 
   window_win32 = GST_GL_WINDOW_WIN32 (window);
-
-  if (window_win32->priv->thread == g_thread_self ()) {
-    /* re-entracy... */
-    if (callback)
-      callback (data);
-    if (destroy)
-      destroy (data);
-    return;
-  }
-
   message = g_slice_new (GstGLMessage);
 
-  if (window_win32) {
-    LRESULT res;
-
-    message->callback = callback;
-    message->data = data;
-    message->destroy = destroy;
+  message->callback = callback;
+  message->data = data;
+  message->destroy = destroy;
 
-    res = PostMessage (window_win32->internal_win_id, WM_GST_GL_WINDOW_CUSTOM,
-        (WPARAM) message, (LPARAM) NULL);
-    g_return_if_fail (SUCCEEDED (res));
-  }
+  g_main_context_invoke (window_win32->main_context, (GSourceFunc) _run_message,
+      message);
 }
 
 /* PRIVATE */
@@ -506,6 +528,12 @@ window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
         PostQuitMessage (0);
         break;
       }
+      case WM_QUIT:
+      {
+        if (window_win32->loop)
+          g_main_loop_quit (window_win32->loop);
+        break;
+      }
       case WM_CAPTURECHANGED:
       {
         GST_DEBUG ("WM_CAPTURECHANGED");
@@ -513,14 +541,6 @@ window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
           window->draw (window->draw_data);
         break;
       }
-      case WM_GST_GL_WINDOW_CUSTOM:
-      {
-        if (!window_win32->is_closed) {
-          GstGLMessage *message = (GstGLMessage *) wParam;
-          _run_message (message);
-        }
-        break;
-      }
       case WM_ERASEBKGND:
         return TRUE;
       default:
index c4416e1..76e1d93 100644 (file)
@@ -50,6 +50,10 @@ struct _GstGLWindowWin32 {
   gboolean is_closed;
   gboolean visible;
 
+  GSource *msg_source;
+  GMainContext *main_context;
+  GMainLoop *loop;
+
   /*< private >*/
   GstGLWindowWin32Private *priv;
 
diff --git a/gst-libs/gst/gl/win32/win32_message_source.c b/gst-libs/gst/gl/win32/win32_message_source.c
new file mode 100644 (file)
index 0000000..fd785f8
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
+ * Copyright (C) 2015 Collabora ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "win32_message_source.h"
+
+typedef struct _Win32MessageSource
+{
+  GSource source;
+  GPollFD pfd;
+  GstGLWindowWin32 *window;
+} Win32MessageSource;
+
+static gboolean
+win32_message_source_check (GSource * base)
+{
+  MSG msg;
+
+  return PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
+}
+
+static gboolean
+win32_message_source_dispatch (GSource * base, GSourceFunc callback,
+    gpointer user_data)
+{
+  Win32MessageSource *source = (Win32MessageSource *) base;
+  Win32MessageSourceFunc func = (Win32MessageSourceFunc) callback;
+  MSG msg;
+
+  if (!PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
+    return G_SOURCE_CONTINUE;
+
+  if (func)
+    func (source->window, &msg, user_data);
+
+  return G_SOURCE_CONTINUE;
+}
+
+static GSourceFuncs win32_message_source_funcs = {
+  NULL,
+  win32_message_source_check,
+  win32_message_source_dispatch,
+  NULL
+};
+
+GSource *
+win32_message_source_new (GstGLWindowWin32 * window_win32)
+{
+  Win32MessageSource *source;
+
+  source = (Win32MessageSource *)
+      g_source_new (&win32_message_source_funcs, sizeof (Win32MessageSource));
+  source->window = window_win32;
+  source->pfd.fd = G_WIN32_MSG_HANDLE;
+  source->pfd.events = G_IO_IN;
+  g_source_add_poll (&source->source, &source->pfd);
+
+  return &source->source;
+}
diff --git a/gst-libs/gst/gl/win32/win32_message_source.h b/gst-libs/gst/gl/win32/win32_message_source.h
new file mode 100644 (file)
index 0000000..eef3eac
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
+ * Copyright (C) 2015 Collabora ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __WIN32_MESSAGE_SOURCE_H__
+#define __WIN32_MESSAGE_SOURCE_H__
+
+#include <glib-object.h>
+#include "gstglwindow_win32.h"
+
+typedef void (*Win32MessageSourceFunc) (GstGLWindowWin32 *window_win32,
+    MSG *msg, gpointer user_data);
+
+GSource *
+win32_message_source_new (GstGLWindowWin32 *window_win32);
+
+#endif /* __WIN32_MESSAGE_SOURCE_H__ */