• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  * Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <stdio.h>
26 
27 #include "gtkgstbasewidget.h"
28 
29 GST_DEBUG_CATEGORY (gst_debug_gtk_base_widget);
30 #define GST_CAT_DEFAULT gst_debug_gtk_base_widget
31 
32 #define DEFAULT_FORCE_ASPECT_RATIO  TRUE
33 #define DEFAULT_DISPLAY_PAR_N       0
34 #define DEFAULT_DISPLAY_PAR_D       1
35 #define DEFAULT_VIDEO_PAR_N         0
36 #define DEFAULT_VIDEO_PAR_D         1
37 #define DEFAULT_IGNORE_ALPHA        TRUE
38 
39 enum
40 {
41   PROP_0,
42   PROP_FORCE_ASPECT_RATIO,
43   PROP_PIXEL_ASPECT_RATIO,
44   PROP_IGNORE_ALPHA,
45   PROP_VIDEO_ASPECT_RATIO_OVERRIDE,
46 };
47 
48 static gboolean
_calculate_par(GtkGstBaseWidget * widget,GstVideoInfo * info)49 _calculate_par (GtkGstBaseWidget * widget, GstVideoInfo * info)
50 {
51   gboolean ok;
52   gint width, height;
53   gint par_n, par_d;
54   gint display_par_n, display_par_d;
55 
56   width = GST_VIDEO_INFO_WIDTH (info);
57   height = GST_VIDEO_INFO_HEIGHT (info);
58   if (width == 0 || height == 0)
59     return FALSE;
60 
61   /* get video's PAR */
62   if (widget->video_par_n != 0 && widget->video_par_d != 0) {
63     par_n = widget->video_par_n;
64     par_d = widget->video_par_d;
65   } else {
66     par_n = GST_VIDEO_INFO_PAR_N (info);
67     par_d = GST_VIDEO_INFO_PAR_D (info);
68   }
69 
70   if (!par_n)
71     par_n = 1;
72 
73   /* get display's PAR */
74   if (widget->par_n != 0 && widget->par_d != 0) {
75     display_par_n = widget->par_n;
76     display_par_d = widget->par_d;
77   } else {
78     display_par_n = 1;
79     display_par_d = 1;
80   }
81 
82 
83   ok = gst_video_calculate_display_ratio (&widget->display_ratio_num,
84       &widget->display_ratio_den, width, height, par_n, par_d, display_par_n,
85       display_par_d);
86 
87   if (ok) {
88     GST_LOG ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n,
89         display_par_d);
90     return TRUE;
91   }
92 
93   return FALSE;
94 }
95 
96 static void
_apply_par(GtkGstBaseWidget * widget)97 _apply_par (GtkGstBaseWidget * widget)
98 {
99   guint display_ratio_num, display_ratio_den;
100   gint width, height;
101 
102   width = GST_VIDEO_INFO_WIDTH (&widget->v_info);
103   height = GST_VIDEO_INFO_HEIGHT (&widget->v_info);
104 
105   if (!width || !height)
106     return;
107 
108   display_ratio_num = widget->display_ratio_num;
109   display_ratio_den = widget->display_ratio_den;
110 
111   if (height % display_ratio_den == 0) {
112     GST_DEBUG ("keeping video height");
113     widget->display_width = (guint)
114         gst_util_uint64_scale_int (height, display_ratio_num,
115         display_ratio_den);
116     widget->display_height = height;
117   } else if (width % display_ratio_num == 0) {
118     GST_DEBUG ("keeping video width");
119     widget->display_width = width;
120     widget->display_height = (guint)
121         gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num);
122   } else {
123     GST_DEBUG ("approximating while keeping video height");
124     widget->display_width = (guint)
125         gst_util_uint64_scale_int (height, display_ratio_num,
126         display_ratio_den);
127     widget->display_height = height;
128   }
129 
130   GST_DEBUG ("scaling to %dx%d", widget->display_width, widget->display_height);
131 }
132 
133 static gboolean
_queue_draw(GtkGstBaseWidget * widget)134 _queue_draw (GtkGstBaseWidget * widget)
135 {
136   GTK_GST_BASE_WIDGET_LOCK (widget);
137   widget->draw_id = 0;
138 
139   if (widget->pending_resize) {
140     widget->pending_resize = FALSE;
141 
142     widget->v_info = widget->pending_v_info;
143     widget->negotiated = TRUE;
144 
145     _apply_par (widget);
146 
147     gtk_widget_queue_resize (GTK_WIDGET (widget));
148   } else {
149     gtk_widget_queue_draw (GTK_WIDGET (widget));
150   }
151 
152   GTK_GST_BASE_WIDGET_UNLOCK (widget);
153 
154   return G_SOURCE_REMOVE;
155 }
156 
157 static void
_update_par(GtkGstBaseWidget * widget)158 _update_par (GtkGstBaseWidget * widget)
159 {
160   GTK_GST_BASE_WIDGET_LOCK (widget);
161   if (widget->pending_resize) {
162     GTK_GST_BASE_WIDGET_UNLOCK (widget);
163     return;
164   }
165 
166   if (!_calculate_par (widget, &widget->v_info)) {
167     GTK_GST_BASE_WIDGET_UNLOCK (widget);
168     return;
169   }
170 
171   widget->pending_resize = TRUE;
172   if (!widget->draw_id) {
173     widget->draw_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10,
174         (GSourceFunc) _queue_draw, widget, NULL);
175   }
176   GTK_GST_BASE_WIDGET_UNLOCK (widget);
177 }
178 
179 static void
gtk_gst_base_widget_get_preferred_width(GtkWidget * widget,gint * min,gint * natural)180 gtk_gst_base_widget_get_preferred_width (GtkWidget * widget, gint * min,
181     gint * natural)
182 {
183   GtkGstBaseWidget *gst_widget = (GtkGstBaseWidget *) widget;
184   gint video_width = gst_widget->display_width;
185 
186   if (!gst_widget->negotiated)
187     video_width = 10;
188 
189   if (min)
190     *min = 1;
191   if (natural)
192     *natural = video_width;
193 }
194 
195 static void
gtk_gst_base_widget_get_preferred_height(GtkWidget * widget,gint * min,gint * natural)196 gtk_gst_base_widget_get_preferred_height (GtkWidget * widget, gint * min,
197     gint * natural)
198 {
199   GtkGstBaseWidget *gst_widget = (GtkGstBaseWidget *) widget;
200   gint video_height = gst_widget->display_height;
201 
202   if (!gst_widget->negotiated)
203     video_height = 10;
204 
205   if (min)
206     *min = 1;
207   if (natural)
208     *natural = video_height;
209 }
210 
211 static void
gtk_gst_base_widget_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)212 gtk_gst_base_widget_set_property (GObject * object, guint prop_id,
213     const GValue * value, GParamSpec * pspec)
214 {
215   GtkGstBaseWidget *gtk_widget = GTK_GST_BASE_WIDGET (object);
216 
217   switch (prop_id) {
218     case PROP_FORCE_ASPECT_RATIO:
219       gtk_widget->force_aspect_ratio = g_value_get_boolean (value);
220       break;
221     case PROP_PIXEL_ASPECT_RATIO:
222       gtk_widget->par_n = gst_value_get_fraction_numerator (value);
223       gtk_widget->par_d = gst_value_get_fraction_denominator (value);
224       _update_par (gtk_widget);
225       break;
226     case PROP_VIDEO_ASPECT_RATIO_OVERRIDE:
227       gtk_widget->video_par_n = gst_value_get_fraction_numerator (value);
228       gtk_widget->video_par_d = gst_value_get_fraction_denominator (value);
229       _update_par (gtk_widget);
230       break;
231     case PROP_IGNORE_ALPHA:
232       gtk_widget->ignore_alpha = g_value_get_boolean (value);
233       break;
234     default:
235       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
236       break;
237   }
238 }
239 
240 static void
gtk_gst_base_widget_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)241 gtk_gst_base_widget_get_property (GObject * object, guint prop_id,
242     GValue * value, GParamSpec * pspec)
243 {
244   GtkGstBaseWidget *gtk_widget = GTK_GST_BASE_WIDGET (object);
245 
246   switch (prop_id) {
247     case PROP_FORCE_ASPECT_RATIO:
248       g_value_set_boolean (value, gtk_widget->force_aspect_ratio);
249       break;
250     case PROP_PIXEL_ASPECT_RATIO:
251       gst_value_set_fraction (value, gtk_widget->par_n, gtk_widget->par_d);
252       break;
253     case PROP_VIDEO_ASPECT_RATIO_OVERRIDE:
254       gst_value_set_fraction (value, gtk_widget->video_par_n,
255           gtk_widget->video_par_d);
256       break;
257     case PROP_IGNORE_ALPHA:
258       g_value_set_boolean (value, gtk_widget->ignore_alpha);
259       break;
260     default:
261       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
262       break;
263   }
264 }
265 
266 static const gchar *
_gdk_key_to_navigation_string(guint keyval)267 _gdk_key_to_navigation_string (guint keyval)
268 {
269   /* TODO: expand */
270   switch (keyval) {
271 #define KEY(key) case GDK_KEY_ ## key: return G_STRINGIFY(key)
272       KEY (Up);
273       KEY (Down);
274       KEY (Left);
275       KEY (Right);
276       KEY (Home);
277       KEY (End);
278 #undef KEY
279     default:
280       return NULL;
281   }
282 }
283 
284 static gboolean
gtk_gst_base_widget_key_event(GtkWidget * widget,GdkEventKey * event)285 gtk_gst_base_widget_key_event (GtkWidget * widget, GdkEventKey * event)
286 {
287   GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget);
288   GstElement *element;
289 
290   if ((element = g_weak_ref_get (&base_widget->element))) {
291     if (GST_IS_NAVIGATION (element)) {
292       const gchar *str = _gdk_key_to_navigation_string (event->keyval);
293       const gchar *key_type =
294           event->type == GDK_KEY_PRESS ? "key-press" : "key-release";
295 
296       if (!str)
297         str = event->string;
298 
299       gst_navigation_send_key_event (GST_NAVIGATION (element), key_type, str);
300     }
301     g_object_unref (element);
302   }
303 
304   return FALSE;
305 }
306 
307 static void
_fit_stream_to_allocated_size(GtkGstBaseWidget * base_widget,GtkAllocation * allocation,GstVideoRectangle * result)308 _fit_stream_to_allocated_size (GtkGstBaseWidget * base_widget,
309     GtkAllocation * allocation, GstVideoRectangle * result)
310 {
311   if (base_widget->force_aspect_ratio) {
312     GstVideoRectangle src, dst;
313 
314     src.x = 0;
315     src.y = 0;
316     src.w = base_widget->display_width;
317     src.h = base_widget->display_height;
318 
319     dst.x = 0;
320     dst.y = 0;
321     dst.w = allocation->width;
322     dst.h = allocation->height;
323 
324     gst_video_sink_center_rect (src, dst, result, TRUE);
325   } else {
326     result->x = 0;
327     result->y = 0;
328     result->w = allocation->width;
329     result->h = allocation->height;
330   }
331 }
332 
333 void
gtk_gst_base_widget_display_size_to_stream_size(GtkGstBaseWidget * base_widget,gdouble x,gdouble y,gdouble * stream_x,gdouble * stream_y)334 gtk_gst_base_widget_display_size_to_stream_size (GtkGstBaseWidget * base_widget,
335     gdouble x, gdouble y, gdouble * stream_x, gdouble * stream_y)
336 {
337   gdouble stream_width, stream_height;
338   GtkAllocation allocation;
339   GstVideoRectangle result;
340 
341   gtk_widget_get_allocation (GTK_WIDGET (base_widget), &allocation);
342   _fit_stream_to_allocated_size (base_widget, &allocation, &result);
343 
344   stream_width = (gdouble) GST_VIDEO_INFO_WIDTH (&base_widget->v_info);
345   stream_height = (gdouble) GST_VIDEO_INFO_HEIGHT (&base_widget->v_info);
346 
347   /* from display coordinates to stream coordinates */
348   if (result.w > 0)
349     *stream_x = (x - result.x) / result.w * stream_width;
350   else
351     *stream_x = 0.;
352 
353   /* clip to stream size */
354   if (*stream_x < 0.)
355     *stream_x = 0.;
356   if (*stream_x > GST_VIDEO_INFO_WIDTH (&base_widget->v_info))
357     *stream_x = GST_VIDEO_INFO_WIDTH (&base_widget->v_info);
358 
359   /* same for y-axis */
360   if (result.h > 0)
361     *stream_y = (y - result.y) / result.h * stream_height;
362   else
363     *stream_y = 0.;
364 
365   if (*stream_y < 0.)
366     *stream_y = 0.;
367   if (*stream_y > GST_VIDEO_INFO_HEIGHT (&base_widget->v_info))
368     *stream_y = GST_VIDEO_INFO_HEIGHT (&base_widget->v_info);
369 
370   GST_TRACE ("transform %fx%f into %fx%f", x, y, *stream_x, *stream_y);
371 }
372 
373 static gboolean
gtk_gst_base_widget_button_event(GtkWidget * widget,GdkEventButton * event)374 gtk_gst_base_widget_button_event (GtkWidget * widget, GdkEventButton * event)
375 {
376   GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget);
377   GstElement *element;
378 
379   if ((element = g_weak_ref_get (&base_widget->element))) {
380     if (GST_IS_NAVIGATION (element)) {
381       const gchar *key_type =
382           event->type ==
383           GDK_BUTTON_PRESS ? "mouse-button-press" : "mouse-button-release";
384       gst_navigation_send_mouse_event (GST_NAVIGATION (element), key_type,
385           event->button, event->x, event->y);
386     }
387     g_object_unref (element);
388   }
389 
390   return FALSE;
391 }
392 
393 static gboolean
gtk_gst_base_widget_motion_event(GtkWidget * widget,GdkEventMotion * event)394 gtk_gst_base_widget_motion_event (GtkWidget * widget, GdkEventMotion * event)
395 {
396   GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget);
397   GstElement *element;
398 
399   if ((element = g_weak_ref_get (&base_widget->element))) {
400     if (GST_IS_NAVIGATION (element)) {
401       gst_navigation_send_mouse_event (GST_NAVIGATION (element), "mouse-move",
402           0, event->x, event->y);
403     }
404     g_object_unref (element);
405   }
406 
407   return FALSE;
408 }
409 
410 static gboolean
gtk_gst_base_widget_scroll_event(GtkWidget * widget,GdkEventScroll * event)411 gtk_gst_base_widget_scroll_event (GtkWidget * widget, GdkEventScroll * event)
412 {
413   GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget);
414   GstElement *element;
415 
416   if ((element = g_weak_ref_get (&base_widget->element))) {
417     if (GST_IS_NAVIGATION (element)) {
418       gdouble x, y, delta_x, delta_y;
419 
420       gtk_gst_base_widget_display_size_to_stream_size (base_widget, event->x,
421           event->y, &x, &y);
422 
423       if (!gdk_event_get_scroll_deltas ((GdkEvent *) event, &delta_x, &delta_y)) {
424         gdouble offset = 20;
425 
426         delta_x = event->delta_x;
427         delta_y = event->delta_y;
428 
429         switch (event->direction) {
430           case GDK_SCROLL_UP:
431             delta_y = offset;
432             break;
433           case GDK_SCROLL_DOWN:
434             delta_y = -offset;
435             break;
436           case GDK_SCROLL_LEFT:
437             delta_x = -offset;
438             break;
439           case GDK_SCROLL_RIGHT:
440             delta_x = offset;
441             break;
442           default:
443             break;
444         }
445       }
446       gst_navigation_send_mouse_scroll_event (GST_NAVIGATION (element),
447           x, y, delta_x, delta_y);
448     }
449     g_object_unref (element);
450   }
451   return FALSE;
452 }
453 
454 
455 void
gtk_gst_base_widget_class_init(GtkGstBaseWidgetClass * klass)456 gtk_gst_base_widget_class_init (GtkGstBaseWidgetClass * klass)
457 {
458   GObjectClass *gobject_klass = (GObjectClass *) klass;
459   GtkWidgetClass *widget_klass = (GtkWidgetClass *) klass;
460 
461   gobject_klass->set_property = gtk_gst_base_widget_set_property;
462   gobject_klass->get_property = gtk_gst_base_widget_get_property;
463 
464   g_object_class_install_property (gobject_klass, PROP_FORCE_ASPECT_RATIO,
465       g_param_spec_boolean ("force-aspect-ratio",
466           "Force aspect ratio",
467           "When enabled, scaling will respect original aspect ratio",
468           DEFAULT_FORCE_ASPECT_RATIO,
469           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
470           GST_PARAM_MUTABLE_PLAYING));
471 
472   g_object_class_install_property (gobject_klass, PROP_PIXEL_ASPECT_RATIO,
473       gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio",
474           "The pixel aspect ratio of the device",
475           0, 1, G_MAXINT, G_MAXINT, DEFAULT_DISPLAY_PAR_N,
476           DEFAULT_DISPLAY_PAR_D, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
477           GST_PARAM_MUTABLE_PLAYING));
478 
479   g_object_class_install_property (gobject_klass,
480       PROP_VIDEO_ASPECT_RATIO_OVERRIDE,
481       gst_param_spec_fraction ("video-aspect-ratio-override",
482           "Video Pixel Aspect Ratio",
483           "The pixel aspect ratio of the video (0/1 = follow stream)", 0,
484           G_MAXINT, G_MAXINT, 1, DEFAULT_VIDEO_PAR_N, DEFAULT_VIDEO_PAR_D,
485           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
486           GST_PARAM_MUTABLE_PLAYING));
487 
488   g_object_class_install_property (gobject_klass, PROP_IGNORE_ALPHA,
489       g_param_spec_boolean ("ignore-alpha", "Ignore Alpha",
490           "When enabled, alpha will be ignored and converted to black",
491           DEFAULT_IGNORE_ALPHA, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
492 
493   widget_klass->get_preferred_width = gtk_gst_base_widget_get_preferred_width;
494   widget_klass->get_preferred_height = gtk_gst_base_widget_get_preferred_height;
495   widget_klass->key_press_event = gtk_gst_base_widget_key_event;
496   widget_klass->key_release_event = gtk_gst_base_widget_key_event;
497   widget_klass->button_press_event = gtk_gst_base_widget_button_event;
498   widget_klass->button_release_event = gtk_gst_base_widget_button_event;
499   widget_klass->motion_notify_event = gtk_gst_base_widget_motion_event;
500   widget_klass->scroll_event = gtk_gst_base_widget_scroll_event;
501 
502   GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_widget, "gtkbasewidget", 0,
503       "Gtk Video Base Widget");
504 }
505 
506 void
gtk_gst_base_widget_init(GtkGstBaseWidget * widget)507 gtk_gst_base_widget_init (GtkGstBaseWidget * widget)
508 {
509   int event_mask;
510 
511   widget->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
512   widget->par_n = DEFAULT_DISPLAY_PAR_N;
513   widget->par_d = DEFAULT_DISPLAY_PAR_D;
514   widget->video_par_n = DEFAULT_VIDEO_PAR_N;
515   widget->video_par_d = DEFAULT_VIDEO_PAR_D;
516   widget->ignore_alpha = DEFAULT_IGNORE_ALPHA;
517 
518   gst_video_info_init (&widget->v_info);
519   gst_video_info_init (&widget->pending_v_info);
520 
521   g_weak_ref_init (&widget->element, NULL);
522   g_mutex_init (&widget->lock);
523 
524   gtk_widget_set_can_focus (GTK_WIDGET (widget), TRUE);
525   event_mask = gtk_widget_get_events (GTK_WIDGET (widget));
526   event_mask |= GDK_KEY_PRESS_MASK
527       | GDK_KEY_RELEASE_MASK
528       | GDK_BUTTON_PRESS_MASK
529       | GDK_BUTTON_RELEASE_MASK
530       | GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_SCROLL_MASK;
531   gtk_widget_set_events (GTK_WIDGET (widget), event_mask);
532 }
533 
534 void
gtk_gst_base_widget_finalize(GObject * object)535 gtk_gst_base_widget_finalize (GObject * object)
536 {
537   GtkGstBaseWidget *widget = GTK_GST_BASE_WIDGET (object);
538 
539   gst_buffer_replace (&widget->pending_buffer, NULL);
540   gst_buffer_replace (&widget->buffer, NULL);
541   g_mutex_clear (&widget->lock);
542   g_weak_ref_clear (&widget->element);
543 
544   if (widget->draw_id)
545     g_source_remove (widget->draw_id);
546 }
547 
548 void
gtk_gst_base_widget_set_element(GtkGstBaseWidget * widget,GstElement * element)549 gtk_gst_base_widget_set_element (GtkGstBaseWidget * widget,
550     GstElement * element)
551 {
552   g_weak_ref_set (&widget->element, element);
553 }
554 
555 gboolean
gtk_gst_base_widget_set_format(GtkGstBaseWidget * widget,GstVideoInfo * v_info)556 gtk_gst_base_widget_set_format (GtkGstBaseWidget * widget,
557     GstVideoInfo * v_info)
558 {
559   GTK_GST_BASE_WIDGET_LOCK (widget);
560 
561   if (gst_video_info_is_equal (&widget->pending_v_info, v_info)) {
562     GTK_GST_BASE_WIDGET_UNLOCK (widget);
563     return TRUE;
564   }
565 
566   if (!_calculate_par (widget, v_info)) {
567     GTK_GST_BASE_WIDGET_UNLOCK (widget);
568     return FALSE;
569   }
570 
571   widget->pending_resize = TRUE;
572   widget->pending_v_info = *v_info;
573 
574   GTK_GST_BASE_WIDGET_UNLOCK (widget);
575 
576   return TRUE;
577 }
578 
579 void
gtk_gst_base_widget_set_buffer(GtkGstBaseWidget * widget,GstBuffer * buffer)580 gtk_gst_base_widget_set_buffer (GtkGstBaseWidget * widget, GstBuffer * buffer)
581 {
582   /* As we have no type, this is better then no check */
583   g_return_if_fail (GTK_IS_WIDGET (widget));
584 
585   GTK_GST_BASE_WIDGET_LOCK (widget);
586 
587   gst_buffer_replace (&widget->pending_buffer, buffer);
588 
589   if (!widget->draw_id) {
590     widget->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT,
591         (GSourceFunc) _queue_draw, widget, NULL);
592   }
593 
594   GTK_GST_BASE_WIDGET_UNLOCK (widget);
595 }
596 
597 void
gtk_gst_base_widget_queue_draw(GtkGstBaseWidget * widget)598 gtk_gst_base_widget_queue_draw (GtkGstBaseWidget * widget)
599 {
600   /* As we have no type, this is better then no check */
601   g_return_if_fail (GTK_IS_WIDGET (widget));
602 
603   GTK_GST_BASE_WIDGET_LOCK (widget);
604 
605   if (!widget->draw_id) {
606     widget->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT,
607         (GSourceFunc) _queue_draw, widget, NULL);
608   }
609 
610   GTK_GST_BASE_WIDGET_UNLOCK (widget);
611 }
612