changed to kernel formatting and added some more documentation

master
fryshorts 2014-02-20 19:41:04 +01:00
parent 63d441e182
commit ce9db65695
4 changed files with 238 additions and 256 deletions

View File

@ -14,47 +14,52 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdlib.h>
#include <stdio.h> #include <stdint.h>
#include <X11/extensions/Xfixes.h> #include <X11/extensions/Xfixes.h>
#include <util/bmem.h>
#include "xcursor.h" #include "xcursor.h"
uint32_t *xcursor_pixels(XFixesCursorImage *xc) { /*
int size = xc->width * xc->height; * Get pixel data for the cursor
uint32_t *pixels = bmalloc(size * 4); *
* XFixes has the data defined as unsigned long, so we can not use memcpy.
* Theres a lot of talk about this in other implementation and they tend to
* be really complicated, but this naive approach seems to work fine ...
*/
static uint32_t *xcursor_pixels(XFixesCursorImage *xc) {
uint_fast32_t size = xc->width * xc->height;
uint32_t *pixels = bmalloc(size * sizeof(uint32_t));
// pixel data from XFixes is defined as unsigned long ... for (uint_fast32_t i = 0; i < size; ++i)
// TODO: check why everybody is making a fuss about this
for (int i = 0; i < size; ++i)
pixels[i] = (uint32_t) xc->pixels[i]; pixels[i] = (uint32_t) xc->pixels[i];
return pixels; return pixels;
} }
void xcursor_create(xcursor_t *data, XFixesCursorImage *xc) { /*
// get cursor pixel data * 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 xcursor_create(xcursor_t *data, XFixesCursorImage *xc) {
uint32_t *pixels = xcursor_pixels(xc); uint32_t *pixels = xcursor_pixels(xc);
// if the cursor has the same size as the last one we can simply update
if (data->tex if (data->tex
&& data->last_height == xc->width && data->last_height == xc->width
&& data->last_width == xc->height) { && data->last_width == xc->height) {
texture_setimage(data->tex, (void **) pixels, xc->width * 4, False); texture_setimage(data->tex, (void **) pixels,
} xc->width * sizeof(uint32_t), False);
else { } else {
if (data->tex) if (data->tex)
texture_destroy(data->tex); texture_destroy(data->tex);
data->tex = gs_create_texture( data->tex = gs_create_texture(xc->width, xc->height,
xc->width, xc->height, GS_RGBA, 1, (const void **) &pixels, GS_DYNAMIC);
GS_RGBA, 1,
(const void **) &pixels,
GS_DYNAMIC
);
} }
bfree(pixels); bfree(pixels);
// set some data
data->last_serial = xc->cursor_serial; data->last_serial = xc->cursor_serial;
data->last_width = xc->width; data->last_width = xc->width;
data->last_height = xc->height; data->last_height = xc->height;
@ -65,8 +70,6 @@ xcursor_t *xcursor_init(Display *dpy) {
memset(data, 0, sizeof(xcursor_t)); memset(data, 0, sizeof(xcursor_t));
data->dpy = dpy; data->dpy = dpy;
// initialize texture so we don't crash
xcursor_tick(data); xcursor_tick(data);
return data; return data;
@ -79,14 +82,10 @@ void xcursor_destroy(xcursor_t *data) {
} }
void xcursor_tick(xcursor_t *data) { void xcursor_tick(xcursor_t *data) {
// get cursor data
XFixesCursorImage *xc = XFixesGetCursorImage(data->dpy); XFixesCursorImage *xc = XFixesGetCursorImage(data->dpy);
// update cursor if necessary
if (!data->tex || data->last_serial != xc->cursor_serial) if (!data->tex || data->last_serial != xc->cursor_serial)
xcursor_create(data, xc); xcursor_create(data, xc);
// update cursor position
data->pos_x = -1.0 * (xc->x - xc->xhot); data->pos_x = -1.0 * (xc->x - xc->xhot);
data->pos_y = -1.0 * (xc->y - xc->yhot); data->pos_y = -1.0 * (xc->y - xc->yhot);
@ -94,7 +93,7 @@ void xcursor_tick(xcursor_t *data) {
} }
void xcursor_render(xcursor_t *data) { void xcursor_render(xcursor_t *data) {
// TODO: why do i need effects ? /* TODO: why do i need effects ? */
effect_t effect = gs_geteffect(); effect_t effect = gs_geteffect();
eparam_t image = effect_getparambyname(effect, "image"); eparam_t image = effect_getparambyname(effect, "image");
@ -102,14 +101,8 @@ void xcursor_render(xcursor_t *data) {
gs_matrix_push(); gs_matrix_push();
// move cursor to the right position gs_matrix_translate3f(data->pos_x, data->pos_y, 0);
gs_matrix_translate3f(
data->pos_x,
data->pos_y,
0
);
// blend cursor
gs_enable_blending(True); gs_enable_blending(True);
gs_blendfunction(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA); gs_blendfunction(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
gs_draw_sprite(data->tex, 0, 0, 0); gs_draw_sprite(data->tex, 0, 0, 0);

View File

@ -14,6 +14,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <obs.h> #include <obs.h>

View File

@ -38,17 +38,19 @@ struct xshm_data {
xcursor_t *cursor; xcursor_t *cursor;
}; };
static const char* xshm_input_getname(const char* locale) static const char* xshm_getname(const char* locale)
{ {
UNUSED_PARAMETER(locale); UNUSED_PARAMETER(locale);
return "X11 Shared Memory Screen Input"; return "X11 Shared Memory Screen Input";
} }
static void xshm_input_destroy(void *vptr) static void xshm_destroy(void *vptr)
{ {
XSHM_DATA(vptr); XSHM_DATA(vptr);
if (data) { if (!data)
return;
gs_entercontext(obs_graphics()); gs_entercontext(obs_graphics());
texture_destroy(data->texture); texture_destroy(data->texture);
@ -56,42 +58,35 @@ static void xshm_input_destroy(void *vptr)
gs_leavecontext(); gs_leavecontext();
// detach xshm
if (data->shm_attached) if (data->shm_attached)
XShmDetach(data->dpy, &data->shm_info); XShmDetach(data->dpy, &data->shm_info);
// detach shared memory
if (data->shm_info.shmaddr != (char *) -1) { if (data->shm_info.shmaddr != (char *) -1) {
shmdt(data->shm_info.shmaddr); shmdt(data->shm_info.shmaddr);
data->shm_info.shmaddr = (char *) -1; data->shm_info.shmaddr = (char *) -1;
} }
// remove shared memory
if (data->shm_info.shmid != -1) if (data->shm_info.shmid != -1)
shmctl(data->shm_info.shmid, IPC_RMID, NULL); shmctl(data->shm_info.shmid, IPC_RMID, NULL);
// destroy image
if (data->image) if (data->image)
XDestroyImage(data->image); XDestroyImage(data->image);
// close display
if (data->dpy) if (data->dpy)
XCloseDisplay(data->dpy); XCloseDisplay(data->dpy);
bfree(data); bfree(data);
} }
}
static void *xshm_input_create(obs_data_t settings, obs_source_t source) static void *xshm_create(obs_data_t settings, obs_source_t source)
{ {
UNUSED_PARAMETER(settings); UNUSED_PARAMETER(settings);
UNUSED_PARAMETER(source); UNUSED_PARAMETER(source);
// create data structure
struct xshm_data *data = bmalloc(sizeof(struct xshm_data)); struct xshm_data *data = bmalloc(sizeof(struct xshm_data));
memset(data, 0, sizeof(struct xshm_data)); memset(data, 0, sizeof(struct xshm_data));
// try to open display and all the good stuff
data->dpy = XOpenDisplay(NULL); data->dpy = XOpenDisplay(NULL);
if (!data->dpy) if (!data->dpy)
goto fail; goto fail;
@ -103,46 +98,41 @@ static void *xshm_input_create(obs_data_t settings, obs_source_t source)
Visual *visual = DefaultVisualOfScreen(screen); Visual *visual = DefaultVisualOfScreen(screen);
int depth = DefaultDepthOfScreen(screen); int depth = DefaultDepthOfScreen(screen);
// query for shm extension
if (!XShmQueryExtension(data->dpy)) if (!XShmQueryExtension(data->dpy))
goto fail; goto fail;
// create xshm image
data->image = XShmCreateImage(data->dpy, visual, depth, data->image = XShmCreateImage(data->dpy, visual, depth,
ZPixmap, NULL, &data->shm_info, ZPixmap, NULL, &data->shm_info, data->width, data->height);
data->width, data->height);
if (!data->image) if (!data->image)
goto fail; goto fail;
// create shared memory data->shm_info.shmid = shmget(IPC_PRIVATE,
data->shm_info.shmid = shmget(IPC_PRIVATE, data->image->bytes_per_line * data->image->bytes_per_line * data->image->height,
data->image->height, IPC_CREAT | 0700); IPC_CREAT | 0700);
if (data->shm_info.shmid < 0) if (data->shm_info.shmid < 0)
goto fail; goto fail;
// attach shared memory data->shm_info.shmaddr
data->shm_info.shmaddr = data->image->data = data->image->data
= (char *) shmat(data->shm_info.shmid, 0, 0); = (char *) shmat(data->shm_info.shmid, 0, 0);
if (data->shm_info.shmaddr == (char *) -1) if (data->shm_info.shmaddr == (char *) -1)
goto fail; goto fail;
// set shared memory as read only
data->shm_info.readOnly = False; data->shm_info.readOnly = False;
// attach shm
if (!XShmAttach(data->dpy, &data->shm_info)) if (!XShmAttach(data->dpy, &data->shm_info))
goto fail; goto fail;
data->shm_attached = 1; data->shm_attached = 1;
// get image
if (!XShmGetImage(data->dpy, data->root_window, data->image, if (!XShmGetImage(data->dpy, data->root_window, data->image,
0, 0, AllPlanes)) 0, 0, AllPlanes)) {
goto fail; goto fail;
}
// create obs texture
gs_entercontext(obs_graphics()); gs_entercontext(obs_graphics());
data->texture = gs_create_texture(data->width, data->height, GS_BGRA, 1, data->texture = gs_create_texture(data->width, data->height,
(const void**) &data->image->data, GS_BGRA, 1, (const void**) &data->image->data, GS_DYNAMIC);
GS_DYNAMIC);
data->cursor = xcursor_init(data->dpy); data->cursor = xcursor_init(data->dpy);
gs_leavecontext(); gs_leavecontext();
@ -152,30 +142,29 @@ static void *xshm_input_create(obs_data_t settings, obs_source_t source)
return data; return data;
fail: fail:
// clean up and return null xshm_destroy(data);
xshm_input_destroy(data);
return NULL; return NULL;
} }
static void xshm_input_video_tick(void *vptr, float seconds) static void xshm_video_tick(void *vptr, float seconds)
{ {
UNUSED_PARAMETER(seconds); UNUSED_PARAMETER(seconds);
XSHM_DATA(vptr); XSHM_DATA(vptr);
gs_entercontext(obs_graphics()); gs_entercontext(obs_graphics());
// update screen texture
XShmGetImage(data->dpy, data->root_window, data->image, 0, 0, AllPlanes); XShmGetImage(data->dpy, data->root_window, data->image,
0, 0, AllPlanes);
texture_setimage(data->texture, (void *) data->image->data, texture_setimage(data->texture, (void *) data->image->data,
data->width * 4, False); data->width * 4, False);
// update mouse cursor
xcursor_tick(data->cursor); xcursor_tick(data->cursor);
gs_leavecontext(); gs_leavecontext();
} }
static void xshm_input_video_render(void *vptr, effect_t effect) static void xshm_video_render(void *vptr, effect_t effect)
{ {
XSHM_DATA(vptr); XSHM_DATA(vptr);
@ -186,18 +175,17 @@ static void xshm_input_video_render(void *vptr, effect_t effect)
gs_draw_sprite(data->texture, 0, 0, 0); gs_draw_sprite(data->texture, 0, 0, 0);
// render the cursor
xcursor_render(data->cursor); xcursor_render(data->cursor);
} }
static uint32_t xshm_input_getwidth(void *vptr) static uint32_t xshm_getwidth(void *vptr)
{ {
XSHM_DATA(vptr); XSHM_DATA(vptr);
return texture_getwidth(data->texture); return texture_getwidth(data->texture);
} }
static uint32_t xshm_input_getheight(void *vptr) static uint32_t xshm_getheight(void *vptr)
{ {
XSHM_DATA(vptr); XSHM_DATA(vptr);
@ -208,11 +196,11 @@ struct obs_source_info xshm_input = {
.id = "xshm_input", .id = "xshm_input",
.type = OBS_SOURCE_TYPE_INPUT, .type = OBS_SOURCE_TYPE_INPUT,
.output_flags = OBS_SOURCE_VIDEO, .output_flags = OBS_SOURCE_VIDEO,
.getname = xshm_input_getname, .getname = xshm_getname,
.create = xshm_input_create, .create = xshm_create,
.destroy = xshm_input_destroy, .destroy = xshm_destroy,
.video_tick = xshm_input_video_tick, .video_tick = xshm_video_tick,
.video_render = xshm_input_video_render, .video_render = xshm_video_render,
.getwidth = xshm_input_getwidth, .getwidth = xshm_getwidth,
.getheight = xshm_input_getheight .getheight = xshm_getheight
}; };