parent
d424ec799d
commit
de40e49ea4
@ -0,0 +1,199 @@
|
|||||||
|
From ccbd491fa48f1c43daeb1a6c5ee91a1a8fa3db88 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jan Grulich <jgrulich@redhat.com>
|
||||||
|
Date: Tue, 9 Aug 2022 14:31:07 +0200
|
||||||
|
Subject: [PATCH] x0vncserver: add new keysym in case we don't find a matching
|
||||||
|
keycode
|
||||||
|
|
||||||
|
We might often fail to find a matching X11 keycode when the client has
|
||||||
|
a different keyboard layout and end up with no key event. To avoid a
|
||||||
|
failure we add it as a new keysym/keycode pair so the next time a keysym
|
||||||
|
from the client that is unknown to the server is send, we will find a
|
||||||
|
match and proceed with key event. This is same behavior used in Xvnc or
|
||||||
|
x11vnc, although Xvnc has more advanced mapping from keysym to keycode.
|
||||||
|
---
|
||||||
|
unix/x0vncserver/XDesktop.cxx | 121 +++++++++++++++++++++++++++++++++-
|
||||||
|
unix/x0vncserver/XDesktop.h | 4 ++
|
||||||
|
2 files changed, 122 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
|
||||||
|
index f2046e43e..933998f05 100644
|
||||||
|
--- a/unix/x0vncserver/XDesktop.cxx
|
||||||
|
+++ b/unix/x0vncserver/XDesktop.cxx
|
||||||
|
@@ -31,6 +31,7 @@
|
||||||
|
#include <x0vncserver/XDesktop.h>
|
||||||
|
|
||||||
|
#include <X11/XKBlib.h>
|
||||||
|
+#include <X11/Xutil.h>
|
||||||
|
#ifdef HAVE_XTEST
|
||||||
|
#include <X11/extensions/XTest.h>
|
||||||
|
#endif
|
||||||
|
@@ -50,6 +51,7 @@ void vncSetGlueContext(Display *dpy, void *res);
|
||||||
|
#include <x0vncserver/Geometry.h>
|
||||||
|
#include <x0vncserver/XPixelBuffer.h>
|
||||||
|
|
||||||
|
+using namespace std;
|
||||||
|
using namespace rfb;
|
||||||
|
|
||||||
|
extern const unsigned short code_map_qnum_to_xorgevdev[];
|
||||||
|
@@ -264,6 +266,9 @@ void XDesktop::start(VNCServer* vs) {
|
||||||
|
void XDesktop::stop() {
|
||||||
|
running = false;
|
||||||
|
|
||||||
|
+ // Delete added keycodes
|
||||||
|
+ deleteAddedKeysyms(dpy);
|
||||||
|
+
|
||||||
|
#ifdef HAVE_XDAMAGE
|
||||||
|
if (haveDamage)
|
||||||
|
XDamageDestroy(dpy, damage);
|
||||||
|
@@ -383,6 +388,118 @@ KeyCode XDesktop::XkbKeysymToKeycode(Display* dpy, KeySym keysym) {
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+KeyCode XDesktop::addKeysym(Display* dpy, KeySym keysym)
|
||||||
|
+{
|
||||||
|
+ int types[1];
|
||||||
|
+ unsigned int key;
|
||||||
|
+ XkbDescPtr xkb;
|
||||||
|
+ XkbMapChangesRec changes;
|
||||||
|
+ KeySym *syms;
|
||||||
|
+ KeySym upper, lower;
|
||||||
|
+
|
||||||
|
+ xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
|
||||||
|
+
|
||||||
|
+ if (!xkb)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ for (key = xkb->max_key_code; key >= xkb->min_key_code; key--) {
|
||||||
|
+ if (XkbKeyNumGroups(xkb, key) == 0)
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (key < xkb->min_key_code)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ memset(&changes, 0, sizeof(changes));
|
||||||
|
+
|
||||||
|
+ XConvertCase(keysym, &lower, &upper);
|
||||||
|
+
|
||||||
|
+ if (upper == lower)
|
||||||
|
+ types[XkbGroup1Index] = XkbOneLevelIndex;
|
||||||
|
+ else
|
||||||
|
+ types[XkbGroup1Index] = XkbAlphabeticIndex;
|
||||||
|
+
|
||||||
|
+ XkbChangeTypesOfKey(xkb, key, 1, XkbGroup1Mask, types, &changes);
|
||||||
|
+
|
||||||
|
+ syms = XkbKeySymsPtr(xkb,key);
|
||||||
|
+ if (upper == lower)
|
||||||
|
+ syms[0] = keysym;
|
||||||
|
+ else {
|
||||||
|
+ syms[0] = lower;
|
||||||
|
+ syms[1] = upper;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ changes.changed |= XkbKeySymsMask;
|
||||||
|
+ changes.first_key_sym = key;
|
||||||
|
+ changes.num_key_syms = 1;
|
||||||
|
+
|
||||||
|
+ if (XkbChangeMap(dpy, xkb, &changes)) {
|
||||||
|
+ vlog.info("Added unknown keysym %s to keycode %d", XKeysymToString(keysym), key);
|
||||||
|
+ addedKeysyms[keysym] = key;
|
||||||
|
+ return key;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void XDesktop::deleteAddedKeysyms(Display* dpy) {
|
||||||
|
+ XkbDescPtr xkb;
|
||||||
|
+ xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
|
||||||
|
+
|
||||||
|
+ if (!xkb)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ XkbMapChangesRec changes;
|
||||||
|
+ memset(&changes, 0, sizeof(changes));
|
||||||
|
+
|
||||||
|
+ KeyCode lowestKeyCode = xkb->max_key_code;
|
||||||
|
+ KeyCode highestKeyCode = xkb->min_key_code;
|
||||||
|
+ std::map<KeySym, KeyCode>::iterator it;
|
||||||
|
+ for (it = addedKeysyms.begin(); it != addedKeysyms.end(); it++) {
|
||||||
|
+ if (XkbKeyNumGroups(xkb, it->second) != 0) {
|
||||||
|
+ // Check if we are removing keysym we added ourself
|
||||||
|
+ if (XkbKeysymToKeycode(dpy, it->first) != it->second)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ XkbChangeTypesOfKey(xkb, it->second, 0, XkbGroup1Mask, NULL, &changes);
|
||||||
|
+
|
||||||
|
+ if (it->second < lowestKeyCode)
|
||||||
|
+ lowestKeyCode = it->second;
|
||||||
|
+
|
||||||
|
+ if (it->second > highestKeyCode)
|
||||||
|
+ highestKeyCode = it->second;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ changes.changed |= XkbKeySymsMask;
|
||||||
|
+ changes.first_key_sym = lowestKeyCode;
|
||||||
|
+ changes.num_key_syms = highestKeyCode - lowestKeyCode + 1;
|
||||||
|
+ XkbChangeMap(dpy, xkb, &changes);
|
||||||
|
+
|
||||||
|
+ addedKeysyms.clear();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+KeyCode XDesktop::keysymToKeycode(Display* dpy, KeySym keysym) {
|
||||||
|
+ int keycode = 0;
|
||||||
|
+
|
||||||
|
+ // XKeysymToKeycode() doesn't respect state, so we have to use
|
||||||
|
+ // something slightly more complex
|
||||||
|
+ keycode = XkbKeysymToKeycode(dpy, keysym);
|
||||||
|
+
|
||||||
|
+ if (keycode != 0)
|
||||||
|
+ return keycode;
|
||||||
|
+
|
||||||
|
+ // TODO: try to further guess keycode with all possible mods as Xvnc does
|
||||||
|
+
|
||||||
|
+ keycode = addKeysym(dpy, keysym);
|
||||||
|
+
|
||||||
|
+ if (keycode == 0)
|
||||||
|
+ vlog.error("Failure adding new keysym 0x%lx", keysym);
|
||||||
|
+
|
||||||
|
+ return keycode;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
void XDesktop::keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down) {
|
||||||
|
#ifdef HAVE_XTEST
|
||||||
|
int keycode = 0;
|
||||||
|
@@ -398,9 +515,7 @@ void XDesktop::keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down) {
|
||||||
|
if (pressedKeys.find(keysym) != pressedKeys.end())
|
||||||
|
keycode = pressedKeys[keysym];
|
||||||
|
else {
|
||||||
|
- // XKeysymToKeycode() doesn't respect state, so we have to use
|
||||||
|
- // something slightly more complex
|
||||||
|
- keycode = XkbKeysymToKeycode(dpy, keysym);
|
||||||
|
+ keycode = keysymToKeycode(dpy, keysym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h
|
||||||
|
index 840d43316..6ebcd9f8a 100644
|
||||||
|
--- a/unix/x0vncserver/XDesktop.h
|
||||||
|
+++ b/unix/x0vncserver/XDesktop.h
|
||||||
|
@@ -55,6 +55,9 @@ class XDesktop : public rfb::SDesktop,
|
||||||
|
const char* userName);
|
||||||
|
virtual void pointerEvent(const rfb::Point& pos, int buttonMask);
|
||||||
|
KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym);
|
||||||
|
+ KeyCode addKeysym(Display* dpy, KeySym keysym);
|
||||||
|
+ void deleteAddedKeysyms(Display* dpy);
|
||||||
|
+ KeyCode keysymToKeycode(Display* dpy, KeySym keysym);
|
||||||
|
virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down);
|
||||||
|
virtual void clientCutText(const char* str);
|
||||||
|
virtual unsigned int setScreenLayout(int fb_width, int fb_height,
|
||||||
|
@@ -78,6 +81,7 @@ class XDesktop : public rfb::SDesktop,
|
||||||
|
bool haveXtest;
|
||||||
|
bool haveDamage;
|
||||||
|
int maxButtons;
|
||||||
|
+ std::map<KeySym, KeyCode> addedKeysyms;
|
||||||
|
std::map<KeySym, KeyCode> pressedKeys;
|
||||||
|
bool running;
|
||||||
|
#ifdef HAVE_XDAMAGE
|
@ -0,0 +1,117 @@
|
|||||||
|
From f783d5c8b567199178b6690f347e060a69d2aa36 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jan Grulich <jgrulich@redhat.com>
|
||||||
|
Date: Thu, 11 Aug 2022 13:15:29 +0200
|
||||||
|
Subject: [PATCH] x0vncserver: update/display cursor only on correct screen in
|
||||||
|
zaphod mode
|
||||||
|
|
||||||
|
We have to check whether we update cursor position/shape only in case
|
||||||
|
the cursor is on our display, otherwise in zaphod mode, ie. when having
|
||||||
|
two instances of x0vncserver on screens :0.0 and :0.1 we would be having
|
||||||
|
the cursor duplicated and actually not funcional (aka ghost cursor) as
|
||||||
|
it would be actually not present. We also additionally watch EnterNotify
|
||||||
|
and LeaveNotify events in order to show/hide cursor accordingly.
|
||||||
|
|
||||||
|
Change made with help from Olivier Fourdan <ofourdan@redhat.com>
|
||||||
|
---
|
||||||
|
unix/x0vncserver/XDesktop.cxx | 60 +++++++++++++++++++++++++++++++----
|
||||||
|
1 file changed, 53 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
|
||||||
|
index f2046e43e..f07fd78bf 100644
|
||||||
|
--- a/unix/x0vncserver/XDesktop.cxx
|
||||||
|
+++ b/unix/x0vncserver/XDesktop.cxx
|
||||||
|
@@ -192,7 +192,8 @@ XDesktop::XDesktop(Display* dpy_, Geometry *geometry_)
|
||||||
|
RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask);
|
||||||
|
/* Override TXWindow::init input mask */
|
||||||
|
XSelectInput(dpy, DefaultRootWindow(dpy),
|
||||||
|
- PropertyChangeMask | StructureNotifyMask | ExposureMask);
|
||||||
|
+ PropertyChangeMask | StructureNotifyMask |
|
||||||
|
+ ExposureMask | EnterWindowMask | LeaveWindowMask);
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
vlog.info("RANDR extension not present");
|
||||||
|
@@ -217,11 +218,13 @@ void XDesktop::poll() {
|
||||||
|
Window root, child;
|
||||||
|
int x, y, wx, wy;
|
||||||
|
unsigned int mask;
|
||||||
|
- XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
|
||||||
|
- &x, &y, &wx, &wy, &mask);
|
||||||
|
- x -= geometry->offsetLeft();
|
||||||
|
- y -= geometry->offsetTop();
|
||||||
|
- server->setCursorPos(rfb::Point(x, y), false);
|
||||||
|
+
|
||||||
|
+ if (XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
|
||||||
|
+ &x, &y, &wx, &wy, &mask)) {
|
||||||
|
+ x -= geometry->offsetLeft();
|
||||||
|
+ y -= geometry->offsetTop();
|
||||||
|
+ server->setCursorPos(rfb::Point(x, y), false);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -253,7 +256,14 @@ void XDesktop::start(VNCServer* vs) {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_XFIXES
|
||||||
|
- setCursor();
|
||||||
|
+ Window root, child;
|
||||||
|
+ int x, y, wx, wy;
|
||||||
|
+ unsigned int mask;
|
||||||
|
+ // Check whether the cursor is initially on our screen
|
||||||
|
+ if (XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
|
||||||
|
+ &x, &y, &wx, &wy, &mask))
|
||||||
|
+ setCursor();
|
||||||
|
+
|
||||||
|
#endif
|
||||||
|
|
||||||
|
server->setLEDState(ledState);
|
||||||
|
@@ -701,6 +711,15 @@ bool XDesktop::handleGlobalEvent(XEvent* ev) {
|
||||||
|
if (cev->subtype != XFixesDisplayCursorNotify)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
+ Window root, child;
|
||||||
|
+ int x, y, wx, wy;
|
||||||
|
+ unsigned int mask;
|
||||||
|
+
|
||||||
|
+ // Check whether the cursor is initially on our screen
|
||||||
|
+ if (!XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
|
||||||
|
+ &x, &y, &wx, &wy, &mask))
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
return setCursor();
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_XRANDR
|
||||||
|
@@ -753,6 +772,33 @@ bool XDesktop::handleGlobalEvent(XEvent* ev) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
+#ifdef HAVE_XFIXES
|
||||||
|
+ } else if (ev->type == EnterNotify) {
|
||||||
|
+ XCrossingEvent* cev;
|
||||||
|
+
|
||||||
|
+ if (!running)
|
||||||
|
+ return true;
|
||||||
|
+
|
||||||
|
+ cev = (XCrossingEvent*)ev;
|
||||||
|
+
|
||||||
|
+ if (cev->window != cev->root)
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ return setCursor();
|
||||||
|
+ } else if (ev->type == LeaveNotify) {
|
||||||
|
+ XCrossingEvent* cev;
|
||||||
|
+
|
||||||
|
+ if (!running)
|
||||||
|
+ return true;
|
||||||
|
+
|
||||||
|
+ cev = (XCrossingEvent*)ev;
|
||||||
|
+
|
||||||
|
+ if (cev->window == cev->root)
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ server->setCursor(0, 0, Point(), NULL);
|
||||||
|
+ return true;
|
||||||
|
+#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
@ -0,0 +1,28 @@
|
|||||||
|
From 774c6bcf33b5c9b94c1ff12895775e77c555decc Mon Sep 17 00:00:00 2001
|
||||||
|
From: Pierre Ossman <ossman@cendio.se>
|
||||||
|
Date: Thu, 9 Feb 2023 11:30:37 +0100
|
||||||
|
Subject: [PATCH] Sanity check when cleaning up keymap changes
|
||||||
|
|
||||||
|
Make sure we don't send a bogus request to the X server in the (common)
|
||||||
|
case that we don't actually have anything to restore.
|
||||||
|
|
||||||
|
(cherry picked from commit 1e3484f2017f038dd5149cd50741feaf39a680e4)
|
||||||
|
---
|
||||||
|
unix/x0vncserver/XDesktop.cxx | 4 ++++
|
||||||
|
1 file changed, 4 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
|
||||||
|
index d5c6b2db9..f9c810968 100644
|
||||||
|
--- a/unix/x0vncserver/XDesktop.cxx
|
||||||
|
+++ b/unix/x0vncserver/XDesktop.cxx
|
||||||
|
@@ -481,6 +481,10 @@ void XDesktop::deleteAddedKeysyms(Display* dpy) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Did we actually find something to remove?
|
||||||
|
+ if (highestKeyCode < lowestKeyCode)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
changes.changed |= XkbKeySymsMask;
|
||||||
|
changes.first_key_sym = lowestKeyCode;
|
||||||
|
changes.num_key_syms = highestKeyCode - lowestKeyCode + 1;
|
@ -0,0 +1,31 @@
|
|||||||
|
From 717d787de8f913070446444e37d552b51f05515e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Zdenek Pytela <zpytela@redhat.com>
|
||||||
|
Date: Mon, 16 Jan 2023 12:35:40 +0100
|
||||||
|
Subject: [PATCH] SELinux: Allow vncsession create ~/.vnc directory
|
||||||
|
|
||||||
|
Addresses the following AVC denial:
|
||||||
|
|
||||||
|
type=PROCTITLE msg=audit(01/12/2023 02:58:12.648:696) : proctitle=/usr/sbin/vncsession fedora :1
|
||||||
|
type=PATH msg=audit(01/12/2023 02:58:12.648:696) : item=1 name=/home/fedora/.vnc nametype=CREATE cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
|
||||||
|
type=PATH msg=audit(01/12/2023 02:58:12.648:696) : item=0 name=/home/fedora/ inode=262145 dev=fc:02 mode=dir,700 ouid=fedora ogid=fedora rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 nametype=PARENT cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
|
||||||
|
type=CWD msg=audit(01/12/2023 02:58:12.648:696) : cwd=/home/fedora
|
||||||
|
type=SYSCALL msg=audit(01/12/2023 02:58:12.648:696) : arch=x86_64 syscall=mkdir success=no exit=EACCES(Permission denied) a0=0x7fff47d52540 a1=0755 a2=0x0 a3=0x0 items=2 ppid=2869 pid=2880 auid=fedora uid=fedora gid=fedora euid=fedora suid=fedora fsuid=fedora egid=fedora sgid=fedora fsgid=fedora tty=(none) ses=8 comm=vncsession exe=/usr/sbin/vncsession subj=system_u:system_r:vnc_session_t:s0 key=(null)
|
||||||
|
type=AVC msg=audit(01/12/2023 02:58:12.648:696) : avc: denied { create } for pid=2880 comm=vncsession name=.vnc scontext=system_u:system_r:vnc_session_t:s0 tcontext=system_u:object_r:vnc_home_t:s0 tclass=dir permissive=0
|
||||||
|
|
||||||
|
Resolves: rhbz#2143704
|
||||||
|
---
|
||||||
|
unix/vncserver/selinux/vncsession.te | 1 +
|
||||||
|
1 file changed, 1 insertion(+)
|
||||||
|
|
||||||
|
diff --git a/unix/vncserver/selinux/vncsession.te b/unix/vncserver/selinux/vncsession.te
|
||||||
|
index fb966c14b..680be8ea1 100644
|
||||||
|
--- a/unix/vncserver/selinux/vncsession.te
|
||||||
|
+++ b/unix/vncserver/selinux/vncsession.te
|
||||||
|
@@ -37,6 +37,7 @@ allow vnc_session_t self:fifo_file rw_fifo_file_perms;
|
||||||
|
allow vnc_session_t vnc_session_var_run_t:file manage_file_perms;
|
||||||
|
files_pid_filetrans(vnc_session_t, vnc_session_var_run_t, file)
|
||||||
|
|
||||||
|
+create_dirs_pattern(vnc_session_t, vnc_home_t, vnc_home_t)
|
||||||
|
manage_files_pattern(vnc_session_t, vnc_home_t, vnc_home_t)
|
||||||
|
manage_fifo_files_pattern(vnc_session_t, vnc_home_t, vnc_home_t)
|
||||||
|
manage_sock_files_pattern(vnc_session_t, vnc_home_t, vnc_home_t)
|
@ -1,35 +0,0 @@
|
|||||||
From 7150ba655c0cc08fa6ded309b81265bb672f2869 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Peter Hutterer <peter.hutterer@who-t.net>
|
|
||||||
Date: Wed, 25 Jan 2023 11:41:40 +1000
|
|
||||||
Subject: [PATCH xserver] Xi: fix potential use-after-free in
|
|
||||||
DeepCopyPointerClasses
|
|
||||||
|
|
||||||
CVE-2023-0494, ZDI-CAN 19596
|
|
||||||
|
|
||||||
This vulnerability was discovered by:
|
|
||||||
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative
|
|
||||||
|
|
||||||
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
|
|
||||||
---
|
|
||||||
Xi/exevents.c | 4 +++-
|
|
||||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/Xi/exevents.c b/Xi/exevents.c
|
|
||||||
index 217baa9561..dcd4efb3bc 100644
|
|
||||||
--- a/Xi/exevents.c
|
|
||||||
+++ b/Xi/exevents.c
|
|
||||||
@@ -619,8 +619,10 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to)
|
|
||||||
memcpy(to->button->xkb_acts, from->button->xkb_acts,
|
|
||||||
sizeof(XkbAction));
|
|
||||||
}
|
|
||||||
- else
|
|
||||||
+ else {
|
|
||||||
free(to->button->xkb_acts);
|
|
||||||
+ to->button->xkb_acts = NULL;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
memcpy(to->button->labels, from->button->labels,
|
|
||||||
from->button->numButtons * sizeof(Atom));
|
|
||||||
--
|
|
||||||
2.39.0
|
|
||||||
|
|
Loading…
Reference in new issue