diff --git a/client/displayservers/X11/CMakeLists.txt b/client/displayservers/X11/CMakeLists.txt index 9c4daa16..f5e11fbe 100644 --- a/client/displayservers/X11/CMakeLists.txt +++ b/client/displayservers/X11/CMakeLists.txt @@ -17,6 +17,7 @@ add_library(displayserver_X11 STATIC x11.c atoms.c clipboard.c + cursor.c wm/default.c wm/i3.c @@ -27,6 +28,7 @@ add_definitions(-D GLX_GLXEXT_PROTOTYPES) target_link_libraries(displayserver_X11 PkgConfig::DISPLAYSERVER_X11 lg_common + lg_resources ) target_include_directories(displayserver_X11 diff --git a/client/displayservers/X11/cursor.c b/client/displayservers/X11/cursor.c new file mode 100644 index 00000000..f963c88b --- /dev/null +++ b/client/displayservers/X11/cursor.c @@ -0,0 +1,105 @@ +/** + * Looking Glass + * Copyright © 2017-2023 The Looking Glass Authors + * https://looking-glass.io + * + * 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 "cursor.h" +#include "common/util.h" + +#include +#include + +struct MemFile +{ + const char * data; + int size; + int pos; +}; + +static int x11cursor_read(XcursorFile *file, unsigned char * buf, int len) +{ + struct MemFile * f = (struct MemFile *)file->closure; + + if (f->pos == f->size) + return 0; + + len = min(f->size - f->pos, len); + memcpy(buf, f->data + f->pos, len); + f->pos += len; + + return len; +} + +static int x11cursor_write(XcursorFile *file, unsigned char * buf, int len) +{ + errno = -EINVAL; + return -1; +} + +static int x11cursor_seek(XcursorFile *file, long offset, int whence) +{ + struct MemFile * f = (struct MemFile *)file->closure; + long target; + + switch(whence) + { + case SEEK_SET: + target = offset; + break; + + case SEEK_CUR: + target = f->pos + offset; + break; + + case SEEK_END: + target = f->size + offset; + break; + + default: + errno = -EINVAL; + return -1; + } + + if (target < 0 || target > f->size) + { + errno = -EINVAL; + return -1; + } + f->pos = target; + return target; +} + +XcursorImages * x11cursor_load(const char * cursor, int size) +{ + struct MemFile closure = + { + .data = cursor, + .size = size, + .pos = 0 + }; + + XcursorFile f = + { + .closure = &closure, + .read = x11cursor_read, + .write = x11cursor_write, + .seek = x11cursor_seek + }; + + return XcursorXcFileLoadAllImages(&f); +} diff --git a/client/displayservers/X11/cursor.h b/client/displayservers/X11/cursor.h new file mode 100644 index 00000000..622387da --- /dev/null +++ b/client/displayservers/X11/cursor.h @@ -0,0 +1,29 @@ +/** + * Looking Glass + * Copyright © 2017-2023 The Looking Glass Authors + * https://looking-glass.io + * + * 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 + */ + +#ifndef _H_X11DS_CURSOR_ +#define _H_X11DS_CURSOR_ + +#include +#include + +XcursorImages * x11cursor_load(const char * cursor, int size); + +#endif diff --git a/client/displayservers/X11/x11.c b/client/displayservers/X11/x11.c index e4dc5fd3..8281e4fd 100644 --- a/client/displayservers/X11/x11.c +++ b/client/displayservers/X11/x11.c @@ -23,7 +23,11 @@ #include "x11.h" #include "atoms.h" #include "clipboard.h" +#include "cursor.h" + #include "resources/icondata.h" +#include "resources/no-input-cursor/16.xcur.h" +#include "resources/no-input-cursor/32.xcur.h" #include #include @@ -626,29 +630,17 @@ static bool x11Init(const LG_DSInitParams params) XFreePixmap(x11.display, temp); } - /* create the square cursor */ - { - static char data[] = { 0x07, 0x05, 0x07 }; - static char mask[] = { 0xff, 0xff, 0xff }; + XcursorImages * images; + if (params.largeCursorDot) + images = x11cursor_load(b_no_input_cursor_32_xcur, + b_no_input_cursor_32_xcur_size); + else + images = x11cursor_load(b_no_input_cursor_16_xcur, + b_no_input_cursor_16_xcur_size); - Colormap cmap = DefaultColormap(x11.display, DefaultScreen(x11.display)); - XColor colors[2] = - { - { .pixel = BlackPixelOfScreen(DefaultScreenOfDisplay(x11.display)) }, - { .pixel = WhitePixelOfScreen(DefaultScreenOfDisplay(x11.display)) } - }; - - XQueryColors(x11.display, cmap, colors, 2); - - Pixmap img = XCreateBitmapFromData(x11.display, x11.window, data, 3, 3); - Pixmap msk = XCreateBitmapFromData(x11.display, x11.window, mask, 3, 3); - - x11.cursors[LG_POINTER_SQUARE] = XCreatePixmapCursor(x11.display, img, msk, - &colors[0], &colors[1], 1, 1); - - XFreePixmap(x11.display, img); - XFreePixmap(x11.display, msk); - } + x11.cursors[LG_POINTER_SQUARE] = + XcursorImagesLoadCursor(x11.display, images); + XcursorImagesDestroy(images); /* initialize the rest of the cursors */ const char * cursorLookup[LG_POINTER_COUNT] = { diff --git a/client/include/interface/displayserver.h b/client/include/interface/displayserver.h index f63089d5..6d62c89d 100644 --- a/client/include/interface/displayserver.h +++ b/client/include/interface/displayserver.h @@ -90,6 +90,7 @@ typedef struct LG_DSInitParams bool resizable; bool borderless; bool maximize; + bool largeCursorDot; // if true the renderer requires an OpenGL context bool opengl; diff --git a/client/src/config.c b/client/src/config.c index 8baa12be..561fdfe4 100644 --- a/client/src/config.c +++ b/client/src/config.c @@ -499,6 +499,13 @@ static struct Option options[] = .type = OPTION_TYPE_BOOL, .value.x_bool = true }, + { + .module = "spice", + .name = "largeCursorDot", + .description = "Use a larger version of the \"dot\" cursor", + .type = OPTION_TYPE_BOOL, + .value.x_bool = false + }, // audio options { @@ -728,6 +735,7 @@ bool config_load(int argc, char * argv[]) g_params.captureOnStart = option_get_bool("spice", "captureOnStart"); g_params.alwaysShowCursor = option_get_bool("spice", "alwaysShowCursor"); g_params.showCursorDot = option_get_bool("spice", "showCursorDot"); + g_params.largeCursorDot = option_get_bool("spice", "largeCursorDot"); } g_params.audioPeriodSize = option_get_int("audio", "periodSize"); diff --git a/client/src/main.c b/client/src/main.c index 98b55a6b..42b48c87 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -1337,6 +1337,7 @@ static int lg_run(void) .resizable = g_params.allowResize, .borderless = g_params.borderless, .maximize = g_params.maximize, + .largeCursorDot = g_params.largeCursorDot, .opengl = needsOpenGL, .jitRender = g_params.jitRender }; diff --git a/client/src/main.h b/client/src/main.h index 4fae595b..e34b147d 100644 --- a/client/src/main.h +++ b/client/src/main.h @@ -218,6 +218,7 @@ struct AppParams bool autoCapture; bool captureInputOnly; bool showCursorDot; + bool largeCursorDot; int audioPeriodSize; int audioBufferLatency; diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index f10c6a99..e284a7cf 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -18,6 +18,8 @@ build_resources( lg-logo.svg status/spice.svg status/recording.svg + no-input-cursor/16.xcur + no-input-cursor/32.xcur ) add_library(lg_resources STATIC ${LG_RESOURCES_OBJS}) diff --git a/resources/no-input-cursor/16.cursor b/resources/no-input-cursor/16.cursor new file mode 100644 index 00000000..cbaf9422 --- /dev/null +++ b/resources/no-input-cursor/16.cursor @@ -0,0 +1 @@ +16 8 8 16.png diff --git a/resources/no-input-cursor/16.png b/resources/no-input-cursor/16.png new file mode 100644 index 00000000..0dbf396c Binary files /dev/null and b/resources/no-input-cursor/16.png differ diff --git a/resources/no-input-cursor/16.xcur b/resources/no-input-cursor/16.xcur new file mode 100644 index 00000000..afcdee3b Binary files /dev/null and b/resources/no-input-cursor/16.xcur differ diff --git a/resources/no-input-cursor/32.cursor b/resources/no-input-cursor/32.cursor new file mode 100644 index 00000000..772d666d --- /dev/null +++ b/resources/no-input-cursor/32.cursor @@ -0,0 +1 @@ +32 16 16 32.png diff --git a/resources/no-input-cursor/32.png b/resources/no-input-cursor/32.png new file mode 100644 index 00000000..7f2315ff Binary files /dev/null and b/resources/no-input-cursor/32.png differ diff --git a/resources/no-input-cursor/32.xcur b/resources/no-input-cursor/32.xcur new file mode 100644 index 00000000..3604857a Binary files /dev/null and b/resources/no-input-cursor/32.xcur differ