• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
4  * Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "gstglwindow_win32.h"
27 
28 LRESULT CALLBACK window_proc (HWND hWnd, UINT uMsg, WPARAM wParam,
29     LPARAM lParam);
30 LRESULT FAR PASCAL sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam,
31     LPARAM lParam);
32 
33 enum
34 {
35   PROP_0
36 };
37 
38 struct _GstGLWindowWin32Private
39 {
40   gint preferred_width;
41   gint preferred_height;
42   GIOChannel *msg_io_channel;
43 };
44 
45 #define GST_CAT_DEFAULT gst_gl_window_win32_debug
46 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
47 
48 #define DEBUG_INIT \
49   GST_DEBUG_CATEGORY_GET (GST_CAT_DEFAULT, "glwindow");
50 #define gst_gl_window_win32_parent_class parent_class
51 G_DEFINE_TYPE_WITH_CODE (GstGLWindowWin32, gst_gl_window_win32,
52     GST_TYPE_GL_WINDOW, G_ADD_PRIVATE (GstGLWindowWin32) DEBUG_INIT);
53 
54 static void gst_gl_window_win32_set_window_handle (GstGLWindow * window,
55     guintptr handle);
56 static guintptr gst_gl_window_win32_get_display (GstGLWindow * window);
57 static guintptr gst_gl_window_win32_get_window_handle (GstGLWindow * window);
58 static void gst_gl_window_win32_set_preferred_size (GstGLWindow * window,
59     gint width, gint height);
60 static void gst_gl_window_win32_show (GstGLWindow * window);
61 static void gst_gl_window_win32_draw (GstGLWindow * window);
62 gboolean gst_gl_window_win32_open (GstGLWindow * window, GError ** error);
63 void gst_gl_window_win32_close (GstGLWindow * window);
64 static void release_parent_win_id (GstGLWindowWin32 * window_win32);
65 static void gst_gl_window_win32_send_message (GstGLWindow * window,
66     GstGLWindowCB callback, gpointer data);
67 
68 static void
gst_gl_window_win32_class_init(GstGLWindowWin32Class * klass)69 gst_gl_window_win32_class_init (GstGLWindowWin32Class * klass)
70 {
71   GstGLWindowClass *window_class = (GstGLWindowClass *) klass;
72 
73   window_class->set_window_handle =
74       GST_DEBUG_FUNCPTR (gst_gl_window_win32_set_window_handle);
75   window_class->draw = GST_DEBUG_FUNCPTR (gst_gl_window_win32_draw);
76   window_class->get_display =
77       GST_DEBUG_FUNCPTR (gst_gl_window_win32_get_display);
78   window_class->get_window_handle =
79       GST_DEBUG_FUNCPTR (gst_gl_window_win32_get_window_handle);
80   window_class->set_preferred_size =
81       GST_DEBUG_FUNCPTR (gst_gl_window_win32_set_preferred_size);
82   window_class->show = GST_DEBUG_FUNCPTR (gst_gl_window_win32_show);
83   window_class->open = GST_DEBUG_FUNCPTR (gst_gl_window_win32_open);
84   window_class->close = GST_DEBUG_FUNCPTR (gst_gl_window_win32_close);
85   window_class->send_message =
86       GST_DEBUG_FUNCPTR (gst_gl_window_win32_send_message);
87 }
88 
89 static void
gst_gl_window_win32_init(GstGLWindowWin32 * window)90 gst_gl_window_win32_init (GstGLWindowWin32 * window)
91 {
92   window->priv = gst_gl_window_win32_get_instance_private (window);
93 }
94 
95 GstGLWindowWin32 *
gst_gl_window_win32_new(GstGLDisplay * display)96 gst_gl_window_win32_new (GstGLDisplay * display)
97 {
98   GstGLWindowWin32 *window;
99 
100   if ((gst_gl_display_get_handle_type (display) &
101           (GST_GL_DISPLAY_TYPE_WIN32 | GST_GL_DISPLAY_TYPE_EGL)) == 0)
102     /* we require an win32 display to create win32 windows */
103     return NULL;
104 
105   window = g_object_new (GST_TYPE_GL_WINDOW_WIN32, NULL);
106   gst_object_ref_sink (window);
107 
108   return window;
109 }
110 
111 static gboolean
msg_cb(GIOChannel * source,GIOCondition condition,gpointer data)112 msg_cb (GIOChannel * source, GIOCondition condition, gpointer data)
113 {
114   MSG msg;
115 
116   if (!PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
117     return G_SOURCE_CONTINUE;
118 
119   GST_TRACE ("handle message");
120   TranslateMessage (&msg);
121   DispatchMessage (&msg);
122 
123   return G_SOURCE_CONTINUE;
124 }
125 
126 gboolean
gst_gl_window_win32_open(GstGLWindow * window,GError ** error)127 gst_gl_window_win32_open (GstGLWindow * window, GError ** error)
128 {
129   GstGLWindowWin32 *window_win32 = GST_GL_WINDOW_WIN32 (window);
130 
131   if (!GST_GL_WINDOW_CLASS (parent_class)->open (window, error))
132     return FALSE;
133 
134   window_win32->priv->msg_io_channel = g_io_channel_win32_new_messages (0);
135   window_win32->msg_source =
136       g_io_create_watch (window_win32->priv->msg_io_channel, G_IO_IN);
137   g_source_set_callback (window_win32->msg_source, (GSourceFunc) msg_cb, NULL,
138       NULL);
139   g_source_attach (window_win32->msg_source, window->main_context);
140 
141   return TRUE;
142 }
143 
144 void
gst_gl_window_win32_close(GstGLWindow * window)145 gst_gl_window_win32_close (GstGLWindow * window)
146 {
147   GstGLWindowWin32 *window_win32 = GST_GL_WINDOW_WIN32 (window);
148 
149   release_parent_win_id (window_win32);
150 
151   if (window_win32->internal_win_id) {
152     RemoveProp (window_win32->internal_win_id, "gl_window");
153     ShowWindow (window_win32->internal_win_id, SW_HIDE);
154     SetParent (window_win32->internal_win_id, NULL);
155     if (!DestroyWindow (window_win32->internal_win_id))
156       GST_WARNING ("failed to destroy window %" G_GUINTPTR_FORMAT
157           ", 0x%x", (guintptr) window_win32->internal_win_id,
158           (unsigned int) GetLastError ());
159   }
160 
161   g_source_destroy (window_win32->msg_source);
162   g_source_unref (window_win32->msg_source);
163   window_win32->msg_source = NULL;
164   g_io_channel_unref (window_win32->priv->msg_io_channel);
165   window_win32->priv->msg_io_channel = NULL;
166 
167   GST_GL_WINDOW_CLASS (parent_class)->close (window);
168 }
169 
170 static void
set_parent_win_id(GstGLWindowWin32 * window_win32)171 set_parent_win_id (GstGLWindowWin32 * window_win32)
172 {
173   WNDPROC window_parent_proc;
174   RECT rect;
175 
176   if (!window_win32->parent_win_id) {
177     /* no parent so the internal window needs borders and system menu */
178     SetWindowLongPtr (window_win32->internal_win_id, GWL_STYLE,
179         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW);
180     SetParent (window_win32->internal_win_id, NULL);
181     return;
182   }
183 
184   window_parent_proc =
185       (WNDPROC) GetWindowLongPtr (window_win32->parent_win_id, GWLP_WNDPROC);
186 
187   GST_DEBUG ("set parent %" G_GUINTPTR_FORMAT,
188       (guintptr) window_win32->parent_win_id);
189 
190   SetProp (window_win32->parent_win_id, "gl_window_id",
191       window_win32->internal_win_id);
192   SetProp (window_win32->parent_win_id, "gl_window_parent_proc",
193       (WNDPROC) window_parent_proc);
194   SetWindowLongPtr (window_win32->parent_win_id, GWLP_WNDPROC,
195       (LONG_PTR) sub_class_proc);
196 
197   SetWindowLongPtr (window_win32->internal_win_id, GWL_STYLE,
198       WS_CHILD | WS_MAXIMIZE);
199   SetParent (window_win32->internal_win_id, window_win32->parent_win_id);
200 
201   /* take changes into account: SWP_FRAMECHANGED */
202   GetClientRect (window_win32->parent_win_id, &rect);
203   SetWindowPos (window_win32->internal_win_id, HWND_TOP, rect.left, rect.top,
204       rect.right, rect.bottom,
205       SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
206       SWP_FRAMECHANGED | SWP_NOACTIVATE);
207   MoveWindow (window_win32->internal_win_id, rect.left, rect.top, rect.right,
208       rect.bottom, FALSE);
209 }
210 
211 static void
release_parent_win_id(GstGLWindowWin32 * window_win32)212 release_parent_win_id (GstGLWindowWin32 * window_win32)
213 {
214   WNDPROC parent_proc;
215 
216   if (!window_win32->parent_win_id)
217     return;
218 
219   parent_proc = GetProp (window_win32->parent_win_id, "gl_window_parent_proc");
220   if (!parent_proc)
221     return;
222 
223   GST_DEBUG ("release parent %" G_GUINTPTR_FORMAT,
224       (guintptr) window_win32->parent_win_id);
225 
226   SetWindowLongPtr (window_win32->parent_win_id, GWLP_WNDPROC,
227       (LONG_PTR) parent_proc);
228 
229   RemoveProp (window_win32->parent_win_id, "gl_window_parent_proc");
230 }
231 
232 gboolean
gst_gl_window_win32_create_window(GstGLWindowWin32 * window_win32,GError ** error)233 gst_gl_window_win32_create_window (GstGLWindowWin32 * window_win32,
234     GError ** error)
235 {
236 //  GstGLWindowWin32 *window_win32 = GST_GL_WINDOW_WIN32 (window);
237   WNDCLASSEX wc;
238   ATOM atom = 0;
239   HINSTANCE hinstance = GetModuleHandle (NULL);
240 
241   static gint x = 0;
242   static gint y = 0;
243 
244   GST_LOG ("Attempting to create a win32 window");
245 
246   x += 20;
247   y += 20;
248 
249   atom = GetClassInfoEx (hinstance, "GSTGL", &wc);
250 
251   if (atom == 0) {
252     ZeroMemory (&wc, sizeof (WNDCLASSEX));
253 
254     wc.cbSize = sizeof (WNDCLASSEX);
255     wc.lpfnWndProc = window_proc;
256     wc.cbClsExtra = 0;
257     wc.cbWndExtra = 0;
258     wc.hInstance = hinstance;
259     wc.hIcon = LoadIcon (NULL, IDI_WINLOGO);
260     wc.hIconSm = NULL;
261     wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
262     wc.hCursor = LoadCursor (NULL, IDC_ARROW);
263     wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
264     wc.lpszMenuName = NULL;
265     wc.lpszClassName = "GSTGL";
266 
267     atom = RegisterClassEx (&wc);
268 
269     if (atom == 0) {
270       g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
271           "Failed to register window class 0x%x\n",
272           (unsigned int) GetLastError ());
273       goto failure;
274     }
275   }
276 
277   window_win32->internal_win_id = 0;
278   window_win32->device = 0;
279   window_win32->visible = FALSE;
280 
281   window_win32->internal_win_id = CreateWindowEx (0,
282       "GSTGL",
283       "OpenGL renderer",
284       WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW,
285       x, y, 0, 0, (HWND) NULL, (HMENU) NULL, hinstance, window_win32);
286 
287   if (!window_win32->internal_win_id) {
288     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
289         "failed to create gl window");
290     goto failure;
291   }
292 
293   GST_DEBUG ("gl window created: %" G_GUINTPTR_FORMAT,
294       (guintptr) window_win32->internal_win_id);
295 
296   //device is set in the window_proc
297   if (!window_win32->device) {
298     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
299         "failed to create device");
300     goto failure;
301   }
302 
303   ShowCursor (TRUE);
304 
305   GST_LOG ("Created a win32 window");
306 
307   /* The window has been created as if it had no parent, so there is nothing
308    * else to do in that case. Even if user has already set a window,
309    * parent_win_id could still be 0 at this point, and in that case calling
310    * set_parent_win_id() here would steal focus from the parent window. */
311   if (window_win32->parent_win_id)
312     set_parent_win_id (window_win32);
313 
314   return TRUE;
315 
316 failure:
317   return FALSE;
318 }
319 
320 static guintptr
gst_gl_window_win32_get_display(GstGLWindow * window)321 gst_gl_window_win32_get_display (GstGLWindow * window)
322 {
323   GstGLWindowWin32 *window_win32;
324 
325   window_win32 = GST_GL_WINDOW_WIN32 (window);
326 
327   return (guintptr) window_win32->device;
328 }
329 
330 static guintptr
gst_gl_window_win32_get_window_handle(GstGLWindow * window)331 gst_gl_window_win32_get_window_handle (GstGLWindow * window)
332 {
333   GstGLWindowWin32 *window_win32;
334 
335   window_win32 = GST_GL_WINDOW_WIN32 (window);
336 
337   return (guintptr) window_win32->internal_win_id;
338 }
339 
340 static void
gst_gl_window_win32_set_window_handle(GstGLWindow * window,guintptr id)341 gst_gl_window_win32_set_window_handle (GstGLWindow * window, guintptr id)
342 {
343   GstGLWindowWin32 *window_win32;
344 
345   window_win32 = GST_GL_WINDOW_WIN32 (window);
346 
347   if (!window_win32->internal_win_id) {
348     window_win32->parent_win_id = (HWND) id;
349     return;
350   }
351 
352   if (window_win32->visible) {
353     ShowWindow (window_win32->internal_win_id, SW_HIDE);
354     window_win32->visible = FALSE;
355   }
356 
357   release_parent_win_id (window_win32);
358   window_win32->parent_win_id = (HWND) id;
359   set_parent_win_id (window_win32);
360 }
361 
362 static void
gst_gl_window_win32_show(GstGLWindow * window)363 gst_gl_window_win32_show (GstGLWindow * window)
364 {
365   GstGLWindowWin32 *window_win32 = GST_GL_WINDOW_WIN32 (window);
366   gint width = window_win32->priv->preferred_width;
367   gint height = window_win32->priv->preferred_height;
368 
369   if (!window_win32->visible) {
370     HWND parent_id = window_win32->parent_win_id;
371 
372     /* if no parent the real size has to be set now because this has not been done
373      * when at window creation */
374     if (!parent_id) {
375       RECT rect;
376       GetClientRect (window_win32->internal_win_id, &rect);
377       width += 2 * GetSystemMetrics (SM_CXSIZEFRAME);
378       height +=
379           2 * GetSystemMetrics (SM_CYSIZEFRAME) +
380           GetSystemMetrics (SM_CYCAPTION);
381       MoveWindow (window_win32->internal_win_id, rect.left, rect.top, width,
382           height, FALSE);
383     }
384 
385     ShowWindowAsync (window_win32->internal_win_id, SW_SHOW);
386     window_win32->visible = TRUE;
387   }
388 }
389 
390 static void
gst_gl_window_win32_set_preferred_size(GstGLWindow * window,gint width,gint height)391 gst_gl_window_win32_set_preferred_size (GstGLWindow * window, gint width,
392     gint height)
393 {
394   GstGLWindowWin32 *window_win32 = GST_GL_WINDOW_WIN32 (window);
395 
396   window_win32->priv->preferred_width = width;
397   window_win32->priv->preferred_height = height;
398 }
399 
400 /* Thread safe */
401 static void
gst_gl_window_win32_draw(GstGLWindow * window)402 gst_gl_window_win32_draw (GstGLWindow * window)
403 {
404   GstGLWindowWin32 *window_win32 = GST_GL_WINDOW_WIN32 (window);
405 
406   RedrawWindow (window_win32->internal_win_id, NULL, NULL,
407       RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE);
408 }
409 
410 typedef struct
411 {
412   GstGLWindow *window;
413   const gchar *event_type;
414   gchar *key_string;
415 } GstGLWindowWin32KeyEvent;
416 
417 static gboolean
gst_gl_window_win32_handle_key_event_func(GstGLWindowWin32KeyEvent * event)418 gst_gl_window_win32_handle_key_event_func (GstGLWindowWin32KeyEvent * event)
419 {
420   gst_gl_window_send_key_event (event->window,
421       event->event_type, event->key_string);
422 
423   return G_SOURCE_REMOVE;
424 }
425 
426 static void
gst_gl_window_win32_key_event_free(GstGLWindowWin32KeyEvent * event)427 gst_gl_window_win32_key_event_free (GstGLWindowWin32KeyEvent * event)
428 {
429   g_free (event->key_string);
430   g_free (event);
431 }
432 
433 static void
gst_gl_window_win32_handle_key_event(GstGLWindow * window,UINT uMsg,LPARAM lParam)434 gst_gl_window_win32_handle_key_event (GstGLWindow * window, UINT uMsg,
435     LPARAM lParam)
436 {
437   gunichar2 wcrep[128];
438 
439   if (GetKeyNameTextW (lParam, (LPWSTR) wcrep, 128)) {
440     gchar *utfrep = g_utf16_to_utf8 (wcrep, 128, NULL, NULL, NULL);
441     if (utfrep) {
442       GstGLDisplay *display = window->display;
443       GstGLWindowWin32KeyEvent *key_event;
444 
445       key_event = g_new0 (GstGLWindowWin32KeyEvent, 1);
446       key_event->window = window;
447       if (uMsg == WM_KEYDOWN)
448         key_event->event_type = "key-press";
449       else
450         key_event->event_type = "key-release";
451       key_event->key_string = utfrep;
452 
453       g_main_context_invoke_full (display->main_context, G_PRIORITY_DEFAULT,
454           (GSourceFunc) gst_gl_window_win32_handle_key_event_func,
455           key_event, (GDestroyNotify) gst_gl_window_win32_key_event_free);
456     }
457   }
458 }
459 
460 typedef struct
461 {
462   GstGLWindow *window;
463   const gchar *event_type;
464   gint button;
465   gdouble pos_x;
466   gdouble pos_y;
467 } GstGLWindowWin32MouseEvent;
468 
469 static gboolean
gst_gl_window_win32_handle_mouse_event_func(GstGLWindowWin32MouseEvent * event)470 gst_gl_window_win32_handle_mouse_event_func (GstGLWindowWin32MouseEvent * event)
471 {
472   gst_gl_window_send_mouse_event (event->window,
473       event->event_type, event->button, event->pos_x, event->pos_y);
474 
475   return G_SOURCE_REMOVE;
476 }
477 
478 static void
gst_gl_window_win32_handle_mouse_event(GstGLWindow * window,UINT uMsg,LPARAM lParam)479 gst_gl_window_win32_handle_mouse_event (GstGLWindow * window, UINT uMsg,
480     LPARAM lParam)
481 {
482   gint button;
483   const gchar *event = NULL;
484 
485   switch (uMsg) {
486     case WM_MOUSEMOVE:
487       button = 0;
488       event = "mouse-move";
489       break;
490     case WM_LBUTTONDOWN:
491       button = 1;
492       event = "mouse-button-press";
493       break;
494     case WM_LBUTTONUP:
495       button = 1;
496       event = "mouse-button-release";
497       break;
498     case WM_RBUTTONDOWN:
499       button = 2;
500       event = "mouse-button-press";
501       break;
502     case WM_RBUTTONUP:
503       button = 2;
504       event = "mouse-button-release";
505       break;
506     case WM_MBUTTONDOWN:
507       button = 3;
508       event = "mouse-button-press";
509       break;
510     case WM_MBUTTONUP:
511       button = 3;
512       event = "mouse-button-release";
513       break;
514     default:
515       break;
516   }
517 
518   if (event) {
519     GstGLDisplay *display = window->display;
520     GstGLWindowWin32MouseEvent *mouse_event;
521 
522     mouse_event = g_new0 (GstGLWindowWin32MouseEvent, 1);
523     mouse_event->window = window;
524     mouse_event->event_type = event;
525     mouse_event->button = button;
526     mouse_event->pos_x = (gdouble) LOWORD (lParam);
527     mouse_event->pos_y = (gdouble) HIWORD (lParam);
528 
529     g_main_context_invoke_full (display->main_context, G_PRIORITY_DEFAULT,
530         (GSourceFunc) gst_gl_window_win32_handle_mouse_event_func,
531         mouse_event, (GDestroyNotify) g_free);
532   }
533 }
534 
535 /* PRIVATE */
536 
537 LRESULT CALLBACK
window_proc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)538 window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
539 {
540   GstGLWindowWin32 *window_win32;
541   LRESULT ret = 0;
542 
543   if (uMsg == WM_CREATE) {
544     window_win32 =
545         GST_GL_WINDOW_WIN32 (((LPCREATESTRUCT) lParam)->lpCreateParams);
546 
547     GST_TRACE ("WM_CREATE");
548 
549     window_win32->device = GetDC (hWnd);
550     /* Do this, otherwise we hang on exit. We can still use it (due to the
551      * CS_OWNDC flag in the WindowClass) after we have Released.
552      */
553     ReleaseDC (hWnd, window_win32->device);
554 
555     SetProp (hWnd, "gl_window", window_win32);
556   } else if (GetProp (hWnd, "gl_window")) {
557     GstGLWindow *window;
558     GstGLContext *context;
559 
560     window_win32 = GST_GL_WINDOW_WIN32 (GetProp (hWnd, "gl_window"));
561     window = GST_GL_WINDOW (window_win32);
562     context = gst_gl_window_get_context (window);
563 
564     g_assert (window_win32->internal_win_id == hWnd);
565 
566     switch (uMsg) {
567       case WM_SIZE:
568         gst_gl_window_resize (window, LOWORD (lParam), HIWORD (lParam));
569         break;
570       case WM_PAINT:
571       {
572         if (window->queue_resize) {
573           guint width, height;
574 
575           gst_gl_window_get_surface_dimensions (window, &width, &height);
576           gst_gl_window_resize (window, width, height);
577         }
578         if (window->draw) {
579           PAINTSTRUCT ps;
580           BeginPaint (hWnd, &ps);
581           window->draw (window->draw_data);
582           gst_gl_context_swap_buffers (context);
583           EndPaint (hWnd, &ps);
584         }
585         break;
586       }
587       case WM_CLOSE:
588       {
589         ShowWindowAsync (window_win32->internal_win_id, SW_HIDE);
590 
591         GST_TRACE ("WM_CLOSE");
592 
593         if (window->close)
594           window->close (window->close_data);
595         break;
596       }
597       case WM_CAPTURECHANGED:
598       {
599         GST_DEBUG ("WM_CAPTURECHANGED");
600         if (window->queue_resize) {
601           guint width, height;
602 
603           gst_gl_window_get_surface_dimensions (window, &width, &height);
604           gst_gl_window_resize (window, width, height);
605         }
606         if (window->draw)
607           window->draw (window->draw_data);
608         break;
609       }
610       case WM_ERASEBKGND:
611       {
612         ret = TRUE;
613         break;
614       }
615       case WM_KEYDOWN:
616       case WM_KEYUP:
617         gst_gl_window_win32_handle_key_event (window, uMsg, lParam);
618         ret = DefWindowProc (hWnd, uMsg, wParam, lParam);
619         break;
620       case WM_LBUTTONDOWN:
621       case WM_LBUTTONUP:
622       case WM_RBUTTONDOWN:
623       case WM_RBUTTONUP:
624       case WM_MBUTTONDOWN:
625       case WM_MBUTTONUP:
626       case WM_MOUSEMOVE:
627         gst_gl_window_win32_handle_mouse_event (window, uMsg, lParam);
628         /* DefWindowProc will not chain up mouse event to parent window */
629         if (window_win32->parent_win_id)
630           PostMessage (window_win32->parent_win_id, uMsg, wParam, lParam);
631         ret = DefWindowProc (hWnd, uMsg, wParam, lParam);
632         break;
633       default:
634       {
635         ret = DefWindowProc (hWnd, uMsg, wParam, lParam);
636       }
637     }
638 
639     gst_object_unref (context);
640   } else {
641     ret = DefWindowProc (hWnd, uMsg, wParam, lParam);
642   }
643 
644   return ret;
645 }
646 
647 LRESULT FAR PASCAL
sub_class_proc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)648 sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
649 {
650   WNDPROC window_parent_proc = GetProp (hWnd, "gl_window_parent_proc");
651 
652   if (uMsg == WM_SIZE) {
653     HWND gl_window_id = GetProp (hWnd, "gl_window_id");
654     MoveWindow (gl_window_id, 0, 0, LOWORD (lParam), HIWORD (lParam), FALSE);
655   }
656 
657   return CallWindowProc (window_parent_proc, hWnd, uMsg, wParam, lParam);
658 }
659 
660 typedef struct _GstGLWin32SyncMessage
661 {
662   GstGLWindowCB callback;
663   gpointer data;
664 
665   HANDLE *event;
666 } GstGLWin32SyncMessage;
667 
668 static void
_run_message_sync(GstGLWin32SyncMessage * message)669 _run_message_sync (GstGLWin32SyncMessage * message)
670 {
671   if (message->callback)
672     message->callback (message->data);
673 
674   SetEvent (message->event);
675 }
676 
677 void
gst_gl_window_win32_send_message(GstGLWindow * window,GstGLWindowCB callback,gpointer data)678 gst_gl_window_win32_send_message (GstGLWindow * window,
679     GstGLWindowCB callback, gpointer data)
680 {
681   GstGLWin32SyncMessage message;
682 
683   message.callback = callback;
684   message.data = data;
685   message.event = CreateEvent (NULL, FALSE, FALSE, NULL);
686 
687   gst_gl_window_send_message_async (window, (GstGLWindowCB) _run_message_sync,
688       &message, NULL);
689 
690   WaitForSingleObject (message.event, INFINITE);
691   CloseHandle (message.event);
692 }
693