Compare commits

...

15 Commits

Author SHA1 Message Date
d317c1c7e8 Consistently use meta_grab_op_is_resizing() for _NET_WM_SYNC_REQUEST
In different places we checked the grab op differently when determing
whether we are using _NET_WM_SYNC_REQUEST. This was somewhat covered
up previously by the fact that we only had a sync alarm when using
_NET_WM_SYNC_REQUEST, but that is no longer the case, so consistently
use meta_grab_op_is_resizing() everywhere.
2013-01-30 15:47:52 -05:00
cf72589635 Distinguish "no delay" frames from spontaneous drawing
When a client is drawing as hard as possible (without sleeping
between frames) we need to draw as soon possible, since sleeping
will decrease the effective frame rate shown to the user, and
can also result in the system never kicking out of power-saving
mode because it doesn't look fully utilized.

Use the amount the client increments the counter value by when
ending the frame to distinguish these cases:

 - Increment by 1: a no-delay frame
 - Increment by more than 1: a non-urgent frame, handle normally

https://bugzilla.gnome.org/show_bug.cgi?id=685463
2013-01-30 15:47:52 -05:00
3ae070720d Send _NET_WM_FRAME_TIMINGS messages
We previously had timestamp information stubbed out in
_NET_WM_FRAME_DRAWN. Instead of this, add a high-resolution timestamp
in _NET_WM_FRAME_DRAWN then send a _NET_WM_FRAME_TIMINGS message
after when we have complete frame timing information, representing
the "presentation time" of the frame as an offset from the timestamp
in _NET_WM_FRAME_DRAWN.

To provide maximum space in the messages,_NET_WM_FRAME_DRAWN and
_NET_WM_FRAME_TIMINGS are not done as WM_PROTOCOLS messages but
have their own message types.

https://bugzilla.gnome.org/show_bug.cgi?id=685463
2013-01-30 15:47:52 -05:00
4b332640eb Add meta_compositor_monotonic_time_to_server_time()
Add a function to convert from g_get_monotonic_time() to a
"high-resolution server timestamp" with microsecond precision.
These timestamps will be used when communicating frame timing
information to the client.

https://bugzilla.gnome.org/show_bug.cgi?id=685463
2013-01-30 15:47:52 -05:00
0d36f4f1dd Use XSyncSetPriority()
Use XSyncSetPriority() to prioritize the compositor above applications
for X server priority. In practice, this makes little difference because
the Xorg "smart scheduler" will schedule in a single application for
time slices that exceed the frame drawing time, but it's theoretically
right and might make a difference if the X server scheduler is improved.

https://bugzilla.gnome.org/show_bug.cgi?id=685463
2013-01-30 15:47:52 -05:00
0c2491e3c9 Use clutter_stage_set_sync_delay()
Using a "sync delay" where we wait for 2 ms after the vblank before
starting to draw the next frame provides for much more predictable
latency for applications. An application can know that if it completes
a frame any time between 8ms before the vblank to the vblank,
it will reliably be drawn on the following vblank period, rather than
having an unpredictable latency depending on whether the compositor
is currently busy drawing a frame or not.

https://bugzilla.gnome.org/show_bug.cgi?id=685463
2013-01-30 15:47:52 -05:00
6de7f4ce36 Enable CLUTTER / COGL_ENABLE_EXPERIMENTAL_API globally
Instead of defining CLUTTER_ENABLE_EXPERIMENTAL_API and
COGL_ENABLE_EXPERIMENTAL_API in individual source files, enable
them on the command line. We weren't tracking exactly what pieces of
experimental API we were using and we were using the experimental
API in most source files that used Clutter and Cogl, so the
local #defines were annoying rather than useful.

https://bugzilla.gnome.org/show_bug.cgi?id=685463
2013-01-30 15:47:52 -05:00
5f77669ba8 Handle _NET_WM_SYNC_REQUEST_COUNTER updates without redraw
It's possible that a client might update the (extended)
_NET_WM_SYNC_REQUEST_COUNTER counter twice without actually drawing
anything. In that case, we still should send a _NET_WM_FRAME_DRAWN
message since it's hard for a client to know every case in which
no damage is generated. For now, do it the easy way by forcing a
stage repaint.

https://bugzilla.gnome.org/show_bug.cgi?id=685463
2013-01-30 15:47:52 -05:00
7a9663500e MetaWindow: always resize the frame first when we have synchronization
Resizing the frame triggers creation of a new backing pixmap for the
window, so we should do that first before we resize the client window
and mess up the contents of the old backing pixmap.

https://bugzilla.gnome.org/show_bug.cgi?id=685463
2013-01-30 15:47:52 -05:00
4f79c70002 Send _NET_WM_FRAME_DRAWN messages
When the application provides the extended second counter for
_NET_WM_SYNC_REQUEST, send a client message with completion
information after the next redraw after each counter update
by the application.

https://bugzilla.gnome.org/show_bug.cgi?id=685463
2013-01-30 15:47:52 -05:00
81c42a8944 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
2013-01-30 15:47:52 -05:00
8d9c83ddcf Support properties with lists of XSyncCounter
Add META_PROP_VALUE_SYNC_COUNTER_LIST for a property that contains
multiple XSyncCounter values.

https://bugzilla.gnome.org/show_bug.cgi?id=685463
2013-01-30 15:47:52 -05:00
5b6020e90d Move sync alarms to be per-window and permanent
Instead of creating a new alarm each time we resize a window
interactively, create an alarm the first time we resize a window
and keep it around permanently until we unmanage the window.
Doing it this way will be useful when we allow the application to
spontaneously generate sync request updates to indicate
frames it is drawing.

https://bugzilla.gnome.org/show_bug.cgi?id=685463
2013-01-30 15:47:52 -05:00
8b57ecebda Implement freezing of updates during resize
Replace the unused meta_compositor_set_updates() with
a reversed-meaning meta_compositor_set_updates_frozen(), and use
it to implement freezing application window updates during
interactive resizing. This avoids drawing new areas of the window
with blank content before the application has a chance to repaint.

https://bugzilla.gnome.org/show_bug.cgi?id=685463
2013-01-30 15:47:51 -05:00
f6c3e48aa5 MetaWindowActor: Use guint for bitfields
A 1-bit boolean (int) bitfield has the values 0 and -1. Use
guint instead for bitfield values.

https://bugzilla.gnome.org/show_bug.cgi?id=685463
2013-01-30 15:47:51 -05:00
17 changed files with 721 additions and 163 deletions

View File

@ -6,6 +6,8 @@ lib_LTLIBRARIES = libmutter.la
SUBDIRS=wm-tester tools compositor/plugins
INCLUDES= \
-DCLUTTER_ENABLE_EXPERIMENTAL_API \
-DCOGL_ENABLE_EXPERIMENTAL_API \
$(MUTTER_CFLAGS) \
-I$(srcdir) \
-I$(srcdir)/core \

View File

@ -25,9 +25,13 @@ struct _MetaCompositor
MetaPlugin *modal_plugin;
gboolean show_redraw : 1;
gboolean debug : 1;
gboolean no_mipmaps : 1;
gint64 server_time_query_time;
gint64 server_time_offset;
guint server_time_is_monotonic_time : 1;
guint show_redraw : 1;
guint debug : 1;
guint no_mipmaps : 1;
};
struct _MetaCompScreen
@ -41,6 +45,9 @@ struct _MetaCompScreen
GHashTable *windows_by_xid;
Window output;
CoglOnscreen *onscreen;
CoglFrameClosure *frame_closure;
/* Used for unredirecting fullscreen windows */
guint disable_unredirect_count;
MetaWindowActor *unredirected_window;
@ -53,6 +60,8 @@ struct _MetaCompScreen
MetaPluginManager *plugin_mgr;
};
#define META_SYNC_DELAY 2
void meta_switch_workspace_completed (MetaScreen *screen);
gboolean meta_begin_modal_for_plugin (MetaScreen *screen,
@ -65,6 +74,9 @@ void meta_end_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
guint32 timestamp);
gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
gint64 monotonic_time);
void meta_check_end_modal (MetaScreen *screen);
#endif /* META_COMPOSITOR_PRIVATE_H */

View File

@ -467,6 +467,16 @@ meta_check_end_modal (MetaScreen *screen)
}
}
static void
after_stage_paint (ClutterActor *stage,
MetaCompScreen *info)
{
GList *l;
for (l = info->windows; l; l = l->next)
meta_window_actor_post_paint (l->data);
}
void
meta_compositor_manage_screen (MetaCompositor *compositor,
MetaScreen *screen)
@ -536,6 +546,11 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
meta_screen_set_cm_selection (screen);
info->stage = clutter_stage_new ();
g_signal_connect_after (info->stage, "paint",
G_CALLBACK (after_stage_paint), info);
/* Wait 6-ms after vblank before starting to draw next frame */
clutter_stage_set_sync_delay (CLUTTER_STAGE (info->stage), META_SYNC_DELAY);
meta_screen_get_size (screen, &width, &height);
clutter_actor_realize (info->stage);
@ -716,10 +731,18 @@ meta_compositor_remove_window (MetaCompositor *compositor,
}
void
meta_compositor_set_updates (MetaCompositor *compositor,
MetaWindow *window,
gboolean updates)
meta_compositor_set_updates_frozen (MetaCompositor *compositor,
MetaWindow *window,
gboolean updates_frozen)
{
MetaWindowActor *window_actor;
DEBUG_TRACE ("meta_compositor_set_updates_frozen\n");
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
if (!window_actor)
return;
meta_window_actor_set_updates_frozen (window_actor, updates_frozen);
}
static gboolean
@ -1182,6 +1205,39 @@ meta_compositor_sync_screen_size (MetaCompositor *compositor,
width, height);
}
static void
frame_callback (CoglOnscreen *onscreen,
CoglFrameEvent event,
CoglFrameInfo *frame_info,
void *user_data)
{
MetaCompScreen *info = user_data;
GList *l;
if (event == COGL_FRAME_EVENT_COMPLETE)
{
gint64 presentation_time_cogl = cogl_frame_info_get_presentation_time (frame_info);
gint64 presentation_time;
if (presentation_time_cogl != 0)
{
CoglContext *context = cogl_framebuffer_get_context (COGL_FRAMEBUFFER (onscreen));
gint64 current_time_cogl = cogl_get_clock_time (context);
gint64 now = g_get_monotonic_time ();
presentation_time =
now + (presentation_time_cogl - current_time_cogl) / 1000;
}
else
{
presentation_time = 0;
}
for (l = info->windows; l; l = l->next)
meta_window_actor_frame_complete (l->data, frame_info, presentation_time);
}
}
static void
pre_paint_windows (MetaCompScreen *info)
{
@ -1189,6 +1245,15 @@ pre_paint_windows (MetaCompScreen *info)
MetaWindowActor *top_window;
MetaWindowActor *expected_unredirected_window = NULL;
if (info->onscreen == NULL)
{
info->onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer ());
info->frame_closure = cogl_onscreen_add_frame_callback (info->onscreen,
frame_callback,
info,
NULL);
}
if (info->windows == NULL)
return;
@ -1391,3 +1456,51 @@ meta_compositor_flash_screen (MetaCompositor *compositor,
"signal-after::completed", flash_in_completed, flash,
NULL);
}
/**
* meta_compositor_monotonic_time_to_server_time:
* @display: a #MetaDisplay
* @monotonic_time: time in the units of g_get_monotonic_time()
*
* _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages represent time
* as a "high resolution server time" - this is the server time interpolated
* to microsecond resolution. The advantage of this time representation
* is that if X server is running on the same computer as a client, and
* the Xserver uses 'clock_gettime(CLOCK_MONOTONIC, ...)' for the server
* time, the client can detect this, and all such clients will share a
* a time representation with high accuracy. If there is not a common
* time source, then the time synchronization will be less accurate.
*/
gint64
meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
gint64 monotonic_time)
{
MetaCompositor *compositor = display->compositor;
if (compositor->server_time_query_time == 0 ||
(!compositor->server_time_is_monotonic_time &&
monotonic_time > compositor->server_time_query_time + 10000000)) /* 10 seconds */
{
guint32 server_time = meta_display_get_current_time_roundtrip (display);
gint64 server_time_usec = (gint64)server_time * 1000;
gint64 current_monotonic_time = g_get_monotonic_time ();
compositor->server_time_query_time = current_monotonic_time;
/* If the server time is within a second of the monotonic time,
* we assume that they are identical. This seems like a big margin,
* but we want to be as robust as possible even if the system
* is under load and our processing of the server response is
* delayed.
*/
if (server_time_usec > current_monotonic_time - 1000000 &&
server_time_usec < current_monotonic_time + 1000000)
compositor->server_time_is_monotonic_time = TRUE;
compositor->server_time_offset = server_time_usec - current_monotonic_time;
}
if (compositor->server_time_is_monotonic_time)
return monotonic_time;
else
return monotonic_time + compositor->server_time_offset;
}

View File

@ -25,10 +25,8 @@
#include <config.h>
#define COGL_ENABLE_EXPERIMENTAL_API
#include <cogl/cogl-texture-pixmap-x11.h>
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#include <clutter/clutter.h>
#include <X11/Xatom.h>

View File

@ -27,9 +27,6 @@
#include <config.h>
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#define COGL_ENABLE_EXPERIMENTAL_API
#include <meta/meta-shaped-texture.h>
#include "meta-texture-tower.h"

View File

@ -25,9 +25,6 @@
#include <config.h>
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#define COGL_ENABLE_EXPERIMENTAL_API
#include <clutter/clutter.h>
#include "meta-texture-rectangle.h"

View File

@ -28,6 +28,10 @@ void meta_window_actor_process_damage (MetaWindowActor *self,
XDamageNotifyEvent *event);
void meta_window_actor_pre_paint (MetaWindowActor *self);
void meta_window_actor_post_paint (MetaWindowActor *self);
void meta_window_actor_frame_complete (MetaWindowActor *self,
CoglFrameInfo *frame_info,
gint64 presentation_time);
void meta_window_actor_invalidate_shadow (MetaWindowActor *self);
@ -45,6 +49,8 @@ void meta_window_actor_update_shape (MetaWindowActor *self);
void meta_window_actor_update_opacity (MetaWindowActor *self);
void meta_window_actor_mapped (MetaWindowActor *self);
void meta_window_actor_unmapped (MetaWindowActor *self);
void meta_window_actor_set_updates_frozen (MetaWindowActor *self,
gboolean updates_frozen);
cairo_region_t *meta_window_actor_get_obscured_region (MetaWindowActor *self);

View File

@ -10,7 +10,6 @@
#include <X11/extensions/Xrender.h>
#include <clutter/x11/clutter-x11.h>
#define COGL_ENABLE_EXPERIMENTAL_API
#include <cogl/cogl-texture-pixmap-x11.h>
#include <gdk/gdk.h> /* for gdk_rectangle_union() */
#include <string.h>
@ -97,6 +96,9 @@ struct _MetaWindowActorPrivate
gint map_in_progress;
gint destroy_in_progress;
/* List of FrameData for recent frames */
GList *frames;
guint visible : 1;
guint mapped : 1;
guint argb32 : 1;
@ -106,11 +108,16 @@ struct _MetaWindowActorPrivate
guint needs_damage_all : 1;
guint received_damage : 1;
/* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
* client message using the most recent frame in ->frames */
guint needs_frame_drawn : 1;
guint needs_pixmap : 1;
guint needs_reshape : 1;
guint recompute_focused_shadow : 1;
guint recompute_unfocused_shadow : 1;
guint size_changed : 1;
guint updates_frozen : 1;
guint needs_destroy : 1;
@ -121,6 +128,15 @@ struct _MetaWindowActorPrivate
guint unredirected : 1;
};
typedef struct _FrameData FrameData;
struct _FrameData
{
int64_t frame_counter;
guint64 sync_request_serial;
gint64 frame_drawn_time;
};
enum
{
PROP_META_WINDOW = 1,
@ -151,8 +167,16 @@ static gboolean meta_window_actor_get_paint_volume (ClutterActor *actor,
static void meta_window_actor_detach (MetaWindowActor *self);
static gboolean meta_window_actor_has_shadow (MetaWindowActor *self);
static void meta_window_actor_handle_updates (MetaWindowActor *self);
G_DEFINE_TYPE (MetaWindowActor, meta_window_actor, CLUTTER_TYPE_GROUP);
static void
frame_data_free (FrameData *frame)
{
g_slice_free (FrameData, frame);
}
static void
meta_window_actor_class_init (MetaWindowActorClass *klass)
{
@ -663,7 +687,7 @@ meta_window_actor_get_paint_volume (ClutterActor *actor,
/* The paint volume is computed before paint functions are called
* so our bounds might not be updated yet. Force an update. */
meta_window_actor_pre_paint (self);
meta_window_actor_handle_updates (self);
meta_window_actor_get_shape_bounds (self, &bounds);
@ -925,12 +949,31 @@ meta_window_actor_thaw (MetaWindowActor *self)
if (self->priv->freeze_count)
return;
/* We ignore moves and resizes on frozen windows */
meta_window_actor_sync_actor_position (self);
/* We do this now since we might be going right back into the
* frozen state */
meta_window_actor_handle_updates (self);
/* Since we ignore damage events while a window is frozen for certain effects
* we may need to issue an update_area() covering the whole pixmap if we
* don't know what real damage has happened. */
if (self->priv->needs_damage_all)
meta_window_actor_damage_all (self);
else if (self->priv->needs_frame_drawn != 0)
{
/* A frame was marked by the client without actually doing any damage;
* we need to make sure that the pre_paint/post_paint functions
* get called, enabling us to send a _NET_WM_FRAME_DRAWN. We do a
* 1-pixel redraw to get consistent timing with non-empty frames.
*/
if (self->priv->mapped && !self->priv->needs_pixmap)
{
const cairo_rectangle_int_t clip = { 0, 0, 1, 1 };
clutter_actor_queue_redraw_with_clip (self->priv->actor, &clip);
}
}
}
gboolean
@ -1279,6 +1322,12 @@ meta_window_actor_destroy (MetaWindowActor *self)
clutter_actor_destroy (CLUTTER_ACTOR (self));
}
static gboolean
is_frozen (MetaWindowActor *self)
{
return self->priv->freeze_count ? TRUE : FALSE;
}
void
meta_window_actor_sync_actor_position (MetaWindowActor *self)
{
@ -1287,6 +1336,9 @@ meta_window_actor_sync_actor_position (MetaWindowActor *self)
meta_window_get_input_rect (priv->window, &window_rect);
if (is_frozen (self))
return;
if (priv->last_width != window_rect.width ||
priv->last_height != window_rect.height)
{
@ -1483,6 +1535,9 @@ meta_window_actor_new (MetaWindow *window)
if (priv->mapped)
meta_window_actor_queue_create_pixmap (self);
meta_window_actor_set_updates_frozen (self,
meta_window_updates_are_frozen (priv->window));
meta_window_actor_sync_actor_position (self);
/* Hang our compositor window state off the MetaWindow for fast retrieval */
@ -1872,12 +1927,6 @@ check_needs_shadow (MetaWindowActor *self)
meta_shadow_unref (old_shadow);
}
static gboolean
is_frozen (MetaWindowActor *self)
{
return self->priv->freeze_count ? TRUE : FALSE;
}
void
meta_window_actor_process_damage (MetaWindowActor *self,
XDamageNotifyEvent *event)
@ -2242,8 +2291,8 @@ meta_window_actor_update_shape (MetaWindowActor *self)
clutter_actor_queue_redraw (priv->actor);
}
void
meta_window_actor_pre_paint (MetaWindowActor *self)
static void
meta_window_actor_handle_updates (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
MetaScreen *screen = priv->screen;
@ -2295,6 +2344,160 @@ meta_window_actor_pre_paint (MetaWindowActor *self)
check_needs_pixmap (self);
check_needs_reshape (self);
check_needs_shadow (self);
if (priv->window->needs_frame_drawn)
{
FrameData *frame = g_slice_new0 (FrameData);
priv->needs_frame_drawn = TRUE;
frame->sync_request_serial = priv->window->sync_request_serial;
priv->frames = g_list_prepend (priv->frames, frame);
priv->window->needs_frame_drawn = FALSE;
if (priv->window->no_delay_frame)
{
ClutterActor *stage = clutter_actor_get_stage (CLUTTER_ACTOR (self));
clutter_stage_skip_sync_delay (CLUTTER_STAGE (stage));
}
}
}
void
meta_window_actor_pre_paint (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
GList *l;
meta_window_actor_handle_updates (self);
for (l = priv->frames; l != NULL; l = l->next)
{
FrameData *frame = l->data;
if (frame->frame_counter == 0)
{
CoglOnscreen *onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer());
frame->frame_counter = cogl_onscreen_get_frame_counter (onscreen);
}
}
}
void
meta_window_actor_post_paint (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->needs_frame_drawn)
{
MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
XClientMessageEvent ev = { 0, };
FrameData *frame = priv->frames->data;
frame->frame_drawn_time = meta_compositor_monotonic_time_to_server_time (display,
g_get_monotonic_time ());
ev.type = ClientMessage;
ev.window = meta_window_get_xwindow (priv->window);
ev.message_type = display->atom__NET_WM_FRAME_DRAWN;
ev.format = 32;
ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT(0xffffffff);
ev.data.l[1] = frame->sync_request_serial >> 32;
ev.data.l[2] = frame->frame_drawn_time & G_GUINT64_CONSTANT(0xffffffff);
ev.data.l[3] = frame->frame_drawn_time >> 32;
meta_error_trap_push (display);
XSendEvent (xdisplay, ev.window, False, 0, (XEvent*) &ev);
XFlush (xdisplay);
meta_error_trap_pop (display);
priv->needs_frame_drawn = FALSE;
}
}
static void
send_frame_timings (MetaWindowActor *self,
FrameData *frame,
CoglFrameInfo *frame_info,
gint64 presentation_time)
{
MetaWindowActorPrivate *priv = self->priv;
MetaDisplay *display = meta_screen_get_display (priv->screen);
Display *xdisplay = meta_display_get_xdisplay (display);
float refresh_rate;
gint64 refresh_interval;
XClientMessageEvent ev = { 0, };
ev.type = ClientMessage;
ev.window = meta_window_get_xwindow (priv->window);
ev.message_type = display->atom__NET_WM_FRAME_TIMINGS;
ev.format = 32;
ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT(0xffffffff);
ev.data.l[1] = frame->sync_request_serial >> 32;
refresh_rate = cogl_frame_info_get_refresh_rate (frame_info);
if (refresh_rate != 0.0)
refresh_interval = (int) (0.5 + 1000000 / refresh_rate);
else
refresh_interval = 0;
if (presentation_time != 0)
{
gint64 presentation_time_server = meta_compositor_monotonic_time_to_server_time (display,
presentation_time);
gint64 presentation_time_offset = presentation_time_server - frame->frame_drawn_time;
if (presentation_time_offset == 0)
presentation_time_offset = 1;
if ((gint32)presentation_time_offset == presentation_time_offset)
ev.data.l[2] = presentation_time_offset;
}
if (refresh_interval != 0 && (gint32)refresh_interval == refresh_interval)
{
ev.data.l[3] = refresh_interval;
}
ev.data.l[4] = 1000 * META_SYNC_DELAY;
meta_error_trap_push (display);
XSendEvent (xdisplay, ev.window, False, 0, (XEvent*) &ev);
XFlush (xdisplay);
meta_error_trap_pop (display);
}
void
meta_window_actor_frame_complete (MetaWindowActor *self,
CoglFrameInfo *frame_info,
gint64 presentation_time)
{
MetaWindowActorPrivate *priv = self->priv;
GList *l;
for (l = priv->frames; l;)
{
GList *l_next = l->next;
FrameData *frame = l->data;
if (frame->frame_counter == cogl_frame_info_get_frame_counter (frame_info))
{
if (frame->frame_drawn_time != 0)
{
priv->frames = g_list_delete_link (priv->frames, l);
send_frame_timings (self, frame, frame_info, presentation_time);
frame_data_free (frame);
}
}
l = l_next;
}
}
void
@ -2329,3 +2532,21 @@ meta_window_actor_update_opacity (MetaWindowActor *self)
self->priv->opacity = opacity;
clutter_actor_set_opacity (self->priv->actor, opacity);
}
void
meta_window_actor_set_updates_frozen (MetaWindowActor *self,
gboolean updates_frozen)
{
MetaWindowActorPrivate *priv = self->priv;
updates_frozen = updates_frozen != FALSE;
if (priv->updates_frozen != updates_frozen)
{
priv->updates_frozen = updates_frozen;
if (updates_frozen)
meta_window_actor_freeze (self);
else
meta_window_actor_thaw (self);
}
}

View File

@ -223,8 +223,7 @@ struct _MetaDisplay
guint32 last_bell_time;
#endif
#ifdef HAVE_XSYNC
/* alarm monitoring client's _NET_WM_SYNC_REQUEST_COUNTER */
XSyncAlarm grab_sync_request_alarm;
gint64 grab_sync_counter_wait_serial;
#endif
int grab_resize_timeout_id;
@ -370,6 +369,16 @@ void meta_display_register_x_window (MetaDisplay *display,
void meta_display_unregister_x_window (MetaDisplay *display,
Window xwindow);
#ifdef HAVE_XSYNC
MetaWindow* meta_display_lookup_sync_alarm (MetaDisplay *display,
XSyncAlarm alarm);
void meta_display_register_sync_alarm (MetaDisplay *display,
XSyncAlarm *alarmp,
MetaWindow *window);
void meta_display_unregister_sync_alarm (MetaDisplay *display,
XSyncAlarm alarm);
#endif /* HAVE_XSYNC */
void meta_display_notify_window_created (MetaDisplay *display,
MetaWindow *window);

View File

@ -531,10 +531,6 @@ meta_display_open (void)
the_display->allow_terminal_deactivation = TRUE; /* Only relevant for when a
terminal has the focus */
#ifdef HAVE_XSYNC
the_display->grab_sync_request_alarm = None;
#endif
/* FIXME copy the checks from GDK probably */
the_display->static_gravity_works = g_getenv ("MUTTER_USE_STATIC_GRAVITY") != NULL;
@ -643,8 +639,11 @@ meta_display_open (void)
the_display->xsync_event_base = 0;
}
else
the_display->have_xsync = TRUE;
{
the_display->have_xsync = TRUE;
XSyncSetPriority (the_display->xdisplay, None, 10);
}
meta_verbose ("Attempted to init Xsync, found version %d.%d error base %d event base %d\n",
major, minor,
the_display->xsync_error_base,
@ -1939,15 +1938,20 @@ event_callback (XEvent *event,
}
#ifdef HAVE_XSYNC
if (META_DISPLAY_HAS_XSYNC (display) &&
event->type == (display->xsync_event_base + XSyncAlarmNotify) &&
((XSyncAlarmNotifyEvent*)event)->alarm == display->grab_sync_request_alarm)
if (META_DISPLAY_HAS_XSYNC (display) &&
event->type == (display->xsync_event_base + XSyncAlarmNotify))
{
XSyncValue value = ((XSyncAlarmNotifyEvent*)event)->counter_value;
guint64 new_counter_value;
new_counter_value = XSyncValueLow32 (value) + ((gint64)XSyncValueHigh32 (value) << 32);
meta_window_update_sync_request_counter (display->grab_window, new_counter_value);
filter_out_event = TRUE; /* GTK doesn't want to see this really */
MetaWindow *alarm_window = meta_display_lookup_sync_alarm (display,
((XSyncAlarmNotifyEvent*)event)->alarm);
if (alarm_window != NULL)
{
XSyncValue value = ((XSyncAlarmNotifyEvent*)event)->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 */
}
}
#endif /* HAVE_XSYNC */
@ -3555,6 +3559,39 @@ meta_display_unregister_x_window (MetaDisplay *display,
remove_pending_pings_for_window (display, xwindow);
}
#ifdef HAVE_XSYNC
/* We store sync alarms in the window ID hash table, because they are
* just more types of XIDs in the same global space, but we have
* typesafe functions to register/unregister for readability.
*/
MetaWindow*
meta_display_lookup_sync_alarm (MetaDisplay *display,
XSyncAlarm alarm)
{
return g_hash_table_lookup (display->window_ids, &alarm);
}
void
meta_display_register_sync_alarm (MetaDisplay *display,
XSyncAlarm *alarmp,
MetaWindow *window)
{
g_return_if_fail (g_hash_table_lookup (display->window_ids, alarmp) == NULL);
g_hash_table_insert (display->window_ids, alarmp, window);
}
void
meta_display_unregister_sync_alarm (MetaDisplay *display,
XSyncAlarm alarm)
{
g_return_if_fail (g_hash_table_lookup (display->window_ids, &alarm) != NULL);
g_hash_table_remove (display->window_ids, &alarm);
}
#endif /* HAVE_XSYNC */
void
meta_display_notify_window_created (MetaDisplay *display,
MetaWindow *window)
@ -3868,7 +3905,6 @@ meta_display_begin_grab_op (MetaDisplay *display,
display->grab_motion_notify_time = 0;
display->grab_old_window_stacking = NULL;
#ifdef HAVE_XSYNC
display->grab_sync_request_alarm = None;
display->grab_last_user_action_was_snap = FALSE;
#endif
display->grab_frame_action = frame_action;
@ -3889,55 +3925,11 @@ meta_display_begin_grab_op (MetaDisplay *display,
#ifdef HAVE_XSYNC
if ( meta_grab_op_is_resizing (display->grab_op) &&
display->grab_window->sync_request_counter != None)
display->grab_window->sync_request_counter != None)
{
XSyncAlarmAttributes values;
XSyncValue init;
meta_error_trap_push_with_return (display);
/* Set the counter to 0, so we know that the application's
* responses to the client messages will always trigger
* a PositiveTransition
*/
XSyncIntToValue (&init, 0);
XSyncSetCounter (display->xdisplay,
display->grab_window->sync_request_counter, init);
display->grab_window->sync_request_serial = 0;
display->grab_window->sync_request_time.tv_sec = 0;
display->grab_window->sync_request_time.tv_usec = 0;
values.trigger.counter = display->grab_window->sync_request_counter;
values.trigger.value_type = XSyncAbsolute;
values.trigger.test_type = XSyncPositiveTransition;
XSyncIntToValue (&values.trigger.wait_value,
display->grab_window->sync_request_serial + 1);
/* After triggering, increment test_value by this.
* (NOT wait_value above)
*/
XSyncIntToValue (&values.delta, 1);
/* we want events (on by default anyway) */
values.events = True;
display->grab_sync_request_alarm = XSyncCreateAlarm (display->xdisplay,
XSyncCACounter |
XSyncCAValueType |
XSyncCAValue |
XSyncCATestType |
XSyncCADelta |
XSyncCAEvents,
&values);
if (meta_error_trap_pop_with_return (display) != Success)
display->grab_sync_request_alarm = None;
meta_topic (META_DEBUG_RESIZING,
"Created update alarm 0x%lx\n",
display->grab_sync_request_alarm);
meta_window_create_sync_request_alarm (display->grab_window);
window->sync_request_time.tv_sec = 0;
window->sync_request_time.tv_usec = 0;
}
#endif
}
@ -4050,14 +4042,6 @@ meta_display_end_grab_op (MetaDisplay *display,
meta_screen_ungrab_all_keys (display->grab_screen, timestamp);
}
#ifdef HAVE_XSYNC
if (display->grab_sync_request_alarm != None)
{
XSyncDestroyAlarm (display->xdisplay,
display->grab_sync_request_alarm);
display->grab_sync_request_alarm = None;
}
#endif /* HAVE_XSYNC */
display->grab_timestamp = 0;
display->grab_window = NULL;

View File

@ -336,14 +336,32 @@ struct _MetaWindow
/* if non-NULL, the bounds of the window frame */
cairo_region_t *frame_bounds;
/* if TRUE, we are freezing updates during a resize */
guint updates_frozen_for_resize : 1;
/* if TRUE, the we have the new form of sync request counter which
* also handles application frames */
guint extended_sync_request_counter : 1;
/* if TRUE, we still need to send a _NET_WM_FRAME_DRAWN message for the
* last update the sync request counter */
guint needs_frame_drawn : 1;
/* if TRUE, the frame that was just drawn was drawn without any delay
* on the client's part and thus is high-priority - if we add delay
* we might cause the client to miss it's target frame rate */
guint no_delay_frame : 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;
#endif
/* Number of UnmapNotify that are caused by us, if
@ -587,7 +605,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,
@ -623,6 +641,8 @@ void meta_window_refresh_resize_popup (MetaWindow *window);
void meta_window_free_delete_dialog (MetaWindow *window);
void meta_window_create_sync_request_alarm (MetaWindow *window);
void meta_window_destroy_sync_request_alarm (MetaWindow *window);
void meta_window_update_keyboard_resize (MetaWindow *window,
gboolean update_cursor);
@ -655,4 +675,6 @@ gboolean meta_window_can_tile_side_by_side (MetaWindow *window);
void meta_window_compute_tile_match (MetaWindow *window);
gboolean meta_window_updates_are_frozen (MetaWindow *window);
#endif

View File

@ -882,12 +882,32 @@ reload_update_counter (MetaWindow *window,
{
if (value->type != META_PROP_VALUE_INVALID)
{
#ifdef HAVE_XSYNC
XSyncCounter counter = value->v.xcounter;
meta_window_destroy_sync_request_alarm (window);
window->sync_request_counter = None;
window->sync_request_counter = counter;
meta_verbose ("Window has _NET_WM_SYNC_REQUEST_COUNTER 0x%lx\n",
window->sync_request_counter);
#ifdef HAVE_XSYNC
if (value->v.xcounter_list.n_counters == 0)
{
meta_warning ("_NET_WM_SYNC_REQUEST_COUNTER is empty\n");
return;
}
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
}
}
@ -1708,7 +1728,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 },

View File

@ -1015,6 +1015,7 @@ meta_window_new_with_attrs (MetaDisplay *display,
window->sync_request_serial = 0;
window->sync_request_time.tv_sec = 0;
window->sync_request_time.tv_usec = 0;
window->sync_request_alarm = None;
#endif
window->screen = screen;
@ -1818,6 +1819,8 @@ meta_window_unmanage (MetaWindow *window,
if (!window->override_redirect)
meta_stack_remove (window->screen->stack, window);
meta_window_destroy_sync_request_alarm (window);
if (window->frame)
meta_window_destroy_frame (window);
@ -4431,16 +4434,112 @@ static_gravity_works (MetaDisplay *display)
return display->static_gravity_works;
}
void
meta_window_create_sync_request_alarm (MetaWindow *window)
{
#ifdef HAVE_XSYNC
XSyncAlarmAttributes values;
XSyncValue init;
if (window->sync_request_counter == None ||
window->sync_request_alarm != None)
return;
meta_error_trap_push_with_return (window->display);
/* In the old style, we're responsible for setting the initial
* value of the counter. In the new (extended style), the counter
* value is initialized by the client before mapping the window
*/
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 = XSyncPositiveComparison;
/* Initialize to one greater than the current value */
values.trigger.value_type = XSyncRelative;
XSyncIntToValue (&values.trigger.wait_value, 1);
/* After triggering, increment test_value by this until
* until the test condition is false */
XSyncIntToValue (&values.delta, 1);
/* we want events (on by default anyway) */
values.events = True;
window->sync_request_alarm = XSyncCreateAlarm (window->display->xdisplay,
XSyncCACounter |
XSyncCAValueType |
XSyncCAValue |
XSyncCATestType |
XSyncCADelta |
XSyncCAEvents,
&values);
if (meta_error_trap_pop_with_return (window->display) == Success)
meta_display_register_sync_alarm (window->display, &window->sync_request_alarm, window);
else
{
window->sync_request_alarm = None;
window->sync_request_counter = None;
}
#endif
}
void
meta_window_destroy_sync_request_alarm (MetaWindow *window)
{
#ifdef HAVE_XSYNC
if (window->sync_request_alarm != None)
{
/* Has to be unregistered _before_ clearing the structure field */
meta_display_unregister_sync_alarm (window->display, window->sync_request_alarm);
XSyncDestroyAlarm (window->display->xdisplay,
window->sync_request_alarm);
window->sync_request_alarm = None;
}
#endif /* HAVE_XSYNC */
}
#ifdef HAVE_XSYNC
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 */
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;
@ -4453,8 +4552,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.
@ -4466,6 +4566,43 @@ send_sync_request (MetaWindow *window)
}
#endif
/**
* meta_window_updates_are_frozen:
* @window: a #MetaWindow
*
* Gets whether the compositor should be updating the window contents;
* window content updates may be frozen at client request by setting
* an odd value in the extended _NET_WM_SYNC_REQUEST_COUNTER counter r
* by the window manager during a resize operation while waiting for
* the client to redraw.
*
* Return value: %TRUE if updates are currently frozen
*/
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;
}
static void
meta_window_set_updates_frozen_for_resize (MetaWindow *window,
gboolean updates_frozen)
{
if (updates_frozen != window->updates_frozen_for_resize)
{
window->updates_frozen_for_resize = updates_frozen;
if (window->display->compositor)
meta_compositor_set_updates_frozen (window->display->compositor, window,
meta_window_updates_are_frozen (window));
}
}
static gboolean
maybe_move_attached_dialog (MetaWindow *window,
void *data)
@ -4914,12 +5051,28 @@ meta_window_move_resize_internal (MetaWindow *window,
* efficiently as possible
*/
/* configure frame first if we grow more than we shrink
/* Normally, we configure the frame first depending on whether
* we grow the frame more than we shrink. The idea is to avoid
* messing up the window contents by having a temporary situation
* where the frame is smaller than the window. However, if we're
* cooperating with the client to create an atomic frame upate,
* and the window is redirected, then we should always update
* the frame first, since updating the frame will force a new
* backing pixmap to be allocated, and the old backing pixmap
* will be left undisturbed for us to paint to the screen until
* the client finishes redrawing.
*/
size_dx = w - window->rect.width;
size_dy = h - window->rect.height;
if (window->extended_sync_request_counter)
{
configure_frame_first = TRUE;
}
else
{
size_dx = w - window->rect.width;
size_dy = h - window->rect.height;
configure_frame_first = (size_dx + size_dy >= 0);
configure_frame_first = size_dx + size_dy >= 0;
}
if (use_static_gravity)
meta_window_set_gravity (window, StaticGravity);
@ -4960,14 +5113,15 @@ meta_window_move_resize_internal (MetaWindow *window,
meta_error_trap_push (window->display);
#ifdef HAVE_XSYNC
if (window->sync_request_counter != None &&
window->display->grab_sync_request_alarm != None &&
if (window == window->display->grab_window &&
meta_grab_op_is_resizing (window->display->grab_op) &&
window->sync_request_counter != None &&
window->sync_request_alarm != None &&
window->sync_request_time.tv_usec == 0 &&
window->sync_request_time.tv_sec == 0)
{
/* turn off updating */
if (window->display->compositor)
meta_compositor_set_updates (window->display->compositor, window, FALSE);
meta_window_set_updates_frozen_for_resize (window, TRUE);
send_sync_request (window);
}
@ -8526,7 +8680,7 @@ check_moveresize_frequency (MetaWindow *window,
#ifdef HAVE_XSYNC
if (!window->disable_sync &&
window->display->grab_sync_request_alarm != None)
window->sync_request_alarm != None)
{
if (window->sync_request_time.tv_sec != 0 ||
window->sync_request_time.tv_usec != 0)
@ -9097,8 +9251,7 @@ update_resize (MetaWindow *window,
}
/* If we get here, it means the client should have redrawn itself */
if (window->display->compositor)
meta_compositor_set_updates (window->display->compositor, window, TRUE);
meta_window_set_updates_frozen_for_resize (window, FALSE);
/* Remove any scheduled compensation events */
if (window->display->grab_resize_timeout_id)
@ -9291,13 +9444,23 @@ 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)
{
if (window->display->grab_op != META_GRAB_OP_NONE &&
window == window->display->grab_window &&
meta_grab_op_is_mouse (window->display->grab_op))
if (window->extended_sync_request_counter &&
new_counter_value % 2 == 0)
{
window->needs_frame_drawn = TRUE;
window->no_delay_frame = new_counter_value == window->sync_request_serial + 1;
}
window->sync_request_serial = new_counter_value;
meta_compositor_set_updates_frozen (window->display->compositor, window,
meta_window_updates_are_frozen (window));
if (window == window->display->grab_window &&
meta_grab_op_is_resizing (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,
@ -9311,36 +9474,13 @@ meta_window_update_sync_request_counter (MetaWindow *window,
window->sync_request_time.tv_sec = 0;
window->sync_request_time.tv_usec = 0;
/* This means we are ready for another configure. */
switch (window->display->grab_op)
{
case META_GRAB_OP_RESIZING_E:
case META_GRAB_OP_RESIZING_W:
case META_GRAB_OP_RESIZING_S:
case META_GRAB_OP_RESIZING_N:
case META_GRAB_OP_RESIZING_SE:
case META_GRAB_OP_RESIZING_SW:
case META_GRAB_OP_RESIZING_NE:
case META_GRAB_OP_RESIZING_NW:
case META_GRAB_OP_KEYBOARD_RESIZING_S:
case META_GRAB_OP_KEYBOARD_RESIZING_N:
case META_GRAB_OP_KEYBOARD_RESIZING_W:
case META_GRAB_OP_KEYBOARD_RESIZING_E:
case META_GRAB_OP_KEYBOARD_RESIZING_SE:
case META_GRAB_OP_KEYBOARD_RESIZING_NE:
case META_GRAB_OP_KEYBOARD_RESIZING_SW:
case META_GRAB_OP_KEYBOARD_RESIZING_NW:
/* no pointer round trip here, to keep in sync */
update_resize (window,
window->display->grab_last_user_action_was_snap,
window->display->grab_latest_motion_x,
window->display->grab_latest_motion_y,
TRUE);
break;
default:
break;
}
/* This means we are ready for another configure;
* no pointer round trip here, to keep in sync */
update_resize (window,
window->display->grab_last_user_action_was_snap,
window->display->grab_latest_motion_x,
window->display->grab_latest_motion_y,
TRUE);
}
}
#endif /* HAVE_XSYNC */
@ -9380,8 +9520,7 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
xev->root_x,
xev->root_y,
TRUE);
if (window->display->compositor)
meta_compositor_set_updates (window->display->compositor, window, TRUE);
meta_window_set_updates_frozen_for_resize (window, FALSE);
/* If a tiled window has been dragged free with a
* mouse resize without snapping back to the tiled

View File

@ -580,6 +580,23 @@ counter_from_results (GetPropertyResults *results,
return TRUE;
}
static gboolean
counter_list_from_results (GetPropertyResults *results,
XSyncCounter **counters_p,
int *n_counters_p)
{
if (!validate_or_free_results (results, 32,
XA_CARDINAL,
FALSE))
return FALSE;
*counters_p = (XSyncCounter*) results->prop;
*n_counters_p = results->n_items;
results->prop = NULL;
return TRUE;
}
#endif
gboolean
@ -1015,6 +1032,7 @@ meta_prop_get_values (MetaDisplay *display,
values[i].required_type = XA_WM_SIZE_HINTS;
break;
case META_PROP_VALUE_SYNC_COUNTER:
case META_PROP_VALUE_SYNC_COUNTER_LIST:
values[i].required_type = XA_CARDINAL;
break;
}
@ -1165,20 +1183,29 @@ meta_prop_get_values (MetaDisplay *display,
&values[i].v.size_hints.flags))
values[i].type = META_PROP_VALUE_INVALID;
break;
case META_PROP_VALUE_SYNC_COUNTER:
#ifdef HAVE_XSYNC
case META_PROP_VALUE_SYNC_COUNTER:
if (!counter_from_results (&results,
&values[i].v.xcounter))
values[i].type = META_PROP_VALUE_INVALID;
break;
case META_PROP_VALUE_SYNC_COUNTER_LIST:
if (!counter_list_from_results (&results,
&values[i].v.xcounter_list.counters,
&values[i].v.xcounter_list.n_counters))
values[i].type = META_PROP_VALUE_INVALID;
break;
#else
case META_PROP_VALUE_SYNC_COUNTER:
case META_PROP_VALUE_SYNC_COUNTER_LIST:
values[i].type = META_PROP_VALUE_INVALID;
if (results.prop)
{
XFree (results.prop);
results.prop = NULL;
}
#endif
break;
#endif
}
next:
@ -1231,6 +1258,9 @@ free_value (MetaPropValue *value)
break;
case META_PROP_VALUE_SYNC_COUNTER:
break;
case META_PROP_VALUE_SYNC_COUNTER_LIST:
meta_XFree (value->v.xcounter_list.counters);
break;
}
}

View File

@ -157,7 +157,8 @@ typedef enum
META_PROP_VALUE_WM_HINTS,
META_PROP_VALUE_CLASS_HINT,
META_PROP_VALUE_SIZE_HINTS,
META_PROP_VALUE_SYNC_COUNTER /* comes back as CARDINAL */
META_PROP_VALUE_SYNC_COUNTER, /* comes back as CARDINAL */
META_PROP_VALUE_SYNC_COUNTER_LIST /* comes back as CARDINAL */
} MetaPropValueType;
/* used to request/return/store property values */
@ -177,6 +178,11 @@ typedef struct
XClassHint class_hint;
#ifdef HAVE_XSYNC
XSyncCounter xcounter;
struct
{
gulong *counters;
int n_counters;
} xcounter_list;
#endif
struct

View File

@ -174,6 +174,8 @@ item(_NET_WM_FULLSCREEN_MONITORS)
item(_NET_WM_STATE_FOCUSED)
item(_NET_WM_BYPASS_COMPOSITOR)
item(_NET_WM_DONT_BYPASS_COMPOSITOR)
item(_NET_WM_FRAME_DRAWN)
item(_NET_WM_FRAME_TIMINGS)
#if 0
/* We apparently never use: */

View File

@ -153,9 +153,9 @@ void meta_compositor_window_unmapped (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_sync_window_geometry (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_set_updates (MetaCompositor *compositor,
void meta_compositor_set_updates_frozen (MetaCompositor *compositor,
MetaWindow *window,
gboolean updates);
gboolean updates_frozen);
void meta_compositor_sync_stack (MetaCompositor *compositor,
MetaScreen *screen,