aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2025-05-02 12:32:08 +0200
committerdec05eba <dec05eba@protonmail.com>2025-05-02 12:32:08 +0200
commit180a3b73dbab2f586c53f9e5f044ab88aca95014 (patch)
tree48e5b5e70f0ef1ea97894270b3f084d7ea0acd8d
parentac1d57e8ba5059608b32ceeed8d91cf509a26d86 (diff)
Fix ui being on wrong monitor/focused monitor capture incorrect on kde plasma wayland when vrr is enabled (fallback to window creation & window position trick)HEADmaster
-rw-r--r--TODO6
-rw-r--r--src/CursorTrackerWayland.cpp74
-rw-r--r--src/Overlay.cpp21
-rw-r--r--src/Process.cpp2
-rw-r--r--src/main.cpp28
5 files changed, 105 insertions, 26 deletions
diff --git a/TODO b/TODO
index 4bf57f7..5e4b3c3 100644
--- a/TODO
+++ b/TODO
@@ -162,5 +162,11 @@ Support cjk font. Use fc-match to find the location of the font. This also works
Keyboard layout is incorrect on wayland when using kde plasma keyboard settings to setup multiple keyboards, for example when changing to french.
Text input is correct, but hotkey is incorrect.
Need to use "setxkbmap fr" as well.
+ This happens only when grabbing keyboard (gsr-global-hotkeys). Same thing is seen with xev.
Allow to configure replay by disk space as well. When changing bitrate change an editable field that says the disk space, and when changing that disk space field then change the bitrate or duration.
+
+Getting focused monitor on wayland doesn't work when vrr is enabled. This is because it uses software cursor instead (at least on kde plasma wayland).
+ Right now it falls back to create window & getting window position trick if there is no cursor visible (or a software cursor) and one monitor has vrr enabled.
+ Remove this when linux & wayland supports vrr with hardware cursor plane.
+ Find out another way to get cursor position on wayland. \ No newline at end of file
diff --git a/src/CursorTrackerWayland.cpp b/src/CursorTrackerWayland.cpp
index 5f37d0a..9a0f442 100644
--- a/src/CursorTrackerWayland.cpp
+++ b/src/CursorTrackerWayland.cpp
@@ -27,19 +27,20 @@ namespace gsr {
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, bool *is_cursor) {
+ 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;
- *is_cursor = false;
uint32_t property_mask = 0;
@@ -80,8 +81,8 @@ namespace gsr {
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) {
+ 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;
@@ -96,6 +97,14 @@ namespace gsr {
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)
@@ -325,7 +334,7 @@ namespace gsr {
};
/* Returns nullptr if not found */
- static const drm_connector* get_drm_connector_by_crtc_id(const drm_connectors *connectors, uint32_t crtc_id) {
+ 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];
@@ -335,6 +344,8 @@ namespace gsr {
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;
@@ -350,23 +361,59 @@ namespace gsr {
uint64_t crtc_id = 0;
connector_get_property_by_name(drm_fd, connector, "CRTC_ID", &crtc_id);
if(crtc_id == 0)
- goto next;
+ goto next_connector;
crtc = drmModeGetCrtc(drm_fd, crtc_id);
if(!crtc)
- goto next;
+ 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:
+ 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);
}
@@ -392,19 +439,20 @@ namespace gsr {
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;
- bool is_cursor = false;
uint32_t property_mask = 0;
plane = drmModeGetPlane(drm_fd, planes->planes[i]);
@@ -414,7 +462,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, &is_cursor);
+ 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;
@@ -426,6 +474,7 @@ namespace gsr {
latest_cursor_position.x = crtc_x;
latest_cursor_position.y = crtc_y;
latest_crtc_id = crtc_id;
+ found_cursor = true;
drmModeFreePlane(plane);
break;
}
@@ -434,6 +483,11 @@ namespace gsr {
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);
}
diff --git a/src/Overlay.cpp b/src/Overlay.cpp
index 91f20db..487b6bc 100644
--- a/src/Overlay.cpp
+++ b/src/Overlay.cpp
@@ -2137,8 +2137,25 @@ namespace gsr {
cursor_info = cursor_tracker->get_latest_cursor_info();
}
- if(cursor_info)
- return cursor_info->monitor_name;
+ std::string focused_monitor_name;
+ if(cursor_info) {
+ focused_monitor_name = std::move(cursor_info->monitor_name);
+ } else {
+ mgl_context *context = mgl_get_context();
+ Display *display = (Display*)context->connection;
+
+ Window x11_cursor_window = None;
+ mgl::vec2i cursor_position = get_cursor_position(display, &x11_cursor_window);
+
+ 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);
+ auto monitors = get_monitors(display);
+ const Monitor *focused_monitor = find_monitor_at_position(monitors, monitor_position_query_value);
+ if(focused_monitor)
+ focused_monitor_name = focused_monitor->name;
+ }
+
+ if(!focused_monitor_name.empty())
+ return focused_monitor_name;
else if(!capture_options.monitors.empty())
return capture_options.monitors.front().name;
else
diff --git a/src/Process.cpp b/src/Process.cpp
index 0a62986..45be208 100644
--- a/src/Process.cpp
+++ b/src/Process.cpp
@@ -130,8 +130,6 @@ namespace gsr {
exit_status = -1;
break;
}
-
- buffer[bytes_read] = '\0';
result.append(buffer, bytes_read);
}
diff --git a/src/main.cpp b/src/main.cpp
index 19a23c7..31ec8ff 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -159,6 +159,21 @@ static bool is_flatpak() {
return getenv("FLATPAK_ID") != nullptr;
}
+static void set_display_server_environment_variables() {
+ // Some users dont have properly setup environments (no display manager that does systemctl --user import-environment DISPLAY WAYLAND_DISPLAY)
+ const char *display = getenv("DISPLAY");
+ if(!display) {
+ display = ":0";
+ setenv("DISPLAY", display, true);
+ }
+
+ const char *wayland_display = getenv("WAYLAND_DISPLAY");
+ if(!wayland_display) {
+ wayland_display = "wayland-1";
+ setenv("WAYLAND_DISPLAY", wayland_display, true);
+ }
+}
+
static void usage() {
printf("usage: gsr-ui [action]\n");
printf("OPTIONS:\n");
@@ -203,18 +218,7 @@ int main(int argc, char **argv) {
usage();
}
- // Some users dont have properly setup environments (no display manager that does systemctl --user import-environment DISPLAY WAYLAND_DISPLAY)
- const char *display = getenv("DISPLAY");
- if(!display) {
- display = ":0";
- setenv("DISPLAY", display, true);
- }
-
- const char *wayland_display = getenv("WAYLAND_DISPLAY");
- if(!wayland_display) {
- wayland_display = "wayland-1";
- setenv("WAYLAND_DISPLAY", wayland_display, true);
- }
+ set_display_server_environment_variables();
// TODO: This is a shitty method to detect if multiple instances of gsr-ui is running but this will work properly even in flatpak
// that uses pid sandboxing. Replace this with a better method once we no longer rely on linux global hotkeys on some platform.