5 #include "gdkbroadway-server.h"
7 #include "gdkprivate-broadway.h"
10 #include <glib/gprintf.h>
11 #include <gio/gunixsocketaddress.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <netinet/tcp.h>
21 typedef struct BroadwayInput BroadwayInput;
23 struct _GdkBroadwayServer {
24 GObject parent_instance;
27 GSocketConnection *connection;
29 guint32 recv_buffer_size;
30 guint8 recv_buffer[1024];
32 guint process_input_idle;
37 struct _GdkBroadwayServerClass
39 GObjectClass parent_class;
42 static gboolean input_available_cb (gpointer stream, gpointer user_data);
44 G_DEFINE_TYPE (GdkBroadwayServer, gdk_broadway_server, G_TYPE_OBJECT)
47 gdk_broadway_server_init (GdkBroadwayServer *server)
49 server->next_serial = 1;
53 gdk_broadway_server_finalize (GObject *object)
55 G_OBJECT_CLASS (gdk_broadway_server_parent_class)->finalize (object);
59 gdk_broadway_server_class_init (GdkBroadwayServerClass * class)
61 GObjectClass *object_class = G_OBJECT_CLASS (class);
63 object_class->finalize = gdk_broadway_server_finalize;
67 _gdk_broadway_server_lookahead_event (GdkBroadwayServer *server,
75 _gdk_broadway_server_get_next_serial (GdkBroadwayServer *server)
77 return (gulong)server->next_serial;
81 _gdk_broadway_server_new (int port, GError **error)
83 GdkBroadwayServer *server;
85 GSocketClient *client;
86 GSocketConnection *connection;
87 GSocketAddress *address;
88 GPollableInputStream *pollable;
93 basename = g_strdup_printf ("broadway%d.socket", port);
94 path = g_build_filename (g_get_user_runtime_dir (), basename, NULL);
97 address = g_unix_socket_address_new_with_type (path, -1,
98 G_UNIX_SOCKET_ADDRESS_ABSTRACT);
101 client = g_socket_client_new ();
104 connection = g_socket_client_connect (client, G_SOCKET_CONNECTABLE (address), NULL, error);
106 g_object_unref (address);
107 g_object_unref (client);
109 if (connection == NULL)
112 server = g_object_new (GDK_TYPE_BROADWAY_SERVER, NULL);
113 server->connection = connection;
115 in = g_io_stream_get_input_stream (G_IO_STREAM (server->connection));
116 pollable = G_POLLABLE_INPUT_STREAM (in);
118 source = g_pollable_input_stream_create_source (pollable, NULL);
119 g_source_attach (source, NULL);
120 g_source_set_callback (source, (GSourceFunc)input_available_cb, server, NULL);
126 _gdk_broadway_server_get_last_seen_time (GdkBroadwayServer *server)
132 gdk_broadway_server_send_message_with_size (GdkBroadwayServer *server, BroadwayRequestBase *base,
133 gsize size, guint32 type)
140 base->serial = server->next_serial++;
142 out = g_io_stream_get_output_stream (G_IO_STREAM (server->connection));
144 if (!g_output_stream_write_all (out, base, size, &written, NULL, NULL))
146 g_printerr ("Unable to write to server\n");
150 g_assert (written == size);
155 #define gdk_broadway_server_send_message(_server, _msg, _type) \
156 gdk_broadway_server_send_message_with_size(_server, (BroadwayRequestBase *)&_msg, sizeof (_msg), _type)
159 parse_all_input (GdkBroadwayServer *server)
163 BroadwayReply *reply;
165 p = server->recv_buffer;
166 end = p + server->recv_buffer_size;
168 while (p + sizeof (guint32) <= end)
170 memcpy (&size, p, sizeof (guint32));
174 reply = g_memdup (p, size);
177 server->incomming = g_list_append (server->incomming, reply);
181 memmove (server->recv_buffer, p, end - p);
182 server->recv_buffer_size = end - p;
186 read_some_input_blocking (GdkBroadwayServer *server)
191 in = g_io_stream_get_input_stream (G_IO_STREAM (server->connection));
193 g_assert (server->recv_buffer_size < sizeof (server->recv_buffer));
194 res = g_input_stream_read (in, &server->recv_buffer[server->recv_buffer_size],
195 sizeof (server->recv_buffer) - server->recv_buffer_size,
200 g_printerr ("Unable to read from broadway server\n");
204 server->recv_buffer_size += res;
208 read_some_input_nonblocking (GdkBroadwayServer *server)
211 GPollableInputStream *pollable;
215 in = g_io_stream_get_input_stream (G_IO_STREAM (server->connection));
216 pollable = G_POLLABLE_INPUT_STREAM (in);
218 g_assert (server->recv_buffer_size < sizeof (server->recv_buffer));
220 res = g_pollable_input_stream_read_nonblocking (pollable, &server->recv_buffer[server->recv_buffer_size],
221 sizeof (server->recv_buffer) - server->recv_buffer_size,
224 if (res < 0 && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
226 g_error_free (error);
231 g_printerr ("Unable to read from broadway server: %s\n", error ? error->message : "eof");
235 server->recv_buffer_size += res;
238 static BroadwayReply *
239 find_response_by_serial (GdkBroadwayServer *server, guint32 serial)
243 for (l = server->incomming; l != NULL; l = l->next)
245 BroadwayReply *reply = l->data;
247 if (reply->base.in_reply_to == serial)
255 process_input_messages (GdkBroadwayServer *server)
257 BroadwayReply *reply;
259 if (server->process_input_idle != 0)
261 g_source_remove (server->process_input_idle);
262 server->process_input_idle = 0;
265 while (server->incomming)
267 reply = server->incomming->data;
269 g_list_delete_link (server->incomming,
272 if (reply->base.type == BROADWAY_REPLY_EVENT)
273 _gdk_broadway_events_got_input (&reply->event.msg);
275 g_warning ("Unhandled reply type %d\n", reply->base.type);
281 process_input_idle_cb (GdkBroadwayServer *server)
283 server->process_input_idle = 0;
284 process_input_messages (server);
285 return G_SOURCE_REMOVE;
289 queue_process_input_at_idle (GdkBroadwayServer *server)
291 if (server->process_input_idle == 0)
292 server->process_input_idle =
293 g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc)process_input_idle_cb, server, NULL);
297 input_available_cb (gpointer stream, gpointer user_data)
299 GdkBroadwayServer *server = user_data;
301 read_some_input_nonblocking (server);
302 parse_all_input (server);
304 process_input_messages (server);
306 return G_SOURCE_CONTINUE;
309 static BroadwayReply *
310 gdk_broadway_server_wait_for_reply (GdkBroadwayServer *server,
313 BroadwayReply *reply;
317 reply = find_response_by_serial (server, serial);
320 server->incomming = g_list_remove (server->incomming, reply);
324 read_some_input_blocking (server);
325 parse_all_input (server);
328 queue_process_input_at_idle (server);
333 _gdk_broadway_server_flush (GdkBroadwayServer *server)
335 BroadwayRequestFlush msg;
337 gdk_broadway_server_send_message(server, msg, BROADWAY_REQUEST_FLUSH);
341 _gdk_broadway_server_sync (GdkBroadwayServer *server)
343 BroadwayRequestSync msg;
345 BroadwayReply *reply;
347 serial = gdk_broadway_server_send_message (server, msg,
348 BROADWAY_REQUEST_SYNC);
349 reply = gdk_broadway_server_wait_for_reply (server, serial);
351 g_assert (reply->base.type == BROADWAY_REPLY_SYNC);
359 _gdk_broadway_server_query_mouse (GdkBroadwayServer *server,
365 BroadwayRequestQueryMouse msg;
367 BroadwayReply *reply;
369 serial = gdk_broadway_server_send_message (server, msg,
370 BROADWAY_REQUEST_QUERY_MOUSE);
371 reply = gdk_broadway_server_wait_for_reply (server, serial);
373 g_assert (reply->base.type == BROADWAY_REPLY_QUERY_MOUSE);
376 *toplevel = reply->query_mouse.toplevel;
378 *root_x = reply->query_mouse.root_x;
380 *root_y = reply->query_mouse.root_y;
382 *mask = reply->query_mouse.mask;
388 _gdk_broadway_server_new_window (GdkBroadwayServer *server,
395 BroadwayRequestNewWindow msg;
397 BroadwayReply *reply;
403 msg.is_temp = is_temp;
405 serial = gdk_broadway_server_send_message (server, msg,
406 BROADWAY_REQUEST_NEW_WINDOW);
407 reply = gdk_broadway_server_wait_for_reply (server, serial);
409 g_assert (reply->base.type == BROADWAY_REPLY_NEW_WINDOW);
411 id = reply->new_window.id;
419 _gdk_broadway_server_destroy_window (GdkBroadwayServer *server,
422 BroadwayRequestDestroyWindow msg;
425 gdk_broadway_server_send_message (server, msg,
426 BROADWAY_REQUEST_DESTROY_WINDOW);
430 _gdk_broadway_server_window_show (GdkBroadwayServer *server,
433 BroadwayRequestShowWindow msg;
436 gdk_broadway_server_send_message (server, msg,
437 BROADWAY_REQUEST_SHOW_WINDOW);
443 _gdk_broadway_server_window_hide (GdkBroadwayServer *server,
446 BroadwayRequestHideWindow msg;
449 gdk_broadway_server_send_message (server, msg,
450 BROADWAY_REQUEST_HIDE_WINDOW);
456 _gdk_broadway_server_window_set_transient_for (GdkBroadwayServer *server,
457 gint id, gint parent)
459 BroadwayRequestSetTransientFor msg;
463 gdk_broadway_server_send_message (server, msg,
464 BROADWAY_REQUEST_SET_TRANSIENT_FOR);
468 _gdk_broadway_server_window_translate (GdkBroadwayServer *server,
470 cairo_region_t *area,
474 BroadwayRequestTranslate *msg;
475 cairo_rectangle_int_t rect;
479 n_rects = cairo_region_num_rectangles (area);
481 msg_size = sizeof (BroadwayRequestTranslate) + (n_rects-1) * sizeof (BroadwayRect);
482 msg = g_malloc (msg_size);
487 msg->n_rects = n_rects;
489 for (i = 0; i < n_rects; i++)
491 cairo_region_get_rectangle (area, i, &rect);
492 msg->rects[i].x = rect.x;
493 msg->rects[i].y = rect.y;
494 msg->rects[i].width = rect.width;
495 msg->rects[i].height = rect.height;
498 gdk_broadway_server_send_message_with_size (server, (BroadwayRequestBase *)msg, msg_size,
499 BROADWAY_REQUEST_TRANSLATE);
505 make_valid_fs_char (char c)
507 if (c == 0 || c == '/')
512 /* name must have at least space for 34 bytes */
514 create_random_shm (char *name)
523 for (i = 0; i < 32/4; i++)
526 name[o++] = make_valid_fs_char ((r >> 0) & 0xff);
527 name[o++] = make_valid_fs_char ((r >> 8) & 0xff);
528 name[o++] = make_valid_fs_char ((r >> 16) & 0xff);
529 name[o++] = make_valid_fs_char ((r >> 24) & 0xff);
533 fd = shm_open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
539 g_printerr ("Unable to allocate shared mem for window");
546 static const cairo_user_data_key_t gdk_broadway_shm_cairo_key;
552 } BroadwayShmSurfaceData;
555 shm_data_destroy (void *_data)
557 BroadwayShmSurfaceData *data = _data;
559 munmap (data->data, data->data_size);
560 shm_unlink (data->name);
565 _gdk_broadway_server_create_surface (int width,
568 BroadwayShmSurfaceData *data;
569 cairo_surface_t *surface;
573 data = g_new (BroadwayShmSurfaceData, 1);
574 data->data_size = width * height * sizeof (guint32);
576 fd = create_random_shm (data->name);
578 res = ftruncate (fd, data->data_size);
579 g_assert (res != -1);
581 data->data = mmap(0, data->data_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
584 surface = cairo_image_surface_create_for_data ((guchar *)data->data,
585 CAIRO_FORMAT_RGB24, width, height, width * sizeof (guint32));
586 g_assert (surface != NULL);
588 cairo_surface_set_user_data (surface, &gdk_broadway_shm_cairo_key,
589 data, shm_data_destroy);
595 _gdk_broadway_server_window_update (GdkBroadwayServer *server,
597 cairo_surface_t *surface)
599 BroadwayRequestUpdate msg;
600 BroadwayShmSurfaceData *data;
605 data = cairo_surface_get_user_data (surface, &gdk_broadway_shm_cairo_key);
606 g_assert (data != NULL);
609 memcpy (msg.name, data->name, 34);
610 msg.width = cairo_image_surface_get_width (surface);
611 msg.height = cairo_image_surface_get_height (surface);
613 gdk_broadway_server_send_message (server, msg,
614 BROADWAY_REQUEST_UPDATE);
618 _gdk_broadway_server_window_move_resize (GdkBroadwayServer *server,
625 BroadwayRequestMoveResize msg;
633 gdk_broadway_server_send_message (server, msg,
634 BROADWAY_REQUEST_MOVE_RESIZE);
640 _gdk_broadway_server_grab_pointer (GdkBroadwayServer *server,
642 gboolean owner_events,
646 BroadwayRequestGrabPointer msg;
647 guint32 serial, status;
648 BroadwayReply *reply;
651 msg.owner_events = owner_events;
652 msg.event_mask = event_mask;
655 serial = gdk_broadway_server_send_message (server, msg,
656 BROADWAY_REQUEST_GRAB_POINTER);
657 reply = gdk_broadway_server_wait_for_reply (server, serial);
659 g_assert (reply->base.type == BROADWAY_REPLY_GRAB_POINTER);
661 status = reply->grab_pointer.status;
669 _gdk_broadway_server_ungrab_pointer (GdkBroadwayServer *server,
672 BroadwayRequestUngrabPointer msg;
673 guint32 serial, status;
674 BroadwayReply *reply;
678 serial = gdk_broadway_server_send_message (server, msg,
679 BROADWAY_REQUEST_UNGRAB_POINTER);
680 reply = gdk_broadway_server_wait_for_reply (server, serial);
682 g_assert (reply->base.type == BROADWAY_REPLY_UNGRAB_POINTER);
684 status = reply->ungrab_pointer.status;