1
0
Fork 0

Add experimental mode to use native scaling of Xwayland clients

Allow scale-aware Xwayland clients to scale by an integer scale
themselves, instead of letting them render them at 1x scale and then
scaling up the texture, making it look blurry.

When monitor framebuffers are scaled, this special cases Xwayland and
sends output regions in a way that Xwayland think everything is N times
as large as the logical region, where N is the ceil of the max monitor
scale.

This is done by introducing a "stage" vs "protocol" coordinate space for
X11, where the "protocol" coordinate space is "stage" multiplied by a
scaling factor.

Xwayland thus will have its own "effective scale", sent via
wl_output.scale. The effective Xwayland scale is also used for the
internal MetaWaylandSurface scale internally, unless there is a viewport
dst size set on the same surface, in which case the scale is still set
to 1, to not interfere with wp_viewport semantics.

We're guarding this behind a new experimental feature
"xwayland-native-scaling", which can only come into effect when enabled
together with "scale-monitor-framebuffer".

[v2]:

Move stage_to_protocol/protocol_to_stage to generic window class.

This means parts that aren't aware of any windowing system specific
logic, only that coordinates originate from there for a given window,
can still get their coordinates properly handled.

In particular, this means coordinates from IBus that originates from the
client, can be scaled properly when that client is using X11.

Also make them properly introspected.

[v3]:

Split up coordinate transform API.

Make it one that takes a MtkRectangle, and another that takes a point.

This means the rounding strategy becames explicit when transforming a
point, while when it's a rectangle, it's still always "grow".

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3567>
This commit is contained in:
Jonas Ådahl 2023-12-12 22:52:44 +01:00 committed by Marge Bot
parent 5bf9cf59aa
commit 6e8c7c5f84
16 changed files with 889 additions and 185 deletions

View file

@ -671,14 +671,21 @@ meta_window_actor_x11_process_damage (MetaWindowActorX11 *actor_x11,
XDamageNotifyEvent *event) XDamageNotifyEvent *event)
{ {
MetaSurfaceActor *surface; MetaSurfaceActor *surface;
MtkRectangle area = MTK_RECTANGLE_INIT (event->area.x,
event->area.y,
event->area.width,
event->area.height);
surface = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11)); surface = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11));
if (surface) if (surface)
meta_surface_actor_process_damage (surface, &area); {
MetaWindow *window =
meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11));
MtkRectangle area;
area = MTK_RECTANGLE_INIT (event->area.x,
event->area.y,
event->area.width,
event->area.height);
meta_window_protocol_to_stage_rect (window, &area, &area);
meta_surface_actor_process_damage (surface, &area);
}
meta_window_actor_notify_damaged (META_WINDOW_ACTOR (actor_x11)); meta_window_actor_notify_damaged (META_WINDOW_ACTOR (actor_x11));
} }

View file

@ -616,6 +616,18 @@ struct _MetaWindowClass
gboolean (*set_transient_for) (MetaWindow *window, gboolean (*set_transient_for) (MetaWindow *window,
MetaWindow *parent); MetaWindow *parent);
void (*stage_to_protocol) (MetaWindow *window,
int stage_x,
int stage_y,
int *protocol_x,
int *protocol_y);
void (*protocol_to_stage) (MetaWindow *window,
int protocol_x,
int protocol_y,
int *stage_x,
int *stage_y,
MtkRoundingStrategy rounding_strategy);
}; };
/* These differ from window->has_foo_func in that they consider /* These differ from window->has_foo_func in that they consider
@ -884,3 +896,16 @@ meta_window_should_attach_to_parent (MetaWindow *window);
*/ */
void meta_window_set_normal_hints (MetaWindow *window, void meta_window_set_normal_hints (MetaWindow *window,
MetaSizeHints *hints); MetaSizeHints *hints);
void meta_window_stage_to_protocol_point (MetaWindow *window,
int stage_x,
int stage_y,
int *protocol_x,
int *protocol_y);
void meta_window_protocol_to_stage_point (MetaWindow *window,
int protocol_x,
int protocol_y,
int *stage_x,
int *stage_y,
MtkRoundingStrategy rounding_strategy);

View file

@ -8037,3 +8037,103 @@ meta_window_set_normal_hints (MetaWindow *window,
*/ */
} }
} }
/**
* meta_window_stage_to_protocol_rect:
* @window: A #MetaWindow
* @stage_rect: x #MtkRectangle in stage coordinate space
* @protocol_rect: (out): x #MtkRectangle in protocol coordinate space
*
* Transform the coordinates from stage coordinates to protocol coordinates
*/
void
meta_window_stage_to_protocol_rect (MetaWindow *window,
const MtkRectangle *stage_rect,
MtkRectangle *protocol_rect)
{
MetaWindowClass *klass = META_WINDOW_GET_CLASS (window);
klass->stage_to_protocol (window,
stage_rect->x, stage_rect->y,
&protocol_rect->x, &protocol_rect->y);
klass->stage_to_protocol (window,
stage_rect->width, stage_rect->height,
&protocol_rect->width, &protocol_rect->height);
}
/**
* meta_window_stage_to_protocol_point:
* @window: A #MetaWindow
* @stage_x: x cordinate in stage coordinate space
* @stage_y: y cordinate in stage coordinate space
* @protocol_x: (out): x cordinate in protocol coordinate space
* @protocol_y: (out): y cordinate in protocol coordinate space
*
* Transform the coordinates from stage coordinates to protocol coordinates
*/
void
meta_window_stage_to_protocol_point (MetaWindow *window,
int stage_x,
int stage_y,
int *protocol_x,
int *protocol_y)
{
MetaWindowClass *klass = META_WINDOW_GET_CLASS (window);
klass->stage_to_protocol (window,
stage_x, stage_y,
protocol_x, protocol_y);
}
/**
* meta_window_protocol_to_stage_rect:
* @window: A #MetaWindow
* @protocol_rect: rectangle in protocol coordinate space
* @stage_rect: (out): rect in stage coordinate space
*
* Transform the coordinates from protocol coordinates to coordinates expected
* by the stage and internal window management logic.
*/
void
meta_window_protocol_to_stage_rect (MetaWindow *window,
const MtkRectangle *protocol_rect,
MtkRectangle *stage_rect)
{
MetaWindowClass *klass = META_WINDOW_GET_CLASS (window);
klass->protocol_to_stage (window,
protocol_rect->x, protocol_rect->y,
&stage_rect->x, &stage_rect->y,
MTK_ROUNDING_STRATEGY_SHRINK);
klass->protocol_to_stage (window,
protocol_rect->width, protocol_rect->height,
&stage_rect->width, &stage_rect->height,
MTK_ROUNDING_STRATEGY_GROW);
}
/**
* meta_window_protocol_to_stage_point:
* @window: A #MetaWindow
* @protocol_x: x cordinate in protocol coordinate space
* @protocol_y: y cordinate in protocol coordinate space
* @stage_x: (out): x cordinate in stage coordinate space
* @stage_y: (out): y cordinate in stage coordinate space
*
* Transform the coordinates from protocol coordinates to coordinates expected
* by the stage and internal window management logic.
*/
void
meta_window_protocol_to_stage_point (MetaWindow *window,
int protocol_x,
int protocol_y,
int *stage_x,
int *stage_y,
MtkRoundingStrategy rounding_strategy)
{
MetaWindowClass *klass = META_WINDOW_GET_CLASS (window);
klass->protocol_to_stage (window,
protocol_x, protocol_y,
stage_x, stage_y,
rounding_strategy);
}

View file

@ -425,3 +425,13 @@ MetaWindowClientType meta_window_get_client_type (MetaWindow *window);
META_EXPORT META_EXPORT
gboolean meta_window_has_pointer (MetaWindow *window); gboolean meta_window_has_pointer (MetaWindow *window);
META_EXPORT
void meta_window_stage_to_protocol_rect (MetaWindow *window,
const MtkRectangle *stage_rect,
MtkRectangle *protocol_rect);
META_EXPORT
void meta_window_protocol_to_stage_rect (MetaWindow *window,
const MtkRectangle *protocol_rect,
MtkRectangle *stage_rect);

View file

@ -101,24 +101,20 @@ cursor_sprite_prepare_at (MetaCursorSprite *cursor_sprite,
logical_monitor = logical_monitor =
meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y); meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
if (logical_monitor)
if (!meta_wayland_surface_is_xwayland (surface))
{ {
if (logical_monitor) int surface_scale = surface->applied_state.scale;
{ float texture_scale;
int surface_scale = surface->applied_state.scale;
float texture_scale;
if (meta_backend_is_stage_views_scaled (backend)) if (meta_backend_is_stage_views_scaled (backend))
texture_scale = 1.0f / surface_scale; texture_scale = 1.0f / surface_scale;
else else
texture_scale = (meta_logical_monitor_get_scale (logical_monitor) / texture_scale = (meta_logical_monitor_get_scale (logical_monitor) /
surface_scale); surface_scale);
meta_cursor_sprite_set_texture_scale (cursor_sprite, texture_scale); meta_cursor_sprite_set_texture_scale (cursor_sprite, texture_scale);
meta_cursor_sprite_set_texture_transform (cursor_sprite, meta_cursor_sprite_set_texture_transform (cursor_sprite,
surface->buffer_transform); surface->buffer_transform);
}
} }
meta_wayland_surface_set_main_monitor (surface, logical_monitor); meta_wayland_surface_set_main_monitor (surface, logical_monitor);

View file

@ -31,6 +31,10 @@
#include "backends/meta-monitor-manager-private.h" #include "backends/meta-monitor-manager-private.h"
#include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-private.h"
#ifdef HAVE_XWAYLAND
#include "wayland/meta-xwayland.h"
#endif
#include "xdg-output-unstable-v1-server-protocol.h" #include "xdg-output-unstable-v1-server-protocol.h"
/* Wayland protocol headers list new additions, not deprecations */ /* Wayland protocol headers list new additions, not deprecations */
@ -50,6 +54,8 @@ struct _MetaWaylandOutput
{ {
GObject parent; GObject parent;
MetaWaylandCompositor *compositor;
struct wl_global *global; struct wl_global *global;
GList *resources; GList *resources;
GList *xdg_output_resources; GList *xdg_output_resources;
@ -157,6 +163,37 @@ wl_output_transform_from_transform (MtkMonitorTransform transform)
g_assert_not_reached (); g_assert_not_reached ();
} }
#ifdef HAVE_XWAYLAND
static gboolean
is_xwayland_resource (MetaWaylandOutput *wayland_output,
struct wl_resource *resource)
{
MetaXWaylandManager *manager = &wayland_output->compositor->xwayland_manager;
return resource && wl_resource_get_client (resource) == manager->client;
}
#endif
static void
maybe_scale_for_xwayland (MetaWaylandOutput *wayland_output,
struct wl_resource *resource,
int *x,
int *y)
{
#ifdef HAVE_XWAYLAND
if (is_xwayland_resource (wayland_output, resource))
{
MetaXWaylandManager *xwayland_manager =
&wayland_output->compositor->xwayland_manager;
int xwayland_scale;
xwayland_scale = meta_xwayland_get_effective_scale (xwayland_manager);
*x *= xwayland_scale;
*y *= xwayland_scale;
}
#endif
}
static void static void
send_output_events (struct wl_resource *resource, send_output_events (struct wl_resource *resource,
MetaWaylandOutput *wayland_output, MetaWaylandOutput *wayland_output,
@ -242,6 +279,9 @@ send_output_events (struct wl_resource *resource,
wl_transform = wl_output_transform_from_transform (transform); wl_transform = wl_output_transform_from_transform (transform);
maybe_scale_for_xwayland (wayland_output, resource,
&layout.x,
&layout.y);
wl_output_send_geometry (resource, wl_output_send_geometry (resource,
layout.x, layout.x,
layout.y, layout.y,
@ -424,6 +464,7 @@ meta_wayland_output_new (MetaWaylandCompositor *compositor,
MetaWaylandOutput *wayland_output; MetaWaylandOutput *wayland_output;
wayland_output = g_object_new (META_TYPE_WAYLAND_OUTPUT, NULL); wayland_output = g_object_new (META_TYPE_WAYLAND_OUTPUT, NULL);
wayland_output->compositor = compositor;
wayland_output->global = wl_global_create (compositor->wayland_display, wayland_output->global = wl_global_create (compositor->wayland_display,
&wl_output_interface, &wl_output_interface,
META_WL_OUTPUT_VERSION, META_WL_OUTPUT_VERSION,
@ -618,6 +659,7 @@ send_xdg_output_events (struct wl_resource *resource,
if (need_all_events || if (need_all_events ||
old_layout.x != layout.x || old_layout.y != layout.y) old_layout.x != layout.x || old_layout.y != layout.y)
{ {
maybe_scale_for_xwayland (wayland_output, resource, &layout.x, &layout.y);
zxdg_output_v1_send_logical_position (resource, layout.x, layout.y); zxdg_output_v1_send_logical_position (resource, layout.x, layout.y);
need_done = TRUE; need_done = TRUE;
} }
@ -625,6 +667,7 @@ send_xdg_output_events (struct wl_resource *resource,
if (need_all_events || if (need_all_events ||
old_layout.width != layout.width || old_layout.height != layout.height) old_layout.width != layout.width || old_layout.height != layout.height)
{ {
maybe_scale_for_xwayland (wayland_output, resource, &layout.width, &layout.height);
zxdg_output_v1_send_logical_size (resource, layout.width, layout.height); zxdg_output_v1_send_logical_size (resource, layout.width, layout.height);
need_done = TRUE; need_done = TRUE;
} }
@ -747,7 +790,7 @@ meta_wayland_outputs_init (MetaWaylandCompositor *compositor)
MetaMonitorManager *monitor_manager = MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend); meta_backend_get_monitor_manager (backend);
g_signal_connect (monitor_manager, "monitors-changed-internal", g_signal_connect (monitor_manager, "monitors-changed",
G_CALLBACK (on_monitors_changed), compositor); G_CALLBACK (on_monitors_changed), compositor);
compositor->outputs = compositor->outputs =

View file

@ -1250,6 +1250,20 @@ pointer_set_cursor (struct wl_client *client,
cursor_surface = META_WAYLAND_CURSOR_SURFACE (surface->role); cursor_surface = META_WAYLAND_CURSOR_SURFACE (surface->role);
meta_wayland_cursor_surface_set_renderer (cursor_surface, meta_wayland_cursor_surface_set_renderer (cursor_surface,
cursor_renderer); cursor_renderer);
#ifdef HAVE_XWAYLAND
if (meta_wayland_surface_is_xwayland (surface))
{
MetaXWaylandManager *xwayland_manager =
&surface->compositor->xwayland_manager;
int scale;
scale = meta_xwayland_get_effective_scale (xwayland_manager);
hot_x = (int32_t) round (hot_x / (double) scale);
hot_y = (int32_t) round (hot_y / (double) scale);
}
#endif
meta_wayland_cursor_surface_set_hotspot (cursor_surface, meta_wayland_cursor_surface_set_hotspot (cursor_surface,
hot_x, hot_y); hot_x, hot_y);

View file

@ -800,9 +800,6 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface,
state->buffer->type != META_WAYLAND_BUFFER_TYPE_SINGLE_PIXEL)); state->buffer->type != META_WAYLAND_BUFFER_TYPE_SINGLE_PIXEL));
} }
if (state->scale > 0)
surface->applied_state.scale = state->scale;
if (state->has_new_buffer_transform) if (state->has_new_buffer_transform)
surface->buffer_transform = state->buffer_transform; surface->buffer_transform = state->buffer_transform;
@ -822,6 +819,28 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface,
surface->viewport.has_dst_size = surface->viewport.dst_width > 0; surface->viewport.has_dst_size = surface->viewport.dst_width > 0;
} }
if (meta_wayland_surface_is_xwayland (surface))
{
#ifdef HAVE_XWAYLAND
MetaXWaylandManager *xwayland_manager =
&surface->compositor->xwayland_manager;
if (surface->viewport.has_dst_size)
{
surface->applied_state.scale = 1;
}
else
{
surface->applied_state.scale =
meta_xwayland_get_effective_scale (xwayland_manager);
}
#endif
}
else if (state->scale > 0)
{
surface->applied_state.scale = state->scale;
}
state->derived.surface_size_changed = state->derived.surface_size_changed =
meta_wayland_surface_get_width (surface) != old_width || meta_wayland_surface_get_width (surface) != old_width ||
meta_wayland_surface_get_height (surface) != old_height; meta_wayland_surface_get_height (surface) != old_height;
@ -999,8 +1018,9 @@ meta_wayland_surface_commit (MetaWaylandSurface *surface)
MetaMultiTexture *committed_texture = surface->committed_state.texture; MetaMultiTexture *committed_texture = surface->committed_state.texture;
int committed_scale = surface->committed_state.scale; int committed_scale = surface->committed_state.scale;
if ((meta_multi_texture_get_width (committed_texture) % committed_scale != 0) || if (((meta_multi_texture_get_width (committed_texture) % committed_scale != 0) ||
(meta_multi_texture_get_height (committed_texture) % committed_scale != 0)) (meta_multi_texture_get_height (committed_texture) % committed_scale != 0)) &&
!meta_wayland_surface_is_xwayland (surface))
{ {
if (surface->role && !META_IS_WAYLAND_CURSOR_SURFACE (surface->role)) if (surface->role && !META_IS_WAYLAND_CURSOR_SURFACE (surface->role))
{ {
@ -1530,6 +1550,16 @@ meta_wayland_surface_update_outputs (MetaWaylandSurface *surface)
g_hash_table_foreach (surface->compositor->outputs, g_hash_table_foreach (surface->compositor->outputs,
update_surface_output_state, update_surface_output_state,
surface); surface);
if (meta_wayland_surface_is_xwayland (surface))
{
#ifdef HAVE_XWAYLAND
MetaXWaylandManager *xwayland_manager =
&surface->compositor->xwayland_manager;
surface->applied_state.scale = meta_xwayland_get_effective_scale (xwayland_manager);
#endif
}
} }
void void

View file

@ -820,6 +820,33 @@ meta_window_wayland_set_transient_for (MetaWindow *window,
return TRUE; return TRUE;
} }
static void
meta_window_wayland_stage_to_protocol (MetaWindow *window,
int stage_x,
int stage_y,
int *protocol_x,
int *protocol_y)
{
if (protocol_x)
*protocol_x = stage_x;
if (protocol_y)
*protocol_y = stage_y;
}
static void
meta_window_wayland_protocol_to_stage (MetaWindow *window,
int protocol_x,
int protocol_y,
int *stage_x,
int *stage_y,
MtkRoundingStrategy rounding_strategy)
{
if (stage_x)
*stage_x = protocol_x;
if (stage_y)
*stage_y = protocol_y;
}
static MetaStackLayer static MetaStackLayer
meta_window_wayland_calculate_layer (MetaWindow *window) meta_window_wayland_calculate_layer (MetaWindow *window)
{ {
@ -938,6 +965,8 @@ meta_window_wayland_class_init (MetaWindowWaylandClass *klass)
window_class->is_focus_async = meta_window_wayland_is_focus_async; window_class->is_focus_async = meta_window_wayland_is_focus_async;
window_class->get_wayland_surface = meta_window_wayland_get_wayland_surface; window_class->get_wayland_surface = meta_window_wayland_get_wayland_surface;
window_class->set_transient_for = meta_window_wayland_set_transient_for; window_class->set_transient_for = meta_window_wayland_set_transient_for;
window_class->stage_to_protocol = meta_window_wayland_stage_to_protocol;
window_class->protocol_to_stage = meta_window_wayland_protocol_to_stage;
obj_props[PROP_SURFACE] = obj_props[PROP_SURFACE] =
g_param_spec_object ("surface", NULL, NULL, g_param_spec_object ("surface", NULL, NULL,

View file

@ -27,8 +27,9 @@
#include "x11/window-x11-private.h" #include "x11/window-x11-private.h"
#include "x11/xprops.h" #include "x11/xprops.h"
#include "wayland/meta-window-xwayland.h" #include "wayland/meta-window-xwayland.h"
#include "wayland/meta-wayland.h" #include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-surface-private.h" #include "wayland/meta-wayland-surface-private.h"
#include "wayland/meta-xwayland.h"
enum enum
{ {
@ -315,6 +316,69 @@ meta_window_xwayland_process_property_notify (MetaWindow *window,
meta_window_queue (window, META_QUEUE_MOVE_RESIZE); meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
} }
static void
meta_window_xwayland_stage_to_protocol (MetaWindow *window,
int stage_x,
int stage_y,
int *protocol_x,
int *protocol_y)
{
MetaDisplay *display = meta_window_get_display (window);
MetaContext *context = meta_display_get_context (display);
MetaWaylandCompositor *wayland_compositor =
meta_context_get_wayland_compositor (context);
MetaXWaylandManager *xwayland_manager = &wayland_compositor->xwayland_manager;
int scale;
scale = meta_xwayland_get_effective_scale (xwayland_manager);
if (protocol_x)
*protocol_x = stage_x * scale;
if (protocol_y)
*protocol_y = stage_y * scale;
}
static void
meta_window_xwayland_protocol_to_stage (MetaWindow *window,
int protocol_x,
int protocol_y,
int *stage_x,
int *stage_y,
MtkRoundingStrategy rounding_strategy)
{
MetaDisplay *display = meta_window_get_display (window);
MetaContext *context = meta_display_get_context (display);
MetaWaylandCompositor *wayland_compositor =
meta_context_get_wayland_compositor (context);
MetaXWaylandManager *xwayland_manager = &wayland_compositor->xwayland_manager;
int xwayland_scale;
float scale;
xwayland_scale = meta_xwayland_get_effective_scale (xwayland_manager);
scale = 1.0f / xwayland_scale;
switch (rounding_strategy)
{
case MTK_ROUNDING_STRATEGY_SHRINK:
if (stage_x)
*stage_x = (int) floorf (protocol_x * scale);
if (stage_y)
*stage_y = (int) floorf (protocol_y * scale);
break;
case MTK_ROUNDING_STRATEGY_GROW:
if (stage_x)
*stage_x = (int) ceilf (protocol_x * scale);
if (stage_y)
*stage_y = (int) ceilf (protocol_y * scale);
break;
case MTK_ROUNDING_STRATEGY_ROUND:
if (stage_x)
*stage_x = (int) roundf (protocol_x * scale);
if (stage_y)
*stage_y = (int) roundf (protocol_y * scale);
break;
}
}
static void static void
meta_window_xwayland_class_init (MetaWindowXwaylandClass *klass) meta_window_xwayland_class_init (MetaWindowXwaylandClass *klass)
{ {
@ -326,6 +390,8 @@ meta_window_xwayland_class_init (MetaWindowXwaylandClass *klass)
window_class->force_restore_shortcuts = meta_window_xwayland_force_restore_shortcuts; window_class->force_restore_shortcuts = meta_window_xwayland_force_restore_shortcuts;
window_class->shortcuts_inhibited = meta_window_xwayland_shortcuts_inhibited; window_class->shortcuts_inhibited = meta_window_xwayland_shortcuts_inhibited;
window_class->get_wayland_surface = meta_window_xwayland_get_wayland_surface; window_class->get_wayland_surface = meta_window_xwayland_get_wayland_surface;
window_class->stage_to_protocol = meta_window_xwayland_stage_to_protocol;
window_class->protocol_to_stage = meta_window_xwayland_protocol_to_stage;
window_x11_class->freeze_commits = meta_window_xwayland_freeze_commits; window_x11_class->freeze_commits = meta_window_xwayland_freeze_commits;
window_x11_class->thaw_commits = meta_window_xwayland_thaw_commits; window_x11_class->thaw_commits = meta_window_xwayland_thaw_commits;

View file

@ -20,6 +20,7 @@
#include <glib.h> #include <glib.h>
#include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-private.h"
#include "wayland/meta-xwayland.h"
gboolean gboolean
meta_xwayland_init (MetaXWaylandManager *manager, meta_xwayland_init (MetaXWaylandManager *manager,

View file

@ -163,13 +163,19 @@ meta_xwayland_surface_get_relative_coordinates (MetaWaylandSurfaceRole *surface_
float *out_sy) float *out_sy)
{ {
MetaXwaylandSurface *xwayland_surface = META_XWAYLAND_SURFACE (surface_role); MetaXwaylandSurface *xwayland_surface = META_XWAYLAND_SURFACE (surface_role);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaWaylandCompositor *compositor =
meta_wayland_surface_get_compositor (surface);
MtkRectangle window_rect = { 0 }; MtkRectangle window_rect = { 0 };
int xwayland_scale;
if (xwayland_surface->window) if (xwayland_surface->window)
meta_window_get_buffer_rect (xwayland_surface->window, &window_rect); meta_window_get_buffer_rect (xwayland_surface->window, &window_rect);
*out_sx = abs_x - window_rect.x; xwayland_scale = meta_xwayland_get_effective_scale (&compositor->xwayland_manager);
*out_sy = abs_y - window_rect.y; *out_sx = (abs_x - window_rect.x) * xwayland_scale;
*out_sy = (abs_y - window_rect.y) * xwayland_scale;
} }
static MetaWaylandSurface * static MetaWaylandSurface *

View file

@ -131,6 +131,42 @@ backend_from_x11_display (MetaX11Display *x11_display)
return meta_context_get_backend (context); return meta_context_get_backend (context);
} }
static void
stage_to_protocol (MetaX11Display *x11_display,
int stage_x,
int stage_y,
int *protocol_x,
int *protocol_y)
{
MetaDisplay *display = meta_x11_display_get_display (x11_display);
MetaContext *context = meta_display_get_context (display);
int scale = 1;
switch (meta_context_get_compositor_type (context))
{
case META_COMPOSITOR_TYPE_WAYLAND:
{
#ifdef HAVE_XWAYLAND
MetaWaylandCompositor *wayland_compositor =
meta_context_get_wayland_compositor (context);
MetaXWaylandManager *xwayland_manager =
&wayland_compositor->xwayland_manager;
scale = meta_xwayland_get_effective_scale (xwayland_manager);
#endif
break;
}
case META_COMPOSITOR_TYPE_X11:
break;
}
if (protocol_x)
*protocol_x = stage_x * scale;
if (protocol_y)
*protocol_y = stage_y * scale;
}
static void static void
meta_x11_display_unmanage_windows (MetaX11Display *x11_display) meta_x11_display_unmanage_windows (MetaX11Display *x11_display)
{ {
@ -181,10 +217,32 @@ update_ui_scaling_factor (MetaX11Display *x11_display)
MetaX11DisplayPrivate *priv = MetaX11DisplayPrivate *priv =
meta_x11_display_get_instance_private (x11_display); meta_x11_display_get_instance_private (x11_display);
MetaBackend *backend = backend_from_x11_display (x11_display); MetaBackend *backend = backend_from_x11_display (x11_display);
MetaSettings *settings = meta_backend_get_settings (backend); MetaContext *context = meta_backend_get_context (backend);
int ui_scaling_factor; int ui_scaling_factor = 1;
switch (meta_context_get_compositor_type (context))
{
case META_COMPOSITOR_TYPE_WAYLAND:
{
#ifdef HAVE_XWAYLAND
MetaWaylandCompositor *wayland_compositor =
meta_context_get_wayland_compositor (context);
MetaXWaylandManager *xwayland_manager =
&wayland_compositor->xwayland_manager;
ui_scaling_factor = meta_xwayland_get_effective_scale (xwayland_manager);
#endif
break;
}
case META_COMPOSITOR_TYPE_X11:
{
MetaSettings *settings = meta_backend_get_settings (backend);
ui_scaling_factor = meta_settings_get_ui_scaling_factor (settings);
break;
}
}
ui_scaling_factor = meta_settings_get_ui_scaling_factor (settings);
meta_dbus_x11_set_ui_scaling_factor (priv->dbus_api, ui_scaling_factor); meta_dbus_x11_set_ui_scaling_factor (priv->dbus_api, ui_scaling_factor);
} }
@ -638,6 +696,9 @@ set_desktop_geometry_hint (MetaX11Display *x11_display)
return; return;
meta_display_get_size (x11_display->display, &monitor_width, &monitor_height); meta_display_get_size (x11_display->display, &monitor_width, &monitor_height);
stage_to_protocol (x11_display,
monitor_width, monitor_height,
&monitor_width, &monitor_height);
data[0] = monitor_width; data[0] = monitor_width;
data[1] = monitor_height; data[1] = monitor_height;
@ -1047,14 +1108,22 @@ set_workspace_work_area_hint (MetaWorkspace *workspace,
for (l = logical_monitors; l; l = l->next) for (l = logical_monitors; l; l = l->next)
{ {
MtkRectangle area; MtkRectangle stage_area;
MtkRectangle protocol_area;
meta_workspace_get_work_area_for_logical_monitor (workspace, l->data, &area); meta_workspace_get_work_area_for_logical_monitor (workspace, l->data,
&stage_area);
tmp[0] = area.x; stage_to_protocol (x11_display,
tmp[1] = area.y; stage_area.x, stage_area.y,
tmp[2] = area.width; &protocol_area.x, &protocol_area.y);
tmp[3] = area.height; stage_to_protocol (x11_display,
stage_area.width, stage_area.height,
&protocol_area.width, &protocol_area.height);
tmp[0] = protocol_area.x;
tmp[1] = protocol_area.y;
tmp[2] = protocol_area.width;
tmp[3] = protocol_area.height;
tmp += 4; tmp += 4;
} }
@ -1083,7 +1152,6 @@ set_work_area_hint (MetaDisplay *display,
int num_workspaces; int num_workspaces;
GList *l; GList *l;
unsigned long *data, *tmp; unsigned long *data, *tmp;
MtkRectangle area;
num_workspaces = meta_workspace_manager_get_n_workspaces (workspace_manager); num_workspaces = meta_workspace_manager_get_n_workspaces (workspace_manager);
data = g_new (unsigned long, num_workspaces * 4); data = g_new (unsigned long, num_workspaces * 4);
@ -1092,14 +1160,22 @@ set_work_area_hint (MetaDisplay *display,
for (l = workspace_manager->workspaces; l; l = l->next) for (l = workspace_manager->workspaces; l; l = l->next)
{ {
MetaWorkspace *workspace = l->data; MetaWorkspace *workspace = l->data;
MtkRectangle stage_area;
MtkRectangle protocol_area;
meta_workspace_get_work_area_all_monitors (workspace, &area); meta_workspace_get_work_area_all_monitors (workspace, &stage_area);
set_workspace_work_area_hint (workspace, x11_display); set_workspace_work_area_hint (workspace, x11_display);
tmp[0] = area.x; stage_to_protocol (x11_display,
tmp[1] = area.y; stage_area.x, stage_area.y,
tmp[2] = area.width; &protocol_area.x, &protocol_area.y);
tmp[3] = area.height; stage_to_protocol (x11_display,
stage_area.width, stage_area.height,
&protocol_area.width, &protocol_area.height);
tmp[0] = protocol_area.x;
tmp[1] = protocol_area.y;
tmp[2] = protocol_area.width;
tmp[3] = protocol_area.height;
tmp += 4; tmp += 4;
} }
@ -1279,6 +1355,41 @@ initialize_dbus_interface (MetaX11Display *x11_display)
update_ui_scaling_factor (x11_display); update_ui_scaling_factor (x11_display);
} }
static void
experimental_features_changed (MetaSettings *settings,
MetaExperimentalFeature old_experimental_features,
MetaX11Display *x11_display)
{
gboolean was_xwayland_native_scaling;
gboolean was_stage_views_scaled;
gboolean is_xwayland_native_scaling;
gboolean is_stage_views_scaled;
was_xwayland_native_scaling =
!!(old_experimental_features &
META_EXPERIMENTAL_FEATURE_XWAYLAND_NATIVE_SCALING);
was_stage_views_scaled =
!!(old_experimental_features &
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER);
is_xwayland_native_scaling =
meta_settings_is_experimental_feature_enabled (
settings,
META_EXPERIMENTAL_FEATURE_XWAYLAND_NATIVE_SCALING);
is_stage_views_scaled =
meta_settings_is_experimental_feature_enabled (
settings,
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER);
if (is_xwayland_native_scaling != was_xwayland_native_scaling ||
is_stage_views_scaled != was_stage_views_scaled)
{
update_ui_scaling_factor (x11_display);
set_desktop_geometry_hint (x11_display);
set_work_area_hint (x11_display->display, x11_display);
}
}
/** /**
* meta_x11_display_new: * meta_x11_display_new:
* *
@ -1297,6 +1408,7 @@ meta_x11_display_new (MetaDisplay *display,
MetaBackend *backend = meta_context_get_backend (context); MetaBackend *backend = meta_context_get_backend (context);
MetaMonitorManager *monitor_manager = MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend); meta_backend_get_monitor_manager (backend);
MetaSettings *settings = meta_backend_get_settings (backend);
g_autoptr (MetaX11Display) x11_display = NULL; g_autoptr (MetaX11Display) x11_display = NULL;
Display *xdisplay; Display *xdisplay;
Screen *xscreen; Screen *xscreen;
@ -1469,7 +1581,7 @@ meta_x11_display_new (MetaDisplay *display,
"monitors-changed-internal", "monitors-changed-internal",
G_CALLBACK (on_monitors_changed_internal), G_CALLBACK (on_monitors_changed_internal),
x11_display, x11_display,
0); G_CONNECT_AFTER);
init_leader_window (x11_display, &timestamp); init_leader_window (x11_display, &timestamp);
x11_display->timestamp = timestamp; x11_display->timestamp = timestamp;
@ -1562,6 +1674,11 @@ meta_x11_display_new (MetaDisplay *display,
meta_prefs_add_listener (prefs_changed_callback, x11_display); meta_prefs_add_listener (prefs_changed_callback, x11_display);
g_signal_connect_object (settings,
"experimental-features-changed",
G_CALLBACK (experimental_features_changed),
x11_display, 0);
set_work_area_hint (display, x11_display); set_work_area_hint (display, x11_display);
g_signal_connect_object (display, "workareas-changed", g_signal_connect_object (display, "workareas-changed",
@ -1775,16 +1892,12 @@ meta_x11_display_reload_cursor (MetaX11Display *x11_display)
} }
static void static void
set_cursor_theme (Display *xdisplay, set_cursor_theme (Display *xdisplay,
MetaBackend *backend) const char *theme,
int size)
{ {
MetaSettings *settings = meta_backend_get_settings (backend); XcursorSetTheme (xdisplay, theme);
int scale; XcursorSetDefaultSize (xdisplay, size);
scale = meta_settings_get_ui_scaling_factor (settings);
XcursorSetTheme (xdisplay, meta_prefs_get_cursor_theme ());
XcursorSetDefaultSize (xdisplay,
meta_prefs_get_cursor_size () * scale);
} }
static void static void
@ -1836,8 +1949,37 @@ static void
update_cursor_theme (MetaX11Display *x11_display) update_cursor_theme (MetaX11Display *x11_display)
{ {
MetaBackend *backend = backend_from_x11_display (x11_display); MetaBackend *backend = backend_from_x11_display (x11_display);
MetaContext *context = meta_backend_get_context (backend);
MetaSettings *settings = meta_backend_get_settings (backend);
int scale = 1;
int size;
const char *theme;
set_cursor_theme (x11_display->xdisplay, backend); switch (meta_context_get_compositor_type (context))
{
case META_COMPOSITOR_TYPE_WAYLAND:
{
#ifdef HAVE_XWAYLAND
MetaWaylandCompositor *wayland_compositor =
meta_context_get_wayland_compositor (context);
MetaXWaylandManager *xwayland_manager =
&wayland_compositor->xwayland_manager;
scale = meta_xwayland_get_effective_scale (xwayland_manager);
#endif
break;
}
case META_COMPOSITOR_TYPE_X11:
scale = meta_settings_get_ui_scaling_factor (settings);
break;
}
size = meta_prefs_get_cursor_size () * scale;
theme = meta_prefs_get_cursor_theme ();
set_cursor_theme (x11_display->xdisplay, theme, size);
schedule_reload_x11_cursor (x11_display); schedule_reload_x11_cursor (x11_display);
#ifdef HAVE_X11 #ifdef HAVE_X11
@ -1846,7 +1988,7 @@ update_cursor_theme (MetaX11Display *x11_display)
MetaBackendX11 *backend_x11 = META_BACKEND_X11 (backend); MetaBackendX11 *backend_x11 = META_BACKEND_X11 (backend);
Display *xdisplay = meta_backend_x11_get_xdisplay (backend_x11); Display *xdisplay = meta_backend_x11_get_xdisplay (backend_x11);
set_cursor_theme (xdisplay, backend); set_cursor_theme (xdisplay, theme, size);
meta_backend_x11_reload_cursor (backend_x11); meta_backend_x11_reload_cursor (backend_x11);
} }
#endif #endif

View file

@ -78,6 +78,7 @@ meta_window_x11_set_frame_xwindow (MetaWindow *window,
g_autoptr (MetaFrame) frame = NULL; g_autoptr (MetaFrame) frame = NULL;
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11); MetaWindowX11Private *priv = meta_window_x11_get_private (window_x11);
int child_x, child_y;
if (priv->frame) if (priv->frame)
return; return;
@ -136,12 +137,17 @@ meta_window_x11_set_frame_xwindow (MetaWindow *window,
meta_stack_tracker_record_remove (window->display->stack_tracker, meta_stack_tracker_record_remove (window->display->stack_tracker,
meta_window_x11_get_xwindow (window), meta_window_x11_get_xwindow (window),
XNextRequest (x11_display->xdisplay)); XNextRequest (x11_display->xdisplay));
meta_window_stage_to_protocol_point (window,
frame->child_x,
frame->child_y,
&child_x,
&child_y);
XReparentWindow (x11_display->xdisplay, XReparentWindow (x11_display->xdisplay,
meta_window_x11_get_xwindow (window), meta_window_x11_get_xwindow (window),
frame->xwindow, frame->xwindow,
frame->child_x, child_x,
frame->child_y); child_y);
if (mtk_x11_error_trap_pop_with_return (x11_display->xdisplay)) if (mtk_x11_error_trap_pop_with_return (x11_display->xdisplay))
{ {
@ -239,6 +245,8 @@ meta_window_destroy_frame (MetaWindow *window)
if (!x11_display->closing) if (!x11_display->closing)
{ {
int child_x, child_y;
if (!window->unmanaging) if (!window->unmanaging)
{ {
meta_stack_tracker_record_add (window->display->stack_tracker, meta_stack_tracker_record_add (window->display->stack_tracker,
@ -246,6 +254,12 @@ meta_window_destroy_frame (MetaWindow *window)
XNextRequest (x11_display->xdisplay)); XNextRequest (x11_display->xdisplay));
} }
meta_window_stage_to_protocol_point (window,
frame->rect.x + borders.invisible.left,
frame->rect.y + borders.invisible.top,
&child_x,
&child_y);
XReparentWindow (x11_display->xdisplay, XReparentWindow (x11_display->xdisplay,
meta_window_x11_get_xwindow (window), meta_window_x11_get_xwindow (window),
x11_display->xroot, x11_display->xroot,
@ -253,8 +267,7 @@ meta_window_destroy_frame (MetaWindow *window)
* coordinates here means we'll need to ensure a configure * coordinates here means we'll need to ensure a configure
* notify event is sent; see bug 399552. * notify event is sent; see bug 399552.
*/ */
frame->rect.x + borders.invisible.left, child_x, child_y);
frame->rect.y + borders.invisible.top);
window->reparents_pending += 1; window->reparents_pending += 1;
} }
@ -323,12 +336,25 @@ meta_frame_query_borders (MetaFrame *frame,
if (mtk_x11_error_trap_pop_with_return (x11_display->xdisplay) == Success && if (mtk_x11_error_trap_pop_with_return (x11_display->xdisplay) == Success &&
res == Success && nitems == 4) res == Success && nitems == 4)
{ {
borders->invisible = (MetaFrameBorder) { int left, right, top, bottom;
((long *) data)[0],
((long *) data)[1], meta_window_protocol_to_stage_point (window,
((long *) data)[2], ((long *) data)[0],
((long *) data)[3], ((long *) data)[1],
}; &left,
&right,
MTK_ROUNDING_STRATEGY_GROW);
meta_window_protocol_to_stage_point (window,
((long *) data)[2],
((long *) data)[3],
&top,
&bottom,
MTK_ROUNDING_STRATEGY_GROW);
borders->invisible.left = left;
borders->invisible.right = right;
borders->invisible.top = top;
borders->invisible.bottom = bottom;
} }
else else
{ {
@ -351,12 +377,24 @@ meta_frame_query_borders (MetaFrame *frame,
if (mtk_x11_error_trap_pop_with_return (x11_display->xdisplay) == Success && if (mtk_x11_error_trap_pop_with_return (x11_display->xdisplay) == Success &&
res == Success && nitems == 4) res == Success && nitems == 4)
{ {
borders->visible = (MetaFrameBorder) { int left, right, top, bottom;
((long *) data)[0],
((long *) data)[1], meta_window_protocol_to_stage_point (window,
((long *) data)[2], ((long *) data)[0],
((long *) data)[3], ((long *) data)[1],
}; &left,
&right,
MTK_ROUNDING_STRATEGY_GROW);
meta_window_protocol_to_stage_point (window,
((long *) data)[2],
((long *) data)[3],
&top,
&bottom,
MTK_ROUNDING_STRATEGY_GROW);
borders->visible.left = left;
borders->visible.right = right;
borders->visible.top = top;
borders->visible.bottom = bottom;
} }
else else
{ {
@ -405,6 +443,7 @@ meta_frame_sync_to_window (MetaFrame *frame,
{ {
MetaWindow *window = frame->window; MetaWindow *window = frame->window;
MetaX11Display *x11_display = window->display->x11_display; MetaX11Display *x11_display = window->display->x11_display;
MtkRectangle rect;
meta_topic (META_DEBUG_GEOMETRY, meta_topic (META_DEBUG_GEOMETRY,
"Syncing frame geometry %d,%d %dx%d (SE: %d,%d)", "Syncing frame geometry %d,%d %dx%d (SE: %d,%d)",
@ -415,12 +454,14 @@ meta_frame_sync_to_window (MetaFrame *frame,
mtk_x11_error_trap_push (x11_display->xdisplay); mtk_x11_error_trap_push (x11_display->xdisplay);
meta_window_stage_to_protocol_rect (window, &frame->rect, &rect);
XMoveResizeWindow (x11_display->xdisplay, XMoveResizeWindow (x11_display->xdisplay,
frame->xwindow, frame->xwindow,
frame->rect.x, rect.x,
frame->rect.y, rect.y,
frame->rect.width, rect.width,
frame->rect.height); rect.height);
mtk_x11_error_trap_pop (x11_display->xdisplay); mtk_x11_error_trap_pop (x11_display->xdisplay);
@ -458,6 +499,7 @@ send_configure_notify (MetaFrame *frame)
{ {
MetaX11Display *x11_display = frame->window->display->x11_display; MetaX11Display *x11_display = frame->window->display->x11_display;
XEvent event = { 0 }; XEvent event = { 0 };
MtkRectangle configure_rect;
/* We never get told by the frames client, just reassert the /* We never get told by the frames client, just reassert the
* current frame size. * current frame size.
@ -466,10 +508,15 @@ send_configure_notify (MetaFrame *frame)
event.xconfigure.display = x11_display->xdisplay; event.xconfigure.display = x11_display->xdisplay;
event.xconfigure.event = frame->xwindow; event.xconfigure.event = frame->xwindow;
event.xconfigure.window = frame->xwindow; event.xconfigure.window = frame->xwindow;
event.xconfigure.x = frame->rect.x;
event.xconfigure.y = frame->rect.y; meta_window_stage_to_protocol_rect (frame->window,
event.xconfigure.width = frame->rect.width; &frame->rect,
event.xconfigure.height = frame->rect.height; &configure_rect);
event.xconfigure.x = configure_rect.x;
event.xconfigure.y = configure_rect.y;
event.xconfigure.width = configure_rect.width;
event.xconfigure.height = configure_rect.height;
event.xconfigure.border_width = 0; event.xconfigure.border_width = 0;
event.xconfigure.above = None; event.xconfigure.above = None;
event.xconfigure.override_redirect = False; event.xconfigure.override_redirect = False;

View file

@ -305,10 +305,11 @@ reload_icon_geometry (MetaWindow *window,
{ {
MtkRectangle geometry; MtkRectangle geometry;
geometry.x = (int)value->v.cardinal_list.cardinals[0]; geometry = MTK_RECTANGLE_INIT (value->v.cardinal_list.cardinals[0],
geometry.y = (int)value->v.cardinal_list.cardinals[1]; value->v.cardinal_list.cardinals[1],
geometry.width = (int)value->v.cardinal_list.cardinals[2]; value->v.cardinal_list.cardinals[2],
geometry.height = (int)value->v.cardinal_list.cardinals[3]; value->v.cardinal_list.cardinals[3]);
meta_window_protocol_to_stage_rect (window, &geometry, &geometry);
meta_window_set_icon_geometry (window, &geometry); meta_window_set_icon_geometry (window, &geometry);
} }
@ -373,11 +374,27 @@ reload_gtk_frame_extents (MetaWindow *window,
} }
else else
{ {
int left, right, top, bottom;
MetaFrameBorder extents; MetaFrameBorder extents;
extents.left = (int)value->v.cardinal_list.cardinals[0];
extents.right = (int)value->v.cardinal_list.cardinals[1]; meta_window_protocol_to_stage_point (window,
extents.top = (int)value->v.cardinal_list.cardinals[2]; value->v.cardinal_list.cardinals[0],
extents.bottom = (int)value->v.cardinal_list.cardinals[3]; value->v.cardinal_list.cardinals[1],
&left,
&right,
MTK_ROUNDING_STRATEGY_GROW);
meta_window_protocol_to_stage_point (window,
value->v.cardinal_list.cardinals[2],
value->v.cardinal_list.cardinals[3],
&top,
&bottom,
MTK_ROUNDING_STRATEGY_GROW);
extents.left = left;
extents.right = right;
extents.top = top;
extents.bottom = bottom;
meta_window_set_custom_frame_extents (window, &extents, initial); meta_window_set_custom_frame_extents (window, &extents, initial);
} }
} }
@ -680,13 +697,15 @@ reload_opaque_region (MetaWindow *window,
i = 0; i = 0;
while (i < nitems) while (i < nitems)
{ {
MtkRectangle region_rect = MTK_RECTANGLE_INIT (region[i + 0],
region[i + 1],
region[i + 2],
region[i + 3]);
MtkRectangle *rect = &rects[rect_index]; MtkRectangle *rect = &rects[rect_index];
rect->x = region[i++]; meta_window_protocol_to_stage_rect (window, &region_rect, rect);
rect->y = region[i++];
rect->width = region[i++];
rect->height = region[i++];
i += 4;
rect_index++; rect_index++;
} }
@ -1219,6 +1238,50 @@ hints_have_changed (const MetaSizeHints *old,
FLAG_TOGGLED_OFF (old, new, META_SIZE_HINTS_PROGRAM_WIN_GRAVITY); FLAG_TOGGLED_OFF (old, new, META_SIZE_HINTS_PROGRAM_WIN_GRAVITY);
} }
static void
scale_size_hints (MetaWindow *window,
MetaSizeHints *hints)
{
meta_window_protocol_to_stage_point (window,
hints->x, hints->y,
&hints->x, &hints->y,
MTK_ROUNDING_STRATEGY_SHRINK);
meta_window_protocol_to_stage_point (window,
hints->width, hints->height,
&hints->width, &hints->height,
MTK_ROUNDING_STRATEGY_GROW);
meta_window_protocol_to_stage_point (window,
hints->min_width, hints->min_height,
&hints->min_width, &hints->min_height,
MTK_ROUNDING_STRATEGY_GROW);
meta_window_protocol_to_stage_point (window,
hints->max_width, hints->max_height,
&hints->max_width, &hints->max_height,
MTK_ROUNDING_STRATEGY_GROW);
meta_window_protocol_to_stage_point (window,
hints->width_inc, hints->height_inc,
&hints->width_inc, &hints->height_inc,
MTK_ROUNDING_STRATEGY_ROUND);
meta_window_protocol_to_stage_point (window,
hints->min_aspect.x, hints->min_aspect.y,
&hints->min_aspect.x, &hints->min_aspect.y,
MTK_ROUNDING_STRATEGY_ROUND);
meta_window_protocol_to_stage_point (window,
hints->max_aspect.x, hints->max_aspect.y,
&hints->max_aspect.x, &hints->max_aspect.y,
MTK_ROUNDING_STRATEGY_ROUND);
meta_window_protocol_to_stage_point (window,
hints->base_width, hints->base_height,
&hints->base_width, &hints->base_height,
MTK_ROUNDING_STRATEGY_GROW);
}
static void static void
reload_normal_hints (MetaWindow *window, reload_normal_hints (MetaWindow *window,
MetaPropValue *value, MetaPropValue *value,
@ -1233,8 +1296,18 @@ reload_normal_hints (MetaWindow *window,
old_hints = window->size_hints; old_hints = window->size_hints;
meta_window_set_normal_hints (window, if (value->v.size_hints.hints)
(MetaSizeHints*)value->v.size_hints.hints); {
MetaSizeHints new_hints;
new_hints = *(MetaSizeHints *) value->v.size_hints.hints;
scale_size_hints (window, &new_hints);
meta_window_set_normal_hints (window, &new_hints);
}
else
{
meta_window_set_normal_hints (window, NULL);
}
hints_have_differences = hints_have_changed (&old_hints, hints_have_differences = hints_have_changed (&old_hints,
&window->size_hints); &window->size_hints);

View file

@ -111,6 +111,56 @@ meta_window_x11_get_private (MetaWindowX11 *window_x11)
return meta_window_x11_get_instance_private (window_x11); return meta_window_x11_get_instance_private (window_x11);
} }
static void
meta_window_x11_stage_to_protocol (MetaWindow *window,
int stage_x,
int stage_y,
int *protocol_x,
int *protocol_y)
{
if (protocol_x)
*protocol_x = stage_x;
if (protocol_y)
*protocol_y = stage_y;
}
static void
meta_window_x11_protocol_to_stage (MetaWindow *window,
int protocol_x,
int protocol_y,
int *stage_x,
int *stage_y,
MtkRoundingStrategy rounding_strategy)
{
if (stage_x)
*stage_x = protocol_x;
if (stage_y)
*stage_y = protocol_y;
}
static MtkRectangle *
protocol_rects_to_stage_rects (MetaWindow *window,
size_t n_rects,
XRectangle *protocol_rects)
{
MtkRectangle *rects;
size_t i;
rects = g_new0 (MtkRectangle, n_rects);
for (i = 0; i < n_rects; i++)
{
MtkRectangle protocol_rect =
MTK_RECTANGLE_INIT (protocol_rects[i].x,
protocol_rects[i].y,
protocol_rects[i].width,
protocol_rects[i].height);
meta_window_protocol_to_stage_rect (window, &protocol_rect, &rects[i]);
}
return rects;
}
static void static void
send_icccm_message (MetaWindow *window, send_icccm_message (MetaWindow *window,
Atom atom, Atom atom,
@ -255,8 +305,11 @@ send_configure_notify (MetaWindow *window)
event.xconfigure.display = x11_display->xdisplay; event.xconfigure.display = x11_display->xdisplay;
event.xconfigure.event = priv->xwindow; event.xconfigure.event = priv->xwindow;
event.xconfigure.window = priv->xwindow; event.xconfigure.window = priv->xwindow;
event.xconfigure.x = priv->client_rect.x - priv->border_width; meta_window_stage_to_protocol_point (window,
event.xconfigure.y = priv->client_rect.y - priv->border_width; priv->client_rect.x - priv->border_width,
priv->client_rect.y - priv->border_width,
&event.xconfigure.x,
&event.xconfigure.y);
if (priv->frame) if (priv->frame)
{ {
if (window->withdrawn) if (window->withdrawn)
@ -268,19 +321,36 @@ send_configure_notify (MetaWindow *window)
meta_frame_calc_borders (priv->frame, &borders); meta_frame_calc_borders (priv->frame, &borders);
event.xconfigure.x = priv->frame->rect.x + borders.invisible.left; meta_window_stage_to_protocol_point (window,
event.xconfigure.y = priv->frame->rect.y + borders.invisible.top; (priv->frame->rect.x +
borders.invisible.left),
(priv->frame->rect.y +
borders.invisible.top),
&event.xconfigure.x,
&event.xconfigure.y);
} }
else else
{ {
int dx, dy;
/* Need to be in root window coordinates */ /* Need to be in root window coordinates */
event.xconfigure.x += priv->frame->rect.x; meta_window_stage_to_protocol_point (window,
event.xconfigure.y += priv->frame->rect.y; priv->frame->rect.x,
priv->frame->rect.y,
&dx,
&dy);
event.xconfigure.x += dx;
event.xconfigure.y += dy;
} }
} }
event.xconfigure.width = priv->client_rect.width; meta_window_stage_to_protocol_point (window,
event.xconfigure.height = priv->client_rect.height; priv->client_rect.width,
event.xconfigure.border_width = priv->border_width; /* requested not actual */ priv->client_rect.height,
&event.xconfigure.width,
&event.xconfigure.height);
meta_window_stage_to_protocol_point (window,
priv->border_width, 0,
&event.xconfigure.border_width, NULL);
event.xconfigure.above = None; /* FIXME */ event.xconfigure.above = None; /* FIXME */
event.xconfigure.override_redirect = False; event.xconfigure.override_redirect = False;
@ -1150,20 +1220,27 @@ update_net_frame_extents (MetaWindow *window)
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
MetaX11Display *x11_display = window->display->x11_display; MetaX11Display *x11_display = window->display->x11_display;
int left, right, top, bottom;
unsigned long data[4]; unsigned long data[4];
MetaFrameBorders borders; MetaFrameBorders borders;
Window xwindow = meta_window_x11_get_xwindow (window); Window xwindow = meta_window_x11_get_xwindow (window);
meta_frame_calc_borders (priv->frame, &borders); meta_frame_calc_borders (priv->frame, &borders);
/* Left */ meta_window_stage_to_protocol_point (window,
data[0] = borders.visible.left; borders.visible.left,
/* Right */ borders.visible.right,
data[1] = borders.visible.right; &left,
/* Top */ &right);
data[2] = borders.visible.top; meta_window_stage_to_protocol_point (window,
/* Bottom */ borders.visible.top,
data[3] = borders.visible.bottom; borders.visible.bottom,
&top,
&bottom);
data[0] = left;
data[1] = right;
data[2] = top;
data[3] = bottom;
meta_topic (META_DEBUG_GEOMETRY, meta_topic (META_DEBUG_GEOMETRY,
"Setting _NET_FRAME_EXTENTS on managed window 0x%lx " "Setting _NET_FRAME_EXTENTS on managed window 0x%lx "
@ -1321,6 +1398,7 @@ meta_window_x11_move_resize_internal (MetaWindow *window,
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
MetaFrameBorders borders; MetaFrameBorders borders;
MtkRectangle client_rect; MtkRectangle client_rect;
MtkRectangle values_rect;
int size_dx, size_dy; int size_dx, size_dy;
XWindowChanges values; XWindowChanges values;
unsigned int mask; unsigned int mask;
@ -1495,11 +1573,12 @@ meta_window_x11_move_resize_internal (MetaWindow *window,
else else
configure_frame_first = size_dx + size_dy >= 0; configure_frame_first = size_dx + size_dy >= 0;
meta_window_stage_to_protocol_rect (window, &client_rect, &values_rect);
values.border_width = 0; values.border_width = 0;
values.x = client_rect.x; values.x = values_rect.x;
values.y = client_rect.y; values.y = values_rect.y;
values.width = client_rect.width; values.width = values_rect.width;
values.height = client_rect.height; values.height = values_rect.height;
mask = 0; mask = 0;
if (is_configure_request && priv->border_width != 0) if (is_configure_request && priv->border_width != 0)
@ -1603,6 +1682,17 @@ meta_window_x11_update_struts (MetaWindow *window)
strut_begin = struts[4+(i*2)]; strut_begin = struts[4+(i*2)];
strut_end = struts[4+(i*2)+1]; strut_end = struts[4+(i*2)+1];
meta_window_protocol_to_stage_point (window,
strut_begin, 0,
&strut_begin, NULL,
MTK_ROUNDING_STRATEGY_SHRINK);
meta_window_protocol_to_stage_point (window,
strut_end,
thickness,
&strut_end,
&thickness,
MTK_ROUNDING_STRATEGY_GROW);
temp = g_new0 (MetaStrut, 1); temp = g_new0 (MetaStrut, 1);
temp->side = 1 << i; /* See MetaSide def. Matches nicely, eh? */ temp->side = 1 << i; /* See MetaSide def. Matches nicely, eh? */
meta_display_get_size (window->display, meta_display_get_size (window->display,
@ -1667,6 +1757,11 @@ meta_window_x11_update_struts (MetaWindow *window)
if (thickness == 0) if (thickness == 0)
continue; continue;
meta_window_protocol_to_stage_point (window,
thickness, 0,
&thickness, NULL,
MTK_ROUNDING_STRATEGY_GROW);
temp = g_new0 (MetaStrut, 1); temp = g_new0 (MetaStrut, 1);
temp->side = 1 << i; temp->side = 1 << i;
meta_display_get_size (window->display, meta_display_get_size (window->display,
@ -2060,9 +2155,10 @@ static void
meta_window_x11_constructed (GObject *object) meta_window_x11_constructed (GObject *object)
{ {
MetaWindow *window = META_WINDOW (object); MetaWindow *window = META_WINDOW (object);
MetaWindowX11 *x11_window = META_WINDOW_X11 (object); MetaWindowX11 *window_x11 = META_WINDOW_X11 (object);
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (x11_window); MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
XWindowAttributes attrs = priv->attributes; XWindowAttributes attrs = priv->attributes;
MtkRectangle rect;
meta_verbose ("attrs->map_state = %d (%s)", meta_verbose ("attrs->map_state = %d (%s)",
attrs.map_state, attrs.map_state,
@ -2077,16 +2173,16 @@ meta_window_x11_constructed (GObject *object)
window->client_type = META_WINDOW_CLIENT_TYPE_X11; window->client_type = META_WINDOW_CLIENT_TYPE_X11;
window->override_redirect = attrs.override_redirect; window->override_redirect = attrs.override_redirect;
window->rect.x = attrs.x; rect = MTK_RECTANGLE_INIT (attrs.x, attrs.y, attrs.width, attrs.height);
window->rect.y = attrs.y; meta_window_protocol_to_stage_rect (window, &rect, &rect);
window->rect.width = attrs.width;
window->rect.height = attrs.height; window->rect = rect;
/* size_hints are the "request" */ /* size_hints are the "request" */
window->size_hints.x = attrs.x; window->size_hints.x = rect.x;
window->size_hints.y = attrs.y; window->size_hints.y = rect.y;
window->size_hints.width = attrs.width; window->size_hints.width = rect.width;
window->size_hints.height = attrs.height; window->size_hints.height = rect.height;
window->depth = attrs.depth; window->depth = attrs.depth;
priv->xvisual = attrs.visual; priv->xvisual = attrs.visual;
@ -2097,11 +2193,12 @@ meta_window_x11_constructed (GObject *object)
priv->frame = NULL; priv->frame = NULL;
window->decorated = TRUE; window->decorated = TRUE;
window->hidden = FALSE; window->hidden = FALSE;
priv->border_width = attrs.border_width;
priv->xclient_leader = None; priv->xclient_leader = None;
priv->keys_grabbed = FALSE; meta_window_protocol_to_stage_point (window,
priv->grab_on_frame = FALSE; attrs.border_width, 0,
&priv->border_width, NULL,
MTK_ROUNDING_STRATEGY_GROW);
g_signal_connect (window, "notify::decorated", g_signal_connect (window, "notify::decorated",
G_CALLBACK (meta_window_x11_update_input_region), G_CALLBACK (meta_window_x11_update_input_region),
@ -2210,6 +2307,8 @@ meta_window_x11_class_init (MetaWindowX11Class *klass)
window_class->calculate_layer = meta_window_x11_calculate_layer; window_class->calculate_layer = meta_window_x11_calculate_layer;
window_class->is_focus_async = meta_window_x11_is_focus_async; window_class->is_focus_async = meta_window_x11_is_focus_async;
window_class->set_transient_for = meta_window_x11_set_transient_for; window_class->set_transient_for = meta_window_x11_set_transient_for;
window_class->stage_to_protocol = meta_window_x11_stage_to_protocol;
window_class->protocol_to_stage = meta_window_x11_protocol_to_stage;
klass->freeze_commits = meta_window_x11_impl_freeze_commits; klass->freeze_commits = meta_window_x11_impl_freeze_commits;
klass->thaw_commits = meta_window_x11_impl_thaw_commits; klass->thaw_commits = meta_window_x11_impl_thaw_commits;
@ -2359,24 +2458,6 @@ meta_window_x11_set_net_wm_state (MetaWindow *window)
update_gtk_edge_constraints (window); update_gtk_edge_constraints (window);
} }
static MtkRegion *
region_create_from_x_rectangles (const XRectangle *rects,
int n_rects)
{
int i;
MtkRectangle *mtk_rects = g_newa (MtkRectangle, n_rects);
for (i = 0; i < n_rects; i++)
{
mtk_rects[i].x = rects[i].x;
mtk_rects[i].y = rects[i].y;
mtk_rects[i].width = rects[i].width;
mtk_rects[i].height = rects[i].height;
}
return mtk_region_create_rectangles (mtk_rects, n_rects);
}
static void static void
meta_window_set_input_region (MetaWindow *window, meta_window_set_input_region (MetaWindow *window,
MtkRegion *region) MtkRegion *region)
@ -2449,15 +2530,16 @@ meta_window_x11_update_input_region (MetaWindow *window)
{ {
/* Translate the set of XShape rectangles that we /* Translate the set of XShape rectangles that we
* get from the X server to a MtkRegion. */ * get from the X server to a MtkRegion. */
XRectangle *rects = NULL; XRectangle *protocol_rects = NULL;
g_autoptr (MtkRectangle) rects = NULL;
int n_rects = -1, ordering; int n_rects = -1, ordering;
mtk_x11_error_trap_push (x11_display->xdisplay); mtk_x11_error_trap_push (x11_display->xdisplay);
rects = XShapeGetRectangles (x11_display->xdisplay, protocol_rects = XShapeGetRectangles (x11_display->xdisplay,
xwindow, xwindow,
ShapeInput, ShapeInput,
&n_rects, &n_rects,
&ordering); &ordering);
mtk_x11_error_trap_pop (x11_display->xdisplay); mtk_x11_error_trap_pop (x11_display->xdisplay);
/* XXX: The X Shape specification is quite unfortunately specified. /* XXX: The X Shape specification is quite unfortunately specified.
@ -2473,6 +2555,9 @@ meta_window_x11_update_input_region (MetaWindow *window)
* hey, it's X11! * hey, it's X11!
*/ */
if (n_rects >= 1)
rects = protocol_rects_to_stage_rects (window, n_rects, protocol_rects);
if (n_rects == -1) if (n_rects == -1)
{ {
/* We had an error. */ /* We had an error. */
@ -2496,10 +2581,10 @@ meta_window_x11_update_input_region (MetaWindow *window)
else else
{ {
/* Window has a custom shape. */ /* Window has a custom shape. */
region = region_create_from_x_rectangles (rects, n_rects); region = mtk_region_create_rectangles (rects, n_rects);
} }
meta_XFree (rects); meta_XFree (protocol_rects);
} }
if (region != NULL) if (region != NULL)
@ -2546,7 +2631,7 @@ meta_window_x11_update_shape_region (MetaWindow *window)
{ {
/* Translate the set of XShape rectangles that we /* Translate the set of XShape rectangles that we
* get from the X server to a MtkRegion. */ * get from the X server to a MtkRegion. */
XRectangle *rects = NULL; XRectangle *protocol_rects = NULL;
int n_rects, ordering; int n_rects, ordering;
int x_bounding, y_bounding, x_clip, y_clip; int x_bounding, y_bounding, x_clip, y_clip;
@ -2562,18 +2647,22 @@ meta_window_x11_update_shape_region (MetaWindow *window)
if (bounding_shaped) if (bounding_shaped)
{ {
rects = XShapeGetRectangles (x11_display->xdisplay, protocol_rects = XShapeGetRectangles (x11_display->xdisplay,
priv->xwindow, priv->xwindow,
ShapeBounding, ShapeBounding,
&n_rects, &n_rects,
&ordering); &ordering);
} }
mtk_x11_error_trap_pop (x11_display->xdisplay); mtk_x11_error_trap_pop (x11_display->xdisplay);
if (rects) if (protocol_rects)
{ {
region = region_create_from_x_rectangles (rects, n_rects); g_autoptr (MtkRectangle) rects = NULL;
XFree (rects);
rects = protocol_rects_to_stage_rects (window, n_rects, protocol_rects);
region = mtk_region_create_rectangles (rects, n_rects);
XFree (protocol_rects);
} }
} }
@ -2959,6 +3048,7 @@ meta_window_x11_configure_request (MetaWindow *window,
{ {
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
MtkRectangle rect;
/* Note that x, y is the corner of the window border, /* Note that x, y is the corner of the window border,
* and width, height is the size of the window inside * and width, height is the size of the window inside
@ -2967,15 +3057,24 @@ meta_window_x11_configure_request (MetaWindow *window,
* requested border here. * requested border here.
*/ */
if (event->xconfigurerequest.value_mask & CWBorderWidth) if (event->xconfigurerequest.value_mask & CWBorderWidth)
priv->border_width = event->xconfigurerequest.border_width; {
meta_window_protocol_to_stage_point (window,
event->xconfigurerequest.border_width, 0,
&priv->border_width, NULL,
MTK_ROUNDING_STRATEGY_GROW);
}
meta_window_move_resize_request(window, rect = MTK_RECTANGLE_INIT (event->xconfigurerequest.x, event->xconfigurerequest.y,
event->xconfigurerequest.value_mask, event->xconfigurerequest.width, event->xconfigurerequest.height);
window->size_hints.win_gravity, meta_window_protocol_to_stage_rect (window, &rect, &rect);
event->xconfigurerequest.x,
event->xconfigurerequest.y, meta_window_move_resize_request (window,
event->xconfigurerequest.width, event->xconfigurerequest.value_mask,
event->xconfigurerequest.height); window->size_hints.win_gravity,
rect.x,
rect.y,
rect.width,
rect.height);
/* Handle stacking. We only handle raises/lowers, mostly because /* Handle stacking. We only handle raises/lowers, mostly because
* stack.c really can't deal with anything else. I guess we'll fix * stack.c really can't deal with anything else. I guess we'll fix
@ -3471,8 +3570,12 @@ meta_window_x11_client_message (MetaWindow *window,
guint32 timestamp; guint32 timestamp;
MetaWindowDrag *window_drag; MetaWindowDrag *window_drag;
x_root = event->xclient.data.l[0]; meta_window_protocol_to_stage_point (window,
y_root = event->xclient.data.l[1]; event->xclient.data.l[0],
event->xclient.data.l[1],
&x_root,
&y_root,
MTK_ROUNDING_STRATEGY_SHRINK);
action = event->xclient.data.l[2]; action = event->xclient.data.l[2];
button = event->xclient.data.l[3]; button = event->xclient.data.l[3];
@ -3636,6 +3739,7 @@ meta_window_x11_client_message (MetaWindow *window,
{ {
MetaGravity gravity; MetaGravity gravity;
guint value_mask; guint value_mask;
MtkRectangle rect;
gravity = (MetaGravity) (event->xclient.data.l[0] & 0xff); gravity = (MetaGravity) (event->xclient.data.l[0] & 0xff);
value_mask = (event->xclient.data.l[0] & 0xf00) >> 8; value_mask = (event->xclient.data.l[0] & 0xf00) >> 8;
@ -3644,13 +3748,19 @@ meta_window_x11_client_message (MetaWindow *window,
if (gravity == 0) if (gravity == 0)
gravity = window->size_hints.win_gravity; gravity = window->size_hints.win_gravity;
rect = MTK_RECTANGLE_INIT (event->xclient.data.l[1],
event->xclient.data.l[2],
event->xclient.data.l[3],
event->xclient.data.l[4]);
meta_window_protocol_to_stage_rect (window, &rect, &rect);
meta_window_move_resize_request(window, meta_window_move_resize_request(window,
value_mask, value_mask,
gravity, gravity,
event->xclient.data.l[1], /* x */ rect.x,
event->xclient.data.l[2], /* y */ rect.y,
event->xclient.data.l[3], /* width */ rect.width,
event->xclient.data.l[4]); /* height */ rect.height);
} }
else if (event->xclient.message_type == else if (event->xclient.message_type ==
x11_display->atom__NET_ACTIVE_WINDOW && x11_display->atom__NET_ACTIVE_WINDOW &&
@ -3707,11 +3817,14 @@ meta_window_x11_client_message (MetaWindow *window,
else if (event->xclient.message_type == else if (event->xclient.message_type ==
x11_display->atom__GTK_SHOW_WINDOW_MENU) x11_display->atom__GTK_SHOW_WINDOW_MENU)
{ {
gulong x, y; int x, y;
/* l[0] is device_id, which we don't use */ /* l[0] is device_id, which we don't use */
x = event->xclient.data.l[1]; meta_window_protocol_to_stage_point (window,
y = event->xclient.data.l[2]; event->xclient.data.l[1],
event->xclient.data.l[2],
&x, &y,
MTK_ROUNDING_STRATEGY_SHRINK);
meta_window_show_menu (window, META_WINDOW_MENU_WM, x, y); meta_window_show_menu (window, META_WINDOW_MENU_WM, x, y);
} }
@ -4237,10 +4350,12 @@ meta_window_x11_configure_notify (MetaWindow *window,
g_assert (window->override_redirect); g_assert (window->override_redirect);
g_assert (priv->frame == NULL); g_assert (priv->frame == NULL);
window->rect.x = event->x; meta_window_protocol_to_stage_rect (window,
window->rect.y = event->y; &MTK_RECTANGLE_INIT (event->x,
window->rect.width = event->width; event->y,
window->rect.height = event->height; event->width,
event->height),
&window->rect);
priv->client_rect = window->rect; priv->client_rect = window->rect;
window->buffer_rect = window->rect; window->buffer_rect = window->rect;