diff --git a/gst-libs/gst/vulkan/xcb/gstvkwindow_xcb.c b/gst-libs/gst/vulkan/xcb/gstvkwindow_xcb.c index efcf64098e..9790606e03 100644 --- a/gst-libs/gst/vulkan/xcb/gstvkwindow_xcb.c +++ b/gst-libs/gst/vulkan/xcb/gstvkwindow_xcb.c @@ -45,8 +45,6 @@ _init_debug (void) } } -gboolean gst_vulkan_window_xcb_handle_event (GstVulkanWindowXCB * window_xcb); - enum { PROP_0, @@ -61,6 +59,7 @@ struct _GstVulkanWindowXCBPrivate gint preferred_height; xcb_intern_atom_reply_t *atom_wm_delete_window; + gboolean handle_events; }; #define gst_vulkan_window_xcb_parent_class parent_class @@ -74,6 +73,8 @@ static gboolean gst_vulkan_window_xcb_get_presentation_support (GstVulkanWindow static gboolean gst_vulkan_window_xcb_open (GstVulkanWindow * window, GError ** error); static void gst_vulkan_window_xcb_close (GstVulkanWindow * window); +static void gst_vulkan_window_xcb_handle_events (GstVulkanWindow * window, + gboolean handle_events); static void gst_vulkan_window_xcb_finalize (GObject * object) @@ -92,6 +93,7 @@ gst_vulkan_window_xcb_class_init (GstVulkanWindowXCBClass * klass) window_class->open = GST_DEBUG_FUNCPTR (gst_vulkan_window_xcb_open); window_class->close = GST_DEBUG_FUNCPTR (gst_vulkan_window_xcb_close); window_class->get_surface = gst_vulkan_window_xcb_get_surface; + window_class->handle_events = gst_vulkan_window_xcb_handle_events; window_class->get_presentation_support = gst_vulkan_window_xcb_get_presentation_support; } @@ -99,6 +101,9 @@ gst_vulkan_window_xcb_class_init (GstVulkanWindowXCBClass * klass) static void gst_vulkan_window_xcb_init (GstVulkanWindowXCB * window) { + GstVulkanWindowXCBPrivate *priv = GET_PRIV (window); + + priv->handle_events = TRUE; } /* Must be called in the gl thread */ @@ -155,6 +160,7 @@ gst_vulkan_window_xcb_hide (GstVulkanWindow * window) gboolean gst_vulkan_window_xcb_create_window (GstVulkanWindowXCB * window_xcb) { + GstVulkanWindowXCBPrivate *priv = GET_PRIV (window_xcb); GstVulkanDisplayXCB *display_xcb; xcb_connection_t *connection; xcb_screen_t *screen; @@ -183,6 +189,9 @@ gst_vulkan_window_xcb_create_window (GstVulkanWindowXCB * window_xcb) root_window, x, y, width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, value_mask, value_list); + gst_vulkan_window_xcb_handle_events (GST_VULKAN_WINDOW (window_xcb), + priv->handle_events); + GST_LOG_OBJECT (window_xcb, "vulkan window id: %p", (gpointer) (guintptr) window_xcb->win_id); GST_LOG_OBJECT (window_xcb, "vulkan window props: x:%d y:%d", x, y); @@ -316,3 +325,139 @@ gst_vulkan_window_xcb_close (GstVulkanWindow * window) GST_VULKAN_WINDOW_CLASS (parent_class)->close (window); } + +G_GNUC_INTERNAL + gboolean +gst_vulkan_window_xcb_handle_event (GstVulkanWindowXCB * window_xcb, + xcb_generic_event_t * event); + +gboolean +gst_vulkan_window_xcb_handle_event (GstVulkanWindowXCB * window_xcb, + xcb_generic_event_t * event) +{ + GstVulkanDisplayXCB *display_xcb = + GST_VULKAN_DISPLAY_XCB (window_xcb->parent.display); + xcb_connection_t *connection = + GST_VULKAN_DISPLAY_XCB_CONNECTION (display_xcb); + uint8_t event_code = event->response_type & 0x7f; + + switch (event_code) { + case XCB_CLIENT_MESSAGE:{ + xcb_client_message_event_t *client_event; + xcb_intern_atom_cookie_t cookie; + xcb_intern_atom_reply_t *reply; + + client_event = (xcb_client_message_event_t *) event; + cookie = xcb_intern_atom (connection, 0, 16, "WM_DELETE_WINDOW"); + reply = xcb_intern_atom_reply (connection, cookie, 0); + + if (client_event->data.data32[0] == reply->atom) { + GST_INFO_OBJECT (window_xcb, "Close requested"); + + gst_vulkan_window_close (GST_VULKAN_WINDOW (window_xcb)); + gst_vulkan_display_remove_window (GST_VULKAN_DISPLAY (display_xcb), + GST_VULKAN_WINDOW (window_xcb)); + } + + g_free (reply); + break; + } + case XCB_CONFIGURE_NOTIFY:{ + xcb_configure_notify_event_t *configure_event; + + configure_event = (xcb_configure_notify_event_t *) event; + + gst_vulkan_window_resize (GST_VULKAN_WINDOW (window_xcb), + configure_event->width, configure_event->height); + break; + } + case XCB_EXPOSE:{ + xcb_expose_event_t *expose_event = (xcb_expose_event_t *) event; + + /* non-zero means that other Expose follows + * so just wait for the last one + * in theory we should not receive non-zero because + * we have no sub areas here but just in case */ + if (expose_event->count != 0) + break; + + gst_vulkan_window_redraw (GST_VULKAN_WINDOW (window_xcb)); + break; + } +#if 0 + case XCB_KEY_PRESS: + case XCB_KEY_RELEASE:{ + xcb_key_press_event_t *kp = (xcb_key_press_event_t *) event; + const gchar *event_type_str; + gchar *key_str; + KeySym keysym; + + keysym = XkbKeycodeToKeysym (connection, kp->detail, 0, 0); + key_str = XKeysymToString (keysym); + + if (event_code == XCB_KEY_PRESS) + event_type_str = "key-press"; + else + event_type_str = "key-release"; + + gst_vulkan_window_send_key_event (window, event_type_str, key_str); + break; + } +#endif + case XCB_BUTTON_PRESS: + case XCB_BUTTON_RELEASE:{ + xcb_button_press_event_t *bp = (xcb_button_press_event_t *) event; + const gchar *event_type_str; + + if (event_code == XCB_BUTTON_PRESS) + event_type_str = "mouse-button-press"; + else + event_type_str = "mouse-button-release"; + + gst_vulkan_window_send_mouse_event (GST_VULKAN_WINDOW (window_xcb), + event_type_str, bp->detail, (double) bp->event_x, + (double) bp->event_y); + break; + } + case XCB_MOTION_NOTIFY:{ + xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *) event; + + gst_vulkan_window_send_mouse_event (GST_VULKAN_WINDOW (window_xcb), + "mouse-move", 0, (double) motion->event_x, (double) motion->event_y); + break; + } + default: + GST_DEBUG ("unhandled XCB type: %u", event_code); + break; + } + + return TRUE; +} + +static void +gst_vulkan_window_xcb_handle_events (GstVulkanWindow * window, + gboolean handle_events) +{ + GstVulkanDisplayXCB *display_xcb = GST_VULKAN_DISPLAY_XCB (window->display); + xcb_connection_t *connection = + GST_VULKAN_DISPLAY_XCB_CONNECTION (display_xcb); + GstVulkanWindowXCB *window_xcb = GST_VULKAN_WINDOW_XCB (window); + GstVulkanWindowXCBPrivate *priv = GET_PRIV (window_xcb); + + priv->handle_events = handle_events; + + if (window_xcb->win_id) { + guint32 events; + + events = XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_EXPOSURE + | XCB_EVENT_MASK_VISIBILITY_CHANGE; + if (handle_events) { + events |= XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_EXPOSURE + | XCB_EVENT_MASK_VISIBILITY_CHANGE | XCB_EVENT_MASK_POINTER_MOTION + | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE + | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE; + } + xcb_change_window_attributes (connection, + window_xcb->win_id, XCB_CW_EVENT_MASK, &events); + } +} diff --git a/gst-libs/gst/vulkan/xcb/xcb_event_source.c b/gst-libs/gst/vulkan/xcb/xcb_event_source.c index f8cebebf13..d55f3ce4e4 100644 --- a/gst-libs/gst/vulkan/xcb/xcb_event_source.c +++ b/gst-libs/gst/vulkan/xcb/xcb_event_source.c @@ -33,20 +33,14 @@ #include "xcb_event_source.h" static gint -_compare_xcb_window (GWeakRef * ref, xcb_window_t * window_id) +_compare_xcb_window (GstVulkanWindowXCB * window_xcb, xcb_window_t * window_id) { - GstVulkanWindowXCB *window_xcb; gint ret; - window_xcb = g_weak_ref_get (ref); - if (!window_xcb) - return -1; - g_return_val_if_fail (GST_IS_VULKAN_WINDOW_XCB (window_xcb), -1); g_return_val_if_fail (window_id != 0, -1); ret = window_xcb->win_id - *window_id; - gst_object_unref (window_xcb); return ret; } @@ -56,23 +50,47 @@ _find_window_from_xcb_window (GstVulkanDisplayXCB * display_xcb, xcb_window_t window_id) { GstVulkanDisplay *display = GST_VULKAN_DISPLAY (display_xcb); - GstVulkanWindowXCB *ret = NULL; - GList *l; if (!window_id) return NULL; - GST_OBJECT_LOCK (display); - l = g_list_find_custom (display->windows, &window_id, - (GCompareFunc) _compare_xcb_window); - if (l) { - ret = g_weak_ref_get (l->data); - } - GST_OBJECT_UNLOCK (display); - - return ret; + return (GstVulkanWindowXCB *) gst_vulkan_display_find_window (display, + &window_id, (GCompareFunc) _compare_xcb_window); } +static GstVulkanWindowXCB * +_window_from_event (GstVulkanDisplayXCB * display_xcb, + xcb_generic_event_t * event) +{ + uint8_t event_code = event->response_type & 0x7f; + + switch (event_code) { +/* *INDENT-OFF* */ +#define WIN_FROM_EVENT(case_val,event_type,window_field) \ + case case_val:{ \ + event_type * real_event = (event_type *) event; \ + return _find_window_from_xcb_window (display_xcb, real_event->window_field); \ + } + WIN_FROM_EVENT (XCB_CLIENT_MESSAGE, xcb_client_message_event_t, window) + WIN_FROM_EVENT (XCB_CONFIGURE_NOTIFY, xcb_configure_notify_event_t, window) + WIN_FROM_EVENT (XCB_EXPOSE, xcb_expose_event_t, window) + WIN_FROM_EVENT (XCB_KEY_PRESS, xcb_key_press_event_t, event) + WIN_FROM_EVENT (XCB_KEY_RELEASE, xcb_key_release_event_t, event) + WIN_FROM_EVENT (XCB_BUTTON_PRESS, xcb_button_press_event_t, event) + WIN_FROM_EVENT (XCB_BUTTON_RELEASE, xcb_button_release_event_t, event) + WIN_FROM_EVENT (XCB_MOTION_NOTIFY, xcb_motion_notify_event_t, event) +#undef WIN_FROM_EVENT +/* *INDENT-ON* */ + default: + return NULL; + } +} + +G_GNUC_INTERNAL + extern gboolean +gst_vulkan_window_xcb_handle_event (GstVulkanWindowXCB * window_xcb, + xcb_generic_event_t * event); + static gboolean _xcb_handle_event (GstVulkanDisplayXCB * display_xcb) { @@ -81,123 +99,13 @@ _xcb_handle_event (GstVulkanDisplayXCB * display_xcb) xcb_generic_event_t *event; gboolean ret = TRUE; - while ((event = xcb_poll_for_event (connection))) { - uint8_t event_code = event->response_type & 0x7f; + while (ret && (event = xcb_poll_for_event (connection))) { + GstVulkanWindowXCB *window_xcb; - switch (event_code) { - case XCB_CLIENT_MESSAGE:{ - xcb_client_message_event_t *client_event; - xcb_intern_atom_cookie_t cookie; - xcb_intern_atom_reply_t *reply; - - client_event = (xcb_client_message_event_t *) event; - cookie = xcb_intern_atom (connection, 0, 16, "WM_DELETE_WINDOW"); - reply = xcb_intern_atom_reply (connection, cookie, 0); - - if (client_event->data.data32[0] == reply->atom) { - GstVulkanWindowXCB *window_xcb; - - window_xcb = - _find_window_from_xcb_window (display_xcb, client_event->window); - - if (window_xcb) { - GST_INFO_OBJECT (window_xcb, "Close requested"); - - gst_vulkan_window_close (GST_VULKAN_WINDOW (window_xcb)); - gst_vulkan_display_remove_window (GST_VULKAN_DISPLAY (display_xcb), - GST_VULKAN_WINDOW (window_xcb)); - gst_object_unref (window_xcb); - } - } - - g_free (reply); - break; - } - case XCB_CONFIGURE_NOTIFY:{ - xcb_configure_notify_event_t *configure_event; - GstVulkanWindowXCB *window_xcb; - - configure_event = (xcb_configure_notify_event_t *) event; - window_xcb = - _find_window_from_xcb_window (display_xcb, configure_event->window); - - if (window_xcb) { - gst_vulkan_window_resize (GST_VULKAN_WINDOW (window_xcb), - configure_event->width, configure_event->height); - - gst_object_unref (window_xcb); - } - break; - } - case XCB_EXPOSE:{ - xcb_expose_event_t *expose_event = (xcb_expose_event_t *) event; - GstVulkanWindowXCB *window_xcb; - - /* non-zero means that other Expose follows - * so just wait for the last one - * in theory we should not receive non-zero because - * we have no sub areas here but just in case */ - if (expose_event->count != 0) - break; - - window_xcb = - _find_window_from_xcb_window (display_xcb, expose_event->window); - - if (window_xcb) { - gst_vulkan_window_redraw (GST_VULKAN_WINDOW (window_xcb)); - gst_object_unref (window_xcb); - } - break; - } -#if 0 - case KeyPress: - case KeyRelease: - keysym = XkbKeycodeToKeysym (window_xcb->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); - g_main_context_invoke (window->navigation_context, - (GSourceFunc) gst_vulkan_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); - 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"; - 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_vulkan_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); - 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_vulkan_window_mouse_event_cb, mouse_data); - break; -#endif - default: - GST_DEBUG ("unhandled XCB type: %u", event_code); - break; + window_xcb = _window_from_event (display_xcb, event); + if (window_xcb) { + ret = gst_vulkan_window_xcb_handle_event (window_xcb, event); + gst_object_unref (window_xcb); } g_free (event);