[gtk+] broadway: Separate out the server parts
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] broadway: Separate out the server parts
- Date: Wed, 19 Dec 2012 23:00:52 +0000 (UTC)
commit 0a808bea5422a9aa4c65070064973f3c09c95e21
Author: Alexander Larsson <alexl redhat com>
Date: Wed Dec 19 12:37:02 2012 +0100
broadway: Separate out the server parts
This (shouldn't) change any behaviour, but it moves the
webserver parts to a separate file, making the broadway display file
smaller and preparing for later separating out the server to its own
process.
gdk/broadway/Makefile.am | 9 +
gdk/broadway/broadway-server.c | 32 +
gdk/broadway/broadway.h | 5 +
gdk/broadway/broadway.js | 6 +-
gdk/broadway/gdkbroadway-server.c | 1695 ++++++++++++++++++++++++++++++++++++
gdk/broadway/gdkbroadway-server.h | 145 +++
gdk/broadway/gdkdevice-broadway.c | 109 +--
gdk/broadway/gdkdisplay-broadway.c | 970 +--------------------
gdk/broadway/gdkdisplay-broadway.h | 100 +---
gdk/broadway/gdkeventsource.c | 47 +-
gdk/broadway/gdkprivate-broadway.h | 3 +-
gdk/broadway/gdkwindow-broadway.c | 282 +------
12 files changed, 1969 insertions(+), 1434 deletions(-)
---
diff --git a/gdk/broadway/Makefile.am b/gdk/broadway/Makefile.am
index 592322e..d608b6e 100644
--- a/gdk/broadway/Makefile.am
+++ b/gdk/broadway/Makefile.am
@@ -17,6 +17,8 @@ LDADDS = $(GDK_DEP_LIBS)
noinst_LTLIBRARIES = libbroadway.la libgdk-broadway.la
+libexec_PROGRAMS = broadway-server
+
libgdkinclude_HEADERS = \
gdkbroadway.h
@@ -27,6 +29,8 @@ libgdkbroadwayinclude_HEADERS = \
gdkbroadwayvisual.h
libbroadway_la_SOURCES = \
+ gdkbroadway-server.h \
+ gdkbroadway-server.c \
broadway.h \
broadway.c
@@ -77,6 +81,11 @@ libgdk_broadway_la_SOURCES = \
libgdk_broadway_la_LIBADD = libbroadway.la
+broadway_server_SOURCES = \
+ broadway-server.c
+
+broadway_server_LDADD = libbroadway.la $(GDK_DEP_LIBS)
+
MAINTAINERCLEANFILES = $(broadway_built_sources)
EXTRA_DIST += $(broadway_built_sources)
diff --git a/gdk/broadway/broadway-server.c b/gdk/broadway/broadway-server.c
new file mode 100644
index 0000000..7395abd
--- /dev/null
+++ b/gdk/broadway/broadway-server.c
@@ -0,0 +1,32 @@
+#include <glib.h>
+
+#include "gdkbroadway-server.h"
+
+int
+main (int argc, char *argv[])
+{
+ GdkBroadwayServer *server;
+ GError *error;
+ GMainLoop *loop;
+
+ error = NULL;
+ server = _gdk_broadway_server_new (8080, &error);
+ if (server == NULL)
+ {
+ g_printerr ("%s\n", error->message);
+ return 1;
+ }
+
+ loop = g_main_loop_new (NULL, FALSE);
+ g_main_loop_run (loop);
+
+ return 0;
+}
+
+
+/* TODO: */
+
+void
+_gdk_broadway_events_got_input (BroadwayInputMsg *message)
+{
+}
diff --git a/gdk/broadway/broadway.h b/gdk/broadway/broadway.h
index e44f332..269a59d 100644
--- a/gdk/broadway/broadway.h
+++ b/gdk/broadway/broadway.h
@@ -1,3 +1,6 @@
+#ifndef __BROADWAY_H__
+#define __BROADWAY_H__
+
#include <glib.h>
#include <gio/gio.h>
@@ -78,3 +81,5 @@ void broadway_output_grab_pointer (BroadwayOutput *output,
gboolean owner_event);
guint32 broadway_output_ungrab_pointer (BroadwayOutput *output);
void broadway_output_pong (BroadwayOutput *output);
+
+#endif /* __BROADWAY_H__ */
diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js
index cea91db..acfec42 100644
--- a/gdk/broadway/broadway.js
+++ b/gdk/broadway/broadway.js
@@ -2671,7 +2671,7 @@ function handleKeyDown(e) {
// browser behaviors or it has no corresponding keyPress
// event, then send it immediately
if (!ignoreKeyEvent(ev))
- sendInput("k", [keysym, lastState]);
+ sendInput("k", [realWindowWithMouse, keysym, lastState]);
suppress = true;
}
@@ -2716,7 +2716,7 @@ function handleKeyPress(e) {
// Send the translated keysym
if (keysym > 0)
- sendInput ("k", [keysym, lastState]);
+ sendInput ("k", [realWindowWithMouse, keysym, lastState]);
// Stop keypress events just in case
return cancelEvent(ev);
@@ -2735,7 +2735,7 @@ function handleKeyUp(e) {
}
if (keysym > 0)
- sendInput ("K", [keysym, lastState]);
+ sendInput ("K", [realWindowWithMouse, keysym, lastState]);
return cancelEvent(ev);
}
diff --git a/gdk/broadway/gdkbroadway-server.c b/gdk/broadway/gdkbroadway-server.c
new file mode 100644
index 0000000..f0992aa
--- /dev/null
+++ b/gdk/broadway/gdkbroadway-server.c
@@ -0,0 +1,1695 @@
+#include "gdkbroadway-server.h"
+
+#include "broadway.h"
+#include "gdkprivate-broadway.h"
+
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+typedef struct BroadwayInput BroadwayInput;
+
+struct _GdkBroadwayServer {
+ GObject parent_instance;
+
+ int port;
+ GSocketService *service;
+ BroadwayOutput *output;
+ guint32 id_counter;
+ guint32 saved_serial;
+ guint64 last_seen_time;
+ BroadwayInput *input;
+ GList *input_messages;
+ guint process_input_idle;
+
+ GHashTable *id_ht;
+ GList *toplevels;
+
+ gint32 mouse_in_toplevel_id;
+ int last_x, last_y; /* in root coords */
+ guint32 last_state;
+ gint32 real_mouse_in_toplevel_id; /* Not affected by grabs */
+
+ /* Explicit pointer grabs: */
+ gint32 pointer_grab_window_id; /* -1 => none */
+ guint32 pointer_grab_time;
+ gboolean pointer_grab_owner_events;
+
+ /* Future data, from the currently queued events */
+ int future_root_x;
+ int future_root_y;
+ guint32 future_state;
+ int future_mouse_in_toplevel;
+};
+
+struct _GdkBroadwayServerClass
+{
+ GObjectClass parent_class;
+};
+
+typedef struct HttpRequest {
+ GdkBroadwayServer *server;
+ GSocketConnection *connection;
+ GDataInputStream *data;
+ GString *request;
+} HttpRequest;
+
+struct BroadwayInput {
+ GdkBroadwayServer *server;
+ GSocketConnection *connection;
+ GByteArray *buffer;
+ GSource *source;
+ gboolean seen_time;
+ gint64 time_base;
+ gboolean proto_v7_plus;
+ gboolean binary;
+};
+
+typedef struct {
+ gint32 id;
+ gint32 x;
+ gint32 y;
+ gint32 width;
+ gint32 height;
+ gboolean is_temp;
+ gboolean last_synced;
+ gboolean visible;
+ gint32 transient_for;
+
+ cairo_surface_t *last_surface;
+} BroadwayWindow;
+
+static void _gdk_broadway_server_resync_windows (GdkBroadwayServer *server);
+
+G_DEFINE_TYPE (GdkBroadwayServer, gdk_broadway_server, G_TYPE_OBJECT)
+
+static void
+gdk_broadway_server_init (GdkBroadwayServer *server)
+{
+ BroadwayWindow *root;
+
+ server->service = g_socket_service_new ();
+ server->pointer_grab_window_id = -1;
+ server->saved_serial = 1;
+ server->last_seen_time = 1;
+ server->id_ht = g_hash_table_new (NULL, NULL);
+ server->id_counter = 0;
+
+ root = g_new0 (BroadwayWindow, 1);
+ root->id = server->id_counter++;
+ root->width = 1024;
+ root->height = 768;
+ root->visible = TRUE;
+
+ g_hash_table_insert (server->id_ht,
+ GINT_TO_POINTER (root->id),
+ root);
+}
+
+static void
+gdk_broadway_server_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (gdk_broadway_server_parent_class)->finalize (object);
+}
+
+static void
+gdk_broadway_server_class_init (GdkBroadwayServerClass * class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = gdk_broadway_server_finalize;
+}
+
+static void start_output (HttpRequest *request, gboolean proto_v7_plus, gboolean binary);
+
+static void
+http_request_free (HttpRequest *request)
+{
+ g_object_unref (request->connection);
+ g_object_unref (request->data);
+ g_string_free (request->request, TRUE);
+ g_free (request);
+}
+
+static void
+broadway_input_free (BroadwayInput *input)
+{
+ g_object_unref (input->connection);
+ g_byte_array_free (input->buffer, FALSE);
+ g_source_destroy (input->source);
+ g_free (input);
+}
+
+static void
+update_event_state (GdkBroadwayServer *server,
+ BroadwayInputMsg *message)
+{
+ switch (message->base.type) {
+ case 'e': /* Enter */
+ server->last_x = message->pointer.root_x;
+ server->last_y = message->pointer.root_y;
+ server->last_state = message->pointer.state;
+ server->real_mouse_in_toplevel_id = message->pointer.mouse_window_id;
+
+ /* TODO: Unset when it dies */
+ server->mouse_in_toplevel_id = message->pointer.event_window_id;
+ break;
+ case 'l': /* Leave */
+ server->last_x = message->pointer.root_x;
+ server->last_y = message->pointer.root_y;
+ server->last_state = message->pointer.state;
+ server->real_mouse_in_toplevel_id = message->pointer.mouse_window_id;
+
+ server->mouse_in_toplevel_id = 0;
+ break;
+ case 'm': /* Mouse move */
+ server->last_x = message->pointer.root_x;
+ server->last_y = message->pointer.root_y;
+ server->last_state = message->pointer.state;
+ server->real_mouse_in_toplevel_id = message->pointer.mouse_window_id;
+ break;
+ case 'b':
+ case 'B':
+ server->last_x = message->pointer.root_x;
+ server->last_y = message->pointer.root_y;
+ server->last_state = message->pointer.state;
+ server->real_mouse_in_toplevel_id = message->pointer.mouse_window_id;
+ break;
+ case 's':
+ server->last_x = message->pointer.root_x;
+ server->last_y = message->pointer.root_y;
+ server->last_state = message->pointer.state;
+ server->real_mouse_in_toplevel_id = message->pointer.mouse_window_id;
+ break;
+ case 'k':
+ case 'K':
+ server->last_state = message->key.state;
+ break;
+ case 'g':
+ case 'u':
+ break;
+ case 'w':
+ break;
+ case 'W':
+ break;
+ case 'd':
+ break;
+
+ default:
+ g_printerr ("update_event_state - Unknown input command %c\n", message->base.type);
+ break;
+ }
+}
+
+gboolean
+_gdk_broadway_server_lookahead_event (GdkBroadwayServer *server,
+ const char *types)
+{
+ BroadwayInputMsg *message;
+ GList *l;
+
+ for (l = server->input_messages; l != NULL; l = l->next)
+ {
+ message = l->data;
+ if (strchr (types, message->base.type) != NULL)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+process_input_messages (GdkBroadwayServer *server)
+{
+ BroadwayInputMsg *message;
+
+ while (server->input_messages)
+ {
+ message = server->input_messages->data;
+ server->input_messages =
+ g_list_delete_link (server->input_messages,
+ server->input_messages);
+
+
+ update_event_state (server, message);
+ _gdk_broadway_events_got_input (message);
+ g_free (message);
+ }
+}
+
+static char *
+parse_pointer_data (char *p, BroadwayInputPointerMsg *data)
+{
+ data->mouse_window_id = strtol (p, &p, 10);
+ p++; /* Skip , */
+ data->event_window_id = strtol (p, &p, 10);
+ p++; /* Skip , */
+ data->root_x = strtol (p, &p, 10);
+ p++; /* Skip , */
+ data->root_y = strtol (p, &p, 10);
+ p++; /* Skip , */
+ data->win_x = strtol (p, &p, 10);
+ p++; /* Skip , */
+ data->win_y = strtol (p, &p, 10);
+ p++; /* Skip , */
+ data->state = strtol (p, &p, 10);
+
+ return p;
+}
+
+static void
+update_future_pointer_info (GdkBroadwayServer *server, BroadwayInputPointerMsg *data)
+{
+ server->future_root_x = data->root_x;
+ server->future_root_y = data->root_y;
+ server->future_state = data->state;
+ server->future_mouse_in_toplevel = data->mouse_window_id;
+}
+
+static void
+parse_input_message (BroadwayInput *input, const char *message)
+{
+ GdkBroadwayServer *server = input->server;
+ BroadwayInputMsg msg;
+ char *p;
+ gint64 time_;
+
+ p = (char *)message;
+ msg.base.type = *p++;
+ msg.base.serial = (guint32)strtol (p, &p, 10);
+ p++; /* Skip , */
+ time_ = strtol(p, &p, 10);
+ p++; /* Skip , */
+
+ if (time_ == 0) {
+ time_ = server->last_seen_time;
+ } else {
+ if (!input->seen_time) {
+ input->seen_time = TRUE;
+ /* Calculate time base so that any following times are normalized to start
+ 5 seconds after last_seen_time, to avoid issues that could appear when
+ a long hiatus due to a reconnect seems to be instant */
+ input->time_base = time_ - (server->last_seen_time + 5000);
+ }
+ time_ = time_ - input->time_base;
+ }
+
+ server->last_seen_time = time_;
+
+ msg.base.time = time_;
+
+ switch (msg.base.type) {
+ case 'e': /* Enter */
+ case 'l': /* Leave */
+ p = parse_pointer_data (p, &msg.pointer);
+ update_future_pointer_info (server, &msg.pointer);
+ p++; /* Skip , */
+ msg.crossing.mode = strtol(p, &p, 10);
+ break;
+
+ case 'm': /* Mouse move */
+ p = parse_pointer_data (p, &msg.pointer);
+ update_future_pointer_info (server, &msg.pointer);
+ break;
+
+ case 'b':
+ case 'B':
+ p = parse_pointer_data (p, &msg.pointer);
+ update_future_pointer_info (server, &msg.pointer);
+ p++; /* Skip , */
+ msg.button.button = strtol(p, &p, 10);
+ break;
+
+ case 's':
+ p = parse_pointer_data (p, &msg.pointer);
+ update_future_pointer_info (server, &msg.pointer);
+ p++; /* Skip , */
+ msg.scroll.dir = strtol(p, &p, 10);
+ break;
+
+ case 'k':
+ case 'K':
+ msg.key.mouse_window_id = strtol(p, &p, 10);
+ p++; /* Skip , */
+ msg.key.key = strtol(p, &p, 10);
+ p++; /* Skip , */
+ msg.key.state = strtol(p, &p, 10);
+ break;
+
+ case 'g':
+ case 'u':
+ msg.grab_reply.res = strtol(p, &p, 10);
+ break;
+
+ case 'w':
+ msg.configure_notify.id = strtol(p, &p, 10);
+ p++; /* Skip , */
+ msg.configure_notify.x = strtol (p, &p, 10);
+ p++; /* Skip , */
+ msg.configure_notify.y = strtol (p, &p, 10);
+ p++; /* Skip , */
+ msg.configure_notify.width = strtol (p, &p, 10);
+ p++; /* Skip , */
+ msg.configure_notify.height = strtol (p, &p, 10);
+ break;
+
+ case 'W':
+ msg.delete_notify.id = strtol(p, &p, 10);
+ break;
+
+ case 'd':
+ msg.screen_resize_notify.width = strtol (p, &p, 10);
+ p++; /* Skip , */
+ msg.screen_resize_notify.height = strtol (p, &p, 10);
+ break;
+
+ default:
+ g_printerr ("parse_input_message - Unknown input command %c (%s)\n", msg.base.type, message);
+ break;
+ }
+
+ server->input_messages = g_list_append (server->input_messages, g_memdup (&msg, sizeof (msg)));
+
+}
+
+static inline void
+hex_dump (guchar *data, gsize len)
+{
+#ifdef DEBUG_WEBSOCKETS
+ gsize i, j;
+ for (j = 0; j < len + 15; j += 16)
+ {
+ fprintf (stderr, "0x%.4x ", j);
+ for (i = 0; i < 16; i++)
+ {
+ if ((j + i) < len)
+ fprintf (stderr, "%.2x ", data[j+i]);
+ else
+ fprintf (stderr, " ");
+ if (i == 8)
+ fprintf (stderr, " ");
+ }
+ fprintf (stderr, " | ");
+
+ for (i = 0; i < 16; i++)
+ if ((j + i) < len && g_ascii_isalnum(data[j+i]))
+ fprintf (stderr, "%c", data[j+i]);
+ else
+ fprintf (stderr, ".");
+ fprintf (stderr, "\n");
+ }
+#endif
+}
+
+static void
+parse_input (BroadwayInput *input)
+{
+ GdkBroadwayServer *server = input->server;
+
+ if (!input->buffer->len)
+ return;
+
+ if (input->proto_v7_plus)
+ {
+ hex_dump (input->buffer->data, input->buffer->len);
+
+ while (input->buffer->len > 2)
+ {
+ gsize len, payload_len;
+ BroadwayWSOpCode code;
+ gboolean is_mask, fin;
+ guchar *buf, *data, *mask;
+
+ buf = input->buffer->data;
+ len = input->buffer->len;
+
+#ifdef DEBUG_WEBSOCKETS
+ g_print ("Parse input first byte 0x%2x 0x%2x\n", buf[0], buf[1]);
+#endif
+
+ fin = buf[0] & 0x80;
+ code = buf[0] & 0x0f;
+ payload_len = buf[1] & 0x7f;
+ is_mask = buf[1] & 0x80;
+ data = buf + 2;
+
+ if (payload_len > 125)
+ {
+ if (len < 4)
+ return;
+ payload_len = GUINT16_FROM_BE( *(guint16 *) data );
+ data += 2;
+ }
+ else if (payload_len > 126)
+ {
+ if (len < 10)
+ return;
+ payload_len = GUINT64_FROM_BE( *(guint64 *) data );
+ data += 8;
+ }
+
+ mask = NULL;
+ if (is_mask)
+ {
+ if (data - buf + 4 > len)
+ return;
+ mask = data;
+ data += 4;
+ }
+
+ if (data - buf + payload_len > len)
+ return; /* wait to accumulate more */
+
+ if (is_mask)
+ {
+ gsize i;
+ for (i = 0; i < payload_len; i++)
+ data[i] ^= mask[i%4];
+ }
+
+ switch (code) {
+ case BROADWAY_WS_CNX_CLOSE:
+ break; /* hang around anyway */
+ case BROADWAY_WS_TEXT:
+ if (!fin)
+ {
+#ifdef DEBUG_WEBSOCKETS
+ g_warning ("can't yet accept fragmented input");
+#endif
+ }
+ else
+ {
+ char *terminated = g_strndup((char *)data, payload_len);
+ parse_input_message (input, terminated);
+ g_free (terminated);
+ }
+ break;
+ case BROADWAY_WS_CNX_PING:
+ broadway_output_pong (server->output);
+ break;
+ case BROADWAY_WS_CNX_PONG:
+ break; /* we never send pings, but tolerate pongs */
+ case BROADWAY_WS_BINARY:
+ case BROADWAY_WS_CONTINUATION:
+ default:
+ {
+ g_warning ("fragmented or unknown input code 0x%2x with fin set", code);
+ break;
+ }
+ }
+
+ g_byte_array_remove_range (input->buffer, 0, data - buf + payload_len);
+ }
+ }
+ else /* old style protocol */
+ {
+ char *buf, *ptr;
+ gsize len;
+
+ buf = (char *)input->buffer->data;
+ len = input->buffer->len;
+
+ if (buf[0] != 0)
+ {
+ server->input = NULL;
+ broadway_input_free (input);
+ return;
+ }
+
+ while ((ptr = memchr (buf, 0xff, len)) != NULL)
+ {
+ *ptr = 0;
+ ptr++;
+
+ parse_input_message (input, buf + 1);
+
+ len -= ptr - buf;
+ buf = ptr;
+
+ if (len > 0 && buf[0] != 0)
+ {
+ server->input = NULL;
+ broadway_input_free (input);
+ break;
+ }
+ }
+ g_byte_array_remove_range (input->buffer, 0, buf - (char *)input->buffer->data);
+ }
+}
+
+
+static gboolean
+process_input_idle_cb (GdkBroadwayServer *server)
+{
+ server->process_input_idle = 0;
+ process_input_messages (server);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+queue_process_input_at_idle (GdkBroadwayServer *server)
+{
+ if (server->process_input_idle == 0)
+ server->process_input_idle =
+ g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc)process_input_idle_cb, server, NULL);
+}
+
+static void
+_gdk_broadway_server_read_all_input_nonblocking (GdkBroadwayServer *server)
+{
+ GInputStream *in;
+ gssize res;
+ guint8 buffer[1024];
+ GError *error;
+ BroadwayInput *input;
+
+ if (server->input == NULL)
+ return;
+
+ input = server->input;
+
+ in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection));
+
+ error = NULL;
+ res = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (in),
+ buffer, sizeof (buffer), NULL, &error);
+
+ if (res <= 0)
+ {
+ if (res < 0 &&
+ g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
+ {
+ g_error_free (error);
+ return;
+ }
+
+ server->input = NULL;
+ broadway_input_free (input);
+ if (res < 0)
+ {
+ g_print ("input error %s\n", error->message);
+ g_error_free (error);
+ }
+ return;
+ }
+
+ g_byte_array_append (input->buffer, buffer, res);
+
+ parse_input (input);
+}
+
+static void
+_gdk_broadway_server_consume_all_input (GdkBroadwayServer *server)
+{
+ _gdk_broadway_server_read_all_input_nonblocking (server);
+
+ /* Since we're parsing input but not processing the resulting messages
+ we might not get a readable callback on the stream, so queue an idle to
+ process the messages */
+ queue_process_input_at_idle (server);
+}
+
+
+static gboolean
+input_data_cb (GObject *stream,
+ BroadwayInput *input)
+{
+ GdkBroadwayServer *server = input->server;
+
+ _gdk_broadway_server_read_all_input_nonblocking (server);
+
+ process_input_messages (server);
+
+ return TRUE;
+}
+
+gulong
+_gdk_broadway_server_get_next_serial (GdkBroadwayServer *server)
+{
+ if (server->output)
+ return broadway_output_get_next_serial (server->output);
+
+ return server->saved_serial;
+}
+
+void
+_gdk_broadway_server_flush (GdkBroadwayServer *server)
+{
+ if (server->output &&
+ !broadway_output_flush (server->output))
+ {
+ server->saved_serial = broadway_output_get_next_serial (server->output);
+ broadway_output_free (server->output);
+ server->output = NULL;
+ }
+}
+
+void
+_gdk_broadway_server_sync (GdkBroadwayServer *server)
+{
+ _gdk_broadway_server_flush (server);
+}
+
+
+/* TODO: This is not used atm, is it needed? */
+/* Note: This may be called while handling a message (i.e. sorta recursively) */
+BroadwayInputMsg *
+_gdk_broadway_server_block_for_input (GdkBroadwayServer *server, char op,
+ guint32 serial, gboolean remove_message)
+{
+ BroadwayInputMsg *message;
+ gssize res;
+ guint8 buffer[1024];
+ BroadwayInput *input;
+ GInputStream *in;
+ GList *l;
+
+ _gdk_broadway_server_flush (server);
+
+ if (server->input == NULL)
+ return NULL;
+
+ input = server->input;
+
+ while (TRUE) {
+ /* Check for existing reply in queue */
+
+ for (l = server->input_messages; l != NULL; l = l->next)
+ {
+ message = l->data;
+
+ if (message->base.type == op)
+ {
+ if (message->base.serial == serial)
+ {
+ if (remove_message)
+ server->input_messages =
+ g_list_delete_link (server->input_messages, l);
+ return message;
+ }
+ }
+ }
+
+ /* Not found, read more, blocking */
+
+ in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection));
+ res = g_input_stream_read (in, buffer, sizeof (buffer), NULL, NULL);
+ if (res <= 0)
+ return NULL;
+ g_byte_array_append (input->buffer, buffer, res);
+
+ parse_input (input);
+
+ /* Since we're parsing input but not processing the resulting messages
+ we might not get a readable callback on the stream, so queue an idle to
+ process the messages */
+ queue_process_input_at_idle (server);
+ }
+}
+
+static char *
+parse_line (char *line, char *key)
+{
+ char *p;
+
+ if (!g_str_has_prefix (line, key))
+ return NULL;
+ p = line + strlen (key);
+ if (*p != ':')
+ return NULL;
+ p++;
+ /* Skip optional initial space */
+ if (*p == ' ')
+ p++;
+ return p;
+}
+static void
+send_error (HttpRequest *request,
+ int error_code,
+ const char *reason)
+{
+ char *res;
+
+ res = g_strdup_printf ("HTTP/1.0 %d %s\r\n\r\n"
+ "<html><head><title>%d %s</title></head>"
+ "<body>%s</body></html>",
+ error_code, reason,
+ error_code, reason,
+ reason);
+ /* TODO: This should really be async */
+ g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
+ res, strlen (res), NULL, NULL, NULL);
+ g_free (res);
+ http_request_free (request);
+}
+
+/* magic from: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17 */
+#define SEC_WEB_SOCKET_KEY_MAGIC "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
+
+/* 'x3JJHMbDL1EzLkh9GBhXDw==' generates 'HSmrc0sMlYUkAGmm5OPpG2HaGWk=' */
+static gchar *
+generate_handshake_response_wsietf_v7 (const gchar *key)
+{
+ gsize digest_len = 20;
+ guchar digest[digest_len];
+ GChecksum *checksum;
+
+ checksum = g_checksum_new (G_CHECKSUM_SHA1);
+ if (!checksum)
+ return NULL;
+
+ g_checksum_update (checksum, (guchar *)key, -1);
+ g_checksum_update (checksum, (guchar *)SEC_WEB_SOCKET_KEY_MAGIC, -1);
+
+ g_checksum_get_digest (checksum, digest, &digest_len);
+ g_checksum_free (checksum);
+
+ g_assert (digest_len == 20);
+
+ return g_base64_encode (digest, digest_len);
+}
+
+static void
+start_input (HttpRequest *request, gboolean binary)
+{
+ char **lines;
+ char *p;
+ int num_key1, num_key2;
+ guint64 key1, key2;
+ int num_space;
+ int i;
+ guint8 challenge[16];
+ char *res;
+ gsize len;
+ GChecksum *checksum;
+ char *origin, *host;
+ GdkBroadwayServer *server;
+ BroadwayInput *input;
+ const void *data_buffer;
+ gsize data_buffer_size;
+ GInputStream *in;
+ char *key_v7;
+ gboolean proto_v7_plus;
+
+ server = GDK_BROADWAY_SERVER (request->server);
+
+ if (server->input != NULL)
+ {
+ send_error (request, 409, "Input already handled");
+ return;
+ }
+
+#ifdef DEBUG_WEBSOCKETS
+ g_print ("incoming request:\n%s\n", request->request->str);
+#endif
+ lines = g_strsplit (request->request->str, "\n", 0);
+
+ num_key1 = 0;
+ num_key2 = 0;
+ key1 = 0;
+ key2 = 0;
+ key_v7 = NULL;
+ origin = NULL;
+ host = NULL;
+ for (i = 0; lines[i] != NULL; i++)
+ {
+ if ((p = parse_line (lines[i], "Sec-WebSocket-Key1")))
+ {
+ num_space = 0;
+ while (*p != 0)
+ {
+ if (g_ascii_isdigit (*p))
+ key1 = key1 * 10 + g_ascii_digit_value (*p);
+ else if (*p == ' ')
+ num_space++;
+
+ p++;
+ }
+ key1 /= num_space;
+ num_key1++;
+ }
+ else if ((p = parse_line (lines[i], "Sec-WebSocket-Key2")))
+ {
+ num_space = 0;
+ while (*p != 0)
+ {
+ if (g_ascii_isdigit (*p))
+ key2 = key2 * 10 + g_ascii_digit_value (*p);
+ else if (*p == ' ')
+ num_space++;
+
+ p++;
+ }
+ key2 /= num_space;
+ num_key2++;
+ }
+ else if ((p = parse_line (lines[i], "Sec-WebSocket-Key")))
+ {
+ key_v7 = p;
+ }
+ else if ((p = parse_line (lines[i], "Origin")))
+ {
+ origin = p;
+ }
+ else if ((p = parse_line (lines[i], "Host")))
+ {
+ host = p;
+ }
+ else if ((p = parse_line (lines[i], "Sec-WebSocket-Origin")))
+ {
+ origin = p;
+ }
+ }
+
+ if (origin == NULL || host == NULL)
+ {
+ g_strfreev (lines);
+ send_error (request, 400, "Bad websocket request");
+ return;
+ }
+
+ if (key_v7 != NULL)
+ {
+ char* accept = generate_handshake_response_wsietf_v7 (key_v7);
+ res = g_strdup_printf ("HTTP/1.1 101 Switching Protocols\r\n"
+ "Upgrade: websocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Sec-WebSocket-Accept: %s\r\n"
+ "Sec-WebSocket-Origin: %s\r\n"
+ "Sec-WebSocket-Location: ws://%s/socket\r\n"
+ "Sec-WebSocket-Protocol: broadway\r\n"
+ "\r\n", accept, origin, host);
+ g_free (accept);
+
+#ifdef DEBUG_WEBSOCKETS
+ g_print ("v7 proto response:\n%s", res);
+#endif
+
+ g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
+ res, strlen (res), NULL, NULL, NULL);
+ g_free (res);
+ proto_v7_plus = TRUE;
+ }
+ else
+ {
+ if (num_key1 != 1 || num_key2 != 1)
+ {
+ g_strfreev (lines);
+ send_error (request, 400, "Bad websocket request");
+ return;
+ }
+
+ challenge[0] = (key1 >> 24) & 0xff;
+ challenge[1] = (key1 >> 16) & 0xff;
+ challenge[2] = (key1 >> 8) & 0xff;
+ challenge[3] = (key1 >> 0) & 0xff;
+ challenge[4] = (key2 >> 24) & 0xff;
+ challenge[5] = (key2 >> 16) & 0xff;
+ challenge[6] = (key2 >> 8) & 0xff;
+ challenge[7] = (key2 >> 0) & 0xff;
+
+ if (!g_input_stream_read_all (G_INPUT_STREAM (request->data), challenge+8, 8, NULL, NULL, NULL))
+ {
+ g_strfreev (lines);
+ send_error (request, 400, "Bad websocket request");
+ return;
+ }
+
+ checksum = g_checksum_new (G_CHECKSUM_MD5);
+ g_checksum_update (checksum, challenge, 16);
+ len = 16;
+ g_checksum_get_digest (checksum, challenge, &len);
+ g_checksum_free (checksum);
+
+ res = g_strdup_printf ("HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
+ "Upgrade: WebSocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Sec-WebSocket-Origin: %s\r\n"
+ "Sec-WebSocket-Location: ws://%s/socket\r\n"
+ "Sec-WebSocket-Protocol: broadway\r\n"
+ "\r\n",
+ origin, host);
+
+#ifdef DEBUG_WEBSOCKETS
+ g_print ("legacy response:\n%s", res);
+#endif
+ g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
+ res, strlen (res), NULL, NULL, NULL);
+ g_free (res);
+ g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
+ challenge, 16, NULL, NULL, NULL);
+ proto_v7_plus = FALSE;
+ }
+
+ input = g_new0 (BroadwayInput, 1);
+
+ input->server = request->server;
+ input->connection = g_object_ref (request->connection);
+ input->proto_v7_plus = proto_v7_plus;
+ input->binary = binary;
+
+ data_buffer = g_buffered_input_stream_peek_buffer (G_BUFFERED_INPUT_STREAM (request->data), &data_buffer_size);
+ input->buffer = g_byte_array_sized_new (data_buffer_size);
+ g_byte_array_append (input->buffer, data_buffer, data_buffer_size);
+
+ server->input = input;
+
+ start_output (request, proto_v7_plus, binary);
+
+ /* This will free and close the data input stream, but we got all the buffered content already */
+ http_request_free (request);
+
+ in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection));
+ input->source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (in), NULL);
+ g_source_set_callback (input->source, (GSourceFunc)input_data_cb, input, NULL);
+ g_source_attach (input->source, NULL);
+
+ /* Process any data in the pipe already */
+ parse_input (input);
+ process_input_messages (server);
+
+ g_strfreev (lines);
+}
+
+static void
+start_output (HttpRequest *request, gboolean proto_v7_plus, gboolean binary)
+{
+ GSocket *socket;
+ GdkBroadwayServer *server;
+ int flag = 1;
+
+ socket = g_socket_connection_get_socket (request->connection);
+ setsockopt(g_socket_get_fd (socket), IPPROTO_TCP,
+ TCP_NODELAY, (char *) &flag, sizeof(int));
+
+ server = GDK_BROADWAY_SERVER (request->server);
+
+ if (server->output)
+ {
+ server->saved_serial = broadway_output_get_next_serial (server->output);
+ broadway_output_free (server->output);
+ }
+
+ server->output =
+ broadway_output_new (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
+ server->saved_serial, proto_v7_plus, binary);
+
+ _gdk_broadway_server_resync_windows (server);
+
+ if (server->pointer_grab_window_id != -1)
+ broadway_output_grab_pointer (server->output,
+ server->pointer_grab_window_id,
+ server->pointer_grab_owner_events);
+}
+
+static void
+send_data (HttpRequest *request,
+ const char *mimetype,
+ const char *data, gsize len)
+{
+ char *res;
+
+ res = g_strdup_printf ("HTTP/1.0 200 OK\r\n"
+ "Content-Type: %s\r\n"
+ "Content-Length: %"G_GSIZE_FORMAT"\r\n"
+ "\r\n",
+ mimetype, len);
+ /* TODO: This should really be async */
+ g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
+ res, strlen (res), NULL, NULL, NULL);
+ g_free (res);
+ g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
+ data, len, NULL, NULL, NULL);
+ http_request_free (request);
+}
+
+#include "clienthtml.h"
+#include "broadwayjs.h"
+
+static void
+got_request (HttpRequest *request)
+{
+ char *start, *escaped, *tmp, *version, *query;
+
+ if (!g_str_has_prefix (request->request->str, "GET "))
+ {
+ send_error (request, 501, "Only GET implemented");
+ return;
+ }
+
+ start = request->request->str + 4; /* Skip "GET " */
+
+ while (*start == ' ')
+ start++;
+
+ for (tmp = start; *tmp != 0 && *tmp != ' ' && *tmp != '\n'; tmp++)
+ ;
+ escaped = g_strndup (start, tmp - start);
+ version = NULL;
+ if (*tmp == ' ')
+ {
+ start = tmp;
+ while (*start == ' ')
+ start++;
+ for (tmp = start; *tmp != 0 && *tmp != ' ' && *tmp != '\n'; tmp++)
+ ;
+ version = g_strndup (start, tmp - start);
+ }
+
+ query = strchr (escaped, '?');
+ if (query)
+ *query = 0;
+
+ if (strcmp (escaped, "/client.html") == 0 || strcmp (escaped, "/") == 0)
+ send_data (request, "text/html", client_html, G_N_ELEMENTS(client_html) - 1);
+ else if (strcmp (escaped, "/broadway.js") == 0)
+ send_data (request, "text/javascript", broadway_js, G_N_ELEMENTS(broadway_js) - 1);
+ else if (strcmp (escaped, "/socket") == 0)
+ start_input (request, FALSE);
+ else if (strcmp (escaped, "/socket-bin") == 0)
+ start_input (request, TRUE);
+ else
+ send_error (request, 404, "File not found");
+
+ g_free (escaped);
+ g_free (version);
+}
+
+static void
+got_http_request_line (GInputStream *stream,
+ GAsyncResult *result,
+ HttpRequest *request)
+{
+ char *line;
+
+ line = g_data_input_stream_read_line_finish (G_DATA_INPUT_STREAM (stream), result, NULL, NULL);
+ if (line == NULL)
+ {
+ http_request_free (request);
+ g_printerr ("Error reading request lines\n");
+ return;
+ }
+ if (strlen (line) == 0)
+ got_request (request);
+ else
+ {
+ /* Protect against overflow in request length */
+ if (request->request->len > 1024 * 5)
+ {
+ send_error (request, 400, "Request too long");
+ }
+ else
+ {
+ g_string_append_printf (request->request, "%s\n", line);
+ g_data_input_stream_read_line_async (request->data, 0, NULL,
+ (GAsyncReadyCallback)got_http_request_line, request);
+ }
+ }
+ g_free (line);
+}
+
+static gboolean
+handle_incoming_connection (GSocketService *service,
+ GSocketConnection *connection,
+ GObject *source_object)
+{
+ HttpRequest *request;
+ GInputStream *in;
+
+ request = g_new0 (HttpRequest, 1);
+ request->connection = g_object_ref (connection);
+ request->server = GDK_BROADWAY_SERVER (source_object);
+ request->request = g_string_new ("");
+
+ in = g_io_stream_get_input_stream (G_IO_STREAM (connection));
+
+ request->data = g_data_input_stream_new (in);
+ g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (request->data), FALSE);
+ /* Be tolerant of input */
+ g_data_input_stream_set_newline_type (request->data, G_DATA_STREAM_NEWLINE_TYPE_ANY);
+
+ g_data_input_stream_read_line_async (request->data, 0, NULL,
+ (GAsyncReadyCallback)got_http_request_line, request);
+ return TRUE;
+}
+
+GdkBroadwayServer *
+_gdk_broadway_server_new (int port, GError **error)
+{
+ GdkBroadwayServer *server;
+
+ server = g_object_new (GDK_TYPE_BROADWAY_SERVER, NULL);
+ server->port = port;
+
+ if (!g_socket_listener_add_inet_port (G_SOCKET_LISTENER (server->service),
+ server->port,
+ G_OBJECT (server),
+ error))
+ {
+ g_prefix_error (error, "Unable to listen to port %d: ", server->port);
+ return NULL;
+ }
+
+ g_signal_connect (server->service, "incoming",
+ G_CALLBACK (handle_incoming_connection), NULL);
+ return server;
+}
+
+guint32
+_gdk_broadway_server_get_last_seen_time (GdkBroadwayServer *server)
+{
+ _gdk_broadway_server_consume_all_input (server);
+ return (guint32) server->last_seen_time;
+}
+
+void
+_gdk_broadway_server_query_mouse (GdkBroadwayServer *server,
+ gint32 *toplevel,
+ gint32 *root_x,
+ gint32 *root_y,
+ guint32 *mask)
+{
+ if (server->output)
+ {
+ _gdk_broadway_server_consume_all_input (server);
+ if (root_x)
+ *root_x = server->future_root_x;
+ if (root_y)
+ *root_y = server->future_root_y;
+ if (mask)
+ *mask = server->future_state;
+ if (toplevel)
+ *toplevel = server->future_mouse_in_toplevel;
+ return;
+ }
+
+ /* Fallback when unconnected */
+ if (root_x)
+ *root_x = server->last_x;
+ if (root_y)
+ *root_y = server->last_y;
+ if (mask)
+ *mask = server->last_state;
+ if (toplevel)
+ *toplevel = server->mouse_in_toplevel_id;
+}
+
+void
+_gdk_broadway_server_destroy_window (GdkBroadwayServer *server,
+ gint id)
+{
+ BroadwayWindow *window;
+
+ if (server->mouse_in_toplevel_id == id)
+ {
+ /* TODO: Send leave + enter event, update cursors, etc */
+ server->mouse_in_toplevel_id = 0;
+ }
+
+ if (server->pointer_grab_window_id == id)
+ server->pointer_grab_window_id = -1;
+
+ if (server->output)
+ broadway_output_destroy_surface (server->output,
+ id);
+
+ window = g_hash_table_lookup (server->id_ht,
+ GINT_TO_POINTER (id));
+ if (window != NULL)
+ {
+ server->toplevels = g_list_remove (server->toplevels, window);
+ g_hash_table_remove (server->id_ht,
+ GINT_TO_POINTER (id));
+ g_free (window);
+ }
+}
+
+gboolean
+_gdk_broadway_server_window_show (GdkBroadwayServer *server,
+ gint id)
+{
+ BroadwayWindow *window;
+ gboolean sent = FALSE;
+
+ window = g_hash_table_lookup (server->id_ht,
+ GINT_TO_POINTER (id));
+ if (window == NULL)
+ return FALSE;
+
+ window->visible = TRUE;
+
+ if (server->output)
+ {
+ broadway_output_show_surface (server->output, window->id);
+ sent = TRUE;
+ }
+
+ return sent;
+}
+
+gboolean
+_gdk_broadway_server_window_hide (GdkBroadwayServer *server,
+ gint id)
+{
+ BroadwayWindow *window;
+ gboolean sent = FALSE;
+
+ window = g_hash_table_lookup (server->id_ht,
+ GINT_TO_POINTER (id));
+ if (window == NULL)
+ return FALSE;
+
+ window->visible = FALSE;
+
+ if (server->mouse_in_toplevel_id == id)
+ {
+ /* TODO: Send leave + enter event, update cursors, etc */
+ server->mouse_in_toplevel_id = 0;
+ }
+
+ if (server->output)
+ {
+ broadway_output_hide_surface (server->output, window->id);
+ sent = TRUE;
+ }
+ return sent;
+}
+
+void
+_gdk_broadway_server_window_set_transient_for (GdkBroadwayServer *server,
+ gint id, gint parent)
+{
+ BroadwayWindow *window;
+
+ window = g_hash_table_lookup (server->id_ht,
+ GINT_TO_POINTER (id));
+ if (window == NULL)
+ return;
+
+ window->transient_for = parent;
+
+ if (server->output)
+ {
+ broadway_output_set_transient_for (server->output, window->id, window->transient_for);
+ _gdk_broadway_server_flush (server);
+ }
+}
+
+gboolean
+_gdk_broadway_server_has_client (GdkBroadwayServer *server)
+{
+ return server->output != NULL;
+}
+
+static void
+_cairo_region (cairo_t *cr,
+ const cairo_region_t *region)
+{
+ cairo_rectangle_int_t box;
+ gint n_boxes, i;
+
+ g_return_if_fail (cr != NULL);
+ g_return_if_fail (region != NULL);
+
+ n_boxes = cairo_region_num_rectangles (region);
+
+ for (i = 0; i < n_boxes; i++)
+ {
+ cairo_region_get_rectangle (region, i, &box);
+ cairo_rectangle (cr, box.x, box.y, box.width, box.height);
+ }
+}
+
+
+static void
+copy_region (cairo_surface_t *surface,
+ cairo_region_t *area,
+ gint dx,
+ gint dy)
+{
+ cairo_t *cr;
+
+ cr = cairo_create (surface);
+
+ _cairo_region (cr, area);
+ cairo_clip (cr);
+
+ /* NB: This is a self-copy and Cairo doesn't support that yet.
+ * So we do a litle trick.
+ */
+ cairo_push_group (cr);
+
+ cairo_set_source_surface (cr, surface, dx, dy);
+ cairo_paint (cr);
+
+ cairo_pop_group_to_source (cr);
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+}
+
+gboolean
+_gdk_broadway_server_window_translate (GdkBroadwayServer *server,
+ gint id,
+ cairo_region_t *area,
+ gint dx,
+ gint dy)
+{
+ BroadwayWindow *window;
+ gboolean sent = FALSE;
+
+ window = g_hash_table_lookup (server->id_ht,
+ GINT_TO_POINTER (id));
+ if (window == NULL)
+ return FALSE;
+
+ if (window->last_synced &&
+ server->output)
+ {
+ BroadwayRect *rects;
+ cairo_rectangle_int_t rect;
+ int i, n_rects;
+
+ copy_region (window->last_surface, area, dx, dy);
+ n_rects = cairo_region_num_rectangles (area);
+ rects = g_new (BroadwayRect, n_rects);
+ for (i = 0; i < n_rects; i++)
+ {
+ cairo_region_get_rectangle (area, i, &rect);
+ rects[i].x = rect.x;
+ rects[i].y = rect.y;
+ rects[i].width = rect.width;
+ rects[i].height = rect.height;
+ }
+ broadway_output_copy_rectangles (server->output,
+ window->id,
+ rects, n_rects, dx, dy);
+ g_free (rects);
+ sent = TRUE;
+ }
+
+ return sent;
+}
+
+static void
+diff_surfaces (cairo_surface_t *surface,
+ cairo_surface_t *old_surface)
+{
+ guint8 *data, *old_data;
+ guint32 *line, *old_line;
+ int w, h, stride, old_stride;
+ int x, y;
+
+ data = cairo_image_surface_get_data (surface);
+ old_data = cairo_image_surface_get_data (old_surface);
+
+ w = cairo_image_surface_get_width (surface);
+ h = cairo_image_surface_get_height (surface);
+
+ stride = cairo_image_surface_get_stride (surface);
+ old_stride = cairo_image_surface_get_stride (old_surface);
+
+ for (y = 0; y < h; y++)
+ {
+ line = (guint32 *)data;
+ old_line = (guint32 *)old_data;
+
+ for (x = 0; x < w; x++)
+ {
+ if ((*line & 0xffffff) == (*old_line & 0xffffff))
+ *old_line = 0;
+ else
+ *old_line = *line | 0xff000000;
+ line ++;
+ old_line ++;
+ }
+
+ data += stride;
+ old_data += old_stride;
+ }
+}
+
+void
+_gdk_broadway_server_window_update (GdkBroadwayServer *server,
+ gint id,
+ cairo_surface_t *surface)
+{
+ cairo_t *cr;
+ BroadwayWindow *window;
+
+ if (surface == NULL)
+ return;
+
+ window = g_hash_table_lookup (server->id_ht,
+ GINT_TO_POINTER (id));
+ if (window == NULL)
+ return;
+
+ if (window->last_surface == NULL)
+ window->last_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+ window->width,
+ window->height);
+
+ if (server->output != NULL)
+ {
+ if (window->last_synced)
+ {
+ diff_surfaces (surface,
+ window->last_surface);
+ broadway_output_put_rgba (server->output, window->id, 0, 0,
+ cairo_image_surface_get_width (window->last_surface),
+ cairo_image_surface_get_height (window->last_surface),
+ cairo_image_surface_get_stride (window->last_surface),
+ cairo_image_surface_get_data (window->last_surface));
+ }
+ else
+ {
+ window->last_synced = TRUE;
+ broadway_output_put_rgb (server->output, window->id, 0, 0,
+ cairo_image_surface_get_width (surface),
+ cairo_image_surface_get_height (surface),
+ cairo_image_surface_get_stride (surface),
+ cairo_image_surface_get_data (surface));
+ }
+
+ broadway_output_surface_flush (server->output, window->id);
+ }
+
+ cr = cairo_create (window->last_surface);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+}
+
+gboolean
+_gdk_broadway_server_window_move_resize (GdkBroadwayServer *server,
+ gint id,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ BroadwayWindow *window;
+ gboolean with_move, with_resize;
+ gboolean sent = FALSE;
+ cairo_t *cr;
+
+ window = g_hash_table_lookup (server->id_ht,
+ GINT_TO_POINTER (id));
+ if (window == NULL)
+ return FALSE;
+
+ with_move = x != window->x || y != window->y;
+ with_resize = width != window->width || height != window->height;
+ window->x = x;
+ window->y = y;
+ window->width = width;
+ window->height = height;
+
+ if (with_resize && window->last_surface != NULL)
+ {
+ cairo_surface_t *old;
+
+ old = window->last_surface;
+
+ window->last_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+ width, height);
+
+
+ cr = cairo_create (window->last_surface);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_surface (cr, old, 0, 0);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ cairo_surface_destroy (old);
+ }
+
+ if (server->output != NULL)
+ {
+ broadway_output_move_resize_surface (server->output,
+ window->id,
+ with_move, window->x, window->y,
+ with_resize, window->width, window->height);
+ sent = TRUE;
+ }
+
+ return sent;
+}
+
+GdkGrabStatus
+_gdk_broadway_server_grab_pointer (GdkBroadwayServer *server,
+ gint id,
+ gboolean owner_events,
+ guint32 event_mask,
+ guint32 time_)
+{
+ if (server->pointer_grab_window_id != -1 &&
+ time_ != 0 && server->pointer_grab_time > time_)
+ return GDK_GRAB_ALREADY_GRABBED;
+
+ if (time_ == 0)
+ time_ = server->last_seen_time;
+
+ server->pointer_grab_window_id = id;
+ server->pointer_grab_owner_events = owner_events;
+ server->pointer_grab_time = time_;
+
+ if (server->output)
+ {
+ broadway_output_grab_pointer (server->output,
+ id,
+ owner_events);
+ _gdk_broadway_server_flush (server);
+ }
+
+ /* TODO: What about toplevel grab events if we're not connected? */
+
+ return GDK_GRAB_SUCCESS;
+}
+
+guint32
+_gdk_broadway_server_ungrab_pointer (GdkBroadwayServer *server,
+ guint32 time_)
+{
+ guint32 serial;
+
+ if (server->pointer_grab_window_id != -1 &&
+ time_ != 0 && server->pointer_grab_time > time_)
+ return 0;
+
+ /* TODO: What about toplevel grab events if we're not connected? */
+
+ if (server->output)
+ {
+ serial = broadway_output_ungrab_pointer (server->output);
+ _gdk_broadway_server_flush (server);
+ }
+ else
+ {
+ serial = server->saved_serial;
+ }
+
+ server->pointer_grab_window_id = -1;
+
+ return serial;
+}
+
+guint32
+_gdk_broadway_server_new_window (GdkBroadwayServer *server,
+ int x,
+ int y,
+ int width,
+ int height,
+ gboolean is_temp)
+{
+ BroadwayWindow *window;
+
+ window = g_new0 (BroadwayWindow, 1);
+ window->id = server->id_counter++;
+ window->x = x;
+ window->y = y;
+ window->width = width;
+ window->height = height;
+ window->is_temp = is_temp;
+
+ g_hash_table_insert (server->id_ht,
+ GINT_TO_POINTER (window->id),
+ window);
+
+ server->toplevels = g_list_prepend (server->toplevels, window);
+
+ if (server->output)
+ broadway_output_new_surface (server->output,
+ window->id,
+ window->x,
+ window->y,
+ window->width,
+ window->height,
+ window->is_temp);
+
+ return window->id;
+}
+
+static void
+_gdk_broadway_server_resync_windows (GdkBroadwayServer *server)
+{
+ GList *l;
+
+ if (server->output == NULL)
+ return;
+
+ /* First create all windows */
+ for (l = server->toplevels; l != NULL; l = l->next)
+ {
+ BroadwayWindow *window = l->data;
+
+ if (window->id == 0)
+ continue; /* Skip root */
+
+ window->last_synced = FALSE;
+ broadway_output_new_surface (server->output,
+ window->id,
+ window->x,
+ window->y,
+ window->width,
+ window->height,
+ window->is_temp);
+ }
+
+ /* Then do everything that may reference other windows */
+ for (l = server->toplevels; l != NULL; l = l->next)
+ {
+ BroadwayWindow *window = l->data;
+
+ if (window->id == 0)
+ continue; /* Skip root */
+
+ if (window->transient_for != -1)
+ broadway_output_set_transient_for (server->output, window->id, window->transient_for);
+ if (window->visible)
+ {
+ broadway_output_show_surface (server->output, window->id);
+
+ if (window->last_surface != NULL)
+ {
+ window->last_synced = TRUE;
+ broadway_output_put_rgb (server->output, window->id, 0, 0,
+ cairo_image_surface_get_width (window->last_surface),
+ cairo_image_surface_get_height (window->last_surface),
+ cairo_image_surface_get_stride (window->last_surface),
+ cairo_image_surface_get_data (window->last_surface));
+ }
+ }
+ }
+
+ _gdk_broadway_server_flush (server);
+}
diff --git a/gdk/broadway/gdkbroadway-server.h b/gdk/broadway/gdkbroadway-server.h
new file mode 100644
index 0000000..e9f7742
--- /dev/null
+++ b/gdk/broadway/gdkbroadway-server.h
@@ -0,0 +1,145 @@
+#ifndef __GDK_BROADWAY_SERVER__
+#define __GDK_BROADWAY_SERVER__
+
+#include <gdk/gdktypes.h>
+
+typedef struct _GdkBroadwayServer GdkBroadwayServer;
+typedef struct _GdkBroadwayServerClass GdkBroadwayServerClass;
+
+#define GDK_TYPE_BROADWAY_SERVER (gdk_broadway_server_get_type())
+#define GDK_BROADWAY_SERVER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_BROADWAY_SERVER, GdkBroadwayServer))
+#define GDK_BROADWAY_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_BROADWAY_SERVER, GdkBroadwayServerClass))
+#define GDK_IS_BROADWAY_SERVER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_BROADWAY_SERVER))
+#define GDK_IS_BROADWAY_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_BROADWAY_SERVER))
+#define GDK_BROADWAY_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_BROADWAY_SERVER, GdkBroadwayServerClass))
+
+typedef struct {
+ guint8 type;
+ guint32 serial;
+ guint64 time;
+} BroadwayInputBaseMsg;
+
+typedef struct {
+ BroadwayInputBaseMsg base;
+ guint32 mouse_window_id; /* The real window, not taking grabs into account */
+ guint32 event_window_id;
+ gint32 root_x;
+ gint32 root_y;
+ gint32 win_x;
+ gint32 win_y;
+ guint32 state;
+} BroadwayInputPointerMsg;
+
+typedef struct {
+ BroadwayInputPointerMsg pointer;
+ guint32 mode;
+} BroadwayInputCrossingMsg;
+
+typedef struct {
+ BroadwayInputPointerMsg pointer;
+ guint32 button;
+} BroadwayInputButtonMsg;
+
+typedef struct {
+ BroadwayInputPointerMsg pointer;
+ gint32 dir;
+} BroadwayInputScrollMsg;
+
+typedef struct {
+ BroadwayInputBaseMsg base;
+ guint32 mouse_window_id; /* The real window, not taking grabs into account */
+ guint32 state;
+ gint32 key;
+} BroadwayInputKeyMsg;
+
+typedef struct {
+ BroadwayInputBaseMsg base;
+ gint32 res;
+} BroadwayInputGrabReply;
+
+typedef struct {
+ BroadwayInputBaseMsg base;
+ gint32 id;
+ gint32 x;
+ gint32 y;
+ gint32 width;
+ gint32 height;
+} BroadwayInputConfigureNotify;
+
+typedef struct {
+ BroadwayInputBaseMsg base;
+ gint32 width;
+ gint32 height;
+} BroadwayInputScreenResizeNotify;
+
+typedef struct {
+ BroadwayInputBaseMsg base;
+ gint32 id;
+} BroadwayInputDeleteNotify;
+
+typedef union {
+ BroadwayInputBaseMsg base;
+ BroadwayInputPointerMsg pointer;
+ BroadwayInputCrossingMsg crossing;
+ BroadwayInputButtonMsg button;
+ BroadwayInputScrollMsg scroll;
+ BroadwayInputKeyMsg key;
+ BroadwayInputGrabReply grab_reply;
+ BroadwayInputConfigureNotify configure_notify;
+ BroadwayInputDeleteNotify delete_notify;
+ BroadwayInputScreenResizeNotify screen_resize_notify;
+} BroadwayInputMsg;
+
+GdkBroadwayServer *_gdk_broadway_server_new (int port,
+ GError **error);
+gboolean _gdk_broadway_server_has_client (GdkBroadwayServer *server);
+void _gdk_broadway_server_flush (GdkBroadwayServer *server);
+void _gdk_broadway_server_sync (GdkBroadwayServer *server);
+gulong _gdk_broadway_server_get_next_serial (GdkBroadwayServer *server);
+guint32 _gdk_broadway_server_get_last_seen_time (GdkBroadwayServer *server);
+gboolean _gdk_broadway_server_lookahead_event (GdkBroadwayServer *server,
+ const char *types);
+void _gdk_broadway_server_query_mouse (GdkBroadwayServer *server,
+ gint *toplevel,
+ gint *root_x,
+ gint *root_y,
+ guint32 *mask);
+GdkGrabStatus _gdk_broadway_server_grab_pointer (GdkBroadwayServer *server,
+ gint id,
+ gboolean owner_events,
+ guint32 event_mask,
+ guint32 time_);
+guint32 _gdk_broadway_server_ungrab_pointer (GdkBroadwayServer *server,
+ guint32 time_);
+gint32 _gdk_broadway_server_get_mouse_toplevel (GdkBroadwayServer *server);
+guint32 _gdk_broadway_server_new_window (GdkBroadwayServer *server,
+ int x,
+ int y,
+ int width,
+ int height,
+ gboolean is_temp);
+void _gdk_broadway_server_destroy_window (GdkBroadwayServer *server,
+ gint id);
+gboolean _gdk_broadway_server_window_show (GdkBroadwayServer *server,
+ gint id);
+gboolean _gdk_broadway_server_window_hide (GdkBroadwayServer *server,
+ gint id);
+void _gdk_broadway_server_window_set_transient_for (GdkBroadwayServer *server,
+ gint id,
+ gint parent);
+gboolean _gdk_broadway_server_window_translate (GdkBroadwayServer *server,
+ gint id,
+ cairo_region_t *area,
+ gint dx,
+ gint dy);
+void _gdk_broadway_server_window_update (GdkBroadwayServer *server,
+ gint id,
+ cairo_surface_t *surface);
+gboolean _gdk_broadway_server_window_move_resize (GdkBroadwayServer *server,
+ gint id,
+ int x,
+ int y,
+ int width,
+ int height);
+
+#endif /* __GDK_BROADWAY_SERVER__ */
diff --git a/gdk/broadway/gdkdevice-broadway.c b/gdk/broadway/gdkdevice-broadway.c
index 6af7270..40e4a2f 100644
--- a/gdk/broadway/gdkdevice-broadway.c
+++ b/gdk/broadway/gdkdevice-broadway.c
@@ -156,7 +156,10 @@ gdk_broadway_device_query_state (GdkDevice *device,
GdkDisplay *display;
GdkBroadwayDisplay *broadway_display;
GdkScreen *screen;
- gint device_root_x, device_root_y;
+ gint32 device_root_x, device_root_y;
+ gint32 mouse_toplevel_id;
+ GdkWindow *mouse_toplevel;
+ guint32 mask32;
if (gdk_device_get_source (device) != GDK_SOURCE_MOUSE)
return;
@@ -173,36 +176,12 @@ gdk_broadway_device_query_state (GdkDevice *device,
*root_window = gdk_screen_get_root_window (screen);
}
- if (broadway_display->output)
- {
- _gdk_broadway_display_consume_all_input (display);
- if (root_x)
- *root_x = broadway_display->future_root_x;
- if (root_y)
- *root_y = broadway_display->future_root_y;
- /* TODO: Should really use future_x/y when we get configure events */
- if (win_x)
- *win_x = broadway_display->future_root_x - toplevel->x;
- if (win_y)
- *win_y = broadway_display->future_root_y - toplevel->y;
- if (mask)
- *mask = broadway_display->future_state;
- if (child_window)
- {
- if (gdk_window_get_window_type (toplevel) == GDK_WINDOW_ROOT)
- *child_window =
- g_hash_table_lookup (broadway_display->id_ht,
- GINT_TO_POINTER (broadway_display->future_mouse_in_toplevel));
- else
- *child_window = toplevel; /* No native children */
- }
- return;
- }
-
- /* Fallback when unconnected */
-
- device_root_x = broadway_display->last_x;
- device_root_y = broadway_display->last_y;
+ _gdk_broadway_server_query_mouse (broadway_display->server,
+ &mouse_toplevel_id,
+ &device_root_x,
+ &device_root_y,
+ &mask32);
+ mouse_toplevel = g_hash_table_lookup (broadway_display->id_ht, GINT_TO_POINTER (mouse_toplevel_id));
if (root_x)
*root_x = device_root_x;
@@ -213,12 +192,12 @@ gdk_broadway_device_query_state (GdkDevice *device,
if (win_y)
*win_y = device_root_y - toplevel->y;
if (mask)
- *mask = broadway_display->last_state;
+ *mask = mask32;
if (child_window)
{
if (gdk_window_get_window_type (toplevel) == GDK_WINDOW_ROOT)
{
- *child_window = broadway_display->mouse_in_toplevel;
+ *child_window = mouse_toplevel;
if (*child_window == NULL)
*child_window = toplevel;
}
@@ -236,13 +215,10 @@ void
_gdk_broadway_window_grab_check_destroy (GdkWindow *window)
{
GdkDisplay *display = gdk_window_get_display (window);
- GdkBroadwayDisplay *broadway_display;
GdkDeviceManager *device_manager;
GdkDeviceGrabInfo *grab;
GList *devices, *d;
- broadway_display = GDK_BROADWAY_DISPLAY (display);
-
device_manager = gdk_display_get_device_manager (display);
/* Get all devices */
@@ -257,8 +233,6 @@ _gdk_broadway_window_grab_check_destroy (GdkWindow *window)
{
grab->serial_end = grab->serial_start;
grab->implicit_ungrab = TRUE;
-
- broadway_display->pointer_grab_window = NULL;
}
}
@@ -290,29 +264,11 @@ gdk_broadway_device_grab (GdkDevice *device,
else
{
/* Device is a pointer */
-
- if (broadway_display->pointer_grab_window != NULL &&
- time_ != 0 && broadway_display->pointer_grab_time > time_)
- return GDK_GRAB_ALREADY_GRABBED;
-
- if (time_ == 0)
- time_ = broadway_display->last_seen_time;
-
- broadway_display->pointer_grab_window = window;
- broadway_display->pointer_grab_owner_events = owner_events;
- broadway_display->pointer_grab_time = time_;
-
- if (broadway_display->output)
- {
- broadway_output_grab_pointer (broadway_display->output,
- GDK_WINDOW_IMPL_BROADWAY (window->impl)->id,
- owner_events);
- gdk_display_flush (display);
- }
-
- /* TODO: What about toplevel grab events if we're not connected? */
-
- return GDK_GRAB_SUCCESS;
+ return _gdk_broadway_server_grab_pointer (broadway_display->server,
+ GDK_WINDOW_IMPL_BROADWAY (window->impl)->id,
+ owner_events,
+ event_mask,
+ time_);
}
}
@@ -340,31 +296,17 @@ gdk_broadway_device_ungrab (GdkDevice *device,
else
{
/* Device is a pointer */
+ serial = _gdk_broadway_server_ungrab_pointer (broadway_display->server, time_);
- if (broadway_display->pointer_grab_window != NULL &&
- time_ != 0 && broadway_display->pointer_grab_time > time_)
- return;
-
- /* TODO: What about toplevel grab events if we're not connected? */
-
- if (broadway_display->output)
- {
- serial = broadway_output_ungrab_pointer (broadway_display->output);
- gdk_display_flush (display);
- }
- else
+ if (serial != 0)
{
- serial = broadway_display->saved_serial;
+ grab = _gdk_display_get_last_device_grab (display, device);
+ if (grab &&
+ (time_ == GDK_CURRENT_TIME ||
+ grab->time == GDK_CURRENT_TIME ||
+ !TIME_IS_LATER (grab->time, time_)))
+ grab->serial_end = serial;
}
-
- grab = _gdk_display_get_last_device_grab (display, device);
- if (grab &&
- (time_ == GDK_CURRENT_TIME ||
- grab->time == GDK_CURRENT_TIME ||
- !TIME_IS_LATER (grab->time, time_)))
- grab->serial_end = serial;
-
- broadway_display->pointer_grab_window = NULL;
}
}
@@ -375,7 +317,6 @@ gdk_broadway_device_window_at_position (GdkDevice *device,
GdkModifierType *mask,
gboolean get_toplevel)
{
- gboolean res;
GdkScreen *screen;
GdkWindow *root_window;
GdkWindow *window;
diff --git a/gdk/broadway/gdkdisplay-broadway.c b/gdk/broadway/gdkdisplay-broadway.c
index 97dfe87..ad5d24b 100644
--- a/gdk/broadway/gdkdisplay-broadway.c
+++ b/gdk/broadway/gdkdisplay-broadway.c
@@ -67,8 +67,6 @@ gdk_event_init (GdkDisplay *display)
broadway_display = GDK_BROADWAY_DISPLAY (display);
broadway_display->event_source = _gdk_broadway_event_source_new (display);
- broadway_display->saved_serial = 1;
- broadway_display->last_seen_time = 1;
}
static void
@@ -123,951 +121,16 @@ gdk_broadway_display_init_input (GdkDisplay *display)
g_list_free (list);
}
-typedef struct HttpRequest {
- GdkDisplay *display;
- GSocketConnection *connection;
- GDataInputStream *data;
- GString *request;
-} HttpRequest;
-
-static void start_output (HttpRequest *request, gboolean proto_v7_plus, gboolean binary);
-
-static void
-http_request_free (HttpRequest *request)
-{
- g_object_unref (request->connection);
- g_object_unref (request->data);
- g_string_free (request->request, TRUE);
- g_free (request);
-}
-
-struct BroadwayInput {
- GdkDisplay *display;
- GSocketConnection *connection;
- GByteArray *buffer;
- GSource *source;
- gboolean seen_time;
- gint64 time_base;
- gboolean proto_v7_plus;
- gboolean binary;
-};
-
-static void
-broadway_input_free (BroadwayInput *input)
-{
- g_object_unref (input->connection);
- g_byte_array_free (input->buffer, FALSE);
- g_source_destroy (input->source);
- g_free (input);
-}
-
-static void
-process_input_messages (GdkBroadwayDisplay *broadway_display)
-{
- BroadwayInputMsg *message;
-
- while (broadway_display->input_messages)
- {
- message = broadway_display->input_messages->data;
- broadway_display->input_messages =
- g_list_delete_link (broadway_display->input_messages,
- broadway_display->input_messages);
-
- _gdk_broadway_events_got_input (GDK_DISPLAY (broadway_display), message);
- g_free (message);
- }
-}
-
-static char *
-parse_pointer_data (char *p, BroadwayInputPointerMsg *data)
-{
- data->mouse_window_id = strtol (p, &p, 10);
- p++; /* Skip , */
- data->event_window_id = strtol (p, &p, 10);
- p++; /* Skip , */
- data->root_x = strtol (p, &p, 10);
- p++; /* Skip , */
- data->root_y = strtol (p, &p, 10);
- p++; /* Skip , */
- data->win_x = strtol (p, &p, 10);
- p++; /* Skip , */
- data->win_y = strtol (p, &p, 10);
- p++; /* Skip , */
- data->state = strtol (p, &p, 10);
-
- return p;
-}
-
-static void
-update_future_pointer_info (GdkBroadwayDisplay *broadway_display, BroadwayInputPointerMsg *data)
-{
- broadway_display->future_root_x = data->root_x;
- broadway_display->future_root_y = data->root_y;
- broadway_display->future_state = data->state;
- broadway_display->future_mouse_in_toplevel = data->mouse_window_id;
-}
-
-static void
-parse_input_message (BroadwayInput *input, const char *message)
-{
- GdkBroadwayDisplay *broadway_display;
- BroadwayInputMsg msg;
- char *p;
- gint64 time_;
-
- broadway_display = GDK_BROADWAY_DISPLAY (input->display);
-
- p = (char *)message;
- msg.base.type = *p++;
- msg.base.serial = (guint32)strtol (p, &p, 10);
- p++; /* Skip , */
- time_ = strtol(p, &p, 10);
- p++; /* Skip , */
-
- if (time_ == 0) {
- time_ = broadway_display->last_seen_time;
- } else {
- if (!input->seen_time) {
- input->seen_time = TRUE;
- /* Calculate time base so that any following times are normalized to start
- 5 seconds after last_seen_time, to avoid issues that could appear when
- a long hiatus due to a reconnect seems to be instant */
- input->time_base = time_ - (broadway_display->last_seen_time + 5000);
- }
- time_ = time_ - input->time_base;
- }
-
- broadway_display->last_seen_time = time_;
-
- msg.base.time = time_;
-
- switch (msg.base.type) {
- case 'e': /* Enter */
- case 'l': /* Leave */
- p = parse_pointer_data (p, &msg.pointer);
- update_future_pointer_info (broadway_display, &msg.pointer);
- p++; /* Skip , */
- msg.crossing.mode = strtol(p, &p, 10);
- break;
-
- case 'm': /* Mouse move */
- p = parse_pointer_data (p, &msg.pointer);
- update_future_pointer_info (broadway_display, &msg.pointer);
- break;
-
- case 'b':
- case 'B':
- p = parse_pointer_data (p, &msg.pointer);
- update_future_pointer_info (broadway_display, &msg.pointer);
- p++; /* Skip , */
- msg.button.button = strtol(p, &p, 10);
- break;
-
- case 's':
- p = parse_pointer_data (p, &msg.pointer);
- update_future_pointer_info (broadway_display, &msg.pointer);
- p++; /* Skip , */
- msg.scroll.dir = strtol(p, &p, 10);
- break;
-
- case 'k':
- case 'K':
- msg.key.key = strtol(p, &p, 10);
- p++; /* Skip , */
- msg.key.state = strtol(p, &p, 10);
- break;
-
- case 'g':
- case 'u':
- msg.grab_reply.res = strtol(p, &p, 10);
- break;
-
- case 'w':
- msg.configure_notify.id = strtol(p, &p, 10);
- p++; /* Skip , */
- msg.configure_notify.x = strtol (p, &p, 10);
- p++; /* Skip , */
- msg.configure_notify.y = strtol (p, &p, 10);
- p++; /* Skip , */
- msg.configure_notify.width = strtol (p, &p, 10);
- p++; /* Skip , */
- msg.configure_notify.height = strtol (p, &p, 10);
- break;
-
- case 'W':
- msg.delete_notify.id = strtol(p, &p, 10);
- break;
-
- case 'd':
- msg.screen_resize_notify.width = strtol (p, &p, 10);
- p++; /* Skip , */
- msg.screen_resize_notify.height = strtol (p, &p, 10);
- break;
-
- default:
- g_printerr ("Unknown input command %s\n", message);
- break;
- }
-
- broadway_display->input_messages = g_list_append (broadway_display->input_messages, g_memdup (&msg, sizeof (msg)));
-
-}
-
-static inline void
-hex_dump (guchar *data, gsize len)
-{
-#ifdef DEBUG_WEBSOCKETS
- gsize i, j;
- for (j = 0; j < len + 15; j += 16)
- {
- fprintf (stderr, "0x%.4x ", j);
- for (i = 0; i < 16; i++)
- {
- if ((j + i) < len)
- fprintf (stderr, "%.2x ", data[j+i]);
- else
- fprintf (stderr, " ");
- if (i == 8)
- fprintf (stderr, " ");
- }
- fprintf (stderr, " | ");
-
- for (i = 0; i < 16; i++)
- if ((j + i) < len && g_ascii_isalnum(data[j+i]))
- fprintf (stderr, "%c", data[j+i]);
- else
- fprintf (stderr, ".");
- fprintf (stderr, "\n");
- }
-#endif
-}
-
-static void
-parse_input (BroadwayInput *input)
-{
- GdkBroadwayDisplay *broadway_display;
-
- broadway_display = GDK_BROADWAY_DISPLAY (input->display);
-
- if (!input->buffer->len)
- return;
-
- if (input->proto_v7_plus)
- {
- hex_dump (input->buffer->data, input->buffer->len);
-
- while (input->buffer->len > 2)
- {
- gsize len, payload_len;
- BroadwayWSOpCode code;
- gboolean is_mask, fin;
- guchar *buf, *data, *mask;
-
- buf = input->buffer->data;
- len = input->buffer->len;
-
-#ifdef DEBUG_WEBSOCKETS
- g_print ("Parse input first byte 0x%2x 0x%2x\n", buf[0], buf[1]);
-#endif
-
- fin = buf[0] & 0x80;
- code = buf[0] & 0x0f;
- payload_len = buf[1] & 0x7f;
- is_mask = buf[1] & 0x80;
- data = buf + 2;
-
- if (payload_len > 125)
- {
- if (len < 4)
- return;
- payload_len = GUINT16_FROM_BE( *(guint16 *) data );
- data += 2;
- }
- else if (payload_len > 126)
- {
- if (len < 10)
- return;
- payload_len = GUINT64_FROM_BE( *(guint64 *) data );
- data += 8;
- }
-
- mask = NULL;
- if (is_mask)
- {
- if (data - buf + 4 > len)
- return;
- mask = data;
- data += 4;
- }
-
- if (data - buf + payload_len > len)
- return; /* wait to accumulate more */
-
- if (is_mask)
- {
- gsize i;
- for (i = 0; i < payload_len; i++)
- data[i] ^= mask[i%4];
- }
-
- switch (code) {
- case BROADWAY_WS_CNX_CLOSE:
- break; /* hang around anyway */
- case BROADWAY_WS_TEXT:
- if (!fin)
- {
-#ifdef DEBUG_WEBSOCKETS
- g_warning ("can't yet accept fragmented input");
-#endif
- }
- else
- {
- char *terminated = g_strndup((char *)data, payload_len);
- parse_input_message (input, terminated);
- g_free (terminated);
- }
- break;
- case BROADWAY_WS_CNX_PING:
- broadway_output_pong (broadway_display->output);
- break;
- case BROADWAY_WS_CNX_PONG:
- break; /* we never send pings, but tolerate pongs */
- case BROADWAY_WS_BINARY:
- case BROADWAY_WS_CONTINUATION:
- default:
- {
- g_warning ("fragmented or unknown input code 0x%2x with fin set", code);
- break;
- }
- }
-
- g_byte_array_remove_range (input->buffer, 0, data - buf + payload_len);
- }
- }
- else /* old style protocol */
- {
- char *buf, *ptr;
- gsize len;
-
- buf = (char *)input->buffer->data;
- len = input->buffer->len;
-
- if (buf[0] != 0)
- {
- broadway_display->input = NULL;
- broadway_input_free (input);
- return;
- }
-
- while ((ptr = memchr (buf, 0xff, len)) != NULL)
- {
- *ptr = 0;
- ptr++;
-
- parse_input_message (input, buf + 1);
-
- len -= ptr - buf;
- buf = ptr;
-
- if (len > 0 && buf[0] != 0)
- {
- broadway_display->input = NULL;
- broadway_input_free (input);
- break;
- }
- }
- g_byte_array_remove_range (input->buffer, 0, buf - (char *)input->buffer->data);
- }
-}
-
-
-static gboolean
-process_input_idle_cb (GdkBroadwayDisplay *display)
-{
- display->process_input_idle = 0;
- process_input_messages (display);
- return G_SOURCE_REMOVE;
-}
-
-static void
-queue_process_input_at_idle (GdkBroadwayDisplay *broadway_display)
-{
- if (broadway_display->process_input_idle == 0)
- broadway_display->process_input_idle =
- g_idle_add_full (GDK_PRIORITY_EVENTS, (GSourceFunc)process_input_idle_cb, broadway_display, NULL);
-}
-
-static void
-_gdk_broadway_display_read_all_input_nonblocking (GdkDisplay *display)
-{
- GdkBroadwayDisplay *broadway_display;
- GInputStream *in;
- gssize res;
- guint8 buffer[1024];
- GError *error;
- BroadwayInput *input;
-
- broadway_display = GDK_BROADWAY_DISPLAY (display);
- if (broadway_display->input == NULL)
- return;
-
- input = broadway_display->input;
-
- in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection));
-
- error = NULL;
- res = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (in),
- buffer, sizeof (buffer), NULL, &error);
-
- if (res <= 0)
- {
- if (res < 0 &&
- g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
- {
- g_error_free (error);
- return;
- }
-
- broadway_display->input = NULL;
- broadway_input_free (input);
- if (res < 0)
- {
- g_print ("input error %s\n", error->message);
- g_error_free (error);
- }
- return;
- }
-
- g_byte_array_append (input->buffer, buffer, res);
-
- parse_input (input);
-}
-
-void
-_gdk_broadway_display_consume_all_input (GdkDisplay *display)
-{
- GdkBroadwayDisplay *broadway_display;
-
- broadway_display = GDK_BROADWAY_DISPLAY (display);
- _gdk_broadway_display_read_all_input_nonblocking (display);
-
- /* Since we're parsing input but not processing the resulting messages
- we might not get a readable callback on the stream, so queue an idle to
- process the messages */
- queue_process_input_at_idle (broadway_display);
-}
-
-
-static gboolean
-input_data_cb (GObject *stream,
- BroadwayInput *input)
-{
- GdkBroadwayDisplay *broadway_display;
-
- broadway_display = GDK_BROADWAY_DISPLAY (input->display);
- _gdk_broadway_display_read_all_input_nonblocking (input->display);
-
- process_input_messages (broadway_display);
-
- return TRUE;
-}
-
-/* Note: This may be called while handling a message (i.e. sorta recursively) */
-BroadwayInputMsg *
-_gdk_broadway_display_block_for_input (GdkDisplay *display, char op,
- guint32 serial, gboolean remove_message)
-{
- GdkBroadwayDisplay *broadway_display;
- BroadwayInputMsg *message;
- gssize res;
- guint8 buffer[1024];
- BroadwayInput *input;
- GInputStream *in;
- GList *l;
-
- gdk_display_flush (display);
-
- broadway_display = GDK_BROADWAY_DISPLAY (display);
- if (broadway_display->input == NULL)
- return NULL;
-
- input = broadway_display->input;
-
- while (TRUE) {
- /* Check for existing reply in queue */
-
- for (l = broadway_display->input_messages; l != NULL; l = l->next)
- {
- message = l->data;
-
- if (message->base.type == op)
- {
- if (message->base.serial == serial)
- {
- if (remove_message)
- broadway_display->input_messages =
- g_list_delete_link (broadway_display->input_messages, l);
- return message;
- }
- }
- }
-
- /* Not found, read more, blocking */
-
- in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection));
- res = g_input_stream_read (in, buffer, sizeof (buffer), NULL, NULL);
- if (res <= 0)
- return NULL;
- g_byte_array_append (input->buffer, buffer, res);
-
- parse_input (input);
-
- /* Since we're parsing input but not processing the resulting messages
- we might not get a readable callback on the stream, so queue an idle to
- process the messages */
- queue_process_input_at_idle (broadway_display);
- }
-}
-
-static char *
-parse_line (char *line, char *key)
-{
- char *p;
-
- if (!g_str_has_prefix (line, key))
- return NULL;
- p = line + strlen (key);
- if (*p != ':')
- return NULL;
- p++;
- /* Skip optional initial space */
- if (*p == ' ')
- p++;
- return p;
-}
-static void
-send_error (HttpRequest *request,
- int error_code,
- const char *reason)
-{
- char *res;
-
- res = g_strdup_printf ("HTTP/1.0 %d %s\r\n\r\n"
- "<html><head><title>%d %s</title></head>"
- "<body>%s</body></html>",
- error_code, reason,
- error_code, reason,
- reason);
- /* TODO: This should really be async */
- g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
- res, strlen (res), NULL, NULL, NULL);
- g_free (res);
- http_request_free (request);
-}
-
-/* magic from: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17 */
-#define SEC_WEB_SOCKET_KEY_MAGIC "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
-
-/* 'x3JJHMbDL1EzLkh9GBhXDw==' generates 'HSmrc0sMlYUkAGmm5OPpG2HaGWk=' */
-static gchar *
-generate_handshake_response_wsietf_v7 (const gchar *key)
-{
- gsize digest_len = 20;
- guchar digest[digest_len];
- GChecksum *checksum;
-
- checksum = g_checksum_new (G_CHECKSUM_SHA1);
- if (!checksum)
- return NULL;
-
- g_checksum_update (checksum, (guchar *)key, -1);
- g_checksum_update (checksum, (guchar *)SEC_WEB_SOCKET_KEY_MAGIC, -1);
-
- g_checksum_get_digest (checksum, digest, &digest_len);
- g_checksum_free (checksum);
-
- g_assert (digest_len == 20);
-
- return g_base64_encode (digest, digest_len);
-}
-
-static void
-start_input (HttpRequest *request, gboolean binary)
-{
- char **lines;
- char *p;
- int num_key1, num_key2;
- guint64 key1, key2;
- int num_space;
- int i;
- guint8 challenge[16];
- char *res;
- gsize len;
- GChecksum *checksum;
- char *origin, *host;
- GdkBroadwayDisplay *broadway_display;
- BroadwayInput *input;
- const void *data_buffer;
- gsize data_buffer_size;
- GInputStream *in;
- char *key_v7;
- gboolean proto_v7_plus;
-
- broadway_display = GDK_BROADWAY_DISPLAY (request->display);
-
- if (broadway_display->input != NULL)
- {
- send_error (request, 409, "Input already handled");
- return;
- }
-
-#ifdef DEBUG_WEBSOCKETS
- g_print ("incoming request:\n%s\n", request->request->str);
-#endif
- lines = g_strsplit (request->request->str, "\n", 0);
-
- num_key1 = 0;
- num_key2 = 0;
- key1 = 0;
- key2 = 0;
- key_v7 = NULL;
- origin = NULL;
- host = NULL;
- for (i = 0; lines[i] != NULL; i++)
- {
- if ((p = parse_line (lines[i], "Sec-WebSocket-Key1")))
- {
- num_space = 0;
- while (*p != 0)
- {
- if (g_ascii_isdigit (*p))
- key1 = key1 * 10 + g_ascii_digit_value (*p);
- else if (*p == ' ')
- num_space++;
-
- p++;
- }
- key1 /= num_space;
- num_key1++;
- }
- else if ((p = parse_line (lines[i], "Sec-WebSocket-Key2")))
- {
- num_space = 0;
- while (*p != 0)
- {
- if (g_ascii_isdigit (*p))
- key2 = key2 * 10 + g_ascii_digit_value (*p);
- else if (*p == ' ')
- num_space++;
-
- p++;
- }
- key2 /= num_space;
- num_key2++;
- }
- else if ((p = parse_line (lines[i], "Sec-WebSocket-Key")))
- {
- key_v7 = p;
- }
- else if ((p = parse_line (lines[i], "Origin")))
- {
- origin = p;
- }
- else if ((p = parse_line (lines[i], "Host")))
- {
- host = p;
- }
- else if ((p = parse_line (lines[i], "Sec-WebSocket-Origin")))
- {
- origin = p;
- }
- }
-
- if (origin == NULL || host == NULL)
- {
- g_strfreev (lines);
- send_error (request, 400, "Bad websocket request");
- return;
- }
-
- if (key_v7 != NULL)
- {
- char* accept = generate_handshake_response_wsietf_v7 (key_v7);
- res = g_strdup_printf ("HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: %s\r\n"
- "Sec-WebSocket-Origin: %s\r\n"
- "Sec-WebSocket-Location: ws://%s/socket\r\n"
- "Sec-WebSocket-Protocol: broadway\r\n"
- "\r\n", accept, origin, host);
- g_free (accept);
-
-#ifdef DEBUG_WEBSOCKETS
- g_print ("v7 proto response:\n%s", res);
-#endif
-
- g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
- res, strlen (res), NULL, NULL, NULL);
- g_free (res);
- proto_v7_plus = TRUE;
- }
- else
- {
- if (num_key1 != 1 || num_key2 != 1)
- {
- g_strfreev (lines);
- send_error (request, 400, "Bad websocket request");
- return;
- }
-
- challenge[0] = (key1 >> 24) & 0xff;
- challenge[1] = (key1 >> 16) & 0xff;
- challenge[2] = (key1 >> 8) & 0xff;
- challenge[3] = (key1 >> 0) & 0xff;
- challenge[4] = (key2 >> 24) & 0xff;
- challenge[5] = (key2 >> 16) & 0xff;
- challenge[6] = (key2 >> 8) & 0xff;
- challenge[7] = (key2 >> 0) & 0xff;
-
- if (!g_input_stream_read_all (G_INPUT_STREAM (request->data), challenge+8, 8, NULL, NULL, NULL))
- {
- g_strfreev (lines);
- send_error (request, 400, "Bad websocket request");
- return;
- }
-
- checksum = g_checksum_new (G_CHECKSUM_MD5);
- g_checksum_update (checksum, challenge, 16);
- len = 16;
- g_checksum_get_digest (checksum, challenge, &len);
- g_checksum_free (checksum);
-
- res = g_strdup_printf ("HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
- "Upgrade: WebSocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Origin: %s\r\n"
- "Sec-WebSocket-Location: ws://%s/socket\r\n"
- "Sec-WebSocket-Protocol: broadway\r\n"
- "\r\n",
- origin, host);
-
-#ifdef DEBUG_WEBSOCKETS
- g_print ("legacy response:\n%s", res);
-#endif
- g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
- res, strlen (res), NULL, NULL, NULL);
- g_free (res);
- g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
- challenge, 16, NULL, NULL, NULL);
- proto_v7_plus = FALSE;
- }
-
- input = g_new0 (BroadwayInput, 1);
-
- input->display = request->display;
- input->connection = g_object_ref (request->connection);
- input->proto_v7_plus = proto_v7_plus;
- input->binary = binary;
-
- data_buffer = g_buffered_input_stream_peek_buffer (G_BUFFERED_INPUT_STREAM (request->data), &data_buffer_size);
- input->buffer = g_byte_array_sized_new (data_buffer_size);
- g_byte_array_append (input->buffer, data_buffer, data_buffer_size);
-
- broadway_display->input = input;
-
- start_output (request, proto_v7_plus, binary);
-
- /* This will free and close the data input stream, but we got all the buffered content already */
- http_request_free (request);
-
- in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection));
- input->source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (in), NULL);
- g_source_set_callback (input->source, (GSourceFunc)input_data_cb, input, NULL);
- g_source_attach (input->source, NULL);
-
- /* Process any data in the pipe already */
- parse_input (input);
- process_input_messages (broadway_display);
-
- g_strfreev (lines);
-}
-
-static void
-start_output (HttpRequest *request, gboolean proto_v7_plus, gboolean binary)
-{
- GSocket *socket;
- GdkBroadwayDisplay *broadway_display;
- int flag = 1;
-
- socket = g_socket_connection_get_socket (request->connection);
- setsockopt(g_socket_get_fd (socket), IPPROTO_TCP,
- TCP_NODELAY, (char *) &flag, sizeof(int));
-
- broadway_display = GDK_BROADWAY_DISPLAY (request->display);
-
- if (broadway_display->output)
- {
- broadway_display->saved_serial = broadway_output_get_next_serial (broadway_display->output);
- broadway_output_free (broadway_display->output);
- }
-
- broadway_display->output =
- broadway_output_new (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
- broadway_display->saved_serial, proto_v7_plus, binary);
-
- _gdk_broadway_resync_windows ();
-
- if (broadway_display->pointer_grab_window)
- broadway_output_grab_pointer (broadway_display->output,
- GDK_WINDOW_IMPL_BROADWAY (broadway_display->pointer_grab_window->impl)->id,
- broadway_display->pointer_grab_owner_events);
-}
-
-static void
-send_data (HttpRequest *request,
- const char *mimetype,
- const char *data, gsize len)
-{
- char *res;
-
- res = g_strdup_printf ("HTTP/1.0 200 OK\r\n"
- "Content-Type: %s\r\n"
- "Content-Length: %"G_GSIZE_FORMAT"\r\n"
- "\r\n",
- mimetype, len);
- /* TODO: This should really be async */
- g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
- res, strlen (res), NULL, NULL, NULL);
- g_free (res);
- g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
- data, len, NULL, NULL, NULL);
- http_request_free (request);
-}
-
-#include "clienthtml.h"
-#include "broadwayjs.h"
-
-static void
-got_request (HttpRequest *request)
-{
- char *start, *escaped, *tmp, *version, *query;
-
- if (!g_str_has_prefix (request->request->str, "GET "))
- {
- send_error (request, 501, "Only GET implemented");
- return;
- }
-
- start = request->request->str + 4; /* Skip "GET " */
-
- while (*start == ' ')
- start++;
-
- for (tmp = start; *tmp != 0 && *tmp != ' ' && *tmp != '\n'; tmp++)
- ;
- escaped = g_strndup (start, tmp - start);
- version = NULL;
- if (*tmp == ' ')
- {
- start = tmp;
- while (*start == ' ')
- start++;
- for (tmp = start; *tmp != 0 && *tmp != ' ' && *tmp != '\n'; tmp++)
- ;
- version = g_strndup (start, tmp - start);
- }
-
- query = strchr (escaped, '?');
- if (query)
- *query = 0;
-
- if (strcmp (escaped, "/client.html") == 0 || strcmp (escaped, "/") == 0)
- send_data (request, "text/html", client_html, G_N_ELEMENTS(client_html) - 1);
- else if (strcmp (escaped, "/broadway.js") == 0)
- send_data (request, "text/javascript", broadway_js, G_N_ELEMENTS(broadway_js) - 1);
- else if (strcmp (escaped, "/socket") == 0)
- start_input (request, FALSE);
- else if (strcmp (escaped, "/socket-bin") == 0)
- start_input (request, TRUE);
- else
- send_error (request, 404, "File not found");
-
- g_free (escaped);
- g_free (version);
-}
-
-static void
-got_http_request_line (GInputStream *stream,
- GAsyncResult *result,
- HttpRequest *request)
-{
- char *line;
-
- line = g_data_input_stream_read_line_finish (G_DATA_INPUT_STREAM (stream), result, NULL, NULL);
- if (line == NULL)
- {
- http_request_free (request);
- g_printerr ("Error reading request lines\n");
- return;
- }
- if (strlen (line) == 0)
- got_request (request);
- else
- {
- /* Protect against overflow in request length */
- if (request->request->len > 1024 * 5)
- {
- send_error (request, 400, "Request too long");
- }
- else
- {
- g_string_append_printf (request->request, "%s\n", line);
- g_data_input_stream_read_line_async (request->data, 0, NULL,
- (GAsyncReadyCallback)got_http_request_line, request);
- }
- }
- g_free (line);
-}
-
-static gboolean
-handle_incoming_connection (GSocketService *service,
- GSocketConnection *connection,
- GObject *source_object)
-{
- HttpRequest *request;
- GInputStream *in;
-
- request = g_new0 (HttpRequest, 1);
- request->connection = g_object_ref (connection);
- request->display = (GdkDisplay *) source_object;
- request->request = g_string_new ("");
-
- in = g_io_stream_get_input_stream (G_IO_STREAM (connection));
-
- request->data = g_data_input_stream_new (in);
- g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (request->data), FALSE);
- /* Be tolerant of input */
- g_data_input_stream_set_newline_type (request->data, G_DATA_STREAM_NEWLINE_TYPE_ANY);
-
- g_data_input_stream_read_line_async (request->data, 0, NULL,
- (GAsyncReadyCallback)got_http_request_line, request);
- return TRUE;
-}
-
GdkDisplay *
_gdk_broadway_display_open (const gchar *display_name)
{
GdkDisplay *display;
GdkBroadwayDisplay *broadway_display;
- GError *error = NULL;
int port;
display = g_object_new (GDK_TYPE_BROADWAY_DISPLAY, NULL);
broadway_display = GDK_BROADWAY_DISPLAY (display);
- broadway_display->output = NULL;
-
/* initialize the display's screens */
broadway_display->screens = g_new (GdkScreen *, 1);
broadway_display->screens[0] = _gdk_broadway_screen_new (display, 0);
@@ -1098,17 +161,12 @@ _gdk_broadway_display_open (const gchar *display_name)
if (port == 0)
port = 8080;
- broadway_display->service = g_socket_service_new ();
- if (!g_socket_listener_add_inet_port (G_SOCKET_LISTENER (broadway_display->service),
- port,
- G_OBJECT (display),
- &error))
+ broadway_display->server = _gdk_broadway_server_new (port, NULL);
+ if (broadway_display->server == NULL)
{
- g_printerr ("Unable to listen to port %d: %s\n", port, error->message);
- g_error_free (error);
+ g_printerr ("Unable to init server\n");
return NULL;
}
- g_signal_connect (broadway_display->service, "incoming", G_CALLBACK (handle_incoming_connection), NULL);
g_signal_emit_by_name (display, "opened");
g_signal_emit_by_name (gdk_display_manager_get (), "display-opened", display);
@@ -1116,7 +174,6 @@ _gdk_broadway_display_open (const gchar *display_name)
return display;
}
-
static const gchar *
gdk_broadway_display_get_name (GdkDisplay *display)
{
@@ -1160,8 +217,11 @@ gdk_broadway_display_beep (GdkDisplay *display)
static void
gdk_broadway_display_sync (GdkDisplay *display)
{
- g_return_if_fail (GDK_IS_DISPLAY (display));
+ GdkBroadwayDisplay *broadway_display = GDK_BROADWAY_DISPLAY (display);
+ g_return_if_fail (GDK_IS_BROADWAY_DISPLAY (display));
+
+ _gdk_broadway_server_sync (broadway_display->server);
}
static void
@@ -1169,15 +229,9 @@ gdk_broadway_display_flush (GdkDisplay *display)
{
GdkBroadwayDisplay *broadway_display = GDK_BROADWAY_DISPLAY (display);
- g_return_if_fail (GDK_IS_DISPLAY (display));
+ g_return_if_fail (GDK_IS_BROADWAY_DISPLAY (display));
- if (broadway_display->output &&
- !broadway_output_flush (broadway_display->output))
- {
- broadway_display->saved_serial = broadway_output_get_next_serial (broadway_display->output);
- broadway_output_free (broadway_display->output);
- broadway_display->output = NULL;
- }
+ _gdk_broadway_server_flush (broadway_display->server);
}
static gboolean
@@ -1307,11 +361,9 @@ gdk_broadway_display_get_next_serial (GdkDisplay *display)
{
GdkBroadwayDisplay *broadway_display;
broadway_display = GDK_BROADWAY_DISPLAY (display);
- if (broadway_display->output)
- return broadway_output_get_next_serial (broadway_display->output);
- return broadway_display->saved_serial;
-}
+ return _gdk_broadway_server_get_next_serial (broadway_display->server);
+}
static void
gdk_broadway_display_event_data_copy (GdkDisplay *display,
diff --git a/gdk/broadway/gdkdisplay-broadway.h b/gdk/broadway/gdkdisplay-broadway.h
index d3699f8..db24a01 100644
--- a/gdk/broadway/gdkdisplay-broadway.h
+++ b/gdk/broadway/gdkdisplay-broadway.h
@@ -27,6 +27,7 @@
#include "gdkwindow.h"
#include "gdkinternals.h"
#include "gdkmain.h"
+#include "gdkbroadway-server.h"
#include "broadway.h"
G_BEGIN_DECLS
@@ -43,82 +44,6 @@ typedef struct BroadwayInput BroadwayInput;
#define GDK_IS_BROADWAY_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_BROADWAY_DISPLAY))
#define GDK_BROADWAY_DISPLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_BROADWAY_DISPLAY, GdkBroadwayDisplayClass))
-typedef struct {
- char type;
- guint32 serial;
- guint64 time;
-} BroadwayInputBaseMsg;
-
-typedef struct {
- BroadwayInputBaseMsg base;
- guint32 mouse_window_id; /* The real window, not taking grabs into account */
- guint32 event_window_id;
- int root_x;
- int root_y;
- int win_x;
- int win_y;
- guint32 state;
-} BroadwayInputPointerMsg;
-
-typedef struct {
- BroadwayInputPointerMsg pointer;
- guint32 mode;
-} BroadwayInputCrossingMsg;
-
-typedef struct {
- BroadwayInputPointerMsg pointer;
- guint32 button;
-} BroadwayInputButtonMsg;
-
-typedef struct {
- BroadwayInputPointerMsg pointer;
- int dir;
-} BroadwayInputScrollMsg;
-
-typedef struct {
- BroadwayInputBaseMsg base;
- guint32 state;
- int key;
-} BroadwayInputKeyMsg;
-
-typedef struct {
- BroadwayInputBaseMsg base;
- int res;
-} BroadwayInputGrabReply;
-
-typedef struct {
- BroadwayInputBaseMsg base;
- int id;
- int x;
- int y;
- int width;
- int height;
-} BroadwayInputConfigureNotify;
-
-typedef struct {
- BroadwayInputBaseMsg base;
- int width;
- int height;
-} BroadwayInputScreenResizeNotify;
-
-typedef struct {
- BroadwayInputBaseMsg base;
- int id;
-} BroadwayInputDeleteNotify;
-
-typedef union {
- BroadwayInputBaseMsg base;
- BroadwayInputPointerMsg pointer;
- BroadwayInputCrossingMsg crossing;
- BroadwayInputButtonMsg button;
- BroadwayInputScrollMsg scroll;
- BroadwayInputKeyMsg key;
- BroadwayInputGrabReply grab_reply;
- BroadwayInputConfigureNotify configure_notify;
- BroadwayInputDeleteNotify delete_notify;
- BroadwayInputScreenResizeNotify screen_resize_notify;
-} BroadwayInputMsg;
-
struct _GdkBroadwayDisplay
{
GdkDisplay parent_instance;
@@ -129,10 +54,6 @@ struct _GdkBroadwayDisplay
GList *toplevels;
GSource *event_source;
- GdkWindow *mouse_in_toplevel;
- int last_x, last_y; /* in root coords */
- guint32 last_state;
- GdkWindow *real_mouse_in_toplevel; /* Not affected by grabs */
/* Keyboard related information */
GdkKeymap *keymap;
@@ -147,24 +68,7 @@ struct _GdkBroadwayDisplay
/* The offscreen window that has the pointer in it (if any) */
GdkWindow *active_offscreen_window;
- GSocketService *service;
- BroadwayOutput *output;
- guint32 saved_serial;
- guint64 last_seen_time;
- BroadwayInput *input;
- GList *input_messages;
- guint process_input_idle;
-
- /* Explicit pointer grabs: */
- GdkWindow *pointer_grab_window;
- guint32 pointer_grab_time;
- gboolean pointer_grab_owner_events;
-
- /* Future data, from the currently queued events */
- int future_root_x;
- int future_root_y;
- GdkModifierType future_state;
- int future_mouse_in_toplevel;
+ GdkBroadwayServer *server;
};
struct _GdkBroadwayDisplayClass
diff --git a/gdk/broadway/gdkeventsource.c b/gdk/broadway/gdkeventsource.c
index 14fa479..ff8430d 100644
--- a/gdk/broadway/gdkeventsource.c
+++ b/gdk/broadway/gdkeventsource.c
@@ -87,9 +87,9 @@ gdk_event_source_check (GSource *source)
}
void
-_gdk_broadway_events_got_input (GdkDisplay *display,
- BroadwayInputMsg *message)
+_gdk_broadway_events_got_input (BroadwayInputMsg *message)
{
+ GdkDisplay *display = gdk_display_get_default ();
GdkBroadwayDisplay *display_broadway = GDK_BROADWAY_DISPLAY (display);
GdkScreen *screen;
GdkWindow *window;
@@ -98,16 +98,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
switch (message->base.type) {
case 'e': /* Enter */
- display_broadway->last_x = message->pointer.root_x;
- display_broadway->last_y = message->pointer.root_y;
- display_broadway->last_state = message->pointer.state;
- display_broadway->real_mouse_in_toplevel =
- g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->pointer.mouse_window_id));
-
window = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->pointer.event_window_id));
-
- /* TODO: Unset when it dies */
- display_broadway->mouse_in_toplevel = window;
if (window)
{
event = gdk_event_new (GDK_ENTER_NOTIFY);
@@ -135,15 +126,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
}
break;
case 'l': /* Leave */
- display_broadway->last_x = message->pointer.root_x;
- display_broadway->last_y = message->pointer.root_y;
- display_broadway->last_state = message->pointer.state;
- display_broadway->real_mouse_in_toplevel =
- g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->pointer.mouse_window_id));
-
window = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->pointer.event_window_id));
-
- display_broadway->mouse_in_toplevel = NULL;
if (window)
{
event = gdk_event_new (GDK_LEAVE_NOTIFY);
@@ -171,12 +154,6 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
}
break;
case 'm': /* Mouse move */
- display_broadway->last_x = message->pointer.root_x;
- display_broadway->last_y = message->pointer.root_y;
- display_broadway->last_state = message->pointer.state;
- display_broadway->real_mouse_in_toplevel =
- g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->pointer.mouse_window_id));
-
if (_gdk_broadway_moveresize_handle_event (display, message))
break;
@@ -200,12 +177,6 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
break;
case 'b':
case 'B':
- display_broadway->last_x = message->pointer.root_x;
- display_broadway->last_y = message->pointer.root_y;
- display_broadway->last_state = message->pointer.state;
- display_broadway->real_mouse_in_toplevel =
- g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->pointer.mouse_window_id));
-
if (message->base.type != 'b' &&
_gdk_broadway_moveresize_handle_event (display, message))
break;
@@ -230,12 +201,6 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
break;
case 's':
- display_broadway->last_x = message->pointer.root_x;
- display_broadway->last_y = message->pointer.root_y;
- display_broadway->last_state = message->pointer.state;
- display_broadway->real_mouse_in_toplevel =
- g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->pointer.mouse_window_id));
-
window = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->pointer.event_window_id));
if (window)
{
@@ -256,8 +221,8 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
break;
case 'k':
case 'K':
- window = display_broadway->mouse_in_toplevel;
-
+ window = g_hash_table_lookup (display_broadway->id_ht,
+ GINT_TO_POINTER (message->key.mouse_window_id));
if (window)
{
event = gdk_event_new (message->base.type == 'k' ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
@@ -269,8 +234,6 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
event->key.length = 0;
gdk_event_set_device (event, display->core_pointer);
- display_broadway->last_state = message->key.state;
-
node = _gdk_event_queue_append (display, event);
_gdk_windowing_got_event (display, node, event, message->base.serial);
}
@@ -335,7 +298,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
break;
default:
- g_printerr ("Unknown input command %c\n", message->base.type);
+ g_printerr ("_gdk_broadway_events_got_input - Unknown input command %c\n", message->base.type);
break;
}
}
diff --git a/gdk/broadway/gdkprivate-broadway.h b/gdk/broadway/gdkprivate-broadway.h
index bcc06d2..8277c08 100644
--- a/gdk/broadway/gdkprivate-broadway.h
+++ b/gdk/broadway/gdkprivate-broadway.h
@@ -126,8 +126,7 @@ GList *_gdk_broadway_screen_list_visuals (GdkScreen *screen);
void _gdk_broadway_screen_size_changed (GdkScreen *screen,
BroadwayInputScreenResizeNotify *msg);
-void _gdk_broadway_events_got_input (GdkDisplay *display,
- BroadwayInputMsg *message);
+void _gdk_broadway_events_got_input (BroadwayInputMsg *message);
void _gdk_broadway_screen_init_root_window (GdkScreen *screen);
void _gdk_broadway_screen_init_visuals (GdkScreen *screen);
diff --git a/gdk/broadway/gdkwindow-broadway.c b/gdk/broadway/gdkwindow-broadway.c
index 08e23af..9709ff6 100644
--- a/gdk/broadway/gdkwindow-broadway.c
+++ b/gdk/broadway/gdkwindow-broadway.c
@@ -83,95 +83,17 @@ G_DEFINE_TYPE (GdkWindowImplBroadway,
gdk_window_impl_broadway,
GDK_TYPE_WINDOW_IMPL)
-static void
-diff_surfaces (cairo_surface_t *surface,
- cairo_surface_t *old_surface)
-{
- guint8 *data, *old_data;
- guint32 *line, *old_line;
- int w, h, stride, old_stride;
- int x, y;
-
- data = cairo_image_surface_get_data (surface);
- old_data = cairo_image_surface_get_data (old_surface);
-
- w = cairo_image_surface_get_width (surface);
- h = cairo_image_surface_get_height (surface);
-
- stride = cairo_image_surface_get_stride (surface);
- old_stride = cairo_image_surface_get_stride (old_surface);
-
- for (y = 0; y < h; y++)
- {
- line = (guint32 *)data;
- old_line = (guint32 *)old_data;
-
- for (x = 0; x < w; x++)
- {
- if ((*line & 0xffffff) == (*old_line & 0xffffff))
- *old_line = 0;
- else
- *old_line = *line | 0xff000000;
- line ++;
- old_line ++;
- }
-
- data += stride;
- old_data += old_stride;
- }
-}
-
static guint dirty_flush_id = 0;
-static void
-window_data_send (BroadwayOutput *output, GdkWindowImplBroadway *impl)
-{
- cairo_t *cr;
-
- if (impl->surface == NULL)
- return;
-
- if (impl->last_synced)
- {
- diff_surfaces (impl->surface,
- impl->last_surface);
- broadway_output_put_rgba (output, impl->id, 0, 0,
- cairo_image_surface_get_width (impl->last_surface),
- cairo_image_surface_get_height (impl->last_surface),
- cairo_image_surface_get_stride (impl->last_surface),
- cairo_image_surface_get_data (impl->last_surface));
- }
- else
- {
- impl->last_synced = TRUE;
- broadway_output_put_rgb (output, impl->id, 0, 0,
- cairo_image_surface_get_width (impl->surface),
- cairo_image_surface_get_height (impl->surface),
- cairo_image_surface_get_stride (impl->surface),
- cairo_image_surface_get_data (impl->surface));
- }
-
- broadway_output_surface_flush (output, impl->id);
-
- cr = cairo_create (impl->last_surface);
- cairo_set_source_surface (cr, impl->surface, 0, 0);
- cairo_paint (cr);
- cairo_destroy (cr);
-}
-
static gboolean
dirty_flush_idle (gpointer data)
{
GList *l;
GdkBroadwayDisplay *display;
- BroadwayOutput *output;
dirty_flush_id = 0;
display = GDK_BROADWAY_DISPLAY (gdk_display_get_default ());
- output = display->output;
- if (output == NULL)
- return FALSE;
for (l = display->toplevels; l != NULL; l = l->next)
{
@@ -180,11 +102,15 @@ dirty_flush_idle (gpointer data)
if (impl->dirty)
{
impl->dirty = FALSE;
- window_data_send (display->output, impl);
+ _gdk_broadway_server_window_update (display->server,
+ impl->id,
+ impl->surface);
}
}
- gdk_display_flush (GDK_DISPLAY (display));
+ /* We sync here to ensure all references to the impl->surface memory
+ is done, as we may later paint new data in them. */
+ gdk_display_sync (GDK_DISPLAY (display));
return FALSE;
}
@@ -192,64 +118,10 @@ dirty_flush_idle (gpointer data)
static void
queue_dirty_flush (GdkBroadwayDisplay *display)
{
- if (dirty_flush_id == 0 && display->output != NULL)
+ if (dirty_flush_id == 0)
dirty_flush_id = gdk_threads_add_idle (dirty_flush_idle, NULL);
}
-void
-_gdk_broadway_resync_windows (void)
-{
- GdkBroadwayDisplay *display;
- GList *l;
-
- dirty_flush_id = 0;
-
- display = GDK_BROADWAY_DISPLAY (gdk_display_get_default ());
-
- /* First create all windows */
- for (l = display->toplevels; l != NULL; l = l->next)
- {
- GdkWindowImplBroadway *impl = l->data;
- GdkWindow *window;
-
- window = impl->wrapper;
-
- if (impl->id == 0)
- continue; /* Skip root */
-
- impl->dirty = FALSE;
- impl->last_synced = FALSE;
- broadway_output_new_surface (display->output,
- impl->id,
- window->x,
- window->y,
- window->width,
- window->height,
- window->window_type == GDK_WINDOW_TEMP);
- }
-
- /* Then do everything that may reference other windows */
- for (l = display->toplevels; l != NULL; l = l->next)
- {
- GdkWindowImplBroadway *impl = l->data;
-
- if (impl->id == 0)
- continue; /* Skip root */
-
- if (impl->transient_for)
- broadway_output_set_transient_for (display->output, impl->id, impl->transient_for);
- /* Can't check GDK_WINDOW_IS_MAPPED here, because that doesn't correctly handle
- withdrawn windows like menus */
- if (impl->visible)
- {
- broadway_output_show_surface (display->output, impl->id);
- window_data_send (display->output, impl);
- }
- }
-
- gdk_display_flush (GDK_DISPLAY (display));
-}
-
static void
gdk_window_impl_broadway_init (GdkWindowImplBroadway *impl)
{
@@ -275,12 +147,6 @@ gdk_window_impl_broadway_finalize (GObject *object)
broadway_display = GDK_BROADWAY_DISPLAY (gdk_window_get_display (impl->wrapper));
- if (broadway_display->mouse_in_toplevel == GDK_WINDOW (wrapper))
- {
- /* TODO: Send leave + enter event, update cursors, etc */
- broadway_display->mouse_in_toplevel = NULL;
- }
-
g_hash_table_remove (broadway_display->id_ht, GINT_TO_POINTER(impl->id));
if (impl->cursor)
@@ -315,6 +181,7 @@ _gdk_broadway_screen_init_root_window (GdkScreen * screen)
impl->screen = screen;
impl->wrapper = window;
+ impl->id = 0;
window->window_type = GDK_WINDOW_ROOT;
window->depth = 24;
@@ -341,13 +208,17 @@ _gdk_broadway_display_create_window_impl (GdkDisplay *display,
{
GdkWindowImplBroadway *impl;
GdkBroadwayDisplay *broadway_display;
- static int current_id = 1; /* 0 is the root window */
broadway_display = GDK_BROADWAY_DISPLAY (display);
impl = g_object_new (GDK_TYPE_WINDOW_IMPL_BROADWAY, NULL);
window->impl = (GdkWindowImpl *)impl;
- impl->id = current_id++;
+ impl->id = _gdk_broadway_server_new_window (broadway_display->server,
+ window->x,
+ window->y,
+ window->width,
+ window->height,
+ window->window_type == GDK_WINDOW_TEMP);
g_hash_table_insert (broadway_display->id_ht, GINT_TO_POINTER(impl->id), window);
impl->wrapper = window;
@@ -358,37 +229,23 @@ _gdk_broadway_display_create_window_impl (GdkDisplay *display,
g_assert (GDK_WINDOW_TYPE (window->parent) == GDK_WINDOW_ROOT);
broadway_display->toplevels = g_list_prepend (broadway_display->toplevels, impl);
-
- if (broadway_display->output)
- broadway_output_new_surface (broadway_display->output,
- impl->id,
- window->x,
- window->y,
- window->width,
- window->height,
- window->window_type == GDK_WINDOW_TEMP);
}
void
_gdk_broadway_window_resize_surface (GdkWindow *window)
{
GdkWindowImplBroadway *impl = GDK_WINDOW_IMPL_BROADWAY (window->impl);
- cairo_surface_t *old, *last_old;
+ cairo_surface_t *old;
if (impl->surface)
{
old = impl->surface;
- last_old = impl->last_surface;
impl->surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
gdk_window_get_width (impl->wrapper),
gdk_window_get_height (impl->wrapper));
- impl->last_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
- gdk_window_get_width (impl->wrapper),
- gdk_window_get_height (impl->wrapper));
cairo_surface_destroy (old);
- cairo_surface_destroy (last_old);
}
if (impl->ref_surface)
@@ -413,7 +270,6 @@ static cairo_surface_t *
gdk_window_broadway_ref_cairo_surface (GdkWindow *window)
{
GdkWindowImplBroadway *impl = GDK_WINDOW_IMPL_BROADWAY (window->impl);
- cairo_t *cr;
int w, h;
if (GDK_IS_WINDOW_IMPL_BROADWAY (window) &&
@@ -425,22 +281,7 @@ gdk_window_broadway_ref_cairo_surface (GdkWindow *window)
/* Create actual backing store if missing */
if (!impl->surface)
- {
- impl->surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
- impl->last_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
-
- cr = cairo_create (impl->surface);
- cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
- cairo_rectangle (cr, 0, 0, w, h);
- cairo_fill (cr);
- cairo_destroy (cr);
-
- cr = cairo_create (impl->last_surface);
- cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
- cairo_rectangle (cr, 0, 0, w, h);
- cairo_fill (cr);
- cairo_destroy (cr);
- }
+ impl->surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
/* Create a destroyable surface referencing the real one */
if (!impl->ref_surface)
@@ -485,16 +326,13 @@ _gdk_broadway_window_destroy (GdkWindow *window,
{
cairo_surface_destroy (impl->surface);
impl->surface = NULL;
- cairo_surface_destroy (impl->last_surface);
- impl->last_surface = NULL;
}
broadway_display = GDK_BROADWAY_DISPLAY (gdk_window_get_display (window));
g_hash_table_remove (broadway_display->id_ht, GINT_TO_POINTER(impl->id));
- if (broadway_display->output)
- broadway_output_destroy_surface (broadway_display->output,
- impl->id);
+ _gdk_broadway_server_destroy_window (broadway_display->server,
+ impl->id);
}
static cairo_surface_t *
@@ -546,11 +384,9 @@ gdk_window_broadway_show (GdkWindow *window, gboolean already_mapped)
_gdk_make_event (GDK_WINDOW (window), GDK_MAP, NULL, FALSE);
broadway_display = GDK_BROADWAY_DISPLAY (gdk_window_get_display (window));
- if (broadway_display->output)
- {
- broadway_output_show_surface (broadway_display->output, impl->id);
- queue_dirty_flush (broadway_display);
- }
+ if (_gdk_broadway_server_window_show (broadway_display->server, impl->id))
+ queue_dirty_flush (broadway_display);
+
}
static void
@@ -569,17 +405,8 @@ gdk_window_broadway_hide (GdkWindow *window)
_gdk_make_event (GDK_WINDOW (window), GDK_UNMAP, NULL, FALSE);
broadway_display = GDK_BROADWAY_DISPLAY (gdk_window_get_display (window));
- if (broadway_display->output)
- {
- broadway_output_hide_surface (broadway_display->output, impl->id);
- queue_dirty_flush (broadway_display);
- }
-
- if (broadway_display->mouse_in_toplevel == window)
- {
- /* TODO: Send leave + enter event, update cursors, etc */
- broadway_display->mouse_in_toplevel = NULL;
- }
+ if (_gdk_broadway_server_window_hide (broadway_display->server, impl->id))
+ queue_dirty_flush (broadway_display);
_gdk_window_clear_update_area (window);
}
@@ -601,7 +428,6 @@ gdk_window_broadway_move_resize (GdkWindow *window,
GdkWindowImplBroadway *impl = GDK_WINDOW_IMPL_BROADWAY (window->impl);
GdkBroadwayDisplay *broadway_display;
gboolean changed, size_changed;;
- gboolean with_resize;
size_changed = changed = FALSE;
@@ -613,10 +439,8 @@ gdk_window_broadway_move_resize (GdkWindow *window,
window->y = y;
}
- with_resize = FALSE;
if (width > 0 || height > 0)
{
- with_resize = TRUE;
if (width < 1)
width = 1;
@@ -644,12 +468,11 @@ gdk_window_broadway_move_resize (GdkWindow *window,
GdkEvent *event;
GList *node;
- if (broadway_display->output != NULL)
+ if (_gdk_broadway_server_window_move_resize (broadway_display->server,
+ impl->id,
+ window->x, window->y,
+ window->width, window->height))
{
- broadway_output_move_resize_surface (broadway_display->output,
- impl->id,
- with_move, window->x, window->y,
- with_resize, window->width, window->height);
queue_dirty_flush (broadway_display);
if (size_changed)
window->resize_count++;
@@ -787,11 +610,7 @@ gdk_broadway_window_set_transient_for (GdkWindow *window,
impl->transient_for = parent_id;
display = GDK_BROADWAY_DISPLAY (gdk_window_get_display (impl->wrapper));
- if (display->output)
- {
- broadway_output_set_transient_for (display->output, impl->id, impl->transient_for);
- gdk_display_flush (GDK_DISPLAY (display));
- }
+ _gdk_broadway_server_window_set_transient_for (display->server, impl->id, impl->transient_for);
}
static void
@@ -1324,20 +1143,10 @@ moveresize_lookahead (GdkDisplay *display,
BroadwayInputMsg *event)
{
GdkBroadwayDisplay *broadway_display;
- BroadwayInputMsg *message;
- GList *l;
broadway_display = GDK_BROADWAY_DISPLAY (display);
- for (l = broadway_display->input_messages; l != NULL; l = l->next)
- {
- message = l->data;
- if (message->base.type == 'm')
- return FALSE;
- if (message->base.type == 'b')
- return FALSE;
- }
- return TRUE;
+ return !_gdk_broadway_server_lookahead_event (broadway_display->server, "mb");
}
gboolean
@@ -1480,7 +1289,7 @@ gdk_broadway_window_begin_resize_drag (GdkWindow *window,
/* We need a connection to be able to get mouse events, if not, punt */
broadway_display = GDK_BROADWAY_DISPLAY (gdk_window_get_display (window));
- if (!broadway_display->output)
+ if (!_gdk_broadway_server_has_client (broadway_display->server))
return;
mv_resize = get_move_resize_data (GDK_WINDOW_DISPLAY (window), TRUE);
@@ -1622,9 +1431,6 @@ _gdk_broadway_window_translate (GdkWindow *window,
{
GdkWindowImplBroadway *impl;
GdkBroadwayDisplay *broadway_display;
- int n_rects, i;
- BroadwayRect *rects;
- cairo_rectangle_int_t rect;
impl = GDK_WINDOW_IMPL_BROADWAY (window->impl);
@@ -1632,26 +1438,11 @@ _gdk_broadway_window_translate (GdkWindow *window,
{
copy_region (impl->surface, area, dx, dy);
broadway_display = GDK_BROADWAY_DISPLAY (gdk_window_get_display (window));
- if (GDK_WINDOW_IMPL_BROADWAY (impl)->last_synced &&
- broadway_display->output)
- {
- copy_region (impl->last_surface, area, dx, dy);
- n_rects = cairo_region_num_rectangles (area);
- rects = g_new (BroadwayRect, n_rects);
- for (i = 0; i < n_rects; i++)
- {
- cairo_region_get_rectangle (area, i, &rect);
- rects[i].x = rect.x;
- rects[i].y = rect.y;
- rects[i].width = rect.width;
- rects[i].height = rect.height;
- }
- broadway_output_copy_rectangles (broadway_display->output,
- GDK_WINDOW_IMPL_BROADWAY (impl)->id,
- rects, n_rects, dx, dy);
- queue_dirty_flush (broadway_display);
- g_free (rects);
- }
+
+ if (_gdk_broadway_server_window_translate (broadway_display->server,
+ impl->id,
+ area, dx, dy))
+ queue_dirty_flush (broadway_display);
}
}
@@ -1661,8 +1452,7 @@ gdk_broadway_get_last_seen_time (GdkWindow *window)
GdkDisplay *display;
display = gdk_window_get_display (window);
- _gdk_broadway_display_consume_all_input (display);
- return (guint32) GDK_BROADWAY_DISPLAY (display)->last_seen_time;
+ return _gdk_broadway_server_get_last_seen_time (GDK_BROADWAY_DISPLAY (display)->server);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]