wayland: add min/max size from xdg-shell v6

Implement min/max size request from xdg-shell-v6 and plug it into the
existing code so that windows with fixed size cannot be tiled/maximized
in Wayland just like in X11.

Bugzilla: https://bugzilla.gnome.org/show_bug.cgi?id=770226
This commit is contained in:
Olivier Fourdan 2016-04-06 14:07:08 +02:00
parent 3acd562a41
commit 4f58a46217
5 changed files with 275 additions and 5 deletions

View File

@ -479,6 +479,8 @@ pending_state_init (MetaWaylandPendingState *state)
wl_list_init (&state->frame_callback_list);
state->has_new_geometry = FALSE;
state->has_new_min_size = FALSE;
state->has_new_max_size = FALSE;
}
static void
@ -523,6 +525,12 @@ move_pending_state (MetaWaylandPendingState *from,
to->opaque_region_set = from->opaque_region_set;
to->new_geometry = from->new_geometry;
to->has_new_geometry = from->has_new_geometry;
to->has_new_min_size = from->has_new_min_size;
to->new_min_width = from->new_min_width;
to->new_min_height = from->new_min_height;
to->has_new_max_size = from->has_new_max_size;
to->new_max_width = from->new_max_width;
to->new_max_height = from->new_max_height;
wl_list_init (&to->frame_callback_list);
wl_list_insert_list (&to->frame_callback_list, &from->frame_callback_list);

View File

@ -142,6 +142,14 @@ struct _MetaWaylandPendingState
MetaRectangle new_geometry;
gboolean has_new_geometry;
/* pending min/max size in window geometry coordinates */
gboolean has_new_min_size;
int new_min_width;
int new_min_height;
gboolean has_new_max_size;
int new_max_width;
int new_max_height;
};
struct _MetaWaylandDragDestFuncs

View File

@ -295,7 +295,20 @@ xdg_toplevel_set_max_size (struct wl_client *client,
int32_t width,
int32_t height)
{
/* TODO */
MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource);
if (width < 0 || height < 0)
{
wl_resource_post_error (resource,
ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
"invalid negative max size requested %i x %i",
width, height);
return;
}
surface->pending->has_new_max_size = TRUE;
surface->pending->new_max_width = width;
surface->pending->new_max_height = height;
}
static void
@ -304,7 +317,20 @@ xdg_toplevel_set_min_size (struct wl_client *client,
int32_t width,
int32_t height)
{
/* TODO */
MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource);
if (width < 0 || height < 0)
{
wl_resource_post_error (resource,
ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
"invalid negative min size requested %i x %i",
width, height);
return;
}
surface->pending->has_new_min_size = TRUE;
surface->pending->new_min_width = width;
surface->pending->new_min_height = height;
}
static void
@ -520,6 +546,37 @@ meta_wayland_xdg_toplevel_send_configure (MetaWaylandXdgToplevel *xdg_toplevel,
}
}
static gboolean
is_new_size_hints_valid (MetaWindow *window,
MetaWaylandPendingState *pending)
{
int new_min_width, new_min_height;
int new_max_width, new_max_height;
if (pending->has_new_min_size)
{
new_min_width = pending->new_min_width;
new_min_height = pending->new_min_height;
}
else
{
meta_window_wayland_get_min_size (window, &new_min_width, &new_min_height);
}
if (pending->has_new_max_size)
{
new_max_width = pending->new_max_width;
new_max_height = pending->new_max_height;
}
else
{
meta_window_wayland_get_max_size (window, &new_max_width, &new_max_height);
}
/* Zero means unlimited */
return ((new_max_width == 0 || new_min_width <= new_max_width) &&
(new_max_height == 0 || new_min_height <= new_max_height));
}
static void
xdg_toplevel_role_commit (MetaWaylandSurfaceRole *surface_role,
MetaWaylandPendingState *pending)
@ -560,6 +617,28 @@ xdg_toplevel_role_commit (MetaWaylandSurfaceRole *surface_role,
return;
}
/* When we get to this point, we ought to have valid size hints */
if (pending->has_new_min_size || pending->has_new_max_size)
{
if (is_new_size_hints_valid (window, pending))
{
if (pending->has_new_min_size)
meta_window_wayland_set_min_size (window, pending->new_min_width, pending->new_min_height);
if (pending->has_new_max_size)
meta_window_wayland_set_max_size (window, pending->new_max_width, pending->new_max_height);
meta_window_recalc_features (window);
}
else
{
wl_resource_post_error (surface->resource,
ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
"Invalid min/max size");
}
}
window_geometry = meta_wayland_xdg_surface_get_window_geometry (xdg_surface);
meta_window_wayland_move_resize (window,
&xdg_surface_priv->acked_configure_serial,

View File

@ -325,10 +325,28 @@ meta_window_wayland_move_resize_internal (MetaWindow *window,
}
static void
scale_rect_size (MetaRectangle *rect, float scale)
scale_size (int *width,
int *height,
float scale)
{
rect->width = (int)(rect->width * scale);
rect->height = (int)(rect->height * scale);
if (*width < G_MAXINT)
{
float new_width = (*width * scale);
*width = (int) MIN (new_width, G_MAXINT);
}
if (*height < G_MAXINT)
{
float new_height = (*height * scale);
*height = (int) MIN (new_height, G_MAXINT);
}
}
static void
scale_rect_size (MetaRectangle *rect,
float scale)
{
scale_size (&rect->width, &rect->height, scale);
}
static void
@ -399,6 +417,9 @@ meta_window_wayland_main_monitor_changed (MetaWindow *window,
scale_rect_size (&window->rect, scale_factor);
scale_rect_size (&window->unconstrained_rect, scale_factor);
scale_rect_size (&window->saved_rect, scale_factor);
scale_size (&window->size_hints.min_width, &window->size_hints.min_height, scale_factor);
scale_size (&window->size_hints.max_width, &window->size_hints.max_height, scale_factor);
/* Window geometry offset (XXX: Need a better place, see
* meta_window_wayland_move_resize). */
@ -650,3 +671,139 @@ meta_window_place_with_placement_rule (MetaWindow *window,
window->unconstrained_rect.height = placement_rule->height;
meta_window_force_placement (window);
}
void
meta_window_wayland_set_min_size (MetaWindow *window,
int width,
int height)
{
gint64 new_width, new_height;
float scale;
meta_topic (META_DEBUG_GEOMETRY, "Window %s sets min size %d x %d\n",
window->desc, width, height);
if (width == 0 && height == 0)
{
window->size_hints.min_width = 0;
window->size_hints.min_height = 0;
window->size_hints.flags &= ~PMinSize;
return;
}
scale = (float) meta_window_wayland_get_main_monitor_scale (window);
scale_size (&width, &height, scale);
new_width = width + (window->custom_frame_extents.left +
window->custom_frame_extents.right);
new_height = height + (window->custom_frame_extents.top +
window->custom_frame_extents.bottom);
window->size_hints.min_width = (int) MIN (new_width, G_MAXINT);
window->size_hints.min_height = (int) MIN (new_height, G_MAXINT);
window->size_hints.flags |= PMinSize;
}
void
meta_window_wayland_set_max_size (MetaWindow *window,
int width,
int height)
{
gint64 new_width, new_height;
float scale;
meta_topic (META_DEBUG_GEOMETRY, "Window %s sets max size %d x %d\n",
window->desc, width, height);
if (width == 0 && height == 0)
{
window->size_hints.max_width = G_MAXINT;
window->size_hints.max_height = G_MAXINT;
window->size_hints.flags &= ~PMaxSize;
return;
}
scale = (float) meta_window_wayland_get_main_monitor_scale (window);
scale_size (&width, &height, scale);
new_width = width + (window->custom_frame_extents.left +
window->custom_frame_extents.right);
new_height = height + (window->custom_frame_extents.top +
window->custom_frame_extents.bottom);
window->size_hints.max_width = (int) ((new_width > 0 && new_width < G_MAXINT) ?
new_width : G_MAXINT);
window->size_hints.max_height = (int) ((new_height > 0 && new_height < G_MAXINT) ?
new_height : G_MAXINT);
window->size_hints.flags |= PMaxSize;
}
void
meta_window_wayland_get_min_size (MetaWindow *window,
int *width,
int *height)
{
gint64 current_width, current_height;
float scale;
if (!(window->size_hints.flags & PMinSize))
{
/* Zero means unlimited */
*width = 0;
*height = 0;
return;
}
current_width = window->size_hints.min_width -
(window->custom_frame_extents.left +
window->custom_frame_extents.right);
current_height = window->size_hints.min_height -
(window->custom_frame_extents.top +
window->custom_frame_extents.bottom);
*width = MAX (current_width, 0);
*height = MAX (current_height, 0);
scale = 1.0 / (float) meta_window_wayland_get_main_monitor_scale (window);
scale_size (width, height, scale);
}
void
meta_window_wayland_get_max_size (MetaWindow *window,
int *width,
int *height)
{
gint64 current_width = 0;
gint64 current_height = 0;
float scale;
if (!(window->size_hints.flags & PMaxSize))
{
/* Zero means unlimited */
*width = 0;
*height = 0;
return;
}
if (window->size_hints.max_width < G_MAXINT)
current_width = window->size_hints.max_width -
(window->custom_frame_extents.left +
window->custom_frame_extents.right);
if (window->size_hints.max_height < G_MAXINT)
current_height = window->size_hints.max_height -
(window->custom_frame_extents.top +
window->custom_frame_extents.bottom);
*width = CLAMP (current_width, 0, G_MAXINT);
*height = CLAMP (current_height, 0, G_MAXINT);
scale = 1.0 / (float) meta_window_wayland_get_main_monitor_scale (window);
scale_size (width, height, scale);
}

View File

@ -61,4 +61,22 @@ void meta_window_wayland_place_relative_to (MetaWindow *window,
void meta_window_place_with_placement_rule (MetaWindow *window,
MetaPlacementRule *placement_rule);
void meta_window_wayland_set_min_size (MetaWindow *window,
int width,
int height);
void meta_window_wayland_set_max_size (MetaWindow *window,
int width,
int height);
void meta_window_wayland_get_min_size (MetaWindow *window,
int *width,
int *height);
void meta_window_wayland_get_max_size (MetaWindow *window,
int *width,
int *height);
#endif