From 886ea15c5226ae41655dbd5fd693c20338ba7dbe Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 20 May 2015 15:29:50 -0400 Subject: [PATCH] gl: win32: use a GMainContext to dispatch win32 messages 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 | 6 +- gst-libs/gst/gl/win32/gstglwindow_win32.c | 124 +++++++++++-------- gst-libs/gst/gl/win32/gstglwindow_win32.h | 4 + gst-libs/gst/gl/win32/win32_message_source.c | 83 +++++++++++++ gst-libs/gst/gl/win32/win32_message_source.h | 34 +++++ 5 files changed, 197 insertions(+), 54 deletions(-) create mode 100644 gst-libs/gst/gl/win32/win32_message_source.c create mode 100644 gst-libs/gst/gl/win32/win32_message_source.h diff --git a/gst-libs/gst/gl/win32/Makefile.am b/gst-libs/gst/gl/win32/Makefile.am index aaea0d7b39..80da958a50 100644 --- a/gst-libs/gst/gl/win32/Makefile.am +++ b/gst-libs/gst/gl/win32/Makefile.am @@ -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 diff --git a/gst-libs/gst/gl/win32/gstglwindow_win32.c b/gst-libs/gst/gl/win32/gstglwindow_win32.c index 4191b0766e..6ee70d04ca 100644 --- a/gst-libs/gst/gl/win32/gstglwindow_win32.c +++ b/gst-libs/gst/gl/win32/gstglwindow_win32.c @@ -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: diff --git a/gst-libs/gst/gl/win32/gstglwindow_win32.h b/gst-libs/gst/gl/win32/gstglwindow_win32.h index c4416e1974..76e1d93701 100644 --- a/gst-libs/gst/gl/win32/gstglwindow_win32.h +++ b/gst-libs/gst/gl/win32/gstglwindow_win32.h @@ -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 index 0000000000..fd785f8278 --- /dev/null +++ b/gst-libs/gst/gl/win32/win32_message_source.c @@ -0,0 +1,83 @@ +/* + * GStreamer + * Copyright (C) 2012 Matthew Waters + * 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 +#include + +#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 index 0000000000..eef3eac4d4 --- /dev/null +++ b/gst-libs/gst/gl/win32/win32_message_source.h @@ -0,0 +1,34 @@ +/* + * GStreamer + * Copyright (C) 2012 Matthew Waters + * 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 +#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__ */