diff --git a/doc/nxagent/README.keystrokes b/doc/nxagent/README.keystrokes
index 750a460ebd..32974cbca6 100644
--- a/doc/nxagent/README.keystrokes
+++ b/doc/nxagent/README.keystrokes
@@ -126,6 +126,12 @@ reread_keystrokes
Forces nxagent to re-read the keystroke configuration. Useful to
add/change keystrokes to a running session.
+autograb
+ Toggles autograb mode
+
+lockinput
+ Locks/unlocsk pointer within nxagent window
+
force_synchronization
Forces immediate drawing of elements to be synchronized which can
fix some visual bugs.
diff --git a/etc/keystrokes.cfg b/etc/keystrokes.cfg
index 8563698392..2cb242641d 100644
--- a/etc/keystrokes.cfg
+++ b/etc/keystrokes.cfg
@@ -24,4 +24,6 @@
+
+
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Args.c b/nx-X11/programs/Xserver/hw/nxagent/Args.c
index 161403cd0a..7ecd363402 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Args.c
+++ b/nx-X11/programs/Xserver/hw/nxagent/Args.c
@@ -1041,6 +1041,21 @@ int ddxProcessArgument(int argc, char *argv[], int i)
return 0;
}
+ if (!strcmp(argv[i], "-autograb"))
+ {
+ nxagentChangeOption(AutoGrab, True);
+
+ return 1;
+ }
+
+ if (!strcmp(argv[i], "-inputlock"))
+ {
+ nxagentChangeOption(InputLock, True);
+
+ return 1;
+ }
+
+
/*
* Disable Xinerama (i.e. fake it in Screen.c) if somehow Xinerama support
* has been disabled on the cmdline.
@@ -1541,6 +1556,32 @@ static void nxagentParseSingleOption(char *name, char *value)
return;
}
+ else if (!strcmp(name, "autograb"))
+ {
+ if (!strcmp(value, "0"))
+ {
+ nxagentChangeOption(AutoGrab, False);
+ }
+ else
+ {
+ nxagentChangeOption(AutoGrab, True);
+ }
+
+ return;
+ }
+ else if (!strcmp(name, "inputlock"))
+ {
+ if (!strcmp(value, "0"))
+ {
+ nxagentChangeOption(InputLock, False);
+ }
+ else
+ {
+ nxagentChangeOption(InputLock, True);
+ }
+
+ return;
+ }
else
{
#ifdef DEBUG
@@ -2197,6 +2238,8 @@ void ddxUseMsg(void)
ErrorF("-noignore don't ignore pointer and keyboard configuration changes mandated by clients\n");
ErrorF("-nokbreset don't reset keyboard device if the session is resumed\n");
ErrorF("-noxkblock always allow applications to change layout through XKEYBOARD\n");
+ ErrorF("-autograb enable autograb\n");
+ ErrorF("-inputlock enable inputlock\n");
ErrorF("-tile WxH size of image tiles (minimum allowed: 32x32)\n");
ErrorF("-keystrokefile file file with keyboard shortcut definitions\n");
ErrorF("-verbose print more warning and error messages\n");
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Events.c b/nx-X11/programs/Xserver/hw/nxagent/Events.c
index d8bf4df60e..608b0e12e2 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Events.c
+++ b/nx-X11/programs/Xserver/hw/nxagent/Events.c
@@ -78,6 +78,8 @@
#undef Atom
#undef Time
+#include
+
#ifdef NXAGENT_FIXKEYS
#include "inputstr.h"
#include "input.h"
@@ -293,6 +295,36 @@ void ProcessInputEvents(void)
mieqProcessInputEvents();
}
+#ifdef DEBUG
+char * nxagentGetNotifyMode(int mode)
+{
+ switch (mode)
+ {
+ case NotifyNormal:
+ {
+ return "NotifyNormal";
+ break;
+ }
+ case NotifyGrab:
+ {
+ return "NotifyGrab";
+ break;
+ }
+ case NotifyUngrab:
+ {
+ return "NotifyUngrab";
+ break;
+ }
+ case NotifyWhileGrabbed:
+ {
+ return "NotifyWhileGrabbed";
+ break;
+ }
+ }
+ return "Unknown";
+}
+#endif
+
#ifdef DEBUG_TREE
/*
@@ -678,6 +710,157 @@ static void nxagentSwitchDeferMode(void)
}
}
+enum {WINDOWSUFFIX_AUTOGRAB = 0, WINDOWSUFFIX_INPUTLOCK, WINDOWSUFFIX_MAX};
+
+static char * nxagentWindowSuffixes[WINDOWSUFFIX_MAX] = {NULL};
+
+void setWinNameSuffix(int index, const char *suffix)
+{
+ if (index < 0 || index >= WINDOWSUFFIX_MAX)
+ return;
+
+ if (nxagentWindowSuffixes[index])
+ {
+ free(nxagentWindowSuffixes[index]);
+ nxagentWindowSuffixes[index] = NULL;
+ }
+
+ if (suffix)
+ nxagentWindowSuffixes[index] = strdup(suffix);
+}
+
+void updateWinName()
+{
+ static const char * pre = " (";
+ static const char * post = ")";
+ static const char * comma = ", ";
+ char * newname;
+
+ int len = strlen(nxagentWindowName) + 1;
+ int count = 0;
+ for (int i = 0; i < WINDOWSUFFIX_MAX; i++)
+ {
+ if (nxagentWindowSuffixes[i])
+ {
+ if (count)
+ len += strlen(comma);
+ len += strlen(nxagentWindowSuffixes[i]);
+ count++;
+ }
+ }
+
+ if (count)
+ len += strlen(pre) + strlen(post);
+
+ if (!(newname = calloc(len, sizeof(char))))
+ {
+ fprintf(stderr, "%s: malloc failed", __func__);
+ return;
+ }
+
+ strncpy(newname, nxagentWindowName, len);
+
+ if (count)
+ strncat(newname, pre, len);
+
+ int first = True;
+ for (int i = 0; i < WINDOWSUFFIX_MAX; i++)
+ {
+ if (nxagentWindowSuffixes[i])
+ {
+ if (!first)
+ strncat(newname, comma, len);
+ strncat(newname, nxagentWindowSuffixes[i], len);
+ first = False;
+ }
+ }
+
+ if (count)
+ strncat(newname, post, len);
+
+ XStoreName(nxagentDisplay, nxagentDefaultWindows[0], newname);
+ free(newname);
+}
+
+static void nxagentEnableAutoGrab(void)
+{
+#ifdef DEBUG
+ fprintf(stderr, "enabling autograb\n");
+#endif
+
+ nxagentGrabPointerAndKeyboard(NULL);
+ setWinNameSuffix(WINDOWSUFFIX_AUTOGRAB, "autograb on");
+ updateWinName();
+ nxagentChangeOption(AutoGrab, True);
+}
+
+static void nxagentDisableAutoGrab(void)
+{
+#ifdef DEBUG
+ fprintf(stderr, "disabling autograb\n");
+#endif
+
+ nxagentUngrabPointerAndKeyboard(NULL);
+ setWinNameSuffix(WINDOWSUFFIX_AUTOGRAB, NULL);
+ updateWinName();
+ nxagentChangeOption(AutoGrab, False);
+}
+
+static void nxagentToggleAutoGrab(void)
+{
+ /* autograb only works in windowed mode */
+ if (nxagentOption(Rootless) || nxagentOption(Fullscreen))
+ return;
+
+ if (!nxagentOption(InputLock))
+ {
+ if (!nxagentOption(AutoGrab))
+ nxagentEnableAutoGrab();
+ else
+ nxagentDisableAutoGrab();
+ }
+}
+
+static void nxagentEnableInputlock(void)
+{
+#ifdef DEBUG
+ fprintf(stderr, "activating inputlock\n");
+#endif
+ setWinNameSuffix(WINDOWSUFFIX_INPUTLOCK, "inputlock on");
+ updateWinName();
+ XGrabPointer(nxagentDisplay,nxagentDefaultWindows[0], True,
+ ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask | EnterWindowMask | LeaveWindowMask,
+ GrabModeAsync, GrabModeAsync, nxagentDefaultWindows[0], None, CurrentTime);
+ nxagentChangeOption(InputLock, True);
+}
+
+static void nxagentDisableInputlock(void)
+{
+#ifdef DEBUG
+ fprintf(stderr, "deactivating inputlock\n");
+#endif
+ nxagentUngrabPointerAndKeyboard(NULL);
+ /* XTextProperty name = {
+ .value = (unsigned char *)nxagentWindowName,
+ .encoding = XA_STRING,
+ .format = 8,
+ .nitems = strlen((char *) name.value)
+ };
+ */
+ setWinNameSuffix(WINDOWSUFFIX_INPUTLOCK, NULL);
+ updateWinName();
+ nxagentChangeOption(InputLock, False);
+}
+
+/* TODO: drop inputlock when switching to Fullscreen */
+static void nxagentToggleInputLock(void)
+{
+ if (!nxagentOption(InputLock))
+ nxagentEnableInputlock();
+ else
+ nxagentDisableInputlock();
+}
+
static Bool nxagentExposurePredicate(Display *display, XEvent *event, XPointer window)
{
/*
@@ -1064,6 +1247,18 @@ void nxagentDispatchEvents(PredicateFuncPtr predicate)
break;
}
+ case doAutoGrab:
+ {
+ nxagentToggleAutoGrab();
+
+ break;
+ }
+ case doInputLock:
+ {
+ nxagentToggleInputLock();
+
+ break;
+ }
default:
{
FatalError("nxagentDispatchEvent: handleKeyPress returned unknown value\n");
@@ -1481,8 +1676,18 @@ FIXME: Don't enqueue the KeyRelease event if the key was
{
WindowPtr pWin;
- #ifdef TEST
- fprintf(stderr, "nxagentDispatchEvents: Going to handle new FocusIn event.\n");
+ #ifdef DEBUG
+ fprintf(stderr, "%s: Going to handle new FocusIn event [0x%x] mode: [%s]\n", __func__, X.xfocus.window, nxagentGetNotifyMode(X.xfocus.mode));
+ {
+ XlibWindow w;
+ int revert_to;
+ XGetInputFocus(nxagentDisplay, &w, &revert_to);
+ fprintf(stderr, "%s: (FocusIn): Event win [0x%x] Focus owner [0x%x] nxagentDefaultWindows[0] [0x%x]\n", __func__, X.xfocus.window, w, nxagentDefaultWindows[0]);
+ }
+ #else
+ #ifdef TEST
+ fprintf(stderr, "%s: Going to handle new FocusIn event\n", __func__);
+ #endif
#endif
/*
@@ -1508,12 +1713,34 @@ FIXME: Don't enqueue the KeyRelease event if the key was
}
}
+ if (nxagentOption(AutoGrab) && !(nxagentOption(AllScreens) || nxagentOption(Fullscreen) || nxagentOption(Rootless)))
+ {
+ if (X.xfocus.window == nxagentDefaultWindows[0] && X.xfocus.mode == NotifyNormal)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "%s: (FocusIn): grabbing\n", __func__);
+ #endif
+ nxagentGrabPointerAndKeyboard(NULL);
+ }
+ /* else
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "%s: (FocusIn): ungrabbing\n", __func__);
+ #endif
+ nxagentUngrabPointerAndKeyboard(NULL);
+ }
+ */
+ }
break;
}
case FocusOut:
{
- #ifdef TEST
- fprintf(stderr, "nxagentDispatchEvents: Going to handle new FocusOut event.\n");
+ #ifdef DEBUG
+ fprintf(stderr, "%s: Going to handle new FocusOut event [0x%x] mode: [%s]\n", __func__, X.xfocus.window, nxagentGetNotifyMode(X.xfocus.mode));
+ #else
+ #ifdef TEST
+ fprintf(stderr, "%s: Going to handle new FocusOut event.\n", __func__);
+ #endif
#endif
if (X.xfocus.detail != NotifyInferior)
@@ -1586,6 +1813,19 @@ FIXME: Don't enqueue the KeyRelease event if the key was
#endif /* NXAGENT_FIXKEYS */
+ if (nxagentOption(AutoGrab))
+ {
+ XlibWindow w;
+ int revert_to;
+ XGetInputFocus(nxagentDisplay, &w, &revert_to);
+ if (w != nxagentDefaultWindows[0] && X.xfocus.mode == NotifyWhileGrabbed)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "%s: (FocusOut): ungrabbing\n", __func__);
+ #endif
+ nxagentUngrabPointerAndKeyboard(NULL);
+ }
+ }
break;
}
case KeymapNotify:
@@ -1721,11 +1961,14 @@ FIXME: Don't enqueue the KeyRelease event if the key was
nxagentLastEnteredWindow = NULL;
}
- if (X.xcrossing.window == nxagentDefaultWindows[0] &&
- X.xcrossing.detail != NotifyInferior &&
- X.xcrossing.mode == NotifyNormal)
+ if (!nxagentOption(AutoGrab))
{
- nxagentUngrabPointerAndKeyboard(&X);
+ if (X.xcrossing.window == nxagentDefaultWindows[0] &&
+ X.xcrossing.detail != NotifyInferior &&
+ X.xcrossing.mode == NotifyNormal)
+ {
+ nxagentUngrabPointerAndKeyboard(&X);
+ }
}
if (X.xcrossing.detail != NotifyInferior)
@@ -3844,13 +4087,26 @@ void nxagentGrabPointerAndKeyboard(XEvent *X)
fprintf(stderr, "nxagentGrabPointerAndKeyboard: Going to grab the keyboard in context [B1].\n");
#endif
- result = XGrabKeyboard(nxagentDisplay, nxagentFullscreenWindow,
- True, GrabModeAsync, GrabModeAsync, now);
+ if (nxagentFullscreenWindow)
+ result = XGrabKeyboard(nxagentDisplay, nxagentFullscreenWindow,
+ True, GrabModeAsync, GrabModeAsync, now);
+ else
+ result = XGrabKeyboard(nxagentDisplay, RootWindow(nxagentDisplay, DefaultScreen(nxagentDisplay)),
+ True, GrabModeAsync, GrabModeAsync, now);
if (result != GrabSuccess)
{
+ #ifdef DEBUG
+ fprintf(stderr, "%s: keyboard grab failed.\n", __func__);
+ #endif
return;
}
+ #ifdef DEBUG
+ else
+ {
+ fprintf(stderr, "%s: keyboard grab successful.\n", __func__);
+ }
+ #endif
/*
* The smart scheduler could be stopped while
@@ -3868,7 +4124,8 @@ void nxagentGrabPointerAndKeyboard(XEvent *X)
resource = nxagentWaitForResource(NXGetCollectGrabPointerResource,
nxagentCollectGrabPointerPredicate);
- NXCollectGrabPointer(nxagentDisplay, resource,
+ if (nxagentFullscreenWindow)
+ NXCollectGrabPointer(nxagentDisplay, resource,
nxagentFullscreenWindow, True, NXAGENT_POINTER_EVENT_MASK,
GrabModeAsync, GrabModeAsync, None, None, now);
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Events.h b/nx-X11/programs/Xserver/hw/nxagent/Events.h
index 5df0e1f05c..3c5623ca16 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Events.h
+++ b/nx-X11/programs/Xserver/hw/nxagent/Events.h
@@ -50,7 +50,9 @@ enum HandleEventResult
doViewportRight,
doViewportDown,
doSwitchResizeMode,
- doSwitchDeferMode
+ doSwitchDeferMode,
+ doAutoGrab,
+ doInputLock
};
extern CARD32 nxagentLastEventTime;
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Keystroke.c b/nx-X11/programs/Xserver/hw/nxagent/Keystroke.c
index 662da6b04d..19f829c8e0 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Keystroke.c
+++ b/nx-X11/programs/Xserver/hw/nxagent/Keystroke.c
@@ -99,6 +99,10 @@ char * nxagentSpecialKeystrokeNames[] = {
"viewport_scroll_down",
"reread_keystrokes",
+
+ "autograb",
+ "inputlock",
+
NULL,
};
@@ -138,6 +142,8 @@ struct nxagentSpecialKeystrokeMap default_map[] = {
{KEYSTROKE_VIEWPORT_SCROLL_DOWN, ControlMask, True, XK_Down},
{KEYSTROKE_VIEWPORT_SCROLL_DOWN, ControlMask, True, XK_KP_Down},
{KEYSTROKE_REREAD_KEYSTROKES, ControlMask, True, XK_k},
+ {KEYSTROKE_AUTOGRAB, ControlMask, True, XK_g},
+ {KEYSTROKE_INPUTLOCK, ControlMask, True, XK_c},
{KEYSTROKE_END_MARKER, 0, False, NoSymbol},
};
struct nxagentSpecialKeystrokeMap *map = default_map;
@@ -467,7 +473,7 @@ static enum nxagentSpecialKeystroke find_keystroke(XKeyEvent *X)
#endif
for (struct nxagentSpecialKeystrokeMap *cur = map; cur->stroke != KEYSTROKE_END_MARKER; cur++) {
#ifdef DEBUG
- fprintf(stderr, "%s: checking keysym '%c' (%d)\n", __func__, cur->keysym, cur->keysym);
+ fprintf(stderr,"%s: keysym %d stroke %d, type %d\n", __func__, cur->keysym, cur->stroke, X->type);
#endif
if (cur->keysym == keysym && modifier_matches(cur->modifierMask, cur->modifierAltMeta, X->state)) {
#ifdef DEBUG
@@ -624,6 +630,12 @@ Bool nxagentCheckSpecialKeystroke(XKeyEvent *X, enum HandleEventResult *result)
if (X->type == KeyRelease)
nxagentInitKeystrokes(True);
break;
+ case KEYSTROKE_AUTOGRAB:
+ *result = doAutoGrab;
+ break;
+ case KEYSTROKE_INPUTLOCK:
+ *result = doInputLock;
+ 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:
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Keystroke.h b/nx-X11/programs/Xserver/hw/nxagent/Keystroke.h
index 13a83d0fea..73d29bbda2 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Keystroke.h
+++ b/nx-X11/programs/Xserver/hw/nxagent/Keystroke.h
@@ -73,6 +73,9 @@ enum nxagentSpecialKeystroke {
KEYSTROKE_REREAD_KEYSTROKES,
+ KEYSTROKE_AUTOGRAB,
+ KEYSTROKE_INPUTLOCK,
+
KEYSTROKE_NOTHING,
/* insert more here and in the string translation */
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Options.c b/nx-X11/programs/Xserver/hw/nxagent/Options.c
index c06967c76e..ad229e042f 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Options.c
+++ b/nx-X11/programs/Xserver/hw/nxagent/Options.c
@@ -172,6 +172,10 @@ void nxagentInitOptions(void)
nxagentOptions.ReconnectTolerance = DEFAULT_TOLERANCE;
nxagentOptions.KeycodeConversion = DEFAULT_KEYCODE_CONVERSION;
+
+ nxagentOptions.AutoGrab = False;
+
+ nxagentOptions.InputLock = False;
}
/*
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Options.h b/nx-X11/programs/Xserver/hw/nxagent/Options.h
index b5394ee016..764a28b82d 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/Options.h
+++ b/nx-X11/programs/Xserver/hw/nxagent/Options.h
@@ -450,6 +450,18 @@ typedef struct _AgentOptions
* Convert evdev keycodes to pc105.
*/
KeycodeConversionMode KeycodeConversion;
+
+ /*
+ * True if agent should grab the input in windowed mode whenever the
+ * agent window gets the focus
+ */
+ int AutoGrab; /* Should be Bool but I do not want to include Xlib.h here */
+
+ /*
+ * True if the pointer is locked within the agent window (in windowed mode)
+ */
+ int InputLock; /* Should be Bool but I do not want to include Xlib.h here */
+
} AgentOptionsRec;
typedef AgentOptionsRec *AgentOptionsPtr;
diff --git a/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1 b/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1
index 6804032a22..2ee5c1bfa0 100644
--- a/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1
+++ b/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1
@@ -751,6 +751,13 @@ format must be included in both. This is potentially unsafe.
means that all of these checks are essentially
deactivated. This is a very bad idea.
.RE
+.TP 8
+.B autograb=
+enable or disable autograb (default: disabled)
+.TP 8
+.B inputlock=
+enable or disable inputlock (default: disabled)
+.RE
If you want to use \fBnxagent\fR as a replacement for Xnest or Xephyr you
can pass options like this: