diff --git a/plugins/linux-capture/CMakeLists.txt b/plugins/linux-capture/CMakeLists.txt index 861e275aa..d4f1649f3 100644 --- a/plugins/linux-capture/CMakeLists.txt +++ b/plugins/linux-capture/CMakeLists.txt @@ -6,15 +6,20 @@ 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} -) + ${XCB_INCLUDE_DIRS} +) set(linux-capture_SOURCES linux-capture.c xcursor.c + xcursor-xcb.c xhelpers.c xshm-input.c xcomposite-main.cpp @@ -23,6 +28,7 @@ set(linux-capture_SOURCES ) set(linux-capture_HEADERS xcursor.h + xcursor-xcb.h xhelpers.h xcompcap-main.hpp xcompcap-helper.hpp @@ -36,11 +42,10 @@ target_link_libraries(linux-capture libobs glad ${X11_LIBRARIES} - ${X11_XShm_LIB} ${X11_Xfixes_LIB} - ${X11_Xinerama_LIB} ${X11_X11_LIB} ${X11_Xcomposite_LIB} + ${XCB_LIBRARIES} ) install_obs_plugin_with_data(linux-capture data) 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 diff --git a/plugins/linux-capture/xhelpers.c b/plugins/linux-capture/xhelpers.c index a1666f1e7..1eeda7c22 100644 --- a/plugins/linux-capture/xhelpers.c +++ b/plugins/linux-capture/xhelpers.c @@ -17,134 +17,158 @@ 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; } -xshm_t *xshm_attach(Display *dpy, Screen *screen, - int_fast32_t w, int_fast32_t h) +xcb_shm_t* xshm_xcb_attach(xcb_connection_t *xcb, const int w, const int h) { - if (!dpy || !screen) + if (!xcb) return NULL; - xshm_t *xshm = bzalloc(sizeof(xshm_t)); + xcb_shm_t *shm = bzalloc(sizeof(xcb_shm_t)); + shm->xcb = xcb; + shm->seg = xcb_generate_id(shm->xcb); - xshm->dpy = dpy; - xshm->image = XShmCreateImage(xshm->dpy, DefaultVisualOfScreen(screen), - DefaultDepthOfScreen(screen), ZPixmap, NULL, &xshm->info, - w, h); - if (!xshm->image) + shm->shmid = shmget(IPC_PRIVATE, w * h * 4, IPC_CREAT | 0777); + if (shm->shmid == -1) 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; + xcb_shm_attach(shm->xcb, shm->seg, shm->shmid, false); - 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; + shm->data = shmat(shm->shmid, NULL, 0); - if (!XShmAttach(xshm->dpy, &xshm->info)) - goto fail; - - xshm->attached = true; - return xshm; + return shm; fail: - xshm_detach(xshm); + xshm_xcb_detach(shm); return NULL; } -void xshm_detach(xshm_t *xshm) +void xshm_xcb_detach(xcb_shm_t *shm) { - if (!xshm) + if (!shm) return; - if (xshm->attached) - XShmDetach(xshm->dpy, &xshm->info); + xcb_shm_detach(shm->xcb, shm->seg); - if (xshm->info.shmaddr != (char *) -1) - shmdt(xshm->info.shmaddr); + if ((char *) shm->data != (char *) -1) + shmdt(shm->data); - if (xshm->info.shmid != -1) - shmctl(xshm->info.shmid, IPC_RMID, NULL); + if (shm->shmid != -1) + shmctl(shm->shmid, IPC_RMID, NULL); - if (xshm->image) - XDestroyImage(xshm->image); + bfree(shm); +} - bfree(xshm); +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 1c0cd0a38..7aa12f227 100644 --- a/plugins/linux-capture/xhelpers.h +++ b/plugins/linux-capture/xhelpers.h @@ -21,30 +21,30 @@ along with this program. If not, see . extern "C" { #endif -#include -#include +#include +#include #include typedef struct { - XShmSegmentInfo info; - XImage *image; - Display *dpy; - bool attached; -} xshm_t; + xcb_connection_t *xcb; + xcb_shm_seg_t seg; + int shmid; + uint8_t *data; +} xcb_shm_t; /** * 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 @@ -60,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 @@ -75,26 +76,33 @@ 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 * - * @param dpy X11 Display - * @param screen X11 Screen - * @param w width for the shared memory segment - * @param h height for the shared memory segment + * @param xcb xcb connection + * @param w width of the captured screen + * @param h height of the captured screen * * @return NULL on error */ -xshm_t *xshm_attach(Display *dpy, Screen *screen, - int_fast32_t w, int_fast32_t h); +xcb_shm_t *xshm_xcb_attach(xcb_connection_t *xcb, const int w, const int h); /** * Detach a shared memory segment */ -void xshm_detach(xshm_t *xshm); +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 } diff --git a/plugins/linux-capture/xshm-input.c b/plugins/linux-capture/xshm-input.c index 6cd305278..39aa43a52 100644 --- a/plugins/linux-capture/xshm-input.c +++ b/plugins/linux-capture/xshm-input.c @@ -18,12 +18,13 @@ along with this program. If not, see . #include #include #include -#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; @@ -31,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; - /** Xlib display object */ - Display *dpy; - /** Xlib screen object */ - Screen *screen; - /** 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 */ - xshm_t *xshm; - /** the texture used to display the capture */ - gs_texture_t *texture; - /** cursor object for displaying the server */ - 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; + obs_source_t *source; + + xcb_connection_t *xcb; + xcb_screen_t *xcb_screen; + xcb_shm_t *xshm; + xcb_xcursor_t *cursor; + + 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; }; /** @@ -74,6 +68,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 * @@ -85,21 +97,21 @@ 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; } - data->screen = XDefaultScreenOfDisplay(data->dpy); + data->xcb_screen = xcb_get_screen(data->xcb, 0); } 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; } - data->screen = XScreenOfDisplay(data->dpy, data->screen_id); + data->xcb_screen = xcb_get_screen(data->xcb, data->screen_id); } if (!data->width || !data->height) { @@ -137,21 +149,20 @@ 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; } obs_leave_graphics(); if (data->xshm) { - xshm_detach(data->xshm); + xshm_xcb_detach(data->xshm); 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) { @@ -168,35 +179,33 @@ 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; } - 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; + data->use_xinerama = xinerama_is_active(data->xcb) ? true : false; if (xshm_update_geometry(data) < 0) { blog(LOG_ERROR, "failed to update geometry !"); 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; } + 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(); @@ -269,26 +278,27 @@ 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; } 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) : + 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) - 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 @@ -309,7 +319,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; @@ -383,16 +393,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_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); + 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) + goto exit; + 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); + xcb_xcursor_update(data->cursor, cur_r); obs_leave_graphics(); + +exit: + free(img_r); + free(cur_r); } /** @@ -412,7 +439,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(); }