From 6292d5af16cfe321b688a1ac3b2982802aa55321 Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Sat, 6 Jun 2009 14:34:57 +0200 Subject: [PATCH] [349/906] can switch xoverlays while playing Fixes bug #584877 Before this commit calling "gst_x_overlay_set_xwindow_id" more than one time, had no effect. It mainly affects the glimagesink implementation. But on win32 (and CE), some stuff has to be done to release the old parent. And add a switchxoverlay example where the user can click on left/right part of the main window to switch the xoverlay. --- gst-libs/gst/gl/gstglwindow_win32.c | 66 +++++++++++++++++++++-------- gst-libs/gst/gl/gstglwindow_winCE.c | 66 +++++++++++++++++++++-------- gst/gl/gstglimagesink.c | 26 ++++++------ gst/gl/gstglimagesink.h | 1 + 4 files changed, 111 insertions(+), 48 deletions(-) diff --git a/gst-libs/gst/gl/gstglwindow_win32.c b/gst-libs/gst/gl/gstglwindow_win32.c index 879bc80ce7..04b9f2c98f 100644 --- a/gst-libs/gst/gl/gstglwindow_win32.c +++ b/gst-libs/gst/gl/gstglwindow_win32.c @@ -197,26 +197,58 @@ void gst_gl_window_set_external_window_id (GstGLWindow * window, gulong id) { GstGLWindowPrivate *priv = window->priv; - WNDPROC window_parent_proc = - (WNDPROC) GetWindowLongPtr ((HWND) id, GWL_WNDPROC); - RECT rect; - SetProp (priv->internal_win_id, "gl_window_parent_id", (HWND) id); - SetProp ((HWND) id, "gl_window_id", priv->internal_win_id); - SetProp ((HWND) id, "gl_window_parent_proc", (WNDPROC) window_parent_proc); - SetWindowLongPtr ((HWND) id, GWL_WNDPROC, (LONG_PTR) sub_class_proc); + //retrieve parent if previously set + HWND parent_id = GetProp (priv->internal_win_id, "gl_window_parent_id"); - SetWindowLongPtr (priv->internal_win_id, GWL_STYLE, WS_CHILD | WS_MAXIMIZE); - SetParent (priv->internal_win_id, (HWND) id); + if (priv->visible) { + ShowWindow (priv->internal_win_id, SW_HIDE); + priv->visible = FALSE; + } + + if (parent_id) { + WNDPROC parent_proc = GetProp (parent_id, "gl_window_parent_proc"); - //take changes into account: SWP_FRAMECHANGED - GetClientRect ((HWND) id, &rect); - SetWindowPos (priv->internal_win_id, HWND_TOP, rect.left, rect.top, - rect.right, rect.bottom, - SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | - SWP_FRAMECHANGED | SWP_NOACTIVATE); - MoveWindow (priv->internal_win_id, rect.left, rect.top, rect.right, - rect.bottom, FALSE); + g_debug ("release parent %lud\n", (gulong) parent_id); + + g_assert (parent_proc); + + SetWindowLongPtr (parent_id, GWL_WNDPROC, (LONG) parent_proc); + SetParent (priv->internal_win_id, NULL); + + RemoveProp (parent_id, "gl_window_parent_proc"); + RemoveProp (priv->internal_win_id, "gl_window_parent_id"); + } + + //not 0 + if (id) { + WNDPROC window_parent_proc = + (WNDPROC) GetWindowLongPtr ((HWND) id, GWL_WNDPROC); + RECT rect; + + g_debug ("set parent %lud\n", (gulong) id); + + SetProp (priv->internal_win_id, "gl_window_parent_id", (HWND) id); + SetProp ((HWND) id, "gl_window_id", priv->internal_win_id); + SetProp ((HWND) id, "gl_window_parent_proc", (WNDPROC) window_parent_proc); + SetWindowLongPtr ((HWND) id, GWL_WNDPROC, (LONG_PTR) sub_class_proc); + + SetWindowLongPtr (priv->internal_win_id, GWL_STYLE, WS_CHILD | WS_MAXIMIZE); + SetParent (priv->internal_win_id, (HWND) id); + + //take changes into account: SWP_FRAMECHANGED + GetClientRect ((HWND) id, &rect); + SetWindowPos (priv->internal_win_id, HWND_TOP, rect.left, rect.top, + rect.right, rect.bottom, + SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | + SWP_FRAMECHANGED | SWP_NOACTIVATE); + MoveWindow (priv->internal_win_id, rect.left, rect.top, rect.right, + rect.bottom, FALSE); + } else { + //no parent so the internal window needs borders and system menu + SetWindowLongPtr (priv->internal_win_id, GWL_STYLE, + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW); + } } /* Must be called in the gl thread */ diff --git a/gst-libs/gst/gl/gstglwindow_winCE.c b/gst-libs/gst/gl/gstglwindow_winCE.c index da0c117d2b..546af06e2f 100644 --- a/gst-libs/gst/gl/gstglwindow_winCE.c +++ b/gst-libs/gst/gl/gstglwindow_winCE.c @@ -204,26 +204,58 @@ void gst_gl_window_set_external_window_id (GstGLWindow * window, gulong id) { GstGLWindowPrivate *priv = window->priv; - WNDPROC window_parent_proc = - (WNDPROC) (guint64) GetWindowLongPtr ((HWND) id, GWL_WNDPROC); - RECT rect; - SetProp (priv->internal_win_id, "gl_window_parent_id", (HWND) id); - SetProp ((HWND) id, "gl_window_id", priv->internal_win_id); - SetProp ((HWND) id, "gl_window_parent_proc", (WNDPROC) window_parent_proc); - SetWindowLongPtr ((HWND) id, GWL_WNDPROC, (DWORD) (guint64) sub_class_proc); + //retrieve parent if previously set + HWND parent_id = GetProp (priv->internal_win_id, "gl_window_parent_id"); - SetWindowLongPtr (priv->internal_win_id, GWL_STYLE, WS_CHILD | WS_MAXIMIZE); - SetParent (priv->internal_win_id, (HWND) id); + if (priv->visible) { + ShowWindow (priv->internal_win_id, SW_HIDE); + priv->visible = FALSE; + } + + if (parent_id) { + WNDPROC parent_proc = GetProp (parent_id, "gl_window_parent_proc"); - //take changes into account: SWP_FRAMECHANGED - GetClientRect ((HWND) id, &rect); - SetWindowPos (priv->internal_win_id, HWND_TOP, rect.left, rect.top, - rect.right, rect.bottom, - SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | - SWP_FRAMECHANGED | SWP_NOACTIVATE); - MoveWindow (priv->internal_win_id, rect.left, rect.top, rect.right, - rect.bottom, FALSE); + g_debug ("release parent %lud\n", (gulong) parent_id); + + g_assert (parent_proc); + + SetWindowLongPtr (parent_id, GWL_WNDPROC, (LONG) parent_proc); + SetParent (priv->internal_win_id, NULL); + + RemoveProp (parent_id, "gl_window_parent_proc"); + RemoveProp (priv->internal_win_id, "gl_window_parent_id"); + } + + //not 0 + if (id) { + WNDPROC window_parent_proc = + (WNDPROC) GetWindowLongPtr ((HWND) id, GWL_WNDPROC); + RECT rect; + + g_debug ("set parent %lud\n", (gulong) id); + + SetProp (priv->internal_win_id, "gl_window_parent_id", (HWND) id); + SetProp ((HWND) id, "gl_window_id", priv->internal_win_id); + SetProp ((HWND) id, "gl_window_parent_proc", (WNDPROC) window_parent_proc); + SetWindowLongPtr ((HWND) id, GWL_WNDPROC, (LONG_PTR) sub_class_proc); + + SetWindowLongPtr (priv->internal_win_id, GWL_STYLE, WS_CHILD | WS_MAXIMIZE); + SetParent (priv->internal_win_id, (HWND) id); + + //take changes into account: SWP_FRAMECHANGED + GetClientRect ((HWND) id, &rect); + SetWindowPos (priv->internal_win_id, HWND_TOP, rect.left, rect.top, + rect.right, rect.bottom, + SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | + SWP_FRAMECHANGED | SWP_NOACTIVATE); + MoveWindow (priv->internal_win_id, rect.left, rect.top, rect.right, + rect.bottom, FALSE); + } else { + //no parent so the internal window needs borders and system menu + SetWindowLongPtr (priv->internal_win_id, GWL_STYLE, + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW); + } } /* Must be called in the gl thread */ diff --git a/gst/gl/gstglimagesink.c b/gst/gl/gstglimagesink.c index 1bdaa229cf..d73f90936f 100644 --- a/gst/gl/gstglimagesink.c +++ b/gst/gl/gstglimagesink.c @@ -251,6 +251,7 @@ gst_glimage_sink_init (GstGLImageSink * glimage_sink, { glimage_sink->display_name = NULL; glimage_sink->window_id = 0; + glimage_sink->new_window_id = 0; glimage_sink->display = NULL; glimage_sink->stored_buffer = NULL; glimage_sink->clientReshapeCallback = NULL; @@ -416,6 +417,9 @@ gst_glimage_sink_stop (GstBaseSink * bsink) glimage_sink->display = NULL; } + glimage_sink->window_id = 0; + //but do not reset glimage_sink->new_window_id + return TRUE; } @@ -485,7 +489,7 @@ gst_glimage_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) glimage_sink->par_n = par_n; glimage_sink->par_d = par_d; - if (!glimage_sink->window_id) + if (!glimage_sink->window_id && !glimage_sink->new_window_id) gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (glimage_sink)); return TRUE; @@ -510,10 +514,6 @@ gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf) if (glimage_sink->display == NULL) { glimage_sink->display = g_object_ref (gl_buffer->display); - if (glimage_sink->window_id) - gst_gl_display_set_window_id (glimage_sink->display, - glimage_sink->window_id); - gst_gl_display_set_client_reshape_callback (glimage_sink->display, glimage_sink->clientReshapeCallback); @@ -532,10 +532,6 @@ gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf) gst_gl_display_create_context (glimage_sink->display, glimage_sink->width, glimage_sink->height, 0); - if (glimage_sink->window_id) - gst_gl_display_set_window_id (glimage_sink->display, - glimage_sink->window_id); - //init colorspace conversion if needed gst_gl_display_init_upload (glimage_sink->display, glimage_sink->format, glimage_sink->width, glimage_sink->height, @@ -558,6 +554,12 @@ gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf) //gl_buffer is created in this block, so the gl buffer is already referenced } + if (glimage_sink->window_id != glimage_sink->new_window_id) { + glimage_sink->window_id = glimage_sink->new_window_id; + gst_gl_display_set_window_id (glimage_sink->display, + glimage_sink->window_id); + } + //the buffer is cleared when an other comes in if (glimage_sink->stored_buffer) { gst_buffer_unref (GST_BUFFER_CAST (glimage_sink->stored_buffer)); @@ -594,11 +596,7 @@ gst_glimage_sink_set_xwindow_id (GstXOverlay * overlay, gulong window_id) GST_DEBUG ("set_xwindow_id %ld", window_id); - if (glimage_sink->window_id == window_id) - return; - - if (window_id) - glimage_sink->window_id = window_id; + glimage_sink->new_window_id = window_id; } diff --git a/gst/gl/gstglimagesink.h b/gst/gl/gstglimagesink.h index 386181d0be..df32788174 100644 --- a/gst/gl/gstglimagesink.h +++ b/gst/gl/gstglimagesink.h @@ -53,6 +53,7 @@ struct _GstGLImageSink gchar *display_name; gulong window_id; + gulong new_window_id; //caps GstCaps *caps;