File: | cdk/broadway/broadway-server.c |
Warning: | line 483, column 5 Value stored to 'p' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | #include "config.h" |
2 | |
3 | #include "broadway-server.h" |
4 | |
5 | #include "broadway-output.h" |
6 | |
7 | #include <glib.h> |
8 | #include <glib/gprintf.h> |
9 | #include "cdktypes.h" |
10 | #include <stdlib.h> |
11 | #include <string.h> |
12 | #include <errno(*__errno_location ()).h> |
13 | |
14 | #ifdef HAVE_UNISTD_H1 |
15 | #include <unistd.h> |
16 | #elif defined (G_OS_WIN32) |
17 | #include <io.h> |
18 | #endif |
19 | #ifdef HAVE_SYS_MMAN_H1 |
20 | #include <sys/mman.h> |
21 | #endif |
22 | #include <sys/stat.h> |
23 | #include <fcntl.h> |
24 | #include <sys/types.h> |
25 | #ifdef G_OS_UNIX |
26 | #include <sys/socket.h> |
27 | #include <netinet/in.h> |
28 | #include <netinet/tcp.h> |
29 | #endif |
30 | #ifdef HAVE_GIO_UNIX1 |
31 | #include <gio/gunixsocketaddress.h> |
32 | #endif |
33 | #ifdef G_OS_WIN32 |
34 | #include <windows.h> |
35 | #include <string.h> |
36 | #endif |
37 | |
38 | typedef struct BroadwayInput BroadwayInput; |
39 | typedef struct BroadwayWindow BroadwayWindow; |
40 | struct _BroadwayServer { |
41 | GObject parent_instance; |
42 | |
43 | char *address; |
44 | int port; |
45 | char *ssl_cert; |
46 | char *ssl_key; |
47 | GSocketService *service; |
48 | BroadwayOutput *output; |
49 | guint32 id_counter; |
50 | guint32 saved_serial; |
51 | guint64 last_seen_time; |
52 | BroadwayInput *input; |
53 | GList *input_messages; |
54 | guint process_input_idle; |
55 | |
56 | GHashTable *id_ht; |
57 | GList *toplevels; |
58 | BroadwayWindow *root; |
59 | gint32 focused_window_id; /* -1 => none */ |
60 | gint show_keyboard; |
61 | |
62 | guint32 screen_width; |
63 | guint32 screen_height; |
64 | |
65 | gint32 mouse_in_toplevel_id; |
66 | int last_x, last_y; /* in root coords */ |
67 | guint32 last_state; |
68 | gint32 real_mouse_in_toplevel_id; /* Not affected by grabs */ |
69 | |
70 | /* Explicit pointer grabs: */ |
71 | gint32 pointer_grab_window_id; /* -1 => none */ |
72 | gint32 pointer_grab_client_id; /* -1 => none */ |
73 | guint32 pointer_grab_time; |
74 | gboolean pointer_grab_owner_events; |
75 | |
76 | /* Future data, from the currently queued events */ |
77 | int future_root_x; |
78 | int future_root_y; |
79 | guint32 future_state; |
80 | int future_mouse_in_toplevel; |
81 | }; |
82 | |
83 | struct _BroadwayServerClass |
84 | { |
85 | GObjectClass parent_class; |
86 | }; |
87 | |
88 | typedef struct HttpRequest { |
89 | BroadwayServer *server; |
90 | GSocketConnection *socket_connection; |
91 | GIOStream *connection; |
92 | GDataInputStream *data; |
93 | GString *request; |
94 | } HttpRequest; |
95 | |
96 | struct BroadwayInput { |
97 | BroadwayServer *server; |
98 | BroadwayOutput *output; |
99 | GIOStream *connection; |
100 | GByteArray *buffer; |
101 | GSource *source; |
102 | gboolean seen_time; |
103 | gint64 time_base; |
104 | gboolean active; |
105 | }; |
106 | |
107 | struct BroadwayWindow { |
108 | gint32 id; |
109 | gint32 x; |
110 | gint32 y; |
111 | gint32 width; |
112 | gint32 height; |
113 | gboolean is_temp; |
114 | gboolean visible; |
115 | gint32 transient_for; |
116 | |
117 | BroadwayBuffer *buffer; |
118 | gboolean buffer_synced; |
119 | |
120 | char *cached_surface_name; |
121 | cairo_surface_t *cached_surface; |
122 | }; |
123 | |
124 | static void broadway_server_resync_windows (BroadwayServer *server); |
125 | |
126 | static GType broadway_server_get_type (void); |
127 | |
128 | G_DEFINE_TYPE (BroadwayServer, broadway_server, G_TYPE_OBJECT)static void broadway_server_init (BroadwayServer *self); static void broadway_server_class_init (BroadwayServerClass *klass) ; static GType broadway_server_get_type_once (void); static gpointer broadway_server_parent_class = ((void*)0); static gint BroadwayServer_private_offset ; static void broadway_server_class_intern_init (gpointer klass ) { broadway_server_parent_class = g_type_class_peek_parent ( klass); if (BroadwayServer_private_offset != 0) g_type_class_adjust_private_offset (klass, &BroadwayServer_private_offset); broadway_server_class_init ((BroadwayServerClass*) klass); } __attribute__ ((__unused__ )) static inline gpointer broadway_server_get_instance_private (BroadwayServer *self) { return (((gpointer) ((guint8*) (self ) + (glong) (BroadwayServer_private_offset)))); } GType broadway_server_get_type (void) { static GType static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); (void) ( 0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0)) ; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ (*(&static_g_define_type_id)) gapg_temp_newval; __typeof__ ((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id ); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5) ; gapg_temp_newval; })) && g_once_init_enter_pointer ( &static_g_define_type_id)); })) ) { GType g_define_type_id = broadway_server_get_type_once (); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer) , "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id ) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer ((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id )); })) ; } return static_g_define_type_id; } __attribute__ ( (__noinline__)) static GType broadway_server_get_type_once (void ) { GType g_define_type_id = g_type_register_static_simple (( (GType) ((20) << (2))), g_intern_static_string ("BroadwayServer" ), sizeof (BroadwayServerClass), (GClassInitFunc)(void (*)(void )) broadway_server_class_intern_init, sizeof (BroadwayServer) , (GInstanceInitFunc)(void (*)(void)) broadway_server_init, ( GTypeFlags) 0); { {{};} } return g_define_type_id; } |
129 | |
130 | static void |
131 | broadway_server_init (BroadwayServer *server) |
132 | { |
133 | BroadwayWindow *root; |
134 | |
135 | server->service = g_socket_service_new (); |
136 | server->pointer_grab_window_id = -1; |
137 | server->saved_serial = 1; |
138 | server->last_seen_time = 1; |
139 | server->id_ht = g_hash_table_new (NULL((void*)0), NULL((void*)0)); |
140 | server->id_counter = 0; |
141 | |
142 | root = g_new0 (BroadwayWindow, 1)((BroadwayWindow *) g_malloc0_n ((1), sizeof (BroadwayWindow) )); |
143 | root->id = server->id_counter++; |
144 | root->width = 1024; |
145 | root->height = 768; |
146 | root->visible = TRUE(!(0)); |
147 | |
148 | server->root = root; |
149 | |
150 | g_hash_table_insert (server->id_ht, |
151 | GINT_TO_POINTER (root->id)((gpointer) (glong) (root->id)), |
152 | root); |
153 | } |
154 | |
155 | static void |
156 | broadway_server_finalize (GObject *object) |
157 | { |
158 | BroadwayServer *server = BROADWAY_SERVER (object)((((BroadwayServer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((broadway_server_get_type())))))); |
159 | |
160 | g_free (server->address); |
161 | g_free (server->ssl_cert); |
162 | g_free (server->ssl_key); |
163 | |
164 | G_OBJECT_CLASS (broadway_server_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((broadway_server_parent_class)), (((GType) ((20) << (2))))))))->finalize (object); |
165 | } |
166 | |
167 | static void |
168 | broadway_server_class_init (BroadwayServerClass * class) |
169 | { |
170 | GObjectClass *object_class = G_OBJECT_CLASS (class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((class)), (((GType) ((20) << (2)))))))); |
171 | |
172 | object_class->finalize = broadway_server_finalize; |
173 | } |
174 | |
175 | static void start (BroadwayInput *input); |
176 | |
177 | static void |
178 | http_request_free (HttpRequest *request) |
179 | { |
180 | g_object_unref (request->socket_connection); |
181 | g_object_unref (request->connection); |
182 | g_object_unref (request->data); |
183 | g_string_free (request->request, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (request->request), ((!(0)))) : g_string_free_and_steal (request ->request)) : (g_string_free) ((request->request), ((!( 0))))); |
184 | g_free (request); |
185 | } |
186 | |
187 | static void |
188 | broadway_input_free (BroadwayInput *input) |
189 | { |
190 | g_object_unref (input->connection); |
191 | g_byte_array_free (input->buffer, FALSE(0)); |
192 | g_source_destroy (input->source); |
193 | g_free (input); |
194 | } |
195 | |
196 | static void |
197 | update_event_state (BroadwayServer *server, |
198 | BroadwayInputMsg *message) |
199 | { |
200 | BroadwayWindow *window; |
201 | |
202 | switch (message->base.type) { |
203 | case BROADWAY_EVENT_ENTER: |
204 | server->last_x = message->pointer.root_x; |
205 | server->last_y = message->pointer.root_y; |
206 | server->last_state = message->pointer.state; |
207 | server->real_mouse_in_toplevel_id = message->pointer.mouse_window_id; |
208 | |
209 | /* TODO: Unset when it dies */ |
210 | server->mouse_in_toplevel_id = message->pointer.event_window_id; |
211 | break; |
212 | case BROADWAY_EVENT_LEAVE: |
213 | server->last_x = message->pointer.root_x; |
214 | server->last_y = message->pointer.root_y; |
215 | server->last_state = message->pointer.state; |
216 | server->real_mouse_in_toplevel_id = message->pointer.mouse_window_id; |
217 | |
218 | server->mouse_in_toplevel_id = 0; |
219 | break; |
220 | case BROADWAY_EVENT_POINTER_MOVE: |
221 | server->last_x = message->pointer.root_x; |
222 | server->last_y = message->pointer.root_y; |
223 | server->last_state = message->pointer.state; |
224 | server->real_mouse_in_toplevel_id = message->pointer.mouse_window_id; |
225 | break; |
226 | case BROADWAY_EVENT_BUTTON_PRESS: |
227 | case BROADWAY_EVENT_BUTTON_RELEASE: |
228 | if (message->base.type == BROADWAY_EVENT_BUTTON_PRESS && |
229 | server->focused_window_id != message->pointer.mouse_window_id && |
230 | server->pointer_grab_window_id == -1) |
231 | { |
232 | broadway_server_window_raise (server, message->pointer.mouse_window_id); |
233 | broadway_server_focus_window (server, message->pointer.mouse_window_id); |
234 | broadway_server_flush (server); |
235 | } |
236 | |
237 | server->last_x = message->pointer.root_x; |
238 | server->last_y = message->pointer.root_y; |
239 | server->last_state = message->pointer.state; |
240 | server->real_mouse_in_toplevel_id = message->pointer.mouse_window_id; |
241 | break; |
242 | case BROADWAY_EVENT_SCROLL: |
243 | server->last_x = message->pointer.root_x; |
244 | server->last_y = message->pointer.root_y; |
245 | server->last_state = message->pointer.state; |
246 | server->real_mouse_in_toplevel_id = message->pointer.mouse_window_id; |
247 | break; |
248 | case BROADWAY_EVENT_TOUCH: |
249 | if (message->touch.touch_type == 0 && message->touch.is_emulated && |
250 | server->focused_window_id != message->touch.event_window_id) |
251 | { |
252 | broadway_server_window_raise (server, message->touch.event_window_id); |
253 | broadway_server_focus_window (server, message->touch.event_window_id); |
254 | broadway_server_flush (server); |
255 | } |
256 | |
257 | if (message->touch.is_emulated) |
258 | { |
259 | server->last_x = message->pointer.root_x; |
260 | server->last_y = message->pointer.root_y; |
261 | } |
262 | |
263 | server->last_state = message->touch.state; |
264 | break; |
265 | case BROADWAY_EVENT_KEY_PRESS: |
266 | case BROADWAY_EVENT_KEY_RELEASE: |
267 | server->last_state = message->key.state; |
268 | break; |
269 | case BROADWAY_EVENT_GRAB_NOTIFY: |
270 | case BROADWAY_EVENT_UNGRAB_NOTIFY: |
271 | break; |
272 | case BROADWAY_EVENT_CONFIGURE_NOTIFY: |
273 | window = g_hash_table_lookup (server->id_ht, |
274 | GINT_TO_POINTER (message->configure_notify.id)((gpointer) (glong) (message->configure_notify.id))); |
275 | if (window != NULL((void*)0)) |
276 | { |
277 | window->x = message->configure_notify.x; |
278 | window->y = message->configure_notify.y; |
279 | } |
280 | break; |
281 | case BROADWAY_EVENT_DELETE_NOTIFY: |
282 | break; |
283 | case BROADWAY_EVENT_SCREEN_SIZE_CHANGED: |
284 | server->root->width = message->screen_resize_notify.width; |
285 | server->root->height = message->screen_resize_notify.height; |
286 | break; |
287 | |
288 | default: |
289 | g_printerr ("update_event_state - Unknown input command %c\n", message->base.type); |
290 | break; |
291 | } |
292 | } |
293 | |
294 | gboolean |
295 | broadway_server_lookahead_event (BroadwayServer *server, |
296 | const char *types) |
297 | { |
298 | GList *l; |
299 | |
300 | for (l = server->input_messages; l != NULL((void*)0); l = l->next) |
301 | { |
302 | BroadwayInputMsg *message; |
303 | |
304 | message = l->data; |
305 | if (strchr (types, message->base.type) != NULL((void*)0)) |
306 | return TRUE(!(0)); |
307 | } |
308 | |
309 | return FALSE(0); |
310 | } |
311 | |
312 | static gboolean |
313 | is_pointer_event (BroadwayInputMsg *message) |
314 | { |
315 | return |
316 | message->base.type == BROADWAY_EVENT_ENTER || |
317 | message->base.type == BROADWAY_EVENT_LEAVE || |
318 | message->base.type == BROADWAY_EVENT_POINTER_MOVE || |
319 | message->base.type == BROADWAY_EVENT_BUTTON_PRESS || |
320 | message->base.type == BROADWAY_EVENT_BUTTON_RELEASE || |
321 | message->base.type == BROADWAY_EVENT_SCROLL || |
322 | message->base.type == BROADWAY_EVENT_GRAB_NOTIFY || |
323 | message->base.type == BROADWAY_EVENT_UNGRAB_NOTIFY; |
324 | } |
325 | |
326 | static void |
327 | process_input_message (BroadwayServer *server, |
328 | BroadwayInputMsg *message) |
329 | { |
330 | gint32 client; |
331 | |
332 | update_event_state (server, message); |
333 | client = -1; |
334 | if (is_pointer_event (message) && |
335 | server->pointer_grab_window_id != -1) |
336 | client = server->pointer_grab_client_id; |
337 | |
338 | broadway_events_got_input (message, client); |
339 | } |
340 | |
341 | static void |
342 | process_input_messages (BroadwayServer *server) |
343 | { |
344 | while (server->input_messages) |
345 | { |
346 | BroadwayInputMsg *message; |
347 | |
348 | message = server->input_messages->data; |
349 | server->input_messages = |
350 | g_list_delete_link (server->input_messages, |
351 | server->input_messages); |
352 | |
353 | if (message->base.serial == 0) |
354 | { |
355 | /* This was sent before we got any requests, but we don't want the |
356 | daemon serials to go backwards, so we fix it up to be the last used |
357 | serial */ |
358 | message->base.serial = server->saved_serial - 1; |
359 | } |
360 | |
361 | process_input_message (server, message); |
362 | g_free (message); |
363 | } |
364 | } |
365 | |
366 | static void |
367 | fake_configure_notify (BroadwayServer *server, |
368 | BroadwayWindow *window) |
369 | { |
370 | BroadwayInputMsg ev = { {0} }; |
371 | |
372 | ev.base.type = BROADWAY_EVENT_CONFIGURE_NOTIFY; |
373 | ev.base.serial = server->saved_serial - 1; |
374 | ev.base.time = server->last_seen_time; |
375 | ev.configure_notify.id = window->id; |
376 | ev.configure_notify.x = window->x; |
377 | ev.configure_notify.y = window->y; |
378 | ev.configure_notify.width = window->width; |
379 | ev.configure_notify.height = window->height; |
380 | |
381 | process_input_message (server, &ev); |
382 | } |
383 | |
384 | static guint32 * |
385 | parse_pointer_data (guint32 *p, BroadwayInputPointerMsg *data) |
386 | { |
387 | data->mouse_window_id = ntohl (*p++); |
388 | data->event_window_id = ntohl (*p++); |
389 | data->root_x = ntohl (*p++); |
390 | data->root_y = ntohl (*p++); |
391 | data->win_x = ntohl (*p++); |
392 | data->win_y = ntohl (*p++); |
393 | data->state = ntohl (*p++); |
394 | |
395 | return p; |
396 | } |
397 | |
398 | static guint32 * |
399 | parse_touch_data (guint32 *p, BroadwayInputTouchMsg *data) |
400 | { |
401 | data->touch_type = ntohl (*p++); |
402 | data->event_window_id = ntohl (*p++); |
403 | data->sequence_id = ntohl (*p++); |
404 | data->is_emulated = ntohl (*p++); |
405 | data->root_x = ntohl (*p++); |
406 | data->root_y = ntohl (*p++); |
407 | data->win_x = ntohl (*p++); |
408 | data->win_y = ntohl (*p++); |
409 | data->state = ntohl (*p++); |
410 | |
411 | return p; |
412 | } |
413 | |
414 | static void |
415 | update_future_pointer_info (BroadwayServer *server, BroadwayInputPointerMsg *data) |
416 | { |
417 | server->future_root_x = data->root_x; |
418 | server->future_root_y = data->root_y; |
419 | server->future_state = data->state; |
420 | server->future_mouse_in_toplevel = data->mouse_window_id; |
421 | } |
422 | |
423 | static void |
424 | parse_input_message (BroadwayInput *input, const unsigned char *message) |
425 | { |
426 | BroadwayServer *server = input->server; |
427 | BroadwayInputMsg msg; |
428 | guint32 *p; |
429 | gint64 time_; |
430 | |
431 | memset (&msg, 0, sizeof (msg)); |
432 | |
433 | p = (guint32 *) message; |
434 | |
435 | msg.base.type = ntohl (*p++); |
436 | msg.base.serial = ntohl (*p++); |
437 | time_ = ntohl (*p++); |
438 | |
439 | if (time_ == 0) { |
440 | time_ = server->last_seen_time; |
441 | } else { |
442 | if (!input->seen_time) { |
443 | input->seen_time = TRUE(!(0)); |
444 | /* Calculate time base so that any following times are normalized to start |
445 | 5 seconds after last_seen_time, to avoid issues that could appear when |
446 | a long hiatus due to a reconnect seems to be instant */ |
447 | input->time_base = time_ - (server->last_seen_time + 5000); |
448 | } |
449 | time_ = time_ - input->time_base; |
450 | } |
451 | |
452 | server->last_seen_time = time_; |
453 | |
454 | msg.base.time = time_; |
455 | |
456 | switch (msg.base.type) { |
457 | case BROADWAY_EVENT_ENTER: |
458 | case BROADWAY_EVENT_LEAVE: |
459 | p = parse_pointer_data (p, &msg.pointer); |
460 | update_future_pointer_info (server, &msg.pointer); |
461 | msg.crossing.mode = ntohl (*p++); |
462 | break; |
463 | |
464 | case BROADWAY_EVENT_POINTER_MOVE: /* Mouse move */ |
465 | p = parse_pointer_data (p, &msg.pointer); |
466 | update_future_pointer_info (server, &msg.pointer); |
467 | break; |
468 | |
469 | case BROADWAY_EVENT_BUTTON_PRESS: |
470 | case BROADWAY_EVENT_BUTTON_RELEASE: |
471 | p = parse_pointer_data (p, &msg.pointer); |
472 | update_future_pointer_info (server, &msg.pointer); |
473 | msg.button.button = ntohl (*p++); |
474 | break; |
475 | |
476 | case BROADWAY_EVENT_SCROLL: |
477 | p = parse_pointer_data (p, &msg.pointer); |
478 | update_future_pointer_info (server, &msg.pointer); |
479 | msg.scroll.dir = ntohl (*p++); |
480 | break; |
481 | |
482 | case BROADWAY_EVENT_TOUCH: |
483 | p = parse_touch_data (p, &msg.touch); |
Value stored to 'p' is never read | |
484 | break; |
485 | |
486 | case BROADWAY_EVENT_KEY_PRESS: |
487 | case BROADWAY_EVENT_KEY_RELEASE: |
488 | msg.key.window_id = server->focused_window_id; |
489 | msg.key.key = ntohl (*p++); |
490 | msg.key.state = ntohl (*p++); |
491 | break; |
492 | |
493 | case BROADWAY_EVENT_GRAB_NOTIFY: |
494 | case BROADWAY_EVENT_UNGRAB_NOTIFY: |
495 | msg.grab_reply.res = ntohl (*p++); |
496 | break; |
497 | |
498 | case BROADWAY_EVENT_CONFIGURE_NOTIFY: |
499 | msg.configure_notify.id = ntohl (*p++); |
500 | msg.configure_notify.x = ntohl (*p++); |
501 | msg.configure_notify.y = ntohl (*p++); |
502 | msg.configure_notify.width = ntohl (*p++); |
503 | msg.configure_notify.height = ntohl (*p++); |
504 | break; |
505 | |
506 | case BROADWAY_EVENT_DELETE_NOTIFY: |
507 | msg.delete_notify.id = ntohl (*p++); |
508 | break; |
509 | |
510 | case BROADWAY_EVENT_SCREEN_SIZE_CHANGED: |
511 | msg.screen_resize_notify.width = ntohl (*p++); |
512 | msg.screen_resize_notify.height = ntohl (*p++); |
513 | break; |
514 | |
515 | default: |
516 | g_printerr ("parse_input_message - Unknown input command %c (%s)\n", msg.base.type, message); |
517 | break; |
518 | } |
519 | |
520 | server->input_messages = g_list_append (server->input_messages, g_memdup2 (&msg, sizeof (msg))); |
521 | |
522 | } |
523 | |
524 | static inline void |
525 | hex_dump (guchar *data G_GNUC_UNUSED__attribute__ ((__unused__)), |
526 | gsize len G_GNUC_UNUSED__attribute__ ((__unused__))) |
527 | { |
528 | #ifdef DEBUG_WEBSOCKETS |
529 | gsize i, j; |
530 | for (j = 0; j < len + 15; j += 16) |
531 | { |
532 | fprintf (stderrstderr, "0x%.4x ", j); |
533 | for (i = 0; i < 16; i++) |
534 | { |
535 | if ((j + i) < len) |
536 | fprintf (stderrstderr, "%.2x ", data[j+i]); |
537 | else |
538 | fprintf (stderrstderr, " "); |
539 | if (i == 8) |
540 | fprintf (stderrstderr, " "); |
541 | } |
542 | fprintf (stderrstderr, " | "); |
543 | |
544 | for (i = 0; i < 16; i++) |
545 | if ((j + i) < len && g_ascii_isalnum(data[j+i])((g_ascii_table[(guchar) (data[j+i])] & G_ASCII_ALNUM) != 0)) |
546 | fprintf (stderrstderr, "%c", data[j+i]); |
547 | else |
548 | fprintf (stderrstderr, "."); |
549 | fprintf (stderrstderr, "\n"); |
550 | } |
551 | #endif |
552 | } |
553 | |
554 | static void |
555 | parse_input (BroadwayInput *input) |
556 | { |
557 | if (!input->buffer->len) |
558 | return; |
559 | |
560 | hex_dump (input->buffer->data, input->buffer->len); |
561 | |
562 | while (input->buffer->len > 2) |
563 | { |
564 | gsize len, payload_len; |
565 | BroadwayWSOpCode code; |
566 | gboolean is_mask, fin; |
567 | guchar *buf, *data, *mask; |
568 | |
569 | buf = input->buffer->data; |
570 | len = input->buffer->len; |
571 | |
572 | #ifdef DEBUG_WEBSOCKETS |
573 | g_print ("Parse input first byte 0x%2x 0x%2x\n", buf[0], buf[1]); |
574 | #endif |
575 | |
576 | fin = buf[0] & 0x80; |
577 | code = buf[0] & 0x0f; |
578 | payload_len = buf[1] & 0x7f; |
579 | is_mask = buf[1] & 0x80; |
580 | data = buf + 2; |
581 | |
582 | if (payload_len == 126) |
583 | { |
584 | if (len < 4) |
585 | return; |
586 | payload_len = GUINT16_FROM_BE( *(guint16 *) data )(((((guint16) ( (guint16) ((guint16) (*(guint16 *) data) >> 8) | (guint16) ((guint16) (*(guint16 *) data) << 8)))) )); |
587 | data += 2; |
588 | } |
589 | else if (payload_len == 127) |
590 | { |
591 | if (len < 10) |
592 | return; |
593 | payload_len = GUINT64_FROM_BE( *(guint64 *) data )(((((guint64) ( (((guint64) (*(guint64 *) data) & (guint64 ) (0x00000000000000ffUL)) << 56) | (((guint64) (*(guint64 *) data) & (guint64) (0x000000000000ff00UL)) << 40 ) | (((guint64) (*(guint64 *) data) & (guint64) (0x0000000000ff0000UL )) << 24) | (((guint64) (*(guint64 *) data) & (guint64 ) (0x00000000ff000000UL)) << 8) | (((guint64) (*(guint64 *) data) & (guint64) (0x000000ff00000000UL)) >> 8) | (((guint64) (*(guint64 *) data) & (guint64) (0x0000ff0000000000UL )) >> 24) | (((guint64) (*(guint64 *) data) & (guint64 ) (0x00ff000000000000UL)) >> 40) | (((guint64) (*(guint64 *) data) & (guint64) (0xff00000000000000UL)) >> 56 )))))); |
594 | data += 8; |
595 | } |
596 | |
597 | mask = NULL((void*)0); |
598 | if (is_mask) |
599 | { |
600 | if (data - buf + 4 > len) |
601 | return; |
602 | mask = data; |
603 | data += 4; |
604 | } |
605 | |
606 | if (data - buf + payload_len > len) |
607 | return; /* wait to accumulate more */ |
608 | |
609 | if (is_mask) |
610 | { |
611 | gsize i; |
612 | for (i = 0; i < payload_len; i++) |
613 | data[i] ^= mask[i%4]; |
614 | } |
615 | |
616 | switch (code) { |
617 | case BROADWAY_WS_CNX_CLOSE: |
618 | break; /* hang around anyway */ |
619 | case BROADWAY_WS_BINARY: |
620 | if (!fin) |
621 | { |
622 | #ifdef DEBUG_WEBSOCKETS |
623 | g_warning ("can't yet accept fragmented input"); |
624 | #endif |
625 | } |
626 | else |
627 | { |
628 | parse_input_message (input, data); |
629 | } |
630 | break; |
631 | case BROADWAY_WS_CNX_PING: |
632 | broadway_output_pong (input->output); |
633 | break; |
634 | case BROADWAY_WS_CNX_PONG: |
635 | break; /* we never send pings, but tolerate pongs */ |
636 | case BROADWAY_WS_TEXT: |
637 | case BROADWAY_WS_CONTINUATION: |
638 | default: |
639 | { |
640 | g_warning ("fragmented or unknown input code 0x%2x with fin set", code); |
641 | break; |
642 | } |
643 | } |
644 | |
645 | g_byte_array_remove_range (input->buffer, 0, data - buf + payload_len); |
646 | } |
647 | } |
648 | |
649 | |
650 | static gboolean |
651 | process_input_idle_cb (BroadwayServer *server) |
652 | { |
653 | server->process_input_idle = 0; |
654 | process_input_messages (server); |
655 | return G_SOURCE_REMOVE(0); |
656 | } |
657 | |
658 | static void |
659 | queue_process_input_at_idle (BroadwayServer *server) |
660 | { |
661 | if (server->process_input_idle == 0) |
662 | server->process_input_idle = |
663 | g_idle_add_full (G_PRIORITY_DEFAULT0, (GSourceFunc)process_input_idle_cb, server, NULL((void*)0)); |
664 | } |
665 | |
666 | static gboolean |
667 | broadway_server_read_all_input_nonblocking (BroadwayInput *input) |
668 | { |
669 | GInputStream *in; |
670 | gssize res; |
671 | guint8 buffer[1024]; |
672 | GError *error = NULL((void*)0); |
673 | |
674 | if (input == NULL((void*)0)) |
675 | return FALSE(0); |
676 | |
677 | in = g_io_stream_get_input_stream (input->connection); |
678 | |
679 | res = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (in)((((GPollableInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((in)), ((g_pollable_input_stream_get_type ())))))), |
680 | buffer, sizeof (buffer), NULL((void*)0), &error); |
681 | |
682 | if (res <= 0) |
683 | { |
684 | if (res < 0 && |
685 | g_error_matches (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_WOULD_BLOCK)) |
686 | { |
687 | g_error_free (error); |
688 | return TRUE(!(0)); |
689 | } |
690 | |
691 | if (input->server->input == input) |
692 | input->server->input = NULL((void*)0); |
693 | broadway_input_free (input); |
694 | if (res < 0) |
695 | { |
696 | g_printerr ("input error %s\n", error->message); |
697 | g_error_free (error); |
698 | } |
699 | return FALSE(0); |
700 | } |
701 | |
702 | g_byte_array_append (input->buffer, buffer, res); |
703 | |
704 | parse_input (input); |
705 | return TRUE(!(0)); |
706 | } |
707 | |
708 | static void |
709 | broadway_server_consume_all_input (BroadwayServer *server) |
710 | { |
711 | broadway_server_read_all_input_nonblocking (server->input); |
712 | |
713 | /* Since we're parsing input but not processing the resulting messages |
714 | we might not get a readable callback on the stream, so queue an idle to |
715 | process the messages */ |
716 | queue_process_input_at_idle (server); |
717 | } |
718 | |
719 | |
720 | static gboolean |
721 | input_data_cb (GObject *stream G_GNUC_UNUSED__attribute__ ((__unused__)), |
722 | BroadwayInput *input) |
723 | { |
724 | BroadwayServer *server = input->server; |
725 | |
726 | if (!broadway_server_read_all_input_nonblocking (input)) |
727 | return FALSE(0); |
728 | |
729 | if (input->active) |
730 | process_input_messages (server); |
731 | |
732 | return TRUE(!(0)); |
733 | } |
734 | |
735 | guint32 |
736 | broadway_server_get_next_serial (BroadwayServer *server) |
737 | { |
738 | if (server->output) |
739 | return broadway_output_get_next_serial (server->output); |
740 | |
741 | return server->saved_serial; |
742 | } |
743 | |
744 | void |
745 | broadway_server_get_screen_size (BroadwayServer *server, |
746 | guint32 *width, |
747 | guint32 *height) |
748 | { |
749 | *width = server->root->width; |
750 | *height = server->root->height; |
751 | } |
752 | |
753 | |
754 | void |
755 | broadway_server_flush (BroadwayServer *server) |
756 | { |
757 | if (server->output && |
758 | !broadway_output_flush (server->output)) |
759 | { |
760 | server->saved_serial = broadway_output_get_next_serial (server->output); |
761 | broadway_output_free (server->output); |
762 | server->output = NULL((void*)0); |
763 | } |
764 | } |
765 | |
766 | #if 0 |
767 | /* TODO: This is not used atm, is it needed? */ |
768 | /* Note: This may be called while handling a message (i.e. sorta recursively) */ |
769 | static BroadwayInputMsg * |
770 | broadway_server_block_for_input (BroadwayServer *server, char op, |
771 | guint32 serial, gboolean remove_message) |
772 | { |
773 | BroadwayInputMsg *message; |
774 | gssize res; |
775 | guint8 buffer[1024]; |
776 | BroadwayInput *input; |
777 | GInputStream *in; |
778 | GList *l; |
779 | |
780 | broadway_server_flush (server); |
781 | |
782 | if (server->input == NULL((void*)0)) |
783 | return NULL((void*)0); |
784 | |
785 | input = server->input; |
786 | |
787 | while (TRUE(!(0))) { |
788 | /* Check for existing reply in queue */ |
789 | |
790 | for (l = server->input_messages; l != NULL((void*)0); l = l->next) |
791 | { |
792 | message = l->data; |
793 | |
794 | if (message->base.type == op) |
795 | { |
796 | if (message->base.serial == serial) |
797 | { |
798 | if (remove_message) |
799 | server->input_messages = |
800 | g_list_delete_link (server->input_messages, l); |
801 | return message; |
802 | } |
803 | } |
804 | } |
805 | |
806 | /* Not found, read more, blocking */ |
807 | |
808 | in = g_io_stream_get_input_stream (input->connection); |
809 | |
810 | res = g_input_stream_read (in, buffer, sizeof (buffer), NULL((void*)0), NULL((void*)0)); |
811 | if (res <= 0) |
812 | return NULL((void*)0); |
813 | g_byte_array_append (input->buffer, buffer, res); |
814 | |
815 | parse_input (input); |
816 | |
817 | /* Since we're parsing input but not processing the resulting messages |
818 | we might not get a readable callback on the stream, so queue an idle to |
819 | process the messages */ |
820 | queue_process_input_at_idle (server); |
821 | } |
822 | } |
823 | #endif |
824 | |
825 | static void * |
826 | map_named_shm (char *name, gsize size) |
827 | { |
828 | #ifdef G_OS_UNIX |
829 | |
830 | int fd; |
831 | void *ptr; |
832 | char *filename = NULL((void*)0); |
833 | |
834 | fd = shm_open (name, O_RDONLY00, 0600); |
835 | if (fd == -1) |
836 | { |
837 | filename = g_build_filename (g_get_tmp_dir (), name, NULL((void*)0)); |
838 | fd = open (filename, O_RDONLY00); |
839 | if (fd == -1) |
840 | { |
841 | perror ("Failed to map shm"); |
842 | g_free (filename); |
843 | |
844 | return NULL((void*)0); |
845 | } |
846 | } |
847 | |
848 | ptr = mmap (0, size, PROT_READ0x1, MAP_SHARED0x01, fd, 0); |
849 | |
850 | (void) close (fd); |
851 | |
852 | if (filename) |
853 | { |
854 | unlink (filename); |
855 | g_free (filename); |
856 | } |
857 | else |
858 | shm_unlink (name); |
859 | |
860 | return ptr; |
861 | |
862 | #elif defined(G_OS_WIN32) |
863 | |
864 | int fd; |
865 | void *ptr; |
866 | char *shmpath; |
867 | void *map = ((void *)-1); |
868 | |
869 | if (*name == '/') |
870 | ++name; |
871 | shmpath = g_build_filename (g_get_tmp_dir (), name, NULL((void*)0)); |
872 | |
873 | fd = open(shmpath, O_RDONLY00, 0600); |
874 | if (fd == -1) |
875 | { |
876 | g_free (shmpath); |
877 | perror ("Failed to shm_open"); |
878 | return NULL((void*)0); |
879 | } |
880 | |
881 | if (size == 0) |
882 | ptr = map; |
883 | else |
884 | { |
885 | HANDLE h, fm; |
886 | h = (HANDLE)_get_osfhandle (fd); |
887 | fm = CreateFileMapping (h, NULL((void*)0), PAGE_READONLY, 0, (DWORD)size, NULL((void*)0)); |
888 | ptr = MapViewOfFile (fm, FILE_MAP_READ, 0, 0, (size_t)size); |
889 | CloseHandle (fm); |
890 | } |
891 | |
892 | (void) close(fd); |
893 | |
894 | remove (shmpath); |
895 | g_free (shmpath); |
896 | |
897 | return ptr; |
898 | |
899 | #else |
900 | #error "No shm mapping supported" |
901 | |
902 | return NULL((void*)0); |
903 | #endif |
904 | } |
905 | |
906 | static char * |
907 | parse_line (char *line, char *key) |
908 | { |
909 | char *p; |
910 | |
911 | if (!g_str_has_prefix (line, key)(__builtin_constant_p (key)? __extension__ ({ const char * const __str = (line); const char * const __prefix = (key); gboolean __result = (0); if (__str == ((void*)0) || __prefix == ((void *)0)) __result = (g_str_has_prefix) (__str, __prefix); else { const size_t __str_len = strlen (((__str) + !(__str))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0; } __result; }) : (g_str_has_prefix) (line, key) )) |
912 | return NULL((void*)0); |
913 | p = line + strlen (key); |
914 | if (*p != ':') |
915 | return NULL((void*)0); |
916 | p++; |
917 | /* Skip optional initial space */ |
918 | if (*p == ' ') |
919 | p++; |
920 | return p; |
921 | } |
922 | |
923 | static void |
924 | send_error (HttpRequest *request, |
925 | int error_code, |
926 | const char *reason) |
927 | { |
928 | char *res; |
929 | |
930 | res = g_strdup_printf ("HTTP/1.0 %d %s\r\n\r\n" |
931 | "<html><head><title>%d %s</title></head>" |
932 | "<body>%s</body></html>", |
933 | error_code, reason, |
934 | error_code, reason, |
935 | reason); |
936 | |
937 | /* TODO: This should really be async */ |
938 | g_output_stream_write_all (g_io_stream_get_output_stream (request->connection), |
939 | res, strlen (res), NULL((void*)0), NULL((void*)0), NULL((void*)0)); |
940 | |
941 | g_free (res); |
942 | http_request_free (request); |
943 | } |
944 | |
945 | /* magic from: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17 */ |
946 | #define SEC_WEB_SOCKET_KEY_MAGIC"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" |
947 | |
948 | /* 'x3JJHMbDL1EzLkh9GBhXDw==' generates 'HSmrc0sMlYUkAGmm5OPpG2HaGWk=' */ |
949 | static gchar * |
950 | generate_handshake_response_wsietf_v7 (const gchar *key) |
951 | { |
952 | gsize digest_len = 20; |
953 | guchar digest[20]; |
954 | GChecksum *checksum; |
955 | |
956 | checksum = g_checksum_new (G_CHECKSUM_SHA1); |
957 | if (!checksum) |
958 | return NULL((void*)0); |
959 | |
960 | g_checksum_update (checksum, (guchar *)key, -1); |
961 | g_checksum_update (checksum, (guchar *)SEC_WEB_SOCKET_KEY_MAGIC"258EAFA5-E914-47DA-95CA-C5AB0DC85B11", -1); |
962 | |
963 | g_checksum_get_digest (checksum, digest, &digest_len); |
964 | g_checksum_free (checksum); |
965 | |
966 | g_assert (digest_len == 20)do { if (digest_len == 20) ; else g_assertion_message_expr ("Cdk" , "broadway-server.c", 966, ((const char*) (__func__)), "digest_len == 20" ); } while (0); |
967 | |
968 | return g_base64_encode (digest, digest_len); |
969 | } |
970 | |
971 | static void |
972 | start_input (HttpRequest *request) |
973 | { |
974 | char **lines; |
975 | char *p; |
976 | int i; |
977 | char *res; |
978 | char *origin, *host; |
979 | BroadwayInput *input; |
980 | const void *data_buffer; |
981 | gsize data_buffer_size; |
982 | GInputStream *in; |
983 | char *key; |
984 | GSocket *socket; |
985 | int flag = 1; |
986 | |
987 | #ifdef DEBUG_WEBSOCKETS |
988 | g_print ("incoming request:\n%s\n", request->request->str); |
989 | #endif |
990 | lines = g_strsplit (request->request->str, "\n", 0); |
991 | |
992 | key = NULL((void*)0); |
993 | origin = NULL((void*)0); |
994 | host = NULL((void*)0); |
995 | for (i = 0; lines[i] != NULL((void*)0); i++) |
996 | { |
997 | if ((p = parse_line (lines[i], "Sec-WebSocket-Key"))) |
998 | key = p; |
999 | else if ((p = parse_line (lines[i], "Origin"))) |
1000 | origin = p; |
1001 | else if ((p = parse_line (lines[i], "Host"))) |
1002 | host = p; |
1003 | else if ((p = parse_line (lines[i], "Sec-WebSocket-Origin"))) |
1004 | origin = p; |
1005 | } |
1006 | |
1007 | if (host == NULL((void*)0)) |
1008 | { |
1009 | g_strfreev (lines); |
1010 | send_error (request, 400, "Bad websocket request"); |
1011 | return; |
1012 | } |
1013 | |
1014 | if (key != NULL((void*)0)) |
1015 | { |
1016 | char* accept = generate_handshake_response_wsietf_v7 (key); |
1017 | res = g_strdup_printf ("HTTP/1.1 101 Switching Protocols\r\n" |
1018 | "Upgrade: websocket\r\n" |
1019 | "Connection: Upgrade\r\n" |
1020 | "Sec-WebSocket-Accept: %s\r\n" |
1021 | "%s%s%s" |
1022 | "Sec-WebSocket-Location: ws://%s/socket\r\n" |
1023 | "Sec-WebSocket-Protocol: broadway\r\n" |
1024 | "\r\n", accept, |
1025 | origin?"Sec-WebSocket-Origin: ":"", origin?origin:"", origin?"\r\n":"", |
1026 | host); |
1027 | g_free (accept); |
1028 | |
1029 | #ifdef DEBUG_WEBSOCKETS |
1030 | g_print ("v7 proto response:\n%s", res); |
1031 | #endif |
1032 | |
1033 | g_output_stream_write_all (g_io_stream_get_output_stream (request->connection), |
1034 | res, strlen (res), NULL((void*)0), NULL((void*)0), NULL((void*)0)); |
1035 | g_free (res); |
1036 | } |
1037 | else |
1038 | { |
1039 | g_strfreev (lines); |
1040 | send_error (request, 400, "Bad websocket request"); |
1041 | return; |
1042 | } |
1043 | |
1044 | socket = g_socket_connection_get_socket (request->socket_connection); |
1045 | setsockopt (g_socket_get_fd (socket), IPPROTO_TCPIPPROTO_TCP, |
1046 | TCP_NODELAY1, (char *) &flag, sizeof(int)); |
1047 | |
1048 | input = g_new0 (BroadwayInput, 1)((BroadwayInput *) g_malloc0_n ((1), sizeof (BroadwayInput))); |
1049 | input->server = request->server; |
1050 | input->connection = g_object_ref (request->connection)((__typeof__ (request->connection)) (g_object_ref) (request ->connection)); |
1051 | |
1052 | data_buffer = g_buffered_input_stream_peek_buffer (G_BUFFERED_INPUT_STREAM (request->data)((((GBufferedInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((request->data)), ((g_buffered_input_stream_get_type ())))))), &data_buffer_size); |
1053 | input->buffer = g_byte_array_sized_new (data_buffer_size); |
1054 | g_byte_array_append (input->buffer, data_buffer, data_buffer_size); |
1055 | |
1056 | input->output = |
1057 | broadway_output_new (g_io_stream_get_output_stream (request->connection), 0); |
1058 | |
1059 | /* This will free and close the data input stream, but we got all the buffered content already */ |
1060 | http_request_free (request); |
1061 | |
1062 | in = g_io_stream_get_input_stream (input->connection); |
1063 | |
1064 | input->source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (in)((((GPollableInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((in)), ((g_pollable_input_stream_get_type ())))))), NULL((void*)0)); |
1065 | g_source_set_callback (input->source, (GSourceFunc)input_data_cb, input, NULL((void*)0)); |
1066 | g_source_attach (input->source, NULL((void*)0)); |
1067 | |
1068 | start (input); |
1069 | |
1070 | /* Process any data in the pipe already */ |
1071 | parse_input (input); |
1072 | |
1073 | g_strfreev (lines); |
1074 | } |
1075 | |
1076 | static void |
1077 | start (BroadwayInput *input) |
1078 | { |
1079 | BroadwayServer *server; |
1080 | |
1081 | input->active = TRUE(!(0)); |
1082 | |
1083 | server = BROADWAY_SERVER (input->server)((((BroadwayServer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((input->server)), ((broadway_server_get_type())))))); |
1084 | |
1085 | if (server->output) |
1086 | { |
1087 | broadway_output_disconnected (server->output); |
1088 | broadway_output_flush (server->output); |
1089 | } |
1090 | |
1091 | if (server->input != NULL((void*)0)) |
1092 | { |
1093 | broadway_input_free (server->input); |
1094 | server->input = NULL((void*)0); |
1095 | } |
1096 | |
1097 | server->input = input; |
1098 | |
1099 | if (server->output) |
1100 | { |
1101 | server->saved_serial = broadway_output_get_next_serial (server->output); |
1102 | broadway_output_free (server->output); |
1103 | } |
1104 | server->output = input->output; |
1105 | |
1106 | broadway_output_set_next_serial (server->output, server->saved_serial); |
1107 | broadway_output_flush (server->output); |
1108 | |
1109 | broadway_server_resync_windows (server); |
1110 | |
1111 | if (server->pointer_grab_window_id != -1) |
1112 | broadway_output_grab_pointer (server->output, |
1113 | server->pointer_grab_window_id, |
1114 | server->pointer_grab_owner_events); |
1115 | |
1116 | process_input_messages (server); |
1117 | } |
1118 | |
1119 | static void |
1120 | send_data (HttpRequest *request, |
1121 | const char *mimetype, |
1122 | const char *data, gsize len) |
1123 | { |
1124 | char *res; |
1125 | |
1126 | res = g_strdup_printf ("HTTP/1.0 200 OK\r\n" |
1127 | "Content-Type: %s\r\n" |
1128 | "Content-Length: %"G_GSIZE_FORMAT"lu""\r\n" |
1129 | "\r\n", |
1130 | mimetype, len); |
1131 | |
1132 | /* TODO: This should really be async */ |
1133 | g_output_stream_write_all (g_io_stream_get_output_stream (request->connection), |
1134 | res, strlen (res), NULL((void*)0), NULL((void*)0), NULL((void*)0)); |
1135 | g_free (res); |
1136 | g_output_stream_write_all (g_io_stream_get_output_stream (request->connection), |
1137 | data, len, NULL((void*)0), NULL((void*)0), NULL((void*)0)); |
1138 | http_request_free (request); |
1139 | } |
1140 | |
1141 | #include "clienthtml.h" |
1142 | #include "broadwayjs.h" |
1143 | |
1144 | static void |
1145 | got_request (HttpRequest *request) |
1146 | { |
1147 | char *start, *escaped, *tmp, *version, *query; |
1148 | |
1149 | if (!g_str_has_prefix (request->request->str, "GET ")(__builtin_constant_p ("GET ")? __extension__ ({ const char * const __str = (request->request->str); const char * const __prefix = ("GET "); gboolean __result = (0); if (__str == ( (void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix ) (__str, __prefix); else { const size_t __str_len = strlen ( ((__str) + !(__str))); const size_t __prefix_len = strlen ((( __prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len ) == 0; } __result; }) : (g_str_has_prefix) (request->request ->str, "GET ") )) |
1150 | { |
1151 | send_error (request, 501, "Only GET implemented"); |
1152 | return; |
1153 | } |
1154 | |
1155 | start = request->request->str + 4; /* Skip "GET " */ |
1156 | |
1157 | while (*start == ' ') |
1158 | start++; |
1159 | |
1160 | for (tmp = start; *tmp != 0 && *tmp != ' ' && *tmp != '\n'; tmp++) |
1161 | ; |
1162 | escaped = g_strndup (start, tmp - start); |
1163 | version = NULL((void*)0); |
1164 | if (*tmp == ' ') |
1165 | { |
1166 | start = tmp; |
1167 | while (*start == ' ') |
1168 | start++; |
1169 | for (tmp = start; *tmp != 0 && *tmp != ' ' && *tmp != '\n'; tmp++) |
1170 | ; |
1171 | version = g_strndup (start, tmp - start); |
1172 | } |
1173 | |
1174 | query = strchr (escaped, '?'); |
1175 | if (query) |
1176 | *query = 0; |
1177 | |
1178 | if (strcmp (escaped, "/client.html") == 0 || strcmp (escaped, "/") == 0) |
1179 | send_data (request, "text/html", client_html, G_N_ELEMENTS(client_html)(sizeof (client_html) / sizeof ((client_html)[0])) - 1); |
1180 | else if (strcmp (escaped, "/broadway.js") == 0) |
1181 | send_data (request, "text/javascript", broadway_js, G_N_ELEMENTS(broadway_js)(sizeof (broadway_js) / sizeof ((broadway_js)[0])) - 1); |
1182 | else if (strcmp (escaped, "/socket") == 0) |
1183 | start_input (request); |
1184 | else |
1185 | send_error (request, 404, "File not found"); |
1186 | |
1187 | g_free (escaped); |
1188 | g_free (version); |
1189 | } |
1190 | |
1191 | static void |
1192 | got_http_request_line (GInputStream *stream, |
1193 | GAsyncResult *result, |
1194 | HttpRequest *request) |
1195 | { |
1196 | char *line; |
1197 | |
1198 | line = g_data_input_stream_read_line_finish (G_DATA_INPUT_STREAM (stream)((((GDataInputStream*) (void *) g_type_check_instance_cast (( GTypeInstance*) ((stream)), ((g_data_input_stream_get_type () )))))), result, NULL((void*)0), NULL((void*)0)); |
1199 | if (line == NULL((void*)0)) |
1200 | { |
1201 | http_request_free (request); |
1202 | g_printerr ("Error reading request lines\n"); |
1203 | return; |
1204 | } |
1205 | if (strlen (line) == 0) |
1206 | got_request (request); |
1207 | else |
1208 | { |
1209 | /* Protect against overflow in request length */ |
1210 | if (request->request->len > 1024 * 5) |
1211 | { |
1212 | send_error (request, 400, "Request too long"); |
1213 | } |
1214 | else |
1215 | { |
1216 | g_string_append_printf (request->request, "%s\n", line); |
1217 | g_data_input_stream_read_line_async (request->data, 0, NULL((void*)0), |
1218 | (GAsyncReadyCallback)got_http_request_line, request); |
1219 | } |
1220 | } |
1221 | g_free (line); |
1222 | } |
1223 | |
1224 | static gboolean |
1225 | handle_incoming_connection (GSocketService *service G_GNUC_UNUSED__attribute__ ((__unused__)), |
1226 | GSocketConnection *connection, |
1227 | GObject *source_object) |
1228 | { |
1229 | HttpRequest *request; |
1230 | GInputStream *in; |
1231 | |
1232 | request = g_new0 (HttpRequest, 1)((HttpRequest *) g_malloc0_n ((1), sizeof (HttpRequest))); |
1233 | request->socket_connection = g_object_ref (connection)((__typeof__ (connection)) (g_object_ref) (connection)); |
1234 | request->server = BROADWAY_SERVER (source_object)((((BroadwayServer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((source_object)), ((broadway_server_get_type())))))); |
1235 | request->request = g_string_new (""); |
1236 | |
1237 | if (request->server->ssl_cert && request->server->ssl_key) |
1238 | { |
1239 | GError *error = NULL((void*)0); |
1240 | GTlsCertificate *certificate; |
1241 | |
1242 | certificate = g_tls_certificate_new_from_files (request->server->ssl_cert, |
1243 | request->server->ssl_key, |
1244 | &error); |
1245 | if (!certificate) |
1246 | { |
1247 | g_warning ("Cannot create TLS certificate: %s", error->message); |
1248 | g_error_free (error); |
1249 | return FALSE(0); |
1250 | } |
1251 | |
1252 | request->connection = g_tls_server_connection_new (G_IO_STREAM (connection)((((GIOStream*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((connection)), ((g_io_stream_get_type ())))))), |
1253 | certificate, |
1254 | &error); |
1255 | if (!request->connection) |
1256 | { |
1257 | g_warning ("Cannot create TLS connection: %s", error->message); |
1258 | g_error_free (error); |
1259 | return FALSE(0); |
1260 | } |
1261 | |
1262 | if (!g_tls_connection_handshake (G_TLS_CONNECTION (request->connection)((((GTlsConnection*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((request->connection)), ((g_tls_connection_get_type () )))))), |
1263 | NULL((void*)0), &error)) |
1264 | { |
1265 | g_warning ("Cannot create TLS connection: %s", error->message); |
1266 | g_error_free (error); |
1267 | return FALSE(0); |
1268 | } |
1269 | } |
1270 | else |
1271 | { |
1272 | request->connection = G_IO_STREAM (g_object_ref (connection))((((GIOStream*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((((__typeof__ (connection)) (g_object_ref) (connection))) ), ((g_io_stream_get_type ())))))); |
1273 | } |
1274 | |
1275 | in = g_io_stream_get_input_stream (request->connection); |
1276 | |
1277 | request->data = g_data_input_stream_new (in); |
1278 | g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (request->data)((((GFilterInputStream*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((request->data)), ((g_filter_input_stream_get_type ())))))), FALSE(0)); |
1279 | /* Be tolerant of input */ |
1280 | g_data_input_stream_set_newline_type (request->data, G_DATA_STREAM_NEWLINE_TYPE_ANY); |
1281 | |
1282 | g_data_input_stream_read_line_async (request->data, 0, NULL((void*)0), |
1283 | (GAsyncReadyCallback)got_http_request_line, request); |
1284 | return TRUE(!(0)); |
1285 | } |
1286 | |
1287 | BroadwayServer * |
1288 | broadway_server_new (char *address, |
1289 | int port, |
1290 | const char *ssl_cert, |
1291 | const char *ssl_key, |
1292 | GError **error) |
1293 | { |
1294 | BroadwayServer *server; |
1295 | |
1296 | server = g_object_new (BROADWAY_TYPE_SERVER(broadway_server_get_type()), NULL((void*)0)); |
1297 | server->port = port; |
1298 | server->address = g_strdup (address)g_strdup_inline (address); |
1299 | server->ssl_cert = g_strdup (ssl_cert)g_strdup_inline (ssl_cert); |
1300 | server->ssl_key = g_strdup (ssl_key)g_strdup_inline (ssl_key); |
1301 | |
1302 | if (address == NULL((void*)0)) |
1303 | { |
1304 | if (!g_socket_listener_add_inet_port (G_SOCKET_LISTENER (server->service)((((GSocketListener*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((server->service)), ((g_socket_listener_get_type ()))) ))), |
1305 | server->port, |
1306 | G_OBJECT (server)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((server)), (((GType) ((20) << (2)))))))), |
1307 | error)) |
1308 | { |
1309 | g_prefix_error (error, "Unable to listen to port %d: ", server->port); |
1310 | g_object_unref (server); |
1311 | return NULL((void*)0); |
1312 | } |
1313 | } |
1314 | else |
1315 | { |
1316 | GInetAddress *inet_address; |
1317 | GSocketAddress *socket_address; |
1318 | |
1319 | inet_address = g_inet_address_new_from_string (address); |
1320 | if (inet_address == NULL((void*)0)) |
1321 | { |
1322 | g_set_error (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_INVALID_DATA, "Invalid ip address %s: ", address); |
1323 | g_object_unref (server); |
1324 | return NULL((void*)0); |
1325 | } |
1326 | socket_address = g_inet_socket_address_new (inet_address, port); |
1327 | g_object_unref (inet_address); |
1328 | if (!g_socket_listener_add_address (G_SOCKET_LISTENER (server->service)((((GSocketListener*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((server->service)), ((g_socket_listener_get_type ()))) ))), |
1329 | socket_address, |
1330 | G_SOCKET_TYPE_STREAM, |
1331 | G_SOCKET_PROTOCOL_TCP, |
1332 | G_OBJECT (server)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((server)), (((GType) ((20) << (2)))))))), |
1333 | NULL((void*)0), |
1334 | error)) |
1335 | { |
1336 | g_prefix_error (error, "Unable to listen to %s:%d: ", server->address, server->port); |
1337 | g_object_unref (socket_address); |
1338 | g_object_unref (server); |
1339 | return NULL((void*)0); |
1340 | } |
1341 | g_object_unref (socket_address); |
1342 | } |
1343 | |
1344 | g_signal_connect (server->service, "incoming",g_signal_connect_data ((server->service), ("incoming"), (( (GCallback) (handle_incoming_connection))), (((void*)0)), ((void *)0), (GConnectFlags) 0) |
1345 | G_CALLBACK (handle_incoming_connection), NULL)g_signal_connect_data ((server->service), ("incoming"), (( (GCallback) (handle_incoming_connection))), (((void*)0)), ((void *)0), (GConnectFlags) 0); |
1346 | return server; |
1347 | } |
1348 | |
1349 | BroadwayServer * |
1350 | broadway_server_on_unix_socket_new (char *address, GError **error) |
1351 | { |
1352 | BroadwayServer *server; |
1353 | GSocketAddress *socket_address = NULL((void*)0); |
1354 | |
1355 | server = g_object_new (BROADWAY_TYPE_SERVER(broadway_server_get_type()), NULL((void*)0)); |
1356 | server->port = -1; |
1357 | server->address = g_strdup (address)g_strdup_inline (address); |
1358 | |
1359 | if (address == NULL((void*)0)) |
1360 | { |
1361 | g_set_error (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_INVALID_DATA, "Unspecified unix domain socket address"); |
1362 | g_object_unref (server); |
1363 | return NULL((void*)0); |
1364 | } |
1365 | else |
1366 | { |
1367 | #ifdef HAVE_GIO_UNIX1 |
1368 | socket_address = g_unix_socket_address_new (address); |
1369 | #endif |
1370 | if (socket_address == NULL((void*)0)) |
1371 | { |
1372 | g_set_error (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_INVALID_DATA, "Invalid unix domain socket address %s: ", address); |
1373 | g_object_unref (server); |
1374 | return NULL((void*)0); |
1375 | } |
1376 | if (!g_socket_listener_add_address (G_SOCKET_LISTENER (server->service)((((GSocketListener*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((server->service)), ((g_socket_listener_get_type ()))) ))), |
1377 | socket_address, |
1378 | G_SOCKET_TYPE_STREAM, |
1379 | G_SOCKET_PROTOCOL_DEFAULT, |
1380 | G_OBJECT (server)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((server)), (((GType) ((20) << (2)))))))), |
1381 | NULL((void*)0), |
1382 | error)) |
1383 | { |
1384 | g_prefix_error (error, "Unable to listen to %s: ", server->address); |
1385 | g_object_unref (socket_address); |
1386 | g_object_unref (server); |
1387 | return NULL((void*)0); |
1388 | } |
1389 | g_object_unref (socket_address); |
1390 | } |
1391 | |
1392 | g_signal_connect (server->service, "incoming",g_signal_connect_data ((server->service), ("incoming"), (( (GCallback) (handle_incoming_connection))), (((void*)0)), ((void *)0), (GConnectFlags) 0) |
1393 | G_CALLBACK (handle_incoming_connection), NULL)g_signal_connect_data ((server->service), ("incoming"), (( (GCallback) (handle_incoming_connection))), (((void*)0)), ((void *)0), (GConnectFlags) 0); |
1394 | return server; |
1395 | } |
1396 | |
1397 | guint32 |
1398 | broadway_server_get_last_seen_time (BroadwayServer *server) |
1399 | { |
1400 | broadway_server_consume_all_input (server); |
1401 | return (guint32) server->last_seen_time; |
1402 | } |
1403 | |
1404 | void |
1405 | broadway_server_query_mouse (BroadwayServer *server, |
1406 | guint32 *toplevel, |
1407 | gint32 *root_x, |
1408 | gint32 *root_y, |
1409 | guint32 *mask) |
1410 | { |
1411 | if (server->output) |
1412 | { |
1413 | broadway_server_consume_all_input (server); |
1414 | if (root_x) |
1415 | *root_x = server->future_root_x; |
1416 | if (root_y) |
1417 | *root_y = server->future_root_y; |
1418 | if (mask) |
1419 | *mask = server->future_state; |
1420 | if (toplevel) |
1421 | *toplevel = server->future_mouse_in_toplevel; |
1422 | return; |
1423 | } |
1424 | |
1425 | /* Fallback when unconnected */ |
1426 | if (root_x) |
1427 | *root_x = server->last_x; |
1428 | if (root_y) |
1429 | *root_y = server->last_y; |
1430 | if (mask) |
1431 | *mask = server->last_state; |
1432 | if (toplevel) |
1433 | *toplevel = server->mouse_in_toplevel_id; |
1434 | } |
1435 | |
1436 | void |
1437 | broadway_server_destroy_window (BroadwayServer *server, |
1438 | gint id) |
1439 | { |
1440 | BroadwayWindow *window; |
1441 | |
1442 | if (server->mouse_in_toplevel_id == id) |
1443 | { |
1444 | /* TODO: Send leave + enter event, update cursors, etc */ |
1445 | server->mouse_in_toplevel_id = 0; |
1446 | } |
1447 | |
1448 | if (server->pointer_grab_window_id == id) |
1449 | server->pointer_grab_window_id = -1; |
1450 | |
1451 | if (server->output) |
1452 | broadway_output_destroy_surface (server->output, |
1453 | id); |
1454 | |
1455 | window = g_hash_table_lookup (server->id_ht, |
1456 | GINT_TO_POINTER (id)((gpointer) (glong) (id))); |
1457 | if (window != NULL((void*)0)) |
1458 | { |
1459 | server->toplevels = g_list_remove (server->toplevels, window); |
1460 | g_hash_table_remove (server->id_ht, |
1461 | GINT_TO_POINTER (id)((gpointer) (glong) (id))); |
1462 | |
1463 | g_free (window->cached_surface_name); |
1464 | if (window->cached_surface != NULL((void*)0)) |
1465 | cairo_surface_destroy (window->cached_surface); |
1466 | |
1467 | g_free (window); |
1468 | } |
1469 | } |
1470 | |
1471 | gboolean |
1472 | broadway_server_window_show (BroadwayServer *server, |
1473 | gint id) |
1474 | { |
1475 | BroadwayWindow *window; |
1476 | gboolean sent = FALSE(0); |
1477 | |
1478 | window = g_hash_table_lookup (server->id_ht, |
1479 | GINT_TO_POINTER (id)((gpointer) (glong) (id))); |
1480 | if (window == NULL((void*)0)) |
1481 | return FALSE(0); |
1482 | |
1483 | window->visible = TRUE(!(0)); |
1484 | |
1485 | if (server->output) |
1486 | { |
1487 | broadway_output_show_surface (server->output, window->id); |
1488 | sent = TRUE(!(0)); |
1489 | } |
1490 | |
1491 | return sent; |
1492 | } |
1493 | |
1494 | gboolean |
1495 | broadway_server_window_hide (BroadwayServer *server, |
1496 | gint id) |
1497 | { |
1498 | BroadwayWindow *window; |
1499 | gboolean sent = FALSE(0); |
1500 | |
1501 | window = g_hash_table_lookup (server->id_ht, |
1502 | GINT_TO_POINTER (id)((gpointer) (glong) (id))); |
1503 | if (window == NULL((void*)0)) |
1504 | return FALSE(0); |
1505 | |
1506 | window->visible = FALSE(0); |
1507 | |
1508 | if (server->mouse_in_toplevel_id == id) |
1509 | { |
1510 | /* TODO: Send leave + enter event, update cursors, etc */ |
1511 | server->mouse_in_toplevel_id = 0; |
1512 | } |
1513 | |
1514 | if (server->pointer_grab_window_id == id) |
1515 | server->pointer_grab_window_id = -1; |
1516 | |
1517 | if (server->output) |
1518 | { |
1519 | broadway_output_hide_surface (server->output, window->id); |
1520 | sent = TRUE(!(0)); |
1521 | } |
1522 | return sent; |
1523 | } |
1524 | |
1525 | void |
1526 | broadway_server_window_raise (BroadwayServer *server, |
1527 | gint id) |
1528 | { |
1529 | BroadwayWindow *window; |
1530 | |
1531 | window = g_hash_table_lookup (server->id_ht, |
1532 | GINT_TO_POINTER (id)((gpointer) (glong) (id))); |
1533 | if (window == NULL((void*)0)) |
1534 | return; |
1535 | |
1536 | server->toplevels = g_list_remove (server->toplevels, window); |
1537 | server->toplevels = g_list_append (server->toplevels, window); |
1538 | |
1539 | if (server->output) |
1540 | broadway_output_raise_surface (server->output, window->id); |
1541 | } |
1542 | |
1543 | void |
1544 | broadway_server_set_show_keyboard (BroadwayServer *server, |
1545 | gboolean show) |
1546 | { |
1547 | server->show_keyboard = show; |
1548 | |
1549 | if (server->output) |
1550 | { |
1551 | broadway_output_set_show_keyboard (server->output, server->show_keyboard); |
1552 | broadway_server_flush (server); |
1553 | } |
1554 | } |
1555 | |
1556 | void |
1557 | broadway_server_window_lower (BroadwayServer *server, |
1558 | gint id) |
1559 | { |
1560 | BroadwayWindow *window; |
1561 | |
1562 | window = g_hash_table_lookup (server->id_ht, |
1563 | GINT_TO_POINTER (id)((gpointer) (glong) (id))); |
1564 | if (window == NULL((void*)0)) |
1565 | return; |
1566 | |
1567 | server->toplevels = g_list_remove (server->toplevels, window); |
1568 | server->toplevels = g_list_prepend (server->toplevels, window); |
1569 | |
1570 | if (server->output) |
1571 | broadway_output_lower_surface (server->output, window->id); |
1572 | } |
1573 | |
1574 | void |
1575 | broadway_server_window_set_transient_for (BroadwayServer *server, |
1576 | gint id, gint parent) |
1577 | { |
1578 | BroadwayWindow *window; |
1579 | |
1580 | window = g_hash_table_lookup (server->id_ht, |
1581 | GINT_TO_POINTER (id)((gpointer) (glong) (id))); |
1582 | if (window == NULL((void*)0)) |
1583 | return; |
1584 | |
1585 | window->transient_for = parent; |
1586 | |
1587 | if (server->output) |
1588 | { |
1589 | broadway_output_set_transient_for (server->output, window->id, window->transient_for); |
1590 | broadway_server_flush (server); |
1591 | } |
1592 | } |
1593 | |
1594 | gboolean |
1595 | broadway_server_has_client (BroadwayServer *server) |
1596 | { |
1597 | return server->output != NULL((void*)0); |
1598 | } |
1599 | |
1600 | void |
1601 | broadway_server_window_update (BroadwayServer *server, |
1602 | gint id, |
1603 | cairo_surface_t *surface) |
1604 | { |
1605 | BroadwayWindow *window; |
1606 | BroadwayBuffer *buffer; |
1607 | |
1608 | if (surface == NULL((void*)0)) |
1609 | return; |
1610 | |
1611 | window = g_hash_table_lookup (server->id_ht, |
1612 | GINT_TO_POINTER (id)((gpointer) (glong) (id))); |
1613 | if (window == NULL((void*)0)) |
1614 | return; |
1615 | |
1616 | g_assert (window->width == cairo_image_surface_get_width (surface))do { if (window->width == cairo_image_surface_get_width (surface )) ; else g_assertion_message_expr ("Cdk", "broadway-server.c" , 1616, ((const char*) (__func__)), "window->width == cairo_image_surface_get_width (surface)" ); } while (0); |
1617 | g_assert (window->height == cairo_image_surface_get_height (surface))do { if (window->height == cairo_image_surface_get_height ( surface)) ; else g_assertion_message_expr ("Cdk", "broadway-server.c" , 1617, ((const char*) (__func__)), "window->height == cairo_image_surface_get_height (surface)" ); } while (0); |
1618 | |
1619 | buffer = broadway_buffer_create (window->width, window->height, |
1620 | cairo_image_surface_get_data (surface), |
1621 | cairo_image_surface_get_stride (surface)); |
1622 | |
1623 | if (server->output != NULL((void*)0)) |
1624 | { |
1625 | window->buffer_synced = TRUE(!(0)); |
1626 | broadway_output_put_buffer (server->output, window->id, |
1627 | window->buffer, buffer); |
1628 | } |
1629 | |
1630 | if (window->buffer) |
1631 | broadway_buffer_destroy (window->buffer); |
1632 | |
1633 | window->buffer = buffer; |
1634 | } |
1635 | |
1636 | gboolean |
1637 | broadway_server_window_move_resize (BroadwayServer *server, |
1638 | gint id, |
1639 | gboolean with_move, |
1640 | int x, |
1641 | int y, |
1642 | int width, |
1643 | int height) |
1644 | { |
1645 | BroadwayWindow *window; |
1646 | gboolean with_resize; |
1647 | gboolean sent = FALSE(0); |
1648 | |
1649 | window = g_hash_table_lookup (server->id_ht, |
1650 | GINT_TO_POINTER (id)((gpointer) (glong) (id))); |
1651 | if (window == NULL((void*)0)) |
1652 | return FALSE(0); |
1653 | |
1654 | with_resize = width != window->width || height != window->height; |
1655 | window->width = width; |
1656 | window->height = height; |
1657 | |
1658 | if (server->output != NULL((void*)0)) |
1659 | { |
1660 | broadway_output_move_resize_surface (server->output, |
1661 | window->id, |
1662 | with_move, x, y, |
1663 | with_resize, window->width, window->height); |
1664 | sent = TRUE(!(0)); |
1665 | } |
1666 | else |
1667 | { |
1668 | if (with_move) |
1669 | { |
1670 | window->x = x; |
1671 | window->y = y; |
1672 | } |
1673 | |
1674 | fake_configure_notify (server, window); |
1675 | } |
1676 | |
1677 | return sent; |
1678 | } |
1679 | |
1680 | void |
1681 | broadway_server_focus_window (BroadwayServer *server, |
1682 | gint new_focused_window) |
1683 | { |
1684 | BroadwayInputMsg focus_msg; |
1685 | |
1686 | if (server->focused_window_id == new_focused_window) |
1687 | return; |
1688 | |
1689 | memset (&focus_msg, 0, sizeof (focus_msg)); |
1690 | focus_msg.base.type = BROADWAY_EVENT_FOCUS; |
1691 | focus_msg.base.time = broadway_server_get_last_seen_time (server); |
1692 | focus_msg.focus.old_id = server->focused_window_id; |
1693 | focus_msg.focus.new_id = new_focused_window; |
1694 | |
1695 | broadway_events_got_input (&focus_msg, -1); |
1696 | |
1697 | /* Keep track of the new focused window */ |
1698 | server->focused_window_id = new_focused_window; |
1699 | } |
1700 | |
1701 | guint32 |
1702 | broadway_server_grab_pointer (BroadwayServer *server, |
1703 | gint client_id, |
1704 | gint id, |
1705 | gboolean owner_events, |
1706 | guint32 event_mask G_GNUC_UNUSED__attribute__ ((__unused__)), |
1707 | guint32 time_) |
1708 | { |
1709 | if (server->pointer_grab_window_id != -1 && |
1710 | time_ != 0 && server->pointer_grab_time > time_) |
1711 | return CDK_GRAB_ALREADY_GRABBED; |
1712 | |
1713 | if (time_ == 0) |
1714 | time_ = server->last_seen_time; |
1715 | |
1716 | server->pointer_grab_window_id = id; |
1717 | server->pointer_grab_client_id = client_id; |
1718 | server->pointer_grab_owner_events = owner_events; |
1719 | server->pointer_grab_time = time_; |
1720 | |
1721 | if (server->output) |
1722 | { |
1723 | broadway_output_grab_pointer (server->output, |
1724 | id, |
1725 | owner_events); |
1726 | broadway_server_flush (server); |
1727 | } |
1728 | |
1729 | /* TODO: What about toplevel grab events if we're not connected? */ |
1730 | |
1731 | return CDK_GRAB_SUCCESS; |
1732 | } |
1733 | |
1734 | guint32 |
1735 | broadway_server_ungrab_pointer (BroadwayServer *server, |
1736 | guint32 time_) |
1737 | { |
1738 | guint32 serial; |
1739 | |
1740 | if (server->pointer_grab_window_id != -1 && |
1741 | time_ != 0 && server->pointer_grab_time > time_) |
1742 | return 0; |
1743 | |
1744 | /* TODO: What about toplevel grab events if we're not connected? */ |
1745 | |
1746 | if (server->output) |
1747 | { |
1748 | serial = broadway_output_ungrab_pointer (server->output); |
1749 | broadway_server_flush (server); |
1750 | } |
1751 | else |
1752 | { |
1753 | serial = server->saved_serial; |
1754 | } |
1755 | |
1756 | server->pointer_grab_window_id = -1; |
1757 | |
1758 | return serial; |
1759 | } |
1760 | |
1761 | static const cairo_user_data_key_t shm_cairo_key; |
1762 | |
1763 | typedef struct { |
1764 | void *data; |
1765 | gsize data_size; |
1766 | } ShmSurfaceData; |
1767 | |
1768 | static void |
1769 | shm_data_unmap (void *_data) |
1770 | { |
1771 | ShmSurfaceData *data = _data; |
1772 | #ifdef G_OS_UNIX |
1773 | munmap (data->data, data->data_size); |
1774 | #elif defined(G_OS_WIN32) |
1775 | UnmapViewOfFile (data->data); |
1776 | #endif |
1777 | g_free (data); |
1778 | } |
1779 | |
1780 | cairo_surface_t * |
1781 | broadway_server_open_surface (BroadwayServer *server, |
1782 | guint32 id, |
1783 | char *name, |
1784 | int width, |
1785 | int height) |
1786 | { |
1787 | BroadwayWindow *window; |
1788 | ShmSurfaceData *data; |
1789 | cairo_surface_t *surface; |
1790 | gsize size; |
1791 | void *ptr; |
1792 | |
1793 | window = g_hash_table_lookup (server->id_ht, |
1794 | GINT_TO_POINTER (id)((gpointer) (glong) (id))); |
1795 | if (window == NULL((void*)0)) |
1796 | return NULL((void*)0); |
1797 | |
1798 | if (window->cached_surface_name != NULL((void*)0) && |
1799 | strcmp (name, window->cached_surface_name) == 0) |
1800 | return cairo_surface_reference (window->cached_surface); |
1801 | |
1802 | size = width * height * sizeof (guint32); |
1803 | |
1804 | ptr = map_named_shm (name, size); |
1805 | |
1806 | if (ptr == NULL((void*)0)) |
1807 | return NULL((void*)0); |
1808 | |
1809 | data = g_new0 (ShmSurfaceData, 1)((ShmSurfaceData *) g_malloc0_n ((1), sizeof (ShmSurfaceData) )); |
1810 | |
1811 | data->data = ptr; |
1812 | data->data_size = size; |
1813 | |
1814 | surface = cairo_image_surface_create_for_data ((guchar *)data->data, |
1815 | CAIRO_FORMAT_ARGB32, |
1816 | width, height, |
1817 | width * sizeof (guint32)); |
1818 | g_assert (surface != NULL)do { if (surface != ((void*)0)) ; else g_assertion_message_expr ("Cdk", "broadway-server.c", 1818, ((const char*) (__func__) ), "surface != NULL"); } while (0); |
1819 | |
1820 | cairo_surface_set_user_data (surface, &shm_cairo_key, |
1821 | data, shm_data_unmap); |
1822 | |
1823 | g_free (window->cached_surface_name); |
1824 | window->cached_surface_name = g_strdup (name)g_strdup_inline (name); |
1825 | |
1826 | if (window->cached_surface != NULL((void*)0)) |
1827 | cairo_surface_destroy (window->cached_surface); |
1828 | window->cached_surface = cairo_surface_reference (surface); |
1829 | |
1830 | return surface; |
1831 | } |
1832 | |
1833 | guint32 |
1834 | broadway_server_new_window (BroadwayServer *server, |
1835 | int x, |
1836 | int y, |
1837 | int width, |
1838 | int height, |
1839 | gboolean is_temp) |
1840 | { |
1841 | BroadwayWindow *window; |
1842 | |
1843 | window = g_new0 (BroadwayWindow, 1)((BroadwayWindow *) g_malloc0_n ((1), sizeof (BroadwayWindow) )); |
1844 | window->id = server->id_counter++; |
1845 | window->x = x; |
1846 | window->y = y; |
1847 | if (x == 0 && y == 0 && !is_temp) |
1848 | { |
1849 | /* TODO: Better way to know if we should pick default pos */ |
1850 | window->x = 100; |
1851 | window->y = 100; |
1852 | } |
1853 | window->width = width; |
1854 | window->height = height; |
1855 | window->is_temp = is_temp; |
1856 | |
1857 | g_hash_table_insert (server->id_ht, |
1858 | GINT_TO_POINTER (window->id)((gpointer) (glong) (window->id)), |
1859 | window); |
1860 | |
1861 | server->toplevels = g_list_append (server->toplevels, window); |
1862 | |
1863 | if (server->output) |
1864 | broadway_output_new_surface (server->output, |
1865 | window->id, |
1866 | window->x, |
1867 | window->y, |
1868 | window->width, |
1869 | window->height, |
1870 | window->is_temp); |
1871 | else |
1872 | fake_configure_notify (server, window); |
1873 | |
1874 | return window->id; |
1875 | } |
1876 | |
1877 | static void |
1878 | broadway_server_resync_windows (BroadwayServer *server) |
1879 | { |
1880 | GList *l; |
1881 | |
1882 | if (server->output == NULL((void*)0)) |
1883 | return; |
1884 | |
1885 | /* First create all windows */ |
1886 | for (l = server->toplevels; l != NULL((void*)0); l = l->next) |
1887 | { |
1888 | BroadwayWindow *window = l->data; |
1889 | |
1890 | if (window->id == 0) |
1891 | continue; /* Skip root */ |
1892 | |
1893 | window->buffer_synced = FALSE(0); |
1894 | broadway_output_new_surface (server->output, |
1895 | window->id, |
1896 | window->x, |
1897 | window->y, |
1898 | window->width, |
1899 | window->height, |
1900 | window->is_temp); |
1901 | } |
1902 | |
1903 | /* Then do everything that may reference other windows */ |
1904 | for (l = server->toplevels; l != NULL((void*)0); l = l->next) |
1905 | { |
1906 | BroadwayWindow *window = l->data; |
1907 | |
1908 | if (window->id == 0) |
1909 | continue; /* Skip root */ |
1910 | |
1911 | if (window->transient_for != -1) |
1912 | broadway_output_set_transient_for (server->output, window->id, window->transient_for); |
1913 | if (window->visible) |
1914 | { |
1915 | broadway_output_show_surface (server->output, window->id); |
1916 | |
1917 | if (window->buffer != NULL((void*)0)) |
1918 | { |
1919 | window->buffer_synced = TRUE(!(0)); |
1920 | broadway_output_put_buffer (server->output, window->id, |
1921 | NULL((void*)0), window->buffer); |
1922 | } |
1923 | } |
1924 | } |
1925 | |
1926 | if (server->show_keyboard) |
1927 | broadway_output_set_show_keyboard (server->output, TRUE(!(0))); |
1928 | |
1929 | broadway_server_flush (server); |
1930 | } |