xcb: added basic cursor support via xcb_fixes

xcb interface now properly supports cursor integration through
a `pointerThread` similar to the nvfbc implementation.
This commit is contained in:
vmfortress 2021-10-30 14:19:17 -04:00 committed by Geoffrey McRae
parent fbf294efd9
commit 8ab130deba

View File

@ -23,9 +23,11 @@
#include "common/option.h" #include "common/option.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/event.h" #include "common/event.h"
#include "common/thread.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <inttypes.h> #include <inttypes.h>
#include <unistd.h>
#include <xcb/shm.h> #include <xcb/shm.h>
#include <xcb/xfixes.h> #include <xcb/xfixes.h>
#include <sys/ipc.h> #include <sys/ipc.h>
@ -33,18 +35,24 @@
struct xcb struct xcb
{ {
bool initialized; bool initialized;
bool stop; bool stop;
xcb_connection_t * xcb; xcb_connection_t * xcb;
xcb_screen_t * xcbScreen; xcb_screen_t * xcbScreen;
uint32_t seg; uint32_t seg;
int shmID; int shmID;
void * data; void * data;
LGEvent * frameEvent; LGEvent * frameEvent;
CaptureGetPointerBuffer getPointerBufferFn;
CapturePostPointerBuffer postPointerBufferFn;
LGThread * pointerThread;
unsigned int width; unsigned int width;
unsigned int height; unsigned int height;
int mouseX, mouseY, mouseHotX, mouseHotY;
bool hasFrame; bool hasFrame;
xcb_shm_get_image_cookie_t imgC; xcb_shm_get_image_cookie_t imgC;
xcb_xfixes_get_cursor_image_cookie_t curC; xcb_xfixes_get_cursor_image_cookie_t curC;
@ -52,6 +60,8 @@ struct xcb
static struct xcb * this = NULL; static struct xcb * this = NULL;
static int pointerThread(void * unused);
// forwards // forwards
static bool xcb_deinit(); static bool xcb_deinit();
@ -81,6 +91,9 @@ static bool xcb_create(CaptureGetPointerBuffer getPointerBufferFn, CapturePostPo
this->data = (void *)-1; this->data = (void *)-1;
this->frameEvent = lgCreateEvent(true, 20); this->frameEvent = lgCreateEvent(true, 20);
this->getPointerBufferFn = getPointerBufferFn;
this->postPointerBufferFn = postPointerBufferFn;
if (!this->frameEvent) if (!this->frameEvent)
{ {
DEBUG_ERROR("Failed to create the frame event"); DEBUG_ERROR("Failed to create the frame event");
@ -137,6 +150,37 @@ static bool xcb_init(void)
} }
DEBUG_INFO("Frame Data : 0x%" PRIXPTR, (uintptr_t)this->data); DEBUG_INFO("Frame Data : 0x%" PRIXPTR, (uintptr_t)this->data);
xcb_query_extension_cookie_t extension_cookie =
xcb_query_extension(this->xcb, strlen("XFIXES"), "XFIXES");
xcb_query_extension_reply_t * extension_reply =
xcb_query_extension_reply(this->xcb, extension_cookie, NULL);
if(!extension_reply)
{
DEBUG_ERROR("Extension \"XFIXES\" isn't available");
free(extension_reply);
goto fail;
}
free(extension_reply);
xcb_xfixes_query_version_cookie_t version_cookie =
xcb_xfixes_query_version(this->xcb, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION);
xcb_xfixes_query_version_reply_t * version_reply =
xcb_xfixes_query_version_reply(this->xcb, version_cookie, NULL);
if(!version_reply)
{
DEBUG_ERROR("Extension \"XFIXES\" isn't available");
free(version_reply);
goto fail;
}
free(version_reply);
if (!lgCreateThread("XCBPointer", pointerThread, NULL, &this->pointerThread))
{
DEBUG_ERROR("Failed to create the XCBPointer thread");
xcb_deinit();
return false;
}
this->initialized = true; this->initialized = true;
return true; return true;
fail: fail:
@ -252,6 +296,77 @@ static CaptureResult xcb_getFrame(FrameBuffer * frame,
return CAPTURE_RESULT_OK; return CAPTURE_RESULT_OK;
} }
static int pointerThread(void * unused)
{
while (!this->stop)
{
if (this->stop)
break;
CapturePointer pointer = { 0 };
this->curC = xcb_xfixes_get_cursor_image_unchecked(this->xcb);
void * data;
uint32_t size;
if (!this->getPointerBufferFn(&data, &size))
{
DEBUG_WARN("failed to get a pointer buffer");
continue;
}
xcb_xfixes_get_cursor_image_reply_t * curReply;
curReply = xcb_xfixes_get_cursor_image_reply(this->xcb, this->curC, NULL);
if (curReply == NULL)
{
DEBUG_WARN("Failed to get cursor reply");
continue;
}
if(curReply->xhot != this->mouseHotX || curReply->yhot != this->mouseHotY)
{
pointer.shapeUpdate = true;
this->mouseHotX = curReply->xhot;
this->mouseHotY = curReply->yhot;
uint32_t * src = xcb_xfixes_get_cursor_image_cursor_image(curReply);
uint32_t * dst = (uint32_t *) (data);
memcpy(dst, src, curReply->width * curReply->height * sizeof(uint32_t));
}
else
pointer.shapeUpdate = false;
if(curReply->x != this->mouseX || curReply->y != this->mouseY)
{
pointer.positionUpdate = true;
this->mouseX = curReply->x;
this->mouseY = curReply->y;
}
else
pointer.positionUpdate = false;
if(pointer.positionUpdate || pointer.shapeUpdate)
{
pointer.hx = curReply->xhot;
pointer.hy = curReply->yhot;
pointer.visible = true;
pointer.x = curReply->x - curReply->xhot;
pointer.y = curReply->y - curReply->yhot;
pointer.format = CAPTURE_FMT_COLOR;
pointer.width = curReply->width;
pointer.height = curReply->height;
pointer.pitch = curReply->width * 4;
this->postPointerBufferFn(pointer);
}
free(curReply);
usleep(1000);
}
return 0;
}
struct CaptureInterface Capture_XCB = struct CaptureInterface Capture_XCB =
{ {
.shortName = "XCB", .shortName = "XCB",