From 40aa275cd8c75b410a69ed82eaa10ef99d1e6d59 Mon Sep 17 00:00:00 2001 From: Mike Gabriel Date: Fri, 6 Dec 2013 15:20:15 +0100 Subject: Add patch: 302_nx-X11_do-not-build-bundled-libs.full.patch. Rename patch: 302_nxagent_configurable-keystrokes.full.patch. * Add patch: 302_nx-X11_do-not-build-bundled-libs.full.patch. Taken from Fedora. Do not build bundled libraries, rather use system libraries instead. * Rename patch: 302_nxagent_configurable-keystrokes.full.patch to 320_nxagent_configurable-keystrokes.full.patch. --- debian/changelog | 4 + ...302_nx-X11_do-not-build-bundled-libs.full.patch | 39 + .../302_nxagent_configurable-keystrokes.full.patch | 1031 -------------------- .../320_nxagent_configurable-keystrokes.full.patch | 1031 ++++++++++++++++++++ debian/patches/series | 3 +- 5 files changed, 1076 insertions(+), 1032 deletions(-) create mode 100644 debian/patches/302_nx-X11_do-not-build-bundled-libs.full.patch delete mode 100644 debian/patches/302_nxagent_configurable-keystrokes.full.patch create mode 100644 debian/patches/320_nxagent_configurable-keystrokes.full.patch diff --git a/debian/changelog b/debian/changelog index 6c3062036..9568708ad 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,6 +13,10 @@ nx-libs (2:3.5.0.22-0x2go1) UNRELEASED; urgency=low * debian/control: + Add libfreetype6-dev to Build-Depends: field. * Refresh patch: 600_nx-X11+nxcompext+nxcompshad_unique-libnames.full.patch. + * Add patch: 302_nx-X11_do-not-build-bundled-libs.full.patch. Taken from Fedora. + Do not build bundled libraries, rather use system libraries instead. + * Rename patch: 302_nxagent_configurable-keystrokes.full.patch to + 320_nxagent_configurable-keystrokes.full.patch. * nx-libs.spec: + Ship nx-libs.spec (RPM package definitions) in upstream project. (Thanks to the Fedora package maintainers). File differs from the Fedora file diff --git a/debian/patches/302_nx-X11_do-not-build-bundled-libs.full.patch b/debian/patches/302_nx-X11_do-not-build-bundled-libs.full.patch new file mode 100644 index 000000000..4437aaacf --- /dev/null +++ b/debian/patches/302_nx-X11_do-not-build-bundled-libs.full.patch @@ -0,0 +1,39 @@ +Description: Do not build bundled libraries +Author: Orion Poplawski +--- a/nx-X11/config/cf/host.def 2013-08-30 13:23:26.000000000 -0600 ++++ b/nx-X11/config/cf/host.def 2013-08-30 20:44:19.647460161 -0600 +@@ -962,7 +962,7 @@ XCOMM $XFree86: xc/config/cf/xf86site.de + + #define SharedLibXdmcp YES + +-#define BuildXaw7 YES ++#define BuildXaw7 NO + + #else /* #if !defined(NXZaurusXServer) && !defined(NXiPAQXServer) && !defined(DarwinArchitecture) */ + +@@ -1023,3 +1023,8 @@ XCOMM $XFree86: xc/config/cf/xf86site.de + + #define BuildRman NO + #define BuildFontEncLib NO ++#define BuildXcursorLibrary NO ++#define BuildXftLibrary NO ++#define BuildXft1Library NO ++#define SharedLibFont NO ++#define BuildLoadableXlibI18n NO +diff -up nx-libs-3.5.0.21/nx-X11/lib/Imakefile.bundled nx-libs-3.5.0.21/nx-X11/lib/Imakefile +--- a/nx-X11/lib/Imakefile 2013-08-30 08:18:40.000000000 -0600 ++++ b/nx-X11/lib/Imakefile 2013-08-30 20:42:40.344850909 -0600 +@@ -213,14 +213,8 @@ XEXTLIBDIR = Xext + + #if BuildLibraries + OLDXLIBDIR = oldX +-ICELIBDIR = ICE +-SMLIBDIR = SM +-XTLIBDIR = Xt +-XMULIBDIR = Xmu +-XMUULIBDIR = Xmuu + XPMLIBDIR = Xpm + XTSTLIBDIR = Xtst +-FSLIBDIR = FS + #endif + diff --git a/debian/patches/302_nxagent_configurable-keystrokes.full.patch b/debian/patches/302_nxagent_configurable-keystrokes.full.patch deleted file mode 100644 index e7a3e4a3f..000000000 --- a/debian/patches/302_nxagent_configurable-keystrokes.full.patch +++ /dev/null @@ -1,1031 +0,0 @@ -Author: Alexander Wuerstlein -Description: Make nxagent-specific keyboard bindings configurable - Replaces the hardcoded nxagent keybindings by a configurable - table of keybindings. The default configuration is the same as the - original one, to maintain compatibility. A user/administrator can either - specify a command line parameter, environment variable or place a file - in ~/.nx/config/keystroke.cfg or /etc/nxagent/keystroke.cfg to reconfigure - these keybindings. - . - The configuration file format is XML, a dependency on libxml2 is added - to allow parsing the configuration. ---- a/nx-X11/programs/Xserver/Imakefile -+++ b/nx-X11/programs/Xserver/Imakefile -@@ -1013,15 +1013,18 @@ - #if defined(SunArchitecture) - NXAGENTNXLIBS = -L ../../../nxcomp -L ../../../nxcompext -L ../../../nxcompshad \ - -lXcomp -lXcompext -lXcompshad -lrt -L/usr/sfw/lib -lXrender -lXfixes \ -- -L../../../nx-X11/exports/lib -lXtst -lXdamage -lXrandr -lXcomposite -lXdmcp -+ -L../../../nx-X11/exports/lib -lXtst -lXdamage -lXrandr -lXcomposite -lXdmcp \ -+`pkg-config --libs libxml-2.0` - #elif defined(cygwinArchitecture) - NXAGENTNXLIBS = -L ../../../nxcomp -L ../../../nxcompext \ - -lXcomp -lXcompext -lXrender -lX11 -lXext -lXcomposite -lXfixes \ -- -L ../../../nxcompshad -lXcompshad -L../../../nx-X11/exports/lib -lXtst -lXdmcp -+ -L ../../../nxcompshad -lXcompshad -L../../../nx-X11/exports/lib -lXtst -lXdmcp \ -+`pkg-config --libs libxml-2.0` - #else - NXAGENTNXLIBS = -L ../../../nxcomp -L ../../../nxcompext -L ../../../nxcompshad \ - -lXcomp -lXcompext -lXcompshad -lXrender -lX11 -lXext -lXfixes \ -- -L../../../nx-X11/exports/lib -lXtst -lXdamage -lXrandr -lXcomposite -lXinerama -lXdmcp -+ -L../../../nx-X11/exports/lib -lXtst -lXdamage -lXrandr -lXcomposite -lXinerama -lXdmcp \ -+`pkg-config --libs libxml-2.0` - #endif - - #endif ---- a/nx-X11/programs/Xserver/hw/nxagent/Imakefile -+++ b/nx-X11/programs/Xserver/hw/nxagent/Imakefile -@@ -142,7 +142,8 @@ - -I../../miext/damage -I../../miext/cw \ - -I../../GL/glx -I../../GL/include -I../../../../lib/GL/include -I../../Xext \ - -I$(EXTINCSRC) -I$(XINCLUDESRC) \ -- $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) -+ $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) \ -+ `pkg-config --cflags-only-I libxml-2.0` - #ifdef SunArchitecture - INCLUDES = -I. -I../../../../../nxcomp -I../../../../../nxcompext -I../../../../../nxcompshad \ - -I../../../../extras/Mesa/include \ -@@ -152,7 +153,8 @@ - -I../../GL/glx -I../../GL/include -I../../../../lib/GL/include -I../../Xext \ - -I../../miext/damage -I../../miext/cw \ - -I$(EXTINCSRC) -I$(XINCLUDESRC) \ -- $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) -+ $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) \ -+ `pkg-config --cflags-only-I libxml-2.0` - #else - #ifdef cygwinArchitecture - INCLUDES = -I. -I$(XBUILDINCDIR) -I$(FONTINCSRC) \ -@@ -162,7 +164,8 @@ - -I../../../../../nxcomp -I../../../../../nxcompext -I../../../../../nxcompshad \ - -I../../../../extras/Mesa/include \ - -I$(EXTINCSRC) -I$(XINCLUDESRC) \ -- $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) -+ $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) \ -+ `pkg-config --cflags-only-I libxml-2.0` - #endif - #endif - ---- a/nx-X11/programs/Xserver/hw/nxagent/Keystroke.c -+++ b/nx-X11/programs/Xserver/hw/nxagent/Keystroke.c -@@ -28,8 +28,15 @@ - #include "Keystroke.h" - #include "Drawable.h" - -+#include -+ -+#include -+#include -+ - extern Bool nxagentWMIsRunning; - extern Bool nxagentIpaq; -+extern char *nxagentKeystrokeFile; -+Bool nxagentKeystrokeFileParsed = False; - - #ifdef NX_DEBUG_INPUT - int nxagentDebugInputDevices = 0; -@@ -47,297 +54,527 @@ - #undef DEBUG - #undef DUMP - --int nxagentCheckSpecialKeystroke(XKeyEvent *X, enum HandleEventResult *result) --{ -- KeySym sym; -- int index = 0; - -- *result = doNothing; -+/* this table is used to parse actions given on the command line or in the -+ * config file, therefore indices have to match the enum in Keystroke.h */ -+char * nxagentSpecialKeystrokeNames[] = { -+ "end_marker", -+ "close_session", -+ "switch_all_screens", -+ "minimize", -+ "left", -+ "up", -+ "right", -+ "down", -+ "resize", -+ "defer", -+ "ignore", -+ "force_synchronization", -+ -+ "debug_tree", -+ "regions_on_screen", -+ "test_input", -+ "deactivate_input_devices_grab", -+ -+ "fullscreen", -+ "viewport_move_left", -+ "viewport_move_up", -+ "viewport_move_right", -+ "viewport_move_down", -+ NULL, -+}; -+ -+struct nxagentSpecialKeystrokeMap default_map[] = { -+ /* stroke, modifierMask, modifierAltMeta, keysym */ -+ {KEYSTROKE_DEBUG_TREE, ControlMask, 1, XK_q}, -+ {KEYSTROKE_DEBUG_TREE, ControlMask, 1, XK_Q}, -+ {KEYSTROKE_CLOSE_SESSION, ControlMask, 1, XK_t}, -+ {KEYSTROKE_CLOSE_SESSION, ControlMask, 1, XK_T}, -+ {KEYSTROKE_SWITCH_ALL_SCREENS, ControlMask, 1, XK_f}, -+ {KEYSTROKE_SWITCH_ALL_SCREENS, ControlMask, 1, XK_F}, -+ {KEYSTROKE_MINIMIZE, ControlMask, 1, XK_m}, -+ {KEYSTROKE_MINIMIZE, ControlMask, 1, XK_M}, -+ {KEYSTROKE_LEFT, ControlMask, 1, XK_Left}, -+ {KEYSTROKE_LEFT, ControlMask, 1, XK_KP_Left}, -+ {KEYSTROKE_UP, ControlMask, 1, XK_Up}, -+ {KEYSTROKE_UP, ControlMask, 1, XK_KP_Up}, -+ {KEYSTROKE_RIGHT, ControlMask, 1, XK_Right}, -+ {KEYSTROKE_RIGHT, ControlMask, 1, XK_KP_Right}, -+ {KEYSTROKE_DOWN, ControlMask, 1, XK_Down}, -+ {KEYSTROKE_DOWN, ControlMask, 1, XK_KP_Down}, -+ {KEYSTROKE_RESIZE, ControlMask, 1, XK_r}, -+ {KEYSTROKE_RESIZE, ControlMask, 1, XK_R}, -+ {KEYSTROKE_DEFER, ControlMask, 1, XK_e}, -+ {KEYSTROKE_DEFER, ControlMask, 1, XK_E}, -+ {KEYSTROKE_IGNORE, ControlMask, 1, XK_BackSpace}, -+ {KEYSTROKE_IGNORE, 0, 0, XK_Terminate_Server}, -+ {KEYSTROKE_FORCE_SYNCHRONIZATION, ControlMask, 1, XK_j}, -+ {KEYSTROKE_FORCE_SYNCHRONIZATION, ControlMask, 1, XK_J}, -+ {KEYSTROKE_REGIONS_ON_SCREEN, ControlMask, 1, XK_a}, -+ {KEYSTROKE_REGIONS_ON_SCREEN, ControlMask, 1, XK_A}, -+ {KEYSTROKE_TEST_INPUT, ControlMask, 1, XK_x}, -+ {KEYSTROKE_TEST_INPUT, ControlMask, 1, XK_X}, -+ {KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB, ControlMask, 1, XK_y}, -+ {KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB, ControlMask, 1, XK_Y}, -+ {KEYSTROKE_FULLSCREEN, ControlMask | ShiftMask, 1, XK_f}, -+ {KEYSTROKE_FULLSCREEN, ControlMask | ShiftMask, 1, XK_F}, -+ {KEYSTROKE_VIEWPORT_MOVE_LEFT, ControlMask | ShiftMask, 1, XK_Left}, -+ {KEYSTROKE_VIEWPORT_MOVE_LEFT, ControlMask | ShiftMask, 1, XK_KP_Left}, -+ {KEYSTROKE_VIEWPORT_MOVE_UP, ControlMask | ShiftMask, 1, XK_Up}, -+ {KEYSTROKE_VIEWPORT_MOVE_UP, ControlMask | ShiftMask, 1, XK_KP_Up}, -+ {KEYSTROKE_VIEWPORT_MOVE_RIGHT, ControlMask | ShiftMask, 1, XK_Right}, -+ {KEYSTROKE_VIEWPORT_MOVE_RIGHT, ControlMask | ShiftMask, 1, XK_KP_Right}, -+ {KEYSTROKE_VIEWPORT_MOVE_DOWN, ControlMask | ShiftMask, 1, XK_Down}, -+ {KEYSTROKE_VIEWPORT_MOVE_DOWN, ControlMask | ShiftMask, 1, XK_KP_Down}, -+ {KEYSTROKE_END_MARKER, 0, 0, 0}, -+}; -+struct nxagentSpecialKeystrokeMap *map = default_map; - -- /* -- * I don't know how much hard work is doing this operation. -- * Do we need a cache ? -+static int modifier_matches(unsigned int mask, int compare_alt_meta, unsigned int state) -+{ -+ /* nxagentAltMetaMask needs special handling -+ * it seems to me its an and-ed mask of all possible meta and alt keys -+ * somehow... -+ * -+ * otherwise this function would be just a simple bitop - */ -+ int ret = 1; - -- sym = XKeycodeToKeysym(nxagentDisplay, X -> keycode, index); -+ if (compare_alt_meta) { -+ if (! (state & nxagentAltMetaMask)) { -+ ret = 0; -+ } - -- if (sym == XK_VoidSymbol || sym == NoSymbol) -- { -- return 0; -+ mask &= ~nxagentAltMetaMask; - } - -- #ifdef TEST -- fprintf(stderr, "nxagentCheckSpecialKeystroke: got code %x - state %x - sym %lx\n", -- X -> keycode, X -> state, sym); -- #endif -- -- /* -- * Check special keys. -- */ -- -- /* -- * FIXME: We should use the keysym instead that the keycode -- * here. -- */ -+ /* all modifiers except meta/alt have to match exactly, extra bits are evil */ -+ if ((mask & state) != mask) { -+ ret = 0; -+ } - -- if (X -> keycode == 130 && nxagentIpaq) -- { -- *result = doStartKbd; -+ return ret; -+} - -- return 1; -- } -+static int read_binding_from_xmlnode(xmlNode *node, struct nxagentSpecialKeystrokeMap *ret) -+{ -+ int successful = 0; -+ struct nxagentSpecialKeystrokeMap new = {0, 0, 0, 0}; -+ xmlAttr *attr; - -- if ((X -> state & nxagentAltMetaMask) && -- ((X -> state & (ControlMask | ShiftMask)) == ControlMask)) -+ for (attr = node->properties; attr; attr = attr->next) - { -- switch (sym) -+ /* ignore attributes without data (which should never happen anyways) */ -+ if (attr->children->content == NULL) - { -- #ifdef DEBUG_TREE -- -- case XK_q: -- case XK_Q: -- { -- *result = doDebugTree; -- -- break; -- } -- -- #endif /* DEBUG_TREE */ -- -- case XK_t: -- case XK_T: -- { -- *result = doCloseSession; -- -- break; -- } -- case XK_f: -- case XK_F: -+ char *aname = (attr->name)?(attr->name):"unknown"; -+ fprintf(stderr, "attribute %s with NULL value", aname); -+ continue; -+ } -+ if (strcmp((char *)attr->name, "action") == 0) -+ { -+ int i; -+ for (i = 0; nxagentSpecialKeystrokeNames[i] != NULL; i++) - { -- if (nxagentOption(Rootless) == False) -+ if (strcmp(nxagentSpecialKeystrokeNames[i],(char *)attr->children->content) == 0) - { -- *result = doSwitchAllScreens; -+ /* this relies on the values of enum nxagentSpecialKeystroke and the -+ * indices of nxagentSpecialKeystrokeNames being in sync */ -+ new.stroke = i; -+ break; - } -- -- break; - } -- case XK_m: -- case XK_M: -+ continue; -+ } -+ else if (strcmp((char *)attr->name, "key") == 0) -+ { -+ new.keysym = XStringToKeysym((char *)attr->children->content); -+ /* NoSymbol is usually 0, but could there be weird implementations? */ -+ if (new.keysym == NoSymbol) - { -- if (nxagentOption(Rootless) == False) -- { -- *result = doMinimize; -- } -- -- break; -+ new.keysym = 0; - } -- case XK_Left: -- case XK_KP_Left: -- { -- if (nxagentOption(Rootless) == False && -- nxagentOption(DesktopResize) == False) -- { -- *result = doViewportLeft; -- } -+ continue; -+ } - -- break; -- } -- case XK_Up: -- case XK_KP_Up: -- { -- if (nxagentOption(Rootless) == False && -- nxagentOption(DesktopResize) == False) -- { -- *result = doViewportUp; -- } -+ /* ignore attributes with value="0" or "false", everything else is interpreted as true */ -+ if (strcmp((char *)attr->children->content, "0") == 0 || strcmp((char *)attr->children->content, "false") == 0) -+ continue; - -- break; -- } -- case XK_Right: -- case XK_KP_Right: -- { -- if (nxagentOption(Rootless) == False && -- nxagentOption(DesktopResize) == False) -- { -- *result = doViewportRight; -- } -+ if (strcmp((char *)attr->name, "Mod1") == 0) -+ { -+ new.modifierMask |= Mod1Mask; -+ } -+ else if (strcmp((char *)attr->name, "Mod2") == 0) -+ { -+ new.modifierMask |= Mod2Mask; -+ } -+ else if (strcmp((char *)attr->name, "Mod3") == 0) -+ { -+ new.modifierMask |= Mod3Mask; -+ } -+ else if (strcmp((char *)attr->name, "Mod4") == 0) -+ { -+ new.modifierMask |= Mod4Mask; -+ } -+ else if (strcmp((char *)attr->name, "Control") == 0) -+ { -+ new.modifierMask |= ControlMask; -+ } -+ else if (strcmp((char *)attr->name, "Shift") == 0) -+ { -+ new.modifierMask |= ShiftMask; -+ } -+ else if (strcmp((char *)attr->name, "Lock") == 0) -+ { -+ new.modifierMask |= LockMask; -+ } -+ else if (strcmp((char *)attr->name, "AltMeta") == 0) -+ { -+ new.modifierAltMeta = 1; -+ } -+ } - -- break; -- } -- case XK_Down: -- case XK_KP_Down: -- { -- if (nxagentOption(Rootless) == 0 && -- nxagentOption(DesktopResize) == 0) -- { -- *result = doViewportDown; -- } -+ if (new.stroke != 0 && new.keysym != 0) -+ { -+ /* keysym and stroke are required, everything else is optional */ -+ successful = 1; -+ memcpy(ret, &new, sizeof(struct nxagentSpecialKeystrokeMap)); -+ } -+ return successful; -+} - -- break; -- } -- case XK_R: -- case XK_r: -- { -- if (nxagentOption(Rootless) == 0) -- { -- *result = doSwitchResizeMode; -- } -+/* -+ * searches a keystroke xml file -+ * -+ * search order: -+ * - '-keystrokefile' commandline parameter -+ * - $NXAGENT_KEYSTROKEFILE environment variable -+ * - $HOME/.nx/config/keystroke.cfg -+ * - /etc/nxagent/keystroke.cfg -+ * - hardcoded traditional NX default settings -+ */ -+static void parse_keystroke_file(void) -+{ -+ char *filename = NULL; - -- break; -- } -- case XK_E: -- case XK_e: -- { -- *result = doSwitchDeferMode; -+ char *homefile = "/.nx/config/keystroke.cfg"; -+ char *etcfile = "/etc/nxagent/keystroke.cfg"; - -- break; -+ if (nxagentKeystrokeFile != NULL && access(nxagentKeystrokeFile, R_OK) == 0) -+ { -+ filename = strdup(nxagentKeystrokeFile); -+ if (filename == NULL) -+ { -+ fprintf(stderr, "malloc failed"); -+ exit(EXIT_FAILURE); -+ } -+ } -+ else if ((filename = getenv("NXAGENT_KEYSTROKEFILE")) != NULL && access(filename, R_OK) == 0) -+ { -+ filename = strdup(filename); -+ if (filename == NULL) -+ { -+ fprintf(stderr, "malloc failed"); -+ exit(EXIT_FAILURE); -+ } -+ } -+ else -+ { -+ char *homedir = getenv("HOME"); -+ filename = NULL; -+ if (homedir != NULL) -+ { -+ homedir = strdup(homedir); -+ if (homedir == NULL) -+ { -+ fprintf(stderr, "malloc failed"); -+exit(EXIT_FAILURE); - } -- case XK_BackSpace: -- case XK_Terminate_Server: -+ filename = calloc(1, strlen(homefile) + strlen(homedir) + 1); -+ if (filename == NULL) - { -- /* -- * Discard Ctrl-Alt-BackSpace key. -- */ -- -- return 1; -- -- break; -+ fprintf(stderr, "malloc failed"); -+ exit(EXIT_FAILURE); - } -- -- case XK_J: -- case XK_j: -+ strcpy(filename, homedir); -+ strcpy(filename + strlen(homedir), homefile); -+ if (homedir) - { -- nxagentForceSynchronization = 1; -- -- return 1; -+ free(homedir); - } -+ } - -- #ifdef DUMP -- -- case XK_A: -- case XK_a: -+ if (access(filename, R_OK) == 0) -+ { -+ /* empty */ -+ } -+ else if (access(etcfile, R_OK == 0)) -+ { -+ if (filename) -+ free(filename); -+ filename = strdup(etcfile); -+ if (filename == NULL) - { -- /* -- * Used to test the lazy encoding. -- */ -- -- nxagentRegionsOnScreen(); -- -- return 1; -+ fprintf(stderr, "malloc failed"); -+ exit(EXIT_FAILURE); - } -+ } -+ else -+ { -+ if (filename) -+free(filename); -+ filename = NULL; -+ } -+ } - -- #endif -- -- #ifdef NX_DEBUG_INPUT -+ /* now we know which file to read, if any */ -+ if (filename) -+ { -+ xmlDoc *doc = NULL; -+ xmlNode *root = NULL; -+ LIBXML_TEST_VERSION -+ doc = xmlReadFile(filename, NULL, 0); -+ if (doc != NULL) -+ { -+ xmlNode *cur = NULL; -+ root = xmlDocGetRootElement(doc); - -- case XK_X: -- case XK_x: -+ for (cur = root; cur; cur = cur->next) - { -- /* -- * Used to test the input devices state. -- */ -+ if (cur->type == XML_ELEMENT_NODE && strcmp((char *)cur->name, "keystrokes") == 0) -+{ -+ xmlNode *bindings = NULL; -+ int num = 0; -+ int idx = 0; - -- if (X -> type == KeyPress) -- { -- if (nxagentDebugInputDevices == 0) -+ for (bindings = cur->children; bindings; bindings = bindings->next) - { -- fprintf(stderr, "Info: Turning input devices debug ON.\n"); -- -- nxagentDebugInputDevices = 1; -+ if (bindings->type == XML_ELEMENT_NODE && strcmp((char *)bindings->name, "keystroke") == 0) -+ { -+ num++; -+ } - } -- else -+ map = calloc((num + 1), sizeof(struct nxagentSpecialKeystrokeMap)); -+ if (map == NULL) - { -- fprintf(stderr, "Info: Turning input devices debug OFF.\n"); -- -- nxagentDebugInputDevices = 0; -- -- nxagentLastInputDevicesDumpTime = 0; -+ fprintf(stderr, "malloc failed"); -+ exit(EXIT_FAILURE); - } -- } -- -- return 1; -- } - -- case XK_Y: -- case XK_y: -- { -- /* -- * Used to deactivate input devices grab. -- */ -+ for (bindings = cur->children; bindings; bindings = bindings->next) -+ { -+ if (bindings->type == XML_ELEMENT_NODE && strcmp((char *)bindings->name, "keystroke") == 0) -+ { -+ int res = 0; -+ res = read_binding_from_xmlnode(bindings, &(map[idx])); -+ if (res) -+ idx++; -+ } -+ } - -- if (X -> type == KeyPress) -- { -- nxagentDeactivateInputDevicesGrabs(); -+ map[idx].stroke = KEYSTROKE_END_MARKER; - } -- -- return 1; - } - -+ xmlFreeDoc(doc); -+ xmlCleanupParser(); -+ } -+ else -+ { -+ #ifdef DEBUG -+ fprintf("XML parsing for %s failed\n", filename); - #endif - } -+ free(filename); - } -- else if ((X -> state & nxagentAltMetaMask) && -- ((X -> state & (ControlMask | ShiftMask)) == (ControlMask | -- ShiftMask))) -+} -+ -+static enum nxagentSpecialKeystroke find_keystroke(XKeyEvent *X) -+{ -+ KeySym keysym = XKeycodeToKeysym(nxagentDisplay, X->keycode, 0); -+ struct nxagentSpecialKeystrokeMap *cur = map; -+ -+ if (! nxagentKeystrokeFileParsed) - { -- switch (sym) -- { -- case XK_f: -- case XK_F: -- { -- if (nxagentOption(Rootless) == 0) -- { -- *result = doSwitchFullscreen; -- } -+ parse_keystroke_file(); -+ nxagentKeystrokeFileParsed = True; -+ } - -- break; -- } -- case XK_Left: -- case XK_KP_Left: -- { -- if (nxagentOption(Rootless) == 0 && -- nxagentOption(DesktopResize) == 0) -- { -- *result = doViewportMoveLeft; -- } -+ enum nxagentSpecialKeystroke ret = KEYSTROKE_NOTHING; - -- break; -- } -- case XK_Up: -- case XK_KP_Up: -- { -- if (nxagentOption(Rootless) == 0 && -- nxagentOption(DesktopResize) == 0) -- { -- *result = doViewportMoveUp; -- } -+ while ((cur++)->stroke != KEYSTROKE_END_MARKER) { -+ if (cur->keysym == keysym && modifier_matches(cur->modifierMask, cur->modifierAltMeta, X->state)) { -+ return cur->stroke; -+ } -+ } - -- break; -- } -- case XK_Right: -- case XK_KP_Right: -- { -- if (nxagentOption(Rootless) == 0 && -- nxagentOption(DesktopResize) == 0) -- { -- *result = doViewportMoveRight; -- } -+ return ret; -+} - -- break; -- } -- case XK_Down: -- case XK_KP_Down: -- { -- if (nxagentOption(Rootless) == 0 && -- nxagentOption(DesktopResize) == 0) -- { -- *result = doViewportMoveDown; -- } -+int nxagentCheckSpecialKeystroke(XKeyEvent *X, enum HandleEventResult *result) -+{ -+ KeySym sym; -+ int index = 0; -+ enum nxagentSpecialKeystroke stroke = find_keystroke(X); - -- break; -- } -- } -+ *result = doNothing; -+ -+ /* -+ * I don't know how much hard work is doing this operation. -+ * Do we need a cache ? -+ */ -+ -+ sym = XKeycodeToKeysym(nxagentDisplay, X -> keycode, index); -+ -+ if (sym == XK_VoidSymbol || sym == NoSymbol) -+ { -+ return 0; - } - -+ #ifdef TEST -+ fprintf(stderr, "nxagentCheckSpecialKeystroke: got code %x - state %x - sym %lx\n", -+ X -> keycode, X -> state, sym); -+ #endif -+ -+ /* -+ * Check special keys. -+ */ -+ -+ /* -+ * FIXME: We should use the keysym instead that the keycode -+ * here. -+ */ -+ -+ if (X -> keycode == 130 && nxagentIpaq) -+ { -+ *result = doStartKbd; -+ -+ return 1; -+ } -+ -+ switch (stroke) { -+ case KEYSTROKE_DEBUG_TREE: -+ #ifdef DEBUG_TREE -+ *result = doDebugTree; -+ #endif -+ break; -+ case KEYSTROKE_CLOSE_SESSION: -+ *result = doCloseSession; -+ break; -+ case KEYSTROKE_SWITCH_ALL_SCREENS: -+ if (nxagentOption(Rootless) == False) { -+ *result = doSwitchAllScreens; -+ } -+ break; -+ case KEYSTROKE_MINIMIZE: -+ if (nxagentOption(Rootless) == False) { -+ *result = doMinimize; -+ } -+ break; -+ case KEYSTROKE_LEFT: -+ if (nxagentOption(Rootless) == False && -+ nxagentOption(DesktopResize) == False) { -+ *result = doViewportLeft; -+ } -+ break; -+ case KEYSTROKE_UP: -+ if (nxagentOption(Rootless) == False && -+ nxagentOption(DesktopResize) == False) { -+ *result = doViewportUp; -+ } -+ break; -+ case KEYSTROKE_RIGHT: -+ if (nxagentOption(Rootless) == False && -+ nxagentOption(DesktopResize) == False) { -+ *result = doViewportRight; -+ } -+ break; -+ case KEYSTROKE_DOWN: -+ if (nxagentOption(Rootless) == False && -+ nxagentOption(DesktopResize) == False) { -+ *result = doViewportDown; -+ } -+ break; -+ case KEYSTROKE_RESIZE: -+ if (nxagentOption(Rootless) == False) { -+ *result = doSwitchResizeMode; -+ } -+ break; -+ case KEYSTROKE_DEFER: -+ *result = doSwitchDeferMode; -+ break; -+ case KEYSTROKE_IGNORE: -+ /* this is used e.g. to ignore C-A-Backspace aka XK_Terminate_Server */ -+ return 1; -+ break; -+ case KEYSTROKE_FORCE_SYNCHRONIZATION: -+ nxagentForceSynchronization = 1; -+ break; -+ case KEYSTROKE_REGIONS_ON_SCREEN: -+ #ifdef DUMP -+ nxagentRegionsOnScreen(); -+ #endif -+ break; -+ case KEYSTROKE_TEST_INPUT: -+ /* -+ * Used to test the input devices state. -+ */ -+ #ifdef NX_DEBUG_INPUT -+ if (X -> type == KeyPress) { -+ if (nxagentDebugInputDevices == 0) { -+ fprintf(stderr, "Info: Turning input devices debug ON.\n"); -+ nxagentDebugInputDevices = 1; -+ } else { -+ fprintf(stderr, "Info: Turning input devices debug OFF.\n"); -+ nxagentDebugInputDevices = 0; -+ nxagentLastInputDevicesDumpTime = 0; -+ } -+ } -+ return 1; -+ #endif -+ break; -+ case KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB: -+ #ifdef NX_DEBUG_INPUT -+ if (X->type == KeyPress) { -+ nxagentDeactivateInputDevicesGrab(); -+ } -+ return 1; -+ #endif -+ break; -+ case KEYSTROKE_FULLSCREEN: -+ if (nxagentOption(Rootless) == 0) { -+ *result = doSwitchFullscreen; -+ } -+ break; -+ case KEYSTROKE_VIEWPORT_MOVE_LEFT: -+ if (nxagentOption(Rootless) == 0 && -+ nxagentOption(DesktopResize) == 0) { -+ *result = doViewportMoveLeft; -+ } -+ break; -+ case KEYSTROKE_VIEWPORT_MOVE_UP: -+ if (nxagentOption(Rootless) == 0 && -+ nxagentOption(DesktopResize) == 0) { -+ *result = doViewportMoveUp; -+ } -+ break; -+ case KEYSTROKE_VIEWPORT_MOVE_RIGHT: -+ if (nxagentOption(Rootless) == 0 && -+ nxagentOption(DesktopResize) == 0) { -+ *result = doViewportMoveRight; -+ } -+ break; -+ case KEYSTROKE_VIEWPORT_MOVE_DOWN: -+ if (nxagentOption(Rootless) == 0 && -+ nxagentOption(DesktopResize) == 0) { -+ *result = doViewportMoveDown; -+ } -+ break; -+ case KEYSTROKE_NOTHING: /* do nothing. difference to KEYSTROKE_IGNORE is the return value */ -+ case KEYSTROKE_END_MARKER: /* just to make gcc STFU */ -+ case KEYSTROKE_MAX: -+ break; -+ } - return (*result == doNothing) ? 0 : 1; - } ---- a/nx-X11/programs/Xserver/hw/nxagent/Keystroke.h -+++ b/nx-X11/programs/Xserver/hw/nxagent/Keystroke.h -@@ -24,4 +24,51 @@ - - unsigned int nxagentAltMetaMask; - -+/* keep this sorted, do not rely on any numerical value in this enum, and be aware -+ * that KEYSTROKE_MAX may be used in a malloc */ -+ -+/* also be aware that if changing any numerical values, you also need to change values -+ * Keystroke.c nxagentSpecialKeystrokeNames */ -+enum nxagentSpecialKeystroke { -+ /* 0 is used as end marker */ -+ KEYSTROKE_END_MARKER = 0, -+ KEYSTROKE_CLOSE_SESSION = 1, -+ KEYSTROKE_SWITCH_ALL_SCREENS = 2, -+ KEYSTROKE_MINIMIZE = 3, -+ KEYSTROKE_LEFT = 4, -+ KEYSTROKE_UP = 5, -+ KEYSTROKE_RIGHT = 6, -+ KEYSTROKE_DOWN = 7, -+ KEYSTROKE_RESIZE = 8, -+ KEYSTROKE_DEFER = 9, -+ KEYSTROKE_IGNORE = 10, -+ KEYSTROKE_FORCE_SYNCHRONIZATION = 11, -+ -+ /* stuff used for debugging, probably not useful for most people */ -+ KEYSTROKE_DEBUG_TREE = 12, -+ KEYSTROKE_REGIONS_ON_SCREEN = 13, -+ KEYSTROKE_TEST_INPUT = 14, -+ KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB = 15, -+ -+ KEYSTROKE_FULLSCREEN = 16, -+ KEYSTROKE_VIEWPORT_MOVE_LEFT = 17, -+ KEYSTROKE_VIEWPORT_MOVE_UP = 18, -+ KEYSTROKE_VIEWPORT_MOVE_RIGHT = 19, -+ KEYSTROKE_VIEWPORT_MOVE_DOWN = 20, -+ -+ KEYSTROKE_NOTHING = 21, -+ -+ /* insert more here, increment KEYSTROKE_MAX accordingly. -+ * then update string translation below */ -+ -+ KEYSTROKE_MAX=22, -+}; -+ -+struct nxagentSpecialKeystrokeMap { -+ enum nxagentSpecialKeystroke stroke; -+ unsigned int modifierMask; /* everything except alt/meta */ -+ int modifierAltMeta; /* modifier combination should include alt/meta */ -+ KeySym keysym; -+}; -+ - #endif /* __Keystroke_H__ */ ---- /dev/null -+++ b/README.keystrokes -@@ -0,0 +1,83 @@ -+Configurable keybindings in nxagent -+ -+Keybindings in the redistributed x2go version of nxagent can now be configured -+by the user. This is done via a configuration file. -+ -+File location -+------------- -+ -+nxagent searches for the configuration file in the following order: -+- in the location given by the '-keystrokefile' command line parameter -+- in the location given by the NXAGENT_KEYSTROKEFILE environment variable -+- in ~/.nx/config/keystroke.cfg -+- in /etc/nxagent/keystroke.cfg -+ -+If none of those files is accessible, the default configuration is used which -+is the same as the old, traditional nxagent keybindings. -+ -+File format -+----------- -+ -+The configuration file is XML with the following format: -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+Each 'action' defines an action to be executed when receiving that keystroke. A -+list of possible actions is given below. Some of those actions are only -+available with debug builds of nxagent. -+ -+Keys are given as a combination of 'key' and (optionally) a number of -+modifiers. The key attribute is evaluated into a X11 key via the usual -+XStringToKeysym function. A list of possible keys can be found in -+/usr/include/X11/keysymdef.h, the names are specified without the leading -+'XK_'. Evaluation is case-sensitive, so, 'space' and 'Escape' will work while -+'Space' and 'escape' won't. -+ -+Modifiers are given as boolean attributes, possible modifiers are Mod1, Mod2, -+Mod3, Mod4, Control, Shift, Lock. Sensible combinations strongly depend on your -+keyboard configuration, but usually you will need Mod1 and Control. Boolean in -+this context means '0', 'false' and an unspecified attribute are false, anything -+else is considered true. -+ -+Everything in this file is case-sensitive. Unknown lines are ignored. -+Keybindings are evaluated from top to bottom, so if a keybinding matches, other -+keybindings further down will be ignored. The contents of the file replaces the -+default keybindings, and only one file is read, no merging between different -+configuration files is done. This also means that an empty or invalid configuration -+file deactivates all keybindings. -+ -+List of possible 'action' attributes: -+------------------------------------- -+ -+close_session -+switch_all_screens -+minimize -+left -+up -+right -+down -+resize -+defer -+ignore -+fullscreen -+viewport_move_left -+viewport_move_up -+viewport_move_right -+viewport_move_down -+ -+Only in builds with certain debugging options enabled, ignored otherwise: -+force_synchronization -+debug_tree -+regions_on_screen -+test_input -+deactivate_input_devices_grab ---- a/nx-X11/programs/Xserver/hw/nxagent/Args.c -+++ b/nx-X11/programs/Xserver/hw/nxagent/Args.c -@@ -148,6 +148,8 @@ - - char nxagentVerbose = 0; - -+char *nxagentKeystrokeFile = NULL; -+ - int ddxProcessArgument(int argc, char *argv[], int i) - { - /* -@@ -1021,6 +1023,20 @@ - return 1; - } - -+ if (!strcmp(argv[i], "-keystrokefile")) -+ { -+ if (i + 1 < argc) -+ { -+ if (NULL != (nxagentKeystrokeFile = strdup(argv[i + 1]))) -+ { -+ return 2; -+ } else { -+ FatalError("malloc failed"); -+ } -+ } -+ return 0; -+ } -+ - return 0; - } - ---- a/nx-X11/programs/Xserver/hw/nxagent/Args.h -+++ b/nx-X11/programs/Xserver/hw/nxagent/Args.h -@@ -83,4 +83,6 @@ - - extern int nxagentRemoteMajor; - -+extern char *nxagentKeystrokeFile; -+ - #endif /* __Args_H__ */ - diff --git a/debian/patches/320_nxagent_configurable-keystrokes.full.patch b/debian/patches/320_nxagent_configurable-keystrokes.full.patch new file mode 100644 index 000000000..e7a3e4a3f --- /dev/null +++ b/debian/patches/320_nxagent_configurable-keystrokes.full.patch @@ -0,0 +1,1031 @@ +Author: Alexander Wuerstlein +Description: Make nxagent-specific keyboard bindings configurable + Replaces the hardcoded nxagent keybindings by a configurable + table of keybindings. The default configuration is the same as the + original one, to maintain compatibility. A user/administrator can either + specify a command line parameter, environment variable or place a file + in ~/.nx/config/keystroke.cfg or /etc/nxagent/keystroke.cfg to reconfigure + these keybindings. + . + The configuration file format is XML, a dependency on libxml2 is added + to allow parsing the configuration. +--- a/nx-X11/programs/Xserver/Imakefile ++++ b/nx-X11/programs/Xserver/Imakefile +@@ -1013,15 +1013,18 @@ + #if defined(SunArchitecture) + NXAGENTNXLIBS = -L ../../../nxcomp -L ../../../nxcompext -L ../../../nxcompshad \ + -lXcomp -lXcompext -lXcompshad -lrt -L/usr/sfw/lib -lXrender -lXfixes \ +- -L../../../nx-X11/exports/lib -lXtst -lXdamage -lXrandr -lXcomposite -lXdmcp ++ -L../../../nx-X11/exports/lib -lXtst -lXdamage -lXrandr -lXcomposite -lXdmcp \ ++`pkg-config --libs libxml-2.0` + #elif defined(cygwinArchitecture) + NXAGENTNXLIBS = -L ../../../nxcomp -L ../../../nxcompext \ + -lXcomp -lXcompext -lXrender -lX11 -lXext -lXcomposite -lXfixes \ +- -L ../../../nxcompshad -lXcompshad -L../../../nx-X11/exports/lib -lXtst -lXdmcp ++ -L ../../../nxcompshad -lXcompshad -L../../../nx-X11/exports/lib -lXtst -lXdmcp \ ++`pkg-config --libs libxml-2.0` + #else + NXAGENTNXLIBS = -L ../../../nxcomp -L ../../../nxcompext -L ../../../nxcompshad \ + -lXcomp -lXcompext -lXcompshad -lXrender -lX11 -lXext -lXfixes \ +- -L../../../nx-X11/exports/lib -lXtst -lXdamage -lXrandr -lXcomposite -lXinerama -lXdmcp ++ -L../../../nx-X11/exports/lib -lXtst -lXdamage -lXrandr -lXcomposite -lXinerama -lXdmcp \ ++`pkg-config --libs libxml-2.0` + #endif + + #endif +--- a/nx-X11/programs/Xserver/hw/nxagent/Imakefile ++++ b/nx-X11/programs/Xserver/hw/nxagent/Imakefile +@@ -142,7 +142,8 @@ + -I../../miext/damage -I../../miext/cw \ + -I../../GL/glx -I../../GL/include -I../../../../lib/GL/include -I../../Xext \ + -I$(EXTINCSRC) -I$(XINCLUDESRC) \ +- $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) ++ $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) \ ++ `pkg-config --cflags-only-I libxml-2.0` + #ifdef SunArchitecture + INCLUDES = -I. -I../../../../../nxcomp -I../../../../../nxcompext -I../../../../../nxcompshad \ + -I../../../../extras/Mesa/include \ +@@ -152,7 +153,8 @@ + -I../../GL/glx -I../../GL/include -I../../../../lib/GL/include -I../../Xext \ + -I../../miext/damage -I../../miext/cw \ + -I$(EXTINCSRC) -I$(XINCLUDESRC) \ +- $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) ++ $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) \ ++ `pkg-config --cflags-only-I libxml-2.0` + #else + #ifdef cygwinArchitecture + INCLUDES = -I. -I$(XBUILDINCDIR) -I$(FONTINCSRC) \ +@@ -162,7 +164,8 @@ + -I../../../../../nxcomp -I../../../../../nxcompext -I../../../../../nxcompshad \ + -I../../../../extras/Mesa/include \ + -I$(EXTINCSRC) -I$(XINCLUDESRC) \ +- $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) ++ $(VFBINCLUDES) $(NXFONTINCLUDES) $(LIBXRANDRINCLUDES) \ ++ `pkg-config --cflags-only-I libxml-2.0` + #endif + #endif + +--- a/nx-X11/programs/Xserver/hw/nxagent/Keystroke.c ++++ b/nx-X11/programs/Xserver/hw/nxagent/Keystroke.c +@@ -28,8 +28,15 @@ + #include "Keystroke.h" + #include "Drawable.h" + ++#include ++ ++#include ++#include ++ + extern Bool nxagentWMIsRunning; + extern Bool nxagentIpaq; ++extern char *nxagentKeystrokeFile; ++Bool nxagentKeystrokeFileParsed = False; + + #ifdef NX_DEBUG_INPUT + int nxagentDebugInputDevices = 0; +@@ -47,297 +54,527 @@ + #undef DEBUG + #undef DUMP + +-int nxagentCheckSpecialKeystroke(XKeyEvent *X, enum HandleEventResult *result) +-{ +- KeySym sym; +- int index = 0; + +- *result = doNothing; ++/* this table is used to parse actions given on the command line or in the ++ * config file, therefore indices have to match the enum in Keystroke.h */ ++char * nxagentSpecialKeystrokeNames[] = { ++ "end_marker", ++ "close_session", ++ "switch_all_screens", ++ "minimize", ++ "left", ++ "up", ++ "right", ++ "down", ++ "resize", ++ "defer", ++ "ignore", ++ "force_synchronization", ++ ++ "debug_tree", ++ "regions_on_screen", ++ "test_input", ++ "deactivate_input_devices_grab", ++ ++ "fullscreen", ++ "viewport_move_left", ++ "viewport_move_up", ++ "viewport_move_right", ++ "viewport_move_down", ++ NULL, ++}; ++ ++struct nxagentSpecialKeystrokeMap default_map[] = { ++ /* stroke, modifierMask, modifierAltMeta, keysym */ ++ {KEYSTROKE_DEBUG_TREE, ControlMask, 1, XK_q}, ++ {KEYSTROKE_DEBUG_TREE, ControlMask, 1, XK_Q}, ++ {KEYSTROKE_CLOSE_SESSION, ControlMask, 1, XK_t}, ++ {KEYSTROKE_CLOSE_SESSION, ControlMask, 1, XK_T}, ++ {KEYSTROKE_SWITCH_ALL_SCREENS, ControlMask, 1, XK_f}, ++ {KEYSTROKE_SWITCH_ALL_SCREENS, ControlMask, 1, XK_F}, ++ {KEYSTROKE_MINIMIZE, ControlMask, 1, XK_m}, ++ {KEYSTROKE_MINIMIZE, ControlMask, 1, XK_M}, ++ {KEYSTROKE_LEFT, ControlMask, 1, XK_Left}, ++ {KEYSTROKE_LEFT, ControlMask, 1, XK_KP_Left}, ++ {KEYSTROKE_UP, ControlMask, 1, XK_Up}, ++ {KEYSTROKE_UP, ControlMask, 1, XK_KP_Up}, ++ {KEYSTROKE_RIGHT, ControlMask, 1, XK_Right}, ++ {KEYSTROKE_RIGHT, ControlMask, 1, XK_KP_Right}, ++ {KEYSTROKE_DOWN, ControlMask, 1, XK_Down}, ++ {KEYSTROKE_DOWN, ControlMask, 1, XK_KP_Down}, ++ {KEYSTROKE_RESIZE, ControlMask, 1, XK_r}, ++ {KEYSTROKE_RESIZE, ControlMask, 1, XK_R}, ++ {KEYSTROKE_DEFER, ControlMask, 1, XK_e}, ++ {KEYSTROKE_DEFER, ControlMask, 1, XK_E}, ++ {KEYSTROKE_IGNORE, ControlMask, 1, XK_BackSpace}, ++ {KEYSTROKE_IGNORE, 0, 0, XK_Terminate_Server}, ++ {KEYSTROKE_FORCE_SYNCHRONIZATION, ControlMask, 1, XK_j}, ++ {KEYSTROKE_FORCE_SYNCHRONIZATION, ControlMask, 1, XK_J}, ++ {KEYSTROKE_REGIONS_ON_SCREEN, ControlMask, 1, XK_a}, ++ {KEYSTROKE_REGIONS_ON_SCREEN, ControlMask, 1, XK_A}, ++ {KEYSTROKE_TEST_INPUT, ControlMask, 1, XK_x}, ++ {KEYSTROKE_TEST_INPUT, ControlMask, 1, XK_X}, ++ {KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB, ControlMask, 1, XK_y}, ++ {KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB, ControlMask, 1, XK_Y}, ++ {KEYSTROKE_FULLSCREEN, ControlMask | ShiftMask, 1, XK_f}, ++ {KEYSTROKE_FULLSCREEN, ControlMask | ShiftMask, 1, XK_F}, ++ {KEYSTROKE_VIEWPORT_MOVE_LEFT, ControlMask | ShiftMask, 1, XK_Left}, ++ {KEYSTROKE_VIEWPORT_MOVE_LEFT, ControlMask | ShiftMask, 1, XK_KP_Left}, ++ {KEYSTROKE_VIEWPORT_MOVE_UP, ControlMask | ShiftMask, 1, XK_Up}, ++ {KEYSTROKE_VIEWPORT_MOVE_UP, ControlMask | ShiftMask, 1, XK_KP_Up}, ++ {KEYSTROKE_VIEWPORT_MOVE_RIGHT, ControlMask | ShiftMask, 1, XK_Right}, ++ {KEYSTROKE_VIEWPORT_MOVE_RIGHT, ControlMask | ShiftMask, 1, XK_KP_Right}, ++ {KEYSTROKE_VIEWPORT_MOVE_DOWN, ControlMask | ShiftMask, 1, XK_Down}, ++ {KEYSTROKE_VIEWPORT_MOVE_DOWN, ControlMask | ShiftMask, 1, XK_KP_Down}, ++ {KEYSTROKE_END_MARKER, 0, 0, 0}, ++}; ++struct nxagentSpecialKeystrokeMap *map = default_map; + +- /* +- * I don't know how much hard work is doing this operation. +- * Do we need a cache ? ++static int modifier_matches(unsigned int mask, int compare_alt_meta, unsigned int state) ++{ ++ /* nxagentAltMetaMask needs special handling ++ * it seems to me its an and-ed mask of all possible meta and alt keys ++ * somehow... ++ * ++ * otherwise this function would be just a simple bitop + */ ++ int ret = 1; + +- sym = XKeycodeToKeysym(nxagentDisplay, X -> keycode, index); ++ if (compare_alt_meta) { ++ if (! (state & nxagentAltMetaMask)) { ++ ret = 0; ++ } + +- if (sym == XK_VoidSymbol || sym == NoSymbol) +- { +- return 0; ++ mask &= ~nxagentAltMetaMask; + } + +- #ifdef TEST +- fprintf(stderr, "nxagentCheckSpecialKeystroke: got code %x - state %x - sym %lx\n", +- X -> keycode, X -> state, sym); +- #endif +- +- /* +- * Check special keys. +- */ +- +- /* +- * FIXME: We should use the keysym instead that the keycode +- * here. +- */ ++ /* all modifiers except meta/alt have to match exactly, extra bits are evil */ ++ if ((mask & state) != mask) { ++ ret = 0; ++ } + +- if (X -> keycode == 130 && nxagentIpaq) +- { +- *result = doStartKbd; ++ return ret; ++} + +- return 1; +- } ++static int read_binding_from_xmlnode(xmlNode *node, struct nxagentSpecialKeystrokeMap *ret) ++{ ++ int successful = 0; ++ struct nxagentSpecialKeystrokeMap new = {0, 0, 0, 0}; ++ xmlAttr *attr; + +- if ((X -> state & nxagentAltMetaMask) && +- ((X -> state & (ControlMask | ShiftMask)) == ControlMask)) ++ for (attr = node->properties; attr; attr = attr->next) + { +- switch (sym) ++ /* ignore attributes without data (which should never happen anyways) */ ++ if (attr->children->content == NULL) + { +- #ifdef DEBUG_TREE +- +- case XK_q: +- case XK_Q: +- { +- *result = doDebugTree; +- +- break; +- } +- +- #endif /* DEBUG_TREE */ +- +- case XK_t: +- case XK_T: +- { +- *result = doCloseSession; +- +- break; +- } +- case XK_f: +- case XK_F: ++ char *aname = (attr->name)?(attr->name):"unknown"; ++ fprintf(stderr, "attribute %s with NULL value", aname); ++ continue; ++ } ++ if (strcmp((char *)attr->name, "action") == 0) ++ { ++ int i; ++ for (i = 0; nxagentSpecialKeystrokeNames[i] != NULL; i++) + { +- if (nxagentOption(Rootless) == False) ++ if (strcmp(nxagentSpecialKeystrokeNames[i],(char *)attr->children->content) == 0) + { +- *result = doSwitchAllScreens; ++ /* this relies on the values of enum nxagentSpecialKeystroke and the ++ * indices of nxagentSpecialKeystrokeNames being in sync */ ++ new.stroke = i; ++ break; + } +- +- break; + } +- case XK_m: +- case XK_M: ++ continue; ++ } ++ else if (strcmp((char *)attr->name, "key") == 0) ++ { ++ new.keysym = XStringToKeysym((char *)attr->children->content); ++ /* NoSymbol is usually 0, but could there be weird implementations? */ ++ if (new.keysym == NoSymbol) + { +- if (nxagentOption(Rootless) == False) +- { +- *result = doMinimize; +- } +- +- break; ++ new.keysym = 0; + } +- case XK_Left: +- case XK_KP_Left: +- { +- if (nxagentOption(Rootless) == False && +- nxagentOption(DesktopResize) == False) +- { +- *result = doViewportLeft; +- } ++ continue; ++ } + +- break; +- } +- case XK_Up: +- case XK_KP_Up: +- { +- if (nxagentOption(Rootless) == False && +- nxagentOption(DesktopResize) == False) +- { +- *result = doViewportUp; +- } ++ /* ignore attributes with value="0" or "false", everything else is interpreted as true */ ++ if (strcmp((char *)attr->children->content, "0") == 0 || strcmp((char *)attr->children->content, "false") == 0) ++ continue; + +- break; +- } +- case XK_Right: +- case XK_KP_Right: +- { +- if (nxagentOption(Rootless) == False && +- nxagentOption(DesktopResize) == False) +- { +- *result = doViewportRight; +- } ++ if (strcmp((char *)attr->name, "Mod1") == 0) ++ { ++ new.modifierMask |= Mod1Mask; ++ } ++ else if (strcmp((char *)attr->name, "Mod2") == 0) ++ { ++ new.modifierMask |= Mod2Mask; ++ } ++ else if (strcmp((char *)attr->name, "Mod3") == 0) ++ { ++ new.modifierMask |= Mod3Mask; ++ } ++ else if (strcmp((char *)attr->name, "Mod4") == 0) ++ { ++ new.modifierMask |= Mod4Mask; ++ } ++ else if (strcmp((char *)attr->name, "Control") == 0) ++ { ++ new.modifierMask |= ControlMask; ++ } ++ else if (strcmp((char *)attr->name, "Shift") == 0) ++ { ++ new.modifierMask |= ShiftMask; ++ } ++ else if (strcmp((char *)attr->name, "Lock") == 0) ++ { ++ new.modifierMask |= LockMask; ++ } ++ else if (strcmp((char *)attr->name, "AltMeta") == 0) ++ { ++ new.modifierAltMeta = 1; ++ } ++ } + +- break; +- } +- case XK_Down: +- case XK_KP_Down: +- { +- if (nxagentOption(Rootless) == 0 && +- nxagentOption(DesktopResize) == 0) +- { +- *result = doViewportDown; +- } ++ if (new.stroke != 0 && new.keysym != 0) ++ { ++ /* keysym and stroke are required, everything else is optional */ ++ successful = 1; ++ memcpy(ret, &new, sizeof(struct nxagentSpecialKeystrokeMap)); ++ } ++ return successful; ++} + +- break; +- } +- case XK_R: +- case XK_r: +- { +- if (nxagentOption(Rootless) == 0) +- { +- *result = doSwitchResizeMode; +- } ++/* ++ * searches a keystroke xml file ++ * ++ * search order: ++ * - '-keystrokefile' commandline parameter ++ * - $NXAGENT_KEYSTROKEFILE environment variable ++ * - $HOME/.nx/config/keystroke.cfg ++ * - /etc/nxagent/keystroke.cfg ++ * - hardcoded traditional NX default settings ++ */ ++static void parse_keystroke_file(void) ++{ ++ char *filename = NULL; + +- break; +- } +- case XK_E: +- case XK_e: +- { +- *result = doSwitchDeferMode; ++ char *homefile = "/.nx/config/keystroke.cfg"; ++ char *etcfile = "/etc/nxagent/keystroke.cfg"; + +- break; ++ if (nxagentKeystrokeFile != NULL && access(nxagentKeystrokeFile, R_OK) == 0) ++ { ++ filename = strdup(nxagentKeystrokeFile); ++ if (filename == NULL) ++ { ++ fprintf(stderr, "malloc failed"); ++ exit(EXIT_FAILURE); ++ } ++ } ++ else if ((filename = getenv("NXAGENT_KEYSTROKEFILE")) != NULL && access(filename, R_OK) == 0) ++ { ++ filename = strdup(filename); ++ if (filename == NULL) ++ { ++ fprintf(stderr, "malloc failed"); ++ exit(EXIT_FAILURE); ++ } ++ } ++ else ++ { ++ char *homedir = getenv("HOME"); ++ filename = NULL; ++ if (homedir != NULL) ++ { ++ homedir = strdup(homedir); ++ if (homedir == NULL) ++ { ++ fprintf(stderr, "malloc failed"); ++exit(EXIT_FAILURE); + } +- case XK_BackSpace: +- case XK_Terminate_Server: ++ filename = calloc(1, strlen(homefile) + strlen(homedir) + 1); ++ if (filename == NULL) + { +- /* +- * Discard Ctrl-Alt-BackSpace key. +- */ +- +- return 1; +- +- break; ++ fprintf(stderr, "malloc failed"); ++ exit(EXIT_FAILURE); + } +- +- case XK_J: +- case XK_j: ++ strcpy(filename, homedir); ++ strcpy(filename + strlen(homedir), homefile); ++ if (homedir) + { +- nxagentForceSynchronization = 1; +- +- return 1; ++ free(homedir); + } ++ } + +- #ifdef DUMP +- +- case XK_A: +- case XK_a: ++ if (access(filename, R_OK) == 0) ++ { ++ /* empty */ ++ } ++ else if (access(etcfile, R_OK == 0)) ++ { ++ if (filename) ++ free(filename); ++ filename = strdup(etcfile); ++ if (filename == NULL) + { +- /* +- * Used to test the lazy encoding. +- */ +- +- nxagentRegionsOnScreen(); +- +- return 1; ++ fprintf(stderr, "malloc failed"); ++ exit(EXIT_FAILURE); + } ++ } ++ else ++ { ++ if (filename) ++free(filename); ++ filename = NULL; ++ } ++ } + +- #endif +- +- #ifdef NX_DEBUG_INPUT ++ /* now we know which file to read, if any */ ++ if (filename) ++ { ++ xmlDoc *doc = NULL; ++ xmlNode *root = NULL; ++ LIBXML_TEST_VERSION ++ doc = xmlReadFile(filename, NULL, 0); ++ if (doc != NULL) ++ { ++ xmlNode *cur = NULL; ++ root = xmlDocGetRootElement(doc); + +- case XK_X: +- case XK_x: ++ for (cur = root; cur; cur = cur->next) + { +- /* +- * Used to test the input devices state. +- */ ++ if (cur->type == XML_ELEMENT_NODE && strcmp((char *)cur->name, "keystrokes") == 0) ++{ ++ xmlNode *bindings = NULL; ++ int num = 0; ++ int idx = 0; + +- if (X -> type == KeyPress) +- { +- if (nxagentDebugInputDevices == 0) ++ for (bindings = cur->children; bindings; bindings = bindings->next) + { +- fprintf(stderr, "Info: Turning input devices debug ON.\n"); +- +- nxagentDebugInputDevices = 1; ++ if (bindings->type == XML_ELEMENT_NODE && strcmp((char *)bindings->name, "keystroke") == 0) ++ { ++ num++; ++ } + } +- else ++ map = calloc((num + 1), sizeof(struct nxagentSpecialKeystrokeMap)); ++ if (map == NULL) + { +- fprintf(stderr, "Info: Turning input devices debug OFF.\n"); +- +- nxagentDebugInputDevices = 0; +- +- nxagentLastInputDevicesDumpTime = 0; ++ fprintf(stderr, "malloc failed"); ++ exit(EXIT_FAILURE); + } +- } +- +- return 1; +- } + +- case XK_Y: +- case XK_y: +- { +- /* +- * Used to deactivate input devices grab. +- */ ++ for (bindings = cur->children; bindings; bindings = bindings->next) ++ { ++ if (bindings->type == XML_ELEMENT_NODE && strcmp((char *)bindings->name, "keystroke") == 0) ++ { ++ int res = 0; ++ res = read_binding_from_xmlnode(bindings, &(map[idx])); ++ if (res) ++ idx++; ++ } ++ } + +- if (X -> type == KeyPress) +- { +- nxagentDeactivateInputDevicesGrabs(); ++ map[idx].stroke = KEYSTROKE_END_MARKER; + } +- +- return 1; + } + ++ xmlFreeDoc(doc); ++ xmlCleanupParser(); ++ } ++ else ++ { ++ #ifdef DEBUG ++ fprintf("XML parsing for %s failed\n", filename); + #endif + } ++ free(filename); + } +- else if ((X -> state & nxagentAltMetaMask) && +- ((X -> state & (ControlMask | ShiftMask)) == (ControlMask | +- ShiftMask))) ++} ++ ++static enum nxagentSpecialKeystroke find_keystroke(XKeyEvent *X) ++{ ++ KeySym keysym = XKeycodeToKeysym(nxagentDisplay, X->keycode, 0); ++ struct nxagentSpecialKeystrokeMap *cur = map; ++ ++ if (! nxagentKeystrokeFileParsed) + { +- switch (sym) +- { +- case XK_f: +- case XK_F: +- { +- if (nxagentOption(Rootless) == 0) +- { +- *result = doSwitchFullscreen; +- } ++ parse_keystroke_file(); ++ nxagentKeystrokeFileParsed = True; ++ } + +- break; +- } +- case XK_Left: +- case XK_KP_Left: +- { +- if (nxagentOption(Rootless) == 0 && +- nxagentOption(DesktopResize) == 0) +- { +- *result = doViewportMoveLeft; +- } ++ enum nxagentSpecialKeystroke ret = KEYSTROKE_NOTHING; + +- break; +- } +- case XK_Up: +- case XK_KP_Up: +- { +- if (nxagentOption(Rootless) == 0 && +- nxagentOption(DesktopResize) == 0) +- { +- *result = doViewportMoveUp; +- } ++ while ((cur++)->stroke != KEYSTROKE_END_MARKER) { ++ if (cur->keysym == keysym && modifier_matches(cur->modifierMask, cur->modifierAltMeta, X->state)) { ++ return cur->stroke; ++ } ++ } + +- break; +- } +- case XK_Right: +- case XK_KP_Right: +- { +- if (nxagentOption(Rootless) == 0 && +- nxagentOption(DesktopResize) == 0) +- { +- *result = doViewportMoveRight; +- } ++ return ret; ++} + +- break; +- } +- case XK_Down: +- case XK_KP_Down: +- { +- if (nxagentOption(Rootless) == 0 && +- nxagentOption(DesktopResize) == 0) +- { +- *result = doViewportMoveDown; +- } ++int nxagentCheckSpecialKeystroke(XKeyEvent *X, enum HandleEventResult *result) ++{ ++ KeySym sym; ++ int index = 0; ++ enum nxagentSpecialKeystroke stroke = find_keystroke(X); + +- break; +- } +- } ++ *result = doNothing; ++ ++ /* ++ * I don't know how much hard work is doing this operation. ++ * Do we need a cache ? ++ */ ++ ++ sym = XKeycodeToKeysym(nxagentDisplay, X -> keycode, index); ++ ++ if (sym == XK_VoidSymbol || sym == NoSymbol) ++ { ++ return 0; + } + ++ #ifdef TEST ++ fprintf(stderr, "nxagentCheckSpecialKeystroke: got code %x - state %x - sym %lx\n", ++ X -> keycode, X -> state, sym); ++ #endif ++ ++ /* ++ * Check special keys. ++ */ ++ ++ /* ++ * FIXME: We should use the keysym instead that the keycode ++ * here. ++ */ ++ ++ if (X -> keycode == 130 && nxagentIpaq) ++ { ++ *result = doStartKbd; ++ ++ return 1; ++ } ++ ++ switch (stroke) { ++ case KEYSTROKE_DEBUG_TREE: ++ #ifdef DEBUG_TREE ++ *result = doDebugTree; ++ #endif ++ break; ++ case KEYSTROKE_CLOSE_SESSION: ++ *result = doCloseSession; ++ break; ++ case KEYSTROKE_SWITCH_ALL_SCREENS: ++ if (nxagentOption(Rootless) == False) { ++ *result = doSwitchAllScreens; ++ } ++ break; ++ case KEYSTROKE_MINIMIZE: ++ if (nxagentOption(Rootless) == False) { ++ *result = doMinimize; ++ } ++ break; ++ case KEYSTROKE_LEFT: ++ if (nxagentOption(Rootless) == False && ++ nxagentOption(DesktopResize) == False) { ++ *result = doViewportLeft; ++ } ++ break; ++ case KEYSTROKE_UP: ++ if (nxagentOption(Rootless) == False && ++ nxagentOption(DesktopResize) == False) { ++ *result = doViewportUp; ++ } ++ break; ++ case KEYSTROKE_RIGHT: ++ if (nxagentOption(Rootless) == False && ++ nxagentOption(DesktopResize) == False) { ++ *result = doViewportRight; ++ } ++ break; ++ case KEYSTROKE_DOWN: ++ if (nxagentOption(Rootless) == False && ++ nxagentOption(DesktopResize) == False) { ++ *result = doViewportDown; ++ } ++ break; ++ case KEYSTROKE_RESIZE: ++ if (nxagentOption(Rootless) == False) { ++ *result = doSwitchResizeMode; ++ } ++ break; ++ case KEYSTROKE_DEFER: ++ *result = doSwitchDeferMode; ++ break; ++ case KEYSTROKE_IGNORE: ++ /* this is used e.g. to ignore C-A-Backspace aka XK_Terminate_Server */ ++ return 1; ++ break; ++ case KEYSTROKE_FORCE_SYNCHRONIZATION: ++ nxagentForceSynchronization = 1; ++ break; ++ case KEYSTROKE_REGIONS_ON_SCREEN: ++ #ifdef DUMP ++ nxagentRegionsOnScreen(); ++ #endif ++ break; ++ case KEYSTROKE_TEST_INPUT: ++ /* ++ * Used to test the input devices state. ++ */ ++ #ifdef NX_DEBUG_INPUT ++ if (X -> type == KeyPress) { ++ if (nxagentDebugInputDevices == 0) { ++ fprintf(stderr, "Info: Turning input devices debug ON.\n"); ++ nxagentDebugInputDevices = 1; ++ } else { ++ fprintf(stderr, "Info: Turning input devices debug OFF.\n"); ++ nxagentDebugInputDevices = 0; ++ nxagentLastInputDevicesDumpTime = 0; ++ } ++ } ++ return 1; ++ #endif ++ break; ++ case KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB: ++ #ifdef NX_DEBUG_INPUT ++ if (X->type == KeyPress) { ++ nxagentDeactivateInputDevicesGrab(); ++ } ++ return 1; ++ #endif ++ break; ++ case KEYSTROKE_FULLSCREEN: ++ if (nxagentOption(Rootless) == 0) { ++ *result = doSwitchFullscreen; ++ } ++ break; ++ case KEYSTROKE_VIEWPORT_MOVE_LEFT: ++ if (nxagentOption(Rootless) == 0 && ++ nxagentOption(DesktopResize) == 0) { ++ *result = doViewportMoveLeft; ++ } ++ break; ++ case KEYSTROKE_VIEWPORT_MOVE_UP: ++ if (nxagentOption(Rootless) == 0 && ++ nxagentOption(DesktopResize) == 0) { ++ *result = doViewportMoveUp; ++ } ++ break; ++ case KEYSTROKE_VIEWPORT_MOVE_RIGHT: ++ if (nxagentOption(Rootless) == 0 && ++ nxagentOption(DesktopResize) == 0) { ++ *result = doViewportMoveRight; ++ } ++ break; ++ case KEYSTROKE_VIEWPORT_MOVE_DOWN: ++ if (nxagentOption(Rootless) == 0 && ++ nxagentOption(DesktopResize) == 0) { ++ *result = doViewportMoveDown; ++ } ++ break; ++ case KEYSTROKE_NOTHING: /* do nothing. difference to KEYSTROKE_IGNORE is the return value */ ++ case KEYSTROKE_END_MARKER: /* just to make gcc STFU */ ++ case KEYSTROKE_MAX: ++ break; ++ } + return (*result == doNothing) ? 0 : 1; + } +--- a/nx-X11/programs/Xserver/hw/nxagent/Keystroke.h ++++ b/nx-X11/programs/Xserver/hw/nxagent/Keystroke.h +@@ -24,4 +24,51 @@ + + unsigned int nxagentAltMetaMask; + ++/* keep this sorted, do not rely on any numerical value in this enum, and be aware ++ * that KEYSTROKE_MAX may be used in a malloc */ ++ ++/* also be aware that if changing any numerical values, you also need to change values ++ * Keystroke.c nxagentSpecialKeystrokeNames */ ++enum nxagentSpecialKeystroke { ++ /* 0 is used as end marker */ ++ KEYSTROKE_END_MARKER = 0, ++ KEYSTROKE_CLOSE_SESSION = 1, ++ KEYSTROKE_SWITCH_ALL_SCREENS = 2, ++ KEYSTROKE_MINIMIZE = 3, ++ KEYSTROKE_LEFT = 4, ++ KEYSTROKE_UP = 5, ++ KEYSTROKE_RIGHT = 6, ++ KEYSTROKE_DOWN = 7, ++ KEYSTROKE_RESIZE = 8, ++ KEYSTROKE_DEFER = 9, ++ KEYSTROKE_IGNORE = 10, ++ KEYSTROKE_FORCE_SYNCHRONIZATION = 11, ++ ++ /* stuff used for debugging, probably not useful for most people */ ++ KEYSTROKE_DEBUG_TREE = 12, ++ KEYSTROKE_REGIONS_ON_SCREEN = 13, ++ KEYSTROKE_TEST_INPUT = 14, ++ KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB = 15, ++ ++ KEYSTROKE_FULLSCREEN = 16, ++ KEYSTROKE_VIEWPORT_MOVE_LEFT = 17, ++ KEYSTROKE_VIEWPORT_MOVE_UP = 18, ++ KEYSTROKE_VIEWPORT_MOVE_RIGHT = 19, ++ KEYSTROKE_VIEWPORT_MOVE_DOWN = 20, ++ ++ KEYSTROKE_NOTHING = 21, ++ ++ /* insert more here, increment KEYSTROKE_MAX accordingly. ++ * then update string translation below */ ++ ++ KEYSTROKE_MAX=22, ++}; ++ ++struct nxagentSpecialKeystrokeMap { ++ enum nxagentSpecialKeystroke stroke; ++ unsigned int modifierMask; /* everything except alt/meta */ ++ int modifierAltMeta; /* modifier combination should include alt/meta */ ++ KeySym keysym; ++}; ++ + #endif /* __Keystroke_H__ */ +--- /dev/null ++++ b/README.keystrokes +@@ -0,0 +1,83 @@ ++Configurable keybindings in nxagent ++ ++Keybindings in the redistributed x2go version of nxagent can now be configured ++by the user. This is done via a configuration file. ++ ++File location ++------------- ++ ++nxagent searches for the configuration file in the following order: ++- in the location given by the '-keystrokefile' command line parameter ++- in the location given by the NXAGENT_KEYSTROKEFILE environment variable ++- in ~/.nx/config/keystroke.cfg ++- in /etc/nxagent/keystroke.cfg ++ ++If none of those files is accessible, the default configuration is used which ++is the same as the old, traditional nxagent keybindings. ++ ++File format ++----------- ++ ++The configuration file is XML with the following format: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++Each 'action' defines an action to be executed when receiving that keystroke. A ++list of possible actions is given below. Some of those actions are only ++available with debug builds of nxagent. ++ ++Keys are given as a combination of 'key' and (optionally) a number of ++modifiers. The key attribute is evaluated into a X11 key via the usual ++XStringToKeysym function. A list of possible keys can be found in ++/usr/include/X11/keysymdef.h, the names are specified without the leading ++'XK_'. Evaluation is case-sensitive, so, 'space' and 'Escape' will work while ++'Space' and 'escape' won't. ++ ++Modifiers are given as boolean attributes, possible modifiers are Mod1, Mod2, ++Mod3, Mod4, Control, Shift, Lock. Sensible combinations strongly depend on your ++keyboard configuration, but usually you will need Mod1 and Control. Boolean in ++this context means '0', 'false' and an unspecified attribute are false, anything ++else is considered true. ++ ++Everything in this file is case-sensitive. Unknown lines are ignored. ++Keybindings are evaluated from top to bottom, so if a keybinding matches, other ++keybindings further down will be ignored. The contents of the file replaces the ++default keybindings, and only one file is read, no merging between different ++configuration files is done. This also means that an empty or invalid configuration ++file deactivates all keybindings. ++ ++List of possible 'action' attributes: ++------------------------------------- ++ ++close_session ++switch_all_screens ++minimize ++left ++up ++right ++down ++resize ++defer ++ignore ++fullscreen ++viewport_move_left ++viewport_move_up ++viewport_move_right ++viewport_move_down ++ ++Only in builds with certain debugging options enabled, ignored otherwise: ++force_synchronization ++debug_tree ++regions_on_screen ++test_input ++deactivate_input_devices_grab +--- a/nx-X11/programs/Xserver/hw/nxagent/Args.c ++++ b/nx-X11/programs/Xserver/hw/nxagent/Args.c +@@ -148,6 +148,8 @@ + + char nxagentVerbose = 0; + ++char *nxagentKeystrokeFile = NULL; ++ + int ddxProcessArgument(int argc, char *argv[], int i) + { + /* +@@ -1021,6 +1023,20 @@ + return 1; + } + ++ if (!strcmp(argv[i], "-keystrokefile")) ++ { ++ if (i + 1 < argc) ++ { ++ if (NULL != (nxagentKeystrokeFile = strdup(argv[i + 1]))) ++ { ++ return 2; ++ } else { ++ FatalError("malloc failed"); ++ } ++ } ++ return 0; ++ } ++ + return 0; + } + +--- a/nx-X11/programs/Xserver/hw/nxagent/Args.h ++++ b/nx-X11/programs/Xserver/hw/nxagent/Args.h +@@ -83,4 +83,6 @@ + + extern int nxagentRemoteMajor; + ++extern char *nxagentKeystrokeFile; ++ + #endif /* __Args_H__ */ + diff --git a/debian/patches/series b/debian/patches/series index ce5237ffd..592bcddbd 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -44,7 +44,8 @@ 220_nxproxy-bind-loopback-only.full+lite.patch 300_nxagent_set-wm-class.full.patch 301_nx-X11_use-shared-libs.full.patch -302_nxagent_configurable-keystrokes.full.patch +302_nx-X11_do-not-build-bundled-libs.full.patch +320_nxagent_configurable-keystrokes.full.patch 600_nx-X11+nxcompext+nxcompshad_unique-libnames.full.patch 601_nx-X11_build-option-changes-to-not-use-bundled-libraries.full.patch 602_nx-X11_initgroups.full.patch -- cgit v1.2.3