From e658c2e0a205c40701b00d97364c2a9903ed34cf Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Wed, 13 Sep 2023 21:51:53 +1000 Subject: [PATCH] [client] x11: change to a more visible "dot" cursor This change alters the small square dot cursor to a more visible 16x16 cursor for X11. A new option `spice:largeDotCursor` can be set to use an alternative 32x32 cursor for the vision impaired. --- client/displayservers/X11/CMakeLists.txt | 2 + client/displayservers/X11/cursor.c | 105 +++++++++++++++++++++++ client/displayservers/X11/cursor.h | 29 +++++++ client/displayservers/X11/x11.c | 36 +++----- client/include/interface/displayserver.h | 1 + client/src/config.c | 8 ++ client/src/main.c | 1 + client/src/main.h | 1 + resources/CMakeLists.txt | 2 + resources/no-input-cursor/16.cursor | 1 + resources/no-input-cursor/16.png | Bin 0 -> 334 bytes resources/no-input-cursor/16.xcur | Bin 0 -> 1088 bytes resources/no-input-cursor/32.cursor | 1 + resources/no-input-cursor/32.png | Bin 0 -> 628 bytes resources/no-input-cursor/32.xcur | Bin 0 -> 3664 bytes 15 files changed, 165 insertions(+), 22 deletions(-) create mode 100644 client/displayservers/X11/cursor.c create mode 100644 client/displayservers/X11/cursor.h create mode 100644 resources/no-input-cursor/16.cursor create mode 100644 resources/no-input-cursor/16.png create mode 100644 resources/no-input-cursor/16.xcur create mode 100644 resources/no-input-cursor/32.cursor create mode 100644 resources/no-input-cursor/32.png create mode 100644 resources/no-input-cursor/32.xcur 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 0000000000000000000000000000000000000000..0dbf396ccbe505db9f4a42ea2e66868d4eb285dc GIT binary patch literal 334 zcmV-U0kQsxP)x`hxZvRmz-D49bDl)`F>F#?R0;{{lYT`F#j zF;cptWM%+e<+MuT=g3-dotYsi?MmK5E9tRqn0d3 gkx@RjOh?xF8_ySCFuHPlUH||907*qoM6N<$g6|5D&Hw-a literal 0 HcmV?d00001 diff --git a/resources/no-input-cursor/16.xcur b/resources/no-input-cursor/16.xcur new file mode 100644 index 0000000000000000000000000000000000000000..afcdee3b62d627d7638313c85ef1544e22a669ba GIT binary patch literal 1088 zcmbu8u?@m75JdwO1wtNxk_ixVfRu`!juMG2($QvzOhCaDDXG$>phYV;Md7-xyPbrUFbN=sL&Jkt#c_`kzHQsfQWy$xb8P4G-RM7C$S_#{T;L_q_`qywphZb7nrAG4^hSa{zg);iX2L zza!?%sA3PLTH|pcf5~{M5#jGQvA#~+{~>XHsrScRQl1~`Q=ebogMIw@{!stKPw(#? D-3uT~ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7f2315ff364f9be57e9e4f948178469fc72673f2 GIT binary patch literal 628 zcmV-)0*n2LP)?y??i3&R&LeHJo}F)J{LP;YXeR^UD{urH z0AGMl_S-8^0#Cp_@C|t5gR&1Kz#34?wYF#W-wS#MESX(s7d z(n!+4u94lFSsh7Ip6809$bnz)0-phj<5)#eI2#*Dmy(9NZY^nObvKe!6oukA_C5dO zKUEY(KIns_>EDt=($t<+Q53%CXTM|b67a+OAnEYE%#?KK!1Fx!3HJ-z6GtR3ywi{7 zqV;?u$tPUm7l$?Av-gsY#Qt-YW$EYn0N}*ssmI=7hrmO}b}!FQLR$uzOeRkEHVA?r zT>)ELw+)P=(AHkYpFv0II6Wg?iM&&^hpI*LjO@k0hz8Di`V(Y$s7& z*A95l0{Gb}Tku`L14*ju+5x|X^dzC}r);-dx3|~g+*J?+CI|upT(!{OYhb(rJOVPt zxab{s?VW8RGRC-2KZbU4V6|E~z3D%Q?6iUL6xwlx#bV($PrEK4z-a^HzPFMY+H|@B zn9t`<|DvlV0bDd}-}u8|Z*8%+L7>;sr`KVxxAC^uf&RZdVS>IMZ9f49VoHb_LTg(9 O0000RUO}G3Pc>StRFd|p9GxvqajBO%~HChzB6-NBCkrVBi3+2f5YPfbD+VsAF zE_+jneGu&u`#!p$#5o7uQs+9?wsGsma?Q^JUXxSTHP5l=I+$