summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Ådahl <jadahl@gmail.com>2018-10-18 16:24:18 +0200
committerFlorian Müllner <florian.muellner@gmail.com>2019-03-17 14:12:40 +0000
commitb4f15696407f06438265af03c4e88e4f7739d5af (patch)
tree64e5c7c90ea24c5c03dfd99ed9d16097bb60593d
parentf2d7165a524a151bc25649472511f0fb5ece005c (diff)
downloadmutter-b4f15696407f06438265af03c4e88e4f7739d5af.tar.gz
window: Unmanage rule placed window if ending up outside of parent
If a client maps a persistent popup with a placement rule, then resizes the parent window so that the popup ends up outside of the parent, unmanage the popup and log a warning about the client being buggy. https://gitlab.gnome.org/GNOME/mutter/merge_requests/496
-rw-r--r--src/core/constraints.c30
-rw-r--r--src/core/window-private.h3
-rw-r--r--src/core/window.c29
3 files changed, 62 insertions, 0 deletions
diff --git a/src/core/constraints.c b/src/core/constraints.c
index f743bae5b..67fb92215 100644
--- a/src/core/constraints.c
+++ b/src/core/constraints.c
@@ -145,6 +145,8 @@ typedef struct
*/
GList *usable_screen_region;
GList *usable_monitor_region;
+
+ gboolean should_unmanage;
} ConstraintInfo;
static gboolean do_screen_and_monitor_relative_constraints (MetaWindow *window,
@@ -253,6 +255,14 @@ do_all_constraints (MetaWindow *window,
satisfied = satisfied &&
(*constraint->func) (window, info, priority, check_only);
+ if (info->should_unmanage)
+ {
+ meta_topic (META_DEBUG_GEOMETRY,
+ "constraint %s wants to unmanage window.\n",
+ constraint->name);
+ return TRUE;
+ }
+
if (!check_only)
{
/* Log how the constraint modified the position */
@@ -312,6 +322,12 @@ meta_window_constrain (MetaWindow *window,
*/
satisfied = do_all_constraints (window, &info, priority, check_only);
+ if (info.should_unmanage)
+ {
+ meta_window_unmanage_on_idle (window);
+ return;
+ }
+
/* Drop the least important constraints if we can't satisfy them all */
priority++;
}
@@ -421,6 +437,8 @@ setup_constraint_info (ConstraintInfo *info,
info->usable_monitor_region =
meta_workspace_get_onmonitor_region (cur_workspace, logical_monitor);
+ info->should_unmanage = FALSE;
+
/* Log all this information for debugging */
meta_topic (META_DEBUG_GEOMETRY,
"Setting up constraint info:\n"
@@ -802,6 +820,8 @@ constrain_custom_rule (MetaWindow *window,
if (window->placement_rule_constrained)
{
+ MetaRectangle parent_buffer_rect;
+
parent = meta_window_get_transient_for (window);
meta_window_get_frame_rect (parent, &parent_rect);
info->current.x =
@@ -809,6 +829,16 @@ constrain_custom_rule (MetaWindow *window,
info->current.y =
parent_rect.y + window->constrained_placement_rule_offset_y;
+ meta_window_get_buffer_rect (parent, &parent_buffer_rect);
+ if (!meta_rectangle_overlap (&info->current, &parent_buffer_rect) &&
+ !meta_rectangle_is_adjacent_to (&info->current, &parent_buffer_rect))
+ {
+ g_warning ("Buggy client caused popup to be placed outside of parent "
+ "window");
+ info->should_unmanage = TRUE;
+ return TRUE;
+ }
+
return TRUE;
}
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 9fe5bc526..a6cebb4fb 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -527,6 +527,8 @@ struct _MetaWindow
gboolean placement_rule_constrained;
int constrained_placement_rule_offset_x;
int constrained_placement_rule_offset_y;
+
+ guint unmanage_idle_id;
};
struct _MetaWindowClass
@@ -610,6 +612,7 @@ MetaWindow * _meta_window_shared_new (MetaDisplay *display,
void meta_window_unmanage (MetaWindow *window,
guint32 timestamp);
+void meta_window_unmanage_on_idle (MetaWindow *window);
void meta_window_queue (MetaWindow *window,
guint queuebits);
void meta_window_tile (MetaWindow *window,
diff --git a/src/core/window.c b/src/core/window.c
index b85db6ee3..d2c24506b 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -1424,6 +1424,9 @@ meta_window_unmanage (MetaWindow *window,
meta_verbose ("Unmanaging %s\n", window->desc);
window->unmanaging = TRUE;
+ if (window->unmanage_idle_id)
+ g_source_remove (window->unmanage_idle_id);
+
#ifdef HAVE_WAYLAND
/* This needs to happen for both Wayland and XWayland clients,
* so it can't be in MetaWindowWayland. */
@@ -1595,6 +1598,32 @@ meta_window_unmanage (MetaWindow *window,
g_object_unref (window);
}
+static gboolean
+unmanage_window_idle_callback (gpointer user_data)
+{
+ MetaWindow *window = META_WINDOW (user_data);
+ uint32_t timestamp;
+
+ window->unmanage_idle_id = 0;
+
+ timestamp = meta_display_get_current_time_roundtrip (window->display);
+ meta_window_unmanage (window, timestamp);
+
+ return G_SOURCE_REMOVE;
+}
+
+void
+meta_window_unmanage_on_idle (MetaWindow *window)
+{
+ if (window->unmanage_idle_id)
+ return;
+
+ window->unmanage_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
+ unmanage_window_idle_callback,
+ window,
+ NULL);
+}
+
static void
set_wm_state (MetaWindow *window)
{