Submitted By: Douglas R. Reno Date: 2019-07-01 Initial Package Version: 3.32.2 Upstream Status: Applied Origin: Upstream Description: Fixes several bugs in mutter-3.32.2, including some bugs that have to do with cogl problems and an issue that causes a crash anytime a monitor is unplugged. diff -Naurp mutter-3.32.2.orig/clutter/clutter/clutter-text.c mutter-3.32.2/clutter/clutter/clutter-text.c --- mutter-3.32.2.orig/clutter/clutter/clutter-text.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/clutter/clutter/clutter-text.c 2019-07-01 21:53:47.219980200 -0500 @@ -1975,6 +1975,7 @@ selection_paint (ClutterText *self, else { /* Paint selection background first */ + CoglPipeline *color_pipeline = cogl_pipeline_copy (default_color_pipeline); PangoLayout *layout = clutter_text_get_layout (self); CoglPath *selection_path = cogl_path_new (); CoglColor cogl_color = { 0, }; @@ -1987,11 +1988,19 @@ selection_paint (ClutterText *self, else color = &priv->text_color; + cogl_color_init_from_4ub (&cogl_color, + color->red, + color->green, + color->blue, + paint_opacity * color->alpha / 255); + cogl_color_premultiply (&cogl_color); + cogl_pipeline_set_color (color_pipeline, &cogl_color); + clutter_text_foreach_selection_rectangle_prescaled (self, add_selection_rectangle_to_path, selection_path); - cogl_path_fill (selection_path); + cogl_framebuffer_fill_path (fb, color_pipeline, selection_path); /* Paint selected text */ cogl_framebuffer_push_path_clip (fb, selection_path); diff -Naurp mutter-3.32.2.orig/cogl/cogl/cogl-pipeline.c mutter-3.32.2/cogl/cogl/cogl-pipeline.c --- mutter-3.32.2.orig/cogl/cogl/cogl-pipeline.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/cogl/cogl/cogl-pipeline.c 2019-07-01 15:34:38.353701635 -0500 @@ -455,9 +455,6 @@ _cogl_pipeline_free (CoglPipeline *pipel _cogl_bitmask_destroy (&uniforms_state->changed_mask); } - if (pipeline->differences & COGL_PIPELINE_STATE_NEEDS_BIG_STATE) - g_slice_free (CoglPipelineBigState, pipeline->big_state); - if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS) { g_list_foreach (pipeline->layer_differences, @@ -471,6 +468,9 @@ _cogl_pipeline_free (CoglPipeline *pipel if (pipeline->differences & COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS) _cogl_pipeline_snippet_list_free (&pipeline->big_state->fragment_snippets); + if (pipeline->differences & COGL_PIPELINE_STATE_NEEDS_BIG_STATE) + g_slice_free (CoglPipelineBigState, pipeline->big_state); + g_list_free (pipeline->deprecated_get_layers_list); recursively_free_layer_caches (pipeline); diff -Naurp mutter-3.32.2.orig/cogl/cogl-path/cogl-path.c mutter-3.32.2/cogl/cogl-path/cogl-path.c --- mutter-3.32.2.orig/cogl/cogl-path/cogl-path.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/cogl/cogl-path/cogl-path.c 2019-07-01 19:25:55.294692907 -0500 @@ -1504,7 +1504,6 @@ cogl_framebuffer_push_path_clip (CoglFra COGL_FRAMEBUFFER_STATE_CLIP; } -/* XXX: deprecated */ void cogl_clip_push_from_path (CoglPath *path) { @@ -1575,7 +1574,6 @@ _cogl_path_build_stroke_attribute_buffer data->stroke_n_attributes = n_attributes; } -/* XXX: deprecated */ void cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, @@ -1588,7 +1586,6 @@ cogl_framebuffer_fill_path (CoglFramebuf _cogl_path_fill_nodes (path, framebuffer, pipeline, 0 /* flags */); } -/* XXX: deprecated */ void cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, diff -Naurp mutter-3.32.2.orig/cogl/cogl-path/cogl-path-functions.h mutter-3.32.2/cogl/cogl-path/cogl-path-functions.h --- mutter-3.32.2.orig/cogl/cogl-path/cogl-path-functions.h 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/cogl/cogl-path/cogl-path-functions.h 2019-07-01 19:24:56.709323461 -0500 @@ -460,9 +460,7 @@ cogl_path_fill (CoglPath *path); * use while filling a path. * * Stability: unstable - * Deprecated: 1.16: Use cogl_path_fill() instead */ -COGL_DEPRECATED_FOR (cogl_path_fill) void cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, @@ -492,9 +490,7 @@ cogl_path_stroke (CoglPath *path); * regardless of the current transformation matrix. * * Stability: unstable - * Deprecated: 1.16: Use cogl_path_stroke() instead */ -COGL_DEPRECATED_FOR (cogl_path_stroke) void cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, @@ -529,9 +525,7 @@ cogl_framebuffer_push_path_clip (CoglFra * * Since: 1.8 * Stability: Unstable - * Deprecated: 1.16: Use cogl_framebuffer_push_path_clip() instead */ -COGL_DEPRECATED_FOR (cogl_framebuffer_push_path_clip) void cogl_clip_push_from_path (CoglPath *path); diff -Naurp mutter-3.32.2.orig/src/backends/meta-renderer.c mutter-3.32.2/src/backends/meta-renderer.c --- mutter-3.32.2.orig/src/backends/meta-renderer.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/backends/meta-renderer.c 2019-07-01 21:29:17.909560150 -0500 @@ -91,6 +91,12 @@ meta_renderer_create_view (MetaRenderer void meta_renderer_rebuild_views (MetaRenderer *renderer) { + return META_RENDERER_GET_CLASS (renderer)->rebuild_views (renderer); +} + +static void +meta_renderer_real_rebuild_views (MetaRenderer *renderer) +{ MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer); MetaBackend *backend = meta_get_backend (); MetaMonitorManager *monitor_manager = @@ -181,4 +187,6 @@ meta_renderer_class_init (MetaRendererCl GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = meta_renderer_finalize; + + klass->rebuild_views = meta_renderer_real_rebuild_views; } diff -Naurp mutter-3.32.2.orig/src/backends/meta-renderer.h mutter-3.32.2/src/backends/meta-renderer.h --- mutter-3.32.2.orig/src/backends/meta-renderer.h 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/backends/meta-renderer.h 2019-07-01 21:30:06.639038031 -0500 @@ -43,6 +43,7 @@ struct _MetaRendererClass CoglRenderer * (* create_cogl_renderer) (MetaRenderer *renderer); MetaRendererView * (* create_view) (MetaRenderer *renderer, MetaLogicalMonitor *logical_monitor); + void (* rebuild_views) (MetaRenderer *renderer); }; CoglRenderer * meta_renderer_create_cogl_renderer (MetaRenderer *renderer); diff -Naurp mutter-3.32.2.orig/src/backends/native/meta-cursor-renderer-native.c mutter-3.32.2/src/backends/native/meta-cursor-renderer-native.c --- mutter-3.32.2.orig/src/backends/native/meta-cursor-renderer-native.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/backends/native/meta-cursor-renderer-native.c 2019-07-01 15:32:14.572326991 -0500 @@ -823,6 +823,7 @@ static void cursor_priv_free (MetaCursorNativePrivate *cursor_priv) { g_hash_table_destroy (cursor_priv->gpu_states); + g_free (cursor_priv); } static MetaCursorNativePrivate * diff -Naurp mutter-3.32.2.orig/src/backends/native/meta-renderer-native.c mutter-3.32.2/src/backends/native/meta-renderer-native.c --- mutter-3.32.2.orig/src/backends/native/meta-renderer-native.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/backends/native/meta-renderer-native.c 2019-07-01 22:16:57.469120864 -0500 @@ -258,6 +258,9 @@ cogl_pixel_format_from_drm_format (uint3 CoglPixelFormat *out_format, CoglTextureComponents *out_components); +static void +meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native); + static MetaBackend * backend_from_renderer_native (MetaRendererNative *renderer_native) { @@ -1277,7 +1280,7 @@ meta_renderer_native_egl_context_created cogl_display_egl->dummy_surface, cogl_display_egl->egl_context)) { - _cogl_set_error (error, COGL_WINSYS_ERROR, + g_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT, "Failed to make context current"); return FALSE; @@ -3036,10 +3039,52 @@ meta_onscreen_native_allocate (CoglOnscr } static void +destroy_egl_surface (CoglOnscreen *onscreen) +{ + CoglOnscreenEGL *onscreen_egl = onscreen->winsys; + + if (onscreen_egl->egl_surface != EGL_NO_SURFACE) + { + MetaOnscreenNative *onscreen_native = onscreen_egl->platform; + MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native); + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); + CoglContext *cogl_context = framebuffer->context; + CoglRenderer *cogl_renderer = cogl_context->display->renderer; + CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; + + meta_egl_destroy_surface (egl, + cogl_renderer_egl->edpy, + onscreen_egl->egl_surface, + NULL); + onscreen_egl->egl_surface = EGL_NO_SURFACE; + } +} + +static void +discard_onscreen_page_flip_retries (MetaOnscreenNative *onscreen_native) +{ + g_list_free_full (onscreen_native->pending_page_flip_retries, + (GDestroyNotify) retry_page_flip_data_free); + onscreen_native->pending_page_flip_retries = NULL; + + if (onscreen_native->retry_page_flips_source) + { + MetaBackend *backend = + backend_from_renderer_native (onscreen_native->renderer_native); + + meta_backend_thaw_updates (backend); + g_clear_pointer (&onscreen_native->retry_page_flips_source, + g_source_destroy); + } +} + +static void meta_renderer_native_release_onscreen (CoglOnscreen *onscreen) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *cogl_context = framebuffer->context; + CoglDisplay *cogl_display = cogl_context_get_display (cogl_context); + CoglDisplayEGL *cogl_display_egl = cogl_display->winsys; CoglRenderer *cogl_renderer = cogl_context->display->renderer; CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; CoglOnscreenEGL *onscreen_egl = onscreen->winsys; @@ -3052,28 +3097,18 @@ meta_renderer_native_release_onscreen (C onscreen_native = onscreen_egl->platform; - g_list_free_full (onscreen_native->pending_page_flip_retries, - (GDestroyNotify) retry_page_flip_data_free); - if (onscreen_native->retry_page_flips_source) - { - MetaBackend *backend = - backend_from_renderer_native (onscreen_native->renderer_native); - - meta_backend_thaw_updates (backend); - g_clear_pointer (&onscreen_native->retry_page_flips_source, - g_source_destroy); - } - - if (onscreen_egl->egl_surface != EGL_NO_SURFACE) - { - MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native); + if (onscreen_egl->egl_surface != EGL_NO_SURFACE && + (cogl_display_egl->current_draw_surface == onscreen_egl->egl_surface || + cogl_display_egl->current_read_surface == onscreen_egl->egl_surface)) + { + if (!_cogl_winsys_egl_make_current (cogl_display, + cogl_display_egl->dummy_surface, + cogl_display_egl->dummy_surface, + cogl_display_egl->egl_context)) + g_warning ("Failed to clear current context"); + } - meta_egl_destroy_surface (egl, - cogl_renderer_egl->edpy, - onscreen_egl->egl_surface, - NULL); - onscreen_egl->egl_surface = EGL_NO_SURFACE; - } + discard_onscreen_page_flip_retries (onscreen_native); renderer_gpu_data = meta_renderer_native_get_gpu_data (onscreen_native->renderer_native, @@ -3087,6 +3122,8 @@ meta_renderer_native_release_onscreen (C free_current_bo (onscreen); + destroy_egl_surface (onscreen); + if (onscreen_native->gbm.surface) { gbm_surface_destroy (onscreen_native->gbm.surface); @@ -3097,6 +3134,9 @@ meta_renderer_native_release_onscreen (C case META_RENDERER_NATIVE_MODE_EGL_DEVICE: release_dumb_fb (&onscreen_native->egl.dumb_fb, onscreen_native->render_gpu); + + destroy_egl_surface (onscreen); + if (onscreen_native->egl.stream != EGL_NO_STREAM_KHR) { MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native); @@ -3157,7 +3197,7 @@ meta_renderer_native_supports_mirroring return TRUE; } -void +static void meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native) { MetaRenderer *renderer = META_RENDERER (renderer_native); @@ -3523,6 +3563,37 @@ meta_renderer_native_create_view (MetaRe return view; } +static void +discard_page_flip_retries (MetaRenderer *renderer) +{ + GList *l; + + for (l = meta_renderer_get_views (renderer); l; l = l->next) + { + ClutterStageView *stage_view = l->data; + CoglFramebuffer *framebuffer = + clutter_stage_view_get_onscreen (stage_view); + CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); + CoglOnscreenEGL *onscreen_egl = onscreen->winsys; + MetaOnscreenNative *onscreen_native = onscreen_egl->platform; + + discard_onscreen_page_flip_retries (onscreen_native); + } +} + +static void +meta_renderer_native_rebuild_views (MetaRenderer *renderer) +{ + MetaRendererClass *parent_renderer_class = + META_RENDERER_CLASS (meta_renderer_native_parent_class); + + discard_page_flip_retries (renderer); + + parent_renderer_class->rebuild_views (renderer); + + meta_renderer_native_queue_modes_reset (META_RENDERER_NATIVE (renderer)); +} + void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native) { @@ -4038,6 +4109,7 @@ create_renderer_gpu_data_egl_device (Met G_IO_ERROR_FAILED, "Missing EGL extensions required for EGLDevice renderer: %s", missing_extensions_str); + meta_egl_terminate (egl, egl_display, NULL); g_free (missing_extensions_str); g_free (missing_extensions); return NULL; @@ -4320,6 +4392,7 @@ meta_renderer_native_class_init (MetaRen renderer_class->create_cogl_renderer = meta_renderer_native_create_cogl_renderer; renderer_class->create_view = meta_renderer_native_create_view; + renderer_class->rebuild_views = meta_renderer_native_rebuild_views; obj_props[PROP_MONITOR_MANAGER] = g_param_spec_object ("monitor-manager", diff -Naurp mutter-3.32.2.orig/src/backends/native/meta-renderer-native.h mutter-3.32.2/src/backends/native/meta-renderer-native.h --- mutter-3.32.2.orig/src/backends/native/meta-renderer-native.h 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/backends/native/meta-renderer-native.h 2019-07-01 21:32:29.002358942 -0500 @@ -53,20 +53,6 @@ struct gbm_device * meta_gbm_device_from gboolean meta_renderer_native_supports_mirroring (MetaRendererNative *renderer_native); -void meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native); - -gboolean meta_renderer_native_set_legacy_view_size (MetaRendererNative *renderer_native, - MetaRendererView *view, - int width, - int height, - GError **error); - -void meta_renderer_native_set_ignore_crtc (MetaRendererNative *renderer_native, - uint32_t id, - gboolean ignore); - -MetaRendererView * meta_renderer_native_create_legacy_view (MetaRendererNative *renderer_native); - void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native); int64_t meta_renderer_native_get_frame_counter (MetaRendererNative *renderer_native); diff -Naurp mutter-3.32.2.orig/src/backends/native/meta-stage-native.c mutter-3.32.2/src/backends/native/meta-stage-native.c --- mutter-3.32.2.orig/src/backends/native/meta-stage-native.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/backends/native/meta-stage-native.c 2019-07-01 21:32:42.082756164 -0500 @@ -140,7 +140,6 @@ meta_stage_native_rebuild_views (MetaSta ClutterActor *stage = meta_backend_get_stage (backend); meta_renderer_rebuild_views (renderer); - meta_renderer_native_queue_modes_reset (META_RENDERER_NATIVE (renderer)); clutter_stage_update_resource_scales (CLUTTER_STAGE (stage)); ensure_frame_callbacks (stage_native); } diff -Naurp mutter-3.32.2.orig/src/compositor/meta-surface-actor-x11.c mutter-3.32.2/src/compositor/meta-surface-actor-x11.c --- mutter-3.32.2.orig/src/compositor/meta-surface-actor-x11.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/compositor/meta-surface-actor-x11.c 2019-07-01 21:56:24.326747542 -0500 @@ -32,6 +32,7 @@ #include "cogl/winsys/cogl-texture-pixmap-x11.h" #include "compositor/meta-cullable.h" #include "compositor/meta-shaped-texture-private.h" +#include "compositor/meta-window-actor-private.h" #include "core/window-private.h" #include "meta/meta-x11-errors.h" #include "x11/meta-x11-display-private.h" @@ -71,11 +72,13 @@ static void free_damage (MetaSurfaceActorX11 *self) { MetaDisplay *display = self->display; - Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); + Display *xdisplay; if (self->damage == None) return; + xdisplay = meta_x11_display_get_xdisplay (display->x11_display); + meta_x11_error_trap_push (display->x11_display); XDamageDestroy (xdisplay, self->damage); self->damage = None; @@ -86,12 +89,14 @@ static void detach_pixmap (MetaSurfaceActorX11 *self) { MetaDisplay *display = self->display; - Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display); MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); + Display *xdisplay; if (self->pixmap == None) return; + xdisplay = meta_x11_display_get_xdisplay (display->x11_display); + /* Get rid of all references to the pixmap before freeing it; it's unclear whether * you are supposed to be able to free a GLXPixmap after freeing the underlying * pixmap, but it certainly doesn't work with current DRI/Mesa @@ -344,12 +349,18 @@ meta_surface_actor_x11_is_unredirected ( } static void +release_x11_resources (MetaSurfaceActorX11 *self) +{ + detach_pixmap (self); + free_damage (self); +} + +static void meta_surface_actor_x11_dispose (GObject *object) { MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (object); - detach_pixmap (self); - free_damage (self); + release_x11_resources (self); G_OBJECT_CLASS (meta_surface_actor_x11_parent_class)->dispose (object); } @@ -403,8 +414,7 @@ window_decorated_notify (MetaWindow *win { MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (user_data); - detach_pixmap (self); - free_damage (self); + release_x11_resources (self); create_damage (self); } @@ -441,6 +451,10 @@ meta_surface_actor_x11_new (MetaWindow * g_signal_connect_object (self->window, "notify::decorated", G_CALLBACK (window_decorated_notify), self, 0); + g_signal_connect_object (meta_window_actor_from_window (window), "destroy", + G_CALLBACK (release_x11_resources), self, + G_CONNECT_SWAPPED); + self->unredirected = FALSE; sync_unredirected (self); diff -Naurp mutter-3.32.2.orig/src/compositor/meta-window-actor.c mutter-3.32.2/src/compositor/meta-window-actor.c --- mutter-3.32.2.orig/src/compositor/meta-window-actor.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/compositor/meta-window-actor.c 2019-07-01 21:45:27.896855286 -0500 @@ -417,7 +417,7 @@ meta_window_actor_update_surface (MetaWi else surface_actor = NULL; - set_surface (self, surface_actor); + META_WINDOW_ACTOR_GET_CLASS (self)->set_surface_actor (self, surface_actor); } static void @@ -430,6 +430,9 @@ meta_window_actor_constructed (GObject * priv->compositor = window->display->compositor; + /* Hang out compositor window state off the MetaWindow for fast retrieval */ + meta_window_set_compositor_private (window, object); + meta_window_actor_update_surface (self); meta_window_actor_update_opacity (self); @@ -446,9 +449,6 @@ meta_window_actor_constructed (GObject * priv->first_frame_state = DRAWING_FIRST_FRAME; meta_window_actor_sync_actor_geometry (self, priv->window->placed); - - /* Hang our compositor window state off the MetaWindow for fast retrieval */ - meta_window_set_compositor_private (window, object); } static void @@ -476,7 +476,7 @@ meta_window_actor_dispose (GObject *obje g_clear_object (&priv->window); - set_surface (self, NULL); + META_WINDOW_ACTOR_GET_CLASS (self)->set_surface_actor (self, NULL); G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object); } diff -Naurp mutter-3.32.2.orig/src/core/display.c mutter-3.32.2/src/core/display.c --- mutter-3.32.2.orig/src/core/display.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/core/display.c 2019-07-01 19:45:08.198338254 -0500 @@ -920,10 +920,6 @@ meta_display_close (MetaDisplay *display g_clear_object (&display->gesture_tracker); - g_clear_pointer (&display->stack, meta_stack_free); - g_clear_pointer (&display->stack_tracker, - meta_stack_tracker_free); - if (display->focus_timeout_id) g_source_remove (display->focus_timeout_id); display->focus_timeout_id = 0; @@ -940,12 +936,6 @@ meta_display_close (MetaDisplay *display /* Stop caring about events */ meta_display_free_events (display); - /* Must be after all calls to meta_window_unmanage() since they - * unregister windows - */ - g_hash_table_destroy (display->wayland_windows); - g_hash_table_destroy (display->stamps); - if (display->compositor) meta_compositor_destroy (display->compositor); @@ -956,6 +946,16 @@ meta_display_close (MetaDisplay *display g_clear_object (&display->x11_display); } + /* Must be after all calls to meta_window_unmanage() since they + * unregister windows. + */ + g_hash_table_destroy (display->wayland_windows); + g_hash_table_destroy (display->stamps); + + g_clear_pointer (&display->stack, meta_stack_free); + g_clear_pointer (&display->stack_tracker, + meta_stack_tracker_free); + meta_display_shutdown_keys (display); g_clear_object (&display->bell); diff -Naurp mutter-3.32.2.orig/src/core/window.c mutter-3.32.2/src/core/window.c --- mutter-3.32.2.orig/src/core/window.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/core/window.c 2019-07-01 21:26:50.469092870 -0500 @@ -3683,6 +3683,12 @@ meta_window_activate_full (MetaWindow { MetaWorkspaceManager *workspace_manager = window->display->workspace_manager; gboolean allow_workspace_switch; + + if (window->unmanaging) + { + g_warning ("Trying to activate unmanaged window '%s'", window->desc); + return; + } meta_topic (META_DEBUG_FOCUS, "_NET_ACTIVE_WINDOW message sent for %s at time %u " "by client type %u.\n", @@ -8562,6 +8568,8 @@ meta_window_shortcuts_inhibited (MetaWin gboolean meta_window_is_focusable (MetaWindow *window) { + g_return_val_if_fail (!window->unmanaging, FALSE); + return META_WINDOW_GET_CLASS (window)->is_focusable (window); } diff -Naurp mutter-3.32.2.orig/src/core/workspace.c mutter-3.32.2/src/core/workspace.c --- mutter-3.32.2.orig/src/core/workspace.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/core/workspace.c 2019-07-01 20:10:06.621801394 -0500 @@ -85,6 +85,12 @@ typedef struct _MetaWorkspaceLogicalMoni MetaRectangle logical_monitor_work_area; } MetaWorkspaceLogicalMonitorData; +typedef struct _MetaWorkspaceFocusableAncestorData +{ + MetaWorkspace *workspace; + MetaWindow *out_window; +} MetaWorkspaceFocusableAncestorData; + static MetaWorkspaceLogicalMonitorData * meta_workspace_get_logical_monitor_data (MetaWorkspace *workspace, MetaLogicalMonitor *logical_monitor) @@ -1322,13 +1328,20 @@ meta_workspace_focus_default_window (Met } static gboolean -record_ancestor (MetaWindow *window, - void *data) +find_focusable_ancestor (MetaWindow *window, + gpointer user_data) { - MetaWindow **result = data; + MetaWorkspaceFocusableAncestorData *data = user_data; + + if (!window->unmanaging && meta_window_is_focusable (window) && + meta_window_located_on_workspace (window, data->workspace) && + meta_window_showing_on_its_workspace (window)) + { + data->out_window = window; + return FALSE; + } - *result = window; - return FALSE; /* quit with the first ancestor we find */ + return TRUE; } /* Focus ancestor of not_this_one if there is one */ @@ -1350,11 +1363,15 @@ focus_ancestor_or_top_window (MetaWorksp if (not_this_one) { MetaWindow *ancestor; - ancestor = NULL; - meta_window_foreach_ancestor (not_this_one, record_ancestor, &ancestor); - if (ancestor != NULL && - meta_window_located_on_workspace (ancestor, workspace) && - meta_window_showing_on_its_workspace (ancestor)) + MetaWorkspaceFocusableAncestorData data; + + data = (MetaWorkspaceFocusableAncestorData) { + .workspace = workspace, + }; + meta_window_foreach_ancestor (not_this_one, find_focusable_ancestor, &data); + ancestor = data.out_window; + + if (ancestor) { meta_topic (META_DEBUG_FOCUS, "Focusing %s, ancestor of %s\n", diff -Naurp mutter-3.32.2.orig/src/tests/headless-start-test.c mutter-3.32.2/src/tests/headless-start-test.c --- mutter-3.32.2.orig/src/tests/headless-start-test.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/tests/headless-start-test.c 2019-07-01 22:22:11.322620952 -0500 @@ -32,6 +32,7 @@ #include "wayland/meta-wayland.h" #define ALL_TRANSFORMS ((1 << (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)) - 1) +#define FRAME_WARNING "Frame has assigned frame counter but no frame drawn time" static gboolean run_tests (gpointer data) @@ -40,6 +41,8 @@ run_tests (gpointer data) MetaSettings *settings = meta_backend_get_settings (backend); gboolean ret; + g_test_log_set_fatal_handler (NULL, NULL); + meta_settings_override_experimental_features (settings); meta_settings_enable_experimental_feature ( @@ -53,6 +56,20 @@ run_tests (gpointer data) return FALSE; } +static gboolean +ignore_frame_counter_warning (const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) +{ + if ((log_level & G_LOG_LEVEL_WARNING) && + g_strcmp0 (log_domain, "mutter") == 0 && + g_str_has_suffix (message, FRAME_WARNING)) + return FALSE; + + return TRUE; +} + static void meta_test_headless_start (void) { @@ -193,6 +210,8 @@ main (int argc, char *argv[]) meta_init (); meta_register_with_session (); + g_test_log_set_fatal_handler (ignore_frame_counter_warning, NULL); + g_idle_add (run_tests, NULL); return meta_run (); diff -Naurp mutter-3.32.2.orig/src/tests/meson.build mutter-3.32.2/src/tests/meson.build --- mutter-3.32.2.orig/src/tests/meson.build 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/tests/meson.build 2019-07-01 21:10:58.824632410 -0500 @@ -38,6 +38,7 @@ test_client = executable('mutter-test-cl dependencies: [ gtk3_dep, gio_unix_dep, + x11_dep, xext_dep, ], install: have_installed_tests, @@ -104,6 +105,10 @@ headless_start_test = executable('mutter stacking_tests = files([ 'stacking/basic-x11.metatest', 'stacking/basic-wayland.metatest', + 'stacking/closed-transient-no-input-no-take-focus-parent.metatest', + 'stacking/closed-transient-no-input-no-take-focus-parents.metatest', + 'stacking/closed-transient-no-input-parent.metatest', + 'stacking/closed-transient-no-input-parent-delayed-focus-default-cancelled.metatest', 'stacking/minimized.metatest', 'stacking/mixed-windows.metatest', 'stacking/set-parent.metatest', diff -Naurp mutter-3.32.2.orig/src/tests/stacking/closed-transient-no-input-no-take-focus-parent.metatest mutter-3.32.2/src/tests/stacking/closed-transient-no-input-no-take-focus-parent.metatest --- mutter-3.32.2.orig/src/tests/stacking/closed-transient-no-input-no-take-focus-parent.metatest 1969-12-31 18:00:00.000000000 -0600 +++ mutter-3.32.2/src/tests/stacking/closed-transient-no-input-no-take-focus-parent.metatest 2019-07-01 21:02:07.799603150 -0500 @@ -0,0 +1,23 @@ +new_client 1 x11 +create 1/1 +show 1/1 + +create 1/2 csd +set_parent 1/2 1 +can_take_focus 1/2 false +accept_focus 1/2 false +show 1/2 + +create 1/3 csd +set_parent 1/3 2 +show 1/3 + +wait +assert_focused 1/3 +assert_stacking 1/1 1/2 1/3 + +destroy 1/3 + +wait +assert_focused 1/1 +assert_stacking 1/1 1/2 diff -Naurp mutter-3.32.2.orig/src/tests/stacking/closed-transient-no-input-no-take-focus-parents.metatest mutter-3.32.2/src/tests/stacking/closed-transient-no-input-no-take-focus-parents.metatest --- mutter-3.32.2.orig/src/tests/stacking/closed-transient-no-input-no-take-focus-parents.metatest 1969-12-31 18:00:00.000000000 -0600 +++ mutter-3.32.2/src/tests/stacking/closed-transient-no-input-no-take-focus-parents.metatest 2019-07-01 21:03:13.105379567 -0500 @@ -0,0 +1,30 @@ +new_client 2 x11 +create 2/1 +show 2/1 +wait + +new_client 1 x11 +create 1/1 +accept_focus 1/1 false +can_take_focus 1/1 false +show 1/1 + +create 1/2 csd +set_parent 1/2 1 +can_take_focus 1/2 false +accept_focus 1/2 false +show 1/2 + +create 1/3 csd +set_parent 1/3 2 +show 1/3 + +wait +assert_focused 1/3 +assert_stacking 2/1 1/1 1/2 1/3 + +destroy 1/3 + +wait +assert_stacking 1/1 1/2 2/1 +assert_focused 2/1 diff -Naurp mutter-3.32.2.orig/src/tests/stacking/closed-transient-no-input-parent-delayed-focus-default-cancelled.metatest mutter-3.32.2/src/tests/stacking/closed-transient-no-input-parent-delayed-focus-default-cancelled.metatest --- mutter-3.32.2.orig/src/tests/stacking/closed-transient-no-input-parent-delayed-focus-default-cancelled.metatest 1969-12-31 18:00:00.000000000 -0600 +++ mutter-3.32.2/src/tests/stacking/closed-transient-no-input-parent-delayed-focus-default-cancelled.metatest 2019-07-01 21:13:19.449765239 -0500 @@ -0,0 +1,36 @@ +new_client 2 x11 +create 2/1 +show 2/1 + +new_client 1 x11 +create 1/1 +show 1/1 + +create 1/2 csd +set_parent 1/2 1 +accept_focus 1/2 false +show 1/2 + +create 1/3 csd +set_parent 1/3 2 +show 1/3 + +wait +assert_focused 1/3 +assert_stacking 2/1 1/1 1/2 1/3 + +destroy 1/3 +sleep 10 + +assert_focused none +assert_stacking 2/1 1/1 1/2 + +activate 2/1 +wait + +assert_focused 2/1 +assert_stacking 1/1 1/2 2/1 + +sleep 250 +assert_focused 2/1 +assert_stacking 1/1 1/2 2/1 diff -Naurp mutter-3.32.2.orig/src/tests/stacking/closed-transient-no-input-parent.metatest mutter-3.32.2/src/tests/stacking/closed-transient-no-input-parent.metatest --- mutter-3.32.2.orig/src/tests/stacking/closed-transient-no-input-parent.metatest 1969-12-31 18:00:00.000000000 -0600 +++ mutter-3.32.2/src/tests/stacking/closed-transient-no-input-parent.metatest 2019-07-01 21:14:55.447607995 -0500 @@ -0,0 +1,30 @@ +new_client 2 x11 +create 2/1 +show 2/1 + +new_client 1 x11 +create 1/1 +show 1/1 + +create 1/2 csd +set_parent 1/2 1 +accept_focus 1/2 false +show 1/2 + +create 1/3 csd +set_parent 1/3 2 +show 1/3 + +wait +assert_focused 1/3 +assert_stacking 2/1 1/1 1/2 1/3 + +destroy 1/3 +dispatch + +assert_focused none +assert_stacking 2/1 1/1 1/2 + +sleep 250 +assert_focused 1/1 +assert_stacking 2/1 1/1 1/2 diff -Naurp mutter-3.32.2.orig/src/tests/test-client.c mutter-3.32.2/src/tests/test-client.c --- mutter-3.32.2.orig/src/tests/test-client.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/tests/test-client.c 2019-07-01 20:30:52.597491726 -0500 @@ -196,6 +196,74 @@ process_line (const char *line) NULL)) g_print ("Fail to export handle for window id %s", argv[2]); } + else if (strcmp (argv[0], "accept_focus") == 0) + { + if (argc != 3) + { + g_print ("usage: %s [true|false", argv[0]); + goto out; + } + + GtkWidget *window = lookup_window (argv[1]); + if (!window) + { + g_print ("unknown window %s", argv[1]); + goto out; + } + + gboolean enabled = g_ascii_strcasecmp (argv[2], "true") == 0; + gtk_window_set_accept_focus (GTK_WINDOW (window), enabled); + } + else if (strcmp (argv[0], "can_take_focus") == 0) + { + if (argc != 3) + { + g_print ("usage: %s [true|false]", argv[0]); + goto out; + } + + GtkWidget *window = lookup_window (argv[1]); + if (!window) + { + g_print ("unknown window %s", argv[1]); + goto out; + } + + if (wayland) + { + g_print ("%s is not supported under wayland", argv[0]); + goto out; + } + + GdkDisplay *display = gdk_display_get_default (); + GdkWindow *gdkwindow = gtk_widget_get_window (window); + Display *xdisplay = gdk_x11_display_get_xdisplay (display); + Window xwindow = GDK_WINDOW_XID (gdkwindow); + Atom wm_take_focus = gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS"); + gboolean add = g_ascii_strcasecmp(argv[2], "true") == 0; + Atom *protocols = NULL; + Atom *new_protocols; + int n_protocols = 0; + int i, n = 0; + + gdk_display_sync (display); + XGetWMProtocols (xdisplay, xwindow, &protocols, &n_protocols); + new_protocols = g_new0 (Atom, n_protocols + (add ? 1 : 0)); + + for (i = 0; i < n_protocols; ++i) + { + if (protocols[i] != wm_take_focus) + new_protocols[n++] = protocols[i]; + } + + if (add) + new_protocols[n++] = wm_take_focus; + + XSetWMProtocols (xdisplay, xwindow, new_protocols, n); + + XFree (new_protocols); + XFree (protocols); + } else if (strcmp (argv[0], "show") == 0) { if (argc != 2) diff -Naurp mutter-3.32.2.orig/src/tests/test-runner.c mutter-3.32.2/src/tests/test-runner.c --- mutter-3.32.2.orig/src/tests/test-runner.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/tests/test-runner.c 2019-07-01 21:10:08.129153559 -0500 @@ -77,7 +77,7 @@ test_case_new (void) } static gboolean -test_case_before_redraw (gpointer data) +test_case_loop_quit (gpointer data) { TestCase *test = data; @@ -87,6 +87,23 @@ test_case_before_redraw (gpointer data) } static gboolean +test_case_dispatch (TestCase *test, + GError **error) +{ + /* Wait until we've done any outstanding queued up work. + * Although we add this as BEFORE_REDRAW, the iteration that runs the + * BEFORE_REDRAW idles will proceed on and do the redraw, so we're + * waiting until after *ALL* frame processing is completed. + */ + meta_later_add (META_LATER_BEFORE_REDRAW, + test_case_loop_quit, + test, + NULL); + g_main_loop_run (test->loop); + + return TRUE; +} +static gboolean test_case_wait (TestCase *test, GError **error) { @@ -102,16 +119,8 @@ test_case_wait (TestCase *test, if (!test_client_wait (value, error)) return FALSE; - /* Then wait until we've done any outstanding queued up work. - * Though we add this as BEFORE_REDRAW, the iteration that runs the - * BEFORE_REDRAW idles will proceed on and do the redraw, so we're - * waiting until after *all* frame processing. - */ - meta_later_add (META_LATER_BEFORE_REDRAW, - test_case_before_redraw, - test, - NULL); - g_main_loop_run (test->loop); + /* Now, we need to wait until we've done any outstanding work.*/ + test_case_dispatch (test, error); /* Then set an XSync counter ourselves and and wait until * we receive the resulting event - this makes sure that we've @@ -121,6 +130,16 @@ test_case_wait (TestCase *test, return TRUE; } +static gboolean +test_case_sleep (TestCase *test, + guint32 interval, + GError **error) +{ + g_timeout_add_full (G_PRIORITY_LOW, interval, test_case_loop_quit, test, NULL); + g_main_loop_run (test->loop); + + return TRUE; +} #define BAD_COMMAND(...) \ G_STMT_START { \ g_set_error (error, \ @@ -238,6 +257,37 @@ test_case_assert_stacking (TestCase *tes } static gboolean +test_case_assert_focused (TestCase *test, + const char *expected_window, + GError **error) +{ + MetaDisplay *display = meta_get_display (); + + if (!display -> focus_window) + { + if (g_strcmp0 (expected_window, "none") != 0) + { + g_set_error (error, TEST_RUNNER_ERROR, TEST_RUNNER_ERROR_ASSERTION_FAILED, + "focus: expected='%s', actual='none'", expected_window); + } + } + else + { + const char *focused = display->focus_window->title; + + if (g_str_has_prefix (focused, "test/")) + focused += 5; + + if (g_strcmp0 (focused, "test/")) + g_set_error(error, TEST_RUNNER_ERROR, TEST_RUNNER_ERROR_ASSERTION_FAILED, + "focus: expected='%s', actual='%s'", + expected_window, focused); + } + + return *error == NULL; +} + +static gboolean test_case_check_xserver_stacking (TestCase *test, GError **error) { @@ -385,6 +435,9 @@ test_case_do (TestCase *test, argc == 3 ? argv[2] : NULL, NULL)) return FALSE; + + if (!test_client_wait (client, error)) + return FALSE; } else if (strcmp (argv[0], "set_parent") == 0 || strcmp (argv[0], "set_parent_exported") == 0) @@ -404,6 +457,44 @@ test_case_do (TestCase *test, NULL)) return FALSE; } + else if (strcmp (argv[0], "accept_focus") == 0) + { + if (argc != 3 || + (g_ascii_strcasecmp (argv[2], "true") != 0 && + g_ascii_strcasecmp (argv[2], "false") != 0)) + BAD_COMMAND("usage: %s / [true|false]", + argv[0]); + + TestClient *client; + const char *window_id; + if (!test_case_parse_window_id (test, argv[1], &client, &window_id, error)) + return FALSE; + + if (!test_client_do (client, error, + argv[0], window_id, + argv[2], + NULL)) + return FALSE; + } + else if (strcmp (argv[0], "can_take_focus") == 0) + { + if (argc != 3 || + (g_ascii_strcasecmp (argv[2], "true") != 0 && + g_ascii_strcasecmp (argv[2], "false") != 0)) + BAD_COMMAND("usage: %s / [true|false]", + argv[0]); + + TestClient *client; + const char *window_id; + if (!test_case_parse_window_id (test, argv[1], &client, &window_id, error)) + return FALSE; + + if (!test_client_do (client, error, + argv[0], window_id, + argv[2], + NULL)) + return FALSE; + } else if (strcmp (argv[0], "show") == 0) { if (argc != 2) @@ -477,6 +568,28 @@ test_case_do (TestCase *test, if (!test_case_wait (test, error)) return FALSE; } + else if (strcmp (argv[0], "dispatch") == 0) + { + if (argc != 1) + BAD_COMMAND("usage: %s", argv[0]); + + if (!test_case_dispatch (test,error)) + return FALSE; + } + else if (strcmp (argv[0], "sleep") == 0) + { + guint64 interval; + + if (argc != 2) + BAD_COMMAND("usage: %s ", argv[0]); + + if (!g_ascii_string_to_unsigned (argv[1], 10, 0, G_MAXUINT32, + &interval, error)) + return FALSE; + + if (!test_case_sleep (test, (guint32) interval, error)) + return FALSE; + } else if (strcmp (argv[0], "assert_stacking") == 0) { if (!test_case_assert_stacking (test, argv + 1, argc - 1, error)) @@ -485,6 +598,11 @@ test_case_do (TestCase *test, if (!test_case_check_xserver_stacking (test, error)) return FALSE; } + else if (strcmp (argv[0], "assert_focused") == 0) + { + if (!test_case_assert_focused (test, argv[1], error)) + return FALSE; + } else { BAD_COMMAND("Unknown command %s", argv[0]); diff -Naurp mutter-3.32.2.orig/src/wayland/meta-wayland-cursor-surface.c mutter-3.32.2/src/wayland/meta-wayland-cursor-surface.c --- mutter-3.32.2.orig/src/wayland/meta-wayland-cursor-surface.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/wayland/meta-wayland-cursor-surface.c 2019-07-01 19:36:41.018322852 -0500 @@ -170,8 +170,9 @@ meta_wayland_cursor_surface_commit (Meta wl_list_init (&pending->frame_callback_list); if (pending->newly_attached && - (!cairo_region_is_empty (pending->surface_damage) || - !cairo_region_is_empty (pending->buffer_damage))) + ((!cairo_region_is_empty (pending->surface_damage) || + !cairo_region_is_empty (pending->buffer_damage)) || + !priv->buffer)) update_cursor_sprite_texture (META_WAYLAND_CURSOR_SURFACE (surface_role)); } diff -Naurp mutter-3.32.2.orig/src/wayland/meta-wayland-seat.c mutter-3.32.2/src/wayland/meta-wayland-seat.c --- mutter-3.32.2.orig/src/wayland/meta-wayland-seat.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/wayland/meta-wayland-seat.c 2019-07-01 15:33:03.077805423 -0500 @@ -266,7 +266,7 @@ meta_wayland_seat_free (MetaWaylandSeat meta_wayland_gtk_text_input_destroy (seat->gtk_text_input); meta_wayland_text_input_destroy (seat->text_input); - g_slice_free (MetaWaylandSeat, seat); + g_free (seat); } static gboolean diff -Naurp mutter-3.32.2.orig/src/wayland/meta-wayland-surface.c mutter-3.32.2/src/wayland/meta-wayland-surface.c --- mutter-3.32.2.orig/src/wayland/meta-wayland-surface.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/wayland/meta-wayland-surface.c 2019-07-01 19:34:56.417500382 -0500 @@ -738,6 +738,10 @@ meta_wayland_surface_apply_pending_state } } + else + { + cogl_clear_object (&surface->texture); + } /* If the newly attached buffer is going to be accessed directly without * making a copy, such as an EGL buffer, mark it as in-use don't release * it until is replaced by a subsequent wl_surface.commit or when the diff -Naurp mutter-3.32.2.orig/src/x11/window-x11.c mutter-3.32.2/src/x11/window-x11.c --- mutter-3.32.2.orig/src/x11/window-x11.c 2019-05-14 12:57:10.000000000 -0500 +++ mutter-3.32.2/src/x11/window-x11.c 2019-07-01 21:59:53.764106326 -0500 @@ -50,6 +50,8 @@ #include "x11/window-props.h" #include "x11/xprops.h" +#define TAKE_FOCUS_FALLBACK_DELAY_MS 250 + enum _MetaGtkEdgeConstraints { META_GTK_EDGE_CONSTRAINT_TOP_TILED = 1 << 0, @@ -776,6 +778,64 @@ request_take_focus (MetaWindow *window, send_icccm_message (window, display->x11_display->atom_WM_TAKE_FOCUS, timestamp); } +typedef struct +{ + MetaWindow *window; + guint32 timestamp; + guint timeout_id; + gulong unmanaged_id; + gulong focused_changed_id; +} MetaWindowX11DelayedFocusData; + +static void +meta_window_x11_delayed_focus_data_free (MetaWindowX11DelayedFocusData *data) +{ + g_signal_handler_disconnect (data->window, data->unmanaged_id); + g_signal_handler_disconnect (data->window->display, data->focused_changed_id); + + g_clear_handle_id (&data->timeout_id, g_source_remove); + g_free (data); +} + +static gboolean +focus_window_delayed_timeout (gpointer user_data) +{ + MetaWindowX11DelayedFocusData *data = user_data; + MetaWindow *window = data->window; + guint32 timestamp = data->timestamp; + + data->timeout_id = 0; + meta_window_x11_delayed_focus_data_free (data); + + meta_window_focus (window, timestamp); + + return G_SOURCE_REMOVE; +} + +static void +meta_window_x11_maybe_focus_delayed (MetaWindow *window, + guint32 timestamp) +{ + MetaWindowX11DelayedFocusData *data; + + data = g_new0 (MetaWindowX11DelayedFocusData, 1); + data->window = window; + data->timestamp = timestamp; + + data->unmanaged_id = + g_signal_connect_swapped (window, "unmanaged", + G_CALLBACK (meta_window_x11_delayed_focus_data_free), + data); + + data->focused_changed_id = + g_signal_connect_swapped (window->display, "notify::focus-window", + G_CALLBACK (meta_window_x11_delayed_focus_data_free), + data); + + data->timeout_id = g_timeout_add (TAKE_FOCUS_FALLBACK_DELAY_MS, + focus_window_delayed_timeout, data); +} + static void meta_window_x11_focus (MetaWindow *window, guint32 timestamp) @@ -827,13 +887,44 @@ meta_window_x11_focus (MetaWindow *windo * Normally, we want to just leave the focus undisturbed until * the window responds to WM_TAKE_FOCUS, but if we're unmanaging * the current focus window we *need* to move the focus away, so - * we focus the no_focus_window now (and set - * display->focus_window to that) before sending WM_TAKE_FOCUS. + * we focus the no_focus_window before sending WM_TAKE_FOCUS, + * and eventually the default focus window excluding this one, + * if meanwhile we don't get any focus request. */ if (window->display->focus_window != NULL && window->display->focus_window->unmanaging) - meta_x11_display_focus_the_no_focus_window (window->display->x11_display, - timestamp); + { + MetaWindow *focus_window = window; + MetaX11Display *x11_display = window->display->x11_display; + MetaWorkspace *workspace = window->workspace; + MetaStack *stack = workspace->display->stack; + + while (TRUE) + { + focus_window = meta_stack_get_default_focus_window (stack, + workspace, + focus_window); + + if (!focus_window) + break; + + if (focus_window->unmanaging) + continue; + + if (focus_window->input) + break; + + if (focus_window->shaded && focus_window->frame) + break; + } + + meta_x11_display_focus_the_no_focus_window (x11_display, + timestamp); + + if (focus_window) + meta_window_x11_maybe_focus_delayed (focus_window, + timestamp); + } } request_take_focus (window, timestamp);