mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-03-31 09:07:13 +09:00
Wayland region: fix incorrect region captured if monitor is scaled
This commit is contained in:
@@ -16,6 +16,8 @@ typedef struct {
|
|||||||
int name_len;
|
int name_len;
|
||||||
vec2i pos; /* This is 0, 0 on wayland. Use |drm_monitor_get_display_server_data| to get the position */
|
vec2i pos; /* This is 0, 0 on wayland. Use |drm_monitor_get_display_server_data| to get the position */
|
||||||
vec2i size;
|
vec2i size;
|
||||||
|
vec2i logical_pos;
|
||||||
|
vec2i logical_size;
|
||||||
uint32_t connector_id; /* Only on x11 and drm */
|
uint32_t connector_id; /* Only on x11 and drm */
|
||||||
gsr_monitor_rotation rotation; /* Only on x11 and wayland */
|
gsr_monitor_rotation rotation; /* Only on x11 and wayland */
|
||||||
uint32_t monitor_identifier; /* On x11 this is the crtc id */
|
uint32_t monitor_identifier; /* On x11 this is the crtc id */
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
|||||||
39
src/main.cpp
39
src/main.cpp
@@ -110,26 +110,23 @@ typedef struct {
|
|||||||
char *output_name;
|
char *output_name;
|
||||||
vec2i monitor_pos;
|
vec2i monitor_pos;
|
||||||
vec2i monitor_size;
|
vec2i monitor_size;
|
||||||
|
double monitor_scale_inverted;
|
||||||
} MonitorByPositionCallback;
|
} MonitorByPositionCallback;
|
||||||
|
|
||||||
static void get_monitor_by_position_callback(const gsr_monitor *monitor, void *userdata) {
|
static void get_monitor_by_position_callback(const gsr_monitor *monitor, void *userdata) {
|
||||||
MonitorByPositionCallback *data = (MonitorByPositionCallback*)userdata;
|
MonitorByPositionCallback *data = (MonitorByPositionCallback*)userdata;
|
||||||
|
|
||||||
vec2i monitor_position = monitor->pos;
|
const vec2i monitor_position = monitor->logical_pos;
|
||||||
vec2i monitor_size = monitor->size;
|
const vec2i monitor_size = monitor->size;
|
||||||
if(gsr_window_get_display_server(data->window) == GSR_DISPLAY_SERVER_WAYLAND) {
|
const vec2i monitor_logical_size = monitor->logical_size;
|
||||||
gsr_monitor_rotation monitor_rotation = GSR_MONITOR_ROT_0;
|
|
||||||
drm_monitor_get_display_server_data(data->window, monitor, &monitor_rotation, &monitor_position);
|
|
||||||
if(monitor_rotation == GSR_MONITOR_ROT_90 || monitor_rotation == GSR_MONITOR_ROT_270)
|
|
||||||
std::swap(monitor_size.x, monitor_size.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!data->output_name && data->position.x >= monitor_position.x && data->position.x <= monitor_position.x + monitor_size.x
|
if(!data->output_name && data->position.x >= monitor_position.x && data->position.x <= monitor_position.x + monitor_logical_size.x
|
||||||
&& data->position.y >= monitor_position.y && data->position.y <= monitor_position.y + monitor_size.y)
|
&& data->position.y >= monitor_position.y && data->position.y <= monitor_position.y + monitor_logical_size.y)
|
||||||
{
|
{
|
||||||
data->output_name = strdup(monitor->name);
|
data->output_name = strdup(monitor->name);
|
||||||
data->monitor_pos = monitor_position;
|
data->monitor_pos = monitor_position;
|
||||||
data->monitor_size = monitor_size;
|
data->monitor_size = monitor_size;
|
||||||
|
data->monitor_scale_inverted = (double)monitor_size.x / (double)monitor_logical_size.x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1204,9 +1201,9 @@ struct VideoSource {
|
|||||||
CaptureSource *capture_source;
|
CaptureSource *capture_source;
|
||||||
};
|
};
|
||||||
|
|
||||||
static RecordingStartResult start_recording_create_streams(const char *filename, const args_parser &args_parser, AVCodecContext *video_codec_context, const std::vector<AudioTrack> &audio_tracks, bool hdr, std::vector<VideoSource> &video_sources) {
|
static RecordingStartResult start_recording_create_streams(const char *filename, const args_parser &arg_parser, AVCodecContext *video_codec_context, const std::vector<AudioTrack> &audio_tracks, bool hdr, std::vector<VideoSource> &video_sources) {
|
||||||
AVFormatContext *av_format_context;
|
AVFormatContext *av_format_context;
|
||||||
avformat_alloc_output_context2(&av_format_context, nullptr, args_parser.container_format, filename);
|
avformat_alloc_output_context2(&av_format_context, nullptr, arg_parser.container_format, filename);
|
||||||
|
|
||||||
AVStream *video_stream = create_stream(av_format_context, video_codec_context);
|
AVStream *video_stream = create_stream(av_format_context, video_codec_context);
|
||||||
avcodec_parameters_from_context(video_stream->codecpar, video_codec_context);
|
avcodec_parameters_from_context(video_stream->codecpar, video_codec_context);
|
||||||
@@ -1231,8 +1228,8 @@ static RecordingStartResult start_recording_create_streams(const char *filename,
|
|||||||
AVDictionary *options = nullptr;
|
AVDictionary *options = nullptr;
|
||||||
av_dict_set(&options, "strict", "experimental", 0);
|
av_dict_set(&options, "strict", "experimental", 0);
|
||||||
|
|
||||||
if(args_parser.ffmpeg_opts)
|
if(arg_parser.ffmpeg_opts)
|
||||||
av_dict_parse_string(&options, args_parser.ffmpeg_opts, "=", ";", 0);
|
av_dict_parse_string(&options, arg_parser.ffmpeg_opts, "=", ";", 0);
|
||||||
|
|
||||||
const int header_write_ret = avformat_write_header(av_format_context, &options);
|
const int header_write_ret = avformat_write_header(av_format_context, &options);
|
||||||
av_dict_free(&options);
|
av_dict_free(&options);
|
||||||
@@ -2140,9 +2137,9 @@ static std::string validate_monitor_get_valid(const gsr_egl *egl, const char* wi
|
|||||||
return capture_source_result;
|
return capture_source_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string get_monitor_by_region_center(const gsr_egl *egl, vec2i region_position, vec2i region_size, vec2i *monitor_pos, vec2i *monitor_size) {
|
static std::string get_monitor_by_region_center(const gsr_egl *egl, vec2i region_position, vec2i region_size, vec2i *monitor_pos, vec2i *monitor_size, double *monitor_scale_inverted) {
|
||||||
const bool is_x11 = gsr_window_get_display_server(egl->window) == GSR_DISPLAY_SERVER_X11;
|
const bool is_x11 = gsr_window_get_display_server(egl->window) == GSR_DISPLAY_SERVER_X11;
|
||||||
const gsr_connection_type connection_type = is_x11 ? GSR_CONNECTION_X11 : GSR_CONNECTION_DRM;
|
const gsr_connection_type connection_type = is_x11 ? GSR_CONNECTION_X11 : GSR_CONNECTION_WAYLAND;
|
||||||
|
|
||||||
MonitorByPositionCallback data;
|
MonitorByPositionCallback data;
|
||||||
data.window = egl->window;
|
data.window = egl->window;
|
||||||
@@ -2150,6 +2147,7 @@ static std::string get_monitor_by_region_center(const gsr_egl *egl, vec2i region
|
|||||||
data.output_name = NULL;
|
data.output_name = NULL;
|
||||||
data.monitor_pos = {0, 0};
|
data.monitor_pos = {0, 0};
|
||||||
data.monitor_size = {0, 0};
|
data.monitor_size = {0, 0};
|
||||||
|
data.monitor_scale_inverted = 1.0;
|
||||||
for_each_active_monitor_output(egl->window, egl->card_path, connection_type, get_monitor_by_position_callback, &data);
|
for_each_active_monitor_output(egl->window, egl->card_path, connection_type, get_monitor_by_position_callback, &data);
|
||||||
|
|
||||||
std::string result;
|
std::string result;
|
||||||
@@ -2159,6 +2157,7 @@ static std::string get_monitor_by_region_center(const gsr_egl *egl, vec2i region
|
|||||||
}
|
}
|
||||||
*monitor_pos = data.monitor_pos;
|
*monitor_pos = data.monitor_pos;
|
||||||
*monitor_size = data.monitor_size;
|
*monitor_size = data.monitor_size;
|
||||||
|
*monitor_scale_inverted = data.monitor_scale_inverted;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2229,7 +2228,8 @@ static gsr_capture* create_monitor_capture(const args_parser &arg_parser, gsr_eg
|
|||||||
static std::string region_get_data(gsr_egl *egl, vec2i *region_size, vec2i *region_position) {
|
static std::string region_get_data(gsr_egl *egl, vec2i *region_size, vec2i *region_position) {
|
||||||
vec2i monitor_pos = {0, 0};
|
vec2i monitor_pos = {0, 0};
|
||||||
vec2i monitor_size = {0, 0};
|
vec2i monitor_size = {0, 0};
|
||||||
std::string window = get_monitor_by_region_center(egl, *region_position, *region_size, &monitor_pos, &monitor_size);
|
double monitor_scale_inverted = 1.0;
|
||||||
|
std::string window = get_monitor_by_region_center(egl, *region_position, *region_size, &monitor_pos, &monitor_size, &monitor_scale_inverted);
|
||||||
if(window.empty()) {
|
if(window.empty()) {
|
||||||
const bool is_x11 = gsr_window_get_display_server(egl->window) == GSR_DISPLAY_SERVER_X11;
|
const bool is_x11 = gsr_window_get_display_server(egl->window) == GSR_DISPLAY_SERVER_X11;
|
||||||
const gsr_connection_type connection_type = is_x11 ? GSR_CONNECTION_X11 : GSR_CONNECTION_DRM;
|
const gsr_connection_type connection_type = is_x11 ? GSR_CONNECTION_X11 : GSR_CONNECTION_DRM;
|
||||||
@@ -2248,6 +2248,11 @@ static std::string region_get_data(gsr_egl *egl, vec2i *region_size, vec2i *regi
|
|||||||
} else {
|
} else {
|
||||||
region_position->x -= monitor_pos.x;
|
region_position->x -= monitor_pos.x;
|
||||||
region_position->y -= monitor_pos.y;
|
region_position->y -= monitor_pos.y;
|
||||||
|
region_position->x *= monitor_scale_inverted;
|
||||||
|
region_position->y *= monitor_scale_inverted;
|
||||||
|
|
||||||
|
region_size->x *= monitor_scale_inverted;
|
||||||
|
region_size->y *= monitor_scale_inverted;
|
||||||
}
|
}
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,6 +121,8 @@ void for_each_active_monitor_output_x11_not_cached(Display *display, active_moni
|
|||||||
.name_len = out_info->nameLen,
|
.name_len = out_info->nameLen,
|
||||||
.pos = { .x = crt_info->x, .y = crt_info->y },
|
.pos = { .x = crt_info->x, .y = crt_info->y },
|
||||||
.size = monitor_size,
|
.size = monitor_size,
|
||||||
|
.logical_pos = { .x = crt_info->x, .y = crt_info->y },
|
||||||
|
.logical_size = monitor_size,
|
||||||
.connector_id = x11_output_get_connector_id(display, screen_res->outputs[i], randr_connector_id_atom),
|
.connector_id = x11_output_get_connector_id(display, screen_res->outputs[i], randr_connector_id_atom),
|
||||||
.rotation = rotation,
|
.rotation = rotation,
|
||||||
.monitor_identifier = out_info->crtc
|
.monitor_identifier = out_info->crtc
|
||||||
@@ -229,6 +231,8 @@ static void for_each_active_monitor_output_drm(const char *card_path, active_mon
|
|||||||
.name_len = display_name_len,
|
.name_len = display_name_len,
|
||||||
.pos = { .x = crtc->x, .y = crtc->y },
|
.pos = { .x = crtc->x, .y = crtc->y },
|
||||||
.size = { .x = (int)crtc->width, .y = (int)crtc->height },
|
.size = { .x = (int)crtc->width, .y = (int)crtc->height },
|
||||||
|
.logical_pos = { .x = crtc->x, .y = crtc->y },
|
||||||
|
.logical_size = { .x = (int)crtc->width, .y = (int)crtc->height },
|
||||||
.connector_id = connector->connector_id,
|
.connector_id = connector->connector_id,
|
||||||
.rotation = GSR_MONITOR_ROT_0,
|
.rotation = GSR_MONITOR_ROT_0,
|
||||||
.monitor_identifier = connector_type_index_name != -1 ? monitor_identifier_from_type_and_count(connector_type_index_name, connector->connector_type_id) : 0
|
.monitor_identifier = connector_type_index_name != -1 ? monitor_identifier_from_type_and_count(connector_type_index_name, connector->connector_type_id) : 0
|
||||||
@@ -264,6 +268,8 @@ static void get_monitor_by_name_callback(const gsr_monitor *monitor, void *userd
|
|||||||
if(!data->found_monitor && strcmp(data->name, monitor->name) == 0) {
|
if(!data->found_monitor && strcmp(data->name, monitor->name) == 0) {
|
||||||
data->monitor->pos = monitor->pos;
|
data->monitor->pos = monitor->pos;
|
||||||
data->monitor->size = monitor->size;
|
data->monitor->size = monitor->size;
|
||||||
|
data->monitor->logical_pos = monitor->logical_pos;
|
||||||
|
data->monitor->logical_size = monitor->logical_size;
|
||||||
data->monitor->connector_id = monitor->connector_id;
|
data->monitor->connector_id = monitor->connector_id;
|
||||||
data->monitor->rotation = monitor->rotation;
|
data->monitor->rotation = monitor->rotation;
|
||||||
data->monitor->monitor_identifier = monitor->monitor_identifier;
|
data->monitor->monitor_identifier = monitor->monitor_identifier;
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ typedef struct {
|
|||||||
struct zxdg_output_v1 *xdg_output;
|
struct zxdg_output_v1 *xdg_output;
|
||||||
vec2i pos;
|
vec2i pos;
|
||||||
vec2i size;
|
vec2i size;
|
||||||
|
vec2i logical_pos;
|
||||||
|
vec2i logical_size;
|
||||||
int32_t transform;
|
int32_t transform;
|
||||||
char *name;
|
char *name;
|
||||||
} gsr_wayland_output;
|
} gsr_wayland_output;
|
||||||
@@ -123,6 +125,8 @@ static void registry_add_object(void *data, struct wl_registry *registry, uint32
|
|||||||
.output = wl_registry_bind(registry, name, &wl_output_interface, 4),
|
.output = wl_registry_bind(registry, name, &wl_output_interface, 4),
|
||||||
.pos = { .x = 0, .y = 0 },
|
.pos = { .x = 0, .y = 0 },
|
||||||
.size = { .x = 0, .y = 0 },
|
.size = { .x = 0, .y = 0 },
|
||||||
|
.logical_pos = { .x = 0, .y = 0 },
|
||||||
|
.logical_size = { .x = 0, .y = 0 },
|
||||||
.transform = 0,
|
.transform = 0,
|
||||||
.name = NULL,
|
.name = NULL,
|
||||||
};
|
};
|
||||||
@@ -160,10 +164,10 @@ static void xdg_output_logical_position(void *data, struct zxdg_output_v1 *zxdg_
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, int32_t width, int32_t height) {
|
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)xdg_output;
|
||||||
(void)width;
|
gsr_wayland_output *gsr_xdg_output = data;
|
||||||
(void)height;
|
gsr_xdg_output->logical_size.x = width;
|
||||||
|
gsr_xdg_output->logical_size.y = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) {
|
static void xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) {
|
||||||
@@ -206,6 +210,42 @@ static void gsr_window_wayland_set_monitor_outputs_from_xdg_output(gsr_window_wa
|
|||||||
wl_display_roundtrip(self->display);
|
wl_display_roundtrip(self->display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static int monitor_sort_x_pos(const void* a, const void* b) {
|
||||||
|
// const gsr_wayland_output *arg1 = *(const gsr_wayland_output**)a;
|
||||||
|
// const gsr_wayland_output *arg2 = *(const gsr_wayland_output**)b;
|
||||||
|
// return arg1->logical_pos.x - arg2->logical_pos.x;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// static int monitor_sort_y_pos(const void* a, const void* b) {
|
||||||
|
// const gsr_wayland_output *arg1 = *(const gsr_wayland_output**)a;
|
||||||
|
// const gsr_wayland_output *arg2 = *(const gsr_wayland_output**)b;
|
||||||
|
// return arg1->logical_pos.y - arg2->logical_pos.y;
|
||||||
|
// }
|
||||||
|
|
||||||
|
static void gsr_window_wayland_set_monitor_real_positions(gsr_window_wayland *self) {
|
||||||
|
gsr_wayland_output *sorted_outputs[GSR_MAX_OUTPUTS];
|
||||||
|
for(int i = 0; i < self->num_outputs; ++i) {
|
||||||
|
sorted_outputs[i] = &self->outputs[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: set correct physical positions
|
||||||
|
|
||||||
|
// qsort(sorted_outputs, self->num_outputs, sizeof(gsr_wayland_output*), monitor_sort_x_pos);
|
||||||
|
// int x_pos = 0;
|
||||||
|
// for(int i = 0; i < self->num_outputs; ++i) {
|
||||||
|
// fprintf(stderr, "monitor: %s\n", sorted_outputs[i]->name);
|
||||||
|
// sorted_outputs[i]->pos.x = x_pos;
|
||||||
|
// x_pos += sorted_outputs[i]->logical_size.x;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// qsort(sorted_outputs, self->num_outputs, sizeof(gsr_wayland_output*), monitor_sort_y_pos);
|
||||||
|
// int y_pos = 0;
|
||||||
|
// for(int i = 0; i < self->num_outputs; ++i) {
|
||||||
|
// sorted_outputs[i]->pos.y = y_pos;
|
||||||
|
// y_pos += sorted_outputs[i]->logical_size.y;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
static void gsr_window_wayland_deinit(gsr_window_wayland *self) {
|
static void gsr_window_wayland_deinit(gsr_window_wayland *self) {
|
||||||
if(self->window) {
|
if(self->window) {
|
||||||
wl_egl_window_destroy(self->window);
|
wl_egl_window_destroy(self->window);
|
||||||
@@ -273,6 +313,7 @@ static bool gsr_window_wayland_init(gsr_window_wayland *self) {
|
|||||||
wl_display_roundtrip(self->display);
|
wl_display_roundtrip(self->display);
|
||||||
|
|
||||||
gsr_window_wayland_set_monitor_outputs_from_xdg_output(self);
|
gsr_window_wayland_set_monitor_outputs_from_xdg_output(self);
|
||||||
|
gsr_window_wayland_set_monitor_real_positions(self);
|
||||||
|
|
||||||
if(!self->compositor) {
|
if(!self->compositor) {
|
||||||
fprintf(stderr, "gsr error: gsr_window_wayland_init failed: failed to find compositor\n");
|
fprintf(stderr, "gsr error: gsr_window_wayland_init failed: failed to find compositor\n");
|
||||||
@@ -337,6 +378,16 @@ static gsr_monitor_rotation wayland_transform_to_gsr_rotation(int32_t rot) {
|
|||||||
return GSR_MONITOR_ROT_0;
|
return GSR_MONITOR_ROT_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static vec2i get_monitor_size_rotated(int width, int height, gsr_monitor_rotation rotation) {
|
||||||
|
vec2i size = { .x = width, .y = height };
|
||||||
|
if(rotation == GSR_MONITOR_ROT_90 || rotation == GSR_MONITOR_ROT_270) {
|
||||||
|
int tmp_x = size.x;
|
||||||
|
size.x = size.y;
|
||||||
|
size.y = tmp_x;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
static void gsr_window_wayland_for_each_active_monitor_output_cached(const gsr_window *window, active_monitor_callback callback, void *userdata) {
|
static void gsr_window_wayland_for_each_active_monitor_output_cached(const gsr_window *window, active_monitor_callback callback, void *userdata) {
|
||||||
const gsr_window_wayland *self = window->priv;
|
const gsr_window_wayland *self = window->priv;
|
||||||
for(int i = 0; i < self->num_outputs; ++i) {
|
for(int i = 0; i < self->num_outputs; ++i) {
|
||||||
@@ -344,15 +395,21 @@ static void gsr_window_wayland_for_each_active_monitor_output_cached(const gsr_w
|
|||||||
if(!output->name)
|
if(!output->name)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
const gsr_monitor_rotation rotation = wayland_transform_to_gsr_rotation(output->transform);
|
||||||
|
vec2i size = { .x = output->size.x, .y = output->size.y };
|
||||||
|
size = get_monitor_size_rotated(size.x, size.y, rotation);
|
||||||
|
|
||||||
const int connector_type_index = get_connector_type_by_name(output->name);
|
const int connector_type_index = get_connector_type_by_name(output->name);
|
||||||
const int connector_type_id = get_connector_type_id_by_name(output->name);
|
const int connector_type_id = get_connector_type_id_by_name(output->name);
|
||||||
const gsr_monitor monitor = {
|
const gsr_monitor monitor = {
|
||||||
.name = output->name,
|
.name = output->name,
|
||||||
.name_len = strlen(output->name),
|
.name_len = strlen(output->name),
|
||||||
.pos = { .x = output->pos.x, .y = output->pos.y },
|
.pos = { .x = output->pos.x, .y = output->pos.y },
|
||||||
.size = { .x = output->size.x, .y = output->size.y },
|
.size = size,
|
||||||
|
.logical_pos = { .x = output->pos.x, .y = output->pos.y },
|
||||||
|
.logical_size = { .x = output->logical_size.x, .y = output->logical_size.y },
|
||||||
.connector_id = 0,
|
.connector_id = 0,
|
||||||
.rotation = wayland_transform_to_gsr_rotation(output->transform),
|
.rotation = rotation,
|
||||||
.monitor_identifier = (connector_type_index != -1 && connector_type_id != -1) ? monitor_identifier_from_type_and_count(connector_type_index, connector_type_id) : 0
|
.monitor_identifier = (connector_type_index != -1 && connector_type_id != -1) ? monitor_identifier_from_type_and_count(connector_type_index, connector_type_id) : 0
|
||||||
};
|
};
|
||||||
callback(&monitor, userdata);
|
callback(&monitor, userdata);
|
||||||
|
|||||||
@@ -121,6 +121,8 @@ static void gsr_window_x11_for_each_active_monitor_output_cached(const gsr_windo
|
|||||||
.name_len = strlen(output->name),
|
.name_len = strlen(output->name),
|
||||||
.pos = output->pos,
|
.pos = output->pos,
|
||||||
.size = output->size,
|
.size = output->size,
|
||||||
|
.logical_pos = output->pos,
|
||||||
|
.logical_size = output->size,
|
||||||
.connector_id = output->connector_id,
|
.connector_id = output->connector_id,
|
||||||
.rotation = output->rotation,
|
.rotation = output->rotation,
|
||||||
.monitor_identifier = output->monitor_identifier
|
.monitor_identifier = output->monitor_identifier
|
||||||
|
|||||||
Reference in New Issue
Block a user