2025-08-08 20:00:36 +02:00

4749 lines
129 KiB
C

/**************************************************************************/
/* */
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
/* Copyright (c) 2008-2017 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
/* Copyright (c) 2011-2022 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
/* Copyright (c) 2014-2019 Mihai Moldovan <ionic@ionic.de> */
/* Copyright (c) 2014-2022 Ulrich Sibiller <uli42@gmx.de> */
/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */
/* */
/* NXAGENT, NX protocol compression and NX extensions to this software */
/* are copyright of the aforementioned persons and companies. */
/* */
/* Redistribution and use of the present software is allowed according */
/* to terms specified in the file LICENSE which comes in the source */
/* distribution. */
/* */
/* All rights reserved. */
/* */
/* NOTE: This software has received contributions from various other */
/* contributors, only the core maintainers and supporters are listed as */
/* copyright holders. Please contact us, if you feel you should be listed */
/* as copyright holder, as well. */
/* */
/**************************************************************************/
#include "X.h"
#include "signal.h"
#include "unistd.h"
#include "Xproto.h"
#include "screenint.h"
#include "input.h"
#include "dix.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 "Error.h"
#include <nx/NX.h>
#include <nx/NXvars.h>
#include <nx/NXproto.h>
#include "xfixesproto.h"
#define Window XlibWindow
#define Atom XlibAtom
#define Time XlibXID
#include "X11/include/Xfixes_nxagent.h"
#undef Window
#undef Atom
#undef Time
#ifdef NXAGENT_FIXKEYS
#include "inputstr.h"
#include "input.h"
#endif
#define Time XlibXID
#include "XKBlib.h"
#undef Time
#define GC XlibGC
#define Font XlibFont
#define KeySym XlibKeySym
#define XID XlibXID
#include "Xlibint.h"
#undef GC
#undef Font
#undef KeySym
#undef XID
#include <nx-X11/cursorfont.h>
#include <nx/Shadow.h>
#include "X11/include/Xrandr_nxagent.h"
#include "compext/Compext.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
/* debug individual subsystems */
#undef DEBUG_AUTOGRAB
/* aktivate subsystems if generic DEBUG is activated */
#ifdef DEBUG
#ifndef DEBUG_AUTOGRAB
#define DEBUG_AUTOGRAB
#endif
#endif
/*
* Log begin and end of the important handlers.
*/
#undef BLOCKS
extern Bool nxagentOnce;
#ifdef NX_DEBUG_INPUT
int nxagentDebugInput = 0;
#endif
#ifdef DEBUG
extern Bool nxagentRootlessTreesMatch(void);
#endif
extern Selection *CurrentSelections;
extern int NumCurrentSelections;
typedef union _XFixesSelectionEvent {
int type;
XFixesSelectionNotifyEvent xfixesselection;
XEvent core;
} XFixesSelectionEvent;
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 *disp, 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;
#define MAX_INC 200
#define INC_STEP 5
#define nextinc(x) ((x) < MAX_INC ? (x) += INC_STEP : (x))
/*
* 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;
static int lastEventSerial = 0;
/*
* 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, void * ptr);
/*
* This is from NXproperty.c.
*/
int GetWindowProperty(WindowPtr pWin, Atom property, long longOffset,
long longLength, Bool delete, Atom type,
Atom *actualType, int *format, unsigned
long *nItems, unsigned long *bytesAfter,
unsigned char **propData);
/*
* 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(void)
{
#ifdef NX_DEBUG_INPUT
if (nxagentDebugInput == 1)
{
fprintf(stderr, "%s: Processing input.\n", __func__);
}
#endif
mieqProcessInputEvents();
}
#ifdef DEBUG
char * nxagentGetNotifyMode(int mode)
{
switch (mode)
{
case NotifyNormal: return "NotifyNormal";
case NotifyGrab: return "NotifyGrab";
case NotifyUngrab: return "NotifyUngrab";
case NotifyWhileGrabbed: return "NotifyWhileGrabbed";
}
return "Unknown";
}
#endif
#ifdef DEBUG_TREE
/*
* Print ID and name of window.
*/
void nxagentRemoteWindowID(Window window, Bool newline)
{
#ifdef NO_I18N
char *winName;
#else
XTextProperty tp;
#endif
fprintf(stderr, "0x%x", window);
if (!window)
{
fprintf(stderr, " (none) ");
}
else
{
if (window == DefaultRootWindow(nxagentDisplay))
{
fprintf(stderr, " (the root window) ");
}
#ifdef NO_I18N
if (!XFetchName(nxagentDisplay, window, &winName))
{
fprintf(stderr, " (has no name) ");
}
else if (winName)
{
fprintf(stderr, " \"%s\" ", winName);
SAFE_XFree(winName);
}
#else
if (XGetWMName(nxagentDisplay, window, &tp) == 0)
{
fprintf(stderr, " (has no name) ");
}
else if (tp.nitems > 0)
{
fprintf(stderr, " \"");
int count = 0;
char **list = NULL;
int ret = XmbTextPropertyToTextList(nxagentDisplay, &tp, &list, &count);
if ((ret == Success || ret > 0) && list != NULL)
{
for (int i = 0; i < count; i++)
{
fprintf(stderr, "%s", list[i]);
}
XFreeStringList(list);
}
else
{
fprintf(stderr, "%s", tp.value);
}
fprintf(stderr, "\" ");
}
#endif
else
{
fprintf(stderr, " (has no name) ");
}
}
if (newline)
{
fprintf(stderr, "\n");
}
return;
}
/*
* Print info about remote window.
*/
void nxagentRemoteWindowInfo(Window win, int indent, Bool newLine)
{
XWindowAttributes attributes;
if (XGetWindowAttributes(nxagentDisplay, win, &attributes) == 0)
{
return;
}
fprintf(stderr, "%*sx=%d y=%d width=%d height=%d class=%s map_state=%s "
"override_redirect=%s\n", indent, "", attributes.x, attributes.y,
attributes.width, attributes.height,
(attributes.class == 0) ? "CopyFromParent" :
((attributes.class == 1) ? "InputOutput" : "InputOnly"),
(attributes.map_state == 0) ?
"IsUnmapped" : (attributes.map_state == 1 ?
"IsUnviewable" : "IsViewable"),
(attributes.override_redirect == 0) ?
"No" : "Yes" );
if (newLine)
{
fprintf(stderr, "\n");
}
}
/*
* Walk remote windows tree.
*
* FIXME:
* ========== nxagentRemoteWindowsTree ============
*
* Root Window ID: 0x169 (the root window) (has no name)
* Parent window ID: 0x2a00063 "NX Agent"
* 0 children.
*
* ========== nxagentInternalWindowsTree ==========
* Window ID=[0x9d] Remote ID=[0x2a0007e] Name: ( has no name )
* x=0 y=0 width=1440 height=810 class=InputOutput map_state=IsViewable override_redirect=No
*
* -> Internal root window's remote id is not listed in RemoteWindowsTree.
*/
void nxagentRemoteWindowsTree(Window window, int level)
{
unsigned long rootWin, parentWin;
unsigned int numChildren;
unsigned long *childList = NULL;
if (!XQueryTree(nxagentDisplay, window, &rootWin, &parentWin, &childList,
&numChildren))
{
fprintf(stderr, "%s - XQueryTree failed.\n", __func__);
return;
}
if (level == 0)
{
fprintf(stderr, "\n");
fprintf(stderr, " Root Window ID: ");
nxagentRemoteWindowID(rootWin, TRUE);
fprintf(stderr, " Parent window ID: ");
nxagentRemoteWindowID(parentWin, TRUE);
}
if (level == 0 || numChildren > 0)
{
fprintf(stderr, "%*s", (level * 4) + 5, ""); /* 4 spaces per level */
fprintf(stderr, "%d child%s%s\n", numChildren, (numChildren == 1) ? "" :
"ren", (numChildren == 1) ? ":" : ".");
}
for (int i = (int) numChildren - 1; i >= 0; i--)
{
fprintf(stderr, "%*s", (level * 5) + 6, ""); /* 5 spaces per level */
nxagentRemoteWindowID(childList[i], TRUE);
nxagentRemoteWindowInfo(childList[i], (level * 5) + 6, TRUE);
nxagentRemoteWindowsTree(childList[i], level + 1);
}
SAFE_XFree(childList);
}
/*
* Print info about internal window.
*/
void nxagentInternalWindowInfo(WindowPtr pWin, int indent, Bool newLine)
{
unsigned long ulReturnItems;
unsigned long ulReturnBytesLeft;
Atom atomReturnType;
int iReturnFormat;
unsigned char *pszReturnData = NULL;
fprintf(stderr, "Window ID=[0x%x] %s Remote ID=[0x%x] ", pWin -> drawable.id,
pWin->parent ? "" : "(the root window)", nxagentWindow(pWin));
int result = GetWindowProperty(pWin, MakeAtom("WM_NAME", 7, False) , 0,
sizeof(CARD32), False, AnyPropertyType,
&atomReturnType, &iReturnFormat,
&ulReturnItems, &ulReturnBytesLeft,
&pszReturnData);
fprintf(stderr, "Name: ");
if (result == Success && pszReturnData != NULL)
{
fprintf(stderr, "\"%*.*s\"\n", (int)ulReturnItems, (int)ulReturnItems, (char *) pszReturnData);
}
else
{
fprintf(stderr, "%s\n", "( has no name )");
}
fprintf(stderr, "%*sx=%d y=%d width=%d height=%d class=%s map_state=%s "
"override_redirect=%s", indent, "", pWin -> drawable.x, pWin -> drawable.y,
pWin -> drawable.width, pWin -> drawable.height,
(pWin -> drawable.class == 0) ? "CopyFromParent" :
((pWin -> drawable.class == 1) ? "InputOutput" :
"InputOnly"),
(pWin -> mapped == 0) ?
"IsUnmapped" : (pWin -> realized == 0 ?
"IsUnviewable" : "IsViewable"),
(pWin -> overrideRedirect == 0) ?
"No" : "Yes");
if (newLine)
{
fprintf(stderr, "\n");
}
}
/*
* Walk internal windows tree.
*/
void nxagentInternalWindowsTree(WindowPtr pWin, int indent)
{
for (; pWin; pWin = pWin -> nextSib)
{
fprintf(stderr, "%*s", indent, "");
nxagentInternalWindowInfo(pWin, indent, TRUE);
fprintf(stderr, "\n");
nxagentInternalWindowsTree(pWin -> firstChild, indent + 4);
}
}
#endif /* DEBUG_TREE */
void nxagentSwitchResizeMode(ScreenPtr pScreen)
{
#ifdef DEBUG
fprintf(stderr, "%s: Called.\n", __func__);
#endif
int desktopResize = nxagentOption(DesktopResize);
nxagentChangeOption(DesktopResize, !desktopResize);
if (!nxagentOption(DesktopResize))
{
fprintf(stderr,"Info: Disabled desktop resize mode in agent.\n");
nxagentLaunchDialog(DIALOG_DISABLE_DESKTOP_RESIZE_MODE);
if (!nxagentOption(Fullscreen))
{
nxagentSetWMNormalHintsMaxsize(pScreen,
nxagentOption(RootWidth),
nxagentOption(RootHeight));
}
}
else
{
fprintf(stderr,"Info: Enabled desktop resize mode in agent.\n");
nxagentLaunchDialog(DIALOG_ENABLE_DESKTOP_RESIZE_MODE);
nxagentChangeScreenConfig(0, nxagentOption(Width), nxagentOption(Height), True);
if (nxagentOption(ClientOs) == ClientOsWinnt)
{
NXSetExposeParameters(nxagentDisplay, 0, 0, 0);
}
nxagentSetWMNormalHintsMaxsize(pScreen,
WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)),
HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)));
}
}
void nxagentShadowSwitchResizeMode(ScreenPtr pScreen)
{
int desktopResize = nxagentOption(DesktopResize);
nxagentChangeOption(DesktopResize, !desktopResize);
if (!nxagentOption(DesktopResize))
{
nxagentShadowSetRatio(1.0, 1.0);
nxagentShadowCreateMainWindow(screenInfo.screens[DefaultScreen(nxagentDisplay)], screenInfo.screens[0]->root,
screenInfo.screens[0]->root -> drawable.width, screenInfo.screens[0]->root -> drawable.height);
nxagentSetWMNormalHintsMaxsize(pScreen,
nxagentOption(RootWidth),
nxagentOption(RootHeight));
fprintf(stderr,"Info: Disabled resize mode in shadow agent.\n");
}
else
{
nxagentShadowSetRatio(nxagentOption(Width) * 1.0 /
screenInfo.screens[0]->root -> drawable.width,
nxagentOption(Height) * 1.0 /
screenInfo.screens[0]->root -> drawable.height);
nxagentShadowCreateMainWindow(screenInfo.screens[DefaultScreen(nxagentDisplay)],
screenInfo.screens[0]->root, screenInfo.screens[0]->root -> drawable.width,
screenInfo.screens[0]->root -> drawable.height);
nxagentSetWMNormalHintsMaxsize(pScreen,
WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)),
HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)));
fprintf(stderr,"Info: Enabled resize mode in shadow agent.\n");
}
}
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 = True;
}
}
static void nxagentEnableAutoGrab(void)
{
#ifdef DEBUG_AUTOGRAB
fprintf(stderr, "enabling autograb\n");
#endif
nxagentGrabPointerAndKeyboard(NULL);
nxagentChangeOption(AutoGrab, True);
nxagentLaunchDialog(DIALOG_ENABLE_AUTOGRAB_MODE);
}
static void nxagentDisableAutoGrab(void)
{
#ifdef DEBUG_AUTOGRAB
fprintf(stderr, "disabling autograb\n");
#endif
nxagentUngrabPointerAndKeyboard(NULL);
nxagentChangeOption(AutoGrab, False);
nxagentLaunchDialog(DIALOG_DISABLE_AUTOGRAB_MODE);
}
static void nxagentToggleAutoGrab(void)
{
/* autograb only works in windowed mode */
if (nxagentOption(Rootless) || nxagentOption(Fullscreen))
return;
if (!nxagentOption(AutoGrab))
nxagentEnableAutoGrab();
else
nxagentDisableAutoGrab();
}
static Bool nxagentExposurePredicate(Display *disp, 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 *disp, XEvent *event, XPointer parameter)
{
return 1;
}
int nxagentInputEventPredicate(Display *disp, XEvent *event, XPointer parameter)
{
switch (event -> type)
{
case KeyPress:
case KeyRelease:
case ButtonPress:
case ButtonRelease:
{
return 1;
}
default:
{
return 0;
}
}
}
void nxagentInitDefaultEventMask(void)
{
Mask mask = NoEventMask;
mask |= (StructureNotifyMask | VisibilityChangeMask);
mask |= ExposureMask;
mask |= NXAGENT_KEYBOARD_EVENT_MASK;
mask |= NXAGENT_POINTER_EVENT_MASK;
defaultEventMask = mask;
}
Mask nxagentGetDefaultEventMask(void)
{
return defaultEventMask;
}
void nxagentSetDefaultEventMask(Mask mask)
{
defaultEventMask = mask;
}
Mask nxagentGetEventMask(WindowPtr pWin)
{
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;
}
return mask;
}
static int nxagentChangeMapPrivate(WindowPtr pWin, void * ptr)
{
if (pWin && nxagentWindowPriv(pWin))
{
nxagentWindowPriv(pWin) -> isMapped = *((Bool *) ptr);
}
return WT_WALKCHILDREN;
}
static int nxagentChangeVisibilityPrivate(WindowPtr pWin, void * 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 closeSession = False;
Bool switchFullscreen = False;
Bool switchAllScreens = False;
/*
* Last entered top level window.
*/
static WindowPtr nxagentLastEnteredTopLevelWindow = NULL;
#ifdef BLOCKS
fprintf(stderr, "[Begin read]\n");
#endif
#ifdef TEST
fprintf(stderr, "%s: Going to handle new events with predicate [%p].\n", __func__,
*(void **)&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, "%s: PANIC! No event needs to be dispatched.\n", __func__);
}
#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, "%s: Going to handle new event type [%d].\n", __func__,
X.type);
#endif
/*
* Handle the incoming event.
*/
switch (X.type)
{
#ifdef NXAGENT_CLIPBOARD
case SelectionClear:
{
#ifdef TEST
fprintf(stderr, "%s: Going to handle new SelectionClear event.\n", __func__);
#endif
nxagentHandleSelectionClearFromXServer(&X);
break;
}
case SelectionRequest:
{
#ifdef TEST
fprintf(stderr, "%s: Going to handle new SelectionRequest event.\n", __func__);
#endif
nxagentHandleSelectionRequestFromXServer(&X);
break;
}
case SelectionNotify:
{
#ifdef TEST
fprintf(stderr, "%s: Going to handle new SelectionNotify event.\n", __func__);
#endif
nxagentHandleSelectionNotifyFromXServer(&X);
break;
}
#endif /* NXAGENT_CLIPBOARD */
case PropertyNotify:
{
#ifdef TEST
fprintf(stderr, "%s: PropertyNotify on prop %d[%s] window %lx state %d\n", __func__,
(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;
#ifdef TEST
fprintf(stderr, "%s: Going to handle new KeyPress event.\n", __func__);
#endif
nxagentInputEvent = 1;
nxagentKeyDown++;
nxagentHandleKeyPress(&X, &result);
if (viewportLastKeyPressResult != result)
{
viewportInc = 1;
viewportLastKeyPressResult = result;
}
if (result != doNothing)
{
pScreen = nxagentScreen(X.xkey.window);
}
switch (result)
{
case doNothing:
{
break;
}
#ifdef DEBUG_TREE
case doDebugTree:
{
fprintf(stderr, "\n========== nxagentRemoteWindowsTree ============\n");
nxagentRemoteWindowsTree(nxagentWindow(screenInfo.screens[0]->root), 0);
fprintf(stderr, "\n========== nxagentInternalWindowsTree ==========\n");
nxagentInternalWindowsTree(screenInfo.screens[0]->root, 0);
break;
}
#endif /* DEBUG_TREE */
case doCloseSession:
{
closeSession = TRUE;
break;
}
case doMinimize:
{
minimize = TRUE;
break;
}
case doSwitchFullscreen:
{
switchFullscreen = TRUE;
break;
}
case doSwitchAllScreens:
{
switchAllScreens = TRUE;
break;
}
case doViewportMoveUp:
{
nxagentMoveViewport(pScreen, 0, -nxagentOption(Height));
break;
}
case doViewportMoveDown:
{
nxagentMoveViewport(pScreen, 0, nxagentOption(Height));
break;
}
case doViewportMoveLeft:
{
nxagentMoveViewport(pScreen, -nxagentOption(Width), 0);
break;
}
case doViewportMoveRight:
{
nxagentMoveViewport(pScreen, nxagentOption(Width), 0);
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))
{
if (nxagentNoDialogIsRunning)
{
nxagentSwitchResizeMode(pScreen);
}
}
else
{
nxagentShadowSwitchResizeMode(pScreen);
}
break;
}
case doSwitchDeferMode:
{
if (nxagentNoDialogIsRunning)
{
nxagentSwitchDeferMode();
}
break;
}
case doAutoGrab:
{
nxagentToggleAutoGrab();
break;
}
case doDumpClipboard:
{
nxagentDumpClipboardStat();
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 latency on the key auto-repeat, handled by
* the remote X server. We may optionally do that only if the
* timestamps in the events show an exces- sive delay.
*/
KeySym keysym = XKeycodeToKeysym(nxagentDisplay, X.xkey.keycode, 0);
if (nxagentMonitoredDuplicate(keysym) == 1)
{
nxagentRemoveDuplicatedKeys(&X);
}
if (!nxagentOption(ViewOnly) && nxagentOption(Shadow) && result == doNothing)
{
X.xkey.keycode = nxagentConvertKeycode(X.xkey.keycode);
NXShadowEvent(nxagentDisplay, X);
}
break;
}
case KeyRelease:
{
enum HandleEventResult result;
int sendKey = 0;
/*
FIXME: If we don't flush the queue here, it could happen that the
inputInfo structure will not be up to date when we perform the
following check on down keys.
*/
ProcessInputEvents();
/*
FIXME: Don't enqueue the KeyRelease event if the key was not already
pressed. This workaround avoids a fake KeyPress being enqueued
by the XKEYBOARD extension. Another solution would be to let
the events enqueued and to remove the KeyPress afterwards.
*/
if (BitIsOn(inputInfo.keyboard -> key -> down,
nxagentConvertKeycode(X.xkey.keycode)))
{
sendKey = 1;
}
#ifdef TEST
fprintf(stderr, "%s: Going to handle new KeyRelease event.\n", __func__);
#endif
nxagentInputEvent = 1;
nxagentKeyDown--;
if (nxagentKeyDown <= 0)
{
nxagentKeyDown = 0;
}
if (!nxagentXkbState.Initialized)
{
if (X.xkey.keycode == nxagentCapsLockKeycode)
{
nxagentXkbCapsTrap = True;
}
else if (X.xkey.keycode == nxagentNumLockKeycode)
{
nxagentXkbNumTrap = True;
}
nxagentInitXkbKeyboardState();
nxagentXkbCapsTrap = False;
nxagentXkbNumTrap = False;
}
/* Calculate the time elapsed between this and the last event
we received. Add this delta to time we recorded for the
last KeyPress event we passed on to our clients. */
memset(&x, 0, sizeof(xEvent));
x.u.u.type = KeyRelease;
x.u.u.detail = nxagentConvertKeycode(X.xkey.keycode);
x.u.keyButtonPointer.time = nxagentLastKeyPressTime +
(X.xkey.time - nxagentLastServerTime);
nxagentLastServerTime = X.xkey.time;
nxagentLastEventTime = GetTimeInMillis();
if (x.u.keyButtonPointer.time > nxagentLastEventTime)
{
x.u.keyButtonPointer.time = nxagentLastEventTime;
}
/* do not send a KeyRelease for a special keystroke since we
also did not send a KeyPress event in that case */
if (!(nxagentCheckSpecialKeystroke(&X.xkey, &result)) && (sendKey == 1))
{
#ifdef TEST
fprintf(stderr, "%s: passing KeyRelease event to clients\n", __func__);
#endif
mieqEnqueue(&x);
CriticalOutputPending = 1;
if (!nxagentOption(ViewOnly) && nxagentOption(Shadow))
{
X.xkey.keycode = nxagentConvertKeycode(X.xkey.keycode);
NXShadowEvent(nxagentDisplay, X);
}
}
else
{
#ifdef TEST
fprintf(stderr, "%s: NOT passing KeyRelease event to clients\n", __func__);
#endif
}
break;
}
case ButtonPress:
{
#ifdef NX_DEBUG_INPUT
if (nxagentDebugInput == 1)
{
fprintf(stderr, "%s: Going to handle new ButtonPress event.\n", __func__);
}
#endif
nxagentInputEvent = 1;
if (nxagentOption(Fullscreen))
{
if ( nxagentOption(MagicPixel) && nxagentMagicPixelZone(X.xbutton.x, X.xbutton.y) )
{
pScreen = nxagentScreen(X.xbutton.window);
minimize = True;
break;
}
}
if (!nxagentOption(DesktopResize) &&
(X.xbutton.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
{
/*
* Start viewport navigation mode.
*/
int resource = nxagentWaitForResource(NXGetCollectGrabPointerResource,
nxagentCollectGrabPointerPredicate);
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))
{
memset(&x, 0, sizeof(xEvent));
x.u.u.type = ButtonPress;
x.u.u.detail = inputInfo.pointer -> button -> map[nxagentReversePointerMap[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);
}
#ifdef NX_DEBUG_INPUT
if (nxagentDebugInput == 1)
{
fprintf(stderr, "%s: Adding ButtonPress event.\n", __func__);
}
#endif
mieqEnqueue(&x);
CriticalOutputPending = 1;
}
if (!nxagentOption(ViewOnly) && 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 NX_DEBUG_INPUT
if (nxagentDebugInput == 1)
{
fprintf(stderr, "%s: Going to handle new ButtonRelease event.\n", __func__);
}
#endif
nxagentInputEvent = 1;
if (viewportCursor)
{
/*
* Leave viewport navigation mode.
*/
XUngrabPointer(nxagentDisplay, CurrentTime);
XFreeCursor(nxagentDisplay, viewportCursor);
viewportCursor = None;
}
if (minimize != True)
{
memset(&x, 0, sizeof(xEvent));
x.u.u.type = ButtonRelease;
x.u.u.detail = inputInfo.pointer -> button -> map[nxagentReversePointerMap[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);
}
#ifdef NX_DEBUG_INPUT
if (nxagentDebugInput == 1)
{
fprintf(stderr, "%s: Adding ButtonRelease event.\n", __func__);
}
#endif
mieqEnqueue(&x);
CriticalOutputPending = 1;
}
if (!nxagentOption(ViewOnly) && 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:
{
pScreen = nxagentScreen(X.xmotion.window);
#ifdef TEST
fprintf(stderr, "%s: Going to handle new MotionNotify event.\n", __func__);
#endif
#ifdef NX_DEBUG_INPUT
if (nxagentDebugInput == 1)
{
fprintf(stderr, "%s: Handling motion notify window [%ld] root [%ld] child [%ld].\n",
__func__, X.xmotion.window, X.xmotion.root, X.xmotion.subwindow);
fprintf(stderr, "%s: Pointer at [%d][%d] relative root [%d][%d].\n", __func__,
X.xmotion.x, X.xmotion.y, X.xmotion.x_root, X.xmotion.y_root);
}
#endif
memset(&x, 0, sizeof(xEvent));
x.u.u.type = MotionNotify;
if (nxagentOption(Rootless))
{
WindowPtr pWin = nxagentWindowPtr(X.xmotion.window);
if (pWin)
{
nxagentLastEnteredWindow = pWin;
}
if (nxagentPulldownDialogPid == 0 && nxagentLastEnteredTopLevelWindow &&
(X.xmotion.y_root < nxagentLastEnteredTopLevelWindow -> drawable.y + 4))
{
if (pWin && nxagentClientIsDialog(wClient(pWin)) == 0 &&
nxagentLastEnteredTopLevelWindow -> parent == screenInfo.screens[0]->root &&
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))
{
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))
{
#ifdef NX_DEBUG_INPUT
if (nxagentDebugInput == 1)
{
fprintf(stderr, "%s: Adding motion event [%d, %d] to the queue.\n", __func__,
x.u.keyButtonPointer.rootX, x.u.keyButtonPointer.rootY);
}
#endif
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) && 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))
{
nxagentInputEvent = 1;
}
break;
}
case FocusIn:
{
WindowPtr pWin;
#ifdef DEBUG
fprintf(stderr, "%s: Going to handle new FocusIn event [0x%lx] 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%lx] Focus owner [0x%lx] 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
/*
* Here we change the focus state in the agent. It looks like
* this is needed only for rootless mode at present.
*/
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);
}
}
if (nxagentOption(AutoGrab) && !(nxagentOption(AllScreens) || nxagentOption(Fullscreen) || nxagentOption(Rootless)))
{
if (X.xfocus.window == nxagentDefaultWindows[0] && X.xfocus.mode == NotifyNormal)
{
#if defined(DEBUG) || defined(DEBUG_AUTOGRAB)
fprintf(stderr, "%s: (FocusIn): grabbing\n", __func__);
#endif
nxagentGrabPointerAndKeyboard(NULL);
}
/* else
{
#if defined(DEBUG) || defined(DEBUG_AUTOGRAB)
fprintf(stderr, "%s: (FocusIn): ungrabbing\n", __func__);
#endif
nxagentUngrabPointerAndKeyboard(NULL);
}
*/
}
break;
}
case FocusOut:
{
#ifdef DEBUG
fprintf(stderr, "%s: Going to handle new FocusOut event [0x%lx] 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)
{
pScreen = nxagentScreen(X.xfocus.window);
if (pScreen)
{
nxagentDirectUninstallColormaps(pScreen);
}
}
#ifdef NXAGENT_FIXKEYS
{
/*
* Force the keys all up when focus is lost.
*/
for (int i = 0; i < DOWN_LENGTH; i++) /* input.h */
{
CARD8 val = inputInfo.keyboard->key->down[i];
if (val != 0)
{
for (int k = 0; k < 8; k++)
{
if (val & (1 << 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])
{
memset(&x, 0, sizeof(xEvent));
x.u.u.type = KeyRelease;
x.u.u.detail = i * 8 + k;
x.u.keyButtonPointer.time = nxagentLastEventTime = GetTimeInMillis();
if (!nxagentOption(ViewOnly) && nxagentOption(Shadow))
{
XEvent xM = {0};
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 */
if (nxagentOption(AutoGrab) && !nxagentFullscreenWindow)
{
XlibWindow w;
int revert_to;
XGetInputFocus(nxagentDisplay, &w, &revert_to);
if (w != nxagentDefaultWindows[0] && X.xfocus.mode == NotifyWhileGrabbed)
{
#if defined(DEBUG) || defined(DEBUG_AUTOGRAB)
fprintf(stderr, "%s: (FocusOut): ungrabbing\n", __func__);
#endif
nxagentUngrabPointerAndKeyboard(NULL);
}
}
break;
}
case KeymapNotify:
{
#ifdef TEST
fprintf(stderr, "%s: Going to handle new KeymapNotify event.\n", __func__);
#endif
break;
}
case EnterNotify:
{
WindowPtr pWin;
#ifdef TEST
fprintf(stderr, "%s: Going to handle new EnterNotify event.\n", __func__);
#endif
if (nxagentOption(Rootless))
{
WindowPtr pTLWin = NULL;
pWin = nxagentWindowPtr(X.xcrossing.window);
if (pWin != NULL)
{
for (pTLWin = pWin;
pTLWin -> parent != pTLWin -> drawable.pScreen -> root;
pTLWin = pTLWin -> parent);
}
if (pTLWin)
{
nxagentLastEnteredTopLevelWindow = pTLWin;
}
#ifdef TEST
fprintf(stderr, "%s: nxagentLastEnteredTopLevelWindow [%p].\n", __func__,
(void *)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.
*/
#ifdef TEST
fprintf(stderr, "%s: pWin -> drawable.x [%d] pWin -> drawable.y [%d].\n", __func__,
pWin -> drawable.x, pWin -> drawable.y);
#endif
XID values[4];
register XID *value = values;
*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 mask = CWX | CWY;
nxagentScreenTrap = True;
ConfigureWindow(pWin, mask, (XID *) values, wClient(pWin));
nxagentScreenTrap = False;
}
if (nxagentOption(Fullscreen) &&
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);
memset(&x, 0, sizeof(xEvent));
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, "%s: Going to handle new LeaveNotify event.\n", __func__);
#endif
if (nxagentOption(Rootless) && X.xcrossing.mode == NotifyNormal &&
X.xcrossing.detail != NotifyInferior)
{
nxagentLastEnteredWindow = NULL;
}
if (!nxagentOption(AutoGrab))
{
if (X.xcrossing.window == nxagentDefaultWindows[0] &&
X.xcrossing.detail != NotifyInferior &&
X.xcrossing.mode == NotifyNormal)
{
nxagentUngrabPointerAndKeyboard(&X);
}
}
if (X.xcrossing.detail != NotifyInferior)
{
pScreen = nxagentScreen(X.xcrossing.window);
if (pScreen)
{
nxagentDirectUninstallColormaps(pScreen);
}
}
nxagentInputEvent = 1;
break;
}
case DestroyNotify:
{
#ifdef TEST
fprintf(stderr, "%s: Going to handle new DestroyNotify event.\n", __func__);
#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, "%s: Going to handle new ClientMessage event.\n", __func__);
#endif
nxagentHandleClientMessageEvent(&X, &result);
if (result == doCloseSession)
{
closeSession = TRUE;
}
break;
}
case VisibilityNotify:
{
#ifdef TEST
fprintf(stderr, "%s: Going to handle new VisibilityNotify event.\n", __func__);
#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))
{
TraverseTree(pWin, nxagentChangeVisibilityPrivate, &value);
}
else
{
nxagentChangeVisibilityPrivate(pWin, &value);
}
}
}
#ifdef TEST
fprintf(stderr, "%s: Suppressing visibility notify on window [%lx].\n", __func__,
X.xvisibility.window);
#endif
break;
}
#ifdef TEST
fprintf(stderr, "%s: Visibility notify state is [%d] with previous [%d].\n", __func__,
X.xvisibility.state, nxagentVisibility);
#endif
nxagentVisibility = X.xvisibility.state;
break;
}
case Expose:
{
#ifdef DEBUG
fprintf(stderr, "%s: Going to handle new Expose event.\n", __func__);
fprintf(stderr, "%s: WARNING! Received Expose event for drawable [%lx]"
" geometry [%d, %d, %d, %d] count [%d].\n", __func__,
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, "%s: Going to handle new GraphicsExpose event.\n", __func__);
fprintf(stderr, "%s: WARNING! Received GraphicsExpose event "
"for drawable [%lx] geometry [%d, %d, %d, %d] count [%d].\n", __func__,
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, "%s: Going to handle new NoExpose event.\n", __func__);
fprintf(stderr, "%s: WARNING! Received NoExpose event for drawable [%lx].\n", __func__, X.xnoexpose.drawable);
#endif
break;
}
case CirculateNotify:
{
#ifdef WARNING
fprintf(stderr, "%s: Going to handle new CirculateNotify event.\n", __func__);
#endif
/*
* FIXME: Do we need this?
*
* WindowPtr 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, "%s: Going to handle new ConfigureNotify event.\n", __func__);
#endif
if (nxagentConfiguredSynchroWindow == X.xconfigure.window)
{
if (nxagentExposeQueue.exposures[nxagentExposeQueue.start].serial != X.xconfigure.x)
{
#ifdef WARNING
if (nxagentVerbose)
{
fprintf(stderr, "%s: Requested ConfigureNotify changes didn't take place.\n", __func__);
}
#endif
}
#ifdef TEST
fprintf(stderr, "%s: Received ConfigureNotify and going to call nxagentSynchronizeExpose.\n", __func__);
#endif
nxagentSynchronizeExpose();
break;
}
nxagentHandleConfigureNotify(&X);
break;
}
case GravityNotify:
{
#ifdef TEST
fprintf(stderr, "%s: Going to handle new GravityNotify event.\n", __func__);
#endif
break;
}
case ReparentNotify:
{
#ifdef TEST
fprintf(stderr, "%s: Going to handle new ReparentNotify event.\n", __func__);
#endif
nxagentHandleReparentNotify(&X);
break;
}
case UnmapNotify:
{
#ifdef TEST
fprintf(stderr, "%s: Going to handle new UnmapNotify event.\n", __func__);
#endif
if (nxagentOption(Rootless))
{
WindowPtr pWin;
if ((pWin = nxagentRootlessTopLevelWindow(X.xunmap.window)) != NULL ||
((pWin = nxagentWindowPtr(X.xunmap.window)) != NULL &&
nxagentWindowTopLevel(pWin)))
{
nxagentScreenTrap = True;
UnmapWindow(pWin, False);
nxagentScreenTrap = False;
}
}
if (nxagentUseNXTrans == 1 && !nxagentOption(Rootless) &&
!nxagentOption(Nested) &&
X.xmap.window != nxagentIconWindow)
{
nxagentVisibility = VisibilityFullyObscured;
}
break;
}
case MapNotify:
{
#ifdef TEST
fprintf(stderr, "%s: Going to handle new MapNotify event.\n", __func__);
#endif
if (nxagentOption(Rootless))
{
WindowPtr pWin;
if ((pWin = nxagentRootlessTopLevelWindow(X.xmap.window)) != NULL ||
((pWin = nxagentWindowPtr(X.xmap.window)) != NULL &&
nxagentWindowTopLevel(pWin)))
{
nxagentScreenTrap = True;
MapWindow(pWin, wClient(pWin));
nxagentScreenTrap = False;
}
if (pWin != NULL)
{
Bool value = 1;
TraverseTree(pWin, nxagentChangeMapPrivate, &value);
}
}
if (nxagentOption(AllScreens))
{
if (X.xmap.window == nxagentIconWindow)
{
pScreen = nxagentScreen(X.xmap.window);
nxagentMaximizeToFullScreen(pScreen);
}
}
if (nxagentOption(Fullscreen))
{
nxagentVisibility = VisibilityUnobscured;
}
/*
* without window manager there will be no ConfigureNotify
* event that would trigger xinerama updates. So we do that
* once the nxagent window gets mapped.
*/
if (!nxagentWMIsRunning &&
X.xmap.window == nxagentDefaultWindows[nxagentScreen(X.xmap.window)->myNum])
{
nxagentChangeScreenConfig(nxagentScreen(X.xmap.window)->myNum, nxagentOption(Width),
nxagentOption(Height), True);
}
break;
}
case MappingNotify:
{
XMappingEvent *mappingEvent = (XMappingEvent *) &X;
#ifdef DEBUG
fprintf(stderr, "%s: WARNING! Going to handle new MappingNotify event.\n", __func__);
#endif
if (mappingEvent -> request == MappingPointer)
{
nxagentInitPointerMap();
}
break;
}
default:
{
/*
* Let's check if this is a XKB state modification event.
*/
if (nxagentHandleXkbKeyboardStateEvent(&X) == 0 && nxagentHandleXFixesSelectionNotify(&X) == 0)
{
#ifdef TEST
fprintf(stderr, "%s: WARNING! Unhandled event code [%d].\n", __func__, X.type);
#endif
}
break;
}
} /* End of switch (X.type) */
if (X.xany.serial < lastEventSerial)
{
/*
* Start over.
*/
nxagentDeleteStaticResizedWindow(0);
}
else
{
nxagentDeleteStaticResizedWindow(X.xany.serial - 1);
}
lastEventSerial = X.xany.serial;
} /* 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(AllScreens))
{
nxagentMinimizeFromFullScreen(pScreen);
}
else
{
XIconifyWindow(nxagentDisplay, nxagentDefaultWindows[0],
DefaultScreen(nxagentDisplay));
}
}
}
if (switchFullscreen)
{
if (nxagentOption(AllScreens) && nxagentOption(Fullscreen))
{
nxagentSwitchAllScreens(pScreen, 0);
}
else
{
nxagentSwitchFullscreen(pScreen, !nxagentOption(Fullscreen));
}
}
if (switchAllScreens)
{
if (!nxagentOption(AllScreens) && nxagentOption(Fullscreen))
{
nxagentSwitchFullscreen(pScreen, False);
}
else
{
nxagentSwitchAllScreens(pScreen, !nxagentOption(AllScreens));
}
}
#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, "%s: Output pending flag is [%d] critical [%d].\n", __func__,
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, "%s: Flushed the processed events to clients.\n", __func__);
#endif
FlushAllOutput();
}
#ifdef TEST
if (nxagentPendingEvents(nxagentDisplay) > 0)
{
fprintf(stderr, "%s: WARNING! More events need to be dispatched.\n", __func__);
}
#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)
{
if (!nxagentXkbState.Initialized)
{
if (X -> xkey.keycode == nxagentCapsLockKeycode)
{
nxagentXkbCapsTrap = True;
}
else if (X -> xkey.keycode == nxagentNumLockKeycode)
{
nxagentXkbNumTrap = True;
}
nxagentInitXkbKeyboardState();
nxagentXkbCapsTrap = False;
nxagentXkbNumTrap = False;
}
if (nxagentCheckSpecialKeystroke(&X -> xkey, result))
{
#ifdef TEST
fprintf(stderr, "%s: NOT passing KeyPress event to clients\n", __func__);
#endif
return 1;
}
if (X -> xkey.keycode == nxagentCapsLockKeycode)
{
nxagentXkbState.Caps = (~nxagentXkbState.Caps & 1);
}
else if (X -> xkey.keycode == nxagentNumLockKeycode)
{
nxagentXkbState.Num = (~nxagentXkbState.Num & 1);
}
nxagentLastServerTime = X -> xkey.time;
nxagentLastEventTime = nxagentLastKeyPressTime = GetTimeInMillis();
xEvent x = {0};
x.u.u.type = KeyPress;
x.u.u.detail = nxagentConvertKeycode(X -> xkey.keycode);
x.u.keyButtonPointer.time = nxagentLastKeyPressTime;
#ifdef TEST
fprintf(stderr, "%s: passing KeyPress event to clients\n", __func__);
#endif
mieqEnqueue(&x);
CriticalOutputPending = 1;
return 1;
}
int nxagentHandlePropertyNotify(XEvent *X)
{
if (nxagentOption(Rootless) && !nxagentNotifyMatchChangeProperty((XPropertyEvent *) X))
{
#ifdef TEST
fprintf(stderr, "%s: Property %ld on window %lx.\n", __func__,
X -> xproperty.atom, X -> xproperty.window);
#endif
if (nxagentWindowPtr(X -> xproperty.window) != NULL)
{
int resource = NXGetCollectPropertyResource(nxagentDisplay);
if (resource == -1)
{
#ifdef WARNING
fprintf(stderr, "%s: WARNING! Asynchronous get property queue is full.\n", __func__);
#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, "%s: Failed to look up remote window property.\n", __func__);
}
#endif
}
return 1;
}
int nxagentHandleExposeEvent(XEvent *X)
{
StaticResizedWindowStruct *resizedWinPtr = NULL;
#ifdef DEBUG
fprintf(stderr, "%s: Checking remote expose events.\n", __func__);
fprintf(stderr, "%s: Looking for window id [%ld].\n", __func__, X -> xexpose.window);
#endif
Window window = X -> xexpose.window;
WindowPtr pWin = nxagentWindowPtr(window);
if (pWin != NULL)
{
RegionRec sum;
RegionRec add;
BoxRec box;
RegionInit(&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, "%s: Adding event for window id [%ld].\n", __func__, X -> xexpose.window);
#endif
box.x1 = pWin -> drawable.x + wBorderWidth(pWin) + X -> xexpose.x;
box.y1 = pWin -> drawable.y + wBorderWidth(pWin) + X -> xexpose.y;
resizedWinPtr = nxagentFindStaticResizedWindow(X -> xany.serial);
while (resizedWinPtr)
{
if (resizedWinPtr -> pWin == pWin)
{
box.x1 += resizedWinPtr -> offX;
box.y1 += resizedWinPtr -> offY;
}
resizedWinPtr = resizedWinPtr -> prev;
}
box.x2 = box.x1 + X -> xexpose.width;
box.y2 = box.y1 + X -> xexpose.height;
RegionInit(&add, &box, 1);
RegionAppend(&sum, &add);
RegionUninit(&add);
if (X -> xexpose.count == 0)
{
break;
}
}
while (nxagentCheckEvents(nxagentDisplay, X, nxagentExposurePredicate,
(XPointer) &window) == 1);
int overlap = 0;
RegionValidate(&sum, &overlap);
RegionIntersect(&sum, &sum,
&pWin->drawable.pScreen->root->winSize);
#ifdef DEBUG
fprintf(stderr, "%s: Sending events for window id [%ld].\n", __func__, X -> xexpose.window);
#endif
/*
* If the agent has already sent auto-generated expose,
* save received exposes for later processing.
*/
int index = nxagentLookupByWindow(pWin);
if (index == -1)
{
miWindowExposures(pWin, &sum, NullRegion);
}
else
{
RegionTranslate(&sum, -pWin -> drawable.x, -pWin -> drawable.y);
if (nxagentExposeQueue.exposures[index].remoteRegion == NullRegion)
{
nxagentExposeQueue.exposures[index].remoteRegion = RegionCreate(NULL, 1);
}
RegionUnion(nxagentExposeQueue.exposures[index].remoteRegion,
nxagentExposeQueue.exposures[index].remoteRegion, &sum);
#ifdef TEST
fprintf(stderr, "%s: Added region for window [%u] to position [%d].\n", __func__,
nxagentWindow(pWin), index);
#endif
if (X -> xexpose.count == 0)
{
nxagentExposeQueue.exposures[index].remoteRegionIsCompleted = True;
}
else
{
nxagentExposeQueue.exposures[index].remoteRegionIsCompleted = False;
}
}
RegionUninit(&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.
*/
StoringPixmapPtr pStoringPixmapRec = NULL;
miBSWindowPtr pBSwindow = NULL;
int drawableType;
WindowPtr 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, "%s: WARNING! Storing pixmap not found.\n", __func__);
#endif
return 1;
}
pBSwindow = (miBSWindowPtr) pStoringPixmapRec -> pSavedWindow -> backStorage;
if (pBSwindow == NULL)
{
#ifdef TEST
fprintf(stderr, "%s: WARNING! Back storage not found.\n", __func__);
#endif
return 1;
}
pWin = pStoringPixmapRec -> pSavedWindow;
}
/*
* Rectangle affected by GraphicsExpose event.
*/
BoxRec rect = {
.x1 = X -> xgraphicsexpose.x,
.y1 = X -> xgraphicsexpose.y,
.x2 = rect.x1 + X -> xgraphicsexpose.width,
.y2 = rect.y1 + X -> xgraphicsexpose.height,
};
RegionPtr exposeRegion = RegionCreate(&rect, 0);
if (drawableType == DRAWABLE_PIXMAP)
{
#ifdef TEST
fprintf(stderr, "%s: Handling GraphicsExpose event on pixmap with id [%lu].\n",
__func__, 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.
*/
RegionTranslate(exposeRegion, pStoringPixmapRec -> backingStoreX,
pStoringPixmapRec -> backingStoreY);
/*
* We remove from SavedRegion the part affected by the
* GraphicsExpose event.
*/
RegionSubtract(&(pBSwindow -> SavedRegion), &(pBSwindow -> SavedRegion),
exposeRegion);
}
/*
* Store the exposeRegion in order to send the expose event
* later. The coordinates must be relative to the screen.
*/
RegionTranslate(exposeRegion, pWin -> drawable.x, pWin -> drawable.y);
RegionUnion(nxagentRemoteExposeRegion, nxagentRemoteExposeRegion, exposeRegion);
RegionDestroy(exposeRegion);
return 1;
}
int nxagentHandleClientMessageEvent(XEvent *X, enum HandleEventResult *result)
{
*result = doNothing;
/*
* 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)
{
#ifdef TEST
fprintf(stderr, "%s: got nxproxy event\n", __func__);
#endif
nxagentHandleProxyEvent(X);
return 1;
}
#ifdef TEST
char * name = XGetAtomName(nxagentDisplay, X -> xclient.message_type);
fprintf(stderr, "nxagentHandleClientMessageEvent: ClientMessage event window [0x%lx] with "
"message_type [%ld][%s] format [%d] type [%d] source_indication [%ld][%s] timestamp [%ld] "
"curwin [0x%lx].\n", X -> xclient.window, X -> xclient.message_type, name,
X -> xclient.format, X -> xclient.type, X -> xclient.data.l[0],
X -> xclient.data.l[0] == 1 ? "'application'" : X -> xclient.data.l[0] == 1 ? "'pager'" : "'none (old spec)'",
X -> xclient.data.l[1], X -> xclient.data.l[2]);
SAFE_XFree(name);
#endif
if (nxagentOption(Rootless))
{
Atom message_type = nxagentRemoteToLocalAtom(X -> xclient.message_type);
if (!ValidAtom(message_type))
{
#ifdef WARNING
fprintf(stderr, "%s: WARNING Invalid type in client message.\n", __func__);
#endif
return 0;
}
WindowPtr pWin = nxagentWindowPtr(X -> xclient.window);
if (pWin == NULL)
{
/*
* If some window on the real X server sends a
* _NET_ACTIVE_WINDOW ClientMessage to indicate the active
* window that window will be one not belonging to nxagent so
* this situation is perfectly legal. For all other situations
* we print a warning.
*/
#ifdef WARNING
if (message_type != MakeAtom("_NET_ACTIVE_WINDOW", strlen("_NET_ACTIVE_WINDOW"), False))
{
fprintf(stderr, "WARNING: Invalid window in ClientMessage xclient.window [0x%lx].\n", X->xclient.window);
}
#endif
return 0;
}
if (message_type == MakeAtom("WM_PROTOCOLS", strlen("WM_PROTOCOLS"), False))
{
xEvent x = {0};
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, "%s: WARNING Invalid value in client message of type WM_PROTOCOLS.\n", __func__);
#endif
return 0;
}
#ifdef TEST
else
{
fprintf(stderr, "%s: Sent client message of type WM_PROTOCOLS and value [%s].\n", __func__,
validateString(NameForAtom(x.u.clientMessage.u.l.longs0)));
}
#endif
TryClientEvents(wClient(pWin), &x, 1, 1, 1, 0);
}
else
{
#ifdef WARNING
fprintf(stderr, "%s: Ignored message type %ld [%s].\n", __func__,
(long int) message_type, validateString(NameForAtom(message_type)));
#endif
return 0;
}
return 1;
}
if (X -> xclient.message_type == nxagentAtoms[1]) /* WM_PROTOCOLS */
{
Atom wmAtom = (Atom) X -> xclient.data.l[0];
Atom deleteWMatom = nxagentAtoms[2]; /* WM_DELETE_WINDOW */
if (wmAtom == deleteWMatom)
{
if (nxagentOnce && (nxagentClients == 0))
{
GiveUp(0);
}
else
{
#ifdef TEST
fprintf(stderr, "%s: WM_DELETE_WINDOW arrived Atom = %u.\n", __func__, wmAtom);
#endif
if (X -> xclient.window == nxagentIconWindow)
{
XMapRaised(nxagentDisplay, nxagentFullscreenWindow);
XIconifyWindow(nxagentDisplay, nxagentIconWindow,
DefaultScreen(nxagentDisplay));
}
if (X -> xclient.window == (nxagentOption(Fullscreen) ?
nxagentIconWindow : nxagentDefaultWindows[0]) ||
!nxagentWMIsRunning)
{
*result = doCloseSession;
}
}
}
}
return 1;
}
int nxagentHandleXkbKeyboardStateEvent(XEvent *X)
{
XkbEvent *xkbev = (XkbEvent *) X;
if (nxagentXkbInfo.EventBase != -1 &&
xkbev -> type == nxagentXkbInfo.EventBase + XkbEventCode &&
xkbev -> any.xkb_type == XkbStateNotify)
{
#ifdef TEST
fprintf(stderr, "%s: Handling event with caps [%d] num [%d] locked [%d].\n", __func__,
nxagentXkbState.Caps, nxagentXkbState.Num, nxagentXkbState.Locked);
#endif
nxagentXkbState.Locked = xkbev -> state.locked_mods;
#ifdef TEST
fprintf(stderr, "%s: Updated XKB locked modifier bits to [%x].\n", __func__,
nxagentXkbState.Locked);
#endif
nxagentXkbState.Initialized = True;
if (nxagentXkbState.Caps == 0 &&
(nxagentXkbState.Locked & CAPSFLAG_IN_EVENT))
{
nxagentXkbState.Caps = 1;
#ifdef TEST
fprintf(stderr, "%s: Sending fake key [66] to engage capslock.\n", __func__);
#endif
if (!nxagentXkbCapsTrap)
{
nxagentSendFakeKey(66);
}
}
if (nxagentXkbState.Caps == 1 &&
!(nxagentXkbState.Locked & CAPSFLAG_IN_EVENT))
{
nxagentXkbState.Caps = 0;
#ifdef TEST
fprintf(stderr, "%s: Sending fake key [66] to release capslock.\n", __func__);
#endif
nxagentSendFakeKey(66);
}
if (nxagentXkbState.Caps == 0 &&
!(nxagentXkbState.Locked & CAPSFLAG_IN_EVENT) &&
nxagentXkbCapsTrap)
{
#ifdef TEST
fprintf(stderr, "%s: Sending fake key [66] to release capslock.\n", __func__);
#endif
nxagentSendFakeKey(66);
}
if (nxagentXkbState.Num == 0 &&
(nxagentXkbState.Locked & NUMFLAG_IN_EVENT))
{
nxagentXkbState.Num = 1;
#ifdef TEST
fprintf(stderr, "%s: Sending fake key [77] to engage numlock.\n", __func__);
#endif
if (!nxagentXkbNumTrap)
{
nxagentSendFakeKey(77);
}
}
if (nxagentXkbState.Num == 1 &&
!(nxagentXkbState.Locked & NUMFLAG_IN_EVENT))
{
nxagentXkbState.Num = 0;
#ifdef TEST
fprintf(stderr, "%s: Sending fake key [77] to release numlock.\n", __func__);
#endif
nxagentSendFakeKey(77);
}
if (nxagentXkbState.Num == 0 &&
!(nxagentXkbState.Locked & NUMFLAG_IN_EVENT) &&
nxagentXkbNumTrap)
{
#ifdef TEST
fprintf(stderr, "%s: Sending fake key [77] to release numlock.\n", __func__);
#endif
nxagentSendFakeKey(77);
}
return 1;
}
return 0;
}
int nxagentHandleXFixesSelectionNotify(XEvent *X)
{
XFixesSelectionEvent *xfixesEvent = (XFixesSelectionEvent *) X;
if (!nxagentXFixesInfo.Initialized)
{
#ifdef DEBUG
fprintf(stderr, "%s: XFixes not initialized - doing nothing.\n", __func__);
#endif
return 0;
}
if (xfixesEvent -> type != (nxagentXFixesInfo.EventBase + XFixesSelectionNotify))
{
#ifdef DEBUG
fprintf(stderr, "%s: event type is [%d] - doing nothing.\n", __func__, xfixesEvent->type);
#endif
return 0;
}
#ifdef DEBUG
fprintf(stderr, "---------\n");
#endif
#ifdef TEST
fprintf(stderr, "%s: Handling event.\n", __func__);
#endif
#ifdef DEBUG
fprintf(stderr, "%s: Event timestamp [%ld]\n", __func__, xfixesEvent->xfixesselection.timestamp);
fprintf(stderr, "%s: Event selection timestamp [%ld]\n", __func__, xfixesEvent->xfixesselection.selection_timestamp);
fprintf(stderr, "%s: Event selection window [0x%lx]\n", __func__, xfixesEvent->xfixesselection.window);
fprintf(stderr, "%s: Event selection owner [0x%lx]\n", __func__, xfixesEvent->xfixesselection.owner);
fprintf(stderr, "%s: Event selection [%s]\n", __func__, NameForAtom(nxagentRemoteToLocalAtom(xfixesEvent->xfixesselection.selection)));
fprintf(stderr, "%s: Subtype ", __func__);
switch (xfixesEvent -> xfixesselection.subtype)
{
case SelectionSetOwner: fprintf(stderr, "SelectionSetOwner.\n"); break;
case SelectionWindowDestroy: fprintf(stderr, "SelectionWindowDestroy.\n"); break;
case SelectionClientClose: fprintf(stderr, "SelectionClientClose.\n"); break;
default: fprintf(stderr, ".\n"); break;
}
#endif
if (xfixesEvent->xfixesselection.owner && xfixesEvent->xfixesselection.owner == nxagentWindow(screenInfo.screens[0]->root))
{
/*
* This is an event that must have been triggered by nxagent itself
* - by calling XSetSelectionOwner(). As this is no news for us we
* can ignore the event.
*/
#ifdef DEBUG
fprintf(stderr, "%s: (new) owner is nxagent (window is [0x%lx]) - ignoring it.\n", __func__, xfixesEvent->xfixesselection.window);
#endif
return 0;
}
/*
* Realistically the only situation where we can receive
* WindowDestroy or ClientClose will also end nxagent, so we do not
* need to handle them. But the code is here, so let's keep it.
*/
if (xfixesEvent -> xfixesselection.subtype == SelectionSetOwner||
xfixesEvent -> xfixesselection.subtype == SelectionWindowDestroy ||
xfixesEvent -> xfixesselection.subtype == SelectionClientClose)
{
/*
* Reception of an owner change on the real X server is - for nxagent - the same as
* receiving a SelectionClear event. We just need to tell a (possible) internal
* owner that it is no longer owning the selection.
*/
nxagentHandleSelectionClearFromXServerByAtom(xfixesEvent -> xfixesselection.selection);
}
else
{
#ifdef DEBUG
fprintf(stderr, "%s: WARNING unexpected xfixesselection subtype [%d]\n", __func__, xfixesEvent -> xfixesselection.subtype);
#endif
}
return 1;
}
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, "%s: PANIC! NXNoSplitNotify received with client [%d].\n", __func__, client);
}
else
{
fprintf(stderr, "%s: PANIC! NXStartSplitNotify received with client [%d].\n", __func__, 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, "%s: NXCommitSplitNotify received with client [%d]"
" request [%d] and position [%d].\n", __func__,
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, "%s: NXEndSplitNotify received with client [%d].\n", __func__, client);
#endif
nxagentHandleEndSplitEvent(client);
return 1;
}
case NXEmptySplitNotify:
{
/*
* All splits have been completed and none remain.
*/
#ifdef TEST
fprintf(stderr, "%s: NXEmptySplitNotify received.\n", __func__);
#endif
nxagentHandleEmptySplitEvent();
return 1;
}
case NXCollectPropertyNotify:
{
#ifdef TEST
int resource = (int) X -> xclient.data.l[1];
fprintf(stderr, "%s: NXCollectPropertyNotify received with resource [%d].\n", __func__, resource);
#endif
nxagentHandleCollectPropertyEvent(X);
return 1;
}
case NXCollectGrabPointerNotify:
{
int resource = (int) X -> xclient.data.l[1];
#ifdef TEST
fprintf(stderr, "%s: NXCollectGrabPointerNotify received with resource [%d].\n", __func__, 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, "%s: NXCollectInputFocusNotify received with resource [%d].\n", __func__, resource);
#endif
nxagentHandleCollectInputFocusEvent(resource);
return 1;
}
default:
{
/*
* Not a recognized ClientMessage event.
*/
#ifdef WARNING
fprintf(stderr, "%s: WARNING! Not a recognized ClientMessage proxy event [%d].\n", __func__,
(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;
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, "%s: Configure frame. No restack.\n", __func__);
#endif
return 1;
}
#ifdef TEST
{
fprintf(stderr, "%s: Before restacking top level window [%p]\n", __func__,
(void *) nxagentWindowPtr(X -> window));
for (WindowPtr pSib = screenInfo.screens[0]->root -> firstChild; pSib; pSib = pSib -> nextSib)
{
fprintf(stderr, "%s: Top level window: [%p].\n", __func__, (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, "%s: WARNING! Failed QueryTree request.\n", __func__);
#endif
}
SAFE_XFree(children_return);
#if 0
fprintf(stderr, "%s: Trees match: %s\n", __func__, nxagentRootlessTreesMatch() ? "Yes" : "No");
#endif
return 1;
}
int nxagentHandleConfigureNotify(XEvent* X)
{
#ifdef DEBUG
fprintf(stderr, "%s: Event info:\n", __func__);
fprintf(stderr, "%s: X->serial [%ld]\n", __func__, X->xconfigure.serial);
fprintf(stderr, "%s: X->override_redirect [%d]\n", __func__, X->xconfigure.override_redirect);
fprintf(stderr, "%s: X->border_width [%d]\n", __func__, X->xconfigure.border_width);
fprintf(stderr, "%s: X->send_event [%d]\n", __func__, X->xconfigure.send_event);
fprintf(stderr, "%s: X->window [0x%lx]\n", __func__, X->xconfigure.window);
fprintf(stderr, "%s: X->event [0x%lx]\n", __func__, X->xconfigure.event);
fprintf(stderr, "%s: X->x, X->y [%d][%d]\n", __func__, X->xconfigure.x, X->xconfigure.y);
fprintf(stderr, "%s: X->width, X->height [%d][%d]\n", __func__, X->xconfigure.width, X->xconfigure.height);
fprintf(stderr, "%s: References:\n", __func__);
fprintf(stderr, "%s: DefaultWindow[0]: [0x%x]\n", __func__, nxagentDefaultWindows[0]);
fprintf(stderr, "%s: DefaultRootWindow(DISPLAY) [0x%lx]\n", __func__, DefaultRootWindow(nxagentDisplay));
#endif
if (nxagentOption(Rootless))
{
int sendEventAnyway = 0;
WindowPtr pWinWindow = nxagentWindowPtr(X -> xconfigure.window);
#ifdef TEST
{
WindowPtr pWinEvent = nxagentWindowPtr(X -> xconfigure.event);
fprintf(stderr, "%s: Generating window is [%p][%ld] target [%p][%ld].\n", __func__,
(void *) pWinEvent, X -> xconfigure.event, (void *) pWinWindow, X -> xconfigure.window);
}
#endif
#ifdef TEST
fprintf(stderr, "%s: New configuration for window [%p][%ld] is [%d][%d][%d][%d] send_event [%i].\n",
__func__, (void *) pWinWindow, X -> xconfigure.window,
X -> xconfigure.x, X -> xconfigure.y, X -> xconfigure.width,
X -> xconfigure.height, X -> xconfigure.send_event);
#endif
WindowPtr pWin = nxagentRootlessTopLevelWindow(X -> xconfigure.window);
if (pWin != NULL)
{
/*
* Checking for new geometry or stacking order changes.
*/
nxagentCheckWindowConfiguration((XConfigureEvent*)X);
return 1;
}
if (nxagentWindowTopLevel(pWinWindow) && !X -> xconfigure.override_redirect)
{
XID values[5];
register XID *value = values;
Mask mask = CWHeight | CWWidth | CWBorderWidth;
/* FIXME: override_redirect is always FALSE here */
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;
*/
nxagentScreenTrap = True;
ConfigureWindow(pWinWindow, mask, (XID *) values, wClient(pWinWindow));
nxagentScreenTrap = False;
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, "%s: Apply workaround for NXWin.\n", __func__);
#endif
sendEventAnyway = 1;
}
if (sendEventAnyway || X -> xconfigure.send_event)
{
xEvent x = {0};
x.u.u.type = X -> xconfigure.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(wClient(pWinWindow), &x, 1, 1, 1, 0);
}
return 1;
}
}
else /* (nxagentOption(Rootless)) */
{
/*
* 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;
if (X -> xconfigure.window == nxagentDefaultWindows[pScreen -> myNum])
{
if (!nxagentOption(AllScreens))
{
/*
* - WITHOUT window manager any position change is relevant
* - WITH window manager only synthetic position changes sent
* by the window manager are relevant, see ICCCM Chapter 4,
* "Configuring the Window"
*/
Bool updatePos = (!nxagentWMIsRunning || X -> xconfigure.send_event != 0);
int newX = X -> xconfigure.x;
int newY = X -> xconfigure.y;
if (nxagentOption(DesktopResize))
{
if (nxagentOption(Width) != X -> xconfigure.width ||
nxagentOption(Height) != X -> xconfigure.height ||
(updatePos && (nxagentOption(X) != newX ||
nxagentOption(Y) != newY)))
{
#ifdef DEBUG
int count = 0;
#endif
Bool newEvents = False;
doRandR = True;
NXFlushDisplay(nxagentDisplay, NXFlushLink);
do
{
newEvents = False;
nxagentWaitEvents(nxagentDisplay, 500);
/*
* This should also flush the NX link for us.
*/
XSync(nxagentDisplay, 0);
while (XCheckTypedWindowEvent(nxagentDisplay, nxagentDefaultWindows[pScreen -> myNum],
ConfigureNotify, X))
{
#ifdef DEBUG
count++;
#endif
if (!nxagentWMIsRunning || X -> xconfigure.send_event)
{
updatePos = True;
#ifdef DEBUG
fprintf(stderr, "%s: Accumulating event %d: x [%d] y [%d] width [%d] height [%d]\n", __func__, count,
X -> xconfigure.x, X -> xconfigure.y, X -> xconfigure.width, X -> xconfigure.height);
#endif
newX = X -> xconfigure.x;
newY = X -> xconfigure.y;
}
newEvents = True;
}
} while (newEvents);
#ifdef DEBUG
fprintf(stderr, "%s: accumulated %d events\n", __func__, count);
#endif
}
}
if (updatePos && (nxagentOption(X) != newX || nxagentOption(Y) != newY))
{
#ifdef DEBUG
fprintf(stderr, "%s: Updating nxagent window position [%d,%d] -> [%d,%d]\n", __func__,
nxagentOption(X), nxagentOption(Y), newX, newY);
#endif
nxagentChangeOption(X, newX);
nxagentChangeOption(Y, newY);
}
if (nxagentOption(Shadow) && nxagentOption(DesktopResize) &&
(nxagentOption(Width) != X -> xconfigure.width ||
nxagentOption(Height) != X -> xconfigure.height))
{
nxagentShadowResize = True;
}
if (nxagentOption(Width) != X->xconfigure.width || nxagentOption(Height) != X->xconfigure.height)
{
#ifdef DEBUG
fprintf(stderr, "%s: Updating width and height [%d,%d] -> [%d,%d]\n", __func__,
nxagentOption(Width), nxagentOption(Height),
X->xconfigure.width, X->xconfigure.height);
#endif
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 in shadowing mode or if neither size nor position have
changed we do not need to adjust RandR */
/* FIXME: Comment makes no sense */
if (nxagentOption(Shadow) ||
(nxagentOption(Width) == nxagentOption(RootWidth) &&
nxagentOption(Height) == nxagentOption(RootHeight) &&
nxagentOption(X) == nxagentOption(RootX) &&
nxagentOption(Y) == nxagentOption(RootY)))
{
doRandR = False;
}
XMoveResizeWindow(nxagentDisplay, nxagentInputWindows[0], 0, 0,
X -> xconfigure.width, X -> xconfigure.height);
if (!nxagentOption(Fullscreen))
{
/* FIXME: has already been done some lines above */
nxagentMoveViewport(pScreen, 0, 0);
}
else
{
nxagentChangeOption(RootX, (nxagentOption(Width) -
nxagentOption(RootWidth)) / 2);
nxagentChangeOption(RootY, (nxagentOption(Height) -
nxagentOption(RootHeight)) / 2);
nxagentChangeOption(ViewportXSpan, nxagentOption(Width) -
nxagentOption(RootWidth));
nxagentChangeOption(ViewportYSpan, nxagentOption(Height) -
nxagentOption(RootHeight));
nxagentUpdateViewportFrame(0, 0, nxagentOption(RootWidth),
nxagentOption(RootHeight));
XMoveWindow(nxagentDisplay, nxagentWindow(pScreen->root),
nxagentOption(RootX), nxagentOption(RootY));
}
if (doRandR)
{
#ifdef TEST
fprintf(stderr,"%s: Width %d Height %d.\n", __func__,
nxagentOption(Width), nxagentOption(Height));
#endif
/*
* we are processing a ConfigureNotifyEvent that brought us
* the current window size. If we issue a XResizeWindow()
* again with these values we might end up in loop if the
* window manager adjusts the size, which is perfectly
* legal for it to do. So we prevent the XResizeWindow call
* from happening.
*/
nxagentChangeScreenConfig(0, nxagentOption(Width),
nxagentOption(Height), False);
}
}
return 1;
}
else
{
if ( (X -> xconfigure.window == DefaultRootWindow(nxagentDisplay)) || nxagentFullscreenWindow )
{
#ifdef TEST
fprintf(stderr, "%s: remote root window has changed: %d,%d %dx%d\n", __func__,
X -> xconfigure.x, X -> xconfigure.y, X -> xconfigure.width, X -> xconfigure.height);
#endif
nxagentChangeOption(RootX, X -> xconfigure.x);
nxagentChangeOption(RootY, X -> xconfigure.y);
nxagentChangeOption(RootWidth, X -> xconfigure.width);
nxagentChangeOption(RootHeight, X -> xconfigure.height);
nxagentChangeScreenConfig(0, nxagentOption(Width),
nxagentOption(Height), True);
return 1;
}
}
}
#ifdef TEST
fprintf(stderr, "%s: received for unexpected window [%ld]\n", __func__, X -> xconfigure.window);
#endif
return 0;
}
int nxagentHandleReparentNotify(XEvent* X)
{
#ifdef TEST
fprintf(stderr, "%s: Going to handle a new reparent event (serial [%ld].\n", __func__, X->xreparent.serial);
#endif
#ifdef DEBUG
fprintf(stderr, "%s: Event info:\n", __func__);
fprintf(stderr, "%s: X->send_event [%d]\n", __func__, X->xreparent.send_event);
fprintf(stderr, "%s: X->event [0x%lx]\n", __func__, X->xreparent.event);
fprintf(stderr, "%s: X->window [0x%lx]\n", __func__, X->xreparent.window);
fprintf(stderr, "%s: X->parent [0x%lx]\n", __func__, X->xreparent.parent);
fprintf(stderr, "%s: X->x, X->y [%d][%d]\n", __func__, X->xreparent.x, X->xreparent.y);
fprintf(stderr, "%s: X->override_redirect [%d]\n", __func__, X->xreparent.override_redirect);
fprintf(stderr, "%s: References:\n", __func__);
fprintf(stderr, "%s: DefaultWindow[0]: [0x%x]\n", __func__, nxagentDefaultWindows[0]);
fprintf(stderr, "%s: RootWindow(DISPLAY, 0): [0x%lx]\n", __func__, RootWindow(nxagentDisplay, 0));
fprintf(stderr, "%s: DefaultRootWindow(DISPLAY): [0x%lx]\n", __func__, DefaultRootWindow(nxagentDisplay));
#endif
if (nxagentOption(Rootless))
{
WindowPtr pWin = nxagentWindowPtr(X -> xreparent.window);
#ifdef TEST
{
WindowPtr pParent = nxagentWindowPtr(X -> xreparent.parent);
WindowPtr pEvent = nxagentWindowPtr(X -> xreparent.event);
fprintf(stderr, "%s: event %p[%lx] window %p[%lx] parent %p[%lx] at (%d, %d)\n", __func__,
(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.
*/
XlibWindow w = None;
XlibWindow root_return = 0;
XlibWindow *children_return = NULL;
unsigned int nchildren_return = 0;
Status result;
XlibWindow 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);
SAFE_XFree(children_return);
if (!result)
{
#ifdef WARNING
fprintf(stderr, "%s: WARNING! Failed QueryTree request.\n", __func__);
#endif
break;
}
}
if (w && !nxagentWindowPtr(w))
{
XSelectInput(nxagentDisplay, w, StructureNotifyMask);
nxagentRootlessAddTopLevelWindow(pWin, w);
#ifdef TEST
fprintf(stderr, "%s: new top level window [%ld].\n", __func__, w);
fprintf(stderr, "%s: reparented window [%ld].\n", __func__, 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, "%s: WARNING! Failed QueryTree request.\n", __func__);
#endif
}
SAFE_XFree(children_return);
}
else
{
#ifdef TEST
fprintf(stderr, "%s: Window at [%p] has been reparented to [%ld] top level parent [%ld].\n",
__func__, (void *) pWin, X -> xreparent.parent, w);
#endif
nxagentRootlessDelTopLevelWindow(pWin);
}
}
return 1;
}
else if (nxagentWMIsRunning && !nxagentOption(Fullscreen) &&
nxagentOption(WMBorderWidth) == -1)
{
/*
* Calculate the absolute upper-left X e Y
*/
XlibWindow parent = X -> xreparent.parent;
XWindowAttributes attributes;
if ((XGetWindowAttributes(nxagentDisplay, parent, &attributes) == 0))
{
#ifdef WARNING
fprintf(stderr, "%s: WARNING! XGetWindowAttributes for parent window failed.\n", __func__);
#endif
return 1;
}
XlibWindow junk;
int x = attributes.x;
int y = attributes.y;
#ifdef DEBUG
int before_x = x;
int before_y = y;
#endif
XTranslateCoordinates(nxagentDisplay, parent,
attributes.root, -attributes.border_width,
-attributes.border_width, &x, &y, &junk);
#ifdef DEBUG
fprintf(stderr, "%s: translated coordinates x,y [%d,%d] -> [%d,%d].\n", __func__, before_x, before_y, x, y);
#endif
/*
* Calculate the parent X and parent Y.
*/
if (parent != DefaultRootWindow(nxagentDisplay))
{
XlibWindow rootReturn = 0;
XlibWindow parentReturn = 0;
XlibWindow *childrenReturn = NULL;
unsigned int nchildrenReturn = 0;
do
{
Status result = XQueryTree(nxagentDisplay, parent, &rootReturn, &parentReturn,
&childrenReturn, &nchildrenReturn);
SAFE_XFree(childrenReturn);
if (parentReturn == rootReturn || parentReturn == 0 || result == 0)
{
break;
}
parent = parentReturn;
}
while (True);
/*
* WM reparented. Find edge of the frame.
*/
if (XGetWindowAttributes(nxagentDisplay, parent, &attributes) == 0)
{
#ifdef WARNING
fprintf(stderr, "%s: WARNING! XGetWindowAttributes failed for parent window.\n", __func__);
#endif
return 1;
}
/*
* Difference between Absolute X and Parent X gives thickness of side frame.
* Difference between Absolute Y and Parent Y gives thickness of title bar.
*/
nxagentChangeOption(WMBorderWidth, (x - attributes.x));
nxagentChangeOption(WMTitleHeight, (y - attributes.y));
#ifdef DEBUG
fprintf(stderr, "%s: WMBorderWidth [%d]\n", __func__, nxagentOption(WMBorderWidth));
fprintf(stderr, "%s: WMTitleHeight [%d]\n", __func__, nxagentOption(WMTitleHeight));
fprintf(stderr, "%s: win_gravity [%d]\n", __func__, attributes.win_gravity);
fprintf(stderr, "%s: bit_gravity [%d]\n", __func__, attributes.bit_gravity);
fprintf(stderr, "%s: border_width [%d]\n", __func__, attributes.border_width);
fprintf(stderr, "%s: height [%d]\n", __func__, attributes.height);
fprintf(stderr, "%s: width [%d]\n", __func__, attributes.width);
fprintf(stderr, "%s: x [%d]\n", __func__, attributes.x);
fprintf(stderr, "%s: y [%d]\n", __func__, attributes.y);
#endif
}
}
return 1;
}
/*
* Helper for nxagent(Enable|Disable)(Keyboard|Pointer)Events
*/
static void nxagentSwitchEventsAllScreens(Mask mask, Bool enable)
{
Mask newmask = nxagentGetDefaultEventMask();
if (enable)
newmask |= mask;
else
newmask &= ~mask;
nxagentSetDefaultEventMask(newmask);
for (int i = 0; i < nxagentNumScreens; i++)
{
XSelectInput(nxagentDisplay, nxagentDefaultWindows[i], newmask);
}
}
void nxagentEnableKeyboardEvents(void)
{
nxagentSwitchEventsAllScreens(NXAGENT_KEYBOARD_EVENT_MASK, True);
XkbSelectEvents(nxagentDisplay, XkbUseCoreKbd,
NXAGENT_KEYBOARD_EXTENSION_EVENT_MASK,
NXAGENT_KEYBOARD_EXTENSION_EVENT_MASK);
}
void nxagentDisableKeyboardEvents(void)
{
nxagentSwitchEventsAllScreens(NXAGENT_KEYBOARD_EVENT_MASK, False);
XkbSelectEvents(nxagentDisplay, XkbUseCoreKbd, 0x0, 0x0);
}
void nxagentEnablePointerEvents(void)
{
nxagentSwitchEventsAllScreens(NXAGENT_POINTER_EVENT_MASK, True);
}
void nxagentDisablePointerEvents(void)
{
nxagentSwitchEventsAllScreens(NXAGENT_POINTER_EVENT_MASK, False);
}
void nxagentSendFakeKey(int key)
{
Time now = GetTimeInMillis();
xEvent fake = {0};
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 nxagentInitXkbKeyboardState(void)
{
XEvent X = {0};
XkbEvent *xkbev = (XkbEvent *) &X;
if (nxagentXkbInfo.EventBase == -1)
{
return 1;
}
#ifdef TEST
fprintf(stderr, "%s: Initializing XKB state.\n", __func__);
#endif
unsigned int modifiers;
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, "%s: Assuming XKB locked modifier bits [%x].\n", __func__,
xkbev -> state.locked_mods);
#endif
xkbev -> type = nxagentXkbInfo.EventBase + XkbEventCode;
xkbev -> any.xkb_type = XkbStateNotify;
nxagentHandleXkbKeyboardStateEvent(&X);
return 1;
}
int nxagentWaitForResource(GetResourceFuncPtr pGetResource, PredicateFuncPtr pPredicate)
{
int resource;
while ((resource = (*pGetResource)(nxagentDisplay)) == -1)
{
if (nxagentWaitEvents(nxagentDisplay, 0) == -1)
{
return -1;
}
nxagentDispatchEvents(pPredicate);
}
return resource;
}
void nxagentGrabPointerAndKeyboard(XEvent *X)
{
#ifdef TEST
fprintf(stderr, "%s: Grabbing pointer and keyboard with event at [%p].\n", __func__,
(void *) X);
#endif
unsigned long now;
if (X != NULL)
{
now = X -> xcrossing.time;
}
else
{
now = CurrentTime;
}
#ifdef TEST
fprintf(stderr, "%s: Going to grab the keyboard in context [B1].\n", __func__);
#endif
int result = XGrabKeyboard(nxagentDisplay,
nxagentFullscreenWindow ? nxagentFullscreenWindow
: 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 waiting for the
* reply. In this case we need to yield explicitly to avoid to be
* stuck in the dispatch loop forever.
*/
isItTimeToYield = 1;
#ifdef TEST
fprintf(stderr, "%s: Going to grab the pointer in context [B2].\n", __func__);
#endif
int resource = nxagentWaitForResource(NXGetCollectGrabPointerResource,
nxagentCollectGrabPointerPredicate);
if (nxagentFullscreenWindow)
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, "%s: Going to force focus in context [B4].\n", __func__);
#endif
XSetInputFocus(nxagentDisplay, nxagentFullscreenWindow,
RevertToParent, now);
}
}
void nxagentUngrabPointerAndKeyboard(XEvent *X)
{
unsigned long now;
#ifdef TEST
fprintf(stderr, "%s: Ungrabbing pointer and keyboard with event at [%p].\n", __func__,
(void *) X);
#endif
if (X != NULL)
{
now = X -> xcrossing.time;
}
else
{
now = CurrentTime;
}
#ifdef TEST
fprintf(stderr, "%s: Going to ungrab the keyboard in context [B5].\n", __func__);
#endif
XUngrabKeyboard(nxagentDisplay, now);
#ifdef TEST
fprintf(stderr, "%s: Going to ungrab the pointer in context [B6].\n", __func__);
#endif
XUngrabPointer(nxagentDisplay, now);
}
void nxagentDeactivatePointerGrab(void)
{
GrabPtr grab = inputInfo.pointer -> grab;
if (grab)
{
XButtonEvent X = {
.type = ButtonRelease,
.serial = 0,
.send_event = FALSE,
.time = currentTime.milliseconds,
.display = nxagentDisplay,
.window = nxagentWindow(grab -> window),
.root = RootWindow(nxagentDisplay, 0),
.subwindow = 0,
.x = 0,
.y = 0,
.x_root = 0,
.y_root = 0,
.state = 0x100,
.button = 1,
.same_screen = TRUE,
};
XPutBackEvent(nxagentDisplay, (XEvent*)&X);
}
}
Bool nxagentCollectGrabPointerPredicate(Display *disp, 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, "%s: PANIC! Failed to get GrabPointer reply for resource [%d].\n", __func__, resource);
#endif
}
}
void nxagentHandleCollectPropertyEvent(XEvent *X)
{
int resource = X -> xclient.data.l[1];
if (X -> xclient.data.l[2] == False)
{
#ifdef DEBUG
fprintf (stderr, "%s: Failed to get reply data for client [%d].\n", __func__,
resource);
#endif
return;
}
if (!nxagentCollectPropertyEventFromXServer(resource))
{
XlibAtom atomReturnType;
int resultFormat;
unsigned long ulReturnItems;
unsigned long ulReturnBytesLeft;
unsigned char *pszReturnData = NULL;
int result = NXGetCollectedProperty(nxagentDisplay,
resource,
&atomReturnType,
&resultFormat,
&ulReturnItems,
&ulReturnBytesLeft,
&pszReturnData);
if (result == True)
{
XlibWindow window = nxagentPropertyRequests[resource].window;
XlibAtom property = nxagentPropertyRequests[resource].property;
nxagentImportProperty(window, property, atomReturnType, resultFormat,
ulReturnItems, ulReturnBytesLeft, pszReturnData);
}
else
{
#ifdef DEBUG
fprintf (stderr, "%s: Failed to get reply data for client [%d].\n", __func__,
resource);
#endif
}
SAFE_XFree(pszReturnData);
return;
}
}
void nxagentSynchronizeExpose(void)
{
if (nxagentExposeQueue.length <= 0)
{
#ifdef TEST
fprintf(stderr, "%s: PANIC! Called with nxagentExposeQueue.length [%d].\n", __func__,
nxagentExposeQueue.length);
#endif
return;
}
WindowPtr pWin = nxagentExposeQueueHead.pWindow;
if (pWin)
{
if ((nxagentExposeQueueHead.localRegion) != NullRegion)
{
RegionTranslate((nxagentExposeQueueHead.localRegion),
pWin -> drawable.x, pWin -> drawable.y);
}
if ((nxagentExposeQueueHead.remoteRegion) != NullRegion)
{
RegionTranslate((nxagentExposeQueueHead.remoteRegion),
pWin -> drawable.x, pWin -> drawable.y);
}
if ((nxagentExposeQueueHead.localRegion) != NullRegion &&
(nxagentExposeQueueHead.remoteRegion) != NullRegion)
{
RegionSubtract((nxagentExposeQueueHead.remoteRegion),
(nxagentExposeQueueHead.remoteRegion),
(nxagentExposeQueueHead.localRegion));
if (!RegionNil(nxagentExposeQueueHead.remoteRegion) &&
((pWin -> eventMask|wOtherEventMasks(pWin)) & ExposureMask))
{
#ifdef TEST
fprintf(stderr, "%s: Going to call miWindowExposures for window [%d] - rects [%d].\n",
__func__, nxagentWindow(pWin),
RegionNumRects(nxagentExposeQueueHead.remoteRegion));
#endif
miWindowExposures(pWin, nxagentExposeQueueHead.remoteRegion, NullRegion);
}
}
}
nxagentExposeQueueHead.pWindow = NULL;
if (nxagentExposeQueueHead.localRegion != NullRegion)
{
RegionDestroy(nxagentExposeQueueHead.localRegion);
}
nxagentExposeQueueHead.localRegion = NullRegion;
if (nxagentExposeQueueHead.remoteRegion != NullRegion)
{
RegionDestroy(nxagentExposeQueueHead.remoteRegion);
}
nxagentExposeQueueHead.remoteRegion = NullRegion;
nxagentExposeQueueHead.remoteRegionIsCompleted = False;
nxagentExposeQueue.start = (nxagentExposeQueue.start + 1) % EXPOSED_SIZE;
nxagentExposeQueue.length--;
return;
}
int nxagentLookupByWindow(WindowPtr pWin)
{
for (int j = 0; j < nxagentExposeQueue.length; j++)
{
int 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 *qelt = nxagentDisplay -> head;
KeyCode lastKeycode = X -> xkey.keycode;
if (qelt == NULL)
{
#ifdef TEST
fprintf(stderr, "%s: Trying to read more events from the X server.\n", __func__);
if (nxagentReadEvents(nxagentDisplay) > 0)
{
fprintf(stderr, "%s: Successfully read more events from the X server.\n", __func__);
}
#else
nxagentReadEvents(nxagentDisplay);
#endif
qelt = nxagentDisplay -> head;
}
if (qelt != NULL)
{
_XQEvent *prev;
_XQEvent *qeltKeyRelease;
_XQEvent *prevKeyRelease;
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 = RegionCreate(NULL, 1);
if (nxagentRemoteExposeRegion == NULL)
{
#ifdef PANIC
fprintf(stderr, "%s: PANIC! Failed to create expose region.\n", __func__);
#endif
}
}
}
void nxagentForwardRemoteExpose(void)
{
if (RegionNotEmpty(nxagentRemoteExposeRegion))
{
#ifdef DEBUG
fprintf(stderr, "%s: Going to forward events.\n", __func__);
#endif
TraverseTree(screenInfo.screens[0]->root, nxagentClipAndSendExpose, (void *)nxagentRemoteExposeRegion);
/*
* Now this region should be empty.
*/
RegionEmpty(nxagentRemoteExposeRegion);
}
}
void nxagentAddRectToRemoteExposeRegion(BoxPtr rect)
{
if (nxagentRemoteExposeRegion == NULL)
{
return;
}
RegionRec exposeRegion;
RegionInit(&exposeRegion, rect, 1);
RegionUnion(nxagentRemoteExposeRegion,
nxagentRemoteExposeRegion, &exposeRegion);
RegionUninit(&exposeRegion);
}
int nxagentClipAndSendExpose(WindowPtr pWin, void * ptr)
{
RegionPtr remoteExposeRgn = (RegionRec *) ptr;
#ifdef DEBUG
fprintf(stderr, "%s: Called.\n", __func__);
#endif
if (pWin -> drawable.class != InputOnly)
{
RegionPtr exposeRgn = RegionCreate(NULL, 1);
#ifdef DEBUG
BoxRec box = *RegionExtents(remoteExposeRgn);
fprintf(stderr, "%s: Root expose extents: [%d] [%d] [%d] [%d].\n", __func__,
box.x1, box.y1, box.x2, box.y2);
box = *RegionExtents(&pWin -> clipList);
fprintf(stderr, "%s: Clip list extents for window at [%p]: [%d] [%d] [%d] [%d].\n", __func__,
(void *)pWin, box.x1, box.y1, box.x2, box.y2);
#endif
RegionIntersect(exposeRgn, remoteExposeRgn, &pWin -> clipList);
if (RegionNotEmpty(exposeRgn))
{
#ifdef DEBUG
fprintf(stderr, "%s: Forwarding expose to window at [%p] pWin.\n", __func__,
(void *)pWin);
#endif
/*
* The miWindowExposures() clears out the region parameters, so
* the subtract ope- ration must be done before calling it.
*/
RegionSubtract(remoteExposeRgn, remoteExposeRgn, exposeRgn);
miWindowExposures(pWin, exposeRgn, NullRegion);
}
RegionDestroy(exposeRgn);
}
if (RegionNotEmpty(remoteExposeRgn))
{
#ifdef DEBUG
fprintf(stderr, "%s: Region not empty. Walk children.\n", __func__);
#endif
return WT_WALKCHILDREN;
}
else
{
#ifdef DEBUG
fprintf(stderr, "%s: Region empty. Stop walking.\n", __func__);
#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
* eventually change the nxagentInputEvent status.
*/
if (nxagentOption(Shadow) &&
nxagentPendingEvents(nxagentDisplay) > 0)
{
nxagentDispatchEvents(NULL);
}
if (nxagentInputEvent == 1)
{
nxagentInputEvent = 0;
result = 1;
}
/*
* The agent working in shadow mode synchronizes 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))
{
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, "%s: Buttons [%d] Keys [%d].\n", __func__,
inputInfo.pointer -> button -> buttonsDown, nxagentKeyDown);
#endif
result = 1;
}
}
return result;
}
int nxagentHandleRRScreenChangeNotify(XEvent *X)
{
XRRScreenChangeNotifyEvent *Xr = (XRRScreenChangeNotifyEvent *) X;
#ifdef DEBUG
fprintf(stderr, "%s: Called.\n", __func__);
#endif
nxagentResizeScreen(screenInfo.screens[DefaultScreen(nxagentDisplay)],
Xr -> width, Xr -> height,
Xr -> mwidth, Xr -> mheight, True);
nxagentShadowCreateMainWindow(screenInfo.screens[DefaultScreen(nxagentDisplay)],
screenInfo.screens[0]->root,
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, "%s: Returning error with display down.\n", __func__);
#endif
return -1;
}
else if (XQLength(dpy) > 0)
{
#ifdef DEBUG
fprintf(stderr, "%s: Returning true with [%d] events queued.\n", __func__,
XQLength(dpy));
#endif
return 1;
}
else
{
int readable;
if (NXTransReadable(dpy -> fd, &readable) == 0)
{
if (readable > 0)
{
#ifdef DEBUG
fprintf(stderr, "%s: Returning true with [%d] bytes readable.\n", __func__,
readable);
#endif
return 1;
}
#ifdef DEBUG
fprintf(stderr, "%s: Returning false with [%d] bytes readable.\n", __func__,
readable);
#endif
return 0;
}
#ifdef TEST
fprintf(stderr, "%s: WARNING! Error detected on the X display.\n", __func__);
#endif
NXForceDisplayError(dpy);
return -1;
}
}
/*
* Blocks until an event becomes available.
*/
int nxagentWaitEvents(Display *dpy, useconds_t msec)
{
#ifdef DEBUG
fprintf(stderr, "%s: Called.\n", __func__);
#endif
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)
{
if (msec > 0)
{
struct timeval tm = {
.tv_sec = 0,
.tv_usec = msec * 1000
};
NXTransContinue(&tm);
}
else
{
NXTransContinue(NULL);
}
}
else
{
XEvent ev;
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 (msec > 0)
{
usleep(msec * 1000);
}
return -1;
}
return 1;
}
void ForwardClientMessage(ClientPtr client, xSendEventReq *stuff)
{
Atom netwmstate = MakeAtom("_NET_WM_STATE", strlen("_NET_WM_STATE"), False);
Atom wmchangestate = MakeAtom("WM_CHANGE_STATE", strlen("WM_CHANGE_STATE"), False);
WindowPtr pWin = (WindowPtr)SecurityLookupWindow(stuff->destination, client,
DixReadAccess);
if (stuff->event.u.clientMessage.u.l.type == netwmstate || stuff->event.u.clientMessage.u.l.type == wmchangestate)
{
if (pWin->drawable.id == pWin->drawable.pScreen->root->drawable.id)
{
#ifdef DEBUG
fprintf(stderr, "%s: dest [0x%x] window [0x%x] clmsg.type [%d]->[%d]\n", __func__, stuff->destination, stuff->event.u.clientMessage.window, stuff->event.u.clientMessage.u.l.type, nxagentLocalToRemoteAtom(stuff->event.u.clientMessage.u.l.type));
#endif
XEvent X = {0};
X.xany.type = ClientMessage;
WindowPtr pWin2 = (WindowPtr)SecurityLookupWindow(stuff->event.u.clientMessage.window, client,
DixReadAccess);
X.xclient.window = nxagentWindowPriv(pWin2)->window;
X.xclient.format = stuff->event.u.u.detail;
X.xclient.send_event = True;
X.xclient.serial = 0;
if (X.xclient.format == 32)
{
X.xclient.message_type = nxagentLocalToRemoteAtom(stuff->event.u.clientMessage.u.l.type);
X.xclient.data.l[0] = stuff->event.u.clientMessage.u.l.longs0;
X.xclient.data.l[1] = nxagentLocalToRemoteAtom(stuff->event.u.clientMessage.u.l.longs1);
X.xclient.data.l[2] = nxagentLocalToRemoteAtom(stuff->event.u.clientMessage.u.l.longs2);
X.xclient.data.l[3] = nxagentLocalToRemoteAtom(stuff->event.u.clientMessage.u.l.longs3);
X.xclient.data.l[4] = nxagentLocalToRemoteAtom(stuff->event.u.clientMessage.u.l.longs4);
//X.xclient.data.l[3] = stuff->event.u.clientMessage.u.l.longs3;
//X.xclient.data.l[4] = stuff->event.u.clientMessage.u.l.longs4;
#ifdef DEBUG
for (int i = 0; i < 5; i++)
{
fprintf(stderr, "%s: data[%d] [%ld]\n", __func__, i, X.xclient.data.l[i]);
}
#endif
}
else
return; // ERROR!
#ifdef DEBUG
fprintf(stderr, "%s: window [0x%lx]\n", __func__, X.xclient.window);
fprintf(stderr, "%s: message_type [%ld]\n", __func__, X.xclient.message_type);
fprintf(stderr, "%s: format [%d]\n", __func__, X.xclient.format);
#endif
XlibWindow dest;
dest = DefaultRootWindow(nxagentDisplay);
#ifdef DEBUG
Status stat =
#endif
XSendEvent(nxagentDisplay, dest, stuff->propagate, stuff->eventMask, &X);
XFlush(nxagentDisplay);
#ifdef DEBUG
fprintf(stderr, "%s: send to window [0x%lx]\n", __func__, dest);
fprintf(stderr, "%s: return Status [%d]\n", __func__, stat);
#endif
}
}
}
#ifdef NX_DEBUG_INPUT
void nxagentGuessDumpInputInfo(ClientPtr client, Atom property, char *data)
{
if (strcmp(validateString(NameForAtom(property)), "NX_DEBUG_INPUT") == 0)
{
if (*data != 0)
{
nxagentDebugInput = 1;
}
else
{
nxagentDebugInput = 0;
}
}
}
void nxagentDeactivateInputDevicesGrabs(void)
{
fprintf(stderr, "Info: Deactivating input devices grabs.\n");
if (inputInfo.pointer -> grab)
{
(*inputInfo.pointer -> DeactivateGrab)(inputInfo.pointer);
}
if (inputInfo.keyboard -> grab)
{
(*inputInfo.keyboard -> DeactivateGrab)(inputInfo.keyboard);
}
}
static const char *nxagentGrabStateToString(int state)
{
switch (state)
{
case 0: return "NOT_GRABBED";
case 1: return "THAWED";
case 2: return "THAWED_BOTH";
case 3: return "FREEZE_NEXT_EVENT";
case 4: return "FREEZE_BOTH_NEXT_EVENT";
case 5: return "FROZEN_NO_EVENT";
case 6: return "FROZEN_WITH_EVENT";
case 7: return "THAW_OTHERS";
default: return "unknown state";
}
}
void nxagentDumpInputDevicesState(void)
{
WindowPtr pWin = NULL;
fprintf(stderr, "\n*** Dump input devices state: BEGIN ***"
"\nKeys down:");
DeviceIntPtr dev = inputInfo.keyboard;
for (int i = 0; i < DOWN_LENGTH; i++)
{
CARD8 val = dev -> key -> down[i];
if (val != 0)
{
for (int k = 0; k < 8; k++)
{
if (val & (1 << k))
{
fprintf(stderr, "\n\t[%d] [%s]", i * 8 + k,
XKeysymToString(XKeycodeToKeysym(nxagentDisplay, i * 8 + k, 0)));
}
}
}
}
fprintf(stderr, "\nKeyboard device state: \n\tdevice [%p]\n\tlast grab time [%u]"
"\n\tfrozen [%s]\n\tstate [%s]\n\tother [%p]\n\tevent count [%d]"
"\n\tfrom passive grab [%s]\n\tactivating key [%d]", (void *)dev,
dev -> grabTime.milliseconds, dev -> sync.frozen ? "Yes": "No",
nxagentGrabStateToString(dev -> sync.state),
(void *)dev -> sync.other, dev -> sync.evcount,
dev -> fromPassiveGrab ? "Yes" : "No",
dev -> activatingKey);
GrabPtr grab = dev -> grab;
if (grab)
{
fprintf(stderr, "\nKeyboard grab state: \n\twindow pointer [%p]"
"\n\towner events flag [%s]\n\tgrab mode [%s]",
(void *)grab -> window, grab -> ownerEvents ? "True" : "False",
grab -> keyboardMode ? "asynchronous" : "synchronous");
/*
* Passive grabs.
*/
pWin = grab -> window;
grab = wPassiveGrabs(pWin);
while (grab)
{
fprintf(stderr, "\nPassive grab state: \n\tdevice [%p]\n\towner events flag [%s]"
"\n\tpointer grab mode [%s]\n\tkeyboard grab mode [%s]\n\tevent type [%d]"
"\n\tmodifiers [%x]\n\tbutton/key [%u]\n\tevent mask [%x]",
(void *)grab -> device, grab -> ownerEvents ? "True" : "False",
grab -> pointerMode ? "asynchronous" : "synchronous",
grab -> keyboardMode ? "asynchronous" : "synchronous",
grab -> type, grab -> modifiersDetail.exact,
grab -> detail.exact, grab -> eventMask);
grab = grab -> next;
}
}
fprintf(stderr, "\nButtons down:");
dev = inputInfo.pointer;
for (int i = 0; i < DOWN_LENGTH; i++)
{
CARD8 val = dev -> button -> down[i];
if (val != 0)
{
for (int k = 0; k < 8; k++)
{
if (val & (1 << k))
{
fprintf(stderr, "\n\t[%d]", i * 8 + k);
}
}
}
}
fprintf(stderr, "\nPointer device state: \n\tdevice [%p]\n\tlast grab time [%u]"
"\n\tfrozen [%s]\n\tstate [%s]\n\tother [%p]\n\tevent count [%d]"
"\n\tfrom passive grab [%s]\n\tactivating button [%d]", (void *)dev,
dev -> grabTime.milliseconds, dev -> sync.frozen ? "Yes" : "No",
nxagentGrabStateToString(dev -> sync.state),
(void *)dev -> sync.other, dev -> sync.evcount,
dev -> fromPassiveGrab ? "Yes" : "No",
dev -> activatingKey);
grab = dev -> grab;
if (grab)
{
fprintf(stderr, "\nPointer grab state: \n\twindow pointer [%p]"
"\n\towner events flag [%s]\n\tgrab mode [%s]",
(void *)grab -> window, grab -> ownerEvents ? "True" : "False",
grab -> pointerMode ? "asynchronous" : "synchronous");
if (grab -> window != pWin)
{
/*
* Passive grabs.
*/
grab = wPassiveGrabs(grab -> window);
while (grab)
{
fprintf(stderr, "\nPassive grab state: \n\tdevice [%p]\n\towner events flag [%s]"
"\n\tpointer grab mode [%s]\n\tkeyboard grab mode [%s]\n\tevent type [%d]"
"\n\tmodifiers [%x]\n\tbutton/key [%u]\n\tevent mask [%x]",
(void *)grab -> device, grab -> ownerEvents ? "True" : "False",
grab -> pointerMode ? "asynchronous" : "synchronous",
grab -> keyboardMode ? "asynchronous" : "synchronous",
grab -> type, grab -> modifiersDetail.exact,
grab -> detail.exact, grab -> eventMask);
grab = grab -> next;
}
}
}
fprintf(stderr, "\n*** Dump input devices state: FINISH ***\n");
}
#endif