aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/programs/Xserver/hw/nxagent/Events.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/programs/Xserver/hw/nxagent/Events.c')
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/Events.c3822
1 files changed, 3822 insertions, 0 deletions
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Events.c b/nx-X11/programs/Xserver/hw/nxagent/Events.c
new file mode 100644
index 000000000..e1eab6fd2
--- /dev/null
+++ b/nx-X11/programs/Xserver/hw/nxagent/Events.c
@@ -0,0 +1,3822 @@
+/**************************************************************************/
+/* */
+/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */
+/* */
+/* NXAGENT, NX protocol compression and NX extensions to this software */
+/* are copyright of NoMachine. Redistribution and use of the present */
+/* software is allowed according to terms specified in the file LICENSE */
+/* which comes in the source distribution. */
+/* */
+/* Check http://www.nomachine.com/licensing.html for applicability. */
+/* */
+/* NX and NoMachine are trademarks of NoMachine S.r.l. */
+/* */
+/* All rights reserved. */
+/* */
+/**************************************************************************/
+
+#include "X.h"
+#include "signal.h"
+#include "unistd.h"
+#define NEED_EVENTS
+#include "Xproto.h"
+#include "screenint.h"
+#include "input.h"
+#include "misc.h"
+#include "scrnintstr.h"
+#include "windowstr.h"
+#include "servermd.h"
+#include "mi.h"
+#include "selection.h"
+#include "keysym.h"
+#include "fb.h"
+#include "mibstorest.h"
+#include "osdep.h"
+
+#include "Agent.h"
+#include "Args.h"
+#include "Atoms.h"
+#include "Colormap.h"
+#include "Display.h"
+#include "Screen.h"
+#include "Windows.h"
+#include "Pixmaps.h"
+#include "Keyboard.h"
+#include "Keystroke.h"
+#include "Events.h"
+#include "Pointer.h"
+#include "Rootless.h"
+#include "Splash.h"
+#include "Trap.h"
+#include "Dialog.h"
+#include "Client.h"
+#include "Clipboard.h"
+#include "Split.h"
+#include "Drawable.h"
+#include "Handlers.h"
+#include "Utils.h"
+
+#include "NX.h"
+#include "NXvars.h"
+#include "NXproto.h"
+
+#ifdef NXAGENT_FIXKEYS
+#include "inputstr.h"
+#include "input.h"
+#endif
+
+#include "XKBlib.h"
+
+#define GC XlibGC
+#define Font XlibFont
+#define KeySym XlibKeySym
+#define XID XlibXID
+#include "Xlibint.h"
+#undef GC
+#undef Font
+#undef KeySym
+#undef XID
+
+#include <X11/cursorfont.h>
+
+#include "Shadow.h"
+#include "Xrandr.h"
+
+#include "NXlib.h"
+
+/*
+ * Set here the required log level. Please note
+ * that if you want to enable DEBUG here, then
+ * you need to enable DEBUG even in Rootless.c
+ */
+
+#define PANIC
+#define WARNING
+#undef TEST
+#undef DEBUG
+
+/*
+ * Log begin and end of the important handlers.
+ */
+
+#undef BLOCKS
+
+extern Bool nxagentOnce;
+
+extern WindowPtr nxagentRootTileWindow;
+extern int nxagentSplashCount;
+
+extern int nxagentLastClipboardClient;
+
+#ifdef DEBUG
+extern Bool nxagentRootlessTreesMatch(void);
+#endif
+
+Bool xkbdRunning = False;
+pid_t pidkbd;
+
+WindowPtr nxagentLastEnteredWindow = NULL;
+
+PropertyRequestRec nxagentPropertyRequests[NXNumberOfResources];
+
+void nxagentHandleCollectPropertyEvent(XEvent*);
+
+/*
+ * Finalize the asynchronous handling
+ * of the X_GrabPointer requests.
+ */
+
+void nxagentHandleCollectGrabPointerEvent(int resource);
+
+Bool nxagentCollectGrabPointerPredicate(Display *display, XEvent *X, XPointer ptr);
+
+/*
+ * Used in Handlers.c to synchronize
+ * the agent with the remote X server.
+ */
+
+void nxagentHandleCollectInputFocusEvent(int resource);
+
+/*
+ * Viewport navigation.
+ */
+
+static int viewportInc = 1;
+static enum HandleEventResult viewportLastKeyPressResult;
+static int viewportLastX;
+static int viewportLastY;
+static Cursor viewportCursor;
+
+/*
+ * Keyboard and pointer are handled as they were real devices by
+ * Xnest and we inherit this behaviour. The following mask will
+ * contain the event mask selected for the root window of the
+ * agent. All the keyboard and pointer events will be translated
+ * by the agent and sent to the internal clients according to
+ * events selected by the inferior windows.
+ */
+
+static Mask defaultEventMask;
+
+#define MAX_INC 200
+#define INC_STEP 5
+#define nextinc(x) ((x) < MAX_INC ? (x) += INC_STEP : (x))
+
+/*
+ * Used to mask the appropriate bits in
+ * the state reported by XkbStateNotify
+ * and XkbGetIndicatorState.
+ */
+
+#define CAPSFLAG_IN_REPLY 1
+#define CAPSFLAG_IN_EVENT 2
+#define NUMFLAG_IN_EVENT 16
+#define NUMFLAG_IN_REPLY 2
+
+CARD32 nxagentLastEventTime = 0;
+CARD32 nxagentLastKeyPressTime = 0;
+Time nxagentLastServerTime = 0;
+
+/*
+ * Used for storing windows that need to
+ * receive expose events from the agent.
+ */
+
+#define nxagentExposeQueueHead nxagentExposeQueue.exposures[nxagentExposeQueue.start]
+
+ExposeQueue nxagentExposeQueue;
+
+RegionPtr nxagentRemoteExposeRegion = NULL;
+
+static void nxagentForwardRemoteExpose(void);
+
+static int nxagentClipAndSendExpose(WindowPtr pWin, pointer ptr);
+
+/*
+ * Associate a resource to a drawable and
+ * store the region affected by the split
+ * operation.
+ */
+
+SplitResourceRec nxagentSplitResources[NXNumberOfResources];
+
+/*
+ * Associate a resource to an unpack
+ * operation.
+ */
+
+UnpackResourceRec nxagentUnpackResources[NXNumberOfResources];
+
+/*
+ * We have to check these before launching
+ * the terminate dialog in rootless mode.
+ */
+
+Bool nxagentLastWindowDestroyed = False;
+Time nxagentLastWindowDestroyedTime = 0;
+
+/*
+ * Set this flag when an user input event
+ * is received.
+ */
+
+int nxagentInputEvent = 0;
+
+int nxagentKeyDown = 0;
+
+void nxagentSwitchResizeMode(ScreenPtr pScreen);
+
+int nxagentCheckWindowConfiguration(XConfigureEvent* X);
+
+#define nxagentMonitoredDuplicate(keysym) \
+ ((keysym) == XK_Left || (keysym) == XK_Up || \
+ (keysym) == XK_Right || (keysym) == XK_Down || \
+ (keysym) == XK_Page_Up || (keysym) == XK_Page_Down || \
+ (keysym) == XK_Delete || (keysym) == XK_BackSpace)
+
+void nxagentRemoveDuplicatedKeys(XEvent *X);
+
+void ProcessInputEvents()
+{
+ mieqProcessInputEvents();
+}
+
+void nxagentSwitchResizeMode(ScreenPtr pScreen)
+{
+ XSizeHints sizeHints;
+
+ int desktopResize = nxagentOption(DesktopResize);
+
+ nxagentChangeOption(DesktopResize, !desktopResize);
+
+ sizeHints.flags = PMaxSize;
+
+ if (nxagentOption(DesktopResize) == 0)
+ {
+ fprintf(stderr,"Info: Disabled desktop resize mode in agent.\n");
+
+ nxagentLaunchDialog(DIALOG_DISABLE_DESKTOP_RESIZE_MODE);
+
+ sizeHints.max_width = nxagentOption(RootWidth);
+ sizeHints.max_height = nxagentOption(RootHeight);
+ }
+ else
+ {
+ fprintf(stderr,"Info: Enabled desktop resize mode in agent.\n");
+
+ nxagentLaunchDialog(DIALOG_ENABLE_DESKTOP_RESIZE_MODE);
+
+ nxagentRRSetScreenConfig(pScreen, nxagentOption(Width), nxagentOption(Height));
+
+ sizeHints.max_width = WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay));
+ sizeHints.max_height = HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay));
+ }
+
+ XSetWMNormalHints(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum],
+ &sizeHints);
+}
+
+void nxagentShadowSwitchResizeMode(ScreenPtr pScreen)
+{
+ XSizeHints sizeHints;
+
+ int desktopResize = nxagentOption(DesktopResize);
+
+ nxagentChangeOption(DesktopResize, !desktopResize);
+
+ sizeHints.flags = PMaxSize;
+
+ if (nxagentOption(DesktopResize) == 0)
+ {
+ nxagentShadowSetRatio(1.0, 1.0);
+
+ nxagentShadowCreateMainWindow(screenInfo.screens[DefaultScreen(nxagentDisplay)], WindowTable[0],
+ WindowTable[0] -> drawable.width, WindowTable[0] -> drawable.height);
+
+ sizeHints.max_width = nxagentOption(RootWidth);
+ sizeHints.max_height = nxagentOption(RootHeight);
+
+ fprintf(stderr,"Info: Disabled resize mode in shadow agent.\n");
+ }
+ else
+ {
+ nxagentShadowSetRatio(nxagentOption(Width) * 1.0 /
+ WindowTable[0] -> drawable.width,
+ nxagentOption(Height) * 1.0 /
+ WindowTable[0] -> drawable.height);
+
+ nxagentShadowCreateMainWindow(screenInfo.screens[DefaultScreen(nxagentDisplay)],
+ WindowTable[0], WindowTable[0] -> drawable.width,
+ WindowTable[0] -> drawable.height);
+
+ sizeHints.max_width = WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay));
+ sizeHints.max_height = HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay));
+
+ fprintf(stderr,"Info: Enabled resize mode in shadow agent.\n");
+ }
+
+ XSetWMNormalHints(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum],
+ &sizeHints);
+}
+
+static void nxagentSwitchDeferMode(void)
+{
+ if (nxagentOption(DeferLevel) == 0)
+ {
+ nxagentChangeOption(DeferLevel, UNDEFINED);
+
+ nxagentSetDeferLevel();
+ }
+ else
+ {
+ nxagentChangeOption(DeferLevel, 0);
+ }
+
+ if (nxagentOption(DeferLevel) != 0)
+ {
+ nxagentLaunchDialog(DIALOG_ENABLE_DEFER_MODE);
+ }
+ else
+ {
+ nxagentLaunchDialog(DIALOG_DISABLE_DEFER_MODE);
+
+ nxagentForceSynchronization = 1;
+ }
+}
+
+static Bool nxagentExposurePredicate(Display *display, XEvent *event, XPointer window)
+{
+ /*
+ * Handle both Expose and ProcessedExpose events.
+ * The latters are those not filtered by function
+ * nxagentWindowExposures().
+ */
+
+ if (window)
+ {
+ return ((event -> type == Expose || event -> type == ProcessedExpose) &&
+ event -> xexpose.window == *((Window *) window));
+ }
+ else
+ {
+ return (event -> type == Expose || event -> type == ProcessedExpose);
+ }
+}
+
+static int nxagentAnyEventPredicate(Display *display, XEvent *event, XPointer parameter)
+{
+ return 1;
+}
+
+int nxagentInputEventPredicate(Display *display, XEvent *event, XPointer parameter)
+{
+ switch (event -> type)
+ {
+ case KeyPress:
+ case KeyRelease:
+ case ButtonPress:
+ case ButtonRelease:
+ {
+ return 1;
+ }
+ default:
+ {
+ return 0;
+ }
+ }
+}
+
+void nxagentInitDefaultEventMask()
+{
+ Mask mask = NoEventMask;
+
+ mask |= (StructureNotifyMask | VisibilityChangeMask);
+
+ mask |= ExposureMask;
+
+ mask |= NXAGENT_KEYBOARD_EVENT_MASK;
+ mask |= NXAGENT_POINTER_EVENT_MASK;
+
+ defaultEventMask = mask;
+}
+
+void nxagentGetDefaultEventMask(Mask *mask_return)
+{
+ *mask_return = defaultEventMask;
+}
+
+void nxagentSetDefaultEventMask(Mask mask)
+{
+ defaultEventMask = mask;
+}
+
+void nxagentGetEventMask(WindowPtr pWin, Mask *mask_return)
+{
+ Mask mask = NoEventMask;
+
+ if (nxagentOption(Rootless))
+ {
+ /*
+ * mask = pWin -> eventMask &
+ * ~(NXAGENT_KEYBOARD_EVENT_MASK | NXAGENT_POINTER_EVENT_MASK);
+ */
+
+ if (pWin -> drawable.class == InputOutput)
+ {
+ if (nxagentWindowTopLevel(pWin))
+ {
+ mask = defaultEventMask;
+ }
+ else
+ {
+ mask = ExposureMask | VisibilityChangeMask | PointerMotionMask;
+ }
+ }
+
+ mask |= PropertyChangeMask;
+ }
+ else if (pWin -> drawable.class != InputOnly)
+ {
+ mask = ExposureMask | VisibilityChangeMask;
+ }
+
+ *mask_return = mask;
+}
+
+static int nxagentChangeMapPrivate(WindowPtr pWin, pointer ptr)
+{
+ if (pWin && nxagentWindowPriv(pWin))
+ {
+ nxagentWindowPriv(pWin) -> isMapped = *((Bool *) ptr);
+ }
+
+ return WT_WALKCHILDREN;
+}
+
+static int nxagentChangeVisibilityPrivate(WindowPtr pWin, pointer ptr)
+{
+ if (pWin && nxagentWindowPriv(pWin))
+ {
+ nxagentWindowPriv(pWin) -> visibilityState = *((int *) ptr);
+ }
+
+ return WT_WALKCHILDREN;
+}
+
+void nxagentDispatchEvents(PredicateFuncPtr predicate)
+{
+ XEvent X;
+ xEvent x;
+ ScreenPtr pScreen = NULL;
+
+ Bool minimize = False;
+ Bool startKbd = False;
+ Bool closeSession = False;
+ Bool switchFullscreen = False;
+
+ /*
+ * Last entered top level window.
+ */
+
+ static WindowPtr nxagentLastEnteredTopLevelWindow = NULL;
+
+ #ifdef BLOCKS
+ fprintf(stderr, "[Begin read]\n");
+ #endif
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new events with "
+ "predicate [%p].\n", predicate);
+ #endif
+
+ if (nxagentRemoteExposeRegion == NULL)
+ {
+ nxagentInitRemoteExposeRegion();
+ }
+
+ /*
+ * We must read here, even if apparently there is
+ * nothing to read. The ioctl() based readable
+ * function, in fact, is often unable to detect a
+ * failure of the socket, in particular if the
+ * agent was connected to the proxy and the proxy
+ * is gone. Thus we must trust the wakeup handler
+ * that called us after the select().
+ */
+
+ #ifdef TEST
+
+ if (nxagentPendingEvents(nxagentDisplay) == 0)
+ {
+ fprintf(stderr, "nxagentDispatchEvents: PANIC! No event needs to be dispatched.\n");
+ }
+
+ #endif
+
+ /*
+ * We want to process all the events already in
+ * the queue, plus any additional event that may
+ * be read from the network. If no event can be
+ * read, we want to continue handling our clients
+ * without flushing the output buffer.
+ */
+
+ while (nxagentCheckEvents(nxagentDisplay, &X, predicate != NULL ? predicate :
+ nxagentAnyEventPredicate, NULL) == 1)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new event type [%d].\n",
+ X.type);
+ #endif
+
+ /*
+ * Handle the incoming event.
+ */
+
+ switch (X.type)
+ {
+ #ifdef NXAGENT_CLIPBOARD
+
+ case SelectionClear:
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new SelectionClear event.\n");
+ #endif
+
+ nxagentClearSelection(&X);
+
+ break;
+ }
+ case SelectionRequest:
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new SelectionRequest event.\n");
+ #endif
+
+ nxagentRequestSelection(&X);
+
+ break;
+ }
+ case SelectionNotify:
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new SelectionNotify event.\n");
+ #endif
+
+ nxagentNotifySelection(&X);
+
+ break;
+ }
+
+ #endif /* NXAGENT_CLIPBOARD */
+
+ case PropertyNotify:
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: PropertyNotify on "
+ "prop %d[%s] window %lx state %d\n",
+ (int)X.xproperty.atom, validateString(XGetAtomName(nxagentDisplay, X.xproperty.atom)),
+ X.xproperty.window, X.xproperty.state);
+ #endif
+
+ nxagentHandlePropertyNotify(&X);
+
+ break;
+ }
+ case KeyPress:
+ {
+ enum HandleEventResult result;
+
+ KeySym keysym;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new KeyPress event.\n");
+ #endif
+
+ nxagentInputEvent = 1;
+
+ nxagentKeyDown++;
+
+ nxagentHandleKeyPress(&X, &result);
+
+ if (viewportLastKeyPressResult != result)
+ {
+ viewportInc = 1;
+
+ viewportLastKeyPressResult = result;
+ }
+
+ if (result != doNothing && result != doStartKbd)
+ {
+ pScreen = nxagentScreen(X.xkey.window);
+ }
+
+ switch (result)
+ {
+ case doNothing:
+ {
+ break;
+ }
+ case doCloseSession:
+ {
+ closeSession = TRUE;
+
+ break;
+ }
+ case doMinimize:
+ {
+ minimize = TRUE;
+
+ break;
+ }
+ case doStartKbd:
+ {
+ startKbd = TRUE;
+
+ break;
+ }
+ case doSwitchFullscreen:
+ {
+ switchFullscreen = TRUE;
+
+ break;
+ }
+ case doViewportUp:
+ {
+ nxagentMoveViewport(pScreen, 0, -nextinc(viewportInc));
+
+ break;
+ }
+ case doViewportDown:
+ {
+ nxagentMoveViewport(pScreen, 0, +nextinc(viewportInc));
+
+ break;
+ }
+ case doViewportLeft:
+ {
+ nxagentMoveViewport(pScreen, -nextinc(viewportInc), 0);
+
+ break;
+ }
+ case doViewportRight:
+ {
+ nxagentMoveViewport(pScreen, +nextinc(viewportInc), 0);
+
+ break;
+ }
+ case doSwitchResizeMode:
+ {
+ if (nxagentOption(Shadow) == 0)
+ {
+ if (nxagentNoDialogIsRunning)
+ {
+ nxagentSwitchResizeMode(pScreen);
+ }
+ }
+ else
+ {
+ nxagentShadowSwitchResizeMode(pScreen);
+ }
+
+ break;
+ }
+ case doSwitchDeferMode:
+ {
+ if (nxagentNoDialogIsRunning)
+ {
+ nxagentSwitchDeferMode();
+ }
+
+ break;
+ }
+ default:
+ {
+ FatalError("nxagentDispatchEvent: handleKeyPress returned unknown value\n");
+
+ break;
+ }
+ }
+
+ /*
+ * Elide multiple KeyPress/KeyRelease events of
+ * the same key and generate a single pair. This
+ * is intended to reduce the impact of the laten-
+ * cy on the key auto-repeat, handled by the re-
+ * mote X server. We may optionally do that only
+ * if the timestamps in the events show an exces-
+ * sive delay.
+ */
+
+ keysym = XKeycodeToKeysym(nxagentDisplay, X.xkey.keycode, 0);
+
+ if (nxagentMonitoredDuplicate(keysym) == 1)
+ {
+ nxagentRemoveDuplicatedKeys(&X);
+ }
+
+ if (nxagentOption(ViewOnly) == 0 && nxagentOption(Shadow) == 1 && result == doNothing)
+ {
+ NXShadowEvent(nxagentDisplay, X);
+ }
+
+ break;
+ }
+ case KeyRelease:
+ {
+ enum HandleEventResult result;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new KeyRelease event.\n");
+ #endif
+
+ nxagentInputEvent = 1;
+
+ nxagentKeyDown--;
+
+ if (nxagentKeyDown <= 0)
+ {
+ nxagentKeyDown = 0;
+ }
+
+ if (nxagentXkbState.Initialized == 0)
+ {
+ nxagentInitKeyboardState();
+ }
+
+ x.u.u.type = KeyRelease;
+ x.u.u.detail = X.xkey.keycode;
+ x.u.keyButtonPointer.time = nxagentLastKeyPressTime + (X.xkey.time - nxagentLastServerTime);
+
+ nxagentLastServerTime = X.xkey.time;
+
+ nxagentLastEventTime = GetTimeInMillis();
+
+ if (!(nxagentCheckSpecialKeystroke(&X.xkey, &result)))
+ {
+ mieqEnqueue(&x);
+
+ CriticalOutputPending = 1;
+
+ if (nxagentOption(ViewOnly) == 0 && nxagentOption(Shadow))
+ {
+ NXShadowEvent(nxagentDisplay, X);
+ }
+ }
+
+ break;
+ }
+ case ButtonPress:
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new ButtonPress event.\n");
+ #endif
+
+ nxagentInputEvent = 1;
+
+ if (nxagentOption(Fullscreen))
+ {
+ if (nxagentMagicPixelZone(X.xbutton.x, X.xbutton.y))
+ {
+ pScreen = nxagentScreen(X.xbutton.window);
+
+ minimize = True;
+
+ break;
+ }
+ }
+
+ if (nxagentIpaq && nxagentClients <= 0)
+ {
+ closeSession = TRUE;
+ }
+
+ if (nxagentOption(DesktopResize) == False &&
+ (X.xbutton.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
+ {
+ /*
+ * Start viewport navigation mode.
+ */
+
+ int resource = nxagentWaitForResource(NXGetCollectGrabPointerResource,
+ nxagentCollectGrabPointerPredicate);
+
+ ScreenPtr pScreen = nxagentScreen(X.xbutton.window);
+ viewportCursor = XCreateFontCursor(nxagentDisplay, XC_fleur);
+
+ NXCollectGrabPointer(nxagentDisplay, resource,
+ nxagentDefaultWindows[pScreen -> myNum], True,
+ NXAGENT_POINTER_EVENT_MASK, GrabModeAsync,
+ GrabModeAsync, None, viewportCursor,
+ CurrentTime);
+ viewportLastX = X.xbutton.x;
+ viewportLastY = X.xbutton.y;
+
+ break;
+ }
+
+ if (!(nxagentOption(Fullscreen) &&
+ X.xbutton.window == nxagentFullscreenWindow &&
+ X.xbutton.subwindow == None))
+ {
+ x.u.u.type = ButtonPress;
+ x.u.u.detail = X.xbutton.button;
+ x.u.keyButtonPointer.time = nxagentLastEventTime = GetTimeInMillis();
+
+ if (nxagentOption(Rootless))
+ {
+ x.u.keyButtonPointer.rootX = X.xmotion.x_root;
+ x.u.keyButtonPointer.rootY = X.xmotion.y_root;
+ }
+ else
+ {
+ x.u.keyButtonPointer.rootX = X.xmotion.x - nxagentOption(RootX);
+ x.u.keyButtonPointer.rootY = X.xmotion.y - nxagentOption(RootY);
+ }
+
+ mieqEnqueue(&x);
+
+ CriticalOutputPending = 1;
+ }
+
+ if (nxagentOption(ViewOnly) == 0 && nxagentOption(Shadow))
+ {
+ X.xbutton.x -= nxagentOption(RootX);
+ X.xbutton.y -= nxagentOption(RootY);
+
+ if (nxagentOption(YRatio) != DONT_SCALE)
+ {
+ X.xbutton.x = (X.xbutton.x << PRECISION) / nxagentOption(YRatio);
+ }
+
+ if (nxagentOption(XRatio) != DONT_SCALE)
+ {
+ X.xbutton.y = (X.xbutton.y << PRECISION) / nxagentOption(YRatio);
+ }
+
+ NXShadowEvent(nxagentDisplay, X);
+ }
+
+ break;
+ }
+ case ButtonRelease:
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new ButtonRelease event.\n");
+ #endif
+
+ nxagentInputEvent = 1;
+
+ if (viewportCursor)
+ {
+ /*
+ * Leave viewport navigation mode.
+ */
+
+ XUngrabPointer(nxagentDisplay, CurrentTime);
+
+ XFreeCursor(nxagentDisplay, viewportCursor);
+
+ viewportCursor = None;
+ }
+
+ if (minimize != True)
+ {
+ x.u.u.type = ButtonRelease;
+ x.u.u.detail = X.xbutton.button;
+ x.u.keyButtonPointer.time = nxagentLastEventTime = GetTimeInMillis();
+
+ if (nxagentOption(Rootless))
+ {
+ x.u.keyButtonPointer.rootX = X.xmotion.x_root;
+ x.u.keyButtonPointer.rootY = X.xmotion.y_root;
+ }
+ else
+ {
+ x.u.keyButtonPointer.rootX = X.xmotion.x - nxagentOption(RootX);
+ x.u.keyButtonPointer.rootY = X.xmotion.y - nxagentOption(RootY);
+ }
+
+ mieqEnqueue(&x);
+
+ CriticalOutputPending = 1;
+ }
+
+ if (nxagentOption(ViewOnly) == 0 && nxagentOption(Shadow))
+ {
+ X.xbutton.x -= nxagentOption(RootX);
+ X.xbutton.y -= nxagentOption(RootY);
+
+ if (nxagentOption(XRatio) != DONT_SCALE)
+ {
+ X.xbutton.x = (X.xbutton.x << PRECISION) / nxagentOption(XRatio);
+ }
+
+ if (nxagentOption(YRatio) != DONT_SCALE)
+ {
+ X.xbutton.y = (X.xbutton.y << PRECISION) / nxagentOption(YRatio);
+ }
+
+ NXShadowEvent(nxagentDisplay, X);
+ }
+
+ break;
+ }
+ case MotionNotify:
+ {
+ ScreenPtr pScreen = nxagentScreen(X.xmotion.window);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new MotionNotify event.\n");
+ #endif
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Handling motion notify window [%ld] root [%ld] child [%ld].\n",
+ X.xmotion.window, X.xmotion.root, X.xmotion.subwindow);
+
+ fprintf(stderr, "nxagentDispatchEvents: Pointer at [%d][%d] relative root [%d][%d].\n",
+ X.xmotion.x, X.xmotion.y, X.xmotion.x_root, X.xmotion.y_root);
+ #endif
+
+ x.u.u.type = MotionNotify;
+
+ if (nxagentOption(Rootless))
+ {
+ WindowPtr pWin = nxagentWindowPtr(X.xmotion.window);
+
+ if (pWin)
+ {
+ nxagentLastEnteredWindow = pWin;
+ }
+
+ if (nxagentPulldownDialogPid == 0 && (X.xmotion.y_root <
+ nxagentLastEnteredTopLevelWindow -> drawable.y + 4))
+ {
+ if (pWin && nxagentLastEnteredTopLevelWindow &&
+ nxagentClientIsDialog(wClient(pWin)) == 0 &&
+ nxagentLastEnteredTopLevelWindow -> parent == WindowTable[0] &&
+ nxagentLastEnteredTopLevelWindow -> overrideRedirect == False &&
+ X.xmotion.x_root > (nxagentLastEnteredTopLevelWindow -> drawable.x +
+ (nxagentLastEnteredTopLevelWindow -> drawable.width >> 1) - 50) &&
+ X.xmotion.x_root < (nxagentLastEnteredTopLevelWindow -> drawable.x +
+ (nxagentLastEnteredTopLevelWindow -> drawable.width >> 1) + 50) &&
+ nxagentOption(Menu) == 1)
+ {
+ nxagentPulldownDialog(nxagentLastEnteredTopLevelWindow -> drawable.id);
+ }
+ }
+
+ x.u.keyButtonPointer.rootX = X.xmotion.x_root;
+ x.u.keyButtonPointer.rootY = X.xmotion.y_root;
+ }
+ else
+ {
+ x.u.keyButtonPointer.rootX = X.xmotion.x - nxagentOption(RootX);
+ x.u.keyButtonPointer.rootY = X.xmotion.y - nxagentOption(RootY);
+ }
+
+ x.u.keyButtonPointer.time = nxagentLastEventTime = GetTimeInMillis();
+
+ if (viewportCursor == None &&
+ !(nxagentOption(Fullscreen) &&
+ X.xmotion.window == nxagentDefaultWindows[pScreen -> myNum]
+ && X.xmotion.subwindow == None))
+ {
+ mieqEnqueue(&x);
+ }
+
+ /*
+ * This test is more complicated and probably not necessary, compared
+ * to a simple check on viewportCursor.
+ *
+ * if (!nxagentOption(Fullscreen) &&
+ * (X.xmotion.state & (ControlMask | Mod1Mask | Button1Mask)) ==
+ * (ControlMask | Mod1Mask | Button1Mask))
+ */
+
+ if (viewportCursor)
+ {
+ /*
+ * Pointer is in viewport navigation mode.
+ */
+
+ nxagentMoveViewport(pScreen, viewportLastX - X.xmotion.x, viewportLastY - X.xmotion.y);
+
+ viewportLastX = X.xmotion.x;
+ viewportLastY = X.xmotion.y;
+ }
+
+ if (nxagentOption(ViewOnly) == 0 && nxagentOption(Shadow) && !viewportCursor)
+ {
+ X.xmotion.x -= nxagentOption(RootX);
+ X.xmotion.y -= nxagentOption(RootY);
+
+ if (nxagentOption(XRatio) != DONT_SCALE)
+ {
+ X.xmotion.x = (X.xmotion.x << PRECISION) / nxagentOption(XRatio);
+ }
+
+ if (nxagentOption(YRatio) != DONT_SCALE)
+ {
+ X.xmotion.y = (X.xmotion.y << PRECISION) / nxagentOption(YRatio);
+ }
+
+ NXShadowEvent(nxagentDisplay, X);
+ }
+
+ if (nxagentOption(Shadow) == 0)
+ {
+ nxagentInputEvent = 1;
+ }
+
+ break;
+ }
+ case FocusIn:
+ {
+ WindowPtr pWin;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new FocusIn event.\n");
+ #endif
+
+ /*
+ * Here we change the focus state in the agent.
+ * It looks like this is needed only for root-
+ * less mode at the present moment.
+ */
+
+ if (nxagentOption(Rootless) &&
+ (pWin = nxagentWindowPtr(X.xfocus.window)))
+ {
+ SetInputFocus(serverClient, inputInfo.keyboard, pWin -> drawable.id,
+ RevertToPointerRoot, GetTimeInMillis(), False);
+ }
+
+ if (X.xfocus.detail != NotifyInferior)
+ {
+ pScreen = nxagentScreen(X.xfocus.window);
+
+ if (pScreen)
+ {
+ nxagentDirectInstallColormaps(pScreen);
+ }
+ }
+
+ break;
+ }
+ case FocusOut:
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new FocusOut event.\n");
+ #endif
+
+ if (X.xfocus.detail != NotifyInferior)
+ {
+ pScreen = nxagentScreen(X.xfocus.window);
+
+ if (pScreen)
+ {
+ nxagentDirectUninstallColormaps(pScreen);
+ }
+ }
+
+ #ifdef NXAGENT_FIXKEYS
+
+ {
+ /*
+ * Force the keys all up when focus is lost.
+ */
+
+ int i, k;
+ int mask = 1;
+ CARD8 val;
+
+ XEvent xM;
+ memset(&xM, 0, sizeof(XEvent));
+
+ for (i = 0; i < DOWN_LENGTH; i++) /* input.h */
+ {
+ val = inputInfo.keyboard->key->down[i];
+
+ if (val != 0)
+ {
+ for (k = 0; k < 8; k++)
+ {
+ if (val & (mask << k))
+ {
+ #ifdef NXAGENT_FIXKEYS_DEBUG
+ fprintf(stderr, "sending KeyRelease event for keycode: %x\n",
+ i * 8 + k);
+ #endif
+
+ if (!nxagentOption(Rootless) ||
+ inputInfo.keyboard->key->modifierMap[i * 8 + k])
+ {
+ x.u.u.type = KeyRelease;
+ x.u.u.detail = i * 8 + k;
+ x.u.keyButtonPointer.time = nxagentLastEventTime = GetTimeInMillis();
+
+ if (nxagentOption(ViewOnly) == 0 && nxagentOption(Shadow))
+ {
+ xM.type = KeyRelease;
+ xM.xkey.display = nxagentDisplay;
+ xM.xkey.type = KeyRelease;
+ xM.xkey.keycode = i * 8 + k;
+ xM.xkey.state = inputInfo.keyboard->key->state;
+ xM.xkey.time = GetTimeInMillis();
+ NXShadowEvent(nxagentDisplay, xM);
+ }
+
+ mieqEnqueue(&x);
+ }
+ }
+ }
+ }
+ }
+
+ nxagentKeyDown = 0;
+ }
+
+ #endif /* NXAGENT_FIXKEYS */
+
+ break;
+ }
+ case KeymapNotify:
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new KeymapNotify event.\n");
+ #endif
+
+ break;
+ }
+ case EnterNotify:
+ {
+ WindowPtr pWin;
+
+ WindowPtr pTLWin = NULL;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new EnterNotify event.\n");
+ #endif
+
+ if (nxagentOption(Rootless))
+ {
+ pWin = nxagentWindowPtr(X.xcrossing.window);
+
+ if (pWin != NULL)
+ {
+ for (pTLWin = pWin;
+ pTLWin -> parent != WindowTable[pTLWin -> drawable.pScreen -> myNum];
+ pTLWin = pTLWin -> parent);
+ }
+
+ if (pTLWin)
+ {
+ nxagentLastEnteredTopLevelWindow = pTLWin;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: nxagentLastEnteredTopLevelWindow [%p].\n",
+ nxagentLastEnteredTopLevelWindow);
+ #endif
+ }
+
+ if (nxagentOption(Rootless) && nxagentWMIsRunning &&
+ (pWin = nxagentWindowPtr(X.xcrossing.window)) &&
+ nxagentWindowTopLevel(pWin) && !pWin -> overrideRedirect &&
+ (pWin -> drawable.x != X.xcrossing.x_root - X.xcrossing.x - pWin -> borderWidth ||
+ pWin -> drawable.y != X.xcrossing.y_root - X.xcrossing.y - pWin -> borderWidth))
+ {
+ /*
+ * This code is useful for finding the window
+ * position. It should be re-implemented by
+ * following the ICCCM 4.1.5 recommendations.
+ */
+
+ XID values[4];
+ register XID *value = values;
+ Mask mask = 0;
+ ClientPtr pClient = wClient(pWin);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: pWin -> drawable.x [%d] pWin -> drawable.y [%d].\n",
+ pWin -> drawable.x, pWin -> drawable.y);
+ #endif
+
+ *value++ = (XID) (X.xcrossing.x_root - X.xcrossing.x - pWin -> borderWidth);
+ *value++ = (XID) (X.xcrossing.y_root - X.xcrossing.y - pWin -> borderWidth);
+
+ /*
+ * nxagentWindowPriv(pWin)->x = (X.xcrossing.x_root - X.xcrossing.x);
+ * nxagentWindowPriv(pWin)->y = (X.xcrossing.y_root - X.xcrossing.y);
+ */
+
+ mask = CWX | CWY;
+
+ nxagentScreenTrap = 1;
+
+ ConfigureWindow(pWin, mask, (XID *) values, pClient);
+
+ nxagentScreenTrap = 0;
+ }
+
+ if (nxagentOption(Fullscreen))
+ {
+ if (X.xcrossing.window == nxagentFullscreenWindow &&
+ X.xcrossing.detail != NotifyInferior)
+ {
+ nxagentGrabPointerAndKeyboard(&X);
+ }
+ }
+
+ if (X.xcrossing.detail != NotifyInferior)
+ {
+ pScreen = nxagentScreen(X.xcrossing.window);
+
+ if (pScreen)
+ {
+ NewCurrentScreen(pScreen, X.xcrossing.x, X.xcrossing.y);
+
+ x.u.u.type = MotionNotify;
+
+ if (nxagentOption(Rootless))
+ {
+ nxagentLastEnteredWindow = nxagentWindowPtr(X.xcrossing.window);
+ x.u.keyButtonPointer.rootX = X.xcrossing.x_root;
+ x.u.keyButtonPointer.rootY = X.xcrossing.y_root;
+ }
+ else
+ {
+ x.u.keyButtonPointer.rootX = X.xcrossing.x - nxagentOption(RootX);
+ x.u.keyButtonPointer.rootY = X.xcrossing.y - nxagentOption(RootY);
+ }
+
+ x.u.keyButtonPointer.time = nxagentLastEventTime = GetTimeInMillis();
+
+ mieqEnqueue(&x);
+
+ nxagentDirectInstallColormaps(pScreen);
+ }
+ }
+
+ nxagentInputEvent = 1;
+
+ break;
+ }
+ case LeaveNotify:
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new LeaveNotify event.\n");
+ #endif
+
+ if (nxagentOption(Rootless) && X.xcrossing.mode == NotifyNormal &&
+ X.xcrossing.detail != NotifyInferior)
+ {
+ nxagentLastEnteredWindow = NULL;
+ }
+
+ if (nxagentOption(Fullscreen))
+ {
+ if (X.xcrossing.window == nxagentFullscreenWindow &&
+ X.xcrossing.detail != NotifyInferior &&
+ X.xcrossing.mode == NotifyNormal)
+ {
+ nxagentUngrabPointerAndKeyboard(&X);
+
+ pScreen = nxagentScreen(X.xcrossing.window);
+
+ minimize = True;
+ }
+ }
+
+ if (X.xcrossing.detail != NotifyInferior)
+ {
+ pScreen = nxagentScreen(X.xcrossing.window);
+
+ if (pScreen)
+ {
+ nxagentDirectUninstallColormaps(pScreen);
+ }
+ }
+
+ nxagentInputEvent = 1;
+
+ break;
+ }
+ case DestroyNotify:
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new DestroyNotify event.\n");
+ #endif
+
+ if (nxagentParentWindow != (Window) 0 &&
+ X.xdestroywindow.window == nxagentParentWindow)
+ {
+ fprintf(stderr, "Warning: Unhandled destroy notify event received in agent.\n");
+ }
+
+ break;
+ }
+ case ClientMessage:
+ {
+ enum HandleEventResult result;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new ClientMessage event.\n");
+ #endif
+
+ nxagentHandleClientMessageEvent(&X, &result);
+
+ if (result == doCloseSession)
+ {
+ closeSession = TRUE;
+ }
+
+ break;
+ }
+ case VisibilityNotify:
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new VisibilityNotify event.\n");
+ #endif
+
+ if (X.xvisibility.window != nxagentDefaultWindows[0])
+ {
+ Window window = X.xvisibility.window;
+
+ WindowPtr pWin = nxagentWindowPtr(window);
+
+ if (pWin && nxagentWindowPriv(pWin))
+ {
+ if (nxagentWindowPriv(pWin) -> visibilityState != X.xvisibility.state)
+ {
+ int value = X.xvisibility.state;
+
+ if (nxagentOption(Rootless) == 1)
+ {
+ TraverseTree(pWin, nxagentChangeVisibilityPrivate, &value);
+ }
+ else
+ {
+ nxagentChangeVisibilityPrivate(pWin, &value);
+ }
+ }
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Suppressing visibility notify on window [%lx].\n",
+ X.xvisibility.window);
+ #endif
+
+ break;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Visibility notify state is [%d] with previous [%d].\n",
+ X.xvisibility.state, nxagentVisibility);
+ #endif
+
+ nxagentVisibility = X.xvisibility.state;
+
+ break;
+ }
+ case Expose:
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new Expose event.\n");
+ #endif
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchEvents: WARNING! Received Expose event "
+ "for drawable [%lx] geometry [%d, %d, %d, %d] count [%d].\n",
+ X.xexpose.window, X.xexpose.x, X.xexpose.y, X.xexpose.width,
+ X.xexpose.height, X.xexpose.count);
+ #endif
+
+ nxagentHandleExposeEvent(&X);
+
+ break;
+ }
+ case GraphicsExpose:
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new GraphicsExpose event.\n");
+ #endif
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchEvents: WARNING! Received GraphicsExpose event "
+ "for drawable [%lx] geometry [%d, %d, %d, %d] count [%d].\n",
+ X.xgraphicsexpose.drawable, X.xgraphicsexpose.x, X.xgraphicsexpose.y,
+ X.xgraphicsexpose.width, X.xgraphicsexpose.height,
+ X.xgraphicsexpose.count);
+ #endif
+
+ nxagentHandleGraphicsExposeEvent(&X);
+
+ break;
+ }
+ case NoExpose:
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new NoExpose event.\n");
+ #endif
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchEvents: WARNING! Received NoExpose event for "
+ "drawable [%lx].\n", X.xnoexpose.drawable);
+ #endif
+
+ break;
+ }
+ case CirculateNotify:
+ {
+ /*
+ * WindowPtr pWin;
+ * WindowPtr pSib;
+ * ClientPtr pClient;
+
+ * XID values[2];
+ * register XID *value = values;
+ * Mask mask = 0;
+ */
+
+ #ifdef WARNING
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new CirculateNotify event.\n");
+ #endif
+
+ /*
+ * FIXME: Do we need this?
+ *
+ * pWin = nxagentWindowPtr(X.xcirculate.window);
+ *
+ * if (!pWin)
+ * {
+ * pWin = nxagentRootlessTopLevelWindow(X.xcirculate.window);
+ * }
+ *
+ * if (!pWin)
+ * {
+ * break;
+ * }
+ *
+ * XQueryTree(nxagentDisplay, DefaultRootWindow(nxagentDisplay),
+ * &root_return, &parent_return, &children_return, &nchildren_return);
+ *
+ * nxagentRootlessRestack(children_return, nchildren_return);
+ */
+
+ break;
+ }
+ case ConfigureNotify:
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new ConfigureNotify event.\n");
+ #endif
+
+ if (nxagentConfiguredSynchroWindow == X.xconfigure.window)
+ {
+ if (nxagentExposeQueue.exposures[nxagentExposeQueue.start].serial != X.xconfigure.x)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentDispatchEvents: Requested ConfigureNotify changes didn't take place.\n");
+ #endif
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Received ConfigureNotify and going to call "
+ "nxagentSynchronizeExpose.\n");
+ #endif
+
+ nxagentSynchronizeExpose();
+
+ break;
+ }
+
+ nxagentHandleConfigureNotify(&X);
+
+ break;
+ }
+ case GravityNotify:
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new GravityNotify event.\n");
+ #endif
+
+ break;
+ }
+ case ReparentNotify:
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new ReparentNotify event.\n");
+ #endif
+
+ nxagentHandleReparentNotify(&X);
+
+ break;
+ }
+ case UnmapNotify:
+ {
+ WindowPtr pWin;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new UnmapNotify event.\n");
+ #endif
+
+ if (nxagentOption(Rootless) == 1)
+ {
+ if ((pWin = nxagentRootlessTopLevelWindow(X.xunmap.window)) != NULL ||
+ ((pWin = nxagentWindowPtr(X.xunmap.window)) != NULL &&
+ nxagentWindowTopLevel(pWin) == 1))
+ {
+ nxagentScreenTrap = 1;
+
+ UnmapWindow(pWin, False);
+
+ nxagentScreenTrap = 0;
+ }
+ }
+
+ if (nxagentUseNXTrans == 1 && nxagentOption(Rootless) == 0 &&
+ nxagentOption(Nested) == 0 && X.xmap.window != nxagentIconWindow)
+ {
+ nxagentVisibility = VisibilityFullyObscured;
+ }
+
+ break;
+ }
+ case MapNotify:
+ {
+ WindowPtr pWin;
+ ClientPtr pClient;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Going to handle new MapNotify event.\n");
+ #endif
+
+ if (nxagentOption(Rootless) == 1)
+ {
+ Bool value = 1;
+
+ if ((pWin = nxagentRootlessTopLevelWindow(X.xmap.window)) != NULL ||
+ ((pWin = nxagentWindowPtr(X.xmap.window)) != NULL &&
+ nxagentWindowTopLevel(pWin) == 1))
+ {
+ pClient = wClient(pWin);
+
+ nxagentScreenTrap = 1;
+
+ MapWindow(pWin, pClient);
+
+ nxagentScreenTrap = 0;
+ }
+
+ if (pWin != NULL)
+ {
+ TraverseTree(pWin, nxagentChangeMapPrivate, &value);
+ }
+ }
+
+ if (nxagentOption(Fullscreen) == 1)
+ {
+ if (X.xmap.window == nxagentIconWindow)
+ {
+ pScreen = nxagentScreen(X.xmap.window);
+ nxagentMaximizeToFullScreen(pScreen);
+ }
+
+ nxagentVisibility = VisibilityUnobscured;
+ nxagentVisibilityStop = False;
+ nxagentVisibilityTimeout = GetTimeInMillis() + 2000;
+ }
+
+ break;
+ }
+ case MappingNotify:
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchEvents: WARNING! Going to handle new MappingNotify event.\n");
+ #endif
+
+ break;
+ }
+ default:
+ {
+ /*
+ * Let's check if this is a XKB
+ * state modification event.
+ */
+
+ if (nxagentHandleKeyboardEvent(&X) == 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: WARNING! Unhandled event code [%d].\n",
+ X.type);
+ #endif
+ }
+
+ break;
+ }
+
+ } /* End of switch (X.type) */
+
+ } /* End of while (...) */
+
+ /*
+ * Send the exposed regions to the clients.
+ */
+
+ nxagentForwardRemoteExpose();
+
+ /*
+ * Handle the agent window's changes.
+ */
+
+ if (closeSession)
+ {
+ if (nxagentOption(Persistent))
+ {
+ if (nxagentNoDialogIsRunning)
+ {
+ nxagentLaunchDialog(DIALOG_SUSPEND_SESSION);
+ }
+ }
+ else
+ {
+ if (nxagentNoDialogIsRunning)
+ {
+ nxagentLaunchDialog(DIALOG_KILL_SESSION);
+ }
+ }
+ }
+
+ if (minimize)
+ {
+ nxagentWMDetect();
+
+ if (nxagentWMIsRunning)
+ {
+ if (nxagentOption(Fullscreen))
+ {
+ nxagentMinimizeFromFullScreen(pScreen);
+ }
+ else
+ {
+ XIconifyWindow(nxagentDisplay, nxagentDefaultWindows[0], DefaultScreen(nxagentDisplay));
+ }
+ }
+ }
+
+ if (switchFullscreen)
+ {
+ nxagentSwitchFullscreen(pScreen, !nxagentOption(Fullscreen));
+ }
+
+ if (startKbd)
+ {
+ if (xkbdRunning)
+ {
+ #ifdef NXAGENT_XKBD_DEBUG
+ fprintf(stderr, "Events: nxkbd now is NOT running: %d, %d\n",
+ X.xkey.keycode, escapecode);
+ #endif
+
+ xkbdRunning = False;
+
+ kill(pidkbd, 9);
+ }
+ else
+ {
+ char kbddisplay[6];
+ char *kbdargs[6];
+
+ strcpy(kbddisplay,":");
+ strncat(kbddisplay, display, 4);
+
+ kbdargs[0] = "nxkbd";
+ kbdargs[1] = "-geometry";
+ kbdargs[2] = "240x70+0+250";
+ kbdargs[3] = "-display";
+ kbdargs[4] = kbddisplay;
+ kbdargs[5] = NULL;
+
+ switch (pidkbd = fork())
+ {
+ case 0:
+ {
+ execvp(kbdargs[0], kbdargs);
+
+ #ifdef NXAGENT_XKBD_DEBUG
+ fprintf(stderr, "Events: The execvp of nxkbd process failed.\n");
+ #endif
+
+ exit(1);
+
+ break;
+ }
+ case -1:
+ {
+ #ifdef NXAGENT_XKBD_DEBUG
+ fprintf(stderr, "Events: Can't fork to run the nxkbd process.\n");
+ #endif
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ #ifdef NXAGENT_XKBD_DEBUG
+ fprintf(stderr, "Events: The nxkbd process now running with [%d][%d].\n",
+ X.xkey.keycode, escapecode);
+ #endif
+
+ xkbdRunning = True;
+ }
+ }
+
+ #ifdef BLOCKS
+ fprintf(stderr, "[End read]\n");
+ #endif
+
+ /*
+ * Let the underlying X server code
+ * process the input events.
+ */
+
+ #ifdef BLOCKS
+ fprintf(stderr, "[Begin events]\n");
+ #endif
+
+ ProcessInputEvents();
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Output pending flag is [%d] critical [%d].\n",
+ NewOutputPending, CriticalOutputPending);
+ #endif
+
+ /*
+ * Write the events to our clients. We may
+ * flush only in the case of critical output
+ * but this doesn't seem beneficial.
+ *
+ * if (CriticalOutputPending == 1)
+ * {
+ * FlushAllOutput();
+ * }
+ */
+
+ if (NewOutputPending == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchEvents: Flushed the processed events to clients.\n");
+ #endif
+
+ FlushAllOutput();
+ }
+
+ #ifdef TEST
+
+ if (nxagentPendingEvents(nxagentDisplay) > 0)
+ {
+ fprintf(stderr, "nxagentDispatchEvents: WARNING! More events need to be dispatched.\n");
+ }
+
+ #endif
+
+ #ifdef BLOCKS
+ fprintf(stderr, "[End events]\n");
+ #endif
+}
+
+/*
+ * Functions providing the ad-hoc handling
+ * of the remote X events.
+ */
+
+int nxagentHandleKeyPress(XEvent *X, enum HandleEventResult *result)
+{
+ xEvent x;
+
+ if (nxagentXkbState.Initialized == 0)
+ {
+ nxagentInitKeyboardState();
+ }
+
+ if (nxagentCheckSpecialKeystroke(&X -> xkey, result))
+ {
+ return 1;
+ }
+
+ nxagentLastEventTime = nxagentLastKeyPressTime = GetTimeInMillis();
+
+ x.u.u.type = KeyPress;
+ x.u.u.detail = X -> xkey.keycode;
+ x.u.keyButtonPointer.time = nxagentLastKeyPressTime;
+
+ nxagentLastServerTime = X -> xkey.time;
+
+ mieqEnqueue(&x);
+
+ CriticalOutputPending = 1;
+
+ return 1;
+}
+
+int nxagentHandlePropertyNotify(XEvent *X)
+{
+ int resource;
+
+ if (nxagentOption(Rootless) && !nxagentNotifyMatchChangeProperty((XPropertyEvent *) X))
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandlePropertyNotify: Property %ld on window %lx.\n",
+ X -> xproperty.atom, X -> xproperty.window);
+ #endif
+
+ if (nxagentWindowPtr(X -> xproperty.window) != NULL)
+ {
+ resource = NXGetCollectPropertyResource(nxagentDisplay);
+
+ if (resource == -1)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentHandlePropertyNotify: WARNING! Asyncronous get property queue is full.\n");
+ #endif
+
+ return 0;
+ }
+
+ NXCollectProperty(nxagentDisplay, resource,
+ X -> xproperty.window, X -> xproperty.atom, 0,
+ MAX_RETRIEVED_PROPERTY_SIZE, False, AnyPropertyType);
+
+ nxagentPropertyRequests[resource].window = X -> xproperty.window;
+ nxagentPropertyRequests[resource].property = X -> xproperty.atom;
+ }
+ #ifdef TEST
+ else
+ {
+ fprintf(stderr, "nxagentHandlePropertyNotify: Failed to look up remote window property.\n");
+ }
+ #endif
+ }
+
+ return 1;
+}
+
+int nxagentHandleExposeEvent(XEvent *X)
+{
+ WindowPtr pWin = NULL;
+ Window window = None;
+
+ RegionRec sum;
+ RegionRec add;
+ BoxRec box;
+ int index = 0;
+ int overlap = 0;
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentHandleExposeEvent: Checking remote expose events.\n");
+ #endif
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentHandleExposeEvent: Looking for window id [%ld].\n",
+ X -> xexpose.window);
+ #endif
+
+ window = X -> xexpose.window;
+
+ pWin = nxagentWindowPtr(window);
+
+ if (pWin != NULL)
+ {
+ REGION_INIT(pWin -> drawable.pScreen, &sum, (BoxRec *) NULL, 1);
+/*
+FIXME: This can be maybe optimized by consuming the
+ events that do not match the predicate.
+*/
+ do
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentHandleExposeEvent: Adding event for window id [%ld].\n",
+ X -> xexpose.window);
+ #endif
+
+ box.x1 = pWin -> drawable.x + wBorderWidth(pWin) + X -> xexpose.x;
+ box.y1 = pWin -> drawable.y + wBorderWidth(pWin) + X -> xexpose.y;
+
+ box.x2 = box.x1 + X -> xexpose.width;
+ box.y2 = box.y1 + X -> xexpose.height;
+
+ REGION_INIT(pWin -> drawable.pScreen, &add, &box, 1);
+
+ REGION_APPEND(pWin -> drawable.pScreen, &sum, &add);
+
+ REGION_UNINIT(pWin -> drawable.pScreen, &add);
+
+ if (X -> xexpose.count == 0)
+ {
+ break;
+ }
+ }
+ while (nxagentCheckEvents(nxagentDisplay, X, nxagentExposurePredicate,
+ (XPointer) &window) == 1);
+
+ REGION_VALIDATE(pWin -> drawable.pScreen, &sum, &overlap);
+
+ REGION_INTERSECT(pWin->drawable.pScreen, &sum, &sum,
+ &WindowTable[pWin->drawable.pScreen->myNum]->winSize);
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentHandleExposeEvent: Sending events for window id [%ld].\n",
+ X -> xexpose.window);
+ #endif
+
+ /*
+ * If the agent has already sent auto-generated expose,
+ * save received exposes for later processing.
+ */
+
+ index = nxagentLookupByWindow(pWin);
+
+ if (index == -1)
+ {
+ miWindowExposures(pWin, &sum, NullRegion);
+ }
+ else
+ {
+ REGION_TRANSLATE(pWin -> drawable.pScreen, &sum, -pWin -> drawable.x, -pWin -> drawable.y);
+
+ if (nxagentExposeQueue.exposures[index].remoteRegion == NullRegion)
+ {
+ nxagentExposeQueue.exposures[index].remoteRegion = REGION_CREATE(pwin -> drawable.pScreen, NULL, 1);
+ }
+
+ REGION_UNION(pWin -> drawable.pScreen, nxagentExposeQueue.exposures[index].remoteRegion,
+ nxagentExposeQueue.exposures[index].remoteRegion, &sum);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleExposeEvent: Added region for window [%ld] to position [%d].\n",
+ nxagentWindow(pWin), index);
+ #endif
+
+ if (X -> xexpose.count == 0)
+ {
+ nxagentExposeQueue.exposures[index].remoteRegionIsCompleted = True;
+ }
+ else
+ {
+ nxagentExposeQueue.exposures[index].remoteRegionIsCompleted = False;
+ }
+ }
+
+ if (nxagentRootTileWindow != NULL)
+ {
+ if (nxagentWindowPriv(nxagentRootTileWindow) -> window == nxagentWindowPriv(pWin) -> window &&
+ nxagentSplashCount == 1 && X -> xexpose.count == 0)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentHandleExposeEvent: Clearing root tile window id [%ld].\n",
+ nxagentWindowPriv(nxagentRootTileWindow) -> window);
+ #endif
+
+ XClearWindow(nxagentDisplay, nxagentWindowPriv(nxagentRootTileWindow) -> window);
+ }
+ }
+
+ REGION_UNINIT(pWin -> drawable.pScreen, &sum);
+ }
+
+ return 1;
+}
+
+int nxagentHandleGraphicsExposeEvent(XEvent *X)
+{
+ /*
+ * Send an expose event to client, instead of graphics
+ * expose. If target drawable is a backing pixmap, send
+ * expose event for the saved window, else do nothing.
+ */
+
+ RegionPtr exposeRegion;
+ BoxRec rect;
+ WindowPtr pWin;
+ ScreenPtr pScreen;
+ StoringPixmapPtr pStoringPixmapRec = NULL;
+ miBSWindowPtr pBSwindow = NULL;
+ int drawableType;
+
+ pWin = nxagentWindowPtr(X -> xgraphicsexpose.drawable);
+
+ if (pWin != NULL)
+ {
+ drawableType = DRAWABLE_WINDOW;
+ }
+ else
+ {
+ drawableType = DRAWABLE_PIXMAP;
+ }
+
+ if (drawableType == DRAWABLE_PIXMAP)
+ {
+ pStoringPixmapRec = nxagentFindItemBSPixmapList(X -> xgraphicsexpose.drawable);
+
+ if (pStoringPixmapRec == NULL)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleGraphicsExposeEvent: WARNING! Storing pixmap not found.\n");
+ #endif
+
+ return 1;
+ }
+
+ pBSwindow = (miBSWindowPtr) pStoringPixmapRec -> pSavedWindow -> backStorage;
+
+ if (pBSwindow == NULL)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleGraphicsExposeEvent: WARNING! Back storage not found.\n");
+ #endif
+
+ return 1;
+ }
+
+ pWin = pStoringPixmapRec -> pSavedWindow;
+ }
+
+ pScreen = pWin -> drawable.pScreen;
+
+ /*
+ * Rectangle affected by GraphicsExpose
+ * event.
+ */
+
+ rect.x1 = X -> xgraphicsexpose.x;
+ rect.y1 = X -> xgraphicsexpose.y;
+ rect.x2 = rect.x1 + X -> xgraphicsexpose.width;
+ rect.y2 = rect.y1 + X -> xgraphicsexpose.height;
+
+ exposeRegion = REGION_CREATE(pScreen, &rect, 0);
+
+ if (drawableType == DRAWABLE_PIXMAP)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleGraphicsExposeEvent: Handling GraphicsExpose event on pixmap with id"
+ " [%lu].\n", X -> xgraphicsexpose.drawable);
+ #endif
+
+ /*
+ * The exposeRegion coordinates are relative
+ * to the pixmap to which GraphicsExpose
+ * event refers. But the BS coordinates of
+ * the savedRegion are relative to the
+ * window.
+ */
+
+ REGION_TRANSLATE(pScreen, exposeRegion, pStoringPixmapRec -> backingStoreX,
+ pStoringPixmapRec -> backingStoreY);
+
+ /*
+ * We remove from SavedRegion the part
+ * affected by the GraphicsExpose event.
+ */
+
+ REGION_SUBTRACT(pScreen, &(pBSwindow -> SavedRegion), &(pBSwindow -> SavedRegion),
+ exposeRegion);
+ }
+
+ /*
+ * Store the exposeRegion in order to send
+ * the expose event later. The coordinates
+ * must be relative to the screen.
+ */
+
+ REGION_TRANSLATE(pScreen, exposeRegion, pWin -> drawable.x, pWin -> drawable.y);
+
+ REGION_UNION(pScreen, nxagentRemoteExposeRegion, nxagentRemoteExposeRegion, exposeRegion);
+
+ REGION_DESTROY(pScreen, exposeRegion);
+
+ return 1;
+}
+
+int nxagentHandleClientMessageEvent(XEvent *X, enum HandleEventResult *result)
+{
+ ScreenPtr pScreen;
+ WindowPtr pWin;
+ xEvent x;
+
+ *result = doNothing;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleClientMessageEvent: ClientMessage event window [%ld] with "
+ "type [%ld] format [%d].\n", X -> xclient.window, X -> xclient.message_type,
+ X -> xclient.format);
+ #endif
+
+ /*
+ * If window is 0, message_type is 0 and format is
+ * 32 then we assume event is coming from proxy.
+ */
+
+ if (X -> xclient.window == 0 &&
+ X -> xclient.message_type == 0 &&
+ X -> xclient.format == 32)
+ {
+ nxagentHandleProxyEvent(X);
+
+ return 1;
+ }
+
+ if (nxagentOption(Rootless))
+ {
+ Atom message_type = nxagentRemoteToLocalAtom(X -> xclient.message_type);
+
+ if (!ValidAtom(message_type))
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentHandleClientMessageEvent: WARNING Invalid type in client message.\n");
+ #endif
+
+ return 0;
+ }
+
+ pWin = nxagentWindowPtr(X -> xclient.window);
+
+ if (pWin == NULL)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "WARNING: Invalid window in ClientMessage.\n");
+ #endif
+
+ return 0;
+ }
+
+ if (message_type == MakeAtom("WM_PROTOCOLS", strlen("WM_PROTOCOLS"), False))
+ {
+ char *message_data;
+
+ x.u.u.type = ClientMessage;
+ x.u.u.detail = X -> xclient.format;
+
+ x.u.clientMessage.window = pWin -> drawable.id;
+ x.u.clientMessage.u.l.type = message_type;
+ x.u.clientMessage.u.l.longs0 = nxagentRemoteToLocalAtom(X -> xclient.data.l[0]);
+ x.u.clientMessage.u.l.longs1 = GetTimeInMillis();
+
+ if (!ValidAtom(x.u.clientMessage.u.l.longs0))
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentHandleClientMessageEvent: WARNING Invalid value in client message "
+ "of type WM_PROTOCOLS.\n");
+ #endif
+
+ return 0;
+ }
+ else
+ {
+ message_data = validateString(NameForAtom(x.u.clientMessage.u.l.longs0));
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleClientMessageEvent: Sent client message of type WM_PROTOCOLS "
+ "and value [%s].\n", message_data);
+ #endif
+
+ TryClientEvents(wClient(pWin), &x, 1, 1, 1, 0);
+ }
+ else
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentHandleClientMessageEvent: Ignored message type %ld [%s].\n",
+ (long int) message_type, validateString(NameForAtom(message_type)));
+ #endif
+
+ return 0;
+ }
+
+ return 1;
+ }
+
+ if (X -> xclient.message_type == nxagentAtoms[1]) /* WM_PROTOCOLS */
+ {
+ Atom deleteWMatom, wmAtom;
+
+ wmAtom = (Atom) X -> xclient.data.l[0];
+
+ deleteWMatom = nxagentAtoms[2]; /* WM_DELETE_WINDOW */
+
+ if (wmAtom == deleteWMatom)
+ {
+ if (nxagentOnce && (nxagentClients == 0))
+ {
+ GiveUp(0);
+ }
+ else
+ {
+ #ifdef TEST
+ fprintf(stderr, "Events: WM_DELETE_WINDOW arrived Atom = %ld.\n", wmAtom);
+ #endif
+
+ if (X -> xclient.window == nxagentIconWindow)
+ {
+ pScreen = nxagentScreen(X -> xmap.window);
+
+ nxagentMaximizeToFullScreen(pScreen);
+ }
+
+ if (X -> xclient.window == (nxagentOption(Fullscreen) ?
+ nxagentIconWindow : nxagentDefaultWindows[0]))
+ {
+ *result = doCloseSession;
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
+int nxagentHandleKeyboardEvent(XEvent *X)
+{
+ XkbEvent *xkbev = (XkbEvent *) X;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleKeyboardEvent: Handling event with caps [%d] num [%d] locked [%d].\n",
+ nxagentXkbState.Caps, nxagentXkbState.Num, nxagentXkbState.Locked);
+ #endif
+
+ if (xkbev -> type == nxagentXkbInfo.EventBase + XkbEventCode &&
+ xkbev -> any.xkb_type == XkbStateNotify)
+ {
+ nxagentXkbState.Locked = xkbev -> state.locked_mods;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleKeyboardEvent: Updated XKB locked modifier bits to [%x].\n",
+ nxagentXkbState.Locked);
+ #endif
+
+ nxagentXkbState.Initialized = 1;
+
+ if (nxagentXkbState.Caps == 0 &&
+ (nxagentXkbState.Locked & CAPSFLAG_IN_EVENT))
+ {
+ nxagentXkbState.Caps = 1;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleKeyboardEvent: Sending fake key [66] to engage capslock.\n");
+ #endif
+
+ nxagentSendFakeKey(66);
+ }
+
+ if (nxagentXkbState.Caps == 1 &&
+ !(nxagentXkbState.Locked & CAPSFLAG_IN_EVENT))
+ {
+ nxagentXkbState.Caps = 0;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleKeyboardEvent: Sending fake key [66] to release capslock.\n");
+ #endif
+
+ nxagentSendFakeKey(66);
+ }
+
+ if (nxagentXkbState.Num == 0 &&
+ (nxagentXkbState.Locked & NUMFLAG_IN_EVENT))
+ {
+ nxagentXkbState.Num = 1;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleKeyboardEvent: Sending fake key [77] to engage numlock.\n");
+ #endif
+
+ nxagentSendFakeKey(77);
+ }
+
+ if (nxagentXkbState.Num == 1 &&
+ !(nxagentXkbState.Locked & NUMFLAG_IN_EVENT))
+ {
+ nxagentXkbState.Num = 0;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleKeyboardEvent: Sending fake key [77] to release numlock.\n");
+ #endif
+
+ nxagentSendFakeKey(77);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int nxagentHandleProxyEvent(XEvent *X)
+{
+ switch (X -> xclient.data.l[0])
+ {
+ case NXNoSplitNotify:
+ case NXStartSplitNotify:
+ {
+ /*
+ * We should never receive such events
+ * in the event loop, as they should
+ * be caught at the time the split is
+ * initiated.
+ */
+
+ #ifdef PANIC
+
+ int client = (int) X -> xclient.data.l[1];
+
+ if (X -> xclient.data.l[0] == NXNoSplitNotify)
+ {
+ fprintf(stderr, "nxagentHandleProxyEvent: PANIC! NXNoSplitNotify received "
+ "with client [%d].\n", client);
+ }
+ else
+ {
+ fprintf(stderr, "nxagentHandleProxyEvent: PANIC! NXStartSplitNotify received "
+ "with client [%d].\n", client);
+ }
+
+ #endif
+
+ return 1;
+ }
+ case NXCommitSplitNotify:
+ {
+ /*
+ * We need to commit an image. Image can be the
+ * result of a PutSubImage() generated by Xlib,
+ * so there can be more than a single image to
+ * commit, even if only one PutImage was perfor-
+ * med by the agent.
+ */
+
+ int client = (int) X -> xclient.data.l[1];
+ int request = (int) X -> xclient.data.l[2];
+ int position = (int) X -> xclient.data.l[3];
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleProxyEvent: NXCommitSplitNotify received with "
+ "client [%d] request [%d] and position [%d].\n",
+ client, request, position);
+ #endif
+
+ nxagentHandleCommitSplitEvent(client, request, position);
+
+ return 1;
+ }
+ case NXEndSplitNotify:
+ {
+ /*
+ * All images for the split were transferred and
+ * we need to restart the client.
+ */
+
+ int client = (int) X -> xclient.data.l[1];
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleProxyEvent: NXEndSplitNotify received with "
+ "client [%d].\n", client);
+ #endif
+
+ nxagentHandleEndSplitEvent(client);
+
+ return 1;
+ }
+ case NXEmptySplitNotify:
+ {
+ /*
+ * All splits have been completed and none remain.
+ */
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleProxyEvent: NXEmptySplitNotify received.\n");
+ #endif
+
+ nxagentHandleEmptySplitEvent();
+
+ return 1;
+ }
+ case NXCollectPropertyNotify:
+ {
+ #ifdef TEST
+ int resource = (int) X -> xclient.data.l[1];
+
+ fprintf(stderr, "nxagentHandleProxyEvent: NXCollectPropertyNotify received with resource [%d].\n",
+ resource);
+ #endif
+
+ nxagentHandleCollectPropertyEvent(X);
+
+ return 1;
+ }
+ case NXCollectGrabPointerNotify:
+ {
+ int resource = (int) X -> xclient.data.l[1];
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleProxyEvent: NXCollectGrabPointerNotify received with resource [%d].\n",
+ resource);
+ #endif
+
+ nxagentHandleCollectGrabPointerEvent(resource);
+
+ return 1;
+ }
+ case NXCollectInputFocusNotify:
+ {
+ int resource = (int) X -> xclient.data.l[1];
+
+ /*
+ * This is not used at the present moment.
+ */
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleProxyEvent: NXCollectInputFocusNotify received with resource [%d].\n",
+ resource);
+ #endif
+
+ nxagentHandleCollectInputFocusEvent(resource);
+
+ return 1;
+ }
+ default:
+ {
+ /*
+ * Not a recognized ClientMessage event.
+ */
+
+ #ifdef WARNING
+ fprintf(stderr, "nxagentHandleProxyEvent: WARNING! Not a recognized ClientMessage proxy event [%d].\n",
+ (int) X -> xclient.data.l[0]);
+ #endif
+
+ return 0;
+ }
+ }
+}
+
+/*
+ * In this function it is assumed that we never
+ * get a configure with both stacking order and
+ * geometry changed, this way we can ignore
+ * stacking changes if the geometry has changed.
+ */
+
+int nxagentCheckWindowConfiguration(XConfigureEvent* X)
+{
+ static int x = 0;
+ static int y = 0;
+ static int width = 0;
+ static int height = 0;
+ static Window win = None;
+ Bool geometryChanged = False;
+
+ XlibWindow root_return = 0;
+ XlibWindow parent_return = 0;
+ XlibWindow *children_return = NULL;
+ unsigned int nchildren_return = 0;
+ Status result;
+
+ WindowPtr pWin;
+
+ pWin = nxagentWindowPtr(X -> window);
+
+ /*
+ * This optimization has some problems to
+ * work in rootless mode inside NXWin. To
+ * verify this you can launch xterm and
+ * another application, f.e. firefox. By
+ * raising xterm above firefox, the stack
+ * order seems to become incoherent showing
+ * the underneath window content in the
+ * overlapping area when the mouse botton is
+ * pressed with the pointer inside of such area.
+ *
+ * if ((pWin != NULL) && X -> override_redirect == 0)
+ * {
+ * return 1;
+ * }
+ *
+ */
+
+ if (win == X -> window)
+ {
+ if (x != X -> x ||
+ y != X -> y ||
+ width != X -> width ||
+ height != X -> height)
+ {
+ geometryChanged = True;
+ }
+ }
+
+ win = X -> window;
+
+ x = X -> x;
+ y = X -> y;
+ width = X -> width;
+ height = X -> height;
+
+ if (geometryChanged)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentCheckWindowConfiguration: Configure frame. No restack.\n");
+ #endif
+
+ return 1;
+ }
+
+ #ifdef TEST
+ {
+ WindowPtr pSib;
+
+ fprintf(stderr, "nxagentCheckWindowConfiguration: Before restacking top level window [%p]\n",
+ (void *) nxagentWindowPtr(X -> window));
+
+ for (pSib = WindowTable[0] -> firstChild; pSib; pSib = pSib -> nextSib)
+ {
+ fprintf(stderr, "nxagentCheckWindowConfiguration: Top level window: [%p].\n",
+ (void *) pSib);
+ }
+ }
+ #endif
+
+ result = XQueryTree(nxagentDisplay, DefaultRootWindow(nxagentDisplay),
+ &root_return, &parent_return, &children_return, &nchildren_return);
+
+ if (result)
+ {
+ nxagentRootlessRestack(children_return, nchildren_return);
+ }
+ else
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentCheckWindowConfiguration: WARNING! Failed QueryTree request.\n");
+ #endif
+ }
+
+ if (result && nchildren_return)
+ {
+ XFree(children_return);
+ }
+
+ #if 0
+ fprintf(stderr, "nxagentCheckWindowConfiguration: Trees match: %s\n",
+ nxagentRootlessTreesMatch() ? "Yes" : "No");
+ #endif
+
+ return 1;
+}
+
+int nxagentHandleConfigureNotify(XEvent* X)
+{
+ if (nxagentOption(Rootless) == True)
+ {
+ ClientPtr pClient;
+ WindowPtr pWinWindow;
+ WindowPtr pWin;
+ xEvent x;
+ int sendEventAnyway = 0;
+
+ pWinWindow = nxagentWindowPtr(X -> xconfigure.window);
+
+ #ifdef TEST
+ {
+ WindowPtr pWinEvent = nxagentWindowPtr(X -> xconfigure.event);
+
+ fprintf(stderr, "nxagentHandleConfigureNotify: Generating window is [%p][%ld] target [%p][%ld].\n",
+ (void *) pWinEvent, X -> xconfigure.event, (void *) pWinWindow, X -> xconfigure.window);
+ }
+ #endif
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleConfigureNotify: New configuration for window [%p][%ld] is [%d][%d][%d][%d] "
+ "send_event [%i].\n", (void *) pWinWindow, X -> xconfigure.window,
+ X -> xconfigure.x, X -> xconfigure.y, X -> xconfigure.width,
+ X -> xconfigure.height, X -> xconfigure.send_event);
+ #endif
+
+ if ((pWin = nxagentRootlessTopLevelWindow(X -> xconfigure.window)) != NULL)
+ {
+ /*
+ * Cheking for new geometry or stacking order changes.
+ */
+
+ nxagentCheckWindowConfiguration((XConfigureEvent*)X);
+
+ return 1;
+ }
+
+ if (nxagentWindowTopLevel(pWinWindow) && !X -> xconfigure.override_redirect)
+ {
+ XID values[5];
+ Mask mask = 0;
+
+ register XID *value = values;
+
+ pClient = wClient(pWinWindow);
+
+ if (X -> xconfigure.send_event || !nxagentWMIsRunning ||
+ X -> xconfigure.override_redirect)
+ {
+ *value++ = (XID)X -> xconfigure.x;
+ *value++ = (XID)X -> xconfigure.y;
+
+ /*
+ * nxagentWindowPriv(pWinWindow)->x = X -> xconfigure.x;
+ * nxagentWindowPriv(pWinWindow)->y = X -> xconfigure.y;
+ */
+
+ mask |= CWX | CWY;
+ }
+
+ *value++ = (XID)X -> xconfigure.width;
+ *value++ = (XID)X -> xconfigure.height;
+ *value++ = (XID)X -> xconfigure.border_width;
+
+ /*
+ * We don't need width and height here.
+ *
+ * nxagentWindowPriv(pWinWindow)->width = X -> xconfigure.width;
+ * nxagentWindowPriv(pWinWindow)->height = X -> xconfigure.height;
+ */
+
+ mask |= CWHeight | CWWidth | CWBorderWidth;
+
+ nxagentScreenTrap = 1;
+
+ ConfigureWindow(pWinWindow, mask, (XID *) values, pClient);
+
+ nxagentScreenTrap = 0;
+
+ nxagentCheckWindowConfiguration((XConfigureEvent*)X);
+
+ /*
+ * This workaround should help with
+ * Java 1.6.0 that seems to ignore
+ * non-synthetic events.
+ */
+
+ if (nxagentOption(ClientOs) == ClientOsWinnt)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleConfigureNotify: Apply workaround for NXWin.\n");
+ #endif
+
+ sendEventAnyway = 1;
+ }
+
+ if (sendEventAnyway || X -> xconfigure.send_event)
+ {
+ x.u.u.type = X -> xconfigure.type;
+ x.u.u.type |= 0x80;
+
+ x.u.configureNotify.event = pWinWindow -> drawable.id;
+ x.u.configureNotify.window = pWinWindow -> drawable.id;
+
+ if (pWinWindow -> nextSib)
+ {
+ x.u.configureNotify.aboveSibling = pWinWindow -> nextSib -> drawable.id;
+ }
+ else
+ {
+ x.u.configureNotify.aboveSibling = None;
+ }
+
+ x.u.configureNotify.x = X -> xconfigure.x;
+ x.u.configureNotify.y = X -> xconfigure.y;
+ x.u.configureNotify.width = X -> xconfigure.width;
+ x.u.configureNotify.height = X -> xconfigure.height;
+ x.u.configureNotify.borderWidth = X -> xconfigure.border_width;
+ x.u.configureNotify.override = X -> xconfigure.override_redirect;
+
+ TryClientEvents(pClient, &x, 1, 1, 1, 0);
+ }
+
+ return 1;
+ }
+ }
+ else
+ {
+ /*
+ * Save the position of the agent default window. Don't
+ * save the values if the agent is in fullscreen mode.
+ *
+ * If we use these values to restore the position of a
+ * window after that we have dynamically changed the
+ * fullscreen attribute, depending on the behaviour of
+ * window manager, we could be not able to place the
+ * window exactly in the requested position, so let the
+ * window manager do the job for us.
+ */
+
+ ScreenPtr pScreen = nxagentScreen(X -> xconfigure.window);
+
+ Bool doRandR = False;
+ struct timeval timeout;
+
+ if (X -> xconfigure.window == nxagentDefaultWindows[pScreen -> myNum])
+ {
+ if (nxagentOption(Fullscreen) == 0)
+ {
+ if (nxagentOption(DesktopResize) == 1)
+ {
+ if (nxagentOption(Width) != X -> xconfigure.width ||
+ nxagentOption(Height) != X -> xconfigure.height)
+ {
+ Bool newEvents = False;
+
+ doRandR = True;
+
+ NXFlushDisplay(nxagentDisplay, NXFlushLink);
+
+ do
+ {
+ newEvents = False;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 500 * 1000;
+
+ nxagentWaitEvents(nxagentDisplay, &timeout);
+
+ /*
+ * This should also flush
+ * the NX link for us.
+ */
+
+ XSync(nxagentDisplay, 0);
+
+ while (XCheckTypedWindowEvent(nxagentDisplay, nxagentDefaultWindows[pScreen -> myNum],
+ ConfigureNotify, X))
+ {
+ newEvents = True;
+ }
+
+ } while (newEvents);
+ }
+ }
+
+ if (nxagentWMIsRunning == 0 || X -> xconfigure.send_event)
+ {
+ nxagentChangeOption(X, X -> xconfigure.x);
+ nxagentChangeOption(Y, X -> xconfigure.y);
+ }
+
+ if (nxagentOption(Shadow) == 1 && nxagentOption(DesktopResize) == 1 &&
+ (nxagentOption(Width) != X -> xconfigure.width ||
+ nxagentOption(Height) != X -> xconfigure.height))
+ {
+ nxagentShadowResize = 1;
+ }
+
+ nxagentChangeOption(Width, X -> xconfigure.width);
+ nxagentChangeOption(Height, X -> xconfigure.height);
+
+ nxagentChangeOption(ViewportXSpan, (int) X -> xconfigure.width -
+ (int) nxagentOption(RootWidth));
+ nxagentChangeOption(ViewportYSpan, (int) X -> xconfigure.height -
+ (int) nxagentOption(RootHeight));
+
+ nxagentMoveViewport(pScreen, 0, 0);
+
+ if (nxagentOption(Shadow) == 1 ||
+ (nxagentOption(Width) == nxagentOption(RootWidth) &&
+ nxagentOption(Height) == nxagentOption(RootHeight)))
+ {
+ doRandR = 0;
+ }
+
+ if (doRandR)
+ {
+ #ifdef TEST
+ fprintf(stderr,"nxagentHandleConfigureNotify: Width %d Height %d.\n",
+ nxagentOption(Width), nxagentOption(Height));
+ #endif
+
+ nxagentRRSetScreenConfig(screenInfo.screens[DefaultScreen(nxagentDisplay)],
+ nxagentOption(Width), nxagentOption(Height));
+ }
+ }
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int nxagentHandleReparentNotify(XEvent* X)
+{
+ ScreenPtr pScreen = nxagentScreen(X -> xreparent.window);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleReparentNotify: Going to handle a new reparent event.\n");
+ #endif
+
+ if (nxagentOption(Rootless))
+ {
+ WindowPtr pWin;
+
+ XlibWindow w;
+ XlibWindow root_return = 0;
+ XlibWindow parent_return = 0;
+ XlibWindow *children_return = NULL;
+ unsigned int nchildren_return = 0;
+ Status result;
+
+ pWin = nxagentWindowPtr(X -> xreparent.window);
+
+ #ifdef TEST
+
+ {
+ WindowPtr pParent = nxagentWindowPtr(X -> xreparent.parent);
+ WindowPtr pEvent = nxagentWindowPtr(X -> xreparent.event);
+
+ fprintf(stderr, "nxagentHandleReparentNotify: event %p[%lx] window %p[%lx] parent %p[%lx] at (%d, %d)\n",
+ (void*)pEvent, X -> xreparent.event, (void*)pWin, X -> xreparent.window,
+ (void*)pParent, X -> xreparent.parent, X -> xreparent.x, X -> xreparent.y);
+ }
+
+ #endif
+
+ if (nxagentWindowTopLevel(pWin))
+ {
+ /*
+ * If the window manager reparents our top level
+ * window, we need to know the new top level
+ * ancestor.
+ */
+
+ w = None;
+ parent_return = X -> xreparent.parent;
+
+ while (parent_return != RootWindow(nxagentDisplay, 0))
+ {
+ w = parent_return;
+ result = XQueryTree(nxagentDisplay, w, &root_return,
+ &parent_return, &children_return, &nchildren_return);
+
+ if (!result)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentHandleReparentNotify: WARNING! Failed QueryTree request.\n");
+ #endif
+ }
+
+ if (result && children_return)
+ {
+ XFree(children_return);
+ }
+ }
+
+ if (w && !nxagentWindowPtr(w))
+ {
+ XSelectInput(nxagentDisplay, w, StructureNotifyMask);
+
+ nxagentRootlessAddTopLevelWindow(pWin, w);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleReparentNotify: new top level window [%ld].\n", w);
+ fprintf(stderr, "nxagentHandleReparentNotify: reparented window [%ld].\n",
+ X -> xreparent.window);
+ #endif
+
+ result = XQueryTree(nxagentDisplay, DefaultRootWindow(nxagentDisplay),
+ &root_return, &parent_return, &children_return, &nchildren_return);
+
+ if (result)
+ {
+ nxagentRootlessRestack(children_return, nchildren_return);
+ }
+ else
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentHandleReparentNotify: WARNING! Failed QueryTree request.\n");
+ #endif
+ }
+
+ if (result && nchildren_return)
+ {
+ XFree(children_return);
+ }
+ }
+ else
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleReparentNotify: Window at [%p] has been reparented to [%ld]"
+ " top level parent [%ld].\n", (void *) pWin, X -> xreparent.parent, w);
+ #endif
+
+ nxagentRootlessDelTopLevelWindow(pWin);
+ }
+ }
+
+ return 1;
+ }
+ else
+ {
+ /*
+ * This code is supposed to detect if a window manager
+ * is running but in some cases it may be unreliable.
+ * Each window manager behaves differently so the check
+ * can fail for some less common WMs.
+ */
+
+ if (!nxagentWMIsRunning && nxagentOption(Fullscreen) &&
+ X -> xreparent.window == nxagentDefaultWindows[pScreen -> myNum])
+ {
+ #ifdef WARNING
+ fprintf(stderr, "Warning: The agent window was reparented. Is a "
+ "window manager running?\n");
+ #endif
+
+ /*
+ * If no window manager is running and we are supposed to
+ * be in fullscreen mode then don't wait for the reparent
+ * event. We can assume that there is an undetected window
+ * manager and, as switching to fullscreen could have fail-
+ * ed, we try it again.
+ */
+
+ nxagentSwitchFullscreen(pScreen, True);
+
+ nxagentWMIsRunning = True;
+ }
+ else if (nxagentWMIsRunning && X -> xreparent.window ==
+ nxagentDefaultWindows[pScreen -> myNum] && X -> xreparent.parent ==
+ RootWindow(nxagentDisplay, (pScreen -> myNum)))
+ {
+ #ifdef WARNING
+
+ fprintf(stderr, "Warning: The agent window has been reparented to the root.\n");
+
+ fprintf(stderr, "Warning: No window manager seems to be running.\n");
+
+ #endif
+
+ /*
+ * The agent window was unexpectedly reparented
+ * to the root window. We assume that the window
+ * manager was terminated.
+ */
+
+ nxagentWMIsRunning = False;
+ }
+ }
+
+ return 1;
+}
+
+void nxagentEnableKeyboardEvents()
+{
+ int i;
+ Mask mask;
+
+ nxagentGetDefaultEventMask(&mask);
+
+ mask |= NXAGENT_KEYBOARD_EVENT_MASK;
+
+ nxagentSetDefaultEventMask(mask);
+
+ for (i = 0; i < nxagentNumScreens; i++)
+ {
+ XSelectInput(nxagentDisplay, nxagentDefaultWindows[i], mask);
+ }
+
+ XkbSelectEvents(nxagentDisplay, XkbUseCoreKbd,
+ NXAGENT_KEYBOARD_EXTENSION_EVENT_MASK,
+ NXAGENT_KEYBOARD_EXTENSION_EVENT_MASK);
+}
+
+void nxagentDisableKeyboardEvents()
+{
+ int i;
+ Mask mask;
+
+ nxagentGetDefaultEventMask(&mask);
+
+ mask &= ~NXAGENT_KEYBOARD_EVENT_MASK;
+
+ nxagentSetDefaultEventMask(mask);
+
+ for (i = 0; i < nxagentNumScreens; i++)
+ {
+ XSelectInput(nxagentDisplay, nxagentDefaultWindows[i], mask);
+ }
+
+ XkbSelectEvents(nxagentDisplay, XkbUseCoreKbd, 0x0, 0x0);
+}
+
+void nxagentEnablePointerEvents()
+{
+ int i;
+ Mask mask;
+
+ nxagentGetDefaultEventMask(&mask);
+
+ mask |= NXAGENT_POINTER_EVENT_MASK;
+
+ nxagentSetDefaultEventMask(mask);
+
+ for (i = 0; i < nxagentNumScreens; i++)
+ {
+ XSelectInput(nxagentDisplay, nxagentDefaultWindows[i], mask);
+ }
+}
+
+void nxagentDisablePointerEvents()
+{
+ int i;
+ Mask mask;
+
+ nxagentGetDefaultEventMask(&mask);
+
+ mask &= ~NXAGENT_POINTER_EVENT_MASK;
+
+ nxagentSetDefaultEventMask(mask);
+
+ for (i = 0; i < nxagentNumScreens; i++)
+ {
+ XSelectInput(nxagentDisplay, nxagentDefaultWindows[i], mask);
+ }
+}
+
+void nxagentSendFakeKey(int key)
+{
+ xEvent fake;
+ Time now;
+
+ now = GetTimeInMillis();
+
+ fake.u.u.type = KeyPress;
+ fake.u.u.detail = key;
+ fake.u.keyButtonPointer.time = now;
+
+ mieqEnqueue(&fake);
+
+ fake.u.u.type = KeyRelease;
+ fake.u.u.detail = key;
+ fake.u.keyButtonPointer.time = now;
+
+ mieqEnqueue(&fake);
+}
+
+int nxagentInitKeyboardState()
+{
+ XEvent X;
+
+ unsigned int modifiers;
+
+ XkbEvent *xkbev = (XkbEvent *) &X;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentInitKeyboardState: Initializing XKB state.\n");
+ #endif
+
+ XkbGetIndicatorState(nxagentDisplay, XkbUseCoreKbd, &modifiers);
+
+ xkbev -> state.locked_mods = 0x0;
+
+ if (modifiers & CAPSFLAG_IN_REPLY)
+ {
+ xkbev -> state.locked_mods |= CAPSFLAG_IN_EVENT;
+ }
+
+ if (modifiers & NUMFLAG_IN_REPLY)
+ {
+ xkbev -> state.locked_mods |= NUMFLAG_IN_EVENT;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentInitKeyboardState: Assuming XKB locked modifier bits [%x].\n",
+ xkbev -> state.locked_mods);
+ #endif
+
+ xkbev -> type = nxagentXkbInfo.EventBase + XkbEventCode;
+ xkbev -> any.xkb_type = XkbStateNotify;
+
+ nxagentHandleKeyboardEvent(&X);
+
+ return 1;
+}
+
+int nxagentWaitForResource(GetResourceFuncPtr pGetResource, PredicateFuncPtr pPredicate)
+{
+ int resource;
+
+ while ((resource = (*pGetResource)(nxagentDisplay)) == -1)
+ {
+ if (nxagentWaitEvents(nxagentDisplay, NULL) == -1)
+ {
+ return -1;
+ }
+
+ nxagentDispatchEvents(pPredicate);
+ }
+
+ return resource;
+}
+
+void nxagentGrabPointerAndKeyboard(XEvent *X)
+{
+ unsigned long now;
+
+ int resource;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentGrabPointerAndKeyboard: Grabbing pointer and keyboard with event at [%p].\n",
+ (void *) X);
+ #endif
+
+ if (X != NULL)
+ {
+ now = X -> xcrossing.time;
+ }
+ else
+ {
+ now = CurrentTime;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentGrabPointerAndKeyboard: Going to grab the keyboard in context [B1].\n");
+ #endif
+
+ XGrabKeyboard(nxagentDisplay, nxagentFullscreenWindow,
+ True, GrabModeAsync, GrabModeAsync, now);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentGrabPointerAndKeyboard: Going to grab the pointer in context [B2].\n");
+ #endif
+
+ resource = nxagentWaitForResource(NXGetCollectGrabPointerResource,
+ nxagentCollectGrabPointerPredicate);
+
+ NXCollectGrabPointer(nxagentDisplay, resource,
+ nxagentFullscreenWindow, True, NXAGENT_POINTER_EVENT_MASK,
+ GrabModeAsync, GrabModeAsync, None, None, now);
+
+ /*
+ * This should not be needed.
+ *
+ * XGrabKey(nxagentDisplay, AnyKey, AnyModifier, nxagentFullscreenWindow,
+ * True, GrabModeAsync, GrabModeAsync);
+ */
+
+ if (X != NULL)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentGrabPointerAndKeyboard: Going to force focus in context [B4].\n");
+ #endif
+
+ XSetInputFocus(nxagentDisplay, nxagentFullscreenWindow,
+ RevertToParent, now);
+ }
+}
+
+void nxagentUngrabPointerAndKeyboard(XEvent *X)
+{
+ unsigned long now;
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentUngrabPointerAndKeyboard: Ungrabbing pointer and keyboard with event at [%p].\n",
+ (void *) X);
+ #endif
+
+ if (X != NULL)
+ {
+ now = X -> xcrossing.time;
+ }
+ else
+ {
+ now = CurrentTime;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentUngrabPointerAndKeyboard: Going to ungrab the keyboard in context [B5].\n");
+ #endif
+
+ XUngrabKeyboard(nxagentDisplay, now);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentGrabPointerAndKeyboard: Going to ungrab the pointer in context [B6].\n");
+ #endif
+
+ XUngrabPointer(nxagentDisplay, now);
+}
+
+void nxagentDeactivatePointerGrab()
+{
+ GrabPtr grab = inputInfo.pointer -> grab;
+
+ XButtonEvent X;
+
+ if (grab)
+ {
+ X.type = ButtonRelease;
+ X.serial = 0;
+ X.send_event = FALSE;
+ X.time = currentTime.milliseconds;
+ X.display = nxagentDisplay;
+ X.window = nxagentWindow(grab -> window);
+ X.root = RootWindow(nxagentDisplay, 0);
+ X.subwindow = 0;
+ X.x = X.y = X.x_root = X.y_root = 0;
+ X.state = 0x100;
+ X.button = 1;
+ X.same_screen = TRUE;
+
+ XPutBackEvent(nxagentDisplay, (XEvent*)&X);
+ }
+}
+
+Bool nxagentCollectGrabPointerPredicate(Display *display, XEvent *X, XPointer ptr)
+{
+ return (X -> xclient.window == 0 &&
+ X -> xclient.message_type == 0 &&
+ X -> xclient.format == 32 &&
+ X -> xclient.data.l[0] == NXCollectGrabPointerNotify);
+}
+
+void nxagentHandleCollectGrabPointerEvent(int resource)
+{
+ int status;
+
+ if (NXGetCollectedGrabPointer(nxagentDisplay, resource, &status) == 0)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentHandleCollectGrabPointerEvent: PANIC! Failed to get GrabPointer "
+ "reply for resource [%d].\n", resource);
+ #endif
+ }
+}
+
+void nxagentHandleCollectPropertyEvent(XEvent *X)
+{
+ Window window;
+ Atom property;
+ Atom atomReturnType;
+ int resultFormat;
+ unsigned long ulReturnItems;
+ unsigned long ulReturnBytesLeft;
+ unsigned char *pszReturnData = NULL;
+ int result;
+ int resource;
+
+ resource = X -> xclient.data.l[1];
+
+ if (X -> xclient.data.l[2] == False)
+ {
+ #ifdef DEBUG
+ fprintf (stderr, "nxagentHandleCollectPropertyEvent: Failed to get reply data for client [%d].\n",
+ resource);
+ #endif
+
+ return;
+ }
+
+ if (resource == nxagentLastClipboardClient)
+ {
+ nxagentCollectPropertyEvent(resource);
+ }
+ else
+ {
+ result = NXGetCollectedProperty(nxagentDisplay,
+ resource,
+ &atomReturnType,
+ &resultFormat,
+ &ulReturnItems,
+ &ulReturnBytesLeft,
+ &pszReturnData);
+
+ if (result == True)
+ {
+ window = nxagentPropertyRequests[resource].window;
+ property = nxagentPropertyRequests[resource].property;
+
+ nxagentImportProperty(window, property, atomReturnType, resultFormat,
+ ulReturnItems, ulReturnBytesLeft, pszReturnData);
+ }
+
+ if (result == 0)
+ {
+ #ifdef DEBUG
+ fprintf (stderr, "nxagentHandleCollectPropertyEvent: Failed to get reply data for client [%d].\n",
+ resource);
+ #endif
+ }
+
+ if (pszReturnData != NULL)
+ {
+ XFree(pszReturnData);
+ }
+
+ return;
+ }
+}
+
+void nxagentSynchronizeExpose(void)
+{
+ WindowPtr pWin;
+
+ if (nxagentExposeQueue.length <= 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeExpose: PANIC! Called with nxagentExposeQueue.length [%d].\n",
+ nxagentExposeQueue.length);
+ #endif
+
+ return;
+ }
+
+ pWin = nxagentExposeQueueHead.pWindow;
+
+ if (pWin)
+ {
+ if ((nxagentExposeQueueHead.localRegion) != NullRegion)
+ {
+ REGION_TRANSLATE(pWin -> drawable.pScreen, (nxagentExposeQueueHead.localRegion),
+ pWin -> drawable.x, pWin -> drawable.y);
+ }
+
+ if ((nxagentExposeQueueHead.remoteRegion) != NullRegion)
+ {
+ REGION_TRANSLATE(pWin -> drawable.pScreen, (nxagentExposeQueueHead.remoteRegion),
+ pWin -> drawable.x, pWin -> drawable.y);
+ }
+
+ if ((nxagentExposeQueueHead.localRegion) != NullRegion &&
+ (nxagentExposeQueueHead.remoteRegion) != NullRegion)
+ {
+ REGION_SUBTRACT(pWin -> drawable.pScreen, (nxagentExposeQueueHead.remoteRegion),
+ (nxagentExposeQueueHead.remoteRegion),
+ (nxagentExposeQueueHead.localRegion));
+
+ if (REGION_NIL(nxagentExposeQueueHead.remoteRegion) == 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentSynchronizeExpose: Going to call miWindowExposures"
+ " for window [%ld] - rects [%ld].\n", nxagentWindow(pWin),
+ REGION_NUM_RECTS(nxagentExposeQueueHead.remoteRegion));
+ #endif
+
+ miWindowExposures(pWin, nxagentExposeQueueHead.remoteRegion, NullRegion);
+ }
+ }
+ }
+
+ nxagentExposeQueueHead.pWindow = NULL;
+
+ if (nxagentExposeQueueHead.localRegion != NullRegion)
+ {
+ REGION_DESTROY(nxagentDefaultScreen, nxagentExposeQueueHead.localRegion);
+ }
+
+ nxagentExposeQueueHead.localRegion = NullRegion;
+
+ if (nxagentExposeQueueHead.remoteRegion != NullRegion)
+ {
+ REGION_DESTROY(nxagentDefaultScreen, nxagentExposeQueueHead.remoteRegion);
+ }
+
+ nxagentExposeQueueHead.remoteRegion = NullRegion;
+
+ nxagentExposeQueueHead.remoteRegionIsCompleted = False;
+
+ nxagentExposeQueue.start = (nxagentExposeQueue.start + 1) % EXPOSED_SIZE;
+
+ nxagentExposeQueue.length--;
+
+ return;
+}
+
+int nxagentLookupByWindow(WindowPtr pWin)
+{
+ int i;
+ int j;
+
+ for (j = 0; j < nxagentExposeQueue.length; j++)
+ {
+ i = (nxagentExposeQueue.start + j) % EXPOSED_SIZE;
+
+ if (nxagentExposeQueue.exposures[i].pWindow == pWin &&
+ !nxagentExposeQueue.exposures[i].remoteRegionIsCompleted)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void nxagentRemoveDuplicatedKeys(XEvent *X)
+{
+ _XQEvent *prev;
+ _XQEvent *qelt;
+
+ _XQEvent *qeltKeyRelease;
+ _XQEvent *prevKeyRelease;
+
+ KeyCode lastKeycode = X -> xkey.keycode;
+
+ qelt = nxagentDisplay -> head;
+
+ if (qelt == NULL)
+ {
+ #ifdef TEST
+
+ int more;
+
+ fprintf(stderr, "nxagentRemoveDuplicatedKeys: Trying to read more events "
+ "from the X server.\n");
+
+ more = nxagentReadEvents(nxagentDisplay);
+
+ if (more > 0)
+ {
+ fprintf(stderr, "nxagentRemoveDuplicatedKeys: Successfully read more events "
+ "from the X server.\n");
+ }
+
+ #else
+
+ nxagentReadEvents(nxagentDisplay);
+
+ #endif
+
+ qelt = nxagentDisplay -> head;
+ }
+
+ if (qelt != NULL)
+ {
+ prev = qeltKeyRelease = prevKeyRelease = NULL;
+
+ LockDisplay(nxagentDisplay);
+
+ while (qelt != NULL)
+ {
+ if (qelt -> event.type == KeyRelease ||
+ qelt -> event.type == KeyPress)
+ {
+ if (qelt -> event.xkey.keycode != lastKeycode ||
+ (qelt -> event.type == KeyPress && qeltKeyRelease == NULL) ||
+ (qelt -> event.type == KeyRelease && qeltKeyRelease != NULL))
+ {
+ break;
+ }
+
+ if (qelt -> event.type == KeyRelease)
+ {
+ prevKeyRelease = prev;
+
+ qeltKeyRelease = qelt;
+ }
+ else if (qelt -> event.type == KeyPress)
+ {
+ _XDeq(nxagentDisplay, prev, qelt);
+
+ qelt = prev -> next;
+
+ if (prev == qeltKeyRelease)
+ {
+ prev = prevKeyRelease;
+ }
+
+ _XDeq(nxagentDisplay, prevKeyRelease, qeltKeyRelease);
+
+ qeltKeyRelease = prevKeyRelease = NULL;
+
+ continue;
+ }
+ }
+
+ prev = qelt;
+
+ qelt = qelt -> next;
+ }
+
+ UnlockDisplay(nxagentDisplay);
+ }
+}
+
+void nxagentInitRemoteExposeRegion(void)
+{
+ if (nxagentRemoteExposeRegion == NULL)
+ {
+ nxagentRemoteExposeRegion = REGION_CREATE(pWin -> drawable.pScreen, NULL, 1);
+
+ if (nxagentRemoteExposeRegion == NULL)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentInitRemoteExposeRegion: PANIC! Failed to create expose region.\n");
+ #endif
+ }
+ }
+}
+
+void nxagentForwardRemoteExpose(void)
+{
+ if (REGION_NOTEMPTY(WindowTable[0] -> drawable.pScreen, nxagentRemoteExposeRegion))
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentForwardRemoteExpose: Going to forward events.\n");
+ #endif
+
+ TraverseTree(WindowTable[0], nxagentClipAndSendExpose, (void *)nxagentRemoteExposeRegion);
+
+ /*
+ * Now this region should be empty.
+ */
+
+ REGION_EMPTY(WindowTable[0] -> drawable.pScreen, nxagentRemoteExposeRegion);
+ }
+}
+
+void nxagentAddRectToRemoteExposeRegion(BoxPtr rect)
+{
+ RegionRec exposeRegion;
+
+ if (nxagentRemoteExposeRegion == NULL)
+ {
+ return;
+ }
+
+ REGION_INIT(nxagentDefaultScreen, &exposeRegion, rect, 1);
+
+ REGION_UNION(nxagentDefaultScreen, nxagentRemoteExposeRegion,
+ nxagentRemoteExposeRegion, &exposeRegion);
+
+ REGION_UNINIT(nxagentDefaultScreen, &exposeRegion);
+}
+
+int nxagentClipAndSendExpose(WindowPtr pWin, pointer ptr)
+{
+ RegionPtr exposeRgn;
+ RegionPtr remoteExposeRgn;
+ BoxRec box;
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentClipAndSendExpose: Called.\n");
+ #endif
+
+ remoteExposeRgn = (RegionRec *) ptr;
+
+ if (pWin -> drawable.class != InputOnly)
+ {
+ exposeRgn = REGION_CREATE(pWin -> drawable.pScreen, NULL, 1);
+
+ box = *REGION_EXTENTS(pWin->drawable.pScreen, remoteExposeRgn);
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentClipAndSendExpose: Root expose extents: [%d] [%d] [%d] [%d].\n",
+ box.x1, box.y1, box.x2, box.y2);
+ #endif
+
+ box = *REGION_EXTENTS(pWin->drawable.pScreen, &pWin -> clipList);
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentClipAndSendExpose: Clip list extents for window at [%p]: [%d] [%d] [%d] [%d].\n",
+ pWin, box.x1, box.y1, box.x2, box.y2);
+ #endif
+
+ REGION_INTERSECT(pWin -> drawable.pScreen, exposeRgn, remoteExposeRgn, &pWin -> clipList);
+
+ if (REGION_NOTEMPTY(pWin -> drawable.pScreen, exposeRgn))
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentClipAndSendExpose: Forwarding expose to window at [%p] pWin.\n",
+ pWin);
+ #endif
+
+ /*
+ * The miWindowExposures() clears out the
+ * region parameters, so the subtract ope-
+ * ration must be done before calling it.
+ */
+
+ REGION_SUBTRACT(pWin -> drawable.pScreen, remoteExposeRgn, remoteExposeRgn, exposeRgn);
+
+ miWindowExposures(pWin, exposeRgn, NullRegion);
+ }
+
+ REGION_DESTROY(pWin -> drawable.pScreen, exposeRgn);
+ }
+
+ if (REGION_NOTEMPTY(pWin -> drawable.pScreen, remoteExposeRgn))
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentClipAndSendExpose: Region not empty. Walk children.\n");
+ #endif
+
+ return WT_WALKCHILDREN;
+ }
+ else
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentClipAndSendExpose: Region empty. Stop walking.\n");
+ #endif
+
+ return WT_STOPWALKING;
+ }
+}
+
+int nxagentUserInput(void *p)
+{
+ int result = 0;
+
+ /*
+ * This function is used as callback in
+ * the polling handler of agent in shadow
+ * mode. When inside the polling loop the
+ * handlers are never called, so we have
+ * to dispatch enqueued events to eventu-
+ * ally change the nxagentInputEvent sta-
+ * tus.
+ */
+
+ if (nxagentOption(Shadow) == 1 &&
+ nxagentPendingEvents(nxagentDisplay) > 0)
+ {
+ nxagentDispatchEvents(NULL);
+ }
+
+ if (nxagentInputEvent == 1)
+ {
+ nxagentInputEvent = 0;
+
+ result = 1;
+ }
+
+ /*
+ * The agent working in shadow mode synch-
+ * ronizes the remote X server even if a
+ * button/key is not released (i.e. when
+ * scrolling a long browser's page), in
+ * order to update the screen smoothly.
+ */
+
+ if (nxagentOption(Shadow) == 1)
+ {
+ return result;
+ }
+
+ if (result == 0)
+ {
+ /*
+ * If there is at least one button/key down,
+ * we are receiving an input. This is not a
+ * condition to break a synchronization loop
+ * if there is enough bandwidth.
+ */
+
+ if (nxagentCongestion > 0 &&
+ (inputInfo.pointer -> button -> buttonsDown > 0 ||
+ nxagentKeyDown > 0))
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentUserInput: Buttons [%d] Keys [%d].\n",
+ inputInfo.pointer -> button -> buttonsDown, nxagentKeyDown);
+ #endif
+
+ result = 1;
+ }
+ }
+
+ return result;
+}
+
+int nxagentHandleRRScreenChangeNotify(XEvent *X)
+{
+ XRRScreenChangeNotifyEvent *Xr;
+
+ Xr = (XRRScreenChangeNotifyEvent *) X;
+
+ nxagentResizeScreen(screenInfo.screens[DefaultScreen(nxagentDisplay)], Xr -> width, Xr -> height,
+ Xr -> mwidth, Xr -> mheight);
+
+ nxagentShadowCreateMainWindow(screenInfo.screens[DefaultScreen(nxagentDisplay)], WindowTable[0],
+ Xr -> width, Xr -> height);
+
+ nxagentShadowSetWindowsSize();
+
+ return 1;
+}
+
+/*
+ * Returns true if there is any event waiting to
+ * be dispatched. This function is critical for
+ * the performance because it is called very,
+ * very often. It must also handle the case when
+ * the display is down. The display descriptor,
+ * in fact, may have been reused by some other
+ * client.
+ */
+
+int nxagentPendingEvents(Display *dpy)
+{
+ if (_XGetIOError(dpy) != 0)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentPendingEvents: Returning error with display down.\n");
+ #endif
+
+ return -1;
+ }
+ else if (XQLength(dpy) > 0)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentPendingEvents: Returning true with [%d] events queued.\n",
+ XQLength(dpy));
+ #endif
+
+ return 1;
+ }
+ else
+ {
+ int result;
+ int readable;
+
+ result = NXTransReadable(dpy -> fd, &readable);
+
+ if (result == 0)
+ {
+ if (readable > 0)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentPendingEvents: Returning true with [%d] bytes readable.\n",
+ readable);
+ #endif
+
+ return 1;
+ }
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentPendingEvents: Returning false with [%d] bytes readable.\n",
+ readable);
+ #endif
+
+ return 0;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentPendingEvents: WARNING! Error detected on the X display.\n");
+ #endif
+
+ NXForceDisplayError(dpy);
+
+ return -1;
+ }
+}
+
+/*
+ * Blocks until an event becomes
+ * available.
+ */
+
+int nxagentWaitEvents(Display *dpy, struct timeval *tm)
+{
+ XEvent ev;
+
+ NXFlushDisplay(dpy, NXFlushLink);
+
+ /*
+ * If the transport is not running we
+ * have to rely on Xlib to wait for an
+ * event. In this case the timeout is
+ * ignored.
+ */
+
+ if (NXTransRunning(NX_FD_ANY) == 1)
+ {
+ NXTransContinue(tm);
+ }
+ else
+ {
+ XPeekEvent(dpy, &ev);
+ }
+
+ /*
+ * Check if we encountered a display
+ * error. If we did, wait for the
+ * time requested by the caller.
+ */
+
+ if (NXDisplayError(dpy) == 1)
+ {
+ if (tm != NULL)
+ {
+ usleep(tm -> tv_sec * 1000 * 1000 +
+ tm -> tv_usec);
+ }
+
+ return -1;
+ }
+
+ return 1;
+}