Bug Summary

File:cdk/broadway/broadway-server.c
Warning:line 411, column 3
Returned pointer value points outside the original object (potential buffer overflow)
Note:line 411, column 10
Original object is an array of 0 'unsigned int' objects, returned pointer points at index 12

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name broadway-server.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/cdk/broadway -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -D G_LOG_DOMAIN="Cdk" -D G_LOG_USE_STRUCTURED=1 -D CDK_COMPILATION -D CDK_DISABLE_DEPRECATION_WARNINGS -I ../.. -I ../../cdk -I ../../cdk -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/cdk/broadway -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-170037-43636-1 -x c broadway-server.c
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
38typedef struct BroadwayInput BroadwayInput;
39typedef struct BroadwayWindow BroadwayWindow;
40struct _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
83struct _BroadwayServerClass
84{
85 GObjectClass parent_class;
86};
87
88typedef struct HttpRequest {
89 BroadwayServer *server;
90 GSocketConnection *socket_connection;
91 GIOStream *connection;
92 GDataInputStream *data;
93 GString *request;
94} HttpRequest;
95
96struct 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
107struct 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
124static void broadway_server_resync_windows (BroadwayServer *server);
125
126static GType broadway_server_get_type (void);
127
128G_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
130static void
131broadway_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
155static void
156broadway_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
167static void
168broadway_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
175static void start (BroadwayInput *input);
176
177static void
178http_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
187static void
188broadway_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
196static void
197update_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
294gboolean
295broadway_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
312static gboolean
313is_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
326static void
327process_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
341static void
342process_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
366static void
367fake_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
384static guint32 *
385parse_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
398static guint32 *
399parse_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++);
31
Value assigned to 'p'
410
411 return p;
Original object is an array of 0 'unsigned int' objects, returned pointer points at index 12
32
Returned pointer value points outside the original object (potential buffer overflow)
412}
413
414static void
415update_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
423static void
424parse_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) {
27
Assuming 'time_' is equal to 0
28
Taking true branch
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) {
29
Control jumps to 'case BROADWAY_EVENT_TOUCH:' at line 482
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);
30
Calling 'parse_touch_data'
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
524static inline void
525hex_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
554static void
555parse_input (BroadwayInput *input)
556{
557 if (!input->buffer->len)
10
Assuming field 'len' is not equal to 0
11
Taking false branch
558 return;
559
560 hex_dump (input->buffer->data, input->buffer->len);
561
562 while (input->buffer->len > 2)
12
Assuming field 'len' is > 2
13
Loop condition is true. Entering loop body
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)
14
Assuming 'payload_len' is not equal to 126
15
Taking false branch
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)
16
Assuming 'payload_len' is not equal to 127
17
Taking false branch
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)
18
Assuming 'is_mask' is 0
19
Taking false branch
599 {
600 if (data - buf + 4 > len)
601 return;
602 mask = data;
603 data += 4;
604 }
605
606 if (data - buf + payload_len > len)
20
Assuming the condition is false
21
Taking false branch
607 return; /* wait to accumulate more */
608
609 if (is_mask
21.1
'is_mask' is 0
)
22
Taking false branch
610 {
611 gsize i;
612 for (i = 0; i < payload_len; i++)
613 data[i] ^= mask[i%4];
614 }
615
616 switch (code) {
23
Control jumps to 'case BROADWAY_WS_BINARY:' at line 619
617 case BROADWAY_WS_CNX_CLOSE:
618 break; /* hang around anyway */
619 case BROADWAY_WS_BINARY:
620 if (!fin)
24
Assuming 'fin' is not equal to 0
25
Taking false branch
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);
26
Calling 'parse_input_message'
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
650static gboolean
651process_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
658static void
659queue_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
666static gboolean
667broadway_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))
5
Assuming 'input' is not equal to NULL
6
Taking false branch
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)
7
Assuming 'res' is > 0
8
Taking false branch
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);
9
Calling 'parse_input'
705 return TRUE(!(0));
706}
707
708static void
709broadway_server_consume_all_input (BroadwayServer *server)
710{
711 broadway_server_read_all_input_nonblocking (server->input);
4
Calling 'broadway_server_read_all_input_nonblocking'
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
720static gboolean
721input_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
735guint32
736broadway_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
744void
745broadway_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
754void
755broadway_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) */
769static BroadwayInputMsg *
770broadway_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
825static void *
826map_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
906static char *
907parse_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
923static void
924send_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=' */
949static gchar *
950generate_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
971static void
972start_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
1076static void
1077start (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
1119static void
1120send_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
1144static void
1145got_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
1191static void
1192got_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
1224static gboolean
1225handle_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
1287BroadwayServer *
1288broadway_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
1349BroadwayServer *
1350broadway_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
1397guint32
1398broadway_server_get_last_seen_time (BroadwayServer *server)
1399{
1400 broadway_server_consume_all_input (server);
1401 return (guint32) server->last_seen_time;
1402}
1403
1404void
1405broadway_server_query_mouse (BroadwayServer *server,
1406 guint32 *toplevel,
1407 gint32 *root_x,
1408 gint32 *root_y,
1409 guint32 *mask)
1410{
1411 if (server->output)
1
Assuming field 'output' is non-null
2
Taking true branch
1412 {
1413 broadway_server_consume_all_input (server);
3
Calling 'broadway_server_consume_all_input'
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
1436void
1437broadway_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
1471gboolean
1472broadway_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
1494gboolean
1495broadway_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
1525void
1526broadway_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
1543void
1544broadway_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
1556void
1557broadway_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
1574void
1575broadway_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
1594gboolean
1595broadway_server_has_client (BroadwayServer *server)
1596{
1597 return server->output != NULL((void*)0);
1598}
1599
1600void
1601broadway_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
1636gboolean
1637broadway_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
1680void
1681broadway_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
1701guint32
1702broadway_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
1734guint32
1735broadway_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
1761static const cairo_user_data_key_t shm_cairo_key;
1762
1763typedef struct {
1764 void *data;
1765 gsize data_size;
1766} ShmSurfaceData;
1767
1768static void
1769shm_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
1780cairo_surface_t *
1781broadway_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
1833guint32
1834broadway_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
1877static void
1878broadway_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}