diff --git a/BUILD.gn b/BUILD.gn
index c6552f9..1727cee 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -40,6 +40,7 @@ if (!defined(dark_frame_color)) {
wayland_protocols = [
"protocol/aura-shell.xml",
"protocol/drm.xml",
+ "protocol/fractional-scale-v1.xml",
"protocol/gaming-input-unstable-v2.xml",
"protocol/gtk-shell.xml",
"protocol/keyboard-extension-unstable-v1.xml",
@@ -107,6 +108,7 @@ static_library("libsommelier") {
"sommelier-ctx.cc",
"sommelier-data-device-manager.cc",
"sommelier-display.cc",
+ "sommelier-fractional-scale.cc",
"sommelier-global.cc",
"sommelier-gtk-shell.cc",
"sommelier-inpututils.cc",
diff --git a/meson.build b/meson.build
index ffd6884..0bd66c3 100644
--- a/meson.build
+++ b/meson.build
@@ -39,6 +39,7 @@ wl_generators = [
wl_protocols = [
'protocol/aura-shell.xml',
'protocol/drm.xml',
+ 'protocol/fractional-scale-v1.xml',
'protocol/gaming-input-unstable-v2.xml',
'protocol/gtk-shell.xml',
'protocol/keyboard-extension-unstable-v1.xml',
@@ -155,6 +156,7 @@ libsommelier = static_library('sommelier',
'sommelier-ctx.cc',
'sommelier-data-device-manager.cc',
'sommelier-display.cc',
+ 'sommelier-fractional-scale.cc',
'sommelier-gtk-shell.cc',
'sommelier-global.cc',
'sommelier-inpututils.cc',
diff --git a/protocol/fractional-scale-v1.xml b/protocol/fractional-scale-v1.xml
new file mode 100644
index 0000000..350bfc0
--- /dev/null
+++ b/protocol/fractional-scale-v1.xml
@@ -0,0 +1,102 @@
+
+
+
+ Copyright © 2022 Kenny Levinsen
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+
+
+ This protocol allows a compositor to suggest for surfaces to render at
+ fractional scales.
+
+ A client can submit scaled content by utilizing wp_viewport. This is done by
+ creating a wp_viewport object for the surface and setting the destination
+ rectangle to the surface size before the scale factor is applied.
+
+ The buffer size is calculated by multiplying the surface size by the
+ intended scale.
+
+ The wl_surface buffer scale should remain set to 1.
+
+ If a surface has a surface-local size of 100 px by 50 px and wishes to
+ submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should
+ be used and the wp_viewport destination rectangle should be 100 px by 50 px.
+
+ For toplevel surfaces, the size is rounded halfway away from zero. The
+ rounding algorithm for subsurface position and size is not defined.
+
+
+
+
+ A global interface for requesting surfaces to use fractional scales.
+
+
+
+
+ Informs the server that the client will not be using this protocol
+ object anymore. This does not affect any other objects,
+ wp_fractional_scale_v1 objects included.
+
+
+
+
+
+
+
+
+
+ Create an add-on object for the the wl_surface to let the compositor
+ request fractional scales. If the given wl_surface already has a
+ wp_fractional_scale_v1 object associated, the fractional_scale_exists
+ protocol error is raised.
+
+
+
+
+
+
+
+
+ An additional interface to a wl_surface object which allows the compositor
+ to inform the client of the preferred scale.
+
+
+
+
+ Destroy the fractional scale object. When this object is destroyed,
+ preferred_scale events will no longer be sent.
+
+
+
+
+
+ Notification of a new preferred scale for this surface that the
+ compositor suggests that the client should use.
+
+ The sent scale is the numerator of a fraction with a denominator of 120.
+
+
+
+
+
diff --git a/sommelier-ctx.cc b/sommelier-ctx.cc
index 0a6c6cc..b763024 100644
--- a/sommelier-ctx.cc
+++ b/sommelier-ctx.cc
@@ -113,6 +113,7 @@ void sl_context_init_default(struct sl_context* ctx) {
ctx->text_input_manager = nullptr;
ctx->text_input_extension = nullptr;
ctx->xdg_output_manager = nullptr;
+ ctx->fractional_scale_manager = nullptr;
#ifdef GAMEPAD_SUPPORT
ctx->gaming_input_manager = nullptr;
ctx->gaming_seat = nullptr;
diff --git a/sommelier-ctx.h b/sommelier-ctx.h
index 41ca57e..3aa97a9 100644
--- a/sommelier-ctx.h
+++ b/sommelier-ctx.h
@@ -94,6 +94,7 @@ struct sl_context {
struct sl_stylus_input_manager* stylus_input_manager;
struct sl_relative_pointer_manager* relative_pointer_manager;
struct sl_pointer_constraints* pointer_constraints;
+ struct sl_fractional_scale_manager* fractional_scale_manager;
struct wl_list outputs;
struct wl_list seats;
std::unique_ptr display_event_source;
diff --git a/sommelier-fractional-scale.cc b/sommelier-fractional-scale.cc
new file mode 100644
index 0000000..bef9440
--- /dev/null
+++ b/sommelier-fractional-scale.cc
@@ -0,0 +1,136 @@
+// Copyright 2023 The ChromiumOS Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sommelier.h" // NOLINT(build/include_directory)
+#include "sommelier-tracing.h" // NOLINT(build/include_directory)
+
+#include
+#include
+
+#include "fractional-scale-v1-client-protocol.h" // NOLINT(build/include_directory)
+#include "fractional-scale-v1-server-protocol.h" // NOLINT(build/include_directory)
+
+struct sl_host_fractional_scale_manager {
+ struct sl_fractional_scale_manager* fractional_scale_manager;
+ struct wl_resource* resource;
+ struct wp_fractional_scale_manager_v1* proxy;
+};
+
+struct sl_host_fractional_scale {
+ struct sl_host_fractional_scale_manager* host_fractional_scale_manager;
+ struct wl_resource* resource;
+ struct wp_fractional_scale_v1* proxy;
+};
+
+static void sl_fractional_scale_destroy(struct wl_client* client,
+ struct wl_resource* resource) {
+ wl_resource_destroy(resource);
+}
+
+static void sl_fractional_scale_handle_preferred_scale(
+ void* data,
+ struct wp_fractional_scale_v1* fractional_scale,
+ uint32_t wire_scale) {
+ struct sl_host_fractional_scale* host_fractional_scale =
+ static_cast(
+ wp_fractional_scale_v1_get_user_data(fractional_scale));
+ struct sl_fractional_scale_manager* fractional_scale_manager =
+ host_fractional_scale->host_fractional_scale_manager
+ ->fractional_scale_manager;
+
+ wp_fractional_scale_v1_send_preferred_scale(
+ host_fractional_scale->resource,
+ round(wire_scale / fractional_scale_manager->ctx->scale));
+}
+
+static const struct wp_fractional_scale_v1_listener fractional_scale_listener =
+ {
+ .preferred_scale = sl_fractional_scale_handle_preferred_scale,
+};
+
+static const struct wp_fractional_scale_v1_interface
+ sl_fractional_scale_implementation = {sl_fractional_scale_destroy};
+
+static void sl_destroy_host_fractional_scale(struct wl_resource* resource) {
+ struct sl_host_fractional_scale* host =
+ static_cast(
+ wl_resource_get_user_data(resource));
+
+ wl_resource_set_user_data(resource, nullptr);
+ delete host;
+}
+
+static void sl_fractional_scale_manager_destroy(struct wl_client* client,
+ struct wl_resource* resource) {
+ wl_resource_destroy(resource);
+}
+
+static void sl_fractional_scale_manager_get_fractional_scale(
+ struct wl_client* client,
+ struct wl_resource* resource,
+ uint32_t id,
+ struct wl_resource* surface_resource) {
+ struct sl_host_fractional_scale_manager* host =
+ static_cast(
+ wl_resource_get_user_data(resource));
+ struct sl_host_surface* host_surface = static_cast(
+ wl_resource_get_user_data(surface_resource));
+ struct sl_host_fractional_scale* host_fractional_scale =
+ new sl_host_fractional_scale();
+
+ host_fractional_scale->host_fractional_scale_manager = host;
+ host_fractional_scale->resource =
+ wl_resource_create(client, &wp_fractional_scale_v1_interface, 1, id);
+ host_fractional_scale->proxy =
+ wp_fractional_scale_manager_v1_get_fractional_scale(
+ host->fractional_scale_manager->internal, host_surface->proxy);
+ wp_fractional_scale_v1_add_listener(host_fractional_scale->proxy,
+ &fractional_scale_listener,
+ host_fractional_scale);
+ wl_resource_set_implementation(
+ host_fractional_scale->resource, &sl_fractional_scale_implementation,
+ host_fractional_scale, sl_destroy_host_fractional_scale);
+}
+
+static const struct wp_fractional_scale_manager_v1_interface
+ sl_wp_fractional_scale_manager_implementation = {
+ sl_fractional_scale_manager_destroy,
+ sl_fractional_scale_manager_get_fractional_scale,
+};
+
+static void sl_destroy_host_fractional_scale_manager(
+ struct wl_resource* resource) {
+ struct sl_host_fractional_scale_manager* host =
+ static_cast(
+ wl_resource_get_user_data(resource));
+
+ wp_fractional_scale_manager_v1_destroy(host->proxy);
+ wl_resource_set_user_data(resource, nullptr);
+ delete host;
+}
+
+static void sl_bind_host_fractional_scale_manager(struct wl_client* client,
+ void* data,
+ uint32_t version,
+ uint32_t id) {
+ struct sl_context* ctx = (struct sl_context*)data;
+ struct sl_host_fractional_scale_manager* host =
+ new sl_host_fractional_scale_manager();
+ host->fractional_scale_manager = ctx->fractional_scale_manager;
+ host->resource = wl_resource_create(
+ client, &wp_fractional_scale_manager_v1_interface, 1, id);
+ wl_resource_set_implementation(
+ host->resource, &sl_wp_fractional_scale_manager_implementation, host,
+ sl_destroy_host_fractional_scale_manager);
+ host->proxy = static_cast(wl_registry_bind(
+ wl_display_get_registry(ctx->display), ctx->fractional_scale_manager->id,
+ &wp_fractional_scale_manager_v1_interface, 1));
+ wp_fractional_scale_manager_v1_set_user_data(host->proxy, host);
+}
+
+struct sl_global* sl_fractional_scale_manager_global_create(
+ struct sl_context* ctx) {
+ return sl_global_create(ctx, &wp_fractional_scale_manager_v1_interface, 1,
+ ctx, sl_bind_host_fractional_scale_manager);
+}
diff --git a/sommelier.cc b/sommelier.cc
index 5997558..6ffd279 100644
--- a/sommelier.cc
+++ b/sommelier.cc
@@ -40,6 +40,7 @@
#include "aura-shell-client-protocol.h" // NOLINT(build/include_directory)
#include "drm-server-protocol.h" // NOLINT(build/include_directory)
+#include "fractional-scale-v1-client-protocol.h" // NOLINT(build/include_directory)
#ifdef GAMEPAD_SUPPORT
#include "gaming-input-unstable-v2-client-protocol.h" // NOLINT(build/include_directory)
#endif
@@ -774,6 +775,22 @@ void sl_registry_handler(void* data,
static_cast(wl_registry_bind(
registry, id, &zxdg_output_manager_v1_interface, MIN(3, version)));
ctx->xdg_output_manager = output_manager;
+ } else if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) ==
+ 0) {
+ struct sl_fractional_scale_manager* fractional_scale_manager =
+ static_cast(
+ malloc(sizeof(struct sl_fractional_scale_manager)));
+ assert(fractional_scale_manager);
+ fractional_scale_manager->ctx = ctx;
+ fractional_scale_manager->id = id;
+ fractional_scale_manager->host_fractional_scale_manager_global = nullptr;
+ fractional_scale_manager->internal =
+ static_cast(wl_registry_bind(
+ registry, id, &wp_fractional_scale_manager_v1_interface, 1));
+ assert(!ctx->fractional_scale_manager);
+ ctx->fractional_scale_manager = fractional_scale_manager;
+ fractional_scale_manager->host_fractional_scale_manager_global =
+ sl_fractional_scale_manager_global_create(ctx);
}
}
diff --git a/sommelier.h b/sommelier.h
index 323fc55..e630c32 100644
--- a/sommelier.h
+++ b/sommelier.h
@@ -53,6 +53,7 @@ struct sl_pointer_constraints;
struct sl_window;
struct sl_host_surface;
struct sl_host_output;
+struct sl_fractional_scale_manager;
struct zaura_shell;
struct zcr_keyboard_extension_v1;
struct zxdg_output_manager_v1;
@@ -137,6 +138,10 @@ struct sl_viewport {
int32_t dst_height;
};
+struct sl_fractional_scale {
+ struct wl_list link;
+};
+
struct sl_host_callback {
struct wl_resource* resource;
struct wl_callback* proxy;
@@ -401,6 +406,13 @@ struct sl_linux_explicit_synchronization {
struct zwp_linux_explicit_synchronization_v1* internal;
};
+struct sl_fractional_scale_manager {
+ struct sl_context* ctx;
+ uint32_t id;
+ struct sl_global* host_fractional_scale_manager_global;
+ struct wp_fractional_scale_manager_v1* internal;
+};
+
struct sl_global {
struct sl_context* ctx;
const struct wl_interface* interface;
@@ -518,6 +530,9 @@ struct sl_global* sl_text_input_crostini_manager_global_create(
struct sl_global* sl_pointer_constraints_global_create(struct sl_context* ctx);
+struct sl_global* sl_fractional_scale_manager_global_create(
+ struct sl_context* ctx);
+
void sl_set_display_implementation(struct sl_context* ctx,
struct wl_client* client);