mirror of
				https://github.com/gnif/LookingGlass.git
				synced 2025-11-03 22:22:08 +00:00 
			
		
		
		
	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:
		
				
					committed by
					
						
						Geoffrey McRae
					
				
			
			
				
	
			
			
			
						parent
						
							fbf294efd9
						
					
				
				
					commit
					8ab130deba
				
			@@ -23,9 +23,11 @@
 | 
			
		||||
#include "common/option.h"
 | 
			
		||||
#include "common/debug.h"
 | 
			
		||||
#include "common/event.h"
 | 
			
		||||
#include "common/thread.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <xcb/shm.h>
 | 
			
		||||
#include <xcb/xfixes.h>
 | 
			
		||||
#include <sys/ipc.h>
 | 
			
		||||
@@ -42,9 +44,15 @@ struct xcb
 | 
			
		||||
  void                      * data;
 | 
			
		||||
  LGEvent                   * frameEvent;
 | 
			
		||||
 | 
			
		||||
  CaptureGetPointerBuffer     getPointerBufferFn;
 | 
			
		||||
  CapturePostPointerBuffer    postPointerBufferFn;
 | 
			
		||||
  LGThread                  * pointerThread;
 | 
			
		||||
 | 
			
		||||
  unsigned int width;
 | 
			
		||||
  unsigned int height;
 | 
			
		||||
 | 
			
		||||
  int mouseX, mouseY, mouseHotX, mouseHotY;
 | 
			
		||||
 | 
			
		||||
  bool                                 hasFrame;
 | 
			
		||||
  xcb_shm_get_image_cookie_t           imgC;
 | 
			
		||||
  xcb_xfixes_get_cursor_image_cookie_t curC;
 | 
			
		||||
@@ -52,6 +60,8 @@ struct xcb
 | 
			
		||||
 | 
			
		||||
static struct xcb * this = NULL;
 | 
			
		||||
 | 
			
		||||
static int pointerThread(void * unused);
 | 
			
		||||
 | 
			
		||||
// forwards
 | 
			
		||||
 | 
			
		||||
static bool xcb_deinit();
 | 
			
		||||
@@ -81,6 +91,9 @@ static bool xcb_create(CaptureGetPointerBuffer getPointerBufferFn, CapturePostPo
 | 
			
		||||
  this->data       = (void *)-1;
 | 
			
		||||
  this->frameEvent = lgCreateEvent(true, 20);
 | 
			
		||||
 | 
			
		||||
  this->getPointerBufferFn = getPointerBufferFn;
 | 
			
		||||
  this->postPointerBufferFn = postPointerBufferFn;
 | 
			
		||||
 | 
			
		||||
  if (!this->frameEvent)
 | 
			
		||||
  {
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
  return true;
 | 
			
		||||
fail:
 | 
			
		||||
@@ -252,6 +296,77 @@ static CaptureResult xcb_getFrame(FrameBuffer * frame,
 | 
			
		||||
  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 =
 | 
			
		||||
{
 | 
			
		||||
  .shortName       = "XCB",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user