linux-capture: Use RandR monitors for screen information
RandR has two sets of screen geometry information: 1. CRTC. These are the physical scanout engines in the hardware 2. Monitors. These are the logical partitions of the screen. By default, each CRTC gets mapped to a Monitor. However, some monitors actually require two CRTCs to drive them due to limitations in the scanout hardware. Users can also create 'virtual' monitors to support VNC or other systems. This patch makes the RandR code prefer the Monitor mechanism to the older CRTC mechanism. If the server doesn't support a new enough RandR version, the existing CRTC code is used instead. The name of the monitor is also provided in place of the arbitrary number to help users select the desired source. Signed-off-by: Keith Packard <keithp@keithp.com>
This commit is contained in:
parent
81a20171b1
commit
96924553f0
@ -104,6 +104,22 @@ bool randr_is_active(xcb_connection_t *xcb)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool randr_has_monitors(xcb_connection_t *xcb)
|
||||
{
|
||||
xcb_randr_query_version_cookie_t ver_c;
|
||||
xcb_randr_query_version_reply_t *ver_r;
|
||||
|
||||
ver_c = xcb_randr_query_version(xcb, XCB_RANDR_MAJOR_VERSION,
|
||||
XCB_RANDR_MINOR_VERSION);
|
||||
ver_r = xcb_randr_query_version_reply(xcb, ver_c, 0);
|
||||
if (!ver_r)
|
||||
return 0;
|
||||
|
||||
bool ret = ver_r->major_version > 1 || ver_r->minor_version >= 5;
|
||||
free(ver_r);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int randr_screen_count(xcb_connection_t *xcb)
|
||||
{
|
||||
if (!xcb)
|
||||
@ -111,6 +127,19 @@ int randr_screen_count(xcb_connection_t *xcb)
|
||||
xcb_screen_t *screen;
|
||||
screen = xcb_setup_roots_iterator(xcb_get_setup(xcb)).data;
|
||||
|
||||
if (randr_has_monitors(xcb)) {
|
||||
xcb_randr_get_monitors_cookie_t mon_c;
|
||||
xcb_randr_get_monitors_reply_t *mon_r;
|
||||
|
||||
mon_c = xcb_randr_get_monitors(xcb, screen->root, true);
|
||||
mon_r = xcb_randr_get_monitors_reply(xcb, mon_c, 0);
|
||||
if (!mon_r)
|
||||
return 0;
|
||||
|
||||
int count = xcb_randr_get_monitors_monitors_length(mon_r);
|
||||
free(mon_r);
|
||||
return count;
|
||||
}
|
||||
xcb_randr_get_screen_resources_cookie_t res_c;
|
||||
xcb_randr_get_screen_resources_reply_t *res_r;
|
||||
|
||||
@ -124,11 +153,58 @@ int randr_screen_count(xcb_connection_t *xcb)
|
||||
|
||||
int randr_screen_geo(xcb_connection_t *xcb, int_fast32_t screen,
|
||||
int_fast32_t *x, int_fast32_t *y, int_fast32_t *w,
|
||||
int_fast32_t *h, xcb_screen_t **rscreen)
|
||||
int_fast32_t *h, xcb_screen_t **rscreen, char **name)
|
||||
{
|
||||
xcb_screen_t *xscreen;
|
||||
xscreen = xcb_setup_roots_iterator(xcb_get_setup(xcb)).data;
|
||||
|
||||
if (randr_has_monitors(xcb)) {
|
||||
xcb_randr_get_monitors_cookie_t mon_c;
|
||||
xcb_randr_get_monitors_reply_t *mon_r;
|
||||
|
||||
mon_c = xcb_randr_get_monitors(xcb, xscreen->root, true);
|
||||
mon_r = xcb_randr_get_monitors_reply(xcb, mon_c, 0);
|
||||
if (!mon_r)
|
||||
return 0;
|
||||
|
||||
int monitors = xcb_randr_get_monitors_monitors_length(mon_r);
|
||||
if (screen < 0 || screen >= monitors) {
|
||||
free(mon_r);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
xcb_randr_monitor_info_iterator_t mon_i;
|
||||
mon_i = xcb_randr_get_monitors_monitors_iterator(mon_r);
|
||||
|
||||
int s;
|
||||
for (s = 0; s < screen; s++)
|
||||
xcb_randr_monitor_info_next(&mon_i);
|
||||
|
||||
xcb_randr_monitor_info_t *mon = mon_i.data;
|
||||
|
||||
*x = mon->x;
|
||||
*y = mon->y;
|
||||
*w = mon->width;
|
||||
*h = mon->height;
|
||||
if (rscreen)
|
||||
*rscreen = xscreen;
|
||||
|
||||
if (mon->name && name) {
|
||||
xcb_get_atom_name_cookie_t atom_c;
|
||||
xcb_get_atom_name_reply_t *atom_r;
|
||||
|
||||
atom_c = xcb_get_atom_name(xcb, mon->name);
|
||||
atom_r = xcb_get_atom_name_reply(xcb, atom_c, 0);
|
||||
if (atom_r) {
|
||||
*name = strndup(
|
||||
xcb_get_atom_name_name(atom_r),
|
||||
xcb_get_atom_name_name_length(atom_r));
|
||||
free(atom_r);
|
||||
}
|
||||
}
|
||||
free(mon_r);
|
||||
return 0;
|
||||
}
|
||||
xcb_randr_get_screen_resources_cookie_t res_c;
|
||||
xcb_randr_get_screen_resources_reply_t *res_r;
|
||||
|
||||
|
@ -94,7 +94,7 @@ int randr_screen_count(xcb_connection_t *xcb);
|
||||
*/
|
||||
int randr_screen_geo(xcb_connection_t *xcb, int_fast32_t screen,
|
||||
int_fast32_t *x, int_fast32_t *y, int_fast32_t *w,
|
||||
int_fast32_t *h, xcb_screen_t **rscreen);
|
||||
int_fast32_t *h, xcb_screen_t **rscreen, char **name);
|
||||
|
||||
/**
|
||||
* Get screen geometry for a X11 screen
|
||||
|
@ -104,7 +104,7 @@ static int_fast32_t xshm_update_geometry(struct xshm_data *data)
|
||||
if (data->use_randr) {
|
||||
if (randr_screen_geo(data->xcb, data->screen_id, &data->x_org,
|
||||
&data->y_org, &data->width, &data->height,
|
||||
&data->xcb_screen) < 0) {
|
||||
&data->xcb_screen, NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if (data->use_xinerama) {
|
||||
@ -308,21 +308,31 @@ static bool xshm_server_changed(obs_properties_t *props, obs_property_t *p,
|
||||
: xcb_setup_roots_length(xcb_get_setup(xcb));
|
||||
|
||||
for (int_fast32_t i = 0; i < count; ++i) {
|
||||
char *name;
|
||||
char name_tmp[12];
|
||||
int_fast32_t x, y, w, h;
|
||||
x = y = w = h = 0;
|
||||
|
||||
name = NULL;
|
||||
if (randr)
|
||||
randr_screen_geo(xcb, i, &x, &y, &w, &h, NULL);
|
||||
randr_screen_geo(xcb, i, &x, &y, &w, &h, NULL, &name);
|
||||
else if (xinerama)
|
||||
xinerama_screen_geo(xcb, i, &x, &y, &w, &h);
|
||||
else
|
||||
x11_screen_geo(xcb, i, &w, &h);
|
||||
|
||||
if (name == NULL) {
|
||||
sprintf(name_tmp, "%" PRIuFAST32, i);
|
||||
name = name_tmp;
|
||||
}
|
||||
|
||||
dstr_printf(&screen_info,
|
||||
"Screen %" PRIuFAST32 " (%" PRIuFAST32
|
||||
"x%" PRIuFAST32 " @ %" PRIuFAST32 ",%" PRIuFAST32
|
||||
")",
|
||||
i, w, h, x, y);
|
||||
"Screen %s (%" PRIuFAST32 "x%" PRIuFAST32
|
||||
" @ %" PRIuFAST32 ",%" PRIuFAST32 ")",
|
||||
name, w, h, x, y);
|
||||
|
||||
if (name != name_tmp)
|
||||
free(name);
|
||||
|
||||
if (h > 0 && w > 0)
|
||||
obs_property_list_add_int(screens, screen_info.array,
|
||||
|
Loading…
x
Reference in New Issue
Block a user