diff --git a/CI/install-dependencies-linux-ubuntu16.sh b/CI/install-dependencies-linux-ubuntu16.sh index e6652e5d6..52e8d2268 100755 --- a/CI/install-dependencies-linux-ubuntu16.sh +++ b/CI/install-dependencies-linux-ubuntu16.sh @@ -30,6 +30,7 @@ sudo apt-get install -y \ libvlc-dev \ libx11-dev \ libx264-dev \ + libxcb-randr0-dev \ libxcb-shm0-dev \ libxcb-xinerama0-dev \ libxcomposite-dev \ diff --git a/CI/install-dependencies-linux.sh b/CI/install-dependencies-linux.sh index f7749201c..4ab021959 100755 --- a/CI/install-dependencies-linux.sh +++ b/CI/install-dependencies-linux.sh @@ -33,6 +33,7 @@ sudo apt-get install -y \ libvlc-dev \ libx11-dev \ libx264-dev \ + libxcb-randr0-dev \ libxcb-shm0-dev \ libxcb-xinerama0-dev \ libxcomposite-dev \ diff --git a/plugins/linux-capture/CMakeLists.txt b/plugins/linux-capture/CMakeLists.txt index d4f1649f3..70803461f 100644 --- a/plugins/linux-capture/CMakeLists.txt +++ b/plugins/linux-capture/CMakeLists.txt @@ -6,7 +6,7 @@ if(NOT X11_Xcomposite_FOUND) return() endif() -find_package(XCB COMPONENTS XCB SHM XFIXES XINERAMA REQUIRED) +find_package(XCB COMPONENTS XCB RANDR SHM XFIXES XINERAMA REQUIRED) find_package(X11_XCB REQUIRED) include_directories(SYSTEM diff --git a/plugins/linux-capture/xhelpers.c b/plugins/linux-capture/xhelpers.c index 1eeda7c22..724f4f3ed 100644 --- a/plugins/linux-capture/xhelpers.c +++ b/plugins/linux-capture/xhelpers.c @@ -17,6 +17,7 @@ along with this program. If not, see . #include #include +#include #include #include @@ -95,6 +96,78 @@ fail: return -1; } +bool randr_is_active(xcb_connection_t *xcb) +{ + if (!xcb || !xcb_get_extension_data(xcb, &xcb_randr_id)->present) + return false; + + return true; +} + +int randr_screen_count(xcb_connection_t *xcb) +{ + if (!xcb) + return 0; + + xcb_screen_t *screen; + screen = xcb_setup_roots_iterator(xcb_get_setup(xcb)).data; + + xcb_randr_get_screen_resources_cookie_t res_c; + xcb_randr_get_screen_resources_reply_t* res_r; + + res_c = xcb_randr_get_screen_resources(xcb, screen->root); + res_r = xcb_randr_get_screen_resources_reply(xcb, res_c, 0); + if (!res_r) + return 0; + + return xcb_randr_get_screen_resources_crtcs_length(res_r); +} + +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) +{ + xcb_screen_t *xscreen; + xscreen = xcb_setup_roots_iterator(xcb_get_setup(xcb)).data; + + xcb_randr_get_screen_resources_cookie_t res_c; + xcb_randr_get_screen_resources_reply_t* res_r; + + res_c = xcb_randr_get_screen_resources(xcb, xscreen->root); + res_r = xcb_randr_get_screen_resources_reply(xcb, res_c, 0); + if (!res_r) + goto fail; + + int screens = xcb_randr_get_screen_resources_crtcs_length(res_r); + if (screen < 0 || screen >= screens) + goto fail; + + xcb_randr_crtc_t *crtc = xcb_randr_get_screen_resources_crtcs(res_r); + + xcb_randr_get_crtc_info_cookie_t crtc_c; + xcb_randr_get_crtc_info_reply_t *crtc_r; + + crtc_c = xcb_randr_get_crtc_info(xcb, *(crtc + screen), 0); + crtc_r = xcb_randr_get_crtc_info_reply(xcb, crtc_c, 0); + if (!crtc_r) + goto fail; + + *x = crtc_r->x; + *y = crtc_r->y; + *w = crtc_r->width; + *h = crtc_r->height; + + if (rscreen) + *rscreen = xscreen; + + return 0; + +fail: + *x = *y = *w = *h = 0; + return -1; +} + int x11_screen_geo(xcb_connection_t *xcb, int_fast32_t screen, int_fast32_t *w, int_fast32_t *h) { diff --git a/plugins/linux-capture/xhelpers.h b/plugins/linux-capture/xhelpers.h index 066684fea..95aff5c59 100644 --- a/plugins/linux-capture/xhelpers.h +++ b/plugins/linux-capture/xhelpers.h @@ -64,6 +64,39 @@ int xinerama_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); +/** + * Check for Randr extension + * + * @return true if randr is available which means it's active. + */ +bool randr_is_active(xcb_connection_t *xcb); + +/** + * Get the number of Randr screens + * + * @return number of screens + */ +int randr_screen_count(xcb_connection_t *xcb); + +/** + * Get screen geometry for a Rand crtc (screen) + * + * @note On error the passed coordinates/sizes will be set to 0. + * + * @param xcb xcb connection + * @param screen screen number to get geometry for + * @param x x-coordinate of the screen + * @param y y-coordinate of the screen + * @param w width of the screen + * @param h height of the screen + * + * @return < 0 on error + */ +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); + /** * Get screen geometry for a X11 screen * diff --git a/plugins/linux-capture/xshm-input.c b/plugins/linux-capture/xshm-input.c index b5fa3a307..f00c0eb8c 100644 --- a/plugins/linux-capture/xshm-input.c +++ b/plugins/linux-capture/xshm-input.c @@ -18,6 +18,7 @@ along with this program. If not, see . #include #include #include +#include #include #include #include @@ -50,6 +51,7 @@ struct xshm_data { bool show_cursor; bool use_xinerama; + bool use_randr; bool advanced; }; @@ -83,6 +85,9 @@ static bool xshm_check_extensions(xcb_connection_t *xcb) if (!xcb_get_extension_data(xcb, &xcb_xinerama_id)->present) blog(LOG_INFO, "Missing Xinerama extension !"); + if (!xcb_get_extension_data(xcb, &xcb_randr_id)->present) + blog(LOG_INFO, "Missing Randr extension !"); + return ok; } @@ -96,7 +101,15 @@ static int_fast32_t xshm_update_geometry(struct xshm_data *data) int_fast32_t old_width = data->width; int_fast32_t old_height = data->height; - if (data->use_xinerama) { + 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) { + return -1; + } + } + else if (data->use_xinerama) { if (xinerama_screen_geo(data->xcb, data->screen_id, &data->x_org, &data->y_org, &data->width, &data->height) < 0) { @@ -189,6 +202,7 @@ static void xshm_capture_start(struct xshm_data *data) if (!xshm_check_extensions(data->xcb)) goto fail; + data->use_randr = randr_is_active(data->xcb) ? true : false; data->use_xinerama = xinerama_is_active(data->xcb) ? true : false; if (xshm_update_geometry(data) < 0) { @@ -287,16 +301,21 @@ static bool xshm_server_changed(obs_properties_t *props, struct dstr screen_info; dstr_init(&screen_info); + bool randr = randr_is_active(xcb); bool xinerama = xinerama_is_active(xcb); - int_fast32_t count = (xinerama) ? - xinerama_screen_count(xcb) : - xcb_setup_roots_length(xcb_get_setup(xcb)); + int_fast32_t count = (randr) ? + randr_screen_count(xcb) : + (xinerama) ? + xinerama_screen_count(xcb) : + xcb_setup_roots_length(xcb_get_setup(xcb)); for (int_fast32_t i = 0; i < count; ++i) { int_fast32_t x, y, w, h; x = y = w = h = 0; - if (xinerama) + if (randr) + randr_screen_geo(xcb, i, &x, &y, &w, &h, NULL); + else if (xinerama) xinerama_screen_geo(xcb, i, &x, &y, &w, &h); else x11_screen_geo(xcb, i, &w, &h);