aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wlr/types/wlr_fractional_scale_v1.h34
-rw-r--r--protocol/meson.build1
-rw-r--r--types/meson.build1
-rw-r--r--types/wlr_fractional_scale_v1.c206
4 files changed, 242 insertions, 0 deletions
diff --git a/include/wlr/types/wlr_fractional_scale_v1.h b/include/wlr/types/wlr_fractional_scale_v1.h
new file mode 100644
index 00000000..9126360d
--- /dev/null
+++ b/include/wlr/types/wlr_fractional_scale_v1.h
@@ -0,0 +1,34 @@
+/*
+ * This an unstable interface of wlroots. No guarantees are made regarding the
+ * future consistency of this API.
+ */
+#ifndef WLR_USE_UNSTABLE
+#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
+#endif
+
+#ifndef WLR_TYPES_WLR_FRACTIONAL_SCALE_V1_H
+#define WLR_TYPES_WLR_FRACTIONAL_SCALE_V1_H
+
+#include <wayland-server-core.h>
+
+struct wlr_surface;
+
+struct wlr_fractional_scale_manager_v1 {
+ struct wl_global *global;
+
+ struct {
+ struct wl_signal destroy;
+ } events;
+
+ // private state
+
+ struct wl_listener display_destroy;
+};
+
+void wlr_fractional_scale_v1_notify_scale(
+ struct wlr_surface *surface, double scale);
+
+struct wlr_fractional_scale_manager_v1 *wlr_fractional_scale_manager_v1_create(
+ struct wl_display *display, uint32_t version);
+
+#endif
diff --git a/protocol/meson.build b/protocol/meson.build
index 965dc342..f4a91b94 100644
--- a/protocol/meson.build
+++ b/protocol/meson.build
@@ -22,6 +22,7 @@ protocols = {
'drm-lease-v1': wl_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml',
'ext-idle-notify-v1': wl_protocol_dir / 'staging/ext-idle-notify/ext-idle-notify-v1.xml',
'ext-session-lock-v1': wl_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1.xml',
+ 'fractional-scale-v1': wl_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml',
'single-pixel-buffer-v1': wl_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml',
'xdg-activation-v1': wl_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml',
'xwayland-shell-v1': wl_protocol_dir / 'staging/xwayland-shell/xwayland-shell-v1.xml',
diff --git a/types/meson.build b/types/meson.build
index 5bc217eb..bcf1073b 100644
--- a/types/meson.build
+++ b/types/meson.build
@@ -73,6 +73,7 @@ wlr_files += files(
'wlr_shm.c',
'wlr_single_pixel_buffer_v1.c',
'wlr_subcompositor.c',
+ 'wlr_fractional_scale_v1.c',
'wlr_switch.c',
'wlr_tablet_pad.c',
'wlr_tablet_tool.c',
diff --git a/types/wlr_fractional_scale_v1.c b/types/wlr_fractional_scale_v1.c
new file mode 100644
index 00000000..d9852758
--- /dev/null
+++ b/types/wlr_fractional_scale_v1.c
@@ -0,0 +1,206 @@
+#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
+#include <stdlib.h>
+#include <wlr/types/wlr_compositor.h>
+#include <wlr/types/wlr_fractional_scale_v1.h>
+#include <wlr/util/log.h>
+
+#include "fractional-scale-v1-protocol.h"
+
+#define FRACTIONAL_SCALE_VERSION 1
+
+struct wlr_fractional_scale_v1 {
+ struct wl_resource *resource;
+ struct wlr_addon addon;
+
+ // Used for dummy objects to store scale
+ double scale;
+};
+
+static const struct wp_fractional_scale_v1_interface fractional_scale_interface;
+
+static struct wlr_fractional_scale_v1 *fractional_scale_from_resource(
+ struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource,
+ &wp_fractional_scale_v1_interface, &fractional_scale_interface));
+ return wl_resource_get_user_data(resource);
+}
+
+static const struct wp_fractional_scale_manager_v1_interface scale_manager_interface;
+
+static void fractional_scale_destroy(struct wlr_fractional_scale_v1 *info) {
+ if (info == NULL) {
+ return;
+ }
+
+ // If this is a dummy object then we do not have a wl_resource
+ if (info->resource != NULL) {
+ wl_resource_set_user_data(info->resource, NULL);
+ }
+ wlr_addon_finish(&info->addon);
+ free(info);
+}
+
+static void fractional_scale_handle_resource_destroy(struct wl_resource *resource) {
+ struct wlr_fractional_scale_v1 *info = fractional_scale_from_resource(resource);
+ fractional_scale_destroy(info);
+}
+
+static void fractional_scale_handle_destroy(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static const struct wp_fractional_scale_v1_interface fractional_scale_interface = {
+ .destroy = fractional_scale_handle_destroy,
+};
+
+static void fractional_scale_addon_destroy(struct wlr_addon *addon) {
+ struct wlr_fractional_scale_v1 *info = wl_container_of(addon, info, addon);
+ fractional_scale_destroy(info);
+}
+
+static const struct wlr_addon_interface fractional_scale_addon_impl = {
+ .name = "wlr_fractional_scale_v1",
+ .destroy = fractional_scale_addon_destroy,
+};
+
+static uint32_t double_to_v120(double d) {
+ return round(d * 120);
+}
+
+void wlr_fractional_scale_v1_notify_scale(struct wlr_surface *surface, double scale) {
+ struct wlr_addon *addon = wlr_addon_find(&surface->addons,
+ NULL, &fractional_scale_addon_impl);
+
+ if (addon == NULL) {
+ // Create a dummy object to store the scale
+ struct wlr_fractional_scale_v1 *info = calloc(1, sizeof(*info));
+ if (info == NULL) {
+ return;
+ }
+
+ wlr_addon_init(&info->addon, &surface->addons, NULL, &fractional_scale_addon_impl);
+ info->scale = scale;
+ return;
+ }
+
+ struct wlr_fractional_scale_v1 *info = wl_container_of(addon, info, addon);
+ if (info->scale == scale) {
+ return;
+ }
+
+ info->scale = scale;
+
+ if (!info->resource) {
+ // Update existing dummy object
+ return;
+ }
+
+ wp_fractional_scale_v1_send_preferred_scale(info->resource, double_to_v120(scale));
+}
+
+static void handle_get_fractional_scale(struct wl_client *client,
+ struct wl_resource *mgr_resource, uint32_t id,
+ struct wl_resource *surface_resource) {
+ struct wlr_surface *surface = wlr_surface_from_resource(surface_resource);
+ struct wlr_fractional_scale_v1 *info = NULL;
+
+ // If no fractional_scale object had been created but scale had been set, then
+ // there will be a dummy object for us to fill out with a resource. Check if
+ // that's the case.
+ struct wlr_addon *addon = wlr_addon_find(&surface->addons, NULL, &fractional_scale_addon_impl);
+
+ if (addon != NULL) {
+ info = wl_container_of(addon, info, addon);
+ if (info->resource != NULL) {
+ wl_resource_post_error(mgr_resource,
+ WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS,
+ "a surface scale object for that surface already exists");
+ return;
+ }
+ }
+
+ if (info == NULL) {
+ info = calloc(1, sizeof(*info));
+ if (info == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wlr_addon_init(&info->addon, &surface->addons, NULL, &fractional_scale_addon_impl);
+ }
+
+ uint32_t version = wl_resource_get_version(mgr_resource);
+ info->resource = wl_resource_create(client, &wp_fractional_scale_v1_interface, version, id);
+ if (info->resource == NULL) {
+ wl_client_post_no_memory(client);
+ fractional_scale_destroy(info);
+ return;
+ }
+ wl_resource_set_implementation(info->resource,
+ &fractional_scale_interface, info,
+ fractional_scale_handle_resource_destroy);
+
+ if (info->scale != 0) {
+ wp_fractional_scale_v1_send_preferred_scale(info->resource, double_to_v120(info->scale));
+ }
+}
+
+static void fractional_scale_manager_handle_destroy(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static const struct wp_fractional_scale_manager_v1_interface scale_manager_interface = {
+ .destroy = fractional_scale_manager_handle_destroy,
+ .get_fractional_scale = handle_get_fractional_scale,
+};
+
+static void fractional_scale_manager_bind(struct wl_client *client, void *data,
+ uint32_t version, uint32_t id) {
+ struct wlr_fractional_scale_manager_v1 *mgr = data;
+
+ struct wl_resource *resource = wl_resource_create(client,
+ &wp_fractional_scale_manager_v1_interface, version, id);
+ if (resource == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+ wl_resource_set_implementation(resource, &scale_manager_interface, mgr, NULL);
+}
+
+static void handle_display_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_fractional_scale_manager_v1 *mgr =
+ wl_container_of(listener, mgr, display_destroy);
+ wl_signal_emit_mutable(&mgr->events.destroy, NULL);
+ assert(wl_list_empty(&mgr->events.destroy.listener_list));
+ wl_list_remove(&mgr->display_destroy.link);
+ free(mgr);
+}
+
+struct wlr_fractional_scale_manager_v1 *wlr_fractional_scale_manager_v1_create(
+ struct wl_display *display, uint32_t version) {
+ assert(version <= FRACTIONAL_SCALE_VERSION);
+
+ struct wlr_fractional_scale_manager_v1 *mgr = calloc(1, sizeof(*mgr));
+ if (mgr == NULL) {
+ return NULL;
+ }
+
+ mgr->global = wl_global_create(display,
+ &wp_fractional_scale_manager_v1_interface,
+ version, mgr, fractional_scale_manager_bind);
+ if (mgr->global == NULL) {
+ free(mgr);
+ return NULL;
+ }
+
+ mgr->display_destroy.notify = handle_display_destroy;
+ wl_display_add_destroy_listener(display, &mgr->display_destroy);
+
+ wl_signal_init(&mgr->events.destroy);
+
+ return mgr;
+}
+