From 70c0d39fa703daff5d5b3fd677dae6495dedf624 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Wed, 8 Jun 2011 13:58:54 -0400 Subject: [PATCH] Add support for an extended style of _NET_WM_SYNC_REQUEST_COUNTER If an application provides two values in _NET_WM_SYNC_REQUEST_COUNTER, use that as a signal that the applications wants an extended behavior where it can update the counter as well as the window manager. If the application updates the counter to an odd value, updates of the window are frozen until the counter is updated again to an even value. https://bugzilla.gnome.org/show_bug.cgi?id=685463 --- src/core/display-private.h | 3 ++ src/core/display.c | 2 +- src/core/window-private.h | 8 +++-- src/core/window-props.c | 28 ++++++++++++--- src/core/window.c | 71 +++++++++++++++++++++++++++++--------- 5 files changed, 88 insertions(+), 24 deletions(-) diff --git a/src/core/display-private.h b/src/core/display-private.h index 75351129d..99984e14a 100644 --- a/src/core/display-private.h +++ b/src/core/display-private.h @@ -222,6 +222,9 @@ struct _MetaDisplay #ifdef HAVE_XKB int xkb_base_event_type; guint32 last_bell_time; +#endif +#ifdef HAVE_XSYNC + gint64 grab_sync_counter_wait_serial; #endif int grab_resize_timeout_id; diff --git a/src/core/display.c b/src/core/display.c index dd45633b9..da735fdce 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -1958,7 +1958,7 @@ event_callback (XEvent *event, if (alarm_window != NULL) { XSyncValue value = ((XSyncAlarmNotifyEvent*)event)->counter_value; - guint64 new_counter_value; + gint64 new_counter_value; new_counter_value = XSyncValueLow32 (value) + ((gint64)XSyncValueHigh32 (value) << 32); meta_window_update_sync_request_counter (alarm_window, new_counter_value); filter_out_event = TRUE; /* GTK doesn't want to see this really */ diff --git a/src/core/window-private.h b/src/core/window-private.h index 00f1c7a10..04ee11046 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -352,13 +352,17 @@ struct _MetaWindow /* if non-NULL, the opaque region _NET_WM_OPAQUE_REGION */ cairo_region_t *opaque_region; + /* if TRUE, the we have the new form of sync request counter which + * also handles application frames */ + guint extended_sync_request_counter : 1; + /* Note: can be NULL */ GSList *struts; #ifdef HAVE_XSYNC /* XSync update counter */ XSyncCounter sync_request_counter; - guint sync_request_serial; + gint64 sync_request_serial; GTimeVal sync_request_time; /* alarm monitoring client's _NET_WM_SYNC_REQUEST_COUNTER */ XSyncAlarm sync_request_alarm; @@ -607,7 +611,7 @@ void meta_window_set_gravity (MetaWindow *window, #ifdef HAVE_XSYNC void meta_window_update_sync_request_counter (MetaWindow *window, - guint64 new_counter_value); + gint64 new_counter_value); #endif /* HAVE_XSYNC */ void meta_window_handle_mouse_grab_op_event (MetaWindow *window, diff --git a/src/core/window-props.c b/src/core/window-props.c index 1637c2d63..5e7eb8f54 100644 --- a/src/core/window-props.c +++ b/src/core/window-props.c @@ -921,13 +921,31 @@ reload_update_counter (MetaWindow *window, if (value->type != META_PROP_VALUE_INVALID) { meta_window_destroy_sync_request_alarm (window); + window->sync_request_counter = None; #ifdef HAVE_XSYNC - XSyncCounter counter = value->v.xcounter; + if (value->v.xcounter_list.n_counters == 0) + { + meta_warning ("_NET_WM_SYNC_REQUEST_COUNTER is empty\n"); + return; + } - window->sync_request_counter = counter; - meta_verbose ("Window has _NET_WM_SYNC_REQUEST_COUNTER 0x%lx\n", - window->sync_request_counter); + if (value->v.xcounter_list.n_counters == 1) + { + window->sync_request_counter = value->v.xcounter_list.counters[0]; + window->extended_sync_request_counter = FALSE; + } + else + { + window->sync_request_counter = value->v.xcounter_list.counters[1]; + window->extended_sync_request_counter = TRUE; + } + meta_verbose ("Window has _NET_WM_SYNC_REQUEST_COUNTER 0x%lx (extended=%s)\n", + window->sync_request_counter, + window->extended_sync_request_counter ? "true" : "false"); + + if (window->extended_sync_request_counter) + meta_window_create_sync_request_alarm (window); #endif } } @@ -1721,7 +1739,7 @@ meta_display_init_window_prop_hooks (MetaDisplay *display) { XA_WM_ICON_NAME, META_PROP_VALUE_TEXT_PROPERTY, reload_wm_icon_name, TRUE, FALSE }, { display->atom__NET_WM_DESKTOP, META_PROP_VALUE_CARDINAL, reload_net_wm_desktop, TRUE, FALSE }, { display->atom__NET_STARTUP_ID, META_PROP_VALUE_UTF8, reload_net_startup_id, TRUE, FALSE }, - { display->atom__NET_WM_SYNC_REQUEST_COUNTER, META_PROP_VALUE_SYNC_COUNTER, reload_update_counter, TRUE, FALSE }, + { display->atom__NET_WM_SYNC_REQUEST_COUNTER, META_PROP_VALUE_SYNC_COUNTER_LIST, reload_update_counter, TRUE, TRUE }, { XA_WM_NORMAL_HINTS, META_PROP_VALUE_SIZE_HINTS, reload_normal_hints, TRUE, FALSE }, { display->atom_WM_PROTOCOLS, META_PROP_VALUE_ATOM_LIST, reload_wm_protocols, TRUE, FALSE }, { XA_WM_HINTS, META_PROP_VALUE_WM_HINTS, reload_wm_hints, TRUE, FALSE }, diff --git a/src/core/window.c b/src/core/window.c index af7cdb085..5bf8f050b 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -4453,17 +4453,38 @@ meta_window_create_sync_request_alarm (MetaWindow *window) meta_error_trap_push_with_return (window->display); - /* Set the counter to 0, so we know that the application's - * responses to the client messages will always trigger - * a PositiveTransition + /* In the new (extended style), the counter value is initialized by + * the client before mapping the window. In the old style, we're + * responsible for setting the initial value of the counter. */ - XSyncIntToValue (&init, 0); - XSyncSetCounter (window->display->xdisplay, - window->sync_request_counter, init); - window->sync_request_serial = 0; + if (window->extended_sync_request_counter) + { + if (!XSyncQueryCounter(window->display->xdisplay, + window->sync_request_counter, + &init)) + { + meta_error_trap_pop_with_return (window->display); + window->sync_request_counter = None; + return; + } + + window->sync_request_serial = + XSyncValueLow32 (init) + ((gint64)XSyncValueHigh32 (init) << 32); + + /* if the value is odd, the window starts off with updates frozen */ + meta_compositor_set_updates_frozen (window->display->compositor, window, + meta_window_updates_are_frozen (window)); + } + else + { + XSyncIntToValue (&init, 0); + XSyncSetCounter (window->display->xdisplay, + window->sync_request_counter, init); + window->sync_request_serial = 0; + } values.trigger.counter = window->sync_request_counter; - values.trigger.test_type = XSyncPositiveTransition; + values.trigger.test_type = XSyncPositiveComparison; /* Initialize to one greater than the current value */ values.trigger.value_type = XSyncRelative; @@ -4514,12 +4535,19 @@ meta_window_destroy_sync_request_alarm (MetaWindow *window) static void send_sync_request (MetaWindow *window) { - XSyncValue value; XClientMessageEvent ev; + gint64 wait_serial; - window->sync_request_serial++; + /* For the old style of _NET_WM_SYNC_REQUEST_COUNTER, we just have to + * increase the value, but for the new "extended" style we need to + * pick an even (unfrozen) value sufficiently ahead of the last serial + * that we received from the client; the same code still works + * for the old style. The increment of 240 is specified by the EWMH + * and is (1 second) * (60fps) * (an increment of 4 per frame). + */ + wait_serial = window->sync_request_serial + 240; - XSyncIntToValue (&value, window->sync_request_serial); + window->display->grab_sync_counter_wait_serial = wait_serial; ev.type = ClientMessage; ev.window = window->xwindow; @@ -4532,8 +4560,9 @@ send_sync_request (MetaWindow *window) * want to use _roundtrip, though? */ ev.data.l[1] = meta_display_get_current_time (window->display); - ev.data.l[2] = XSyncValueLow32 (value); - ev.data.l[3] = XSyncValueHigh32 (value); + ev.data.l[2] = wait_serial & G_GUINT64_CONSTANT(0xffffffff); + ev.data.l[3] = wait_serial >> 32; + ev.data.l[4] = window->extended_sync_request_counter ? 1 : 0; /* We don't need to trap errors here as we are already * inside an error_trap_push()/pop() pair. @@ -4560,6 +4589,12 @@ send_sync_request (MetaWindow *window) gboolean meta_window_updates_are_frozen (MetaWindow *window) { +#ifdef HAVE_XSYNC + if (window->extended_sync_request_counter && + window->sync_request_serial % 2 == 1) + return TRUE; +#endif + return window->updates_frozen_for_resize; } @@ -9456,13 +9491,17 @@ update_tile_mode (MetaWindow *window) #ifdef HAVE_XSYNC void meta_window_update_sync_request_counter (MetaWindow *window, - guint64 new_counter_value) + gint64 new_counter_value) { + window->sync_request_serial = new_counter_value; + meta_compositor_set_updates_frozen (window->display->compositor, window, + meta_window_updates_are_frozen (window)); + if (window->display->grab_op != META_GRAB_OP_NONE && window == window->display->grab_window && - meta_grab_op_is_mouse (window->display->grab_op)) + meta_grab_op_is_mouse (window->display->grab_op) && + new_counter_value >= window->display->grab_sync_counter_wait_serial) { - meta_topic (META_DEBUG_RESIZING, "Alarm event received last motion x = %d y = %d\n", window->display->grab_latest_motion_x,