Fix incorrect region captured on wayland when using monitor scaling and without letting x11 scale monitors

This commit is contained in:
dec05eba
2026-01-20 18:31:29 +01:00
parent e44b2ec528
commit 794064a8b8
9 changed files with 360 additions and 273 deletions

View File

@@ -1,11 +1,10 @@
#include "../../include/CursorTracker/CursorTrackerWayland.hpp"
#include "../../include/WindowUtils.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;
@@ -136,177 +135,14 @@ namespace gsr {
}
// 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) {
static const Monitor* get_wayland_monitor_by_name(const std::vector<Monitor> &monitors, const std::string &name) {
for(const Monitor &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) {
@@ -390,7 +226,7 @@ namespace gsr {
drmModeFreeResources(resources);
}
CursorTrackerWayland::CursorTrackerWayland(const char *card_path) {
CursorTrackerWayland::CursorTrackerWayland(const char *card_path, struct wl_display *wayland_dpy) : wayland_dpy(wayland_dpy) {
drm_fd = open(card_path, O_RDONLY);
if(drm_fd <= 0) {
fprintf(stderr, "Error: CursorTrackerWayland: failed to open %s\n", card_path);
@@ -402,7 +238,6 @@ namespace gsr {
}
CursorTrackerWayland::~CursorTrackerWayland() {
clear_monitors();
if(drm_fd > 0)
close(drm_fd);
}
@@ -465,80 +300,19 @@ namespace gsr {
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);
}
void CursorTrackerWayland::clear_monitors() {
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();
}
std::optional<CursorInfo> CursorTrackerWayland::get_latest_cursor_info() {
if(drm_fd <= 0 || latest_crtc_id == -1)
if(drm_fd <= 0 || latest_crtc_id == -1 || !wayland_dpy)
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");
const std::vector<Monitor> wayland_monitors = get_monitors_wayland(wayland_dpy);
const Monitor *wayland_monitor = get_wayland_monitor_by_name(wayland_monitors, monitor_name);
if(!wayland_monitor)
return std::nullopt;
}
clear_monitors();
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) {
clear_monitors();
return std::nullopt;
}
cursor_position = wayland_monitor->pos + latest_cursor_position;
clear_monitors();
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) };
return CursorInfo{ wayland_monitor->position + latest_cursor_position, std::move(monitor_name) };
}
}

View File

@@ -39,6 +39,9 @@
#include <X11/extensions/XInput2.h>
#include <X11/extensions/shapeconst.h>
#include <X11/Xcursor/Xcursor.h>
#include <wayland-client.h>
#include <mglpp/system/Rect.hpp>
#include <mglpp/window/Event.hpp>
#include <mglpp/system/Utf8.hpp>
@@ -487,6 +490,14 @@ namespace gsr {
top_bar_background({0.0f, 0.0f}),
close_button_widget({0.0f, 0.0f})
{
if(this->gsr_info.system_info.display_server == DisplayServer::WAYLAND) {
wayland_dpy = wl_display_connect(nullptr);
if(!wayland_dpy)
fprintf(stderr, "Warning: failed to connect to the wayland server\n");
} else {
wayland_dpy = nullptr;
}
gsr_icon_path = this->resources_path + "images/gpu_screen_recorder_logo.png";
key_bindings[0].key_event.code = mgl::Keyboard::Escape;
@@ -530,7 +541,7 @@ namespace gsr {
cursor_tracker = std::make_unique<CursorTrackerX11>((Display*)mgl_get_context()->connection);
else if(this->gsr_info.system_info.display_server == DisplayServer::WAYLAND) {
if(!this->gsr_info.gpu_info.card_path.empty())
cursor_tracker = std::make_unique<CursorTrackerWayland>(this->gsr_info.gpu_info.card_path.c_str());
cursor_tracker = std::make_unique<CursorTrackerWayland>(this->gsr_info.gpu_info.card_path.c_str(), wayland_dpy);
if(!config.main_config.wayland_warning_shown) {
config.main_config.wayland_warning_shown = true;
@@ -582,6 +593,9 @@ namespace gsr {
if(x11_dpy)
XCloseDisplay(x11_dpy);
if(wayland_dpy)
wl_display_disconnect(wayland_dpy);
}
void Overlay::xi_setup() {
@@ -2507,8 +2521,8 @@ namespace gsr {
return result;
}
static void add_region_command(std::vector<const char*> &args, char *region_str, int region_str_size, const RegionSelector &region_selector) {
Region region = region_selector.get_selection();
void Overlay::add_region_command(std::vector<const char*> &args, char *region_str, int region_str_size) {
Region region = region_selector.get_selection(x11_dpy, wayland_dpy);
if(region.size.x <= 32 && region.size.y <= 32) {
region.size.x = 0;
region.size.y = 0;
@@ -2518,7 +2532,7 @@ namespace gsr {
args.push_back(region_str);
}
static void add_common_gpu_screen_recorder_args(std::vector<const char*> &args, const RecordOptions &record_options, const std::vector<std::string> &audio_tracks, const std::string &video_bitrate, const char *region, char *region_str, int region_str_size, const RegionSelector &region_selector, const std::string &region_area_option) {
void Overlay::add_common_gpu_screen_recorder_args(std::vector<const char*> &args, const RecordOptions &record_options, const std::vector<std::string> &audio_tracks, const std::string &video_bitrate, const char *region, char *region_str, int region_str_size, const std::string &region_area_option) {
if(record_options.video_quality == "custom") {
args.push_back("-bm");
args.push_back("cbr");
@@ -2550,7 +2564,7 @@ namespace gsr {
}
if(region_area_option == "region")
add_region_command(args, region_str, region_str_size, region_selector);
add_region_command(args, region_str, region_str_size);
}
static bool validate_capture_target(const std::string &capture_target, const SupportedCaptureOptions &capture_options) {
@@ -2906,7 +2920,7 @@ namespace gsr {
}
char region_str[128];
add_common_gpu_screen_recorder_args(args, config.replay_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), region_selector, config.replay_config.record_options.record_area_option);
add_common_gpu_screen_recorder_args(args, config.replay_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), config.replay_config.record_options.record_area_option);
if(gsr_info.system_info.gsr_version >= GsrVersion{5, 4, 0}) {
args.push_back("-ro");
@@ -3133,7 +3147,7 @@ namespace gsr {
};
char region_str[128];
add_common_gpu_screen_recorder_args(args, config.record_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), region_selector, record_area_option);
add_common_gpu_screen_recorder_args(args, config.record_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), record_area_option);
args.push_back(nullptr);
@@ -3331,7 +3345,7 @@ namespace gsr {
};
char region_str[128];
add_common_gpu_screen_recorder_args(args, config.streaming_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), region_selector, config.streaming_config.record_options.record_area_option);
add_common_gpu_screen_recorder_args(args, config.streaming_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), config.streaming_config.record_options.record_area_option);
if(gsr_info.system_info.gsr_version >= GsrVersion{5, 4, 0}) {
args.push_back("-ro");
@@ -3463,7 +3477,7 @@ namespace gsr {
char region_str[128];
if(record_area_option == "region")
add_region_command(args, region_str, sizeof(region_str), region_selector);
add_region_command(args, region_str, sizeof(region_str));
args.push_back(nullptr);

View File

@@ -166,6 +166,62 @@ namespace gsr {
return ((uint32_t)color.a << 24) | (((uint32_t)color.r * color.a / 0xFF) << 16) | (((uint32_t)color.g * color.a / 0xFF) << 8) | ((uint32_t)color.b * color.a / 0xFF);
}
static const Monitor* get_monitor_by_region_center(const std::vector<Monitor> &monitors, Region region) {
const mgl::vec2i center = {region.pos.x + region.size.x / 2, region.pos.y + region.size.y / 2};
for(const Monitor &monitor : monitors) {
if(center.x >= monitor.position.x && center.x <= monitor.position.x + monitor.size.x
&& center.y >= monitor.position.y && center.y <= monitor.position.y + monitor.size.y)
{
return &monitor;
}
}
return nullptr;
}
// Name is the x11 name. TODO: verify if this works on all wayland compositors
static const Monitor* get_wayland_monitor_by_name(const std::vector<Monitor> &monitors, const std::string &name) {
for(const Monitor &monitor : monitors) {
if(monitor.name == name)
return &monitor;
}
return nullptr;
}
static mgl::vec2d to_vec2d(mgl::vec2i v) {
return { (double)v.x, (double)v.y };
}
static Region x11_region_to_wayland_region(Display *dpy, struct wl_display *wayland_dpy, Region x11_region) {
const std::vector<Monitor> x11_monitors = get_monitors(dpy);
const Monitor *x11_selected_monitor = get_monitor_by_region_center(x11_monitors, x11_region);
if(!x11_selected_monitor) {
fprintf(stderr, "Warning: RegionSelector: failed to get x11 monitor\n");
return x11_region;
}
const std::vector<Monitor> wayland_monitors = get_monitors_wayland(wayland_dpy);
const Monitor *wayland_monitor = get_wayland_monitor_by_name(wayland_monitors, x11_selected_monitor->name);
if(!wayland_monitor) {
fprintf(stderr, "Warning: RegionSelector: failed to get wayland monitor\n");
return x11_region;
}
const mgl::vec2d region_relative_pos = {
(double)(x11_region.pos.x - x11_selected_monitor->position.x) / (double)x11_selected_monitor->size.x,
(double)(x11_region.pos.y - x11_selected_monitor->position.y) / (double)x11_selected_monitor->size.y,
};
const mgl::vec2d region_relative_size = {
(double)x11_region.size.x / (double)x11_selected_monitor->size.x,
(double)x11_region.size.y / (double)x11_selected_monitor->size.y,
};
return Region {
wayland_monitor->position + (region_relative_pos * to_vec2d(wayland_monitor->size)).to_vec2i(),
(region_relative_size * to_vec2d(wayland_monitor->size)).to_vec2i(),
};
}
RegionSelector::RegionSelector() {
}
@@ -385,8 +441,11 @@ namespace gsr {
return result;
}
Region RegionSelector::get_selection() const {
return region;
Region RegionSelector::get_selection(Display *x11_dpy, struct wl_display *wayland_dpy) const {
Region returned_region = region;
if(is_wayland && x11_dpy && wayland_dpy)
returned_region = x11_region_to_wayland_region(x11_dpy, wayland_dpy, returned_region);
return returned_region;
}
void RegionSelector::on_button_press(const void *de) {

View File

@@ -8,6 +8,9 @@
#include <X11/extensions/shapeconst.h>
#include <X11/extensions/Xrandr.h>
#include <wayland-client.h>
#include "xdg-output-unstable-v1-client-protocol.h"
#include <mglpp/system/Utf8.hpp>
extern "C" {
@@ -23,6 +26,209 @@ extern "C" {
#define MAX_PROPERTY_VALUE_LEN 4096
namespace gsr {
struct WaylandOutput {
uint32_t wl_name;
struct wl_output *output;
struct zxdg_output_v1 *xdg_output;
mgl::vec2i pos;
mgl::vec2i size;
int32_t transform;
std::string name;
};
struct Wayland {
std::vector<WaylandOutput> outputs;
struct zxdg_output_manager_v1 *xdg_output_manager = nullptr;
};
static WaylandOutput* get_wayland_monitor_by_output(Wayland &wayland, struct wl_output *output) {
for(WaylandOutput &monitor : wayland.outputs) {
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;
Wayland *wayland = (Wayland*)data;
WaylandOutput *monitor = get_wayland_monitor_by_output(*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;
Wayland *wayland = (Wayland*)data;
WaylandOutput *monitor = get_wayland_monitor_by_output(*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;
Wayland *wayland = (Wayland*)data;
WaylandOutput *monitor = get_wayland_monitor_by_output(*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;
Wayland *wayland = (Wayland*)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);
wayland->outputs.push_back(
WaylandOutput{
name,
output,
nullptr,
mgl::vec2i{0, 0},
mgl::vec2i{0, 0},
0,
""
});
wl_output_add_listener(output, &output_listener, 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(wayland->xdg_output_manager) {
zxdg_output_manager_v1_destroy(wayland->xdg_output_manager);
wayland->xdg_output_manager = NULL;
}
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)xdg_output;
WaylandOutput *monitor = (WaylandOutput*)data;
monitor->size.x = width;
monitor->size.y = 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,
};
static const int transform_90 = 1;
static const int transform_270 = 3;
static void transform_monitors(Wayland &wayland) {
for(WaylandOutput &output : wayland.outputs) {
if(output.transform == transform_90 || output.transform == transform_270)
std::swap(output.size.x, output.size.y);
}
}
static void set_monitor_outputs_from_xdg_output(Wayland &wayland, struct wl_display *dpy) {
if(!wayland.xdg_output_manager) {
fprintf(stderr, "Warning: WindowUtils::set_monitor_outputs_from_xdg_output: zxdg_output_manager not found. Registered monitor positions might be incorrect\n");
return;
}
for(WaylandOutput &monitor : wayland.outputs) {
monitor.xdg_output = zxdg_output_manager_v1_get_xdg_output(wayland.xdg_output_manager, monitor.output);
zxdg_output_v1_add_listener(monitor.xdg_output, &xdg_output_listener, &monitor);
}
// Fetch xdg_output
wl_display_roundtrip(dpy);
}
static unsigned char* window_get_property(Display *dpy, Window window, Atom property_type, const char *property_name, unsigned int *property_size) {
Atom ret_property_type = None;
int ret_format = 0;
@@ -519,6 +725,47 @@ namespace gsr {
return monitors;
}
std::vector<Monitor> get_monitors_wayland(struct wl_display *dpy) {
Wayland wayland;
struct wl_registry *registry = wl_display_get_registry(dpy);
wl_registry_add_listener(registry, &registry_listener, &wayland);
// Fetch globals
wl_display_roundtrip(dpy);
// Fetch wl_output
wl_display_roundtrip(dpy);
transform_monitors(wayland);
set_monitor_outputs_from_xdg_output(wayland, dpy);
std::vector<Monitor> monitors;
for(WaylandOutput &output : wayland.outputs) {
monitors.push_back(Monitor{output.pos, output.size, std::move(output.name)});
if(output.output) {
wl_output_destroy(output.output);
output.output = nullptr;
}
if(output.xdg_output) {
zxdg_output_v1_destroy(output.xdg_output);
output.xdg_output = nullptr;
}
}
wayland.outputs.clear();
if(wayland.xdg_output_manager) {
zxdg_output_manager_v1_destroy(wayland.xdg_output_manager);
wayland.xdg_output_manager = nullptr;
}
wl_registry_destroy(registry);
return monitors;
}
static bool device_is_mouse(const XIDeviceInfo *dev) {
for(int i = 0; i < dev->num_classes; ++i) {
if(dev->classes[i]->type == XIMasterPointer || dev->classes[i]->type == XISlavePointer)