diff --git a/src/meson.build b/src/meson.build index e359610d4..a4fe0850c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -596,6 +596,8 @@ if have_wayland 'wayland/meta-wayland-dnd-surface.h', 'wayland/meta-wayland-filter-manager.c', 'wayland/meta-wayland-filter-manager.h', + 'wayland/meta-wayland-fractional-scale.c', + 'wayland/meta-wayland-fractional-scale.h', 'wayland/meta-wayland-gtk-shell.c', 'wayland/meta-wayland-gtk-shell.h', 'wayland/meta-wayland.h', @@ -1005,6 +1007,7 @@ if have_wayland # - protocol stability ('private', 'stable' or 'unstable') # - protocol version (if stability is 'unstable') wayland_protocols = [ + ['fractional-scale', 'staging', 'v1', ], ['gtk-shell', 'private', ], ['keyboard-shortcuts-inhibit', 'unstable', 'v1', ], ['linux-dmabuf', 'unstable', 'v1', ], diff --git a/src/wayland/meta-wayland-fractional-scale.c b/src/wayland/meta-wayland-fractional-scale.c new file mode 100644 index 000000000..6be75ab44 --- /dev/null +++ b/src/wayland/meta-wayland-fractional-scale.c @@ -0,0 +1,164 @@ +/* + * Wayland Support + * + * Copyright (C) 2022 Robert Mader + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#include "config.h" + +#include "meta-wayland-fractional-scale.h" + +#include + +#include "wayland/meta-wayland-outputs.h" +#include "wayland/meta-wayland-private.h" +#include "wayland/meta-wayland-surface.h" +#include "wayland/meta-wayland-versions.h" + +#include "fractional-scale-v1-server-protocol.h" + +static void +wp_fractional_scale_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface; + + surface = wl_resource_get_user_data (resource); + if (!surface) + return; + + g_clear_signal_handler (&surface->fractional_scale.destroy_handler_id, + surface); + surface->fractional_scale.resource = NULL; +} + +static void +on_surface_destroyed (MetaWaylandSurface *surface) +{ + wl_resource_set_user_data (surface->fractional_scale.resource, NULL); +} + +static void +wp_fractional_scale_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static const struct wp_fractional_scale_v1_interface meta_wayland_fractional_scale_interface = { + wp_fractional_scale_destroy, +}; + +static void +wp_fractional_scale_manager_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +wp_fractional_scale_manager_get_fractional_scale (struct wl_client *client, + struct wl_resource *resource, + uint32_t fractional_scale_id, + struct wl_resource *surface_resource) +{ + MetaWaylandSurface *surface; + struct wl_resource *fractional_scale_resource; + double scale; + + surface = wl_resource_get_user_data (surface_resource); + if (surface->fractional_scale.resource) + { + wl_resource_post_error (resource, + WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, + "fractional scale resource already exists on surface"); + return; + } + + fractional_scale_resource = wl_resource_create (client, + &wp_fractional_scale_v1_interface, + wl_resource_get_version (resource), + fractional_scale_id); + wl_resource_set_implementation (fractional_scale_resource, + &meta_wayland_fractional_scale_interface, + surface, + wp_fractional_scale_destructor); + + surface->fractional_scale.resource = fractional_scale_resource; + surface->fractional_scale.destroy_handler_id = + g_signal_connect (surface, + "destroy", + G_CALLBACK (on_surface_destroyed), + NULL); + + scale = meta_wayland_surface_get_highest_output_scale (surface); + meta_wayland_fractional_scale_maybe_send_preferred_scale (surface, scale); +} + +static const struct wp_fractional_scale_manager_v1_interface meta_wayland_fractional_scale_manager_interface = { + wp_fractional_scale_manager_destroy, + wp_fractional_scale_manager_get_fractional_scale, +}; + +static void +wp_fractional_scale_bind (struct wl_client *client, + void *data, + uint32_t version, + uint32_t id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, + &wp_fractional_scale_manager_v1_interface, + version, + id); + wl_resource_set_implementation (resource, + &meta_wayland_fractional_scale_manager_interface, + data, + NULL); +} + +void +meta_wayland_init_fractional_scale (MetaWaylandCompositor *compositor) +{ + if (wl_global_create (compositor->wayland_display, + &wp_fractional_scale_manager_v1_interface, + META_WP_FRACTIONAL_SCALE_VERSION, + compositor, + wp_fractional_scale_bind) == NULL) + g_error ("Failed to register a global wp_fractional_scale object"); +} + +void +meta_wayland_fractional_scale_maybe_send_preferred_scale (MetaWaylandSurface *surface, + double scale) +{ + uint32_t wire_scale; + + if (!surface->fractional_scale.resource) + return; + + if (G_APPROX_VALUE (scale, 0.0, FLT_EPSILON) || + G_APPROX_VALUE (scale, surface->fractional_scale.scale, FLT_EPSILON)) + return; + + wire_scale = round (scale * 120); + wp_fractional_scale_v1_send_preferred_scale (surface->fractional_scale.resource, + wire_scale); + surface->fractional_scale.scale = scale; +} diff --git a/src/wayland/meta-wayland-fractional-scale.h b/src/wayland/meta-wayland-fractional-scale.h new file mode 100644 index 000000000..0c2105275 --- /dev/null +++ b/src/wayland/meta-wayland-fractional-scale.h @@ -0,0 +1,33 @@ +/* + * Wayland Support + * + * Copyright (C) 2022 Robert Mader + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#ifndef META_WAYLAND_FRACTIONAL_SCALE_H +#define META_WAYLAND_FRACTIONAL_SCALE_H + +#include "wayland/meta-wayland-types.h" + +void meta_wayland_init_fractional_scale (MetaWaylandCompositor *compositor); + +void meta_wayland_fractional_scale_maybe_send_preferred_scale (MetaWaylandSurface *surface, + double scale); + +#endif /* META_WAYLAND_FRACTIONAL_SCALE_H */ diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index e5def80a2..0d64e2d90 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -39,6 +39,7 @@ #include "wayland/meta-wayland-actor-surface.h" #include "wayland/meta-wayland-buffer.h" #include "wayland/meta-wayland-data-device.h" +#include "wayland/meta-wayland-fractional-scale.h" #include "wayland/meta-wayland-gtk-shell.h" #include "wayland/meta-wayland-keyboard.h" #include "wayland/meta-wayland-outputs.h" @@ -1425,15 +1426,45 @@ surface_output_disconnect_signals (gpointer key, surface); } +static void +get_highest_output_scale (gpointer key, + gpointer value, + gpointer data) +{ + MetaWaylandOutput *wayland_output = value; + MetaLogicalMonitor *logical_monitor = + meta_wayland_output_get_logical_monitor (wayland_output); + double *scale = data; + double new_scale; + + new_scale = meta_logical_monitor_get_scale (logical_monitor); + if (new_scale > *scale) + *scale = new_scale; +} + +double +meta_wayland_surface_get_highest_output_scale (MetaWaylandSurface *surface) +{ + double scale = 0.0; + + g_hash_table_foreach (surface->outputs, get_highest_output_scale, &scale); + return scale; +} + void meta_wayland_surface_update_outputs (MetaWaylandSurface *surface) { + double scale; + if (!surface->compositor) return; g_hash_table_foreach (surface->compositor->outputs, update_surface_output_state, surface); + + scale = meta_wayland_surface_get_highest_output_scale (surface); + meta_wayland_fractional_scale_maybe_send_preferred_scale (surface, scale); } void @@ -1594,6 +1625,7 @@ meta_wayland_shell_init (MetaWaylandCompositor *compositor) meta_wayland_xdg_shell_init (compositor); meta_wayland_init_gtk_shell (compositor); meta_wayland_init_viewporter (compositor); + meta_wayland_init_fractional_scale (compositor); } void diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index a183447fc..e83dd5599 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -233,6 +233,14 @@ struct _MetaWaylandSurface int dst_height; } viewport; + /* wp_fractional_scale */ + struct { + struct wl_resource *resource; + gulong destroy_handler_id; + + double scale; + } fractional_scale; + /* table of seats for which shortcuts are inhibited */ GHashTable *shortcut_inhibited_seats; @@ -313,6 +321,8 @@ void meta_wayland_surface_drag_dest_focus_out (MetaWaylandSurface void meta_wayland_surface_drag_dest_drop (MetaWaylandSurface *surface); void meta_wayland_surface_drag_dest_update (MetaWaylandSurface *surface); +double meta_wayland_surface_get_highest_output_scale (MetaWaylandSurface *surface); + void meta_wayland_surface_update_outputs (MetaWaylandSurface *surface); MetaWaylandSurface *meta_wayland_surface_get_toplevel (MetaWaylandSurface *surface); diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h index 22773ad03..2323d3407 100644 --- a/src/wayland/meta-wayland-versions.h +++ b/src/wayland/meta-wayland-versions.h @@ -58,5 +58,6 @@ #define META_XDG_ACTIVATION_V1_VERSION 1 #define META_WP_SINGLE_PIXEL_BUFFER_V1_VERSION 1 #define META_MUTTER_X11_INTEROP_VERSION 1 +#define META_WP_FRACTIONAL_SCALE_VERSION 1 #endif