From 820de55ae2135e8d94a8aaa5bbee3cef6ed8305c Mon Sep 17 00:00:00 2001 From: fryshorts Date: Sun, 9 Feb 2014 20:36:52 +0100 Subject: [PATCH] Added initial Mouse pointer lib Added library to get the mouse pointer with the XFixes extension and draw it via a sprite. --- test/linux/CMakeLists.txt | 6 +-- test/linux/xcursor.c | 94 +++++++++++++++++++++++++++++++++++++++ test/linux/xcursor.h | 36 +++++++++++++++ test/linux/xshm-input.c | 36 +++++++-------- 4 files changed, 148 insertions(+), 24 deletions(-) create mode 100644 test/linux/xcursor.c create mode 100644 test/linux/xcursor.h diff --git a/test/linux/CMakeLists.txt b/test/linux/CMakeLists.txt index bb2522b7c..20f8be146 100644 --- a/test/linux/CMakeLists.txt +++ b/test/linux/CMakeLists.txt @@ -3,14 +3,15 @@ project(linux) find_package(X11 REQUIRED) include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs") -#include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs-opengl") set(linux_SOURCES linux.c + xcursor.c xshm-input.c ) set(linux_HEADERS linux.h + xcursor.h xshm-input.h ) @@ -22,8 +23,7 @@ target_link_libraries(linux libobs ${X11_LIBRARIES} ${X11_XShm_LIB} + ${X11_Xfixes_LIB} ) install_obs_plugin(linux) - -#obs_fixup_install_target(xshm-input PATH ${Libx264_LIBRARIES}) diff --git a/test/linux/xcursor.c b/test/linux/xcursor.c new file mode 100644 index 000000000..b3f012854 --- /dev/null +++ b/test/linux/xcursor.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include "xcursor.h" + +uint32_t *xcursor_pixels(XFixesCursorImage *xc) { + int size = xc->width * xc->height; + uint32_t *pixels = bmalloc(size * 4); + + // pixel data from XFixes is defined as unsigned long ... + // TODO: check why everybody is making a fuss about this + for (int i = 0; i < size; ++i) + pixels[i] = (uint32_t) xc->pixels[i]; + + return pixels; +} + +void xcursor_create(xcursor_t *data, XFixesCursorImage *xc) { + // get cursor pixel data + uint32_t *pixels = xcursor_pixels(xc); + + // if the cursor has the same size as the last one we can simply update + if (data->tex + && data->last_height == xc->width + && data->last_width == xc->height) { + texture_setimage(data->tex, (void **) pixels, xc->width * 4, False); + } + else { + if (data->tex) + texture_destroy(data->tex); + + data->tex = gs_create_texture( + xc->width, xc->height, + GS_RGBA, 1, + (const void **) &pixels, + GS_DYNAMIC + ); + } + bfree(pixels); + + // set some data + data->last_serial = xc->cursor_serial; + data->last_width = xc->width; + data->last_height = xc->height; +} + +xcursor_t *xcursor_init(Display *dpy) { + xcursor_t *data = bmalloc(sizeof(xcursor_t)); + memset(data, 0, sizeof(xcursor_t)); + + data->dpy = dpy; + + return data; +} + +void xcursor_destroy(xcursor_t *data) { + if (data->tex) + texture_destroy(data->tex); + bfree(data); +} + +void xcursor_render(xcursor_t *data) { + // get cursor data + XFixesCursorImage *xc = XFixesGetCursorImage(data->dpy); + + // update cursor if necessary + if (!data->tex || data->last_serial != xc->cursor_serial) + xcursor_create(data, xc); + + // TODO: why do i need effects ? + effect_t effect = gs_geteffect(); + eparam_t diffuse = effect_getparambyname(effect, "diffuse"); + + effect_settexture(effect, diffuse, data->tex); + + gs_matrix_push(); + + // move cursor to the right position + gs_matrix_translate3f( + -1.0 * (xc->x - xc->xhot), + -1.0 * (xc->y - xc->yhot), + 0 + ); + + // blend cursor + gs_enable_blending(True); + gs_blendfunction(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA); + gs_draw_sprite(data->tex, 0, 0, 0); + gs_enable_blending(False); + + gs_matrix_pop(); + + XFree(xc); +} \ No newline at end of file diff --git a/test/linux/xcursor.h b/test/linux/xcursor.h new file mode 100644 index 000000000..110067362 --- /dev/null +++ b/test/linux/xcursor.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + Display *dpy; + unsigned long last_serial; + short unsigned int last_width; + short unsigned int last_height; + texture_t tex; +} xcursor_t; + +/** + * Initializes the xcursor object + */ +xcursor_t *xcursor_init(Display *dpy); + +/** + * Destroys the xcursor object + */ +void xcursor_destroy(xcursor_t *data); + +/** + * Draw the cursor + * + * This needs to be executed within a valid render context + */ +void xcursor_render(xcursor_t *data); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/test/linux/xshm-input.c b/test/linux/xshm-input.c index 5a3ea988a..ee7e12f27 100644 --- a/test/linux/xshm-input.c +++ b/test/linux/xshm-input.c @@ -4,6 +4,7 @@ #include #include #include +#include "xcursor.h" #include "xshm-input.h" struct xshm_data { @@ -17,6 +18,7 @@ struct xshm_data { XShmSegmentInfo shm_info; XImage *image; texture_t texture; + xcursor_t *cursor; }; const char* xshm_input_getname(const char* locale) @@ -53,45 +55,36 @@ struct xshm_data *xshm_input_create(const char *settings, obs_source_t source) if (!data->image) goto fail; - printf("Image size: %dx%d\n", data->image->width, data->image->height); - // create shared memory data->shm_info.shmid = shmget(IPC_PRIVATE, data->image->bytes_per_line * data->image->height, IPC_CREAT | 0700); - if (data->shm_info.shmid < 0) { - printf("Failed to create shared memory !\n"); + if (data->shm_info.shmid < 0) goto fail; - } // attach shared memory data->shm_info.shmaddr = data->image->data = (char *) shmat(data->shm_info.shmid, 0, 0); - if (data->shm_info.shmaddr == (char *) -1) { - printf("Failed to attach shared memory !\n"); + if (data->shm_info.shmaddr == (char *) -1) goto fail; - } // set shared memory as read only data->shm_info.readOnly = False; // attach shm - if (!XShmAttach(data->dpy, &data->shm_info)) { - printf("Failed to attach to XShm !\n"); + if (!XShmAttach(data->dpy, &data->shm_info)) goto fail; - } data->shm_attached = 1; // get image if (!XShmGetImage(data->dpy, data->root_window, data->image, - 0, 0, AllPlanes)) { - printf("Failed to get image data !\n"); + 0, 0, AllPlanes)) goto fail; - } // create obs texture gs_entercontext(obs_graphics()); data->texture = gs_create_texture(data->width, data->height, GS_BGRA, 1, (const void**) &data->image->data, GS_DYNAMIC); + data->cursor = xcursor_init(data->dpy); gs_leavecontext(); if (!data->texture) @@ -111,6 +104,7 @@ void xshm_input_destroy(struct xshm_data *data) gs_entercontext(obs_graphics()); texture_destroy(data->texture); + xcursor_destroy(data->cursor); gs_leavecontext(); @@ -148,18 +142,18 @@ uint32_t xshm_input_get_output_flags(struct xshm_data *data) void xshm_input_video_render(struct xshm_data *data, obs_source_t filter_target) { // update texture - if (!XShmGetImage(data->dpy, data->root_window, data->image, - 0, 0, AllPlanes)) { - printf("Failed to get image !\n"); - } + XShmGetImage(data->dpy, data->root_window, data->image, 0, 0, AllPlanes); texture_setimage(data->texture, (void *) data->image->data, data->width * 4, False); - //effect_t effect = gs_geteffect(); - //eparam_t diffuse = effect_getparambyname(effect, "diffuse"); + effect_t effect = gs_geteffect(); + eparam_t diffuse = effect_getparambyname(effect, "diffuse"); - //effect_settexture(effect, diffuse, data->texture); + effect_settexture(effect, diffuse, data->texture); gs_draw_sprite(data->texture, 0, 0, 0); + + // render the cursor + xcursor_render(data->cursor); } uint32_t xshm_input_getwidth(struct xshm_data *data)