diff --git a/gst-libs/gst/gl/gstglwindow.c b/gst-libs/gst/gl/gstglwindow.c index 6732a144c8..d3d9c45217 100644 --- a/gst-libs/gst/gl/gstglwindow.c +++ b/gst-libs/gst/gl/gstglwindow.c @@ -79,10 +79,16 @@ G_DEFINE_ABSTRACT_TYPE (GstGLWindow, gst_gl_window, GST_TYPE_OBJECT); static void gst_gl_window_default_send_message (GstGLWindow * window, GstGLWindowCB callback, gpointer data); +static gpointer gst_gl_window_navigation_thread (GstGLWindow * window); +void gst_gl_window_run_navigation (GstGLWindow * window); +void gst_gl_window_open_navigation (GstGLWindow * window); +void gst_gl_window_close_navigation (GstGLWindow * window); +void gst_gl_window_quit_navigation (GstGLWindow * window); struct _GstGLWindowPrivate { GThread *gl_thread; + GThread *navigation_thread; gboolean alive; }; @@ -128,6 +134,11 @@ gst_gl_window_init (GstGLWindow * window) window->priv = GST_GL_WINDOW_GET_PRIVATE (window); g_mutex_init (&window->lock); + g_mutex_init (&window->nav_lock); + g_cond_init (&window->nav_create_cond); + g_cond_init (&window->nav_destroy_cond); + window->nav_created = FALSE; + window->nav_alive = FALSE; window->is_drawing = FALSE; g_weak_ref_init (&window->context_ref, NULL); @@ -235,6 +246,17 @@ gst_gl_window_new (GstGLDisplay * display) window->display = gst_object_ref (display); + g_mutex_lock (&window->nav_lock); + + if (!window->nav_created) { + window->priv->navigation_thread = g_thread_new ("gstglnavigation", + (GThreadFunc) gst_gl_window_navigation_thread, window); + + g_cond_wait (&window->nav_create_cond, &window->nav_lock); + window->nav_created = TRUE; + } + g_mutex_unlock (&window->nav_lock); + return window; } @@ -243,9 +265,22 @@ gst_gl_window_finalize (GObject * object) { GstGLWindow *window = GST_GL_WINDOW (object); + if (window->nav_alive) { + g_mutex_lock (&window->nav_lock); + GST_INFO ("send quit navigation loop"); + gst_gl_window_quit_navigation (window); + while (window->nav_alive) { + g_cond_wait (&window->nav_destroy_cond, &window->nav_lock); + } + g_mutex_unlock (&window->nav_lock); + } + g_weak_ref_clear (&window->context_ref); g_mutex_clear (&window->lock); + g_mutex_clear (&window->nav_lock); + g_cond_clear (&window->nav_create_cond); + g_cond_clear (&window->nav_destroy_cond); gst_object_unref (window->display); G_OBJECT_CLASS (gst_gl_window_parent_class)->finalize (object); @@ -336,6 +371,21 @@ gst_gl_window_run (GstGLWindow * window) window_class->run (window); } +/** + * gst_gl_window_run_navigation: + * @window: a #GstGLWindow + * + * Start the execution of the navigation runloop. + */ +void +gst_gl_window_run_navigation (GstGLWindow * window) +{ + g_return_if_fail (GST_GL_IS_WINDOW (window)); + g_return_if_fail (window->navigation_context != NULL); + g_return_if_fail (window->navigation_loop != NULL); + g_main_loop_run (window->navigation_loop); +} + /** * gst_gl_window_quit: * @window: a #GstGLWindow @@ -613,7 +663,6 @@ gst_gl_window_get_surface_dimensions (GstGLWindow * window, guint * width, guint * height) { GstGLWindowClass *window_class; - g_return_if_fail (GST_GL_IS_WINDOW (window)); window_class = GST_GL_WINDOW_GET_CLASS (window); g_return_if_fail (window_class->get_surface_dimensions != NULL); @@ -660,6 +709,54 @@ gst_gl_dummy_window_run (GstGLWindow * window) g_main_loop_run (dummy->loop); } +void +gst_gl_window_open_navigation (GstGLWindow * window) +{ + g_return_if_fail (GST_GL_IS_WINDOW (window)); + g_mutex_lock (&window->nav_lock); + window->navigation_context = g_main_context_new (); + window->navigation_loop = g_main_loop_new (window->navigation_context, FALSE); + g_main_context_push_thread_default (window->navigation_context); + window->nav_alive = TRUE; + g_cond_signal (&window->nav_create_cond); + g_mutex_unlock (&window->nav_lock); +} + +void +gst_gl_window_close_navigation (GstGLWindow * window) +{ + g_return_if_fail (GST_GL_IS_WINDOW (window)); + g_return_if_fail (window->navigation_context != NULL); + g_return_if_fail (window->navigation_loop != NULL); + + g_mutex_lock (&window->nav_lock); + window->nav_alive = FALSE; + g_main_context_pop_thread_default (window->navigation_context); + g_main_loop_unref (window->navigation_loop); + g_main_context_unref (window->navigation_context); + g_cond_signal (&window->nav_destroy_cond); + g_mutex_unlock (&window->nav_lock); +} + +void +gst_gl_window_quit_navigation (GstGLWindow * window) +{ + g_return_if_fail (GST_GL_IS_WINDOW (window)); + + g_main_loop_quit (window->navigation_loop); +} + +static gpointer +gst_gl_window_navigation_thread (GstGLWindow * window) +{ + gst_gl_window_open_navigation (window); + gst_gl_window_run_navigation (window); + GST_INFO ("navigation loop exited\n"); + gst_gl_window_close_navigation (window); + + return NULL; +} + typedef struct _GstGLMessage { GstGLWindowCB callback; @@ -797,6 +894,20 @@ gst_gl_dummy_window_new (void) return g_object_new (gst_gl_dummy_window_get_type (), NULL); } +gboolean +gst_gl_window_key_event_cb (gpointer data) +{ + struct key_event *key_data = (struct key_event *) data; + GST_DEBUG + ("%s called data struct %p window %p key %s event %s ", + __func__, key_data, key_data->window, key_data->key_str, + key_data->event_type); + gst_gl_window_send_key_event (GST_GL_WINDOW (key_data->window), + key_data->event_type, key_data->key_str); + g_slice_free (struct key_event, key_data); + return G_SOURCE_REMOVE; +} + void gst_gl_window_send_key_event (GstGLWindow * window, const char *event_type, const char *key_str) @@ -805,6 +916,20 @@ gst_gl_window_send_key_event (GstGLWindow * window, const char *event_type, event_type, key_str); } +gboolean +gst_gl_window_mouse_event_cb (gpointer data) +{ + struct mouse_event *mouse_data = (struct mouse_event *) data; + GST_DEBUG ("%s called data struct %p mouse event %s button %d at %g, %g", + __func__, mouse_data, mouse_data->event_type, mouse_data->button, + mouse_data->posx, mouse_data->posy); + gst_gl_window_send_mouse_event (GST_GL_WINDOW (mouse_data->window), + mouse_data->event_type, mouse_data->button, mouse_data->posx, + mouse_data->posy); + g_slice_free (struct mouse_event, mouse_data); + return G_SOURCE_REMOVE; +} + void gst_gl_window_send_mouse_event (GstGLWindow * window, const char *event_type, int button, double posx, double posy) diff --git a/gst-libs/gst/gl/gstglwindow.h b/gst-libs/gst/gl/gstglwindow.h index 2337849941..6f244eadef 100644 --- a/gst-libs/gst/gl/gstglwindow.h +++ b/gst-libs/gst/gl/gstglwindow.h @@ -67,6 +67,11 @@ struct _GstGLWindow { GstObject parent; GMutex lock; + GMutex nav_lock; + GCond nav_create_cond; + GCond nav_destroy_cond; + gboolean nav_created; + gboolean nav_alive; GstGLDisplay *display; GWeakRef context_ref; @@ -87,6 +92,8 @@ struct _GstGLWindow { /*< private >*/ gpointer _reserved[GST_PADDING]; + GMainContext *navigation_context; + GMainLoop *navigation_loop; GstGLWindowPrivate *priv; }; @@ -129,6 +136,21 @@ struct _GstGLWindowClass { gpointer _reserved[GST_PADDING]; }; +struct key_event +{ + GstGLWindow *window; + const char *event_type; + const char *key_str; +}; + +struct mouse_event +{ + GstGLWindow *window; + const char *event_type; + int button; + double posx; + double posy; +}; /* methods */ GQuark gst_gl_window_error_quark (void); @@ -156,6 +178,12 @@ GstGLContext * gst_gl_window_get_context (GstGLWindow *window); gboolean gst_gl_window_is_running (GstGLWindow *window); +gboolean +gst_gl_window_key_event_cb (gpointer data); + +gboolean +gst_gl_window_mouse_event_cb (gpointer data); + void gst_gl_window_send_key_event(GstGLWindow * window, const char * event_type, const char * key_str); void gst_gl_window_send_mouse_event(GstGLWindow * window, const char * diff --git a/gst-libs/gst/gl/x11/gstglwindow_x11.c b/gst-libs/gst/gl/x11/gstglwindow_x11.c index b654a043c3..84c71af165 100644 --- a/gst-libs/gst/gl/x11/gstglwindow_x11.c +++ b/gst-libs/gst/gl/x11/gstglwindow_x11.c @@ -507,6 +507,9 @@ gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11) gboolean ret = TRUE; const char *key_str = NULL; KeySym keysym; + struct mouse_event *mouse_data; + struct key_event *key_data; + XWindowAttributes attr; window = GST_GL_WINDOW (window_x11); @@ -516,6 +519,10 @@ gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11) /* XSendEvent (which are called in other threads) are done from another display structure */ XNextEvent (window_x11->device, &event); + XGetWindowAttributes (window_x11->device, window_x11->internal_win_id, + &attr); + window_x11->current_width = attr.width; + window_x11->current_height = attr.height; window_x11->allow_extra_expose_events = XPending (window_x11->device) <= 2; @@ -583,26 +590,44 @@ gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11) keysym = XkbKeycodeToKeysym (window_x11->device, event.xkey.keycode, 0, 0); key_str = XKeysymToString (keysym); + key_data = g_slice_new (struct key_event); + key_data->window = window; + key_data->key_str = XKeysymToString (keysym); + key_data->event_type = + event.type == KeyPress ? "key-press" : "key-release"; GST_DEBUG ("input event key %d pressed over window at %d,%d (%s)", event.xkey.keycode, event.xkey.x, event.xkey.y, key_str); - gst_gl_window_send_key_event (window, - event.type == KeyPress ? "key-press" : "key-release", key_str); + g_main_context_invoke (window->navigation_context, + (GSourceFunc) gst_gl_window_key_event_cb, key_data); break; case ButtonPress: case ButtonRelease: GST_DEBUG ("input event mouse button %d pressed over window at %d,%d", event.xbutton.button, event.xbutton.x, event.xbutton.y); - gst_gl_window_send_mouse_event (window, + mouse_data = g_slice_new (struct mouse_event); + mouse_data->window = window; + mouse_data->event_type = event.type == - ButtonPress ? "mouse-button-press" : "mouse-button-release", - event.xbutton.button, (double) event.xbutton.x, - (double) event.xbutton.y); + ButtonPress ? "mouse-button-press" : "mouse-button-release"; + mouse_data->button = event.xbutton.button; + mouse_data->posx = (double) event.xbutton.x; + mouse_data->posy = (double) event.xbutton.y; + + g_main_context_invoke (window->navigation_context, + (GSourceFunc) gst_gl_window_mouse_event_cb, mouse_data); break; case MotionNotify: GST_DEBUG ("input event pointer moved over window at %d,%d", event.xmotion.x, event.xmotion.y); - gst_gl_window_send_mouse_event (window, "mouse-move", 0, - (double) event.xmotion.x, (double) event.xmotion.y); + mouse_data = g_slice_new (struct mouse_event); + mouse_data->window = window; + mouse_data->event_type = "mouse-move"; + mouse_data->button = 0; + mouse_data->posx = (double) event.xbutton.x; + mouse_data->posy = (double) event.xbutton.y; + + g_main_context_invoke (window->navigation_context, (GSourceFunc) + gst_gl_window_mouse_event_cb, mouse_data); break; default: GST_DEBUG ("unknown XEvent type: %u", event.type); @@ -715,10 +740,8 @@ gst_gl_window_x11_get_surface_dimensions (GstGLWindow * window, guint * width, guint * height) { GstGLWindowX11 *window_x11 = GST_GL_WINDOW_X11 (window); - XWindowAttributes attr; - XGetWindowAttributes (window_x11->device, window_x11->internal_win_id, &attr); if (width != NULL) - *width = attr.width; + *width = window_x11->current_width; if (height != NULL) - *height = attr.height; + *height = window_x11->current_height; } diff --git a/gst-libs/gst/gl/x11/gstglwindow_x11.h b/gst-libs/gst/gl/x11/gstglwindow_x11.h index 02a3aaaeac..56e876db03 100644 --- a/gst-libs/gst/gl/x11/gstglwindow_x11.h +++ b/gst-libs/gst/gl/x11/gstglwindow_x11.h @@ -64,6 +64,8 @@ struct _GstGLWindowX11 gint depth; gint device_width; gint device_height; + gint current_width; + gint current_height; gint connection; XVisualInfo *visual_info; Window parent_win;