diff --git a/c-host/Makefile b/c-host/Makefile index 90dd34ec..cf0669b0 100644 --- a/c-host/Makefile +++ b/c-host/Makefile @@ -34,6 +34,7 @@ else ifeq ($(USE_XCB), 1) CFLAGS += -DUSE_XCB + LIBS += -lxcb -lxcb-shm -lXfixes OBJS += linux/capture/xcb.o endif endif diff --git a/c-host/linux/capture/xcb.c b/c-host/linux/capture/xcb.c new file mode 100644 index 00000000..866fa98d --- /dev/null +++ b/c-host/linux/capture/xcb.c @@ -0,0 +1,184 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017-2019 Geoffrey McRae +https://looking-glass.hostfission.com + +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, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "capture/interface.h" +#include "debug.h" +#include +#include +#include +#include +#include +#include +#include + +struct xcb +{ + bool initialized; + xcb_connection_t * xcb; + xcb_screen_t * xcbScreen; + uint32_t seg; + int shmID; + void * data; + + unsigned int width; + unsigned int height; + + xcb_shm_get_image_cookie_t imgC; + xcb_xfixes_get_cursor_image_cookie_t curC; +}; + +struct xcb * this = NULL; + +// forwards + +static bool xcb_deinit(); +static unsigned int xcb_getMaxFrameSize(); + +// implementation + +static const char * xcb_getName() +{ + return "XCB"; +} + +static bool xcb_create() +{ + assert(!this); + this = (struct xcb *)calloc(sizeof(struct xcb), 1); + this->shmID = -1; + this->data = (void *)-1; + return true; +} + +static bool xcb_init() +{ + assert(this); + assert(!this->initialized); + + this->xcb = xcb_connect(NULL, NULL); + if (!this->xcb || xcb_connection_has_error(this->xcb)) + { + DEBUG_ERROR("Unable to open the X display"); + goto fail; + } + + if (!xcb_get_extension_data(this->xcb, &xcb_shm_id)->present) + { + DEBUG_ERROR("Missing the SHM extension"); + goto fail; + } + + xcb_screen_iterator_t iter; + iter = xcb_setup_roots_iterator(xcb_get_setup(this->xcb)); + this->xcbScreen = iter.data; + this->width = iter.data->width_in_pixels; + this->height = iter.data->height_in_pixels; + DEBUG_INFO("Frame Size : %u x %u", this->width, this->height); + + this->seg = xcb_generate_id(this->xcb); + this->shmID = shmget(IPC_PRIVATE, xcb_getMaxFrameSize(), IPC_CREAT | 0777); + if (this->shmID == -1) + { + DEBUG_ERROR("shmget failed"); + goto fail; + } + + xcb_shm_attach(this->xcb, this->seg ,this->shmID, false); + this->data = shmat(this->shmID, NULL, 0); + if ((uintptr_t)this->data == -1) + { + DEBUG_ERROR("shmat failed"); + goto fail; + } + DEBUG_INFO("Frame Data : 0x%" PRIXPTR, (uintptr_t)this->data); + + this->initialized = true; + return true; +fail: + xcb_deinit(); + return false; +} + +static bool xcb_deinit() +{ + assert(this); + + if ((uintptr_t)this->data != -1) + { + shmdt(this->data); + this->data = (void *)-1; + } + + if (this->shmID != -1) + { + shmctl(this->shmID, IPC_RMID, NULL); + this->shmID = -1; + } + + if (this->xcb) + { + xcb_disconnect(this->xcb); + this->xcb = NULL; + } + + this->initialized = false; + return false; +} + +static void xcb_free() +{ + free(this); + this = NULL; +} + +static unsigned int xcb_getMaxFrameSize() +{ + return this->width * this->height * 4; +} + +static CaptureResult xcb_capture(bool * hasFrameUpdate, bool * hasPointerUpdate) +{ + assert(this); + assert(this->initialized); + + this->imgC = xcb_shm_get_image_unchecked( + this->xcb, + this->xcbScreen->root, + 0, 0, + this->width, + this->height, + ~0, + XCB_IMAGE_FORMAT_Z_PIXMAP, + this->seg, + 0); + + *hasFrameUpdate = true; + return CAPTURE_RESULT_OK; +} + +struct CaptureInterface Capture_XCB = +{ + .getName = xcb_getName, + .create = xcb_create, + .init = xcb_init, + .deinit = xcb_deinit, + .free = xcb_free, + .getMaxFrameSize = xcb_getMaxFrameSize, + .capture = xcb_capture +}; \ No newline at end of file