From e3799133a8f05112a706604c1e2535cf1d3247c3 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Mon, 27 Jun 2022 06:40:55 +0800 Subject: [PATCH 01/21] Make PKGBUILD much less flaky and ideompotent --- archlinux/.gitignore | 3 +++ archlinux/PKGBUILD | 40 ++++++++++++++++++++++++++++------------ 2 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 archlinux/.gitignore diff --git a/archlinux/.gitignore b/archlinux/.gitignore new file mode 100644 index 00000000..79de598d --- /dev/null +++ b/archlinux/.gitignore @@ -0,0 +1,3 @@ +pkg/ +src/ +*.tar.zst diff --git a/archlinux/PKGBUILD b/archlinux/PKGBUILD index cf69505f..ad349faf 100644 --- a/archlinux/PKGBUILD +++ b/archlinux/PKGBUILD @@ -1,5 +1,4 @@ pkgname=(qubes-vm-gui qubes-vm-pulseaudio) -pkgver=$(cat version) pkgrel=10 epoch= pkgdesc="The Qubes GUI Agent for AppVMs" @@ -8,8 +7,8 @@ url="http://qubes-os.org/" license=('GPL') groups=() makedepends=(pkg-config make gcc patch git automake autoconf libtool - 'pulseaudio<=16.1' - xorg-server-devel xorg-util-macros libxcomposite libxt pixman lsb-release + 'pulseaudio' + xorg-server-devel xorg-util-macros libxcomposite libxt pixman qubes-vm-gui-common qubes-libvchan qubes-db-vm ) checkdepends=() @@ -21,21 +20,39 @@ backup=() options=() changelog= -source=(PKGBUILD-z-qubes-session.sh) +source=() +md5sums=() noextract=() -md5sums=() #generate with 'makepkg -g' -pa_ver=$((pkg-config --modversion libpulse 2>/dev/null || echo 0.0) | cut -f 1 -d "-") +pa_ver=16.1 #specify this manually please +# If using pkg-config, you must update libpulse first. +#pa_ver=$((pkg-config --modversion libpulse 2>/dev/null || echo 0.0) | cut -f 1 -d "-") + +export PA_VER_FULL=$pa_ver + +if [ -e archlinux ] # on no, at repo root +then + echo Do not run 'makepkg' at repo root! >&2 + cd archlinux +fi + +pkgver=$(cat $startdir/../version) + +clean() { + rm $srcdir/* -r || true +} build() { -for source in Makefile appvm-scripts gui-common include pulse gui-agent common xf86-input-mfndev xf86-video-dummy xf86-qubes-common window-icon-updater version; do - (ln -s $srcdir/../$source $srcdir/$source) +rm $srcdir/PKGBUILD-z-qubes-session.sh || true +cp $startdir/PKGBUILD-z-qubes-session.sh $srcdir/ +for source in Makefile appvm-scripts gui-common include pulse gui-agent common xf86-input-mfndev xf86-video-dummy xf86-qubes-common window-icon-updater version; do + rm $source -r || true + cp -r $startdir/../$source $source done -pa_ver=$((pkg-config --modversion libpulse 2>/dev/null || echo 0.0) | cut -f 1 -d "-") -rm -f pulse/pulsecore +rm -rf pulse/pulsecore ln -s pulsecore-$pa_ver pulse/pulsecore # Bug fixes : /var/run/console depends on pam_console, which is fedora specific @@ -71,9 +88,8 @@ install -D $srcdir/PKGBUILD-z-qubes-session.sh $pkgdir/etc/X11/xinit/xinitrc.d/z package_qubes-vm-pulseaudio() { pkgdesc="Pulseaudio support for Qubes VM" -depends=('alsa-lib' 'alsa-utils' 'pulseaudio-alsa' 'pulseaudio<=16.1') +depends=('alsa-lib' 'alsa-utils' 'pulseaudio-alsa' 'pulseaudio') install=PKGBUILD-pulseaudio.install -pa_ver=$((pkg-config --modversion libpulse 2>/dev/null || echo 0.0) | cut -f 1 -d "-") make install-pulseaudio DESTDIR=$pkgdir PA_VER=$pa_ver LIBDIR=/usr/lib USRLIBDIR=/usr/lib SYSLIBDIR=/usr/lib From 055e536de99d4679b2aae9ad9afce845046db852 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:03:22 +0800 Subject: [PATCH 02/21] Only handle Capslock specially --- gui-agent/vmside.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index fd76f4db..8ab69048 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -1611,11 +1611,9 @@ static void handle_keypress(Ghandles * g, XID UNUSED(winid)) fprintf(stderr, "failed to get modifier state\n"); state.mods = key.state; } - if (!g->sync_all_modifiers) { - // ignore all but CapsLock - state.mods &= LockMask; - key.state &= LockMask; - } + // ignore all but CapsLock + state.mods &= LockMask; + key.state &= LockMask; if (state.mods != key.state) { XModifierKeymap *modmap; int mod_index; @@ -1660,6 +1658,7 @@ static void handle_keypress(Ghandles * g, XID UNUSED(winid)) } } + if (key.keycode == 66) return; // caplocks feed_xdriver(g, 'K', key.keycode, key.type == KeyPress ? 1 : 0); } From 9bd0e6e7934ed3aacfabc269df8079ef6089ca52 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Sun, 6 Mar 2022 15:34:50 +0800 Subject: [PATCH 03/21] Refactor; make capslock work worse --- gui-agent/vmside.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index 8ab69048..c21876ff 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -1611,9 +1612,13 @@ static void handle_keypress(Ghandles * g, XID UNUSED(winid)) fprintf(stderr, "failed to get modifier state\n"); state.mods = key.state; } - // ignore all but CapsLock - state.mods &= LockMask; - key.state &= LockMask; + if (!g->sync_all_modifiers) { + // ignore all but CapsLock + state.mods &= LockMask; + key.state &= LockMask; + } + bool is_press = key.type == KeyPress; + bool duplicate = false; if (state.mods != key.state) { XModifierKeymap *modmap; int mod_index; @@ -1634,7 +1639,8 @@ static void handle_keypress(Ghandles * g, XID UNUSED(winid)) // #define Mod4MapIndex 6 // #define Mod5MapIndex 7 for (mod_index = 0; mod_index < 8; mod_index++) { - if (modmap->modifiermap[mod_index*modmap->max_keypermod] == 0x00) { + uint32_t keycode = modmap->modifiermap[mod_index*modmap->max_keypermod]; + if (keycode == 0x00) { if (g->log_level > 1) fprintf(stderr, "ignoring disabled modifier %d\n", mod_index); // no key set for this modifier, ignore @@ -1644,22 +1650,24 @@ static void handle_keypress(Ghandles * g, XID UNUSED(winid)) // special case for caps lock switch by press+release if (mod_index == LockMapIndex) { if ((state.mods & mod_mask) ^ (key.state & mod_mask)) { - feed_xdriver(g, 'K', modmap->modifiermap[mod_index*modmap->max_keypermod], 1); - feed_xdriver(g, 'K', modmap->modifiermap[mod_index*modmap->max_keypermod], 0); + feed_xdriver(g, 'K', keycode, 1); + feed_xdriver(g, 'K', keycode, 0); } } else { - if ((state.mods & mod_mask) && !(key.state & mod_mask)) - feed_xdriver(g, 'K', modmap->modifiermap[mod_index*modmap->max_keypermod], 0); - else if (!(state.mods & mod_mask) && (key.state & mod_mask)) - feed_xdriver(g, 'K', modmap->modifiermap[mod_index*modmap->max_keypermod], 1); + if ((state.mods & mod_mask) && !(key.state & mod_mask)) { + feed_xdriver(g, 'K', keycode, 0); + if (keycode == key.keycode && is_press == 0) duplicate = true; + } + else if (!(state.mods & mod_mask) && (key.state & mod_mask)) { + feed_xdriver(g, 'K', keycode, 1); + if (keycode == key.keycode && is_press == 1) duplicate = true; + } } } XFreeModifiermap(modmap); } } - - if (key.keycode == 66) return; // caplocks - feed_xdriver(g, 'K', key.keycode, key.type == KeyPress ? 1 : 0); + if (!duplicate) feed_xdriver(g, 'K', key.keycode, is_press); } static void handle_button(Ghandles * g, XID winid) From 2bdb952bbc578ae173f8d9ec56a561ae9a5bd2c4 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Sun, 13 Mar 2022 20:10:35 +0800 Subject: [PATCH 04/21] Modify .gitignore --- .gitignore | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.gitignore b/.gitignore index c7ea199b..c920403b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,14 @@ tags deb/ pkgs debian/changelog.* +/PKGBUILD* +/gui-agent/qubes-gui +/gui-common/qubes-gui-runuser +/pkg/ +*.tar.zst +/src/ +/xf86-input-mfndev/compile +/xf86-input-mfndev/config.h.in +/xf86-input-mfndev/depcomp +/xf86-input-mfndev/ltmain.sh +/xf86-qubes-common/libxf86-qubes-common.so From bffdd7916b7700fb668ce4fab6fa6166c2ee1382 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:20:39 +0800 Subject: [PATCH 05/21] squashed focus-related commits --- gui-agent/vmside.c | 83 ++++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index c21876ff..b303dd20 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -95,6 +95,7 @@ struct _global_handles { Atom wm_class; /* Atom: WM_CLASS */ Atom tray_selection; /* Atom: _NET_SYSTEM_TRAY_SELECTION_S */ Atom tray_opcode; /* Atom: _NET_SYSTEM_TRAY_OPCODE */ + int xi_opcode; Atom xembed_info; /* Atom: _XEMBED_INFO */ Atom utf8_string_atom; /* Atom: UTF8_STRING */ Atom wm_state; /* Atom: WM_STATE */ @@ -1618,7 +1619,7 @@ static void handle_keypress(Ghandles * g, XID UNUSED(winid)) key.state &= LockMask; } bool is_press = key.type == KeyPress; - bool duplicate = false; + bool is_mod_key = false; if (state.mods != key.state) { XModifierKeymap *modmap; int mod_index; @@ -1640,6 +1641,7 @@ static void handle_keypress(Ghandles * g, XID UNUSED(winid)) // #define Mod5MapIndex 7 for (mod_index = 0; mod_index < 8; mod_index++) { uint32_t keycode = modmap->modifiermap[mod_index*modmap->max_keypermod]; + if (keycode == key.keycode) is_mod_key = true; if (keycode == 0x00) { if (g->log_level > 1) fprintf(stderr, "ignoring disabled modifier %d\n", mod_index); @@ -1656,18 +1658,16 @@ static void handle_keypress(Ghandles * g, XID UNUSED(winid)) } else { if ((state.mods & mod_mask) && !(key.state & mod_mask)) { feed_xdriver(g, 'K', keycode, 0); - if (keycode == key.keycode && is_press == 0) duplicate = true; } else if (!(state.mods & mod_mask) && (key.state & mod_mask)) { feed_xdriver(g, 'K', keycode, 1); - if (keycode == key.keycode && is_press == 1) duplicate = true; } } } XFreeModifiermap(modmap); } } - if (!duplicate) feed_xdriver(g, 'K', key.keycode, is_press); + if (!is_mod_key) feed_xdriver(g, 'K', key.keycode, is_press); } static void handle_button(Ghandles * g, XID winid) @@ -1791,59 +1791,69 @@ static void take_focus(Ghandles * g, XID winid) if (g->log_level > 0) fprintf(stderr, "WM_TAKE_FOCUS sent for 0x%x\n", (int) winid); - } static void handle_focus(Ghandles * g, XID winid) { struct msg_focus key; struct genlist *l; - int input_hint; - int use_take_focus; + int use_take_focus = false; read_data(g->vchan, (char *) &key, sizeof(key)); - if (key.type == FocusIn - && (key.mode == NotifyNormal || key.mode == NotifyUngrab)) { - + + // send event directly + XFocusChangeEvent ev; + ev.detail = key.detail; + ev.mode = key.mode; + ev.type = key.type; + ev.window = winid; + + XGenericEventCookie evi; // X Input Extension + XILeaveEvent evi_leave; + memset(&evi_leave, 0, sizeof(evi_leave)); // no UB... + evi.type = GenericEvent; + evi.evtype = key.type; + evi.extension = g->xi_opcode; + // evi.cookie = ????; // no documentation about how to set this field + evi.data = &evi_leave; + evi_leave.type = GenericEvent; + evi_leave.evtype = key.type; + evi_leave.extension = g->xi_opcode; + evi_leave.detail = key.detail; + evi_leave.mode = key.mode; + // good luck on applications not rely on other fields + + XSendEvent(g->display, winid, true, 0, (XEvent *)&ev); + XSendEvent(g->display, winid, true, 0, (XEvent *)&evi); + + if (key.type == FocusIn) { + // XSetInputFocus(g->display, winid, RevertToParent, g->time); XRaiseWindow(g->display, winid); - + if ( (l=list_lookup(windows_list, winid)) && (l->data) ) { - input_hint = ((struct window_data*)l->data)->input_hint; use_take_focus = ((struct window_data*)l->data)->support_take_focus; if (((struct window_data*)l->data)->is_docked) - XRaiseWindow(g->display, ((struct window_data*)l->data)->embeder); + if (key.detail == NotifyNormal) + XRaiseWindow(g->display, ((struct window_data*)l->data)->embeder); } else { fprintf(stderr, "WARNING handle_focus: Window 0x%x data not initialized", (int)winid); - input_hint = True; - use_take_focus = False; } - // Give input focus only to window that set the input hint - if (input_hint) - XSetInputFocus(g->display, winid, RevertToParent, g->time); - - // Do not send take focus if the window doesn't support it + // Do not send WM_TAKE_FOCUS if the window doesn't support it if (use_take_focus) take_focus(g, winid); if (g->log_level > 1) fprintf(stderr, "0x%x raised\n", (int) winid); - } else if (key.type == FocusOut - && (key.mode == NotifyNormal - || key.mode == NotifyUngrab)) { - if ( (l=list_lookup(windows_list, winid)) && (l->data) ) - input_hint = ((struct window_data*)l->data)->input_hint; - else { - fprintf(stderr, "WARNING handle_focus: Window 0x%x data not initialized", (int)winid); - input_hint = True; - } - if (input_hint) - XSetInputFocus(g->display, None, RevertToParent, g->time); - + } else if (key.type == FocusOut) { + // int ignore; + // XID winid_focused; + // XGetInputFocus(g->display, &winid_focused, &ignore); + // if (winid_focused == winid) + // XSetInputFocus(g->display, None, RevertToNone, g->time); if (g->log_level > 1) fprintf(stderr, "0x%x lost focus\n", (int) winid); } - } static int bitset(unsigned char *keys, int num) @@ -2278,6 +2288,7 @@ int main(int argc, char **argv) XSelectInput(g.display, RootWindow(g.display, i), SubstructureNotifyMask); + if (!XDamageQueryExtension(g.display, &damage_event, &damage_error)) { @@ -2298,6 +2309,12 @@ int main(int argc, char **argv) XFixesDisplayCursorNotifyMask); } else fprintf(stderr, "XFixes not available, cursor shape handling off"); + + int ev_base, err_base; // ignore those + if (!XQueryExtension(g.display, "XInputExtension", &g.xi_opcode, &ev_base, &err_base)) { + fprintf(stderr, "X Input extension not available. Key press events not available. Upgrade your X11 server now."); + return 1; + } XAutoRepeatOff(g.display); signal(SIGCHLD, SIG_IGN); From 9be9425226e0020e0fea518c69274f684148ed85 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:13:42 +0100 Subject: [PATCH 06/21] xfce4-terminal work well with all kinds with focus --- gui-agent/vmside.c | 50 +++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index b303dd20..530dd2de 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -1827,32 +1827,36 @@ static void handle_focus(Ghandles * g, XID winid) XSendEvent(g->display, winid, true, 0, (XEvent *)&evi); if (key.type == FocusIn) { - // XSetInputFocus(g->display, winid, RevertToParent, g->time); - XRaiseWindow(g->display, winid); - - if ( (l=list_lookup(windows_list, winid)) && (l->data) ) { - use_take_focus = ((struct window_data*)l->data)->support_take_focus; - if (((struct window_data*)l->data)->is_docked) - if (key.detail == NotifyNormal) - XRaiseWindow(g->display, ((struct window_data*)l->data)->embeder); - } else { - fprintf(stderr, "WARNING handle_focus: Window 0x%x data not initialized", (int)winid); - } + if (key.mode == NotifyNormal || key.mode == NotifyUngrab) { + XSetInputFocus(g->display, winid, RevertToNone, g->time); + XRaiseWindow(g->display, winid); + if (g->log_level > 1) + fprintf(stderr, "0x%x gained focus\n", (int) winid); - // Do not send WM_TAKE_FOCUS if the window doesn't support it - if (use_take_focus) - take_focus(g, winid); - if (g->log_level > 1) - fprintf(stderr, "0x%x raised\n", (int) winid); + if ( (l=list_lookup(windows_list, winid)) && (l->data) ) { + use_take_focus = ((struct window_data*)l->data)->support_take_focus; + if (((struct window_data*)l->data)->is_docked) + XRaiseWindow(g->display, ((struct window_data*)l->data)->embeder); + } else { + fprintf(stderr, "WARNING handle_focus: Window 0x%x data not initialized", (int)winid); + } + + // Do not send WM_TAKE_FOCUS if the window doesn't support it + if (use_take_focus) + take_focus(g, winid); + } } else if (key.type == FocusOut) { - // int ignore; - // XID winid_focused; - // XGetInputFocus(g->display, &winid_focused, &ignore); - // if (winid_focused == winid) - // XSetInputFocus(g->display, None, RevertToNone, g->time); - if (g->log_level > 1) - fprintf(stderr, "0x%x lost focus\n", (int) winid); + if (key.mode == NotifyNormal || key.mode == NotifyUngrab) { + int ignore; + XID winid_focused; + XGetInputFocus(g->display, &winid_focused, &ignore); + if (winid_focused == winid) { + XSetInputFocus(g->display, None, RevertToNone, g->time); + if (g->log_level > 1) + fprintf(stderr, "0x%x lost focus\n", (int) winid); + } + } } } From b1b8a618095d42edbef3f9195f7336ae538dece0 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Tue, 15 Mar 2022 23:09:54 +0800 Subject: [PATCH 07/21] WIP: SendEvent theater --- gui-agent/vmside.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index 530dd2de..c68a8e15 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -20,6 +20,7 @@ * */ +#include #include #include #include @@ -1823,8 +1824,12 @@ static void handle_focus(Ghandles * g, XID winid) evi_leave.mode = key.mode; // good luck on applications not rely on other fields - XSendEvent(g->display, winid, true, 0, (XEvent *)&ev); + // TODO: figure out what's the best way for this to work + // some applications ignore events with send_event = true + XSendEvent(g->display, winid, true, FocusChangeMask, (XEvent *)&ev); + // XSendEvent(g->display, winid, false, 0, (XEvent *)&ev); XSendEvent(g->display, winid, true, 0, (XEvent *)&evi); + // XSendEvent(g->display, winid, false, 0, (XEvent *)&evi); // not working if (key.type == FocusIn) { if (key.mode == NotifyNormal || key.mode == NotifyUngrab) { From 3df8fc668a1210920b903a32683bfed8648537cf Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Wed, 16 Mar 2022 22:19:46 +0800 Subject: [PATCH 08/21] send focus event later --- gui-agent/vmside.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index c68a8e15..95eca4d9 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -1824,13 +1824,6 @@ static void handle_focus(Ghandles * g, XID winid) evi_leave.mode = key.mode; // good luck on applications not rely on other fields - // TODO: figure out what's the best way for this to work - // some applications ignore events with send_event = true - XSendEvent(g->display, winid, true, FocusChangeMask, (XEvent *)&ev); - // XSendEvent(g->display, winid, false, 0, (XEvent *)&ev); - XSendEvent(g->display, winid, true, 0, (XEvent *)&evi); - // XSendEvent(g->display, winid, false, 0, (XEvent *)&evi); // not working - if (key.type == FocusIn) { if (key.mode == NotifyNormal || key.mode == NotifyUngrab) { XSetInputFocus(g->display, winid, RevertToNone, g->time); @@ -1863,6 +1856,11 @@ static void handle_focus(Ghandles * g, XID winid) } } } + + XSendEvent(g->display, winid, false, 0, (XEvent *)&ev); + XSendEvent(g->display, winid, false, 0, (XEvent *)&evi); + XSendEvent(g->display, winid, true, FocusChangeMask, (XEvent *)&ev); + XSendEvent(g->display, winid, true, FocusChangeMask, (XEvent *)&evi); } static int bitset(unsigned char *keys, int num) From 19974bf98ba81f18ea86ad2cc673c893d23a7406 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Fri, 1 Apr 2022 15:57:56 +0200 Subject: [PATCH 09/21] Try to send correct focus events via different API calls --- gui-agent/vmside.c | 43 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index 95eca4d9..9e8872f9 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -1801,31 +1801,9 @@ static void handle_focus(Ghandles * g, XID winid) int use_take_focus = false; read_data(g->vchan, (char *) &key, sizeof(key)); - - // send event directly - XFocusChangeEvent ev; - ev.detail = key.detail; - ev.mode = key.mode; - ev.type = key.type; - ev.window = winid; - - XGenericEventCookie evi; // X Input Extension - XILeaveEvent evi_leave; - memset(&evi_leave, 0, sizeof(evi_leave)); // no UB... - evi.type = GenericEvent; - evi.evtype = key.type; - evi.extension = g->xi_opcode; - // evi.cookie = ????; // no documentation about how to set this field - evi.data = &evi_leave; - evi_leave.type = GenericEvent; - evi_leave.evtype = key.type; - evi_leave.extension = g->xi_opcode; - evi_leave.detail = key.detail; - evi_leave.mode = key.mode; - // good luck on applications not rely on other fields if (key.type == FocusIn) { - if (key.mode == NotifyNormal || key.mode == NotifyUngrab) { + if (key.mode == NotifyNormal) { XSetInputFocus(g->display, winid, RevertToNone, g->time); XRaiseWindow(g->display, winid); if (g->log_level > 1) @@ -1844,8 +1822,14 @@ static void handle_focus(Ghandles * g, XID winid) if (use_take_focus) take_focus(g, winid); } - } else if (key.type == FocusOut) { + if (key.mode == NotifyGrab) { + XGrabPointer(g->display, winid, false, 0, GrabModeSync, GrabModeSync, None, None, CurrentTime); + } if (key.mode == NotifyNormal || key.mode == NotifyUngrab) { + XUngrabPointer(g->display, CurrentTime); + } + } else if (key.type == FocusOut) { + if (key.mode == NotifyNormal) { int ignore; XID winid_focused; XGetInputFocus(g->display, &winid_focused, &ignore); @@ -1855,12 +1839,13 @@ static void handle_focus(Ghandles * g, XID winid) fprintf(stderr, "0x%x lost focus\n", (int) winid); } } + if (key.mode == NotifyGrab) { + XGrabPointer(g->display, g->root_win, false, 0, GrabModeSync, GrabModeSync, None, None, CurrentTime); + } + if (key.mode == NotifyUngrab) { + XUngrabPointer(g->display, CurrentTime); + } } - - XSendEvent(g->display, winid, false, 0, (XEvent *)&ev); - XSendEvent(g->display, winid, false, 0, (XEvent *)&evi); - XSendEvent(g->display, winid, true, FocusChangeMask, (XEvent *)&ev); - XSendEvent(g->display, winid, true, FocusChangeMask, (XEvent *)&evi); } static int bitset(unsigned char *keys, int num) From a058ba5e0cf22cdb7bfb92744e548148f0e586b7 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Tue, 21 Jun 2022 04:22:29 +0800 Subject: [PATCH 10/21] Name msg_* properly --- gui-agent/vmside.c | 56 +++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index 9e8872f9..edd9dc2c 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -1673,11 +1673,11 @@ static void handle_keypress(Ghandles * g, XID UNUSED(winid)) static void handle_button(Ghandles * g, XID winid) { - struct msg_button key; + struct msg_button msg; struct genlist *l = list_lookup(windows_list, winid); - read_data(g->vchan, (char *) &key, sizeof(key)); + read_data(g->vchan, (char *) &msg, sizeof(msg)); if (l && l->data && ((struct window_data*)l->data)->is_docked) { /* get position of embeder, not icon itself*/ winid = ((struct window_data*)l->data)->embeder; @@ -1687,19 +1687,19 @@ static void handle_button(Ghandles * g, XID winid) if (g->log_level > 1) fprintf(stderr, "send buttonevent, win 0x%x type=%d button=%d\n", - (int) winid, key.type, key.button); - feed_xdriver(g, 'B', key.button, key.type == ButtonPress ? 1 : 0); + (int) winid, msg.type, msg.button); + feed_xdriver(g, 'B', msg.button, msg.type == ButtonPress ? 1 : 0); } static void handle_motion(Ghandles * g, XID winid) { - struct msg_motion key; + struct msg_motion msg; // XMotionEvent event; XWindowAttributes attr; int ret; struct genlist *l = list_lookup(windows_list, winid); - read_data(g->vchan, (char *) &key, sizeof(key)); + read_data(g->vchan, (char *) &msg, sizeof(msg)); if (l && l->data && ((struct window_data*)l->data)->is_docked) { /* get position of embeder, not icon itself*/ winid = ((struct window_data*)l->data)->embeder; @@ -1712,14 +1712,14 @@ static void handle_motion(Ghandles * g, XID winid) return; }; - feed_xdriver(g, 'M', attr.x + key.x, attr.y + key.y); + feed_xdriver(g, 'M', attr.x + msg.x, attr.y + msg.y); } // ensure that LeaveNotify is delivered to the window - if pointer is still // above this window, place stub window between pointer and the window static void handle_crossing(Ghandles * g, XID winid) { - struct msg_crossing key; + struct msg_crossing msg; XWindowAttributes attr; int ret; struct genlist *l = list_lookup(windows_list, winid); @@ -1731,9 +1731,9 @@ static void handle_crossing(Ghandles * g, XID winid) winid = ((struct window_data*)l->data)->embeder; } - read_data(g->vchan, (char *) &key, sizeof(key)); + read_data(g->vchan, (char *) &msg, sizeof(msg)); - if (key.mode != NotifyNormal) + if (msg.mode != NotifyNormal) return; ret = XGetWindowAttributes(g->display, winid, &attr); if (ret != 1) { @@ -1743,11 +1743,11 @@ static void handle_crossing(Ghandles * g, XID winid) return; }; - if (key.type == EnterNotify) { + if (msg.type == EnterNotify) { // hide stub window XUnmapWindow(g->display, g->stub_win); - feed_xdriver(g, 'M', attr.x + key.x, attr.y + key.y); - } else if (key.type == LeaveNotify) { + feed_xdriver(g, 'M', attr.x + msg.x, attr.y + msg.y); + } else if (msg.type == LeaveNotify) { XID window_under_pointer, root_returned; int root_x, root_y, win_x, win_y; unsigned int mask_return; @@ -1771,7 +1771,7 @@ static void handle_crossing(Ghandles * g, XID winid) XRaiseWindow(g->display, g->stub_win); } } else { - fprintf(stderr, "Invalid crossing event: %d\n", key.type); + fprintf(stderr, "Invalid crossing event: %d\n", msg.type); } } @@ -1794,16 +1794,15 @@ static void take_focus(Ghandles * g, XID winid) (int) winid); } -static void handle_focus(Ghandles * g, XID winid) +static void handle_focus_helper(Ghandles * g, XID winid, struct msg_focus msg) { - struct msg_focus key; struct genlist *l; int use_take_focus = false; - read_data(g->vchan, (char *) &key, sizeof(key)); + read_data(g->vchan, (char *) &msg, sizeof(msg)); - if (key.type == FocusIn) { - if (key.mode == NotifyNormal) { + if (msg.type == FocusIn) { + if (msg.mode == NotifyNormal) { XSetInputFocus(g->display, winid, RevertToNone, g->time); XRaiseWindow(g->display, winid); if (g->log_level > 1) @@ -1822,14 +1821,14 @@ static void handle_focus(Ghandles * g, XID winid) if (use_take_focus) take_focus(g, winid); } - if (key.mode == NotifyGrab) { + if (msg.mode == NotifyGrab) { XGrabPointer(g->display, winid, false, 0, GrabModeSync, GrabModeSync, None, None, CurrentTime); } - if (key.mode == NotifyNormal || key.mode == NotifyUngrab) { + if (msg.mode == NotifyNormal || msg.mode == NotifyUngrab) { XUngrabPointer(g->display, CurrentTime); } - } else if (key.type == FocusOut) { - if (key.mode == NotifyNormal) { + } else if (msg.type == FocusOut) { + if (msg.mode == NotifyNormal) { int ignore; XID winid_focused; XGetInputFocus(g->display, &winid_focused, &ignore); @@ -1839,15 +1838,22 @@ static void handle_focus(Ghandles * g, XID winid) fprintf(stderr, "0x%x lost focus\n", (int) winid); } } - if (key.mode == NotifyGrab) { + if (msg.mode == NotifyGrab) { XGrabPointer(g->display, g->root_win, false, 0, GrabModeSync, GrabModeSync, None, None, CurrentTime); } - if (key.mode == NotifyUngrab) { + if (msg.mode == NotifyUngrab) { XUngrabPointer(g->display, CurrentTime); } } } +static void handle_focus(Ghandles * g, XID winid) +{ + struct msg_focus msg; + read_data(g->vchan, (char *) &msg, sizeof(msg)); + return handle_focus_helper(g, winid, msg); +} + static int bitset(unsigned char *keys, int num) { return (keys[num / 8] >> (num % 8)) & 1; From 93fe41179485b80cf72f217b617dbdef6021e28f Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Tue, 21 Jun 2022 04:27:59 +0800 Subject: [PATCH 11/21] Focus window before clicked --- gui-agent/vmside.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index edd9dc2c..bd7f0db0 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -1671,6 +1671,8 @@ static void handle_keypress(Ghandles * g, XID UNUSED(winid)) if (!is_mod_key) feed_xdriver(g, 'K', key.keycode, is_press); } +static void handle_focus_helper(Ghandles * g, XID winid, struct msg_focus msg); + static void handle_button(Ghandles * g, XID winid) { struct msg_button msg; @@ -1688,7 +1690,24 @@ static void handle_button(Ghandles * g, XID winid) fprintf(stderr, "send buttonevent, win 0x%x type=%d button=%d\n", (int) winid, msg.type, msg.button); - feed_xdriver(g, 'B', msg.button, msg.type == ButtonPress ? 1 : 0); + + bool is_button_press = msg.type == ButtonPress; + + // Fake a "focus in" when mouse down on unfocused window. + if (is_button_press) { + int _return_to; + XID focused_winid; + XGetInputFocus(g->display, &focused_winid, &_return_to); + if (focused_winid != winid) { + struct msg_focus msg_focusin; + msg_focusin.type = FocusIn; + msg_focusin.mode = NotifyNormal; + msg_focusin.detail = NotifyAncestor; + handle_focus_helper(g, winid, msg_focusin); + } + } + + feed_xdriver(g, 'B', msg.button, is_button_press ? 1 : 0); } static void handle_motion(Ghandles * g, XID winid) From 35bd3335286874808e110f1a1da0f56a574b8fb5 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Tue, 28 Jun 2022 09:24:40 +0800 Subject: [PATCH 12/21] Merge vmside.c from master branch. Fix severe logic bug. --- gui-agent/vmside.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index bd7f0db0..af661648 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -1816,17 +1816,19 @@ static void take_focus(Ghandles * g, XID winid) static void handle_focus_helper(Ghandles * g, XID winid, struct msg_focus msg) { struct genlist *l; - int use_take_focus = false; - - read_data(g->vchan, (char *) &msg, sizeof(msg)); - + bool use_take_focus = false; + bool input_hint = false; + if ( (l=list_lookup(windows_list, winid)) && (l->data) ) + input_hint = ((struct window_data*)l->data)->input_hint; + else { + fprintf(stderr, "WARNING handle_focus: Window 0x%x data not initialized", (int)winid); + input_hint = true; + } + if (msg.type == FocusIn) { if (msg.mode == NotifyNormal) { - XSetInputFocus(g->display, winid, RevertToNone, g->time); XRaiseWindow(g->display, winid); - if (g->log_level > 1) - fprintf(stderr, "0x%x gained focus\n", (int) winid); - + if ( (l=list_lookup(windows_list, winid)) && (l->data) ) { use_take_focus = ((struct window_data*)l->data)->support_take_focus; @@ -1836,6 +1838,12 @@ static void handle_focus_helper(Ghandles * g, XID winid, struct msg_focus msg) fprintf(stderr, "WARNING handle_focus: Window 0x%x data not initialized", (int)winid); } + if (input_hint) { + if (g->log_level > 1) + fprintf(stderr, "0x%x gained focus\n", (int) winid); + XSetInputFocus(g->display, winid, RevertToNone, g->time); + } + // Do not send WM_TAKE_FOCUS if the window doesn't support it if (use_take_focus) take_focus(g, winid); @@ -1846,7 +1854,7 @@ static void handle_focus_helper(Ghandles * g, XID winid, struct msg_focus msg) if (msg.mode == NotifyNormal || msg.mode == NotifyUngrab) { XUngrabPointer(g->display, CurrentTime); } - } else if (msg.type == FocusOut) { + } else if (msg.type == FocusOut && input_hint) { if (msg.mode == NotifyNormal) { int ignore; XID winid_focused; From 835ecd2fa05e5d8bc1d6ffa0000851fd79d467f9 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Sat, 2 Jul 2022 22:18:42 +0200 Subject: [PATCH 13/21] Attempt to fix modifier key reversely stuck --- gui-agent/vmside.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index af661648..c624883f 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -1620,7 +1620,7 @@ static void handle_keypress(Ghandles * g, XID UNUSED(winid)) key.state &= LockMask; } bool is_press = key.type == KeyPress; - bool is_mod_key = false; + bool already_handled = false; if (state.mods != key.state) { XModifierKeymap *modmap; int mod_index; @@ -1642,7 +1642,6 @@ static void handle_keypress(Ghandles * g, XID UNUSED(winid)) // #define Mod5MapIndex 7 for (mod_index = 0; mod_index < 8; mod_index++) { uint32_t keycode = modmap->modifiermap[mod_index*modmap->max_keypermod]; - if (keycode == key.keycode) is_mod_key = true; if (keycode == 0x00) { if (g->log_level > 1) fprintf(stderr, "ignoring disabled modifier %d\n", mod_index); @@ -1658,9 +1657,13 @@ static void handle_keypress(Ghandles * g, XID UNUSED(winid)) } } else { if ((state.mods & mod_mask) && !(key.state & mod_mask)) { + // need to release + if (keycode == key.keycode && !is_press) already_handled = true; feed_xdriver(g, 'K', keycode, 0); } else if (!(state.mods & mod_mask) && (key.state & mod_mask)) { + // need to press + if (keycode == key.keycode && is_press) already_handled = true; feed_xdriver(g, 'K', keycode, 1); } } @@ -1668,7 +1671,7 @@ static void handle_keypress(Ghandles * g, XID UNUSED(winid)) XFreeModifiermap(modmap); } } - if (!is_mod_key) feed_xdriver(g, 'K', key.keycode, is_press); + if (!already_handled) feed_xdriver(g, 'K', key.keycode, is_press); } static void handle_focus_helper(Ghandles * g, XID winid, struct msg_focus msg); From 4fa451e1b5f4c44aaa2cadac60d1d9b685069e72 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Sat, 2 Jul 2022 23:20:51 +0200 Subject: [PATCH 14/21] revert to parent --- gui-agent/vmside.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index c624883f..376d5e2a 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -1844,7 +1844,7 @@ static void handle_focus_helper(Ghandles * g, XID winid, struct msg_focus msg) if (input_hint) { if (g->log_level > 1) fprintf(stderr, "0x%x gained focus\n", (int) winid); - XSetInputFocus(g->display, winid, RevertToNone, g->time); + XSetInputFocus(g->display, winid, RevertToParent, g->time); } // Do not send WM_TAKE_FOCUS if the window doesn't support it @@ -1863,7 +1863,7 @@ static void handle_focus_helper(Ghandles * g, XID winid, struct msg_focus msg) XID winid_focused; XGetInputFocus(g->display, &winid_focused, &ignore); if (winid_focused == winid) { - XSetInputFocus(g->display, None, RevertToNone, g->time); + XSetInputFocus(g->display, None, RevertToParent, g->time); if (g->log_level > 1) fprintf(stderr, "0x%x lost focus\n", (int) winid); } From e894a10cd7d0da87500acff1bce4f8bc6d43e1bd Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Sun, 3 Jul 2022 09:37:42 +0200 Subject: [PATCH 15/21] Disable focus detection on click for now --- gui-agent/vmside.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index 376d5e2a..44d8a081 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -1698,16 +1698,17 @@ static void handle_button(Ghandles * g, XID winid) // Fake a "focus in" when mouse down on unfocused window. if (is_button_press) { - int _return_to; - XID focused_winid; - XGetInputFocus(g->display, &focused_winid, &_return_to); - if (focused_winid != winid) { - struct msg_focus msg_focusin; - msg_focusin.type = FocusIn; - msg_focusin.mode = NotifyNormal; - msg_focusin.detail = NotifyAncestor; - handle_focus_helper(g, winid, msg_focusin); - } + // TODO: detect focus correctly + // int _return_to; + // XID focused_winid; + // XGetInputFocus(g->display, &focused_winid, &_return_to); + // if (focused_winid != winid) { + // struct msg_focus msg_focusin; + // msg_focusin.type = FocusIn; + // msg_focusin.mode = NotifyNormal; + // msg_focusin.detail = NotifyAncestor; + // handle_focus_helper(g, winid, msg_focusin); + // } } feed_xdriver(g, 'B', msg.button, is_button_press ? 1 : 0); From 5032d0a464ee07b299654d07aaf4f90478d8a637 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Mon, 4 Jul 2022 09:58:29 +0200 Subject: [PATCH 16/21] Comment on X's focus and window hierarchy --- gui-agent/vmside.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index 44d8a081..80a12193 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -1696,22 +1696,28 @@ static void handle_button(Ghandles * g, XID winid) bool is_button_press = msg.type == ButtonPress; + // click first, or some weird race condition may happen + // some applications close all context menus when focused, and the click will happen after + feed_xdriver(g, 'B', msg.button, is_button_press ? 1 : 0); + // Fake a "focus in" when mouse down on unfocused window. if (is_button_press) { - // TODO: detect focus correctly // int _return_to; // XID focused_winid; // XGetInputFocus(g->display, &focused_winid, &_return_to); - // if (focused_winid != winid) { - // struct msg_focus msg_focusin; - // msg_focusin.type = FocusIn; - // msg_focusin.mode = NotifyNormal; - // msg_focusin.detail = NotifyAncestor; - // handle_focus_helper(g, winid, msg_focusin); - // } + // bool a = focused_winid != winid + // TODO: check if window is "top-level" (has border), and only focus if it or its child was not focused + // some applications get confused if you give focus to its context menu + // I'm not sure how this works yet + bool need_focus = false; + if (need_focus) { + struct msg_focus msg_focusin; + msg_focusin.type = FocusIn; + msg_focusin.mode = NotifyNormal; + msg_focusin.detail = NotifyNonlinear; + handle_focus_helper(g, winid, msg_focusin); + } } - - feed_xdriver(g, 'B', msg.button, is_button_press ? 1 : 0); } static void handle_motion(Ghandles * g, XID winid) From 2019ae0390f9d2ed9158e7ca04788383542c6687 Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Sat, 9 Jul 2022 04:06:52 +0800 Subject: [PATCH 17/21] fix: Ungrab when focused in This fixed the bug that the mouse remains grabbed when the focused window is killed with "Close Window" from XFCE --- gui-agent/vmside.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index 80a12193..51fd7c4d 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -1860,8 +1860,7 @@ static void handle_focus_helper(Ghandles * g, XID winid, struct msg_focus msg) } if (msg.mode == NotifyGrab) { XGrabPointer(g->display, winid, false, 0, GrabModeSync, GrabModeSync, None, None, CurrentTime); - } - if (msg.mode == NotifyNormal || msg.mode == NotifyUngrab) { + } else { XUngrabPointer(g->display, CurrentTime); } } else if (msg.type == FocusOut && input_hint) { From 5a4f1aafafbdc58249315eefa8bb246aa9d6ffcf Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Tue, 19 Jul 2022 01:49:44 +0800 Subject: [PATCH 18/21] Ungrab pointer when any window is destroyed in the same VM Seem to have less focus problem with this change --- gui-agent/vmside.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index 51fd7c4d..ea77b399 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -872,6 +872,7 @@ static void process_xevent_destroy(Ghandles * g, XID window) } SKIP_NONMANAGED_WINDOW; + XUngrabPointer(g->display, CurrentTime); if (g->log_level > 0) fprintf(stderr, "handle destroy 0x%x\n", (int) window); hdr.type = MSG_DESTROY; From dda5c3bdcba581f779b93e3048da993d0ab32fbb Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Thu, 11 Aug 2022 18:53:59 +0800 Subject: [PATCH 19/21] Add qubes-common protocol headers as git submodule --- .gitmodules | 4 ++++ archlinux/.gitignore | 3 +++ gui-agent/.gitignore | 1 + gui-agent/Makefile | 2 +- qubes-common | 1 + 5 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 .gitmodules create mode 100644 archlinux/.gitignore create mode 160000 qubes-common diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..287e2c1a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "qubes-common"] + path = qubes-common + url = git@github.com:locriacyber/qubes-gui-common.git + branch = xinput2 diff --git a/archlinux/.gitignore b/archlinux/.gitignore new file mode 100644 index 00000000..e2e4594b --- /dev/null +++ b/archlinux/.gitignore @@ -0,0 +1,3 @@ +*.tar.zst +/src/ +/pkg/ \ No newline at end of file diff --git a/gui-agent/.gitignore b/gui-agent/.gitignore index 7d05a284..510b7d6c 100644 --- a/gui-agent/.gitignore +++ b/gui-agent/.gitignore @@ -1 +1,2 @@ qubes_gui +qubes-gui \ No newline at end of file diff --git a/gui-agent/Makefile b/gui-agent/Makefile index 3b26e887..d86d5152 100644 --- a/gui-agent/Makefile +++ b/gui-agent/Makefile @@ -20,7 +20,7 @@ # CC ?= gcc -CFLAGS += -I../include/ `pkg-config --cflags vchan` -g -Wall -Wextra -Werror -pie -fPIC +CFLAGS += -I../qubes-common/include -I../include/ `pkg-config --cflags vchan` -g -Wall -Wextra -Werror -pie -fPIC OBJS = vmside.o \ ../gui-common/txrx-vchan.o ../gui-common/error.o ../common/list.o ../gui-common/encoding.o LIBS = -lX11 -lXdamage -lXcomposite -lXfixes `pkg-config --libs vchan` -lqubesdb diff --git a/qubes-common b/qubes-common new file mode 160000 index 00000000..ee3b1b94 --- /dev/null +++ b/qubes-common @@ -0,0 +1 @@ +Subproject commit ee3b1b9495fe0b680a2984596b1f9636c4c72003 From b5c3995474e9491e471a0c05eeb93d55d0773e5d Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Thu, 11 Aug 2022 19:18:54 +0800 Subject: [PATCH 20/21] Modify to work with protocol v1.5 --- gui-agent/vmside.c | 177 ++++++++++++++++++++++++--------------------- 1 file changed, 95 insertions(+), 82 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index ea77b399..77cfa763 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -20,6 +20,8 @@ * */ +#define _POSIX_C_SOURCE 2 // getopt + #include #include #include @@ -64,7 +66,7 @@ /* Supported protocol version */ #define PROTOCOL_VERSION_MAJOR 1 -#define PROTOCOL_VERSION_MINOR 3 +#define PROTOCOL_VERSION_MINOR 5 #define PROTOCOL_VERSION (PROTOCOL_VERSION_MAJOR << 16 | PROTOCOL_VERSION_MINOR) #if !(PROTOCOL_VERSION_MAJOR == QUBES_GUID_PROTOCOL_VERSION_MAJOR && \ @@ -1604,78 +1606,16 @@ static void mkghandles(Ghandles * g) g->clipboard_data_len = 0; } -static void handle_keypress(Ghandles * g, XID UNUSED(winid)) +static void handle_xi_key(Ghandles * g, XID UNUSED(winid)) { - struct msg_keypress key; - XkbStateRec state; + struct msg_xi_key key; read_data(g->vchan, (char *) &key, sizeof(key)); - // sync modifiers state - if (XkbGetState(g->display, XkbUseCoreKbd, &state) != Success) { - if (g->log_level > 0) - fprintf(stderr, "failed to get modifier state\n"); - state.mods = key.state; - } - if (!g->sync_all_modifiers) { - // ignore all but CapsLock - state.mods &= LockMask; - key.state &= LockMask; - } - bool is_press = key.type == KeyPress; - bool already_handled = false; - if (state.mods != key.state) { - XModifierKeymap *modmap; - int mod_index; - int mod_mask; - - modmap = XGetModifierMapping(g->display); - if (!modmap) { - if (g->log_level > 0) - fprintf(stderr, "failed to get modifier mapping\n"); - } else { - // from X.h: - // #define ShiftMapIndex 0 - // #define LockMapIndex 1 - // #define ControlMapIndex 2 - // #define Mod1MapIndex 3 - // #define Mod2MapIndex 4 - // #define Mod3MapIndex 5 - // #define Mod4MapIndex 6 - // #define Mod5MapIndex 7 - for (mod_index = 0; mod_index < 8; mod_index++) { - uint32_t keycode = modmap->modifiermap[mod_index*modmap->max_keypermod]; - if (keycode == 0x00) { - if (g->log_level > 1) - fprintf(stderr, "ignoring disabled modifier %d\n", mod_index); - // no key set for this modifier, ignore - continue; - } - mod_mask = (1<display, XkbUseCoreKbd, &state) != Success) { + if (g->log_level > 0) + fprintf(stderr, "failed to get modifier state\n"); + state.mods = key_modifier; + } + if (!g->sync_all_modifiers) { + // ignore all but CapsLock + state.mods &= LockMask; + key_modifier &= LockMask; + } + bool is_press = key_evtype == KeyPress; + bool already_handled = false; + if (state.mods != key_modifier) { + XModifierKeymap *modmap; + int mod_index; + int mod_mask; + + modmap = XGetModifierMapping(g->display); + if (!modmap) { + if (g->log_level > 0) + fprintf(stderr, "failed to get modifier mapping\n"); + } else { + // from X.h: + // #define ShiftMapIndex 0 + // #define LockMapIndex 1 + // #define ControlMapIndex 2 + // #define Mod1MapIndex 3 + // #define Mod2MapIndex 4 + // #define Mod3MapIndex 5 + // #define Mod4MapIndex 6 + // #define Mod5MapIndex 7 + for (mod_index = 0; mod_index < 8; mod_index++) { + uint32_t keycode = modmap->modifiermap[mod_index*modmap->max_keypermod]; + if (keycode == 0x00) { + if (g->log_level > 1) + fprintf(stderr, "ignoring disabled modifier %d\n", mod_index); + // no key set for this modifier, ignore + continue; + } + mod_mask = (1<data) ) input_hint = ((struct window_data*)l->data)->input_hint; else { - fprintf(stderr, "WARNING handle_focus: Window 0x%x data not initialized", (int)winid); + fprintf(stderr, "WARNING handle_xi_focus: Window 0x%x data not initialized", (int)winid); input_hint = true; } - if (msg.type == FocusIn) { + if (msg.evtype == FocusIn) { if (msg.mode == NotifyNormal) { XRaiseWindow(g->display, winid); @@ -1846,7 +1858,7 @@ static void handle_focus_helper(Ghandles * g, XID winid, struct msg_focus msg) if (((struct window_data*)l->data)->is_docked) XRaiseWindow(g->display, ((struct window_data*)l->data)->embeder); } else { - fprintf(stderr, "WARNING handle_focus: Window 0x%x data not initialized", (int)winid); + fprintf(stderr, "WARNING handle_xi_focus: Window 0x%x data not initialized", (int)winid); } if (input_hint) { @@ -1864,7 +1876,7 @@ static void handle_focus_helper(Ghandles * g, XID winid, struct msg_focus msg) } else { XUngrabPointer(g->display, CurrentTime); } - } else if (msg.type == FocusOut && input_hint) { + } else if (msg.evtype == FocusOut && input_hint) { if (msg.mode == NotifyNormal) { int ignore; XID winid_focused; @@ -1884,10 +1896,11 @@ static void handle_focus_helper(Ghandles * g, XID winid, struct msg_focus msg) } } -static void handle_focus(Ghandles * g, XID winid) +static void handle_xi_focus(Ghandles * g, XID winid) { - struct msg_focus msg; + struct msg_xi_focus msg; read_data(g->vchan, (char *) &msg, sizeof(msg)); + reset_modifier_keys(g, 0, 0, msg.modifier_effective); // release keys when focus out return handle_focus_helper(g, winid, msg); } @@ -2125,8 +2138,8 @@ static void handle_message(Ghandles * g) if (g->log_level > 1) fprintf(stderr, "received message type %d for 0x%x\n", hdr.type, hdr.window); switch (hdr.type) { - case MSG_KEYPRESS: - handle_keypress(g, hdr.window); + case MSG_XI_KEY: + handle_xi_key(g, hdr.window); break; case MSG_CONFIGURE: handle_configure(g, hdr.window); @@ -2146,8 +2159,8 @@ static void handle_message(Ghandles * g) case MSG_CROSSING: handle_crossing(g, hdr.window); break; - case MSG_FOCUS: - handle_focus(g, hdr.window); + case MSG_XI_FOCUS: + handle_xi_focus(g, hdr.window); break; case MSG_CLIPBOARD_REQ: handle_clipboard_req(g, hdr.window); From 8074cb8d854884b50a8f64795f791b3a5959f69d Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Thu, 11 Aug 2022 22:30:21 +0800 Subject: [PATCH 21/21] Add -V to show version --- gui-agent/vmside.c | 163 ++++++++++++++++++++++++--------------------- qubes-common | 2 +- 2 files changed, 89 insertions(+), 76 deletions(-) diff --git a/gui-agent/vmside.c b/gui-agent/vmside.c index 77cfa763..74d64ec6 100644 --- a/gui-agent/vmside.c +++ b/gui-agent/vmside.c @@ -20,11 +20,13 @@ * */ -#define _POSIX_C_SOURCE 2 // getopt +#define _POSIX_C_SOURCE 200112L // getopt #include +#include #include #include +#include #include #include #include @@ -1606,10 +1608,86 @@ static void mkghandles(Ghandles * g) g->clipboard_data_len = 0; } + +// return true if the key is already handled +static bool reset_modifier_keys(Ghandles * g, uint32_t key_evtype, uint32_t key_detail, uint32_t key_modifier) +{ + XkbStateRec state; + // sync modifiers state + if (XkbGetState(g->display, XkbUseCoreKbd, &state) != Success) { + if (g->log_level > 0) + fprintf(stderr, "failed to get modifier state\n"); + state.mods = key_modifier; + } + if (!g->sync_all_modifiers) { + // ignore all but CapsLock + state.mods &= LockMask; + key_modifier &= LockMask; + } + bool is_press = key_evtype == KeyPress; + bool already_handled = false; + if (state.mods != key_modifier) { + XModifierKeymap *modmap; + int mod_index; + int mod_mask; + + modmap = XGetModifierMapping(g->display); + if (!modmap) { + if (g->log_level > 0) + fprintf(stderr, "failed to get modifier mapping\n"); + } else { + // from X.h: + // #define ShiftMapIndex 0 + // #define LockMapIndex 1 + // #define ControlMapIndex 2 + // #define Mod1MapIndex 3 + // #define Mod2MapIndex 4 + // #define Mod3MapIndex 5 + // #define Mod4MapIndex 6 + // #define Mod5MapIndex 7 + for (mod_index = 0; mod_index < 8; mod_index++) { + uint32_t keycode = modmap->modifiermap[mod_index*modmap->max_keypermod]; + if (keycode == 0x00) { + if (g->log_level > 1) + fprintf(stderr, "ignoring disabled modifier %d\n", mod_index); + // no key set for this modifier, ignore + continue; + } + mod_mask = (1<vchan, (char *) &key, sizeof(key)); + // TODO: make this an tweakable option (in config file) + // drop key repeat + if (key.flags & XIKeyRepeat) return; bool is_press = key.evtype == KeyPress; bool already_handled = reset_modifier_keys(g, key.evtype, key.detail, key.modifier_effective); if (!already_handled) feed_xdriver(g, 'K', key.detail, is_press); @@ -1764,78 +1842,6 @@ static void take_focus(Ghandles * g, XID winid) (int) winid); } -// return true if the key is already handled -static bool reset_modifier_keys(Ghandles * g, uint32_t key_evtype, uint32_t key_detail, uint32_t key_modifier) -{ - XkbStateRec state; - // sync modifiers state - if (XkbGetState(g->display, XkbUseCoreKbd, &state) != Success) { - if (g->log_level > 0) - fprintf(stderr, "failed to get modifier state\n"); - state.mods = key_modifier; - } - if (!g->sync_all_modifiers) { - // ignore all but CapsLock - state.mods &= LockMask; - key_modifier &= LockMask; - } - bool is_press = key_evtype == KeyPress; - bool already_handled = false; - if (state.mods != key_modifier) { - XModifierKeymap *modmap; - int mod_index; - int mod_mask; - - modmap = XGetModifierMapping(g->display); - if (!modmap) { - if (g->log_level > 0) - fprintf(stderr, "failed to get modifier mapping\n"); - } else { - // from X.h: - // #define ShiftMapIndex 0 - // #define LockMapIndex 1 - // #define ControlMapIndex 2 - // #define Mod1MapIndex 3 - // #define Mod2MapIndex 4 - // #define Mod3MapIndex 5 - // #define Mod4MapIndex 6 - // #define Mod5MapIndex 7 - for (mod_index = 0; mod_index < 8; mod_index++) { - uint32_t keycode = modmap->modifiermap[mod_index*modmap->max_keypermod]; - if (keycode == 0x00) { - if (g->log_level > 1) - fprintf(stderr, "ignoring disabled modifier %d\n", mod_index); - // no key set for this modifier, ignore - continue; - } - mod_mask = (1<vchan, (char *) &msg, sizeof(msg)); - reset_modifier_keys(g, 0, 0, msg.modifier_effective); // release keys when focus out + // disabled, since it doesn't seem to do much + // reset_modifier_keys(g, 0, 0, msg.modifier_effective); // release keys when focus out return handle_focus_helper(g, winid, msg); } @@ -2205,6 +2212,8 @@ static pid_t get_xconf_and_run_x(Ghandles *g) static void send_protocol_version(libvchan_t *vchan) { uint32_t version = PROTOCOL_VERSION; + // todo: remove + fprintf(stderr, "send version %d", version); write_struct(vchan, version); } @@ -2240,6 +2249,7 @@ static void handle_sigterm() static void usage() { fprintf(stderr, "Usage: qubes_gui [options]\n"); + fprintf(stderr, " -V show version\n"); fprintf(stderr, " -v increase log verbosity\n"); fprintf(stderr, " -q decrease log verbosity\n"); fprintf(stderr, " -m sync all modifiers before key event (default)\n"); @@ -2263,7 +2273,7 @@ static void parse_args(Ghandles * g, int argc, char **argv) g->sync_all_modifiers = 1; g->composite_redirect_automatic = 1; g->domid = 0; - while ((opt = getopt(argc, argv, "qvchmMd:")) != -1) { + while ((opt = getopt(argc, argv, "qvVchmMd:")) != -1) { switch (opt) { case 'q': g->log_level--; @@ -2271,6 +2281,9 @@ static void parse_args(Ghandles * g, int argc, char **argv) case 'v': g->log_level++; break; + case 'V': + fprintf(stderr, "qubes-gui version %d.%d\n", PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR); + exit(0); case 'm': g->sync_all_modifiers = 1; break; diff --git a/qubes-common b/qubes-common index ee3b1b94..59dd27dc 160000 --- a/qubes-common +++ b/qubes-common @@ -1 +1 @@ -Subproject commit ee3b1b9495fe0b680a2984596b1f9636c4c72003 +Subproject commit 59dd27dcc99308aff0000d008b01485274642f14