window: Keep windows with placement rule attached to parent

A window placed using a placement rule should keep that relative
position even if the parent window moves, as the position tied to the
parent window, not to the stage. Thus, if the parent window moves, the
child window should move with it.

In the implementation in this commit, the constraints engine is not
used when repositioning the children; the window is simply positioned
according to the effective placement rule that was derived from the
initial constraining, as the a xdg_popup at the moment cannot move
(relative its parent) after being mapped.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/274
This commit is contained in:
Jonas Ådahl 2018-08-22 21:54:16 +02:00
parent ca5b27baf5
commit 5376c31a33
3 changed files with 46 additions and 18 deletions

View File

@ -787,7 +787,7 @@ constrain_custom_rule (MetaWindow *window,
MetaPlacementRule *placement_rule;
MetaRectangle intersection;
gboolean constraint_satisfied;
MetaPlacementRule current_rule;
MetaPlacementRule *current_rule;
if (priority > PRIORITY_CUSTOM_RULE)
return TRUE;
@ -796,6 +796,14 @@ constrain_custom_rule (MetaWindow *window,
if (!placement_rule)
return TRUE;
if (window->constrained_placement_rule)
{
meta_window_process_placement (window,
window->constrained_placement_rule,
&info->current.x, &info->current.y);
return TRUE;
}
meta_rectangle_intersect (&info->current, &info->work_area_monitor,
&intersection);
@ -803,24 +811,28 @@ constrain_custom_rule (MetaWindow *window,
placement_rule,
&intersection);
if (constraint_satisfied || check_only)
if (check_only)
return constraint_satisfied;
current_rule = *placement_rule;
current_rule = g_new0 (MetaPlacementRule, 1);
*current_rule = *placement_rule;
if (constraint_satisfied)
goto done;
if (info->current.width != intersection.width &&
(current_rule.constraint_adjustment &
(current_rule->constraint_adjustment &
META_PLACEMENT_CONSTRAINT_ADJUSTMENT_FLIP_X))
{
try_flip_window_position (window, info, &current_rule,
try_flip_window_position (window, info, current_rule,
META_PLACEMENT_CONSTRAINT_ADJUSTMENT_FLIP_X,
&info->current, &intersection);
}
if (info->current.height != intersection.height &&
(current_rule.constraint_adjustment &
(current_rule->constraint_adjustment &
META_PLACEMENT_CONSTRAINT_ADJUSTMENT_FLIP_Y))
{
try_flip_window_position (window, info, &current_rule,
try_flip_window_position (window, info, current_rule,
META_PLACEMENT_CONSTRAINT_ADJUSTMENT_FLIP_Y,
&info->current, &intersection);
}
@ -832,9 +844,9 @@ constrain_custom_rule (MetaWindow *window,
&intersection);
if (constraint_satisfied)
return TRUE;
goto done;
if (current_rule.constraint_adjustment &
if (current_rule->constraint_adjustment &
META_PLACEMENT_CONSTRAINT_ADJUSTMENT_SLIDE_X)
{
if (info->current.x != intersection.x)
@ -842,7 +854,7 @@ constrain_custom_rule (MetaWindow *window,
else if (info->current.width != intersection.width)
info->current.x -= info->current.width - intersection.width;
}
if (current_rule.constraint_adjustment &
if (current_rule->constraint_adjustment &
META_PLACEMENT_CONSTRAINT_ADJUSTMENT_SLIDE_Y)
{
if (info->current.y != intersection.y)
@ -858,21 +870,25 @@ constrain_custom_rule (MetaWindow *window,
&intersection);
if (constraint_satisfied)
return TRUE;
goto done;
if (current_rule.constraint_adjustment &
if (current_rule->constraint_adjustment &
META_PLACEMENT_CONSTRAINT_ADJUSTMENT_RESIZE_X)
{
info->current.x = intersection.x;
info->current.width = intersection.width;
}
if (current_rule.constraint_adjustment &
if (current_rule->constraint_adjustment &
META_PLACEMENT_CONSTRAINT_ADJUSTMENT_RESIZE_Y)
{
info->current.y = intersection.y;
info->current.height = intersection.height;
}
done:
g_clear_pointer (&window->constrained_placement_rule, g_free);
window->constrained_placement_rule = current_rule;
return TRUE;
}

View File

@ -521,6 +521,7 @@ struct _MetaWindow
guint bypass_compositor;
MetaPlacementRule *placement_rule;
MetaPlacementRule *constrained_placement_rule;
};
struct _MetaWindowClass

View File

@ -313,6 +313,7 @@ meta_window_finalize (GObject *object)
g_free (window->gtk_app_menu_object_path);
g_free (window->gtk_menubar_object_path);
g_free (window->placement_rule);
g_free (window->constrained_placement_rule);
G_OBJECT_CLASS (meta_window_parent_class)->finalize (object);
}
@ -3752,13 +3753,23 @@ meta_window_updates_are_frozen (MetaWindow *window)
return FALSE;
}
static void
meta_window_reposition (MetaWindow *window)
{
meta_window_move_resize_internal (window,
(META_MOVE_RESIZE_MOVE_ACTION |
META_MOVE_RESIZE_RESIZE_ACTION),
NorthWestGravity,
window->rect);
}
static gboolean
maybe_move_attached_dialog (MetaWindow *window,
maybe_move_attached_window (MetaWindow *window,
void *data)
{
if (meta_window_is_attached_dialog (window))
/* It ignores x,y for such a dialog */
meta_window_move_frame (window, FALSE, 0, 0);
if (meta_window_is_attached_dialog (window) ||
meta_window_get_placement_rule (window))
meta_window_reposition (window);
return FALSE;
}
@ -4061,7 +4072,7 @@ meta_window_move_resize_internal (MetaWindow *window,
window->frame_bounds = NULL;
}
meta_window_foreach_transient (window, maybe_move_attached_dialog, NULL);
meta_window_foreach_transient (window, maybe_move_attached_window, NULL);
meta_stack_update_window_tile_matches (window->display->stack,
workspace_manager->active_workspace);