mirror of
https://repo.dec05eba.com/gpu-screen-recorder-ui
synced 2026-05-07 07:16:23 +09:00
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)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -130,8 +130,6 @@ namespace gsr {
|
||||
exit_status = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
buffer[bytes_read] = '\0';
|
||||
result.append(buffer, bytes_read);
|
||||
}
|
||||
|
||||
|
||||
28
src/main.cpp
28
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.
|
||||
|
||||
Reference in New Issue
Block a user