From 8caba4decacabb9b34920d0d8a66028a5cd1876f Mon Sep 17 00:00:00 2001 From: fryshorts Date: Sun, 21 Dec 2014 15:04:07 +0100 Subject: [PATCH 01/15] linux-capture: Add xcb libraries to cmake Add xcb libraries needed to port the plugin away from xlib to cmake. --- plugins/linux-capture/CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/linux-capture/CMakeLists.txt b/plugins/linux-capture/CMakeLists.txt index 861e275aa..a19716f09 100644 --- a/plugins/linux-capture/CMakeLists.txt +++ b/plugins/linux-capture/CMakeLists.txt @@ -6,11 +6,16 @@ if(NOT X11_Xcomposite_FOUND) return() endif() +find_package(XCB COMPONENTS XCB SHM XFIXES XINERAMA REQUIRED) +find_package(X11_XCB REQUIRED) + include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs" ${X11_Xcomposite_INCLUDE_PATH} ${X11_X11_INCLUDE_PATH} -) + ${X11_XCB_INCLUDE_DIR} + ${XCB_INCLUDE_DIRS} +) set(linux-capture_SOURCES linux-capture.c @@ -41,6 +46,8 @@ target_link_libraries(linux-capture ${X11_Xinerama_LIB} ${X11_X11_LIB} ${X11_Xcomposite_LIB} + ${X11_XCB_LIBRARIES} + ${XCB_LIBRARIES} ) install_obs_plugin_with_data(linux-capture data) From e7cdb837aaa18341584d8ae6f21d4715feb1f9e5 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Sun, 21 Dec 2014 19:05:50 +0100 Subject: [PATCH 02/15] linux-capture: Add xcb helper functions for shm Add new helper functions managing the shm segment with xcb to xhelpers. --- plugins/linux-capture/xhelpers.c | 40 ++++++++++++++++++++++++++++++++ plugins/linux-capture/xhelpers.h | 24 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/plugins/linux-capture/xhelpers.c b/plugins/linux-capture/xhelpers.c index a1666f1e7..60b5e788e 100644 --- a/plugins/linux-capture/xhelpers.c +++ b/plugins/linux-capture/xhelpers.c @@ -148,3 +148,43 @@ void xshm_detach(xshm_t *xshm) bfree(xshm); } + +xcb_shm_t* xshm_xcb_attach(xcb_connection_t *xcb, const int w, const int h) +{ + if (!xcb) + return NULL; + + xcb_shm_t *shm = bzalloc(sizeof(xcb_shm_t)); + shm->xcb = xcb; + shm->seg = xcb_generate_id(shm->xcb); + + shm->shmid = shmget(IPC_PRIVATE, w * h * 4, IPC_CREAT | 0777); + if (shm->shmid == -1) + goto fail; + + xcb_shm_attach(shm->xcb, shm->seg, shm->shmid, false); + + shm->data = shmat(shm->shmid, NULL, 0); + + return shm; +fail: + xshm_xcb_detach(shm); + return NULL; +} + +void xshm_xcb_detach(xcb_shm_t *shm) +{ + if (!shm) + return; + + xcb_shm_detach(shm->xcb, shm->seg); + + if ((char *) shm->data != (char *) -1) + shmdt(shm->data); + + if (shm->shmid != -1) + shmctl(shm->shmid, IPC_RMID, NULL); + + bfree(shm); +} + diff --git a/plugins/linux-capture/xhelpers.h b/plugins/linux-capture/xhelpers.h index 1c0cd0a38..d94cf5c6c 100644 --- a/plugins/linux-capture/xhelpers.h +++ b/plugins/linux-capture/xhelpers.h @@ -23,6 +23,7 @@ extern "C" { #include #include +#include #include typedef struct { @@ -32,6 +33,13 @@ typedef struct { bool attached; } xshm_t; +typedef struct { + xcb_connection_t *xcb; + xcb_shm_seg_t seg; + int shmid; + uint8_t *data; +} xcb_shm_t; + /** * Check for Xinerama extension * @@ -96,6 +104,22 @@ xshm_t *xshm_attach(Display *dpy, Screen *screen, */ void xshm_detach(xshm_t *xshm); +/** + * Attach a shared memory segment to the X-Server + * + * @param xcb xcb connection + * @param w width of the captured screen + * @param h height of the captured screen + * + * @return NULL on error + */ +xcb_shm_t *xshm_xcb_attach(xcb_connection_t *xcb, const int w, const int h); + +/** + * Detach a shared memory segment + */ +void xshm_xcb_detach(xcb_shm_t *shm); + #ifdef __cplusplus } #endif From 069ee92ff436b4872d382b5574936872b7e6540f Mon Sep 17 00:00:00 2001 From: fryshorts Date: Sun, 21 Dec 2014 19:51:14 +0100 Subject: [PATCH 03/15] linux-capture: Add helper to get xcb screen Add a helper function to get a xcb screen from a screen id. --- plugins/linux-capture/xhelpers.c | 12 ++++++++++++ plugins/linux-capture/xhelpers.h | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/plugins/linux-capture/xhelpers.c b/plugins/linux-capture/xhelpers.c index 60b5e788e..1604a107e 100644 --- a/plugins/linux-capture/xhelpers.c +++ b/plugins/linux-capture/xhelpers.c @@ -188,3 +188,15 @@ void xshm_xcb_detach(xcb_shm_t *shm) bfree(shm); } +xcb_screen_t *xcb_get_screen(xcb_connection_t *xcb, int screen) +{ + xcb_screen_iterator_t iter; + + iter = xcb_setup_roots_iterator(xcb_get_setup(xcb)); + for (; iter.rem; --screen, xcb_screen_next(&iter)) { + if (screen == 0) + return iter.data; + } + + return NULL; +} diff --git a/plugins/linux-capture/xhelpers.h b/plugins/linux-capture/xhelpers.h index d94cf5c6c..8b7f9b91a 100644 --- a/plugins/linux-capture/xhelpers.h +++ b/plugins/linux-capture/xhelpers.h @@ -24,6 +24,7 @@ extern "C" { #include #include #include +#include #include typedef struct { @@ -120,6 +121,15 @@ xcb_shm_t *xshm_xcb_attach(xcb_connection_t *xcb, const int w, const int h); */ void xshm_xcb_detach(xcb_shm_t *shm); +/** + * Get screen by id for a xcb connection + * + * @param xcb xcb connection + * @param screen id of the screen + * @return screen info structure + */ +xcb_screen_t *xcb_get_screen(xcb_connection_t *xcb, int screen); + #ifdef __cplusplus } #endif From 172a4d7a5244efa36e44a547e4f42ff283aa7b87 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Sun, 21 Dec 2014 21:33:10 +0100 Subject: [PATCH 04/15] linux-capture: Add xcb cursor helper library Add a new helper library to handle the mouse cursor using xcb. Since porting the old library without either keeping legacy code or breaking the api would have been non-trivial, this is added as a completely separate implementation. Once all code is ported over to use this library, the old one can be removed. --- plugins/linux-capture/CMakeLists.txt | 2 + plugins/linux-capture/xcursor-xcb.c | 114 +++++++++++++++++++++++++++ plugins/linux-capture/xcursor-xcb.h | 79 +++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 plugins/linux-capture/xcursor-xcb.c create mode 100644 plugins/linux-capture/xcursor-xcb.h diff --git a/plugins/linux-capture/CMakeLists.txt b/plugins/linux-capture/CMakeLists.txt index a19716f09..3fb035025 100644 --- a/plugins/linux-capture/CMakeLists.txt +++ b/plugins/linux-capture/CMakeLists.txt @@ -20,6 +20,7 @@ include_directories(SYSTEM set(linux-capture_SOURCES linux-capture.c xcursor.c + xcursor-xcb.c xhelpers.c xshm-input.c xcomposite-main.cpp @@ -28,6 +29,7 @@ set(linux-capture_SOURCES ) set(linux-capture_HEADERS xcursor.h + xcursor-xcb.h xhelpers.h xcompcap-main.hpp xcompcap-helper.hpp diff --git a/plugins/linux-capture/xcursor-xcb.c b/plugins/linux-capture/xcursor-xcb.c new file mode 100644 index 000000000..fb912181a --- /dev/null +++ b/plugins/linux-capture/xcursor-xcb.c @@ -0,0 +1,114 @@ +/* +Copyright (C) 2014 by Leonhard Oelke + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include +#include + +#include +#include "xcursor-xcb.h" + +/* + * Create the cursor texture, either by updating if the new cursor has the same + * size or by creating a new texture if the size is different + */ +static void xcb_xcursor_create(xcb_xcursor_t *data, + xcb_xfixes_get_cursor_image_reply_t *xc) +{ + uint32_t *pixels = xcb_xfixes_get_cursor_image_cursor_image(xc); + if (!pixels) + return; + + if (data->tex && data->last_height == xc->width && + data->last_width == xc->height) { + gs_texture_set_image(data->tex, (const uint8_t *) pixels, + xc->width * sizeof(uint32_t), false); + } else { + if (data->tex) + gs_texture_destroy(data->tex); + + data->tex = gs_texture_create(xc->width, xc->height, + GS_BGRA, 1, (const uint8_t **) &pixels, GS_DYNAMIC); + } + + data->last_serial = xc->cursor_serial; + data->last_width = xc->width; + data->last_height = xc->height; +} + +/** + * We need to check for the xfixes version in order to initialize it ? + */ +xcb_xcursor_t *xcb_xcursor_init(xcb_connection_t *xcb) +{ + xcb_xcursor_t *data = bzalloc(sizeof(xcb_xcursor_t)); + + xcb_xfixes_query_version_cookie_t xfix_c; + + xfix_c = xcb_xfixes_query_version_unchecked(xcb, + XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION); + free(xcb_xfixes_query_version_reply(xcb, xfix_c, NULL)); + + return data; +} + +void xcb_xcursor_destroy(xcb_xcursor_t *data) +{ + if (data->tex) + gs_texture_destroy(data->tex); + bfree(data); +} + +void xcb_xcursor_update(xcb_xcursor_t *data, + xcb_xfixes_get_cursor_image_reply_t *xc) +{ + if (!data || !xc) + return; + + if (!data->tex || data->last_serial != xc->cursor_serial) + xcb_xcursor_create(data, xc); + + data->x = xc->x - data->x_org; + data->y = xc->y - data->y_org; + data->x_render = data->x - xc->xhot; + data->y_render = data->y - xc->yhot; +} + +void xcb_xcursor_render(xcb_xcursor_t *data) +{ + if (!data->tex) + return; + + gs_effect_t *effect = gs_get_effect(); + gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image"); + gs_effect_set_texture(image, data->tex); + + gs_matrix_push(); + gs_matrix_translate3f(data->x_render, data->y_render, 0.0f); + + gs_enable_blending(true); + gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA); + gs_draw_sprite(data->tex, 0, 0, 0); + + gs_matrix_pop(); +} + +void xcb_xcursor_offset(xcb_xcursor_t* data, const int x_org, const int y_org) +{ + data->x_org = x_org; + data->y_org = y_org; +} + diff --git a/plugins/linux-capture/xcursor-xcb.h b/plugins/linux-capture/xcursor-xcb.h new file mode 100644 index 000000000..69561b6aa --- /dev/null +++ b/plugins/linux-capture/xcursor-xcb.h @@ -0,0 +1,79 @@ +/* +Copyright (C) 2014 by Leonhard Oelke + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + unsigned int last_serial; + unsigned int last_width; + unsigned int last_height; + gs_texture_t *tex; + + int x; + int y; + int x_org; + int y_org; + float x_render; + float y_render; +} xcb_xcursor_t; + +/** + * Initializes the xcursor object + * + * @return NULL on error + */ +xcb_xcursor_t *xcb_xcursor_init(xcb_connection_t *xcb); + +/** + * Destroys the xcursor object + * @param data xcursor object + */ +void xcb_xcursor_destroy(xcb_xcursor_t *data); + +/** + * Update the cursor data + * @param data xcursor object + * @param xc xcb cursor image reply + * + * @note This needs to be executed within a valid render context + * + */ +void xcb_xcursor_update(xcb_xcursor_t *data, + xcb_xfixes_get_cursor_image_reply_t *xc); + +/** + * Draw the cursor + * + * This needs to be executed within a valid render context + */ +void xcb_xcursor_render(xcb_xcursor_t *data); + +/** + * Specify offset for the cursor + */ +void xcb_xcursor_offset(xcb_xcursor_t *data, const int x_org, const int y_org); + +#ifdef __cplusplus +} +#endif From 4ad41004e03076d189e21ec3084338ee4855df31 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Sun, 21 Dec 2014 22:32:28 +0100 Subject: [PATCH 05/15] linux-capture: Add function to check extensions Add an internal function to check for all the extensions needed by the xshm capture to work. --- plugins/linux-capture/xshm-input.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/plugins/linux-capture/xshm-input.c b/plugins/linux-capture/xshm-input.c index 6cd305278..9ef7a77db 100644 --- a/plugins/linux-capture/xshm-input.c +++ b/plugins/linux-capture/xshm-input.c @@ -20,6 +20,9 @@ along with this program. If not, see . #include #include #include +#include +#include +#include #include #include @@ -74,6 +77,24 @@ static inline void xshm_resize_texture(struct xshm_data *data) GS_BGRA, 1, NULL, GS_DYNAMIC); } +/** + * Check if the xserver supports all the extensions we need + */ +static bool xshm_check_extensions(xcb_connection_t *xcb) +{ + bool ok = true; + + if (!xcb_get_extension_data(xcb, &xcb_shm_id)->present) { + blog(LOG_ERROR, "Missing SHM extension !"); + ok = false; + } + + if (!xcb_get_extension_data(xcb, &xcb_xinerama_id)->present) + blog(LOG_INFO, "Missing Xinerama extension !"); + + return ok; +} + /** * Update the capture * From 53ee22ae5a9c8b922e7d3bb1417450515e3a0fa4 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Sun, 21 Dec 2014 18:51:36 +0100 Subject: [PATCH 06/15] linux-capture: Add xcb connection to source data Add a xcb connection to the source data for the xshm capture for later use in the porting process. --- plugins/linux-capture/xshm-input.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/linux-capture/xshm-input.c b/plugins/linux-capture/xshm-input.c index 9ef7a77db..709bdc398 100644 --- a/plugins/linux-capture/xshm-input.c +++ b/plugins/linux-capture/xshm-input.c @@ -40,6 +40,9 @@ struct xshm_data { Display *dpy; /** Xlib screen object */ Screen *screen; + + xcb_connection_t *xcb; + /** user setting - the server name to capture from */ char *server; /** user setting - the id of the screen that should be captured */ @@ -195,6 +198,9 @@ static void xshm_capture_start(struct xshm_data *data) goto fail; } + XSetEventQueueOwner(data->dpy, XCBOwnsEventQueue); + data->xcb = XGetXCBConnection(data->dpy); + if (!XShmQueryExtension(data->dpy)) { blog(LOG_ERROR, "XShm extension not found !"); goto fail; @@ -296,6 +302,9 @@ static bool xshm_server_changed(obs_properties_t *props, return true; } + XSetEventQueueOwner(dpy, XCBOwnsEventQueue); + xcb_connection_t *xcb = XGetXCBConnection(dpy); + struct dstr screen_info; dstr_init(&screen_info); bool xinerama = xinerama_is_active(dpy); From e20cf649b81a625d8eb02ec593c2024bfb43ba19 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Sun, 21 Dec 2014 20:05:38 +0100 Subject: [PATCH 07/15] linux-capture: Add xcb screen to source data Add xcb screen structure to the source data for later use in the porting process. --- plugins/linux-capture/xshm-input.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/linux-capture/xshm-input.c b/plugins/linux-capture/xshm-input.c index 709bdc398..8353a10a4 100644 --- a/plugins/linux-capture/xshm-input.c +++ b/plugins/linux-capture/xshm-input.c @@ -42,6 +42,7 @@ struct xshm_data { Screen *screen; xcb_connection_t *xcb; + xcb_screen_t *xcb_screen; /** user setting - the server name to capture from */ char *server; @@ -114,7 +115,8 @@ static int_fast32_t xshm_update_geometry(struct xshm_data *data) &data->width, &data->height) < 0) { return -1; } - data->screen = XDefaultScreenOfDisplay(data->dpy); + data->screen = XDefaultScreenOfDisplay(data->dpy); + data->xcb_screen = xcb_get_screen(data->xcb, 0); } else { data->x_org = 0; @@ -123,7 +125,8 @@ static int_fast32_t xshm_update_geometry(struct xshm_data *data) &data->width, &data->height) < 0) { return -1; } - data->screen = XScreenOfDisplay(data->dpy, data->screen_id); + data->screen = XScreenOfDisplay(data->dpy, data->screen_id); + data->xcb_screen = xcb_get_screen(data->xcb, data->screen_id); } if (!data->width || !data->height) { From 38f2c57c12d21e0942a574d9326423abcfc2491d Mon Sep 17 00:00:00 2001 From: fryshorts Date: Sun, 21 Dec 2014 19:56:48 +0100 Subject: [PATCH 08/15] linux-capture: Port xshm handling to xcb Use the new xcb based xshm functions to attach the shared memory segment and capture the image from the xserver. --- plugins/linux-capture/xshm-input.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/plugins/linux-capture/xshm-input.c b/plugins/linux-capture/xshm-input.c index 8353a10a4..ede765f37 100644 --- a/plugins/linux-capture/xshm-input.c +++ b/plugins/linux-capture/xshm-input.c @@ -53,7 +53,7 @@ struct xshm_data { /** size for the capture */ int_fast32_t width, height; /** shared memory management object */ - xshm_t *xshm; + xcb_shm_t *xshm; /** the texture used to display the capture */ gs_texture_t *texture; /** cursor object for displaying the server */ @@ -171,7 +171,7 @@ static void xshm_capture_stop(struct xshm_data *data) obs_leave_graphics(); if (data->xshm) { - xshm_detach(data->xshm); + xshm_xcb_detach(data->xshm); data->xshm = NULL; } @@ -216,8 +216,7 @@ static void xshm_capture_start(struct xshm_data *data) goto fail; } - data->xshm = xshm_attach(data->dpy, data->screen, - data->width, data->height); + data->xshm = xshm_xcb_attach(data->xcb, data->width, data->height); if (!data->xshm) { blog(LOG_ERROR, "failed to attach shm !"); goto fail; @@ -416,16 +415,27 @@ static void xshm_video_tick(void *vptr, float seconds) if (!data->texture) return; + xcb_shm_get_image_cookie_t img_c; + xcb_shm_get_image_reply_t *img_r; + + img_c = xcb_shm_get_image_unchecked(data->xcb, data->xcb_screen->root, + data->x_org, data->y_org, data->width, data->height, + ~0, XCB_IMAGE_FORMAT_Z_PIXMAP, data->xshm->seg, 0); + img_r = xcb_shm_get_image_reply(data->xcb, img_c, NULL); + + if (!img_r) + return; + obs_enter_graphics(); - XShmGetImage(data->dpy, XRootWindowOfScreen(data->screen), - data->xshm->image, data->x_org, data->y_org, AllPlanes); - gs_texture_set_image(data->texture, (void *) data->xshm->image->data, + gs_texture_set_image(data->texture, (void *) data->xshm->data, data->width * 4, false); xcursor_tick(data->cursor); obs_leave_graphics(); + + free(img_r); } /** From aa016706a24376dd23edb47d08022f1d763f5e86 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Sun, 21 Dec 2014 21:35:17 +0100 Subject: [PATCH 09/15] linux-capture: Port cursor handling to xcb Use the new xcb based cursor library to handle the cursor in the xshm plugin. --- plugins/linux-capture/xshm-input.c | 32 +++++++++++++++++++----------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/plugins/linux-capture/xshm-input.c b/plugins/linux-capture/xshm-input.c index ede765f37..6f4cb89d7 100644 --- a/plugins/linux-capture/xshm-input.c +++ b/plugins/linux-capture/xshm-input.c @@ -22,11 +22,12 @@ along with this program. If not, see . #include #include #include +#include #include #include #include -#include "xcursor.h" +#include "xcursor-xcb.h" #include "xhelpers.h" #define XSHM_DATA(voidptr) struct xshm_data *data = voidptr; @@ -57,7 +58,7 @@ struct xshm_data { /** the texture used to display the capture */ gs_texture_t *texture; /** cursor object for displaying the server */ - xcursor_t *cursor; + xcb_xcursor_t *cursor; /** user setting - if cursor should be displayed */ bool show_cursor; /** set if xinerama is available and active on the screen */ @@ -164,7 +165,7 @@ static void xshm_capture_stop(struct xshm_data *data) data->texture = NULL; } if (data->cursor) { - xcursor_destroy(data->cursor); + xcb_xcursor_destroy(data->cursor); data->cursor = NULL; } @@ -222,10 +223,11 @@ static void xshm_capture_start(struct xshm_data *data) goto fail; } + data->cursor = xcb_xcursor_init(data->xcb); + xcb_xcursor_offset(data->cursor, data->x_org, data->y_org); + obs_enter_graphics(); - data->cursor = xcursor_init(data->dpy); - xcursor_offset(data->cursor, data->x_org, data->y_org); xshm_resize_texture(data); obs_leave_graphics(); @@ -415,27 +417,33 @@ static void xshm_video_tick(void *vptr, float seconds) if (!data->texture) return; - xcb_shm_get_image_cookie_t img_c; - xcb_shm_get_image_reply_t *img_r; + xcb_shm_get_image_cookie_t img_c; + xcb_shm_get_image_reply_t *img_r; + xcb_xfixes_get_cursor_image_cookie_t cur_c; + xcb_xfixes_get_cursor_image_reply_t *cur_r; img_c = xcb_shm_get_image_unchecked(data->xcb, data->xcb_screen->root, data->x_org, data->y_org, data->width, data->height, ~0, XCB_IMAGE_FORMAT_Z_PIXMAP, data->xshm->seg, 0); - img_r = xcb_shm_get_image_reply(data->xcb, img_c, NULL); + cur_c = xcb_xfixes_get_cursor_image_unchecked(data->xcb); + + img_r = xcb_shm_get_image_reply(data->xcb, img_c, NULL); + cur_r = xcb_xfixes_get_cursor_image_reply(data->xcb, cur_c, NULL); if (!img_r) - return; + goto exit; obs_enter_graphics(); gs_texture_set_image(data->texture, (void *) data->xshm->data, data->width * 4, false); - - xcursor_tick(data->cursor); + xcb_xcursor_update(data->cursor, cur_r); obs_leave_graphics(); +exit: free(img_r); + free(cur_r); } /** @@ -455,7 +463,7 @@ static void xshm_video_render(void *vptr, gs_effect_t *effect) gs_draw_sprite(data->texture, 0, 0, 0); if (data->show_cursor) - xcursor_render(data->cursor); + xcb_xcursor_render(data->cursor); gs_reset_blend_state(); } From 008f4467f001b3f1c5757629ed1fb078d8ac36c8 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Sun, 21 Dec 2014 22:43:11 +0100 Subject: [PATCH 10/15] linux-capture: Use xcb to check for extensions Use the previously added helper function to check for needed extensions. --- plugins/linux-capture/xshm-input.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/linux-capture/xshm-input.c b/plugins/linux-capture/xshm-input.c index 6f4cb89d7..6fb4e9bcd 100644 --- a/plugins/linux-capture/xshm-input.c +++ b/plugins/linux-capture/xshm-input.c @@ -205,10 +205,8 @@ static void xshm_capture_start(struct xshm_data *data) XSetEventQueueOwner(data->dpy, XCBOwnsEventQueue); data->xcb = XGetXCBConnection(data->dpy); - if (!XShmQueryExtension(data->dpy)) { - blog(LOG_ERROR, "XShm extension not found !"); + if (!xshm_check_extensions(data->xcb)) goto fail; - } data->use_xinerama = xinerama_is_active(data->dpy) ? true : false; From 4d2e730bfabb01af2b3abc3c7202fc99fcc9ddb1 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Sun, 21 Dec 2014 22:54:54 +0100 Subject: [PATCH 11/15] linux-capture: Remove XLib based shm helpers Remove the old XLib based shm helper functions from xhelpers. --- plugins/linux-capture/xhelpers.c | 58 ------------------------------ plugins/linux-capture/xhelpers.h | 26 -------------- plugins/linux-capture/xshm-input.c | 4 +-- 3 files changed, 2 insertions(+), 86 deletions(-) diff --git a/plugins/linux-capture/xhelpers.c b/plugins/linux-capture/xhelpers.c index 1604a107e..2bd769067 100644 --- a/plugins/linux-capture/xhelpers.c +++ b/plugins/linux-capture/xhelpers.c @@ -91,64 +91,6 @@ fail: return -1; } -xshm_t *xshm_attach(Display *dpy, Screen *screen, - int_fast32_t w, int_fast32_t h) -{ - if (!dpy || !screen) - return NULL; - - xshm_t *xshm = bzalloc(sizeof(xshm_t)); - - xshm->dpy = dpy; - xshm->image = XShmCreateImage(xshm->dpy, DefaultVisualOfScreen(screen), - DefaultDepthOfScreen(screen), ZPixmap, NULL, &xshm->info, - w, h); - if (!xshm->image) - goto fail; - - xshm->info.shmid = shmget(IPC_PRIVATE, - xshm->image->bytes_per_line * xshm->image->height, - IPC_CREAT | 0700); - if (xshm->info.shmid < 0) - goto fail; - - xshm->info.shmaddr - = xshm->image->data - = (char *) shmat(xshm->info.shmid, 0, 0); - if (xshm->info.shmaddr == (char *) -1) - goto fail; - xshm->info.readOnly = false; - - if (!XShmAttach(xshm->dpy, &xshm->info)) - goto fail; - - xshm->attached = true; - return xshm; -fail: - xshm_detach(xshm); - return NULL; -} - -void xshm_detach(xshm_t *xshm) -{ - if (!xshm) - return; - - if (xshm->attached) - XShmDetach(xshm->dpy, &xshm->info); - - if (xshm->info.shmaddr != (char *) -1) - shmdt(xshm->info.shmaddr); - - if (xshm->info.shmid != -1) - shmctl(xshm->info.shmid, IPC_RMID, NULL); - - if (xshm->image) - XDestroyImage(xshm->image); - - bfree(xshm); -} - xcb_shm_t* xshm_xcb_attach(xcb_connection_t *xcb, const int w, const int h) { if (!xcb) diff --git a/plugins/linux-capture/xhelpers.h b/plugins/linux-capture/xhelpers.h index 8b7f9b91a..50b1e4986 100644 --- a/plugins/linux-capture/xhelpers.h +++ b/plugins/linux-capture/xhelpers.h @@ -22,18 +22,10 @@ extern "C" { #endif #include -#include #include #include #include -typedef struct { - XShmSegmentInfo info; - XImage *image; - Display *dpy; - bool attached; -} xshm_t; - typedef struct { xcb_connection_t *xcb; xcb_shm_seg_t seg; @@ -87,24 +79,6 @@ int_fast32_t xinerama_screen_geo(Display *dpy, const int_fast32_t screen, int_fast32_t x11_screen_geo(Display *dpy, const int_fast32_t screen, int_fast32_t *w, int_fast32_t *h); -/** - * Attach a shared memory segment to the X-Server - * - * @param dpy X11 Display - * @param screen X11 Screen - * @param w width for the shared memory segment - * @param h height for the shared memory segment - * - * @return NULL on error - */ -xshm_t *xshm_attach(Display *dpy, Screen *screen, - int_fast32_t w, int_fast32_t h); - -/** - * Detach a shared memory segment - */ -void xshm_detach(xshm_t *xshm); - /** * Attach a shared memory segment to the X-Server * diff --git a/plugins/linux-capture/xshm-input.c b/plugins/linux-capture/xshm-input.c index 6fb4e9bcd..dd290e5b7 100644 --- a/plugins/linux-capture/xshm-input.c +++ b/plugins/linux-capture/xshm-input.c @@ -18,8 +18,8 @@ along with this program. If not, see . #include #include #include -#include -#include +//#include +//#include #include #include #include From 114ccd33ee24d73b2576bd289150d4799bc43670 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Mon, 22 Dec 2014 00:12:37 +0100 Subject: [PATCH 12/15] linux-capture: Port geometry functions to xcb Replace XLib code with xcb in the geometry helper functions. --- plugins/linux-capture/xhelpers.c | 118 ++++++++++++++++++----------- plugins/linux-capture/xhelpers.h | 16 ++-- plugins/linux-capture/xshm-input.c | 16 ++-- 3 files changed, 89 insertions(+), 61 deletions(-) diff --git a/plugins/linux-capture/xhelpers.c b/plugins/linux-capture/xhelpers.c index 2bd769067..1eeda7c22 100644 --- a/plugins/linux-capture/xhelpers.c +++ b/plugins/linux-capture/xhelpers.c @@ -17,75 +17,105 @@ along with this program. If not, see . #include #include -#include -#include +#include +#include #include "xhelpers.h" -int_fast32_t xinerama_is_active(Display *dpy) +bool xinerama_is_active(xcb_connection_t *xcb) { - int minor, major; - if (!dpy) - return 0; - if (!XineramaQueryVersion(dpy, &minor, &major)) - return 0; - if (!XineramaIsActive(dpy)) - return 0; - return 1; + if (!xcb || !xcb_get_extension_data(xcb, &xcb_xinerama_id)->present) + return false; + + bool active = true; + xcb_xinerama_is_active_cookie_t xnr_c; + xcb_xinerama_is_active_reply_t *xnr_r; + + xnr_c = xcb_xinerama_is_active_unchecked(xcb); + xnr_r = xcb_xinerama_is_active_reply(xcb, xnr_c, NULL); + if (!xnr_r || xnr_r->state == 0) + active = false; + free(xnr_r); + + return active; } -int_fast32_t xinerama_screen_count(Display *dpy) +int xinerama_screen_count(xcb_connection_t *xcb) { - int screens; - if (!dpy) + if (!xcb) return 0; - XFree(XineramaQueryScreens(dpy, &screens)); + + int screens = 0; + xcb_xinerama_query_screens_cookie_t scr_c; + xcb_xinerama_query_screens_reply_t *scr_r; + + scr_c = xcb_xinerama_query_screens_unchecked(xcb); + scr_r = xcb_xinerama_query_screens_reply(xcb, scr_c, NULL); + if (scr_r) + screens = scr_r->number; + free(scr_r); + return screens; } -int_fast32_t xinerama_screen_geo(Display *dpy, const int_fast32_t screen, - int_fast32_t *x, int_fast32_t *y, int_fast32_t *w, int_fast32_t *h) +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) { - int screens; - XineramaScreenInfo *info = NULL; - - if (!dpy) - goto fail; - info = XineramaQueryScreens(dpy, &screens); - if (screen < 0 || screen >= screens) + if (!xcb) goto fail; - *x = info[screen].x_org; - *y = info[screen].y_org; - *w = info[screen].width; - *h = info[screen].height; + bool success = false; + xcb_xinerama_query_screens_cookie_t scr_c; + xcb_xinerama_query_screens_reply_t *scr_r; + xcb_xinerama_screen_info_iterator_t iter; + + scr_c = xcb_xinerama_query_screens_unchecked(xcb); + scr_r = xcb_xinerama_query_screens_reply(xcb, scr_c, NULL); + if (!scr_r) + goto fail; + + iter = xcb_xinerama_query_screens_screen_info_iterator(scr_r); + for (; iter.rem; --screen, xcb_xinerama_screen_info_next(&iter)) { + if (!screen) { + *x = iter.data->x_org; + *y = iter.data->y_org; + *w = iter.data->width; + *h = iter.data->height; + success = true; + } + } + free(scr_r); + + if (success) + return 0; - XFree(info); - return 0; fail: - if (info) - XFree(info); - *x = *y = *w = *h = 0; return -1; } -int_fast32_t x11_screen_geo(Display *dpy, const int_fast32_t screen, - int_fast32_t *w, int_fast32_t *h) +int x11_screen_geo(xcb_connection_t *xcb, int_fast32_t screen, + int_fast32_t *w, int_fast32_t *h) { - Screen *scr; - - if (!dpy || screen < 0 || screen >= XScreenCount(dpy)) + if (!xcb) goto fail; - scr = XScreenOfDisplay(dpy, screen); - if (!scr) - goto fail; + bool success = false; + xcb_screen_iterator_t iter; - *w = XWidthOfScreen(scr); - *h = XHeightOfScreen(scr); + iter = xcb_setup_roots_iterator(xcb_get_setup(xcb)); + for (; iter.rem; --screen, xcb_screen_next(&iter)) { + if (!screen) { + *w = iter.data->width_in_pixels; + *h = iter.data->height_in_pixels; + success = true; + } + } + + if (success) + return 0; - return 0; fail: *w = *h = 0; return -1; diff --git a/plugins/linux-capture/xhelpers.h b/plugins/linux-capture/xhelpers.h index 50b1e4986..7aa12f227 100644 --- a/plugins/linux-capture/xhelpers.h +++ b/plugins/linux-capture/xhelpers.h @@ -21,7 +21,6 @@ along with this program. If not, see . extern "C" { #endif -#include #include #include #include @@ -36,16 +35,16 @@ typedef struct { /** * Check for Xinerama extension * - * @return > 0 if Xinerama is available and active + * @return true if xinerama is available and active */ -int_fast32_t xinerama_is_active(Display *dpy); +bool xinerama_is_active(xcb_connection_t *xcb); /** * Get the number of Xinerama screens * * @return number of screens */ -int_fast32_t xinerama_screen_count(Display *dpy); +int xinerama_screen_count(xcb_connection_t *xcb); /** * Get screen geometry for a Xinerama screen @@ -61,8 +60,9 @@ int_fast32_t xinerama_screen_count(Display *dpy); * * @return < 0 on error */ -int_fast32_t xinerama_screen_geo(Display *dpy, const int_fast32_t screen, - int_fast32_t *x, int_fast32_t *y, int_fast32_t *w, int_fast32_t *h); +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); /** * Get screen geometry for a X11 screen @@ -76,8 +76,8 @@ int_fast32_t xinerama_screen_geo(Display *dpy, const int_fast32_t screen, * * @return < 0 on error */ -int_fast32_t x11_screen_geo(Display *dpy, const int_fast32_t screen, - int_fast32_t *w, int_fast32_t *h); +int x11_screen_geo(xcb_connection_t *xcb, int_fast32_t screen, + int_fast32_t *w, int_fast32_t *h); /** * Attach a shared memory segment to the X-Server diff --git a/plugins/linux-capture/xshm-input.c b/plugins/linux-capture/xshm-input.c index dd290e5b7..1b48f5b6e 100644 --- a/plugins/linux-capture/xshm-input.c +++ b/plugins/linux-capture/xshm-input.c @@ -18,8 +18,6 @@ along with this program. If not, see . #include #include #include -//#include -//#include #include #include #include @@ -111,7 +109,7 @@ static int_fast32_t xshm_update_geometry(struct xshm_data *data) int_fast32_t old_height = data->height; if (data->use_xinerama) { - if (xinerama_screen_geo(data->dpy, data->screen_id, + if (xinerama_screen_geo(data->xcb, data->screen_id, &data->x_org, &data->y_org, &data->width, &data->height) < 0) { return -1; @@ -122,7 +120,7 @@ static int_fast32_t xshm_update_geometry(struct xshm_data *data) else { data->x_org = 0; data->y_org = 0; - if (x11_screen_geo(data->dpy, data->screen_id, + if (x11_screen_geo(data->xcb, data->screen_id, &data->width, &data->height) < 0) { return -1; } @@ -208,7 +206,7 @@ static void xshm_capture_start(struct xshm_data *data) if (!xshm_check_extensions(data->xcb)) goto fail; - data->use_xinerama = xinerama_is_active(data->dpy) ? true : false; + data->use_xinerama = xinerama_is_active(data->xcb) ? true : false; if (xshm_update_geometry(data) < 0) { blog(LOG_ERROR, "failed to update geometry !"); @@ -309,18 +307,18 @@ static bool xshm_server_changed(obs_properties_t *props, struct dstr screen_info; dstr_init(&screen_info); - bool xinerama = xinerama_is_active(dpy); + bool xinerama = xinerama_is_active(xcb); int_fast32_t count = (xinerama) ? - xinerama_screen_count(dpy) : XScreenCount(dpy); + xinerama_screen_count(xcb) : XScreenCount(dpy); for (int_fast32_t i = 0; i < count; ++i) { int_fast32_t x, y, w, h; x = y = w = h = 0; if (xinerama) - xinerama_screen_geo(dpy, i, &x, &y, &w, &h); + xinerama_screen_geo(xcb, i, &x, &y, &w, &h); else - x11_screen_geo(dpy, i, &w, &h); + x11_screen_geo(xcb, i, &w, &h); dstr_printf(&screen_info, "Screen %"PRIuFAST32" (%"PRIuFAST32 "x%"PRIuFAST32" @ %"PRIuFAST32 From 2dffa894f33137ce8ed1b082e2c004a6c54452f4 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Mon, 22 Dec 2014 00:30:14 +0100 Subject: [PATCH 13/15] linux-capture: Port display connection to xcb Remove the last bits of Xlib code from the xshm capture plugin and use xcb exclusively. --- plugins/linux-capture/xshm-input.c | 33 +++++++++--------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/plugins/linux-capture/xshm-input.c b/plugins/linux-capture/xshm-input.c index 1b48f5b6e..2648779c5 100644 --- a/plugins/linux-capture/xshm-input.c +++ b/plugins/linux-capture/xshm-input.c @@ -18,7 +18,6 @@ along with this program. If not, see . #include #include #include -#include #include #include #include @@ -35,10 +34,6 @@ along with this program. If not, see . struct xshm_data { /** The source object */ obs_source_t *source; - /** Xlib display object */ - Display *dpy; - /** Xlib screen object */ - Screen *screen; xcb_connection_t *xcb; xcb_screen_t *xcb_screen; @@ -114,7 +109,6 @@ static int_fast32_t xshm_update_geometry(struct xshm_data *data) &data->width, &data->height) < 0) { return -1; } - data->screen = XDefaultScreenOfDisplay(data->dpy); data->xcb_screen = xcb_get_screen(data->xcb, 0); } else { @@ -124,7 +118,6 @@ static int_fast32_t xshm_update_geometry(struct xshm_data *data) &data->width, &data->height) < 0) { return -1; } - data->screen = XScreenOfDisplay(data->dpy, data->screen_id); data->xcb_screen = xcb_get_screen(data->xcb, data->screen_id); } @@ -174,10 +167,9 @@ static void xshm_capture_stop(struct xshm_data *data) data->xshm = NULL; } - if (data->dpy) { - XSync(data->dpy, true); - XCloseDisplay(data->dpy); - data->dpy = NULL; + if (data->xcb) { + xcb_disconnect(data->xcb); + data->xcb = NULL; } if (data->server) { @@ -194,15 +186,12 @@ static void xshm_capture_start(struct xshm_data *data) const char *server = (data->advanced && *data->server) ? data->server : NULL; - data->dpy = XOpenDisplay(server); - if (!data->dpy) { + data->xcb = xcb_connect(server, NULL); + if (!data->xcb || xcb_connection_has_error(data->xcb)) { blog(LOG_ERROR, "Unable to open X display !"); goto fail; } - XSetEventQueueOwner(data->dpy, XCBOwnsEventQueue); - data->xcb = XGetXCBConnection(data->dpy); - if (!xshm_check_extensions(data->xcb)) goto fail; @@ -296,20 +285,18 @@ static bool xshm_server_changed(obs_properties_t *props, obs_property_list_clear(screens); - Display *dpy = XOpenDisplay(server); - if (!dpy) { + xcb_connection_t *xcb = xcb_connect(server, NULL); + if (!xcb || xcb_connection_has_error(xcb)) { obs_property_set_enabled(screens, false); return true; } - XSetEventQueueOwner(dpy, XCBOwnsEventQueue); - xcb_connection_t *xcb = XGetXCBConnection(dpy); - struct dstr screen_info; dstr_init(&screen_info); bool xinerama = xinerama_is_active(xcb); int_fast32_t count = (xinerama) ? - xinerama_screen_count(xcb) : XScreenCount(dpy); + 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; @@ -339,7 +326,7 @@ static bool xshm_server_changed(obs_properties_t *props, dstr_free(&screen_info); - XCloseDisplay(dpy); + xcb_disconnect(xcb); obs_property_set_enabled(screens, true); return true; From ed839dce1943b8eabda984534ca4608c15b11f2d Mon Sep 17 00:00:00 2001 From: fryshorts Date: Mon, 22 Dec 2014 00:35:32 +0100 Subject: [PATCH 14/15] linux-capture: Remove unused dependencies Remove dependencies from cmake that are no longer needed due to the port to xcb. --- plugins/linux-capture/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/linux-capture/CMakeLists.txt b/plugins/linux-capture/CMakeLists.txt index 3fb035025..d4f1649f3 100644 --- a/plugins/linux-capture/CMakeLists.txt +++ b/plugins/linux-capture/CMakeLists.txt @@ -13,7 +13,6 @@ include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs" ${X11_Xcomposite_INCLUDE_PATH} ${X11_X11_INCLUDE_PATH} - ${X11_XCB_INCLUDE_DIR} ${XCB_INCLUDE_DIRS} ) @@ -43,12 +42,9 @@ target_link_libraries(linux-capture libobs glad ${X11_LIBRARIES} - ${X11_XShm_LIB} ${X11_Xfixes_LIB} - ${X11_Xinerama_LIB} ${X11_X11_LIB} ${X11_Xcomposite_LIB} - ${X11_XCB_LIBRARIES} ${XCB_LIBRARIES} ) From db9b71b80b03469c0fc0b0bd898d60b9cf5e1cb4 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Mon, 22 Dec 2014 00:39:32 +0100 Subject: [PATCH 15/15] linux-capture: Refactor source data Remove comments from and align members in the source data struct for the xshm capture plugin. --- plugins/linux-capture/xshm-input.c | 37 ++++++++++++------------------ 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/plugins/linux-capture/xshm-input.c b/plugins/linux-capture/xshm-input.c index 2648779c5..39aa43a52 100644 --- a/plugins/linux-capture/xshm-input.c +++ b/plugins/linux-capture/xshm-input.c @@ -32,32 +32,25 @@ along with this program. If not, see . #define blog(level, msg, ...) blog(level, "xshm-input: " msg, ##__VA_ARGS__) struct xshm_data { - /** The source object */ - obs_source_t *source; + obs_source_t *source; xcb_connection_t *xcb; xcb_screen_t *xcb_screen; + xcb_shm_t *xshm; + xcb_xcursor_t *cursor; - /** user setting - the server name to capture from */ - char *server; - /** user setting - the id of the screen that should be captured */ - uint_fast32_t screen_id; - /** root coordinates for the capture */ - int_fast32_t x_org, y_org; - /** size for the capture */ - int_fast32_t width, height; - /** shared memory management object */ - xcb_shm_t *xshm; - /** the texture used to display the capture */ - gs_texture_t *texture; - /** cursor object for displaying the server */ - xcb_xcursor_t *cursor; - /** user setting - if cursor should be displayed */ - bool show_cursor; - /** set if xinerama is available and active on the screen */ - bool use_xinerama; - /** user setting - if advanced settings should be displayed */ - bool advanced; + char *server; + uint_fast32_t screen_id; + int_fast32_t x_org; + int_fast32_t y_org; + int_fast32_t width; + int_fast32_t height; + + gs_texture_t *texture; + + bool show_cursor; + bool use_xinerama; + bool advanced; }; /**