Better cursor position handling on wayland

This commit is contained in:
dec05eba
2026-01-24 22:07:51 +01:00
parent c6339ac9c2
commit 9ed4bc3426
3 changed files with 40 additions and 9 deletions

4
TODO
View File

@@ -258,4 +258,6 @@ Redesign the UI to allow capturing multiple video sources. Move webcam to captur
Add option to choose video container (either flv or mpegts) for youtube livestreaming.
Get wayland cursor position for region selector, otherwise the start position before the cursor moves is off.
Get wayland cursor position for region selector, otherwise the start position before the cursor moves is off.
Add option to set preset on nvidia. Use -ffmpeg-video-opts for that.

View File

@@ -6,15 +6,19 @@
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <mglpp/system/Rect.hpp>
namespace gsr {
static const int MAX_CONNECTORS = 32;
static const uint32_t plane_property_all = 0xF;
static const uint32_t plane_property_all = 0x3F;
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_CRTC_W = 1 << 2,
PLANE_PROPERTY_CRTC_H = 1 << 3,
PLANE_PROPERTY_CRTC_ID = 1 << 4,
PLANE_PROPERTY_TYPE_CURSOR = 1 << 5,
} plane_property_mask;
typedef struct {
@@ -29,10 +33,17 @@ namespace gsr {
bool has_any_crtc_with_vrr_enabled;
} drm_connectors;
static bool rectangles_intersect(mgl::IntRect rect1, mgl::IntRect rect2) {
return rect1.position.x < rect2.position.x + rect2.size.x && rect1.position.x + rect1.size.x > rect2.position.x &&
rect1.position.y < rect2.position.y + rect2.size.y && rect1.position.y + rect1.size.y > rect2.position.y;
}
/* 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) {
static uint32_t plane_get_properties(int drm_fd, uint32_t plane_id, int *crtc_x, int *crtc_y, int *crtc_w, int *crtc_h, int *crtc_id) {
*crtc_x = 0;
*crtc_y = 0;
*crtc_w = 0;
*crtc_h = 0;
*crtc_id = 0;
uint32_t property_mask = 0;
@@ -54,6 +65,12 @@ namespace gsr {
} 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_RANGE) && strcmp(prop->name, "CRTC_W") == 0) {
*crtc_w = (int)props->prop_values[i];
property_mask |= PLANE_PROPERTY_CRTC_W;
} else if((type & DRM_MODE_PROP_RANGE) && strcmp(prop->name, "CRTC_H") == 0) {
*crtc_h = (int)props->prop_values[i];
property_mask |= PLANE_PROPERTY_CRTC_H;
} 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;
@@ -259,11 +276,17 @@ namespace gsr {
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_w = 0;
int crtc_h = 0;
int crtc_id = 0;
uint32_t property_mask = 0;
mgl::IntRect monitor_rect;
mgl::IntRect cursor_rect;
plane = drmModeGetPlane(drm_fd, planes->planes[i]);
if(!plane)
goto next;
@@ -271,7 +294,7 @@ namespace gsr {
if(!plane->fb_id)
goto next;
property_mask = plane_get_properties(drm_fd, planes->planes[i], &crtc_x, &crtc_y, &crtc_id);
property_mask = plane_get_properties(drm_fd, planes->planes[i], &crtc_x, &crtc_y, &crtc_w, &crtc_h, &crtc_id);
if(property_mask != plane_property_all || crtc_id <= 0)
goto next;
@@ -279,7 +302,10 @@ namespace gsr {
if(!connector)
goto next;
if(crtc_x >= 0 && crtc_x <= connector->size.x && crtc_y >= 0 && crtc_y <= connector->size.y) {
monitor_rect = { mgl::vec2i(0, 0), connector->size };
cursor_rect = { mgl::vec2i(crtc_x, crtc_y), mgl::vec2i(crtc_w, crtc_h) };
if(rectangles_intersect(cursor_rect, cursor_rect)) {
latest_cursor_position.x = crtc_x;
latest_cursor_position.y = crtc_y;
latest_crtc_id = crtc_id;

View File

@@ -1052,7 +1052,6 @@ namespace gsr {
focused_monitor = find_monitor_by_name(monitors, cursor_info->monitor_name);
if(!focused_monitor)
focused_monitor = &monitors.front();
cursor_position = cursor_info->position;
} else {
const mgl::vec2i monitor_position_query_value = (x11_cursor_window || gsr_info.system_info.display_server != DisplayServer::WAYLAND) ? cursor_position : create_window_get_center_position(display);
focused_monitor = find_monitor_at_position(monitors, monitor_position_query_value);
@@ -1069,6 +1068,10 @@ namespace gsr {
|| is_wlroots
|| is_hyprland;
const bool drm_cursor_pos = !prevent_game_minimizing && cursor_info;
if(drm_cursor_pos)
cursor_position = cursor_info->position;
if(prevent_game_minimizing) {
window_pos = focused_monitor->position;
window_size = focused_monitor->size;
@@ -1162,7 +1165,7 @@ namespace gsr {
// The real cursor doesn't move when all devices are grabbed, so we create our own cursor and diplay that while grabbed
cursor_hotspot = {0, 0};
xi_setup_fake_cursor();
if(cursor_info && gsr_info.system_info.display_server == DisplayServer::WAYLAND) {
if(drm_cursor_pos) {
win->cursor_position.x += cursor_hotspot.x;
win->cursor_position.y += cursor_hotspot.y;
}