diff options
author | dec05eba <dec05eba@protonmail.com> | 2025-05-03 12:03:43 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2025-05-03 12:03:43 +0200 |
commit | d08ea692771caa8e385412c2f992089672773e30 (patch) | |
tree | 994c05673d90b130e25d8bc25c6c365f607134db /src/CursorTrackerWayland.cpp | |
parent | 180a3b73dbab2f586c53f9e5f044ab88aca95014 (diff) |
Keep keyboard led when turning on global hotkeys, move files
Diffstat (limited to 'src/CursorTrackerWayland.cpp')
-rw-r--r-- | src/CursorTrackerWayland.cpp | 564 |
1 files changed, 0 insertions, 564 deletions
diff --git a/src/CursorTrackerWayland.cpp b/src/CursorTrackerWayland.cpp deleted file mode 100644 index 9a0f442..0000000 --- a/src/CursorTrackerWayland.cpp +++ /dev/null @@ -1,564 +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; - bool vrr_enabled; - } drm_connector; - - typedef struct { - drm_connector connectors[MAX_CONNECTORS]; - int num_connectors; - bool has_any_crtc_with_vrr_enabled; - } 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) { - *crtc_x = 0; - *crtc_y = 0; - *crtc_id = 0; - - 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 get_drm_property_by_name(int drm_fd, drmModeObjectPropertiesPtr props, const char *name, uint64_t *result) { - for(uint32_t 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 bool connector_get_property_by_name(int drm_fd, drmModeConnectorPtr props, const char *name, uint64_t *result) { - drmModeObjectProperties properties; - properties.count_props = (uint32_t)props->count_props; - properties.props = props->props; - properties.prop_values = props->prop_values; - return get_drm_property_by_name(drm_fd, &properties, name, result); - } - - 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 drm_connector* get_drm_connector_by_crtc_id(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; - drm_connectors->has_any_crtc_with_vrr_enabled = false; - - 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_connector; - - crtc = drmModeGetCrtc(drm_fd, crtc_id); - if(!crtc) - goto next_connector; - - 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->connectors[drm_connectors->num_connectors].vrr_enabled = false; - ++drm_connectors->num_connectors; - - next_connector: - if(crtc) - drmModeFreeCrtc(crtc); - - if(connector) - drmModeFreeConnector(connector); - } - - for(int i = 0; i < resources->count_crtcs; ++i) { - drmModeCrtcPtr crtc = nullptr; - drmModeObjectPropertiesPtr properties = nullptr; - uint64_t vrr_enabled = 0; - drm_connector *connector = nullptr; - - crtc = drmModeGetCrtc(drm_fd, resources->crtcs[i]); - if(!crtc) - continue; - - properties = drmModeObjectGetProperties(drm_fd, crtc->crtc_id, DRM_MODE_OBJECT_CRTC); - if(!properties) - goto next_crtc; - - if(!get_drm_property_by_name(drm_fd, properties, "VRR_ENABLED", &vrr_enabled)) - goto next_crtc; - - connector = get_drm_connector_by_crtc_id(drm_connectors, crtc->crtc_id); - if(!connector) - goto next_crtc; - - if(vrr_enabled) { - connector->vrr_enabled = true; - drm_connectors->has_any_crtc_with_vrr_enabled = true; - } - - next_crtc: - if(properties) - drmModeFreeObjectProperties(properties); - - if(crtc) - drmModeFreeCrtc(crtc); - } - - 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; - connectors.has_any_crtc_with_vrr_enabled = false; - get_drm_connectors(drm_fd, &connectors); - - drmModePlaneResPtr planes = drmModeGetPlaneResources(drm_fd); - if(!planes) - return; - - bool found_cursor = false; - 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; - 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); - 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; - found_cursor = true; - drmModeFreePlane(plane); - break; - } - - next: - drmModeFreePlane(plane); - } - - // On kde plasma wayland (and possibly other wayland compositors) it uses a software cursor only for the monitors with vrr enabled. - // In that case we cant know the cursor location and we instead want to fallback to getting focused monitor by using the hack of creating a window and getting the position. - if(!found_cursor && latest_crtc_id > 0 && connectors.has_any_crtc_with_vrr_enabled) - latest_crtc_id = -1; - - 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, ®istry_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 |