aboutsummaryrefslogtreecommitdiff
path: root/src/CursorTrackerWayland.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/CursorTrackerWayland.cpp')
-rw-r--r--src/CursorTrackerWayland.cpp510
1 files changed, 0 insertions, 510 deletions
diff --git a/src/CursorTrackerWayland.cpp b/src/CursorTrackerWayland.cpp
deleted file mode 100644
index 5f37d0a..0000000
--- a/src/CursorTrackerWayland.cpp
+++ /dev/null
@@ -1,510 +0,0 @@
-#include "../include/CursorTrackerWayland.hpp"
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-#include <wayland-client.h>
-#include "xdg-output-unstable-v1-client-protocol.h"
-
-namespace gsr {
- static const int MAX_CONNECTORS = 32;
- static const int CONNECTOR_TYPE_COUNTS = 32;
- static const uint32_t plane_property_all = 0xF;
-
- typedef struct {
- int type;
- int count;
- } drm_connector_type_count;
-
- typedef enum {
- PLANE_PROPERTY_CRTC_X = 1 << 0,
- PLANE_PROPERTY_CRTC_Y = 1 << 1,
- PLANE_PROPERTY_CRTC_ID = 1 << 2,
- PLANE_PROPERTY_TYPE_CURSOR = 1 << 3,
- } plane_property_mask;
-
- typedef struct {
- uint64_t crtc_id;
- mgl::vec2i size;
- } drm_connector;
-
- typedef struct {
- drm_connector connectors[MAX_CONNECTORS];
- int num_connectors;
- } drm_connectors;
-
- /* Returns plane_property_mask */
- static uint32_t plane_get_properties(int drm_fd, uint32_t plane_id, int *crtc_x, int *crtc_y, int *crtc_id, bool *is_cursor) {
- *crtc_x = 0;
- *crtc_y = 0;
- *crtc_id = 0;
- *is_cursor = false;
-
- uint32_t property_mask = 0;
-
- drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_fd, plane_id, DRM_MODE_OBJECT_PLANE);
- if(!props)
- return property_mask;
-
- for(uint32_t i = 0; i < props->count_props; ++i) {
- drmModePropertyPtr prop = drmModeGetProperty(drm_fd, props->props[i]);
- if(!prop)
- continue;
-
- // SRC_* values are fixed 16.16 points
- const uint32_t type = prop->flags & (DRM_MODE_PROP_LEGACY_TYPE | DRM_MODE_PROP_EXTENDED_TYPE);
- if((type & DRM_MODE_PROP_SIGNED_RANGE) && strcmp(prop->name, "CRTC_X") == 0) {
- *crtc_x = (int)props->prop_values[i];
- property_mask |= PLANE_PROPERTY_CRTC_X;
- } else if((type & DRM_MODE_PROP_SIGNED_RANGE) && strcmp(prop->name, "CRTC_Y") == 0) {
- *crtc_y = (int)props->prop_values[i];
- property_mask |= PLANE_PROPERTY_CRTC_Y;
- } else if((type & DRM_MODE_PROP_OBJECT) && strcmp(prop->name, "CRTC_ID") == 0) {
- *crtc_id = (int)props->prop_values[i];
- property_mask |= PLANE_PROPERTY_CRTC_ID;
- } else if((type & DRM_MODE_PROP_ENUM) && strcmp(prop->name, "type") == 0) {
- const uint64_t current_enum_value = props->prop_values[i];
- for(int j = 0; j < prop->count_enums; ++j) {
- if(prop->enums[j].value == current_enum_value && strcmp(prop->enums[j].name, "Cursor") == 0) {
- property_mask |= PLANE_PROPERTY_TYPE_CURSOR;
- break;
- }
- }
- }
-
- drmModeFreeProperty(prop);
- }
-
- drmModeFreeObjectProperties(props);
- return property_mask;
- }
-
- static bool connector_get_property_by_name(int drm_fd, drmModeConnectorPtr props, const char *name, uint64_t *result) {
- for(int i = 0; i < props->count_props; ++i) {
- drmModePropertyPtr prop = drmModeGetProperty(drm_fd, props->props[i]);
- if(!prop)
- continue;
-
- if(strcmp(name, prop->name) == 0) {
- *result = props->prop_values[i];
- drmModeFreeProperty(prop);
- return true;
- }
- drmModeFreeProperty(prop);
- }
- return false;
- }
-
- static drm_connector_type_count* drm_connector_types_get_index(drm_connector_type_count *type_counts, int *num_type_counts, int connector_type) {
- for(int i = 0; i < *num_type_counts; ++i) {
- if(type_counts[i].type == connector_type)
- return &type_counts[i];
- }
-
- if(*num_type_counts == CONNECTOR_TYPE_COUNTS)
- return NULL;
-
- const int index = *num_type_counts;
- type_counts[index].type = connector_type;
- type_counts[index].count = 0;
- ++*num_type_counts;
- return &type_counts[index];
- }
-
- // Note: this monitor name logic is kept in sync with gpu screen recorder
- static std::string get_monitor_name_from_crtc_id(int drm_fd, uint32_t crtc_id) {
- std::string result;
- drmModeResPtr resources = drmModeGetResources(drm_fd);
- if(!resources)
- return result;
-
- drm_connector_type_count type_counts[CONNECTOR_TYPE_COUNTS];
- int num_type_counts = 0;
-
- for(int i = 0; i < resources->count_connectors; ++i) {
- uint64_t connector_crtc_id = 0;
- drmModeConnectorPtr connector = drmModeGetConnectorCurrent(drm_fd, resources->connectors[i]);
- if(!connector)
- continue;
-
- drm_connector_type_count *connector_type = drm_connector_types_get_index(type_counts, &num_type_counts, connector->connector_type);
- const char *connection_name = drmModeGetConnectorTypeName(connector->connector_type);
- if(connector_type)
- ++connector_type->count;
-
- if(connector->connection != DRM_MODE_CONNECTED)
- goto next;
-
- if(connector_type && connector_get_property_by_name(drm_fd, connector, "CRTC_ID", &connector_crtc_id) && connector_crtc_id == crtc_id) {
- result = connection_name;
- result += "-";
- result += std::to_string(connector_type->count);
- drmModeFreeConnector(connector);
- break;
- }
-
- next:
- drmModeFreeConnector(connector);
- }
-
- drmModeFreeResources(resources);
- return result;
- }
-
- // Name is the crtc name. TODO: verify if this works on all wayland compositors
- static const WaylandOutput* get_wayland_monitor_by_name(const std::vector<WaylandOutput> &monitors, const std::string &name) {
- for(const WaylandOutput &monitor : monitors) {
- if(monitor.name == name)
- return &monitor;
- }
- return nullptr;
- }
-
- static WaylandOutput* get_wayland_monitor_by_output(CursorTrackerWayland &cursor_tracker_wayland, struct wl_output *output) {
- for(WaylandOutput &monitor : cursor_tracker_wayland.monitors) {
- if(monitor.output == output)
- return &monitor;
- }
- return nullptr;
- }
-
- static void output_handle_geometry(void *data, struct wl_output *wl_output,
- int32_t x, int32_t y, int32_t phys_width, int32_t phys_height,
- int32_t subpixel, const char *make, const char *model,
- int32_t transform) {
- (void)wl_output;
- (void)phys_width;
- (void)phys_height;
- (void)subpixel;
- (void)make;
- (void)model;
- CursorTrackerWayland *cursor_tracker_wayland = (CursorTrackerWayland*)data;
- WaylandOutput *monitor = get_wayland_monitor_by_output(*cursor_tracker_wayland, wl_output);
- if(!monitor)
- return;
-
- monitor->pos.x = x;
- monitor->pos.y = y;
- monitor->transform = transform;
- }
-
- static void output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
- (void)wl_output;
- (void)flags;
- (void)refresh;
- CursorTrackerWayland *cursor_tracker_wayland = (CursorTrackerWayland*)data;
- WaylandOutput *monitor = get_wayland_monitor_by_output(*cursor_tracker_wayland, wl_output);
- if(!monitor)
- return;
-
- monitor->size.x = width;
- monitor->size.y = height;
- }
-
- static void output_handle_done(void *data, struct wl_output *wl_output) {
- (void)data;
- (void)wl_output;
- }
-
- static void output_handle_scale(void* data, struct wl_output *wl_output, int32_t factor) {
- (void)data;
- (void)wl_output;
- (void)factor;
- }
-
- static void output_handle_name(void *data, struct wl_output *wl_output, const char *name) {
- (void)wl_output;
- CursorTrackerWayland *cursor_tracker_wayland = (CursorTrackerWayland*)data;
- WaylandOutput *monitor = get_wayland_monitor_by_output(*cursor_tracker_wayland, wl_output);
- if(!monitor)
- return;
-
- monitor->name = name;
- }
-
- static void output_handle_description(void *data, struct wl_output *wl_output, const char *description) {
- (void)data;
- (void)wl_output;
- (void)description;
- }
-
- static const struct wl_output_listener output_listener = {
- output_handle_geometry,
- output_handle_mode,
- output_handle_done,
- output_handle_scale,
- output_handle_name,
- output_handle_description,
- };
-
- static void registry_add_object(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) {
- (void)version;
- CursorTrackerWayland *cursor_tracker_wayland = (CursorTrackerWayland*)data;
- if(strcmp(interface, wl_output_interface.name) == 0) {
- if(version < 4) {
- fprintf(stderr, "Warning: wl output interface version is < 4, expected >= 4\n");
- return;
- }
-
- struct wl_output *output = (struct wl_output*)wl_registry_bind(registry, name, &wl_output_interface, 4);
- cursor_tracker_wayland->monitors.push_back(
- WaylandOutput{
- name,
- output,
- nullptr,
- mgl::vec2i{0, 0},
- mgl::vec2i{0, 0},
- 0,
- ""
- });
- wl_output_add_listener(output, &output_listener, cursor_tracker_wayland);
- } else if(strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
- if(version < 1) {
- fprintf(stderr, "Warning: xdg output interface version is < 1, expected >= 1\n");
- return;
- }
-
- if(cursor_tracker_wayland->xdg_output_manager) {
- zxdg_output_manager_v1_destroy(cursor_tracker_wayland->xdg_output_manager);
- cursor_tracker_wayland->xdg_output_manager = NULL;
- }
- cursor_tracker_wayland->xdg_output_manager = (struct zxdg_output_manager_v1*)wl_registry_bind(registry, name, &zxdg_output_manager_v1_interface, 1);
- }
- }
-
- static void registry_remove_object(void *data, struct wl_registry *registry, uint32_t name) {
- (void)data;
- (void)registry;
- (void)name;
- // TODO: Remove output
- }
-
- static struct wl_registry_listener registry_listener = {
- registry_add_object,
- registry_remove_object,
- };
-
- static void xdg_output_logical_position(void *data, struct zxdg_output_v1 *zxdg_output_v1, int32_t x, int32_t y) {
- (void)zxdg_output_v1;
- WaylandOutput *monitor = (WaylandOutput*)data;
- monitor->pos.x = x;
- monitor->pos.y = y;
- }
-
- static void xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, int32_t width, int32_t height) {
- (void)data;
- (void)xdg_output;
- (void)width;
- (void)height;
- }
-
- static void xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) {
- (void)data;
- (void)xdg_output;
- }
-
- static void xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, const char *name) {
- (void)data;
- (void)xdg_output;
- (void)name;
- }
-
- static void xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output, const char *description) {
- (void)data;
- (void)xdg_output;
- (void)description;
- }
-
- static const struct zxdg_output_v1_listener xdg_output_listener = {
- xdg_output_logical_position,
- xdg_output_handle_logical_size,
- xdg_output_handle_done,
- xdg_output_handle_name,
- xdg_output_handle_description,
- };
-
- /* Returns nullptr if not found */
- static const drm_connector* get_drm_connector_by_crtc_id(const drm_connectors *connectors, uint32_t crtc_id) {
- for(int i = 0; i < connectors->num_connectors; ++i) {
- if(connectors->connectors[i].crtc_id == crtc_id)
- return &connectors->connectors[i];
- }
- return nullptr;
- }
-
- static void get_drm_connectors(int drm_fd, drm_connectors *drm_connectors) {
- drm_connectors->num_connectors = 0;
- drmModeResPtr resources = drmModeGetResources(drm_fd);
- if(!resources)
- return;
-
- for(int i = 0; i < resources->count_connectors && drm_connectors->num_connectors < MAX_CONNECTORS; ++i) {
- drmModeConnectorPtr connector = nullptr;
- drmModeCrtcPtr crtc = nullptr;
-
- connector = drmModeGetConnectorCurrent(drm_fd, resources->connectors[i]);
- if(!connector)
- continue;
-
- uint64_t crtc_id = 0;
- connector_get_property_by_name(drm_fd, connector, "CRTC_ID", &crtc_id);
- if(crtc_id == 0)
- goto next;
-
- crtc = drmModeGetCrtc(drm_fd, crtc_id);
- if(!crtc)
- goto next;
-
- drm_connectors->connectors[drm_connectors->num_connectors].crtc_id = crtc_id;
- drm_connectors->connectors[drm_connectors->num_connectors].size = mgl::vec2i{(int)crtc->width, (int)crtc->height};
- ++drm_connectors->num_connectors;
-
- next:
- if(crtc)
- drmModeFreeCrtc(crtc);
-
- if(connector)
- drmModeFreeConnector(connector);
- }
- drmModeFreeResources(resources);
- }
-
- CursorTrackerWayland::CursorTrackerWayland(const char *card_path) {
- drm_fd = open(card_path, O_RDONLY);
- if(drm_fd <= 0) {
- fprintf(stderr, "Error: CursorTrackerWayland: failed to open %s\n", card_path);
- return;
- }
-
- drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
- drmSetClientCap(drm_fd, DRM_CLIENT_CAP_ATOMIC, 1);
- }
-
- CursorTrackerWayland::~CursorTrackerWayland() {
- if(drm_fd > 0)
- close(drm_fd);
- }
-
- void CursorTrackerWayland::update() {
- if(drm_fd <= 0)
- return;
-
- drm_connectors connectors;
- connectors.num_connectors = 0;
- get_drm_connectors(drm_fd, &connectors);
-
- drmModePlaneResPtr planes = drmModeGetPlaneResources(drm_fd);
- if(!planes)
- return;
-
- for(uint32_t i = 0; i < planes->count_planes; ++i) {
- drmModePlanePtr plane = nullptr;
- const drm_connector *connector = nullptr;
- int crtc_x = 0;
- int crtc_y = 0;
- int crtc_id = 0;
- bool is_cursor = false;
- uint32_t property_mask = 0;
-
- plane = drmModeGetPlane(drm_fd, planes->planes[i]);
- if(!plane)
- goto next;
-
- if(!plane->fb_id)
- goto next;
-
- property_mask = plane_get_properties(drm_fd, planes->planes[i], &crtc_x, &crtc_y, &crtc_id, &is_cursor);
- if(property_mask != plane_property_all || crtc_id <= 0)
- goto next;
-
- connector = get_drm_connector_by_crtc_id(&connectors, crtc_id);
- if(!connector)
- goto next;
-
- if(crtc_x >= 0 && crtc_x <= connector->size.x && crtc_y >= 0 && crtc_y <= connector->size.y) {
- latest_cursor_position.x = crtc_x;
- latest_cursor_position.y = crtc_y;
- latest_crtc_id = crtc_id;
- drmModeFreePlane(plane);
- break;
- }
-
- next:
- drmModeFreePlane(plane);
- }
-
- drmModeFreePlaneResources(planes);
- }
-
- void CursorTrackerWayland::set_monitor_outputs_from_xdg_output(struct wl_display *dpy) {
- if(!xdg_output_manager) {
- fprintf(stderr, "Warning: CursorTrackerWayland::set_monitor_outputs_from_xdg_output: zxdg_output_manager not found. Registered monitor positions might be incorrect\n");
- return;
- }
-
- for(WaylandOutput &monitor : monitors) {
- monitor.xdg_output = zxdg_output_manager_v1_get_xdg_output(xdg_output_manager, monitor.output);
- zxdg_output_v1_add_listener(monitor.xdg_output, &xdg_output_listener, &monitor);
- }
-
- // Fetch xdg_output
- wl_display_roundtrip(dpy);
- }
-
- std::optional<CursorInfo> CursorTrackerWayland::get_latest_cursor_info() {
- if(drm_fd <= 0 || latest_crtc_id == -1)
- return std::nullopt;
-
- std::string monitor_name = get_monitor_name_from_crtc_id(drm_fd, latest_crtc_id);
- if(monitor_name.empty())
- return std::nullopt;
-
- struct wl_display *dpy = wl_display_connect(nullptr);
- if(!dpy) {
- fprintf(stderr, "Error: CursorTrackerWayland::get_latest_cursor_info: failed to connect to the wayland server\n");
- return std::nullopt;
- }
-
- monitors.clear();
- struct wl_registry *registry = wl_display_get_registry(dpy);
- wl_registry_add_listener(registry, &registry_listener, this);
-
- // Fetch globals
- wl_display_roundtrip(dpy);
-
- // Fetch wl_output
- wl_display_roundtrip(dpy);
-
- set_monitor_outputs_from_xdg_output(dpy);
-
- mgl::vec2i cursor_position = latest_cursor_position;
- const WaylandOutput *wayland_monitor = get_wayland_monitor_by_name(monitors, monitor_name);
- if(!wayland_monitor)
- return std::nullopt;
-
- cursor_position = wayland_monitor->pos + latest_cursor_position;
- for(WaylandOutput &monitor : monitors) {
- if(monitor.output) {
- wl_output_destroy(monitor.output);
- monitor.output = nullptr;
- }
-
- if(monitor.xdg_output) {
- zxdg_output_v1_destroy(monitor.xdg_output);
- monitor.xdg_output = nullptr;
- }
- }
- monitors.clear();
-
- if(xdg_output_manager) {
- zxdg_output_manager_v1_destroy(xdg_output_manager);
- xdg_output_manager = nullptr;
- }
-
- wl_registry_destroy(registry);
- wl_display_disconnect(dpy);
-
- return CursorInfo{ cursor_position, std::move(monitor_name) };
- }
-} \ No newline at end of file