20470edc5d7ad619ae96ddabb395c12ddbddab9e
[platform/upstream/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapiwindow_x11.c
1 /*
2  *  gstvaapiwindow_x11.c - VA/X11 window abstraction
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2012-2014 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public License
11  *  as published by the Free Software Foundation; either version 2.1
12  *  of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free
21  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301 USA
23  */
24
25 /**
26  * SECTION:gstvaapiwindow_x11
27  * @short_description: VA/X11 window abstraction
28  */
29
30 #include "sysdeps.h"
31 #include <string.h>
32 #include <X11/Xatom.h>
33 #include "gstvaapicompat.h"
34 #include "gstvaapiwindow_x11.h"
35 #include "gstvaapiwindow_x11_priv.h"
36 #include "gstvaapipixmap_x11.h"
37 #include "gstvaapipixmap_priv.h"
38 #include "gstvaapidisplay_x11.h"
39 #include "gstvaapidisplay_x11_priv.h"
40 #include "gstvaapiutils.h"
41 #include "gstvaapiutils_x11.h"
42
43 #define DEBUG 1
44 #include "gstvaapidebug.h"
45
46 #define _NET_WM_STATE_REMOVE    0       /* remove/unset property */
47 #define _NET_WM_STATE_ADD       1       /* add/set property      */
48 #define _NET_WM_STATE_TOGGLE    2       /* toggle property       */
49
50 static void
51 send_wmspec_change_state (GstVaapiWindow * window, Atom state, gboolean add)
52 {
53   GstVaapiWindowX11Private *const priv =
54       GST_VAAPI_WINDOW_X11_GET_PRIVATE (window);
55   Display *const dpy = GST_VAAPI_OBJECT_XDISPLAY (window);
56   XClientMessageEvent xclient;
57
58   memset (&xclient, 0, sizeof (xclient));
59
60   xclient.type = ClientMessage;
61   xclient.window = GST_VAAPI_OBJECT_ID (window);
62   xclient.message_type = priv->atom_NET_WM_STATE;
63   xclient.format = 32;
64
65   xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
66   xclient.data.l[1] = state;
67   xclient.data.l[2] = 0;
68   xclient.data.l[3] = 0;
69   xclient.data.l[4] = 0;
70
71   XSendEvent (dpy,
72       DefaultRootWindow (dpy),
73       False,
74       SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *) & xclient);
75 }
76
77 static void
78 wait_event (GstVaapiWindow * window, int type)
79 {
80   Display *const dpy = GST_VAAPI_OBJECT_XDISPLAY (window);
81   const Window xid = GST_VAAPI_OBJECT_ID (window);
82   XEvent e;
83   Bool got_event;
84
85   for (;;) {
86     GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
87     got_event = XCheckTypedWindowEvent (dpy, xid, type, &e);
88     GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
89     if (got_event)
90       break;
91     g_usleep (10);
92   }
93 }
94
95 static gboolean
96 timed_wait_event (GstVaapiWindow * window, int type, guint64 end_time,
97     XEvent * e)
98 {
99   Display *const dpy = GST_VAAPI_OBJECT_XDISPLAY (window);
100   const Window xid = GST_VAAPI_OBJECT_ID (window);
101   XEvent tmp_event;
102   GTimeVal now;
103   guint64 now_time;
104   Bool got_event;
105
106   if (!e)
107     e = &tmp_event;
108
109   GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
110   got_event = XCheckTypedWindowEvent (dpy, xid, type, e);
111   GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
112   if (got_event)
113     return TRUE;
114
115   do {
116     g_usleep (10);
117     GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
118     got_event = XCheckTypedWindowEvent (dpy, xid, type, e);
119     GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
120     if (got_event)
121       return TRUE;
122     g_get_current_time (&now);
123     now_time = (guint64) now.tv_sec * 1000000 + now.tv_usec;
124   } while (now_time < end_time);
125   return FALSE;
126 }
127
128 static gboolean
129 gst_vaapi_window_x11_show (GstVaapiWindow * window)
130 {
131   GstVaapiWindowX11Private *const priv =
132       GST_VAAPI_WINDOW_X11_GET_PRIVATE (window);
133   Display *const dpy = GST_VAAPI_OBJECT_XDISPLAY (window);
134   const Window xid = GST_VAAPI_OBJECT_ID (window);
135   XWindowAttributes wattr;
136   gboolean has_errors;
137
138   if (priv->is_mapped)
139     return TRUE;
140
141   GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
142   x11_trap_errors ();
143   if (window->use_foreign_window) {
144     XGetWindowAttributes (dpy, xid, &wattr);
145     if (!(wattr.your_event_mask & StructureNotifyMask))
146       XSelectInput (dpy, xid, StructureNotifyMask);
147   }
148   XMapWindow (dpy, xid);
149   has_errors = x11_untrap_errors () != 0;
150   GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
151
152   if (!has_errors) {
153     wait_event (window, MapNotify);
154     if (window->use_foreign_window &&
155         !(wattr.your_event_mask & StructureNotifyMask)) {
156       GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
157       x11_trap_errors ();
158       XSelectInput (dpy, xid, wattr.your_event_mask);
159       has_errors = x11_untrap_errors () != 0;
160       GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
161     }
162     priv->is_mapped = TRUE;
163
164     if (priv->fullscreen_on_map)
165       gst_vaapi_window_set_fullscreen (window, TRUE);
166   }
167   return !has_errors;
168 }
169
170 static gboolean
171 gst_vaapi_window_x11_hide (GstVaapiWindow * window)
172 {
173   GstVaapiWindowX11Private *const priv =
174       GST_VAAPI_WINDOW_X11_GET_PRIVATE (window);
175   Display *const dpy = GST_VAAPI_OBJECT_XDISPLAY (window);
176   const Window xid = GST_VAAPI_OBJECT_ID (window);
177   XWindowAttributes wattr;
178   gboolean has_errors;
179
180   if (!priv->is_mapped)
181     return TRUE;
182
183   GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
184   x11_trap_errors ();
185   if (window->use_foreign_window) {
186     XGetWindowAttributes (dpy, xid, &wattr);
187     if (!(wattr.your_event_mask & StructureNotifyMask))
188       XSelectInput (dpy, xid, StructureNotifyMask);
189   }
190   XUnmapWindow (dpy, xid);
191   has_errors = x11_untrap_errors () != 0;
192   GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
193
194   if (!has_errors) {
195     wait_event (window, UnmapNotify);
196     if (window->use_foreign_window &&
197         !(wattr.your_event_mask & StructureNotifyMask)) {
198       GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
199       x11_trap_errors ();
200       XSelectInput (dpy, xid, wattr.your_event_mask);
201       has_errors = x11_untrap_errors () != 0;
202       GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
203     }
204     priv->is_mapped = FALSE;
205   }
206   return !has_errors;
207 }
208
209 static gboolean
210 gst_vaapi_window_x11_create (GstVaapiWindow * window, guint * width,
211     guint * height)
212 {
213   GstVaapiWindowX11Private *const priv =
214       GST_VAAPI_WINDOW_X11_GET_PRIVATE (window);
215   Display *const dpy = GST_VAAPI_OBJECT_XDISPLAY (window);
216   Window xid = GST_VAAPI_OBJECT_ID (window);
217   Visual *vis = NULL;
218   Colormap cmap = None;
219   const GstVaapiWindowX11Class *klass;
220   XWindowAttributes wattr;
221   Atom atoms[2];
222   gboolean ok;
223
224   static const char *atom_names[2] = {
225     "_NET_WM_STATE",
226     "_NET_WM_STATE_FULLSCREEN",
227   };
228
229   priv->has_xrender =
230       GST_VAAPI_DISPLAY_HAS_XRENDER (GST_VAAPI_OBJECT_DISPLAY (window));
231
232   if (window->use_foreign_window && xid) {
233     GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
234     XGetWindowAttributes (dpy, xid, &wattr);
235     priv->is_mapped = wattr.map_state == IsViewable;
236     ok = x11_get_geometry (dpy, xid, NULL, NULL, width, height, NULL);
237     GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
238     return ok;
239   }
240
241   klass = GST_VAAPI_WINDOW_X11_GET_CLASS (window);
242   if (klass) {
243     if (klass->get_visual)
244       vis = klass->get_visual (window);
245     if (klass->get_colormap)
246       cmap = klass->get_colormap (window);
247   }
248
249   GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
250   XInternAtoms (dpy,
251       (char **) atom_names, G_N_ELEMENTS (atom_names), False, atoms);
252   priv->atom_NET_WM_STATE = atoms[0];
253   priv->atom_NET_WM_STATE_FULLSCREEN = atoms[1];
254
255   xid = x11_create_window (dpy, *width, *height, vis, cmap);
256   if (xid)
257     XRaiseWindow (dpy, xid);
258   GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
259
260   GST_DEBUG ("xid %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (xid));
261   GST_VAAPI_OBJECT_ID (window) = xid;
262   return xid != None;
263 }
264
265 static void
266 gst_vaapi_window_x11_destroy (GstVaapiWindow * window)
267 {
268   Display *const dpy = GST_VAAPI_OBJECT_XDISPLAY (window);
269   const Window xid = GST_VAAPI_OBJECT_ID (window);
270
271 #ifdef HAVE_XRENDER
272   GstVaapiWindowX11Private *const priv =
273       GST_VAAPI_WINDOW_X11_GET_PRIVATE (window);
274   if (priv->picture) {
275     GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
276     XRenderFreePicture (dpy, priv->picture);
277     GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
278     priv->picture = None;
279   }
280 #endif
281
282   if (xid) {
283     if (!window->use_foreign_window) {
284       GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
285       XDestroyWindow (dpy, xid);
286       GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
287     }
288     GST_VAAPI_OBJECT_ID (window) = None;
289   }
290 }
291
292 static gboolean
293 gst_vaapi_window_x11_get_geometry (GstVaapiWindow * window,
294     gint * px, gint * py, guint * pwidth, guint * pheight)
295 {
296   Display *const dpy = GST_VAAPI_OBJECT_XDISPLAY (window);
297   const Window xid = GST_VAAPI_OBJECT_ID (window);
298
299   return x11_get_geometry (dpy, xid, px, py, pwidth, pheight, NULL);
300 }
301
302 static gboolean
303 gst_vaapi_window_x11_set_fullscreen (GstVaapiWindow * window,
304     gboolean fullscreen)
305 {
306   GstVaapiWindowX11Private *const priv =
307       GST_VAAPI_WINDOW_X11_GET_PRIVATE (window);
308   Display *const dpy = GST_VAAPI_OBJECT_XDISPLAY (window);
309   const Window xid = GST_VAAPI_OBJECT_ID (window);
310   XEvent e;
311   guint width, height;
312   gboolean has_errors;
313   GTimeVal now;
314   guint64 end_time;
315
316   GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
317   x11_trap_errors ();
318   if (fullscreen) {
319     if (!priv->is_mapped) {
320       priv->fullscreen_on_map = TRUE;
321
322       XChangeProperty (dpy,
323           xid,
324           priv->atom_NET_WM_STATE, XA_ATOM, 32,
325           PropModeReplace,
326           (unsigned char *) &priv->atom_NET_WM_STATE_FULLSCREEN, 1);
327     } else {
328       send_wmspec_change_state (window,
329           priv->atom_NET_WM_STATE_FULLSCREEN, TRUE);
330     }
331   } else {
332     if (!priv->is_mapped) {
333       priv->fullscreen_on_map = FALSE;
334
335       XDeleteProperty (dpy, xid, priv->atom_NET_WM_STATE);
336     } else {
337       send_wmspec_change_state (window,
338           priv->atom_NET_WM_STATE_FULLSCREEN, FALSE);
339     }
340   }
341   XSync (dpy, False);
342   has_errors = x11_untrap_errors () != 0;
343   GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
344   if (has_errors)
345     return FALSE;
346
347   /* Try to wait for the completion of the fullscreen mode switch */
348   if (!window->use_foreign_window && priv->is_mapped) {
349     const guint DELAY = 100000; /* 100 ms */
350     g_get_current_time (&now);
351     end_time = DELAY + ((guint64) now.tv_sec * 1000000 + now.tv_usec);
352     while (timed_wait_event (window, ConfigureNotify, end_time, &e)) {
353       if (fullscreen) {
354         gst_vaapi_display_get_size (GST_VAAPI_OBJECT_DISPLAY (window),
355             &width, &height);
356         if (e.xconfigure.width == width && e.xconfigure.height == height)
357           return TRUE;
358       } else {
359         gst_vaapi_window_get_size (window, &width, &height);
360         if (e.xconfigure.width != width || e.xconfigure.height != height)
361           return TRUE;
362       }
363     }
364   }
365   return FALSE;
366 }
367
368 static gboolean
369 gst_vaapi_window_x11_resize (GstVaapiWindow * window, guint width, guint height)
370 {
371   gboolean has_errors;
372
373   if (!GST_VAAPI_OBJECT_ID (window))
374     return FALSE;
375
376   GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
377   x11_trap_errors ();
378   XResizeWindow (GST_VAAPI_OBJECT_XDISPLAY (window),
379       GST_VAAPI_OBJECT_ID (window), width, height);
380   has_errors = x11_untrap_errors () != 0;
381   GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
382   return !has_errors;
383 }
384
385 static gboolean
386 gst_vaapi_window_x11_render (GstVaapiWindow * window,
387     GstVaapiSurface * surface,
388     const GstVaapiRectangle * src_rect,
389     const GstVaapiRectangle * dst_rect, guint flags)
390 {
391   VASurfaceID surface_id;
392   VAStatus status;
393
394   surface_id = GST_VAAPI_OBJECT_ID (surface);
395   if (surface_id == VA_INVALID_ID)
396     return FALSE;
397
398   GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
399   status = vaPutSurface (GST_VAAPI_OBJECT_VADISPLAY (window),
400       surface_id,
401       GST_VAAPI_OBJECT_ID (window),
402       src_rect->x,
403       src_rect->y,
404       src_rect->width,
405       src_rect->height,
406       dst_rect->x,
407       dst_rect->y,
408       dst_rect->width,
409       dst_rect->height, NULL, 0, from_GstVaapiSurfaceRenderFlags (flags)
410       );
411   GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
412   if (!vaapi_check_status (status, "vaPutSurface()"))
413     return FALSE;
414
415   return TRUE;
416 }
417
418 static gboolean
419 gst_vaapi_window_x11_render_pixmap_xrender (GstVaapiWindow * window,
420     GstVaapiPixmap * pixmap,
421     const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect)
422 {
423 #ifdef HAVE_XRENDER
424   GstVaapiWindowX11Private *const priv =
425       GST_VAAPI_WINDOW_X11_GET_PRIVATE (window);
426   Display *const dpy = GST_VAAPI_OBJECT_XDISPLAY (window);
427   const Window win = GST_VAAPI_OBJECT_ID (window);
428   const Pixmap pix = GST_VAAPI_OBJECT_ID (pixmap);
429   Picture picture;
430   XRenderPictFormat *pic_fmt;
431   XWindowAttributes wattr;
432   int fmt, op;
433   gboolean success = FALSE;
434
435   /* Ensure Picture for window is created */
436   if (!priv->picture) {
437     GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
438     XGetWindowAttributes (dpy, win, &wattr);
439     pic_fmt = XRenderFindVisualFormat (dpy, wattr.visual);
440     if (pic_fmt)
441       priv->picture = XRenderCreatePicture (dpy, win, pic_fmt, 0, NULL);
442     GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
443     if (!priv->picture)
444       return FALSE;
445   }
446
447   /* Check pixmap format */
448   switch (GST_VAAPI_PIXMAP_FORMAT (pixmap)) {
449     case GST_VIDEO_FORMAT_xRGB:
450       fmt = PictStandardRGB24;
451       op = PictOpSrc;
452       goto get_pic_fmt;
453     case GST_VIDEO_FORMAT_ARGB:
454       fmt = PictStandardARGB32;
455       op = PictOpOver;
456     get_pic_fmt:
457       GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
458       pic_fmt = XRenderFindStandardFormat (dpy, fmt);
459       GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
460       break;
461     default:
462       pic_fmt = NULL;
463       break;
464   }
465   if (!pic_fmt)
466     return FALSE;
467
468   GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
469   do {
470     const double sx = (double) src_rect->width / dst_rect->width;
471     const double sy = (double) src_rect->height / dst_rect->height;
472     XTransform xform;
473
474     picture = XRenderCreatePicture (dpy, pix, pic_fmt, 0, NULL);
475     if (!picture)
476       break;
477
478     xform.matrix[0][0] = XDoubleToFixed (sx);
479     xform.matrix[0][1] = XDoubleToFixed (0.0);
480     xform.matrix[0][2] = XDoubleToFixed (src_rect->x);
481     xform.matrix[1][0] = XDoubleToFixed (0.0);
482     xform.matrix[1][1] = XDoubleToFixed (sy);
483     xform.matrix[1][2] = XDoubleToFixed (src_rect->y);
484     xform.matrix[2][0] = XDoubleToFixed (0.0);
485     xform.matrix[2][1] = XDoubleToFixed (0.0);
486     xform.matrix[2][2] = XDoubleToFixed (1.0);
487     XRenderSetPictureTransform (dpy, picture, &xform);
488
489     XRenderComposite (dpy, op, picture, None, priv->picture,
490         0, 0, 0, 0, dst_rect->x, dst_rect->y,
491         dst_rect->width, dst_rect->height);
492     XSync (dpy, False);
493     success = TRUE;
494   } while (0);
495   if (picture)
496     XRenderFreePicture (dpy, picture);
497   GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
498   return success;
499 #endif
500   return FALSE;
501 }
502
503 static gboolean
504 gst_vaapi_window_x11_render_pixmap (GstVaapiWindow * window,
505     GstVaapiPixmap * pixmap,
506     const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect)
507 {
508   GstVaapiWindowX11Private *const priv =
509       GST_VAAPI_WINDOW_X11_GET_PRIVATE (window);
510
511   if (priv->has_xrender)
512     return gst_vaapi_window_x11_render_pixmap_xrender (window, pixmap,
513         src_rect, dst_rect);
514
515   /* XXX: only X RENDER extension is supported for now */
516   return FALSE;
517 }
518
519 void
520 gst_vaapi_window_x11_class_init (GstVaapiWindowX11Class * klass)
521 {
522   GstVaapiObjectClass *const object_class = GST_VAAPI_OBJECT_CLASS (klass);
523   GstVaapiWindowClass *const window_class = GST_VAAPI_WINDOW_CLASS (klass);
524
525   object_class->finalize = (GstVaapiObjectFinalizeFunc)
526       gst_vaapi_window_x11_destroy;
527
528   window_class->create = gst_vaapi_window_x11_create;
529   window_class->show = gst_vaapi_window_x11_show;
530   window_class->hide = gst_vaapi_window_x11_hide;
531   window_class->get_geometry = gst_vaapi_window_x11_get_geometry;
532   window_class->set_fullscreen = gst_vaapi_window_x11_set_fullscreen;
533   window_class->resize = gst_vaapi_window_x11_resize;
534   window_class->render = gst_vaapi_window_x11_render;
535   window_class->render_pixmap = gst_vaapi_window_x11_render_pixmap;
536 }
537
538 #define gst_vaapi_window_x11_finalize \
539     gst_vaapi_window_x11_destroy
540
541 GST_VAAPI_OBJECT_DEFINE_CLASS_WITH_CODE (GstVaapiWindowX11,
542     gst_vaapi_window_x11, gst_vaapi_window_x11_class_init (&g_class));
543
544 /**
545  * gst_vaapi_window_x11_new:
546  * @display: a #GstVaapiDisplay
547  * @width: the requested window width, in pixels
548  * @height: the requested windo height, in pixels
549  *
550  * Creates a window with the specified @width and @height. The window
551  * will be attached to the @display and remains invisible to the user
552  * until gst_vaapi_window_show() is called.
553  *
554  * Return value: the newly allocated #GstVaapiWindow object
555  */
556 GstVaapiWindow *
557 gst_vaapi_window_x11_new (GstVaapiDisplay * display, guint width, guint height)
558 {
559   GST_DEBUG ("new window, size %ux%u", width, height);
560
561   g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display), NULL);
562
563   return
564       gst_vaapi_window_new (GST_VAAPI_WINDOW_CLASS (gst_vaapi_window_x11_class
565           ()), display, width, height);
566 }
567
568 /**
569  * gst_vaapi_window_x11_new_with_xid:
570  * @display: a #GstVaapiDisplay
571  * @xid: an X11 #Window id
572  *
573  * Creates a #GstVaapiWindow using the X11 #Window @xid. The caller
574  * still owns the window and must call XDestroyWindow() when all
575  * #GstVaapiWindow references are released. Doing so too early can
576  * yield undefined behaviour.
577  *
578  * Return value: the newly allocated #GstVaapiWindow object
579  */
580 GstVaapiWindow *
581 gst_vaapi_window_x11_new_with_xid (GstVaapiDisplay * display, Window xid)
582 {
583   GST_DEBUG ("new window from xid 0x%08x", (guint) xid);
584
585   g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display), NULL);
586   g_return_val_if_fail (xid != None, NULL);
587
588   return
589       gst_vaapi_window_new_from_native (GST_VAAPI_WINDOW_CLASS
590       (gst_vaapi_window_x11_class ()), display, GINT_TO_POINTER (xid));
591 }
592
593 /**
594  * gst_vaapi_window_x11_get_xid:
595  * @window: a #GstVaapiWindowX11
596  *
597  * Returns the underlying X11 #Window that was created by
598  * gst_vaapi_window_x11_new() or that was bound with
599  * gst_vaapi_window_x11_new_with_xid().
600  *
601  * Return value: the underlying X11 #Window bound to @window.
602  */
603 Window
604 gst_vaapi_window_x11_get_xid (GstVaapiWindowX11 * window)
605 {
606   g_return_val_if_fail (window != NULL, None);
607
608   return GST_VAAPI_OBJECT_ID (window);
609 }
610
611 /**
612  * gst_vaapi_window_x11_is_foreign_xid:
613  * @window: a #GstVaapiWindowX11
614  *
615  * Checks whether the @window XID was created by gst_vaapi_window_x11_new() or bound with gst_vaapi_window_x11_new_with_xid().
616  *
617  * Return value: %TRUE if the underlying X window is owned by the
618  *   caller (foreign window)
619  */
620 gboolean
621 gst_vaapi_window_x11_is_foreign_xid (GstVaapiWindowX11 * window)
622 {
623   g_return_val_if_fail (window != NULL, FALSE);
624
625   return GST_VAAPI_WINDOW (window)->use_foreign_window;
626 }