diff options
author | Alexander Larsson <alexl@redhat.com> | 2013-01-08 10:14:41 +0100 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2013-01-08 18:05:06 +0100 |
commit | c83d35d1dfb0e655c4c327b0780e80127afebd0d (patch) | |
tree | d005555f28beb5788d14863271ec60bd2fe00290 | |
parent | 71e7912940c23119b274062bb95a2c7dbd284dad (diff) | |
download | gtk+-c83d35d1dfb0e655c4c327b0780e80127afebd0d.tar.gz |
broadway: Rewrite serials for clients
This seems right, but atm it breaks grabs.
-rw-r--r-- | gdk/broadway/broadway-server.c | 11 | ||||
-rw-r--r-- | gdk/broadway/broadway-server.h | 2 | ||||
-rw-r--r-- | gdk/broadway/broadwayd.c | 114 |
3 files changed, 121 insertions, 6 deletions
diff --git a/gdk/broadway/broadway-server.c b/gdk/broadway/broadway-server.c index 05e3485944..07652ef3aa 100644 --- a/gdk/broadway/broadway-server.c +++ b/gdk/broadway/broadway-server.c @@ -253,13 +253,20 @@ process_input_messages (BroadwayServer *server) g_list_delete_link (server->input_messages, server->input_messages); + if (message->base.serial == 0) + { + /* This was sent before we got any requests, but we don't want the + daemon serials to go backwards, so we fix it up to be the last used + serial */ + message->base.serial = server->saved_serial - 1; + } update_event_state (server, message); client = -1; if (is_pointer_event (message) && server->pointer_grab_window_id != -1) client = server->pointer_grab_client_id; - + broadway_events_got_input (message, client); g_free (message); } @@ -651,7 +658,7 @@ input_data_cb (GObject *stream, return TRUE; } -gulong +guint32 broadway_server_get_next_serial (BroadwayServer *server) { if (server->output) diff --git a/gdk/broadway/broadway-server.h b/gdk/broadway/broadway-server.h index b408139879..e0a59c1fad 100644 --- a/gdk/broadway/broadway-server.h +++ b/gdk/broadway/broadway-server.h @@ -24,7 +24,7 @@ BroadwayServer *broadway_server_new (int gboolean broadway_server_has_client (BroadwayServer *server); void broadway_server_flush (BroadwayServer *server); void broadway_server_sync (BroadwayServer *server); -gulong broadway_server_get_next_serial (BroadwayServer *server); +guint32 broadway_server_get_next_serial (BroadwayServer *server); guint32 broadway_server_get_last_seen_time (BroadwayServer *server); gboolean broadway_server_lookahead_event (BroadwayServer *server, const char *types); diff --git a/gdk/broadway/broadwayd.c b/gdk/broadway/broadwayd.c index dce7b7f58a..ac100be6f4 100644 --- a/gdk/broadway/broadwayd.c +++ b/gdk/broadway/broadwayd.c @@ -17,11 +17,34 @@ GList *clients; static guint32 client_id_count = 1; +/* Serials: + * + * Broadway tracks serials for all clients primarily to get the right behaviour wrt + * grabs. Each request the client sends gets an increasing per-client serial number, starting + * at 1. Thus, the client can now when a mouse event is seen whether the mouse event was + * sent before or after the server saw the grab request from the client (as this affects how + * the event is handled). + * + * There is only a single stream of increasing serials sent from the daemon to the web browser + * though, called "daemon serials", so we need to map back from the daemon serials to the client + * serials when we send an event to a client. So, each client keeps track of the mappings + * between its serials and daemon serials for any outstanding requests. + * + * There is some additional complexity in that there may be multiple consecutive web browser + * sessions, so we need to keep track of the last daemon serial used inbetween each web client + * connection so that the daemon serials can be strictly increasing. + */ + +typedef struct { + guint32 client_serial; + guint32 daemon_serial; +} BroadwaySerialMapping; + typedef struct { guint32 id; GSocketConnection *connection; GBufferedInputStream *in; - guint32 last_seen_serial; + GSList *serial_mappings; GList *windows; guint disconnect_idle; } BroadwayClient; @@ -34,6 +57,7 @@ client_free (BroadwayClient *client) clients = g_list_remove (clients, client); g_object_unref (client->connection); g_object_unref (client->in); + g_slist_free_full (client->serial_mappings, g_free); g_free (client); } @@ -172,6 +196,70 @@ open_surface (char *name, int width, int height) return surface; } +void +add_client_serial_mapping (BroadwayClient *client, + guint32 client_serial, + guint32 daemon_serial) +{ + BroadwaySerialMapping *map; + GSList *last; + + last = g_slist_last (client->serial_mappings); + + if (last != NULL) + { + map = last->data; + + /* If we have no web client, don't grow forever */ + if (map->daemon_serial == daemon_serial) + { + map->client_serial = client_serial; + return; + } + } + + map = g_new0 (BroadwaySerialMapping, 1); + map->client_serial = client_serial; + map->daemon_serial = daemon_serial; + client->serial_mappings = g_slist_append (client->serial_mappings, map); +} + +/* Returns the latest seen client serial at the time we sent + a daemon request to the browser with a specific daemon serial */ +guint32 +get_client_serial (BroadwayClient *client, guint32 daemon_serial) +{ + BroadwaySerialMapping *map; + GSList *l, *found; + guint32 client_serial = 0; + + found = NULL; + for (l = client->serial_mappings; l != NULL; l = l->next) + { + map = l->data; + + if (map->daemon_serial <= daemon_serial) + { + found = l; + client_serial = map->client_serial; + } + else + break; + } + + /* Remove mappings before the found one, they will never more be used */ + while (found != NULL && + client->serial_mappings != found) + { + g_free (client->serial_mappings->data); + client->serial_mappings = + g_slist_delete_link (client->serial_mappings, client->serial_mappings); + } + + return client_serial; +} + + static void client_handle_request (BroadwayClient *client, BroadwayRequest *request) @@ -183,8 +271,9 @@ client_handle_request (BroadwayClient *client, BroadwayReplyUngrabPointer reply_ungrab_pointer; cairo_region_t *area; cairo_surface_t *surface; + guint32 before_serial, now_serial; - client->last_seen_serial = request->base.serial; + before_serial = broadway_server_get_next_serial (server); switch (request->base.type) { @@ -199,7 +288,7 @@ client_handle_request (BroadwayClient *client, client->windows = g_list_prepend (client->windows, GUINT_TO_POINTER (reply_new_window.id)); - + send_reply (client, request, (BroadwayReply *)&reply_new_window, sizeof (reply_new_window), BROADWAY_REPLY_NEW_WINDOW); break; @@ -291,6 +380,20 @@ client_handle_request (BroadwayClient *client, default: g_warning ("Unknown request of type %d\n", request->base.type); } + + + now_serial = broadway_server_get_next_serial (server); + + /* If we sent a new output request, map that this client serial to that, otherwise + update old mapping for previously sent daemon serial */ + if (now_serial != before_serial) + add_client_serial_mapping (client, + request->base.serial, + before_serial); + else + add_client_serial_mapping (client, + request->base.serial, + before_serial - 1); } static void @@ -494,9 +597,12 @@ broadway_events_got_input (BroadwayInputMsg *message, GList *l; BroadwayReplyEvent reply_event; gsize size; + guint32 daemon_serial; size = get_event_size (message->base.type); + daemon_serial = message->base.serial; + reply_event.msg = *message; for (l = clients; l != NULL; l = l->next) @@ -506,6 +612,8 @@ broadway_events_got_input (BroadwayInputMsg *message, if (client_id == -1 || client->id == client_id) { + message->base.serial = get_client_serial (client, daemon_serial); + send_reply (client, NULL, (BroadwayReply *)&reply_event, sizeof (BroadwayReplyBase) + size, BROADWAY_REPLY_EVENT); |