>From the documentation:

"This protocol uses the XSync extension to let client and window manager
synchronize the repaint of the window manager frame and the client window"

 * It makes sure the window manager doesn't send configure events faster
than the application can handle them.
 * If an sync request hasn't been replied after 1 second, the wm switches
back to unsync'd resizing until the sync request counter is updated.
 * Only supported with application/toolkits implementing the protocol.
---
 configure.ac                  |   2 +-
 src/xwayland/window-manager.c | 231 ++++++++++++++++++++++++++++++++++++++++--
 src/xwayland/xwayland.h       |   5 +
 3 files changed, 230 insertions(+), 8 deletions(-)

diff --git a/configure.ac b/configure.ac
index f9f1c53..4edd283 100644
--- a/configure.ac
+++ b/configure.ac
@@ -91,7 +91,7 @@ AC_ARG_ENABLE(xwayland-test, [  --enable-xwayland-test],,
 AM_CONDITIONAL(ENABLE_XWAYLAND, test x$enable_xwayland = xyes)
 AM_CONDITIONAL(ENABLE_XWAYLAND_TEST, test x$enable_xwayland = xyes -a 
x$enable_xwayland_test = xyes)
 if test x$enable_xwayland = xyes; then
-  PKG_CHECK_MODULES([XWAYLAND], xcb xcb-xfixes xcursor cairo-xcb)
+  PKG_CHECK_MODULES([XWAYLAND], xcb xcb-sync xcb-xfixes xcursor cairo-xcb)
   AC_DEFINE([BUILD_XWAYLAND], [1], [Build the X server launcher])
 
   AC_ARG_WITH(xserver-path, AS_HELP_STRING([--with-xserver-path=PATH],
diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c
index 76294fa..b3c9251 100644
--- a/src/xwayland/window-manager.c
+++ b/src/xwayland/window-manager.c
@@ -119,12 +119,22 @@ struct weston_wm_window {
        int has_alpha;
        int map_notified;
        int mapped;
+       xcb_sync_alarm_t sync_request_alarm;
+       xcb_sync_counter_t sync_request_counter;
+       struct wl_event_source *sync_request_timer;
+       int64_t sync_request_serial;
+       int configure_pending;
+       int sync_disabled;
+       int wait_redraw;
 };
 
 static struct weston_wm_window *
 get_wm_window(struct weston_surface *surface);
 
 static void
+weston_wm_window_configure(void *data);
+
+static void
 weston_wm_window_schedule_repaint(struct weston_wm_window *window);
 
 static void
@@ -356,6 +366,7 @@ weston_wm_window_read_properties(struct weston_wm_window 
*window)
                { wm->atom.net_wm_window_type, XCB_ATOM_ATOM, F(type) },
                { wm->atom.net_wm_name, XCB_ATOM_STRING, F(name) },
                { wm->atom.net_wm_pid, XCB_ATOM_CARDINAL, F(pid) },
+               { wm->atom.net_wm_sync_request_counter, XCB_SYNC_COUNTER, 
F(sync_request_counter) },
                { wm->atom.motif_wm_hints, TYPE_MOTIF_WM_HINTS, 0 },
                { wm->atom.wm_client_machine, XCB_ATOM_WM_CLIENT_MACHINE, 
F(machine) },
        };
@@ -366,6 +377,7 @@ weston_wm_window_read_properties(struct weston_wm_window 
*window)
        void *p;
        uint32_t *xid;
        xcb_atom_t *atom;
+       xcb_sync_counter_t *counter;
        uint32_t i;
        struct motif_wm_hints *hints;
 
@@ -416,6 +428,10 @@ weston_wm_window_read_properties(struct weston_wm_window 
*window)
                        atom = xcb_get_property_value(reply);
                        *(xcb_atom_t *) p = *atom;
                        break;
+               case XCB_SYNC_COUNTER:
+                       counter = xcb_get_property_value(reply);
+                       *(xcb_sync_counter_t *) p = *counter;
+                       break;
                case TYPE_WM_PROTOCOLS:
                        break;
                case TYPE_NET_WM_STATE:
@@ -731,6 +747,93 @@ weston_wm_window_set_net_wm_state(struct weston_wm_window 
*window)
 }
 
 static void
+weston_wm_window_create_sync_alarm(struct weston_wm_window *window)
+{
+       struct weston_wm *wm = window->wm;
+       xcb_sync_int64_t value;
+       uint32_t mask;
+       xcb_sync_create_alarm_value_list_t value_list;
+
+       if (window->sync_request_counter == 0) {
+               weston_log("NET_WM_SYNC_REQUEST isn't supported by the 
client\n");
+               return;
+       }
+
+       if (window->sync_request_alarm != 0) {
+               weston_log("Sync request alarm has already been created\n");
+               return;
+       }
+
+       value.hi = 0;
+       value.lo = 0;
+       window->sync_request_serial = 0;
+       xcb_sync_set_counter(wm->conn, window->sync_request_counter, value);
+
+       mask = (XCB_SYNC_CA_COUNTER | XCB_SYNC_CA_VALUE_TYPE |
+               XCB_SYNC_CA_VALUE | XCB_SYNC_CA_TEST_TYPE |
+               XCB_SYNC_CA_DELTA | XCB_SYNC_CA_EVENTS);
+       value_list.counter = window->sync_request_counter;
+       value_list.valueType = XCB_SYNC_VALUETYPE_ABSOLUTE;
+       value_list.value.hi = 0;
+       value_list.value.lo = 1;
+       value_list.testType = XCB_SYNC_TESTTYPE_POSITIVE_COMPARISON;
+       value_list.delta.hi = 0;
+       value_list.delta.lo = 1;
+       value_list.events = 1;
+
+       window->sync_request_alarm = xcb_generate_id(wm->conn);
+       xcb_sync_create_alarm_aux(wm->conn, window->sync_request_alarm, mask, 
&value_list);
+
+       hash_table_insert(wm->alarm_hash, window->sync_request_alarm, window);
+}
+
+static int
+sync_request_timeout(void *data)
+{
+       struct weston_wm_window *window = data;
+       struct weston_wm *wm = window->wm;
+
+       wl_event_source_timer_update(window->sync_request_timer, 0);
+
+       weston_log("Sync request timed out. Temporarily disabling syncing.\n");
+       window->sync_disabled = 1;
+       window->wait_redraw = 0;
+
+       if (window->configure_pending && !window->configure_source) {
+               window->configure_source =
+                       wl_event_loop_add_idle(wm->server->loop,
+                                              weston_wm_window_configure, 
window);
+       }
+
+       return 0;
+}
+
+static void
+weston_wm_window_send_sync_request(struct weston_wm_window *window)
+{
+       xcb_client_message_event_t client_message;
+       struct weston_wm *wm = window->wm;
+
+       window->sync_request_serial++;
+
+       client_message.response_type = XCB_CLIENT_MESSAGE;
+       client_message.format = 32;
+       client_message.window = window->id;
+       client_message.type = wm->atom.wm_protocols;
+       client_message.data.data32[0] = wm->atom.net_wm_sync_request;
+       client_message.data.data32[1] = XCB_TIME_CURRENT_TIME;
+       client_message.data.data32[2] = window->sync_request_serial & 
0xffffffff;
+       client_message.data.data32[3] = (window->sync_request_serial >> 32) & 
0xffffffff;
+
+       weston_log("SEND SYNC REQUEST %llu\n", window->sync_request_serial);
+
+       xcb_send_event(wm->conn, 0, window->id, 0,
+                      (char *) &client_message);
+
+       wl_event_source_timer_update(window->sync_request_timer, 1000);
+}
+
+static void
 weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event)
 {
        xcb_map_request_event_t *map_request =
@@ -805,6 +908,16 @@ weston_wm_handle_map_request(struct weston_wm *wm, 
xcb_generic_event_t *event)
                                                             width, height);
 
        hash_table_insert(wm->window_hash, window->frame_id, window);
+
+       if (window->sync_request_counter != 0) {
+               window->sync_request_timer =
+                       wl_event_loop_add_timer(wm->server->loop,
+                                               sync_request_timeout,
+                                               window);
+               weston_wm_window_create_sync_alarm(window);
+               weston_wm_window_send_sync_request(window);
+               weston_wm_window_send_configure_notify(window);
+       }
 }
 
 static void
@@ -863,6 +976,13 @@ weston_wm_handle_unmap_notify(struct weston_wm *wm, 
xcb_generic_event_t *event)
                window->frame_id = XCB_WINDOW_NONE;
        }
 
+       if (window->sync_request_alarm) {
+               xcb_sync_destroy_alarm(wm->conn, window->sync_request_alarm);
+               hash_table_remove(wm->alarm_hash, window->sync_request_alarm);
+       }
+       if (window->sync_request_timer)
+               wl_event_source_remove(window->sync_request_timer);
+
        if (wm->focus_window == window)
                wm->focus_window = NULL;
        if (window->surface)
@@ -1026,6 +1146,11 @@ weston_wm_window_create(struct weston_wm *wm,
        window->surface = NULL;
        window->map_notified = 0;
        window->mapped = 0;
+       window->sync_request_counter = 0;
+       window->sync_request_alarm = 0;
+       window->configure_pending = 0;
+       window->sync_disabled = 0;
+       window->wait_redraw = 0;
 
        geometry_reply = xcb_get_geometry_reply(wm->conn, geometry_cookie, 
NULL);
        /* technically we should use XRender and check the visual format's
@@ -1187,9 +1312,6 @@ update_state(int action, int *state)
 }
 
 static void
-weston_wm_window_configure(void *data);
-
-static void
 weston_wm_window_handle_state(struct weston_wm_window *window,
                              xcb_client_message_event_t *client_message)
 {
@@ -1246,6 +1368,38 @@ weston_wm_handle_client_message(struct weston_wm *wm,
                weston_wm_window_handle_state(window, client_message);
 }
 
+static void
+weston_wm_handle_sync_alarm_notify(struct weston_wm *wm,
+                                  xcb_generic_event_t *event)
+{
+       xcb_sync_alarm_notify_event_t *alarm_event =
+               (xcb_sync_alarm_notify_event_t *) event;
+       struct weston_wm_window *window;
+       int64_t counter_value = 0;
+
+       counter_value = alarm_event->counter_value.lo;
+       counter_value += (int64_t) alarm_event->counter_value.hi << 32;
+
+       weston_log("XCB_SYNC_ALARM_NOTIFY %llu\n", counter_value);
+
+       window = hash_table_lookup(wm->alarm_hash, alarm_event->alarm);
+
+       if (!window) {
+               weston_log("Alarm doesn't match a window\n");
+               return;
+       }
+
+       wl_event_source_timer_update(window->sync_request_timer, 0);
+       window->sync_disabled = 0;
+       window->wait_redraw = 0;
+
+       if (window->configure_pending && !window->configure_source) {
+               window->configure_source =
+                       wl_event_loop_add_idle(wm->server->loop,
+                                              weston_wm_window_configure, 
window);
+       }
+}
+
 enum cursor_type {
        XWM_CURSOR_TOP,
        XWM_CURSOR_BOTTOM,
@@ -1437,6 +1591,16 @@ weston_wm_handle_leave(struct weston_wm *wm, 
xcb_generic_event_t *event)
        weston_wm_window_set_cursor(wm, window->frame_id, XWM_CURSOR_LEFT_PTR);
 }
 
+static void
+weston_wm_handle_error(xcb_generic_error_t *error)
+{
+       weston_log("XCB ERROR type=%d, error=%d, major=%d, minor=%d\n",
+                  error->response_type,
+                  error->error_code,
+                  error->major_code,
+                  error->minor_code);
+}
+
 static int
 weston_wm_handle_event(int fd, uint32_t mask, void *data)
 {
@@ -1452,6 +1616,9 @@ weston_wm_handle_event(int fd, uint32_t mask, void *data)
                }
 
                switch (EVENT_TYPE(event)) {
+               case 0:
+                       weston_wm_handle_error((xcb_generic_error_t *) event);
+                       break;
                case XCB_BUTTON_PRESS:
                case XCB_BUTTON_RELEASE:
                        weston_wm_handle_button(wm, event);
@@ -1500,6 +1667,12 @@ weston_wm_handle_event(int fd, uint32_t mask, void *data)
                        break;
                }
 
+               if (wm->sync) {
+                       uint8_t base = wm->sync->first_event;
+                       if (EVENT_TYPE(event) == base + XCB_SYNC_ALARM_NOTIFY)
+                               weston_wm_handle_sync_alarm_notify(wm, event);
+               }
+
                free(event);
                count++;
        }
@@ -1576,6 +1749,9 @@ weston_wm_get_resources(struct weston_wm *wm)
                { "_NET_WM_WINDOW_TYPE_DND", F(atom.net_wm_window_type_dnd) },
                { "_NET_WM_WINDOW_TYPE_NORMAL", 
F(atom.net_wm_window_type_normal) },
 
+               { "_NET_WM_SYNC_REQUEST", F(atom.net_wm_sync_request) },
+               { "_NET_WM_SYNC_REQUEST_COUNTER", 
F(atom.net_wm_sync_request_counter) },
+
                { "_NET_WM_MOVERESIZE", F(atom.net_wm_moveresize) },
                { "_NET_SUPPORTING_WM_CHECK",
                                        F(atom.net_supporting_wm_check) },
@@ -1600,6 +1776,8 @@ weston_wm_get_resources(struct weston_wm *wm)
 
        xcb_xfixes_query_version_cookie_t xfixes_cookie;
        xcb_xfixes_query_version_reply_t *xfixes_reply;
+       xcb_sync_initialize_cookie_t sync_cookie;
+       xcb_sync_initialize_reply_t *sync_reply;
        xcb_intern_atom_cookie_t cookies[ARRAY_LENGTH(atoms)];
        xcb_intern_atom_reply_t *reply;
        xcb_render_query_pict_formats_reply_t *formats_reply;
@@ -1607,6 +1785,7 @@ weston_wm_get_resources(struct weston_wm *wm)
        xcb_render_pictforminfo_t *formats;
        uint32_t i;
 
+       xcb_prefetch_extension_data (wm->conn, &xcb_sync_id);
        xcb_prefetch_extension_data (wm->conn, &xcb_xfixes_id);
 
        formats_cookie = xcb_render_query_pict_formats(wm->conn);
@@ -1622,6 +1801,22 @@ weston_wm_get_resources(struct weston_wm *wm)
                free(reply);
        }
 
+       wm->sync = xcb_get_extension_data(wm->conn, &xcb_sync_id);
+       if (!wm->sync || !wm->sync->present) {
+               weston_log("sync not available\n");
+       } else {
+               sync_cookie = xcb_sync_initialize(wm->conn,
+                                                 XCB_SYNC_MAJOR_VERSION,
+                                                 XCB_SYNC_MINOR_VERSION);
+               sync_reply = xcb_sync_initialize_reply(wm->conn,
+                                                      sync_cookie, NULL);
+
+               weston_log("sync version: %d.%d\n",
+                      sync_reply->major_version, sync_reply->minor_version);
+
+               free(sync_reply);
+       }
+
        wm->xfixes = xcb_get_extension_data(wm->conn, &xcb_xfixes_id);
        if (!wm->xfixes || !wm->xfixes->present)
                weston_log("xfixes not available\n");
@@ -1717,7 +1912,7 @@ weston_wm_create(struct weston_xserver *wxs)
        xcb_screen_iterator_t s;
        uint32_t values[1];
        int sv[2];
-       xcb_atom_t supported[3];
+       xcb_atom_t supported[5];
 
        wm = malloc(sizeof *wm);
        if (wm == NULL)
@@ -1731,8 +1926,16 @@ weston_wm_create(struct weston_xserver *wxs)
                return NULL;
        }
 
+       wm->alarm_hash = hash_table_create();
+       if (wm->alarm_hash == NULL) {
+               hash_table_destroy(wm->window_hash);
+               free(wm);
+               return NULL;
+       }
+
        if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
                weston_log("socketpair failed\n");
+               hash_table_destroy(wm->alarm_hash);
                hash_table_destroy(wm->window_hash);
                free(wm);
                return NULL;
@@ -1747,6 +1950,7 @@ weston_wm_create(struct weston_xserver *wxs)
        if (xcb_connection_has_error(wm->conn)) {
                weston_log("xcb_connect_to_fd failed\n");
                close(sv[0]);
+               hash_table_destroy(wm->alarm_hash);
                hash_table_destroy(wm->window_hash);
                free(wm);
                return NULL;
@@ -1778,6 +1982,8 @@ weston_wm_create(struct weston_xserver *wxs)
        supported[0] = wm->atom.net_wm_moveresize;
        supported[1] = wm->atom.net_wm_state;
        supported[2] = wm->atom.net_wm_state_fullscreen;
+       supported[3] = wm->atom.net_wm_sync_request;
+       supported[4] = wm->atom.net_wm_sync_request_counter;
        xcb_change_property(wm->conn,
                            XCB_PROP_MODE_REPLACE,
                            wm->screen->root,
@@ -1855,6 +2061,11 @@ weston_wm_window_configure(void *data)
        uint32_t values[4];
        int x, y, width, height;
 
+       if (window->sync_request_counter != 0 && !window->sync_disabled) {
+               window->wait_redraw = 1;
+               weston_wm_window_send_sync_request(window);
+       }
+
        weston_wm_window_get_child_position(window, &x, &y);
        values[0] = x;
        values[1] = y;
@@ -1877,6 +2088,7 @@ weston_wm_window_configure(void *data)
                             XCB_CONFIG_WINDOW_HEIGHT,
                             values);
 
+       window->configure_pending = 0;
        window->configure_source = NULL;
 
        weston_wm_window_schedule_repaint(window);
@@ -1915,9 +2127,14 @@ send_configure(struct weston_surface *surface,
        if (window->configure_source)
                return;
 
-       window->configure_source =
-               wl_event_loop_add_idle(wm->server->loop,
-                                      weston_wm_window_configure, window);
+       if (window->wait_redraw) {
+               weston_log("WAIT FOR REDRAW\n");
+               window->configure_pending = 1;
+       } else {
+               window->configure_source =
+                       wl_event_loop_add_idle(wm->server->loop,
+                                              weston_wm_window_configure, 
window);
+       }
 }
 
 static const struct weston_shell_client shell_client = {
diff --git a/src/xwayland/xwayland.h b/src/xwayland/xwayland.h
index c68a517..c609cf2 100644
--- a/src/xwayland/xwayland.h
+++ b/src/xwayland/xwayland.h
@@ -22,6 +22,7 @@
 
 #include <wayland-server.h>
 #include <xcb/xcb.h>
+#include <xcb/sync.h>
 #include <xcb/xfixes.h>
 #include <cairo/cairo-xcb.h>
 
@@ -46,9 +47,11 @@ struct weston_xserver {
 
 struct weston_wm {
        xcb_connection_t *conn;
+       const xcb_query_extension_reply_t *sync;
        const xcb_query_extension_reply_t *xfixes;
        struct wl_event_source *source;
        xcb_screen_t *screen;
+       struct hash_table *alarm_hash;
        struct hash_table *window_hash;
        struct weston_xserver *server;
        xcb_window_t wm_window;
@@ -108,6 +111,8 @@ struct weston_wm {
                xcb_atom_t               net_wm_window_type_dnd;
                xcb_atom_t               net_wm_window_type_normal;
                xcb_atom_t               net_wm_moveresize;
+               xcb_atom_t               net_wm_sync_request;
+               xcb_atom_t               net_wm_sync_request_counter;
                xcb_atom_t               net_supporting_wm_check;
                xcb_atom_t               net_supported;
                xcb_atom_t               motif_wm_hints;
-- 
1.8.3.1

_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to