1 /*
2 * GStreamer
3 * Copyright (C) 2012 Matthew Waters <ystreet00@gmail.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 <stdint.h>
26 #include <stdlib.h>
27
28 #include <gst/vulkan/gstvkapi.h>
29
30 #include <gst/vulkan/xcb/gstvkdisplay_xcb.h>
31 #include "gstvkwindow_xcb.h"
32
33 #include "xcb_event_source.h"
34
35 static gint
_compare_xcb_window(GstVulkanWindowXCB * window_xcb,xcb_window_t * window_id)36 _compare_xcb_window (GstVulkanWindowXCB * window_xcb, xcb_window_t * window_id)
37 {
38 gint ret;
39
40 g_return_val_if_fail (GST_IS_VULKAN_WINDOW_XCB (window_xcb), -1);
41 g_return_val_if_fail (window_id != 0, -1);
42
43 ret = window_xcb->win_id - *window_id;
44
45 return ret;
46 }
47
48 static GstVulkanWindowXCB *
_find_window_from_xcb_window(GstVulkanDisplayXCB * display_xcb,xcb_window_t window_id)49 _find_window_from_xcb_window (GstVulkanDisplayXCB * display_xcb,
50 xcb_window_t window_id)
51 {
52 GstVulkanDisplay *display = GST_VULKAN_DISPLAY (display_xcb);
53
54 if (!window_id)
55 return NULL;
56
57 return (GstVulkanWindowXCB *) gst_vulkan_display_find_window (display,
58 &window_id, (GCompareFunc) _compare_xcb_window);
59 }
60
61 static GstVulkanWindowXCB *
_window_from_event(GstVulkanDisplayXCB * display_xcb,xcb_generic_event_t * event)62 _window_from_event (GstVulkanDisplayXCB * display_xcb,
63 xcb_generic_event_t * event)
64 {
65 uint8_t event_code = event->response_type & 0x7f;
66
67 switch (event_code) {
68 /* *INDENT-OFF* */
69 #define WIN_FROM_EVENT(case_val,event_type,window_field) \
70 case case_val:{ \
71 event_type * real_event = (event_type *) event; \
72 return _find_window_from_xcb_window (display_xcb, real_event->window_field); \
73 }
74 WIN_FROM_EVENT (XCB_CLIENT_MESSAGE, xcb_client_message_event_t, window)
75 WIN_FROM_EVENT (XCB_CONFIGURE_NOTIFY, xcb_configure_notify_event_t, window)
76 WIN_FROM_EVENT (XCB_EXPOSE, xcb_expose_event_t, window)
77 WIN_FROM_EVENT (XCB_KEY_PRESS, xcb_key_press_event_t, event)
78 WIN_FROM_EVENT (XCB_KEY_RELEASE, xcb_key_release_event_t, event)
79 WIN_FROM_EVENT (XCB_BUTTON_PRESS, xcb_button_press_event_t, event)
80 WIN_FROM_EVENT (XCB_BUTTON_RELEASE, xcb_button_release_event_t, event)
81 WIN_FROM_EVENT (XCB_MOTION_NOTIFY, xcb_motion_notify_event_t, event)
82 #undef WIN_FROM_EVENT
83 /* *INDENT-ON* */
84 default:
85 return NULL;
86 }
87 }
88
89 G_GNUC_INTERNAL
90 extern gboolean
91 gst_vulkan_window_xcb_handle_event (GstVulkanWindowXCB * window_xcb,
92 xcb_generic_event_t * event);
93
94 static gboolean
_xcb_handle_event(GstVulkanDisplayXCB * display_xcb)95 _xcb_handle_event (GstVulkanDisplayXCB * display_xcb)
96 {
97 xcb_connection_t *connection =
98 GST_VULKAN_DISPLAY_XCB_CONNECTION (display_xcb);
99 xcb_generic_event_t *event;
100 gboolean ret = TRUE;
101
102 while (ret && (event = xcb_poll_for_event (connection))) {
103 GstVulkanWindowXCB *window_xcb;
104
105 window_xcb = _window_from_event (display_xcb, event);
106 if (window_xcb) {
107 ret = gst_vulkan_window_xcb_handle_event (window_xcb, event);
108 gst_object_unref (window_xcb);
109 }
110
111 g_free (event);
112 }
113
114 return ret;
115 }
116
117 typedef struct _XCBEventSource
118 {
119 GSource source;
120 GPollFD pfd;
121 uint32_t mask;
122 GstVulkanDisplayXCB *display_xcb;
123 } XCBEventSource;
124
125 static gboolean
xcb_event_source_prepare(GSource * base,gint * timeout)126 xcb_event_source_prepare (GSource * base, gint * timeout)
127 {
128 *timeout = -1;
129 return FALSE;
130 }
131
132 static gboolean
xcb_event_source_check(GSource * base)133 xcb_event_source_check (GSource * base)
134 {
135 XCBEventSource *source = (XCBEventSource *) base;
136 gboolean retval;
137
138 retval = source->pfd.revents;
139
140 return retval;
141 }
142
143 static gboolean
xcb_event_source_dispatch(GSource * base,GSourceFunc callback,gpointer data)144 xcb_event_source_dispatch (GSource * base, GSourceFunc callback, gpointer data)
145 {
146 XCBEventSource *source = (XCBEventSource *) base;
147
148 gboolean ret = _xcb_handle_event (source->display_xcb);
149
150 if (callback)
151 callback (data);
152
153 return ret;
154 }
155
156 static GSourceFuncs xcb_event_source_funcs = {
157 xcb_event_source_prepare,
158 xcb_event_source_check,
159 xcb_event_source_dispatch,
160 NULL
161 };
162
163 GSource *
xcb_event_source_new(GstVulkanDisplayXCB * display_xcb)164 xcb_event_source_new (GstVulkanDisplayXCB * display_xcb)
165 {
166 xcb_connection_t *connection;
167 XCBEventSource *source;
168
169 connection = GST_VULKAN_DISPLAY_XCB_CONNECTION (display_xcb);
170 g_return_val_if_fail (connection != NULL, NULL);
171
172 source = (XCBEventSource *)
173 g_source_new (&xcb_event_source_funcs, sizeof (XCBEventSource));
174 source->display_xcb = display_xcb;
175 source->pfd.fd = xcb_get_file_descriptor (connection);
176 source->pfd.events = G_IO_IN | G_IO_ERR;
177 g_source_add_poll (&source->source, &source->pfd);
178
179 return &source->source;
180 }
181