[818/906] window: add send_message_async vmethod
[platform/upstream/gstreamer.git] / gst-libs / gst / gl / x11 / gstglwindow_x11.c
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 #define GLIB_DISABLE_DEPRECATION_WARNINGS
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <gst/gst.h>
29 #include <locale.h>
30
31 #include "x11_event_source.h"
32 #include "gstglwindow_x11.h"
33
34 #define GST_GL_WINDOW_X11_GET_PRIVATE(o)  \
35   (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_WINDOW_X11, GstGLWindowX11Private))
36
37 #define GST_CAT_DEFAULT gst_gl_window_debug
38
39 #define gst_gl_window_x11_parent_class parent_class
40 G_DEFINE_TYPE (GstGLWindowX11, gst_gl_window_x11, GST_GL_TYPE_WINDOW);
41
42 /* X error trap */
43 static int TrappedErrorCode = 0;
44 static int (*old_error_handler) (Display *, XErrorEvent *);
45
46 enum
47 {
48   ARG_0,
49   ARG_DISPLAY
50 };
51
52 struct _GstGLWindowX11Private
53 {
54   gboolean activate;
55   gboolean activate_result;
56 };
57
58 guintptr gst_gl_window_x11_get_display (GstGLWindow * window);
59 guintptr gst_gl_window_x11_get_gl_context (GstGLWindow * window);
60 gboolean gst_gl_window_x11_activate (GstGLWindow * window, gboolean activate);
61 void gst_gl_window_x11_set_window_handle (GstGLWindow * window,
62     guintptr handle);
63 guintptr gst_gl_window_x11_get_window_handle (GstGLWindow * window);
64 void gst_gl_window_x11_draw_unlocked (GstGLWindow * window, guint width,
65     guint height);
66 void gst_gl_window_x11_draw (GstGLWindow * window, guint width, guint height);
67 void gst_gl_window_x11_run (GstGLWindow * window);
68 void gst_gl_window_x11_quit (GstGLWindow * window);
69 void gst_gl_window_x11_send_message_async (GstGLWindow * window,
70     GstGLWindowCB callback, gpointer data, GDestroyNotify destroy);
71 gboolean gst_gl_window_x11_create_context (GstGLWindow * window,
72     GstGLAPI gl_api, guintptr external_gl_context, GError ** error);
73 gboolean gst_gl_window_x11_open (GstGLWindow * window, GError ** error);
74 void gst_gl_window_x11_close (GstGLWindow * window);
75
76 static void
77 gst_gl_window_x11_set_property (GObject * object, guint prop_id,
78     const GValue * value, GParamSpec * pspec)
79 {
80   GstGLWindowX11 *window_x11;
81
82   g_return_if_fail (GST_GL_IS_WINDOW_X11 (object));
83
84   window_x11 = GST_GL_WINDOW_X11 (object);
85
86   switch (prop_id) {
87     case ARG_DISPLAY:
88       window_x11->display_name = g_strdup (g_value_get_string (value));
89       break;
90     default:
91       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
92       break;
93   }
94 }
95
96 static void
97 gst_gl_window_x11_get_property (GObject * object, guint prop_id,
98     GValue * value, GParamSpec * pspec)
99 {
100   GstGLWindowX11 *window_x11;
101
102   g_return_if_fail (GST_GL_IS_WINDOW_X11 (object));
103
104   window_x11 = GST_GL_WINDOW_X11 (object);
105
106   switch (prop_id) {
107     case ARG_DISPLAY:
108       g_value_set_string (value, window_x11->display_name);
109       break;
110     default:
111       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
112       break;
113   }
114 }
115
116 static void
117 gst_gl_window_x11_finalize (GObject * object)
118 {
119   GstGLWindowX11 *window_x11;
120
121   g_return_if_fail (GST_GL_IS_WINDOW_X11 (object));
122
123   window_x11 = GST_GL_WINDOW_X11 (object);
124
125   g_mutex_clear (&window_x11->disp_send_lock);
126
127   G_OBJECT_CLASS (parent_class)->finalize (object);
128 }
129
130 static void
131 gst_gl_window_x11_class_init (GstGLWindowX11Class * klass)
132 {
133   GObjectClass *obj_class = G_OBJECT_CLASS (klass);
134   GstGLWindowClass *window_class = (GstGLWindowClass *) klass;
135
136   g_type_class_add_private (klass, sizeof (GstGLWindowX11Private));
137
138   obj_class->set_property = gst_gl_window_x11_set_property;
139   obj_class->get_property = gst_gl_window_x11_get_property;
140   obj_class->finalize = gst_gl_window_x11_finalize;
141
142   g_object_class_install_property (obj_class, ARG_DISPLAY,
143       g_param_spec_string ("display", "Display", "X Display name", NULL,
144           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
145
146   window_class->get_display = GST_DEBUG_FUNCPTR (gst_gl_window_x11_get_display);
147   window_class->set_window_handle =
148       GST_DEBUG_FUNCPTR (gst_gl_window_x11_set_window_handle);
149   window_class->get_window_handle =
150       GST_DEBUG_FUNCPTR (gst_gl_window_x11_get_window_handle);
151   window_class->draw_unlocked =
152       GST_DEBUG_FUNCPTR (gst_gl_window_x11_draw_unlocked);
153   window_class->draw = GST_DEBUG_FUNCPTR (gst_gl_window_x11_draw);
154   window_class->run = GST_DEBUG_FUNCPTR (gst_gl_window_x11_run);
155   window_class->quit = GST_DEBUG_FUNCPTR (gst_gl_window_x11_quit);
156   window_class->send_message_async =
157       GST_DEBUG_FUNCPTR (gst_gl_window_x11_send_message_async);
158   window_class->open = GST_DEBUG_FUNCPTR (gst_gl_window_x11_open);
159   window_class->close = GST_DEBUG_FUNCPTR (gst_gl_window_x11_close);
160 }
161
162 static void
163 gst_gl_window_x11_init (GstGLWindowX11 * window)
164 {
165   window->priv = GST_GL_WINDOW_X11_GET_PRIVATE (window);
166
167   g_mutex_init (&window->disp_send_lock);
168 }
169
170 /* Must be called in the gl thread */
171 GstGLWindowX11 *
172 gst_gl_window_x11_new (void)
173 {
174   GstGLWindowX11 *window = NULL;
175
176   window = g_object_new (GST_GL_TYPE_WINDOW_X11, NULL);
177
178   gst_gl_window_set_need_lock (GST_GL_WINDOW (window), FALSE);
179
180   return window;
181 }
182
183 gboolean
184 gst_gl_window_x11_open (GstGLWindow * window, GError ** error)
185 {
186   GstGLWindowX11 *window_x11 = GST_GL_WINDOW_X11 (window);
187
188   window_x11->device = XOpenDisplay (window_x11->display_name);
189   if (window_x11->device == NULL) {
190     g_set_error (error, GST_GL_WINDOW_ERROR,
191         GST_GL_WINDOW_ERROR_RESOURCE_UNAVAILABLE,
192         "Failed to connect to X display server");
193     goto failure;
194   }
195
196   XSynchronize (window_x11->device, FALSE);
197
198   GST_LOG ("gl device id: %ld", (gulong) window_x11->device);
199
200   window_x11->disp_send = XOpenDisplay (window_x11->display_name);
201
202   XSynchronize (window_x11->disp_send, FALSE);
203
204   GST_LOG ("gl display sender: %ld", (gulong) window_x11->disp_send);
205
206   g_assert (window_x11->device);
207
208   window_x11->screen = DefaultScreenOfDisplay (window_x11->device);
209   window_x11->screen_num = DefaultScreen (window_x11->device);
210   window_x11->visual =
211       DefaultVisual (window_x11->device, window_x11->screen_num);
212   window_x11->root = DefaultRootWindow (window_x11->device);
213   window_x11->white = XWhitePixel (window_x11->device, window_x11->screen_num);
214   window_x11->black = XBlackPixel (window_x11->device, window_x11->screen_num);
215   window_x11->depth = DefaultDepthOfScreen (window_x11->screen);
216
217   GST_LOG ("gl root id: %lud", (gulong) window_x11->root);
218
219   window_x11->device_width =
220       DisplayWidth (window_x11->device, window_x11->screen_num);
221   window_x11->device_height =
222       DisplayHeight (window_x11->device, window_x11->screen_num);
223
224   window_x11->x11_source = x11_event_source_new (window_x11);
225   window_x11->main_context = g_main_context_new ();
226   window_x11->loop = g_main_loop_new (window_x11->main_context, FALSE);
227
228   g_source_attach (window_x11->x11_source, window_x11->main_context);
229
230   window_x11->allow_extra_expose_events = TRUE;
231
232   return TRUE;
233
234 failure:
235   return FALSE;
236 }
237
238 gboolean
239 gst_gl_window_x11_create_window (GstGLWindowX11 * window_x11)
240 {
241   XSetWindowAttributes win_attr;
242   XTextProperty text_property;
243   XWMHints wm_hints;
244   unsigned long mask;
245   const gchar *title = "OpenGL renderer";
246   Atom wm_atoms[1];
247   gint x = 0, y = 0, width = 1, height = 1;
248
249   if (window_x11->visual_info->visual != window_x11->visual)
250     GST_LOG ("selected visual is different from the default");
251
252   GST_LOG ("visual XID:%d, screen:%d, visualid:%d, depth:%d, class:%d, "
253       "red_mask:%ld, green_mask:%ld, blue_mask:%ld bpp:%d",
254       (gint) XVisualIDFromVisual (window_x11->visual_info->visual),
255       window_x11->visual_info->screen, (gint) window_x11->visual_info->visualid,
256       window_x11->visual_info->depth, window_x11->visual_info->class,
257       window_x11->visual_info->red_mask, window_x11->visual_info->green_mask,
258       window_x11->visual_info->blue_mask,
259       window_x11->visual_info->bits_per_rgb);
260
261   win_attr.event_mask =
262       StructureNotifyMask | ExposureMask | VisibilityChangeMask;
263   win_attr.do_not_propagate_mask = NoEventMask;
264
265   win_attr.background_pixmap = None;
266   win_attr.background_pixel = 0;
267   win_attr.border_pixel = 0;
268
269   win_attr.colormap =
270       XCreateColormap (window_x11->device, window_x11->root,
271       window_x11->visual_info->visual, AllocNone);
272
273   mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
274
275   window_x11->internal_win_id =
276       XCreateWindow (window_x11->device,
277       window_x11->parent_win ? window_x11->parent_win : window_x11->root,
278       x, y, width, height, 0,
279       window_x11->visual_info->depth, InputOutput,
280       window_x11->visual_info->visual, mask, &win_attr);
281
282   XSync (window_x11->device, FALSE);
283
284   XSetWindowBackgroundPixmap (window_x11->device, window_x11->internal_win_id,
285       None);
286
287   GST_LOG ("gl window id: %lud", (gulong) window_x11->internal_win_id);
288   GST_LOG ("gl window props: x:%d y:%d", x, y);
289
290   wm_atoms[0] = XInternAtom (window_x11->device, "WM_DELETE_WINDOW", True);
291   if (wm_atoms[0] == None)
292     GST_DEBUG ("Cannot create WM_DELETE_WINDOW");
293
294   XSetWMProtocols (window_x11->device, window_x11->internal_win_id, wm_atoms,
295       1);
296
297   wm_hints.flags = StateHint;
298   wm_hints.initial_state = NormalState;
299   wm_hints.input = False;
300
301   XStringListToTextProperty ((char **) &title, 1, &text_property);
302
303   XSetWMProperties (window_x11->device, window_x11->internal_win_id,
304       &text_property, &text_property, 0, 0, NULL, &wm_hints, NULL);
305
306   XFree (text_property.value);
307
308   return TRUE;
309 }
310
311 void
312 gst_gl_window_x11_close (GstGLWindow * window)
313 {
314   GstGLWindowX11 *window_x11 = GST_GL_WINDOW_X11 (window);
315   XEvent event;
316
317   GST_GL_WINDOW_LOCK (window_x11);
318
319   if (window_x11->device) {
320     if (window_x11->internal_win_id)
321       XUnmapWindow (window_x11->device, window_x11->internal_win_id);
322
323     XFree (window_x11->visual_info);
324
325     if (window_x11->internal_win_id) {
326       XReparentWindow (window_x11->device, window_x11->internal_win_id,
327           window_x11->root, 0, 0);
328       XDestroyWindow (window_x11->device, window_x11->internal_win_id);
329     }
330     XSync (window_x11->device, FALSE);
331
332     while (XPending (window_x11->device))
333       XNextEvent (window_x11->device, &event);
334
335     XSetCloseDownMode (window_x11->device, DestroyAll);
336
337     /*XAddToSaveSet (display, w)
338        Display *display;
339        Window w; */
340
341     //FIXME: it seems it causes destroy all created windows, even by other display connection:
342     //This is case in: gst-launch-0.10 videotestsrc ! tee name=t t. ! queue ! glimagesink t. ! queue ! glimagesink
343     //When the first window is closed and so its display is closed by the following line, then the other Window managed by the
344     //other glimagesink, is not useable and so each opengl call causes a segmentation fault.
345     //Maybe the solution is to use: XAddToSaveSet
346     //The following line is commented to avoid the disagreement explained before.
347     //XCloseDisplay (window_x11->device);
348
349     GST_DEBUG ("display receiver closed");
350     XCloseDisplay (window_x11->disp_send);
351     GST_DEBUG ("display sender closed");
352   }
353
354   g_source_destroy (window_x11->x11_source);
355   g_source_unref (window_x11->x11_source);
356   window_x11->x11_source = NULL;
357   g_main_loop_unref (window_x11->loop);
358   window_x11->loop = NULL, g_main_context_unref (window_x11->main_context);
359   window_x11->main_context = NULL;
360
361   window_x11->running = FALSE;
362
363   GST_GL_WINDOW_UNLOCK (window_x11);
364 }
365
366 guintptr
367 gst_gl_window_x11_get_gl_context (GstGLWindow * window)
368 {
369   GstGLWindowX11Class *window_class;
370
371   window_class = GST_GL_WINDOW_X11_GET_CLASS (window);
372
373   return window_class->get_gl_context (GST_GL_WINDOW_X11 (window));
374 }
375
376 static void
377 callback_activate (GstGLWindow * window)
378 {
379   GstGLWindowX11Class *window_class;
380   GstGLWindowX11Private *priv;
381   GstGLWindowX11 *window_x11;
382
383   window_x11 = GST_GL_WINDOW_X11 (window);
384   window_class = GST_GL_WINDOW_X11_GET_CLASS (window_x11);
385   priv = window_x11->priv;
386
387   priv->activate_result = window_class->activate (window_x11, priv->activate);
388 }
389
390 gboolean
391 gst_gl_window_x11_activate (GstGLWindow * window, gboolean activate)
392 {
393   GstGLWindowX11 *window_x11;
394   GstGLWindowX11Private *priv;
395
396   window_x11 = GST_GL_WINDOW_X11 (window);
397   priv = window_x11->priv;
398   priv->activate = activate;
399
400   gst_gl_window_send_message (window, GST_GL_WINDOW_CB (callback_activate),
401       window_x11);
402
403   return priv->activate_result;
404 }
405
406 /* Not called by the gl thread */
407 void
408 gst_gl_window_x11_set_window_handle (GstGLWindow * window, guintptr id)
409 {
410   GstGLWindowX11 *window_x11;
411   XWindowAttributes attr;
412
413   window_x11 = GST_GL_WINDOW_X11 (window);
414
415   window_x11->parent_win = (Window) id;
416
417   if (g_main_loop_is_running (window_x11->loop)) {
418     GST_LOG ("set parent window id: %lud", id);
419
420     g_mutex_lock (&window_x11->disp_send_lock);
421     XGetWindowAttributes (window_x11->disp_send, window_x11->parent_win, &attr);
422
423     XResizeWindow (window_x11->disp_send, window_x11->internal_win_id,
424         attr.width, attr.height);
425
426     XReparentWindow (window_x11->disp_send, window_x11->internal_win_id,
427         window_x11->parent_win, 0, 0);
428
429     XSync (window_x11->disp_send, FALSE);
430     g_mutex_unlock (&window_x11->disp_send_lock);
431   }
432 }
433
434 guintptr
435 gst_gl_window_x11_get_window_handle (GstGLWindow * window)
436 {
437   GstGLWindowX11 *window_x11;
438
439   window_x11 = GST_GL_WINDOW_X11 (window);
440
441   return window_x11->internal_win_id;
442 }
443
444 /* Called in the gl thread */
445 void
446 gst_gl_window_x11_draw_unlocked (GstGLWindow * window, guint width,
447     guint height)
448 {
449   GstGLWindowX11 *window_x11;
450
451   window_x11 = GST_GL_WINDOW_X11 (window);
452
453   if (g_main_loop_is_running (window_x11->loop)
454       && window_x11->allow_extra_expose_events) {
455     XEvent event;
456     XWindowAttributes attr;
457
458     XGetWindowAttributes (window_x11->device, window_x11->internal_win_id,
459         &attr);
460
461     event.xexpose.type = Expose;
462     event.xexpose.send_event = TRUE;
463     event.xexpose.display = window_x11->device;
464     event.xexpose.window = window_x11->internal_win_id;
465     event.xexpose.x = attr.x;
466     event.xexpose.y = attr.y;
467     event.xexpose.width = attr.width;
468     event.xexpose.height = attr.height;
469     event.xexpose.count = 0;
470
471     XSendEvent (window_x11->device, window_x11->internal_win_id, FALSE,
472         ExposureMask, &event);
473     XSync (window_x11->device, FALSE);
474   }
475 }
476
477 /* Not called by the gl thread */
478 void
479 gst_gl_window_x11_draw (GstGLWindow * window, guint width, guint height)
480 {
481   GstGLWindowX11 *window_x11;
482
483   window_x11 = GST_GL_WINDOW_X11 (window);
484
485   if (g_main_loop_is_running (window_x11->loop)) {
486     XEvent event;
487     XWindowAttributes attr;
488
489     g_mutex_lock (&window_x11->disp_send_lock);
490
491     XGetWindowAttributes (window_x11->disp_send, window_x11->internal_win_id,
492         &attr);
493
494     if (!window_x11->visible) {
495
496       if (!window_x11->parent_win) {
497         attr.width = width;
498         attr.height = height;
499         XResizeWindow (window_x11->disp_send, window_x11->internal_win_id,
500             attr.width, attr.height);
501         XSync (window_x11->disp_send, FALSE);
502       }
503
504       XMapWindow (window_x11->disp_send, window_x11->internal_win_id);
505       window_x11->visible = TRUE;
506     }
507
508     if (window_x11->parent_win) {
509       XWindowAttributes attr_parent;
510       XGetWindowAttributes (window_x11->disp_send, window_x11->parent_win,
511           &attr_parent);
512
513       if (attr.width != attr_parent.width || attr.height != attr_parent.height) {
514         XMoveResizeWindow (window_x11->disp_send, window_x11->internal_win_id,
515             0, 0, attr_parent.width, attr_parent.height);
516         XSync (window_x11->disp_send, FALSE);
517
518         attr.width = attr_parent.width;
519         attr.height = attr_parent.height;
520
521         GST_LOG ("parent resize:  %d, %d",
522             attr_parent.width, attr_parent.height);
523       }
524     }
525
526     event.xexpose.type = Expose;
527     event.xexpose.send_event = TRUE;
528     event.xexpose.display = window_x11->disp_send;
529     event.xexpose.window = window_x11->internal_win_id;
530     event.xexpose.x = attr.x;
531     event.xexpose.y = attr.y;
532     event.xexpose.width = attr.width;
533     event.xexpose.height = attr.height;
534     event.xexpose.count = 0;
535
536     XSendEvent (window_x11->disp_send, window_x11->internal_win_id, FALSE,
537         ExposureMask, &event);
538     XSync (window_x11->disp_send, FALSE);
539
540     g_mutex_unlock (&window_x11->disp_send_lock);
541   }
542 }
543
544 void
545 gst_gl_window_x11_run (GstGLWindow * window)
546 {
547   GstGLWindowX11 *window_x11;
548
549   window_x11 = GST_GL_WINDOW_X11 (window);
550
551   g_main_loop_run (window_x11->loop);
552 }
553
554 static inline gchar *
555 event_type_to_string (guint type)
556 {
557   switch (type) {
558     case CreateNotify:
559       return "CreateNotify";
560     case ConfigureNotify:
561       return "ConfigureNotify";
562     case DestroyNotify:
563       return "DestroyNotify";
564     case MapNotify:
565       return "MapNotify";
566     case UnmapNotify:
567       return "UnmapNotify";
568     case Expose:
569       return "Expose";
570     case VisibilityNotify:
571       return "VisibilityNotify";
572     case PropertyNotify:
573       return "PropertyNotify";
574     case SelectionClear:
575       return "SelectionClear";
576     case SelectionNotify:
577       return "SelectionNotify";
578     case SelectionRequest:
579       return "SelectionRequest";
580     case ClientMessage:
581       return "ClientMessage";
582     default:
583       return "unknown";
584   }
585 }
586
587 gboolean
588 gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11)
589 {
590   GstGLContext *context;
591   GstGLContextClass *context_class;
592   GstGLWindow *window;
593
594   gboolean ret = TRUE;
595
596   window = GST_GL_WINDOW (window_x11);
597
598   if (g_main_loop_is_running (window_x11->loop)
599       && XPending (window_x11->device)) {
600     XEvent event;
601
602     /* XSendEvent (which are called in other threads) are done from another display structure */
603     XNextEvent (window_x11->device, &event);
604
605     window_x11->allow_extra_expose_events = XPending (window_x11->device) <= 2;
606
607     GST_LOG ("got event %s", event_type_to_string (event.type));
608
609     switch (event.type) {
610       case ClientMessage:
611       {
612         Atom wm_delete =
613             XInternAtom (window_x11->device, "WM_DELETE_WINDOW", True);
614
615         if (wm_delete == None)
616           GST_DEBUG ("Cannot create WM_DELETE_WINDOW");
617
618         /* User clicked on the cross */
619         if (wm_delete != None && (Atom) event.xclient.data.l[0] == wm_delete) {
620           GST_DEBUG ("Close %lud", (gulong) window_x11->internal_win_id);
621
622           if (window->close)
623             window->close (window->close_data);
624
625           ret = FALSE;
626         }
627         break;
628       }
629
630       case CreateNotify:
631       case ConfigureNotify:
632       {
633         if (window->resize)
634           window->resize (window->resize_data, event.xconfigure.width,
635               event.xconfigure.height);
636         break;
637       }
638
639       case DestroyNotify:
640         break;
641
642       case Expose:
643         if (window->draw) {
644           context = gst_gl_window_get_context (window);
645           context_class = GST_GL_CONTEXT_GET_CLASS (context);
646
647           window->draw (window->draw_data);
648           context_class->swap_buffers (context);
649
650           gst_object_unref (context);
651         }
652         break;
653
654       case VisibilityNotify:
655       {
656         switch (event.xvisibility.state) {
657           case VisibilityUnobscured:
658             if (window->draw)
659               window->draw (window->draw_data);
660             break;
661
662           case VisibilityPartiallyObscured:
663             if (window->draw)
664               window->draw (window->draw_data);
665             break;
666
667           case VisibilityFullyObscured:
668             break;
669
670           default:
671             GST_DEBUG ("unknown xvisibility event: %d",
672                 event.xvisibility.state);
673             break;
674         }
675         break;
676       }
677
678       default:
679         GST_DEBUG ("unknown XEvent type: %u", event.type);
680         break;
681
682     }                           // switch
683   }                             // while running
684
685   return ret;
686 }
687
688 /* Not called by the gl thread */
689 void
690 gst_gl_window_x11_quit (GstGLWindow * window)
691 {
692   GstGLWindowX11 *window_x11;
693
694   window_x11 = GST_GL_WINDOW_X11 (window);
695
696   GST_LOG ("sending quit");
697
698   g_main_loop_quit (window_x11->loop);
699
700   GST_LOG ("quit sent");
701 }
702
703 typedef struct _GstGLMessage
704 {
705   GstGLWindowCB callback;
706   gpointer data;
707   GDestroyNotify destroy;
708 } GstGLMessage;
709
710 static gboolean
711 _run_message (GstGLMessage * message)
712 {
713   if (message->callback)
714     message->callback (message->data);
715
716   if (message->destroy)
717     message->destroy (message->data);
718
719   g_slice_free (GstGLMessage, message);
720
721   return FALSE;
722 }
723
724 void
725 gst_gl_window_x11_send_message_async (GstGLWindow * window,
726     GstGLWindowCB callback, gpointer data, GDestroyNotify destroy)
727 {
728   GstGLWindowX11 *window_x11;
729   GstGLMessage *message;
730
731   window_x11 = GST_GL_WINDOW_X11 (window);
732   message = g_slice_new (GstGLMessage);
733
734   message->callback = callback;
735   message->data = data;
736   message->destroy = destroy;
737
738   g_main_context_invoke (window_x11->main_context, (GSourceFunc) _run_message,
739       message);
740 }
741
742 static int
743 error_handler (Display * xdpy, XErrorEvent * error)
744 {
745   TrappedErrorCode = error->error_code;
746   return 0;
747 }
748
749 /**
750  * gst_gl_window_x11_trap_x_errors:
751  *
752  * Traps every X error until gst_gl_window_x11_untrap_x_errors() is called.
753  */
754 void
755 gst_gl_window_x11_trap_x_errors (void)
756 {
757   TrappedErrorCode = 0;
758   old_error_handler = XSetErrorHandler (error_handler);
759 }
760
761 /**
762  * gst_gl_window_x11_untrap_x_errors:
763  *
764  * Removes the X error trap and returns the current status.
765  *
766  * Return value: the trapped error code, or 0 for success
767  */
768 gint
769 gst_gl_window_x11_untrap_x_errors (void)
770 {
771   XSetErrorHandler (old_error_handler);
772
773   return TrappedErrorCode;
774 }
775
776 guintptr
777 gst_gl_window_x11_get_display (GstGLWindow * window)
778 {
779   GstGLWindowX11 *window_x11;
780
781   window_x11 = GST_GL_WINDOW_X11 (window);
782
783   return (guintptr) window_x11->device;
784 }