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
This commit is contained in:
parent
f2d7165a52
commit
b4f1569640
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user