Compare commits
	
		
			15 Commits
		
	
	
		
			wip/carlos
			...
			wip/frame-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | d317c1c7e8 | ||
|   | cf72589635 | ||
|   | 3ae070720d | ||
|   | 4b332640eb | ||
|   | 0d36f4f1dd | ||
|   | 0c2491e3c9 | ||
|   | 6de7f4ce36 | ||
|   | 5f77669ba8 | ||
|   | 7a9663500e | ||
|   | 4f79c70002 | ||
|   | 81c42a8944 | ||
|   | 8d9c83ddcf | ||
|   | 5b6020e90d | ||
|   | 8b57ecebda | ||
|   | f6c3e48aa5 | 
| @@ -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						\ | ||||
|   | ||||
| @@ -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 */ | ||||
|   | ||||
| @@ -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, | ||||
| meta_compositor_set_updates_frozen (MetaCompositor *compositor, | ||||
|                                     MetaWindow     *window, | ||||
|                              gboolean        updates) | ||||
|                                     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; | ||||
| } | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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" | ||||
|  | ||||
|   | ||||
| @@ -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" | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
|  | ||||
|   | ||||
| @@ -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,7 +639,10 @@ meta_display_open (void) | ||||
|         the_display->xsync_event_base = 0; | ||||
|       } | ||||
|     else | ||||
|       { | ||||
|         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, | ||||
| @@ -1940,15 +1939,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) | ||||
|       event->type == (display->xsync_event_base + XSyncAlarmNotify)) | ||||
|     { | ||||
|       MetaWindow *alarm_window = meta_display_lookup_sync_alarm (display, | ||||
|                                                                  ((XSyncAlarmNotifyEvent*)event)->alarm); | ||||
|  | ||||
|       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 (display->grab_window, new_counter_value); | ||||
|           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 */ | ||||
|  | ||||
| #ifdef HAVE_SHAPE | ||||
| @@ -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; | ||||
| @@ -3891,53 +3927,9 @@ meta_display_begin_grab_op (MetaDisplay *display, | ||||
|       if ( meta_grab_op_is_resizing (display->grab_op) && | ||||
|            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; | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 }, | ||||
|   | ||||
| @@ -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. | ||||
|    */ | ||||
|   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 */ | ||||
|       /* 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); | ||||
|           break; | ||||
|  | ||||
|         default: | ||||
|           break; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| #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 | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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: */ | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user