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

3917 lines
106 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 <unistd.h>
#include "X.h"
#include "Xproto.h"
#include "gcstruct.h"
#include "../../include/window.h"
#include "windowstr.h"
#include "pixmapstr.h"
#include "colormapst.h"
#include "scrnintstr.h"
#include "region.h"
#include "dixstruct.h"
#include "selection.h"
#include "mi.h"
#include "fb.h"
#include "mibstorest.h"
#include "Agent.h"
#include "Display.h"
#include "Screen.h"
#include "GCs.h"
#include "GCOps.h"
#include "Drawable.h"
#include "Colormap.h"
#include "Cursor.h"
#include "Visual.h"
#include "Events.h"
#include "Clipboard.h"
#include "Args.h"
#include "Trap.h"
#include "Rootless.h"
#include "Atoms.h"
#include "Client.h"
#include "Reconnect.h"
#include "Dialog.h"
#include "Splash.h"
#include "Init.h"
#include "Composite.h"
#include "Events.h"
#include "Utils.h"
#include <nx/NX.h>
#include "compext/Compext.h"
#include "Xatom.h"
/*
* Used to register the window's privates.
*/
int nxagentWindowPrivateIndex;
/*
* Used to track nxagent window's visibility.
*/
int nxagentVisibility = VisibilityUnobscured;
ConfiguredWindowStruct *nxagentConfiguredWindowList;
StaticResizedWindowStruct *nxagentStaticResizedWindowList;
/*
* Set here the required log level.
*/
#define PANIC
#define WARNING
#undef TEST
#undef DEBUG
/*
* Useful to test the window configuration failures.
*/
#ifdef TEST
#define MAKE_SYNC_CONFIGURE_WINDOW XSync(nxagentDisplay, 0)
#else
#define MAKE_SYNC_CONFIGURE_WINDOW
#endif
extern WindowPtr nxagentViewportFrameLeft;
extern WindowPtr nxagentViewportFrameRight;
extern WindowPtr nxagentViewportFrameAbove;
extern WindowPtr nxagentViewportFrameBelow;
extern Bool nxagentReportPrivateWindowIds;
#define RECTLIMIT 25
#define BSPIXMAPLIMIT 128
Bool nxagentExposeArrayIsInitialized = False;
Window nxagentConfiguredSynchroWindow;
static int nxagentExposeSerial = 0;
StoringPixmapPtr nxagentBSPixmapList[BSPIXMAPLIMIT];
/*
* Used to walk through the window hierarchy to find a window
*/
typedef struct _WindowMatch
{
WindowPtr pWin;
Window id;
} WindowMatchRec;
Bool nxagentReconnectAllWindows(void *);
Bool nxagentDisconnectAllWindows(void);
Bool nxagentIsIconic(WindowPtr);
/*
* From NXproperty.c.
*/
int GetWindowProperty(WindowPtr, Atom, long, long, Bool, Atom, Atom*, int*,
unsigned long*, unsigned long*, unsigned char**);
/*
* Other local functions.
*/
static Bool nxagentSomeWindowsAreMapped(void);
static void nxagentFrameBufferPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what);
static void nxagentTraverseWindow(WindowPtr, void(*)(void *, XID, void *), void *);
static void nxagentDisconnectWindow(void *, XID, void *);
static Bool nxagentLoopOverWindows(void(*)(void *, XID, void *));
static void nxagentReconfigureWindowCursor(void *, XID, void *);
static void nxagentReconnectWindow(void *, XID, void *);
static void nxagentReconfigureWindow(void *, XID, void *);
static int nxagentForceExposure(WindowPtr pWin, void * ptr);
/* by dimbor */
typedef struct
{
CARD32 state;
Window icon;
}
nxagentWMStateRec;
/*
* This is currently unused.
*/
#ifdef TEST
static Bool nxagentCheckWindowIntegrity(WindowPtr pWin);
#endif
WindowPtr nxagentGetWindowFromID(Window id)
{
WindowPtr pWin = screenInfo.screens[0]->root;
while (pWin && nxagentWindowPriv(pWin))
{
if (nxagentWindow(pWin) == id)
{
return pWin;
}
if (pWin -> nextSib)
{
pWin = pWin -> nextSib;
}
else
{
pWin = pWin -> firstChild;
}
}
return NULL;
}
static int nxagentFindWindowMatch(WindowPtr pWin, void * ptr)
{
WindowMatchRec *match = (WindowMatchRec *) ptr;
if (match -> id == nxagentWindow(pWin))
{
match -> pWin = pWin;
return WT_STOPWALKING;
}
else
{
return WT_WALKCHILDREN;
}
}
WindowPtr nxagentWindowPtr(Window window)
{
WindowMatchRec match = {.pWin = NullWindow, .id = window};
for (int i = 0; i < nxagentNumScreens; i++)
{
WalkTree(screenInfo.screens[i], nxagentFindWindowMatch, (void *) &match);
if (match.pWin)
{
break;
}
}
return match.pWin;
}
/*
* from "Definition of the Porting Layer for X v11 Sample Server":
*
* This routine is a hook for when DIX creates a window. It should
* fill in the "Window Procedures in the WindowRec" below and also
* allocate the devPrivate block for it.
*
* See Xserver/fb/fbwindow.c for the sample server implementation.
*/
Bool nxagentCreateWindow(WindowPtr pWin)
{
unsigned long mask;
XSetWindowAttributes attributes;
Visual *visual;
ColormapPtr pCmap;
if (nxagentScreenTrap)
{
return True;
}
if (pWin->drawable.class == InputOnly)
{
mask = CWEventMask;
visual = CopyFromParent;
}
else
{
mask = CWEventMask | CWBackingStore;
if (pWin->optional)
{
mask |= CWBackingPlanes | CWBackingPixel;
attributes.backing_planes = pWin->optional->backingBitPlanes;
attributes.backing_pixel = pWin->optional->backingPixel;
}
attributes.backing_store = NotUseful;
#ifdef TEST
fprintf(stderr, "nxagentCreateWindow: Backing store on window at [%p] is [%d].\n",
(void*)pWin, attributes.backing_store);
#endif
/*
FIXME: We need to set save under on the real display?
*/
if (nxagentSaveUnder)
{
mask |= CWSaveUnder;
attributes.save_under = False;
}
if (pWin->parent)
{
if (pWin->optional && pWin->optional->visual != wVisual(pWin->parent))
{
visual = nxagentVisualFromID(pWin->drawable.pScreen, wVisual(pWin));
mask |= CWColormap;
if (pWin->optional->colormap)
{
pCmap = (ColormapPtr)LookupIDByType(wColormap(pWin), RT_COLORMAP);
attributes.colormap = nxagentColormap(pCmap);
}
else
{
attributes.colormap = nxagentDefaultVisualColormap(visual);
}
}
else if (pWin->optional)
{
visual = CopyFromParent;
}
else
{
visual = nxagentVisualFromID(pWin->drawable.pScreen, wVisual(pWin));
mask |= CWColormap;
attributes.colormap = nxagentDefaultVisualColormap(visual);
}
}
else
{
/* root windows have their own colormaps at creation time */
visual = nxagentVisualFromID(pWin->drawable.pScreen, wVisual(pWin));
pCmap = (ColormapPtr)LookupIDByType(wColormap(pWin), RT_COLORMAP);
mask |= CWColormap;
attributes.colormap = nxagentColormap(pCmap);
}
}
if (mask & CWEventMask)
{
attributes.event_mask = nxagentGetEventMask(pWin);
}
#ifdef WARNING
else
{
attributes.event_mask = NoEventMask;
}
#endif
/*
* Select the event mask if window is a top level window. This at
* least makes the keyboard barely work.
*/
#ifdef TEST
fprintf(stderr, "nxagentCreateWindow: Going to create new window.\n");
#endif
#ifdef TEST
fprintf(stderr, "nxagentCreateWindow: Creating %swindow at %p current event mask = %lX mask & CWEventMask = %ld "
"event_mask = %lX\n",
nxagentWindowTopLevel(pWin) ? "toplevel " : "", (void*)pWin, pWin -> eventMask,
mask & CWEventMask, attributes.event_mask);
fprintf(stderr, "nxagentCreateWindow: position [%d,%d] size [%d,%d] depth [%d] border [%d] class [%d].\n",
pWin->origin.x - wBorderWidth(pWin), pWin->origin.y - wBorderWidth(pWin),
pWin->drawable.width, pWin->drawable.height, pWin->drawable.depth, pWin->borderWidth,
pWin->drawable.class);
#endif
nxagentWindowPriv(pWin)->window = XCreateWindow(nxagentDisplay,
nxagentWindowParent(pWin),
pWin->origin.x -
wBorderWidth(pWin),
pWin->origin.y -
wBorderWidth(pWin),
pWin->drawable.width,
pWin->drawable.height,
pWin->borderWidth,
pWin->drawable.depth,
pWin->drawable.class,
visual,
mask, &attributes);
nxagentWindowPriv(pWin) -> isMapped = 0;
nxagentWindowPriv(pWin) -> isRedirected = 0;
nxagentWindowPriv(pWin) -> visibilityState = VisibilityUnobscured;
nxagentWindowPriv(pWin) -> corruptedRegion = RegionCreate(NULL, 1);
nxagentWindowPriv(pWin) -> hasTransparentChildren = 0;
nxagentWindowPriv(pWin) -> containGlyphs = 0;
nxagentWindowPriv(pWin) -> corruptedId = 0;
nxagentWindowPriv(pWin) -> deferredBackgroundExpose = 0;
nxagentWindowPriv(pWin) -> synchronizationBitmap = NullPixmap;
nxagentWindowPriv(pWin) -> corruptedTimestamp = 0;
nxagentWindowPriv(pWin) -> splitResource = NULL;
if (nxagentOption(Rootless))
{
nxagentWindowPriv(pWin) -> isMapped = 0;
if (pWin != nxagentRootlessWindow)
{
WindowPtr pParent = pWin -> parent;
if (pParent && nxagentWindowPriv(pParent) -> isMapped == 1)
{
nxagentWindowPriv(pWin) -> isMapped = 1;
}
}
}
if (nxagentReportPrivateWindowIds)
{
fprintf(stderr, "NXAGENT_WINDOW_ID: %s_WINDOW,WID:[0x%x],INT:[0x%x]\n",
(pWin->drawable.id == pWin->drawable.pScreen->root->drawable.id) ? "ROOT" : "PRIVATE",
nxagentWindowPriv(pWin)->window, pWin->drawable.id);
}
#ifdef DEBUG
{
char *winname = NULL;
if (-1 != asprintf(&winname, "%s %s[0x%lx]", nxagentWindowName,
(pWin->drawable.id == pWin->drawable.pScreen->root->drawable.id) ? "Root" : "Private",
pWin->drawable.id))
{
Xutf8SetWMProperties(nxagentDisplay, nxagentWindowPriv(pWin)->window,
winname, winname, NULL , 0 , NULL, NULL, NULL);
SAFE_free(winname);
}
}
#endif
#ifdef TEST
fprintf(stderr, "%s: Created new window with id [0x%x].\n", __func__,
nxagentWindowPriv(pWin)->window);
#endif
/*
* Set the WM_DELETE_WINDOW protocols on every top level
* window. Also redirect the window if it is a top level.
*/
if (nxagentOption(Rootless) && nxagentWindowTopLevel(pWin))
{
XlibAtom prop = nxagentMakeAtom("WM_PROTOCOLS", strlen("WM_PROTOCOLS"), True);
XlibAtom atom = nxagentMakeAtom("WM_DELETE_WINDOW", strlen("WM_DELETE_WINDOW"), True);
XSetWMProtocols(nxagentDisplay, nxagentWindowPriv(pWin)->window, &atom, 1);
nxagentAddPropertyToList(prop, pWin);
/*
* Redirect the window to the off-screen memory, if the composite
* extension is supported on the display.
*/
/*
FIXME: Do all the windows for which nxagentWindowTopLevel(pWin)
returns true need to be redirected?
*/
nxagentRedirectWindow(pWin);
}
if ((nxagentRealWindowProp) && (!nxagentWindowTopLevel(pWin)))
{
Atom prop = MakeAtom("NX_REAL_WINDOW", strlen("NX_REAL_WINDOW"), True);
if (ChangeWindowProperty(pWin, prop, XA_WINDOW, 32, PropModeReplace, 1, nxagentWindowPriv(pWin), 1) != Success)
{
fprintf(stderr, "nxagentCreateWindow: Adding NX_REAL_WINDOW failed.\n");
}
#ifdef DEBUG
else
{
fprintf(stderr, "nxagentCreateWindow: Added NX_REAL_WINDOW for Window ID [%x].\n", nxagentWindowPriv(pWin)->window);
}
#endif
}
nxagentWindowPriv(pWin)->x = pWin->origin.x - wBorderWidth(pWin);
nxagentWindowPriv(pWin)->y = pWin->origin.y - wBorderWidth(pWin);
nxagentWindowPriv(pWin)->width = pWin->drawable.width;
nxagentWindowPriv(pWin)->height = pWin->drawable.height;
nxagentWindowPriv(pWin)->borderWidth = pWin->borderWidth;
nxagentWindowPriv(pWin)->siblingAbove = None;
nxagentWindowPriv(pWin)->pPicture = NULL;
if (pWin->nextSib)
{
nxagentWindowPriv(pWin->nextSib)->siblingAbove = nxagentWindow(pWin);
}
#ifdef SHAPE
nxagentWindowPriv(pWin)->boundingShape = NULL;
nxagentWindowPriv(pWin)->clipShape = NULL;
#endif /* SHAPE */
fbCreateWindow(pWin);
/*
* Only the root window will have the right colormap.
*/
if (!pWin->parent)
{
nxagentSetInstalledColormapWindows(pWin->drawable.pScreen);
}
return True;
}
/* set the NX_AGENT_VERSION property for the given window (normally
the root window) */
void nxagentSetVersionProperty(WindowPtr pWin)
{
char *name = "NX_AGENT_VERSION";
Atom prop = MakeAtom(name, strlen(name), True);
if (ChangeWindowProperty(pWin, prop, XA_STRING, 8, PropModeReplace, strlen(NX_VERSION_CURRENT_STRING), NX_VERSION_CURRENT_STRING, True) != Success)
{
fprintf(stderr, "%s: Adding property [%s], value [%s] failed.\n", __func__, name, NX_VERSION_CURRENT_STRING);
}
#ifdef DEBUG
else
{
fprintf(stderr, "%s: Added property [%s], value [%s] for root window [%x].\n", __func__, name, NX_VERSION_CURRENT_STRING, pWin);
}
#endif
}
Bool nxagentSomeWindowsAreMapped(void)
{
WindowPtr pWin = screenInfo.screens[0]->root -> firstChild;
while (pWin)
{
if ((pWin -> mapped || nxagentIsIconic(pWin)) &&
pWin -> drawable.class == InputOutput)
{
return True;
}
pWin = pWin -> nextSib;
}
return False;
}
/*
* from "Definition of the Porting Layer for X v11 Sample Server":
*
* This routine is a hook for when DIX destroys a window. It should
* deallocate the devPrivate block for it and any other blocks that
* need to be freed, besides doing other cleanup actions.
*
* See Xserver/fb/fbwindow.c for the sample server implementation.
*/
Bool nxagentDestroyWindow(WindowPtr pWin)
{
nxagentPrivWindowPtr pWindowPriv;
if (nxagentScreenTrap)
{
return 1;
}
nxagentClearClipboard(NULL, pWin);
for (int j = 0; j < nxagentExposeQueue.length; j++)
{
int i = (nxagentExposeQueue.start + j) % EXPOSED_SIZE;
if (nxagentExposeQueue.exposures[i].pWindow == pWin)
{
if (nxagentExposeQueue.exposures[i].localRegion != NullRegion)
{
RegionDestroy(nxagentExposeQueue.exposures[i].localRegion);
}
nxagentExposeQueue.exposures[i].localRegion = NullRegion;
if (nxagentExposeQueue.exposures[i].remoteRegion != NullRegion)
{
RegionDestroy(nxagentExposeQueue.exposures[i].remoteRegion);
}
nxagentExposeQueue.exposures[i].remoteRegion = NullRegion;
}
}
nxagentDeleteConfiguredWindow(pWin);
pWindowPriv = nxagentWindowPriv(pWin);
if (pWin->nextSib)
{
nxagentWindowPriv(pWin->nextSib)->siblingAbove =
pWindowPriv->siblingAbove;
}
#ifdef SHAPE
if (pWindowPriv->boundingShape)
{
RegionDestroy(pWindowPriv->boundingShape);
}
if (pWindowPriv->clipShape)
{
RegionDestroy(pWindowPriv->clipShape);
}
#endif
if (pWindowPriv -> corruptedRegion)
{
RegionDestroy(pWindowPriv -> corruptedRegion);
pWindowPriv -> corruptedRegion = NULL;
}
if (nxagentSynchronization.pDrawable == (DrawablePtr) pWin)
{
nxagentSynchronization.pDrawable = NULL;
#ifdef TEST
fprintf(stderr, "nxagentDestroyWindow: Synchronization drawable [%p] removed from resources.\n",
(void *) pWin);
#endif
}
nxagentDestroyCorruptedResource((DrawablePtr) pWin, RT_NX_CORR_WINDOW);
nxagentDestroyDrawableBitmap((DrawablePtr) pWin);
if (pWindowPriv -> splitResource != NULL)
{
nxagentReleaseSplit((DrawablePtr) pWin);
}
XDestroyWindow(nxagentDisplay, nxagentWindow(pWin));
if (nxagentOption(Rootless))
{
nxagentRootlessDelTopLevelWindow(pWin);
}
pWindowPriv->window = None;
if (pWin -> optional)
{
pWin -> optional -> userProps = NULL;
}
if (nxagentOption(Rootless) && nxagentRootlessDialogPid == 0 &&
!nxagentLastWindowDestroyed && nxagentSomeWindowsAreMapped() == False)
{
#ifdef TEST
fprintf(stderr, "nxagentDestroyWindow: Last mapped window as been destroyed.\n");
#endif
nxagentLastWindowDestroyed = True;
nxagentLastWindowDestroyedTime = GetTimeInMillis();
}
return True;
}
/*
* from "Definition of the Porting Layer for X v11 Sample Server":
*
* This routine is a hook for when DIX moves or resizes a window. It
* should do whatever private operations need to be done when a window
* is moved or resized. For instance, if DDX keeps a pixmap tile used
* for drawing the background or border, and it keeps the tile rotated
* such that it is longword aligned to longword locations in the frame
* buffer, then you should rotate your tiles here. The actual graphics
* involved in moving the pixels on the screen and drawing the border
* are handled by CopyWindow(), below.
*
* See Xserver/fb/fbwindow.c for the sample server implementation.
*/
Bool nxagentPositionWindow(WindowPtr pWin, int x, int y)
{
if (nxagentScreenTrap)
{
return True;
}
#ifdef TEST
fprintf(stderr, "nxagentPositionWindow: Changing position of window [%p][%ld] to [%d,%d].\n",
(void *) pWin, nxagentWindow(pWin), x, y);
#endif
nxagentAddConfiguredWindow(pWin, CWSibling | CWX | CWY | CWWidth |
CWHeight | CWBorderWidth);
return True;
}
void nxagentRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib)
{
if (nxagentScreenTrap)
{
return;
}
nxagentAddConfiguredWindow(pWin, CW_RootlessRestack);
}
void nxagentSwitchFullscreen(ScreenPtr pScreen, Bool switchOn)
{
if (nxagentOption(Rootless))
{
return;
}
if (!switchOn)
{
nxagentWMDetect();
/*
* 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;
if (!nxagentWMIsRunning)
{
#ifdef WARNING
fprintf(stderr, "Warning: Can't switch to window mode, no window manager "
"has been detected.\n");
#endif
return;
}
}
#ifdef TEST
fprintf(stderr, "%s: Switching to %s mode.\n", __func__,
switchOn ? "fullscreen" : "windowed");
#endif
nxagentChangeOption(Fullscreen, switchOn);
XEvent e = {
.xclient.type = ClientMessage,
.xclient.message_type = nxagentAtoms[13], /* _NET_WM_STATE */
.xclient.display = nxagentDisplay,
.xclient.window = nxagentDefaultWindows[pScreen -> myNum],
.xclient.format = 32,
.xclient.data.l[0] = nxagentOption(Fullscreen) ? 1 : 0,
.xclient.data.l[1] = nxagentAtoms[14] /* _NET_WM_STATE_FULLSCREEN */
};
XSendEvent(nxagentDisplay, DefaultRootWindow(nxagentDisplay), False,
SubstructureRedirectMask, &e);
if (switchOn)
{
nxagentFullscreenWindow = nxagentDefaultWindows[pScreen -> myNum];
nxagentGrabPointerAndKeyboard(NULL);
}
else
{
nxagentFullscreenWindow = None;
/* if we had AutoGrab before entering fullscreen reactivate it now */
if (nxagentOption(AutoGrab))
nxagentGrabPointerAndKeyboard(NULL);
else
nxagentUngrabPointerAndKeyboard(NULL);
}
}
void nxagentSwitchAllScreens(ScreenPtr pScreen, Bool switchOn)
{
if (nxagentOption(Rootless))
{
return;
}
if (!switchOn)
{
nxagentWMDetect();
if (!nxagentWMIsRunning)
{
#ifdef WARNING
fprintf(stderr, "Warning: Can't switch to window mode, no window manager has been detected.\n");
#endif
return;
}
}
Window w = nxagentDefaultWindows[pScreen -> myNum];
/*
* override_redirect makes the window manager ignore the window and
* not add decorations, see ICCCM)
*/
XSetWindowAttributes attributes = {
.override_redirect = switchOn
};
unsigned long valuemask = CWOverrideRedirect;
XUnmapWindow(nxagentDisplay, w);
XChangeWindowAttributes(nxagentDisplay, w, valuemask, &attributes);
XReparentWindow(nxagentDisplay, w, DefaultRootWindow(nxagentDisplay), 0, 0);
if (switchOn)
{
/*
* Change to fullscreen mode.
*/
int i;
XEvent e;
/*
* Wait for window manager reparenting the default window.
*/
for (i = 0; i < 100 && nxagentWMIsRunning; i++)
{
#ifdef TEST
fprintf(stderr, "%s: WARNING! Going to wait for the ReparentNotify event.\n", __func__);
#endif
if (XCheckTypedWindowEvent(nxagentDisplay, w, ReparentNotify, &e))
{
#ifdef TEST
fprintf(stderr, "%s: found ReparentNotify event in iteration [%d].\n", __func__, i);
#endif
break;
}
/*
* This should also flush the NX link for us.
*/
XSync(nxagentDisplay, 0);
nxagentWaitEvents(nxagentDisplay, 50);
}
if (i < 100)
{
/*
* The window manager has done with the reparent operation. We
* can resize and map the window.
*/
nxagentChangeOption(Fullscreen, True);
nxagentChangeOption(AllScreens, True);
/*
* Save the window-mode configuration.
*/
nxagentChangeOption(SavedX, nxagentOption(X));
nxagentChangeOption(SavedY, nxagentOption(Y));
nxagentChangeOption(SavedWidth, nxagentOption(Width));
nxagentChangeOption(SavedHeight, nxagentOption(Height));
nxagentChangeOption(SavedRootWidth, nxagentOption(RootWidth));
nxagentChangeOption(SavedRootHeight, nxagentOption(RootHeight));
/*
* Reconf the Default window.
*/
nxagentChangeOption(X, 0);
nxagentChangeOption(Y, 0);
nxagentChangeOption(Width, WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)));
nxagentChangeOption(Height, HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)));
/*
* Move the root window.
*/
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));
XMoveResizeWindow(nxagentDisplay, w, nxagentOption(X), nxagentOption(Y),
nxagentOption(Width), nxagentOption(Height));
nxagentUpdateViewportFrame(0, 0, nxagentOption(RootWidth), nxagentOption(RootHeight));
XMoveWindow(nxagentDisplay, nxagentWindow(pScreen->root),
nxagentOption(RootX), nxagentOption(RootY));
/*
* We disable the screensaver on the real Xserver when changing mode to
* fullscreen. Is it really needed?
*/
XSetScreenSaver(nxagentDisplay, 0, 0, DefaultExposures, DefaultBlanking);
if (nxagentIconWindow == None)
{
nxagentIconWindow = nxagentCreateIconWindow();
XMapWindow(nxagentDisplay, nxagentIconWindow);
}
XMapRaised(nxagentDisplay, w);
XSetInputFocus(nxagentDisplay, w, RevertToParent, CurrentTime);
XCheckTypedWindowEvent(nxagentDisplay, w, LeaveNotify, &e);
nxagentFullscreenWindow = w;
if (nxagentOption(DesktopResize))
{
if (!nxagentOption(Shadow))
{
nxagentChangeScreenConfig(0, WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)),
HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)), True);
}
else
{
nxagentShadowAdaptToRatio();
}
}
}
else
{
/*
* We have waited for a reparent event unsuccessfully.
* Something happened to the window manager.
*/
#ifdef WARNING
fprintf(stderr, "%s: WARNING! Expected ReparentNotify event missing.\n", __func__);
#endif
nxagentWMIsRunning = False;
attributes.override_redirect = False;
XChangeWindowAttributes(nxagentDisplay, w, valuemask, &attributes);
XMapWindow(nxagentDisplay, w);
}
}
else
{
/*
* FIXME:
* It could be necessary:
* - To restore screensaver.
* - To set or reset nxagentForceBackingStore flag.
* - To propagate device settings to the X server if no WM is running.
*/
/*
* Change to windowed mode.
*/
nxagentChangeOption(Fullscreen, False);
nxagentChangeOption(AllScreens, False);
XDestroyWindow(nxagentDisplay, nxagentIconWindow);
nxagentIconWindow = nxagentFullscreenWindow = None;
if (nxagentOption(DesktopResize))
{
nxagentChangeOption(RootWidth, nxagentOption(SavedRootWidth));
nxagentChangeOption(RootHeight, nxagentOption(SavedRootHeight));
if (!nxagentOption(Shadow))
{
nxagentChangeScreenConfig(0, nxagentOption(RootWidth),
nxagentOption(RootHeight), True);
}
}
/*
* FIXME: These are 0 most of the time nowadays. The effect is,
* that the window is moving a bit to right/bottom every time
* fullscreen mode is left. To fix this query the frame extents
* from the window manager via _NET_REQUEST_FRAME_EXTENTS
*/
if (nxagentOption(WMBorderWidth) > 0)
{
#ifdef DEBUG
fprintf(stderr, "%s: WMBorderWidth [%d]\n", __func__, nxagentOption(WMBorderWidth));
#endif
nxagentChangeOption(X, nxagentOption(SavedX) - nxagentOption(WMBorderWidth));
}
else
{
nxagentChangeOption(X, nxagentOption(SavedX));
}
if (nxagentOption(WMTitleHeight) > 0)
{
#ifdef DEBUG
fprintf(stderr, "%s: WMTitleHeight [%d]\n", __func__, nxagentOption(WMTitleHeight));
#endif
nxagentChangeOption(Y, nxagentOption(SavedY) - nxagentOption(WMTitleHeight));
}
else
{
nxagentChangeOption(Y, nxagentOption(SavedY));
}
nxagentChangeOption(Width, nxagentOption(SavedWidth));
nxagentChangeOption(Height, nxagentOption(SavedHeight));
if (nxagentOption(Shadow) && nxagentOption(DesktopResize))
{
nxagentShadowAdaptToRatio();
}
XMoveResizeWindow(nxagentDisplay, w, nxagentOption(X), nxagentOption(Y),
nxagentOption(Width), nxagentOption(Height));
nxagentUpdateViewportFrame(0, 0, nxagentOption(Width), nxagentOption(Height));
XMoveWindow(nxagentDisplay, nxagentWindow(pScreen->root), 0, 0);
XMapWindow(nxagentDisplay, w);
nxagentChangeOption(RootX, 0);
nxagentChangeOption(RootY, 0);
}
XMoveResizeWindow(nxagentDisplay, nxagentInputWindows[0], 0, 0,
nxagentOption(Width), nxagentOption(Height));
/* if we had AutoGrab before entering fullscreen reactivate it now */
if (nxagentOption(AutoGrab))
nxagentGrabPointerAndKeyboard(NULL);
nxagentSetPrintGeometry(pScreen -> myNum);
}
#ifdef VIEWPORT_FRAME
void nxagentUpdateViewportFrame(int x, int y, int w, int h)
{
/*
* Four virtual windows make a frame around the viewport. We move the frame
* with the viewport together. The areas going into the viewport were covered by
* the frame and become exposed. This make the agent send expose events to his
* clients.
*/
XID values[3];
Mask mask;
/*
* nxagentScreenTrap = True;
*/
values[2] = Above;
values[1] = nxagentOption(RootHeight);
mask = CWX | CWHeight | CWStackMode;
values[0] = x - NXAGENT_FRAME_WIDTH;
ConfigureWindow(nxagentViewportFrameLeft, mask, (XID *) &values, serverClient);
values[0] = x + w;
ConfigureWindow(nxagentViewportFrameRight, mask, (XID *) &values, serverClient);
values[1] = nxagentOption(RootWidth);
mask = CWY | CWWidth | CWStackMode;
values[0] = y - NXAGENT_FRAME_WIDTH;
ConfigureWindow(nxagentViewportFrameAbove, mask, (XID *) &values, serverClient);
values[0] = y + h;
ConfigureWindow(nxagentViewportFrameBelow, mask, (XID *) &values, serverClient);
/*
* nxagentScreenTrap = False;
*/
}
#endif /* #ifdef VIEWPORT_FRAME */
void nxagentMoveViewport(ScreenPtr pScreen, int hShift, int vShift)
{
int newX, newY, oldX = 0, oldY = 0;
Bool doMove = False;
if (nxagentOption(Rootless))
{
return;
}
/*
* We must keep x coordinate between viewportXSpan and zero, if viewportXSpan
* is less then zero. If viewportXSpan is greater or equal to zero, it means
* the agent root window has a size smaller than the agent default window.
* In this case we keep the old coordinate.
*/
#ifdef DEBUG
fprintf(stderr, "nxagentMoveViewport: RootX[%i] RootY[%i], hShift[%i] vShift[%i].\n",
nxagentOption(RootX), nxagentOption(RootY), hShift, vShift);
#endif
nxagentChangeOption(ViewportXSpan, nxagentOption(Width) - nxagentOption(RootWidth));
nxagentChangeOption(ViewportYSpan, nxagentOption(Height) - nxagentOption(RootHeight));
if (nxagentOption(ViewportXSpan) < 0)
{
newX = nxagentOption(RootX) - hShift;
if (newX > 0)
{
newX = 0;
}
else if (newX < nxagentOption(ViewportXSpan))
{
newX = nxagentOption(ViewportXSpan);
}
}
else if (nxagentOption(ViewportXSpan) == 0)
{
newX = 0;
}
else
{
newX = nxagentOption(RootX);
}
if (nxagentOption(ViewportYSpan) < 0)
{
newY = nxagentOption(RootY) - vShift;
if (newY > 0)
{
newY = 0;
}
else if (newY < nxagentOption(ViewportYSpan))
{
newY = nxagentOption(ViewportYSpan);
}
}
else if (nxagentOption(ViewportYSpan) == 0)
{
newY = 0;
}
else
{
newY = nxagentOption(RootY);
}
oldX = nxagentOption(RootX);
if (newX != nxagentOption(RootX))
{
nxagentChangeOption(RootX, newX);
doMove = True;
}
oldY = nxagentOption(RootY);
if (newY != nxagentOption(RootY))
{
nxagentChangeOption(RootY, newY);
doMove = True;
}
if (doMove)
{
#ifdef TEST
fprintf(stderr, "nxagentMoveViewport: New viewport geometry: (%d, %d)-"
"(%d, %d)\n", -nxagentOption(RootX), -nxagentOption(RootY),
-nxagentOption(RootX) + nxagentOption(Width),
-nxagentOption(RootY) + nxagentOption(Height));
fprintf(stderr, "nxagentMoveViewport: Root geometry x=[%d] y=[%d]\n",
pScreen->root -> drawable.x,
pScreen->root -> drawable.y );
#endif
XMoveWindow(nxagentDisplay, nxagentWindow(pScreen->root),
nxagentOption(RootX), nxagentOption(RootY));
if (nxagentOption(ClientOs) == ClientOsWinnt)
{
/*
* If doMove is True we add exposed rectangles to the remote
* expose region. This is done to refresh the areas showed newly
* in the viewport. We create two rectangles, one for
* horizontal pan and one for vertical pan.
*/
BoxRec hRect = {.x1 = -newX, .y1 = -newY};
if (hShift < 0)
{
hRect.x2 = -oldX;
hRect.y2 = -newY + nxagentOption(Height);
}
else if (hShift > 0)
{
hRect.x1 = -oldX + nxagentOption(Width);
hRect.x2 = -newX + nxagentOption(Width);
hRect.y2 = -newY + nxagentOption(Height);
}
#ifdef DEBUG
fprintf(stderr, "nxagentMoveViewport: hRect p1[%i, %i] - p2[%i, %i].\n", hRect.x1, hRect.y1, hRect.x2, hRect.y2);
#endif
BoxRec vRect = {.x1 = -newX, .y1 = -newY};
if (vShift < 0)
{
vRect.x2 = -newX + nxagentOption(Width);
vRect.y2 = -oldY;
}
else if (vShift > 0)
{
vRect.y1 = -oldY + nxagentOption(Height);
vRect.x2 = -newX + nxagentOption(Width);
vRect.y2 = -newY + nxagentOption(Height);
}
#ifdef DEBUG
fprintf(stderr, "nxagentMoveViewport: vRect p1[%i, %i] - p2[%i, %i].\n", vRect.x1, vRect.y1, vRect.x2, vRect.y2);
#endif
if (oldX != newX && hRect.x1 != hRect.x2 && hRect.y1 != hRect.y2)
{
nxagentAddRectToRemoteExposeRegion(&hRect);
}
if (oldY != newY && vRect.x1 != vRect.x2 && vRect.y1 != vRect.y2)
{
nxagentAddRectToRemoteExposeRegion(&vRect);
}
}
}
nxagentUpdateViewportFrame(-nxagentOption(RootX), -nxagentOption(RootY),
nxagentOption(Width), nxagentOption(Height));
}
/*
* This will update the window on the real X server by calling
* XConfigureWindow()/XMapWindow()/XLowerWindow()/XRaiseWindow().
* mask defines the values that need to be updated, see e.g.
* man XConfigureWindow.
*
* In addition to the bit flags known to Xorg it uses these
* self-defined ones: CW_Update, CW_Shape, CW_Map, CW_RootlessRestack.
*/
void nxagentConfigureWindow(WindowPtr pWin, unsigned int mask)
{
unsigned int valuemask;
XWindowChanges values;
int offX = nxagentWindowPriv(pWin)->x - pWin->origin.x;
int offY = nxagentWindowPriv(pWin)->y - pWin->origin.y;
if (nxagentScreenTrap)
{
#ifdef TEST
fprintf(stderr, "nxagentConfigureWindow: WARNING: Called with the screen trap set.\n");
#endif
return;
}
if (nxagentOption(Rootless) &&
nxagentWindowTopLevel(pWin))
{
mask &= ~(CWSibling | CWStackMode);
}
else
{
if (mask & CW_RootlessRestack)
{
mask = CWStackMode;
}
}
#ifdef TEST
fprintf(stderr, "nxagentConfigureWindow: Called with window [%p][%ld] and mask [%x].\n",
(void *) pWin, nxagentWindow(pWin), mask);
#endif
nxagentMoveCorruptedRegion(pWin, mask);
valuemask = 0;
if (mask & CW_Update)
{
mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth | CWStackMode;
}
if (mask & CWX)
{
valuemask |= CWX;
values.x = nxagentWindowPriv(pWin)->x = pWin->origin.x - wBorderWidth(pWin);
}
if (mask & CWY)
{
valuemask |= CWY;
values.y = nxagentWindowPriv(pWin)->y = pWin->origin.y - wBorderWidth(pWin);
}
if (mask & CWWidth)
{
valuemask |= CWWidth;
values.width = nxagentWindowPriv(pWin)->width = pWin->drawable.width;
}
if (mask & CWHeight)
{
valuemask |= CWHeight;
values.height = nxagentWindowPriv(pWin)->height = pWin->drawable.height;
}
if (mask & CWBorderWidth)
{
valuemask |= CWBorderWidth;
values.border_width = nxagentWindowPriv(pWin)->borderWidth =
pWin->borderWidth;
}
if (mask & CW_Update)
{
valuemask = 0;
}
if (valuemask)
{
#ifdef TEST
fprintf(stderr, "nxagentConfigureWindow: Going to configure window [%p][%ld] with mask [%x].\n",
(void *) pWin, nxagentWindow(pWin), valuemask);
#endif
if (pWin->bitGravity == StaticGravity &&
((mask & CWX) || (mask & CWY)) &&
((mask & CWWidth) || (mask & CWHeight)))
{
#ifdef TEST
fprintf(stderr, "nxagentConfigureWindow: Window has StaticGravity. Going to translate Expose events by offset [%d, %d].\n",
offX, offY);
#endif
nxagentAddStaticResizedWindow(pWin, XNextRequest(nxagentDisplay), offX, offY);
for (int j = 0; j < nxagentExposeQueue.length; j++)
{
int i = (nxagentExposeQueue.start + j) % EXPOSED_SIZE;
if (nxagentExposeQueue.exposures[i].pWindow == pWin &&
nxagentExposeQueue.exposures[i].remoteRegion != NullRegion)
{
RegionTranslate(nxagentExposeQueue.exposures[i].remoteRegion, offX, offY);
}
}
}
XConfigureWindow(nxagentDisplay, nxagentWindow(pWin), valuemask, &values);
MAKE_SYNC_CONFIGURE_WINDOW;
}
if (mask & CWStackMode &&
nxagentWindowPriv(pWin)->siblingAbove != nxagentWindowSiblingAbove(pWin))
{
WindowPtr pSib;
/*
* Find the top sibling.
*/
for (pSib = pWin; pSib->prevSib != NullWindow; pSib = pSib->prevSib);
/*
* Configure the top sibling.
*/
valuemask = CWStackMode;
values.stack_mode = Above;
#ifdef TEST
fprintf(stderr, "nxagentConfigureWindow: Going to configure top sibling [%ld] "
"with mask [%x] and parent [%ld].\n", nxagentWindow(pSib),
valuemask, nxagentWindowParent(pWin));
#endif
XConfigureWindow(nxagentDisplay, nxagentWindow(pSib), valuemask, &values);
MAKE_SYNC_CONFIGURE_WINDOW;
nxagentWindowPriv(pSib)->siblingAbove = None;
/*
* Configure the rest of siblings.
*/
valuemask = CWSibling | CWStackMode;
values.stack_mode = Below;
for (pSib = pSib->nextSib; pSib != NullWindow; pSib = pSib->nextSib)
{
values.sibling = nxagentWindowSiblingAbove(pSib);
#ifdef TEST
fprintf(stderr, "nxagentConfigureWindow: Going to configure other sibling [%ld] "
"with mask [%x] and parent [%ld] below [%ld].\n", nxagentWindow(pSib),
valuemask, nxagentWindowParent(pWin), nxagentWindowSiblingAbove(pSib));
#endif
XConfigureWindow(nxagentDisplay, nxagentWindow(pSib), valuemask, &values);
MAKE_SYNC_CONFIGURE_WINDOW;
nxagentWindowPriv(pSib)->siblingAbove = nxagentWindowSiblingAbove(pSib);
}
#ifdef TEST
{
Window root_return;
Window parent_return;
Window *children_return = NULL;
unsigned int nchildren_return;
Status result = XQueryTree(nxagentDisplay, DefaultRootWindow(nxagentDisplay),
&root_return, &parent_return, &children_return, &nchildren_return);
if (result)
{
fprintf(stderr, "nxagentConfigureWindow: Children of the root: ");
while(nchildren_return > 0)
{
pSib = nxagentWindowPtr(children_return[--nchildren_return]);
if (pSib)
{
fprintf(stderr, "%lu ", children_return[nchildren_return]);
}
}
fprintf(stderr, "\n");
}
else
{
fprintf(stderr, "nxagentConfigureWindow: Failed QueryTree request.\n ");
}
SAFE_XFree(children_return);
}
#endif
}
/*
* This should bring again the splash window
* on top, so why the else clause? Is this
* really needed?
*
*
* else if (mask & CWStackMode)
* {
* if (nxagentHaveSplashWindow())
* {
* valuemask = CWStackMode;
*
* values.stack_mode = Above;
*
* #ifdef TEST
* fprintf(stderr, "nxagentConfigureWindow: Going to configure splash window [%ld].\n",
* nxagentSplashWindow);
* #endif
*
* XConfigureWindow(nxagentDisplay, nxagentSplashWindow, valuemask, &values);
*
* MAKE_SYNC_CONFIGURE_WINDOW;
* }
* }
*/
if (mask & CW_RootlessRestack)
{
if (!pWin -> prevSib)
{
#ifdef TEST
fprintf(stderr, "nxagentConfigureWindow: Raising window [%p][%ld].\n",
(void *) pWin, nxagentWindow(pWin));
#endif
XRaiseWindow(nxagentDisplay, nxagentWindow(pWin));
}
else if (!pWin -> nextSib)
{
#ifdef TEST
fprintf(stderr, "nxagentConfigureWindow: Lowering window [%p][%ld].\n",
(void *) pWin, nxagentWindow(pWin));
#endif
XLowerWindow(nxagentDisplay, nxagentWindow(pWin));
}
else
{
XlibWindow windowList[2];
#ifdef TEST
fprintf(stderr, "nxagentConfigureWindow: Putting window [%p][%ld] in the middle.\n",
(void *) pWin, nxagentWindow(pWin));
#endif
windowList[0] = nxagentWindow(pWin->prevSib);
windowList[1] = nxagentWindow(pWin);
XRestackWindows(nxagentDisplay, windowList, 2);
}
}
#ifdef SHAPE
if (mask & CW_Shape)
{
nxagentShapeWindow(pWin);
}
#endif
if (mask & CW_Map &&
(!nxagentOption(Rootless) ||
nxagentRootlessWindow != pWin))
{
XMapWindow(nxagentDisplay, nxagentWindow(pWin));
return;
}
}
/*
* from "Definition of the Porting Layer for X v11 Sample Server":
*
* This function will be called when a window is reparented. At the
* time of the call, pWin will already be spliced into its new
* position in the window tree, and pPriorParent is its previous
* parent. This function can be NULL.
*
* We simply pass this over to the real X server.
*/
void nxagentReparentWindow(WindowPtr pWin, WindowPtr pOldParent)
{
if (nxagentScreenTrap)
{
return;
}
#ifdef TEST
fprintf(stderr, "nxagentReparentWindow: window at %p [%lx] previous parent at %p [%lx].\n",
(void*)pWin, nxagentWindow(pWin),
(void*)pOldParent, nxagentWindow(pOldParent));
#endif
XReparentWindow(nxagentDisplay, nxagentWindow(pWin),
nxagentWindowParent(pWin),
pWin->origin.x - wBorderWidth(pWin),
pWin->origin.y - wBorderWidth(pWin));
}
/*
* from "Definition of the Porting Layer for X v11 Sample Server":
*
* ChangeWindowAttributes is called whenever DIX changes window
* attributes, such as the size, front-to-back ordering, title, or
* anything of lesser severity that affects the window itself. The
* sample server implements this routine. It computes accelerators for
* quickly putting up background and border tiles. (See description of
* the set of routines stored in the WindowRec.)
*/
Bool nxagentChangeWindowAttributes(WindowPtr pWin, unsigned long mask)
{
XSetWindowAttributes attributes;
#ifdef TEST
fprintf(stderr, "nxagentChangeWindowAttributes: Changing attributes for window at [%p] with mask [%lu].\n",
(void *) pWin, mask);
#endif
if (nxagentScreenTrap)
{
return True;
}
if (mask & CWBackPixmap)
{
switch (pWin->backgroundState)
{
case None:
{
attributes.background_pixmap = None;
attributes.background_pixel = nxagentWhitePixel;
/*
* One of problems faced during the implementation of lazy
* encoding policies was due to the presence of windows with
* transparent background, usually created by X clients to
* cover some sensible areas (i.e. checkboxes used by
* Konqueror 3.5). The sequence of operations consists in
* drawing the underneath part before covering it with the
* transparent window, so when we synchronize the deferred
* drawing operation we have to bear in mind that the dest-
* ination area is covered by a window. By using the Inclu-
* deInferiors GC's property and by clipping the region to
* synchronize to the borderClip instead of clipList (to
* include the areas covered by children) we can easily take
* care of this situation, but there is a drawback: if the
* children are not transparent, we are going to synchronize
* invisible areas. To avoid this we have added the 'has-
* TransparentChildren' flag, which is set when a window has
* at least one child with background None. The problem is
* that we don't know when to reset the flag. This solution,
* also, doesn't take care of transparent windows which don't
* have childhood relationships with underneath windows.
* We tried to mark the whole windows as dirty when they are
* created to force the synchronization of transparent windows
* with the content of underneath windows, but, of course,
* this works only with the first synchronization because the
* transparent windows will be never marked again as dirty.
*/
if (pWin -> parent != NULL)
{
nxagentWindowPriv(pWin -> parent) -> hasTransparentChildren = 1;
#ifdef DEBUG
fprintf(stderr, "nxagentChangeWindowAttributes: WARNING! Window at [%p] got the "
"hasTransparentChildren flag.\n", (void *) pWin);
#endif
}
break;
}
case ParentRelative:
{
attributes.background_pixmap = ParentRelative;
break;
}
case BackgroundPixmap:
{
/*
* If a window background is corrupted, we grant its usability
* by clearing it with a solid color. When the pixmap will be
* fully synchronized, an expose will be sent to the window's
* hierarchy.
*/
if (nxagentDrawableStatus((DrawablePtr) pWin -> background.pixmap) == NotSynchronized)
{
#ifdef TEST
fprintf(stderr, "nxagentChangeWindowAttributes: The window at [%p] has the background at [%p] "
"not synchronized.\n", (void *) pWin, (void *) pWin -> background.pixmap);
#endif
if (nxagentIsCorruptedBackground(pWin -> background.pixmap) == 0)
{
nxagentIsCorruptedBackground(pWin -> background.pixmap) = 1;
nxagentAllocateCorruptedResource((DrawablePtr) pWin -> background.pixmap, RT_NX_CORR_BACKGROUND);
/*
* Clearing the remote background to make it usable.
*/
nxagentFillRemoteRegion((DrawablePtr) pWin -> background.pixmap,
nxagentCorruptedRegion((DrawablePtr) pWin -> background.pixmap));
}
}
attributes.background_pixmap = nxagentPixmap(pWin -> background.pixmap);
break;
}
case BackgroundPixel:
{
mask &= ~CWBackPixmap;
break;
}
}
}
if (mask & CWBackPixel)
{
if (pWin -> backgroundState == BackgroundPixel)
{
attributes.background_pixel = nxagentPixel(pWin -> background.pixel);
}
else
{
mask &= ~CWBackPixel;
}
}
if (mask & CWBorderPixmap)
{
if (pWin -> borderIsPixel != 0)
{
mask &= ~CWBorderPixmap;
}
else
{
attributes.border_pixmap = nxagentPixmap(pWin -> border.pixmap);
}
}
if (mask & CWBorderPixel)
{
if (pWin -> borderIsPixel != 0)
{
attributes.border_pixel = nxagentPixel(pWin -> border.pixel);
}
else
{
mask &= ~CWBorderPixel;
}
}
if (mask & CWBitGravity)
{
attributes.bit_gravity = pWin -> bitGravity;
}
/*
* As we set this bit, we must change dix in order not to perform
* PositionWindow and let X move children windows for us.
*/
if (mask & CWWinGravity)
{
attributes.win_gravity = pWin -> winGravity;
}
/*
FIXME: Do we need to set the attribute on the remote display?
*/
if (mask & CWBackingStore)
{
attributes.backing_store = pWin -> backingStore;
#ifdef TEST
fprintf(stderr, "nxagentChangeWindowAttributes: Changing backing store value to %d"
" for window at %p.\n", pWin -> backingStore, (void*)pWin);
#endif
}
if (mask & CWBackingPlanes)
{
if ((nxagentBackingStore == NotUseful) || (pWin -> optional == NULL))
{
mask &= ~CWBackingPlanes;
}
else
{
attributes.backing_planes = pWin -> optional -> backingBitPlanes;
}
}
if (mask & CWBackingPixel)
{
if ((nxagentBackingStore == NotUseful) || (pWin -> optional == NULL))
{
mask &= ~CWBackingPixel;
}
else
{
attributes.backing_pixel = pWin -> optional -> backingPixel;
}
}
if (mask & CWOverrideRedirect)
{
attributes.override_redirect = pWin -> overrideRedirect;
}
/*
FIXME: Do we need to set the attribute on the remote display?
*/
if (mask & CWSaveUnder)
{
attributes.save_under = pWin -> saveUnder;
}
/*
* Events are handled elsewhere.
*/
if (mask & CWEventMask)
{
mask &= ~CWEventMask;
}
if (mask & CWDontPropagate)
{
mask &= ~CWDontPropagate;
}
if (mask & CWColormap)
{
ColormapPtr pCmap = (ColormapPtr) LookupIDByType(wColormap(pWin), RT_COLORMAP);
/*
FIXME: When the caller is nxagentReconfigureWindow sometimes
wColormap(pWin) is 0. Could a window have no colormap?
*/
if (pCmap != NULL)
{
attributes.colormap = nxagentColormap(pCmap);
nxagentSetInstalledColormapWindows(pWin -> drawable.pScreen);
}
else
{
#ifdef WARNING
fprintf(stderr, "nxagentChangeWindowAttributes: WARNING! Bad colormap "
"[%lu] for window at [%p].\n", wColormap(pWin), (void *) pWin);
#endif
mask &= ~CWColormap;
}
}
if (mask & CWCursor)
{
if (nxagentOption(Rootless))
{
if (pWin->cursorIsNone == 0 && pWin->optional != NULL &&
pWin->optional->cursor != NULL && nxagentCursorPriv(pWin ->
optional -> cursor, pWin -> drawable.pScreen) != NULL)
{
attributes.cursor = nxagentCursor(pWin -> optional -> cursor,
pWin -> drawable.pScreen);
}
else
{
attributes.cursor = None;
}
}
else
{
/*
* This is handled in cursor code
*/
mask &= ~CWCursor;
}
}
if (mask != 0)
{
XChangeWindowAttributes(nxagentDisplay, nxagentWindow(pWin), mask, &attributes);
}
return 1;
}
/* Set the WM_STATE property of pWin to the desired value */
void nxagentSetWMState(WindowPtr pWin, CARD32 desired)
{
Atom prop = MakeAtom("WM_STATE", strlen("WM_STATE"), True);
nxagentWMStateRec wmState = {.state = desired, .icon = None};
if (ChangeWindowProperty(pWin, prop, prop, 32, 0, 2, &wmState, 1) != Success)
{
#ifdef WARNING
fprintf(stderr, "%s: Changing WM_STATE failed.\n", __func__);
#endif
}
}
/*
* from "Definition of the Porting Layer for X v11 Sample Server":
*
* RealizeWindow/UnRealizeWindow:
* These routines are hooks for when DIX maps (makes visible) and
* unmaps (makes invisible) a window. It should do whatever private
* operations need to be done when these happen, such as allocating or
* deallocating structures that are only needed for visible
* windows. RealizeWindow does NOT draw the window border, background
* or contents; UnrealizeWindow does NOT erase the window or generate
* exposure events for underlying windows; this is taken care of by
* DIX. DIX does, however, call PaintWindowBackground() and
* PaintWindowBorder() to perform some of these.
-+ */
Bool nxagentRealizeWindow(WindowPtr pWin)
{
if (nxagentScreenTrap)
{
return True;
}
/*
* Not needed.
*
* nxagentConfigureWindow(pWin, CWStackMode);
*
* nxagentFlushConfigureWindow();
*/
nxagentAddConfiguredWindow(pWin, CWStackMode);
nxagentAddConfiguredWindow(pWin, CW_Shape);
/* add by dimbor */
if (nxagentOption(Rootless) && nxagentWindowTopLevel(pWin))
{
nxagentSetWMState(pWin, NormalState);
}
/*
* Not needed.
*
#ifdef SHAPE
nxagentShapeWindow(pWin);
#endif
*/
#ifdef TEST
if (nxagentOption(Rootless) && nxagentLastWindowDestroyed)
{
fprintf(stderr, "%s: Window realized. Stopped termination for rootless session.\n", __func__);
}
#endif
nxagentAddConfiguredWindow(pWin, CW_Map);
nxagentLastWindowDestroyed = False;
return True;
}
/* See nxagentRealizeWindow for a description */
Bool nxagentUnrealizeWindow(WindowPtr pWin)
{
if (nxagentScreenTrap)
{
return True;
}
/* add by dimbor */
if (nxagentOption(Rootless) && nxagentWindowTopLevel(pWin))
{
/*
* The original _comment_ was WithdrawnState, while the _value_
* was 3, which is IconicState.
*/
nxagentSetWMState(pWin, IconicState);
}
XUnmapWindow(nxagentDisplay, nxagentWindow(pWin));
return True;
}
void nxagentFrameBufferPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what)
{
if (pWin->backgroundState == BackgroundPixmap)
{
pWin->background.pixmap = nxagentVirtualPixmap(pWin->background.pixmap);
}
if (pWin->borderIsPixel == False)
{
pWin->border.pixmap = nxagentVirtualPixmap(pWin->border.pixmap);
}
/*
* Call fbPaintWindow(). We need to temporarily replace
* PaintWindowBackground() by ourself because fbPaintWindow() is
* recursively calling it for parent windows, too.
*/
{
void (*PaintWindowBackgroundBackup)(WindowPtr, RegionPtr, int);
PaintWindowBackgroundBackup = pWin->drawable.pScreen -> PaintWindowBackground;
pWin->drawable.pScreen -> PaintWindowBackground = nxagentFrameBufferPaintWindow;
fbPaintWindow(pWin, pRegion, what);
pWin->drawable.pScreen -> PaintWindowBackground = PaintWindowBackgroundBackup;
}
if (pWin->backgroundState == BackgroundPixmap)
{
pWin->background.pixmap = nxagentRealPixmap(pWin->background.pixmap);
}
if (pWin->borderIsPixel == False)
{
pWin->border.pixmap = nxagentRealPixmap(pWin->border.pixmap);
}
}
void nxagentPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, int what)
{
if (pWin -> realized)
{
BoxPtr pBox = RegionRects(pRegion);
for (int i = 0; i < RegionNumRects(pRegion); i++)
{
XClearArea(nxagentDisplay, nxagentWindow(pWin),
pBox[i].x1 - pWin->drawable.x,
pBox[i].y1 - pWin->drawable.y,
pBox[i].x2 - pBox[i].x1,
pBox[i].y2 - pBox[i].y1,
False);
}
}
#ifdef TEST
else
{
fprintf(stderr, "nxagentPaintWindowBackground: Saving the operation with window "
"at [%p] not realized.\n", (void *) pWin);
}
#endif
/*
* The framebuffer operations don't take care of clipping to the
* actual area of the framebuffer so we need to clip ourselves.
*/
RegionRec temp;
RegionInit(&temp, NullBox, 1);
RegionIntersect(&temp, pRegion, &pWin -> clipList);
nxagentFrameBufferPaintWindow(pWin, &temp, what);
RegionUninit(&temp);
}
void nxagentPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, int what)
{
/*
* The framebuffer operations don't take care of clipping to the
* actual area of the framebuffer so we need to clip ourselves.
*/
RegionRec temp;
RegionInit(&temp, NullBox, 1);
RegionIntersect(&temp, pRegion, &pWin -> borderClip);
nxagentFrameBufferPaintWindow(pWin, &temp, what);
RegionUninit(&temp);
}
/*
* from "Definition of the Porting Layer for X v11 Sample Server":
*
* CopyWindow is called when a window is moved, and graphically moves
* to pixels of a window on the screen. It should not change any other
* state within DDX (see PositionWindow(), above).
*
* oldpt is the old location of the upper-left corner. oldRegion is
* the old region it is coming from. The new location and new region
* is stored in the WindowRec. oldRegion might modified in place by
* this routine (the sample implementation does this).
*
* CopyArea could be used, except that this operation has more
* complications. First of all, you do not want to copy a rectangle
* onto a rectangle. The original window may be obscured by other
* windows, and the new window location may be similarly
* obscured. Second, some hardware supports multiple windows with
* multiple depths, and your routine needs to take care of that.
*
* The pixels in oldRegion (with reference point oldpt) are copied to
* the window's new region (pWin->borderClip). pWin->borderClip is
* gotten directly from the window, rather than passing it as a
* parameter.
*
* The sample server implementation is in Xserver/fb/fbwindow.c.
*/
void nxagentCopyWindow(WindowPtr pWin, xPoint oldOrigin, RegionPtr oldRegion)
{
fbCopyWindow(pWin, oldOrigin, oldRegion);
}
/*
* from "Definition of the Porting Layer for X v11 Sample Server":
*
* Whenever the cliplist for a window is changed, this function is
* called to perform whatever hardware manipulations might be
* necessary. When called, the clip list and border clip regions in
* the window are set to the new values. dx,dy are the distance that
* the window has been moved (if at all).
*/
void nxagentClipNotify(WindowPtr pWin, int dx, int dy)
{
/*
* nxagentConfigureWindow(pWin, CWStackMode);
*/
nxagentAddConfiguredWindow(pWin, CWStackMode);
nxagentAddConfiguredWindow(pWin, CW_Shape);
#ifdef SHAPE
/*
* nxagentShapeWindow(pWin);
*/
#endif /* SHAPE */
}
/*
* from "Definition of the Porting Layer for X v11 Sample Server":
*
* The WindowExposures() routine paints the border and generates
* exposure events for the window. pRegion is an unoccluded region of
* the window, and pBSRegion is an occluded region that has backing
* store. Since exposure events include a rectangle describing what
* was exposed, this routine may have to send back a series of
* exposure events, one for each rectangle of the region. The count
* field in the expose event is a hint to the client as to the number
* of regions that are after this one. This routine must be
* provided. The sample server has a machine-independent version in
* Xserver/mi/miexpose.c.
*/
void nxagentWindowExposures(WindowPtr pWin, RegionPtr pRgn, RegionPtr other_exposed)
{
/*
* The problem: we want to synthetize the expose events internally, so
* that we reduce the time between a window operation and the corresp-
* onding graphical output, but at the same time we need to take care
* of the remote exposures, as we need to handle those cases where our
* windows are covered by the windows on the real display. Handling
* both the local and the remote exposures we would generate the same
* redraws twice, something we call "double refreshes", so we must be
* able to identify which events have been already sent to our clients.
*
* Here is how the algorithm is working:
*
* - We collect the exposures that the agent sent to its clients in a
* region (the "local-region") and store the region for a given win-
* dow in a vector.
*
* - Another region collects the expose that were received from the
* real X server (the "remote-region") for the same window.
*
* - We create a "fake" off-screen window. For every generated region
* we send a ConfigureWindow request for that window to synchronize
* ourselves with both the remote X server and/or the window manager.
*
* - When the ConfigureNotify is received, we calculate the difference
* between the "remote-region" and the "local-region" for the window
* that had collected exposures.
*
* - Finally we send the resulting exposures to our clients.
*
* As you may have guessed, the windows are synchronized per-region,
* that is there is a single region for a set of exposures. The regions
* are handled in order. This means that we can always calculate the
* final region by referring to the first element of the vector.
*/
if (nxagentSessionState != SESSION_DOWN)
{
if (!nxagentExposeArrayIsInitialized)
{
#ifdef TEST
fprintf(stderr, "nxagentWindowExposures: Initializing expose queue.\n");
#endif
for (int i = 0; i < EXPOSED_SIZE; i++)
{
nxagentExposeQueue.exposures[i].pWindow = NULL;
nxagentExposeQueue.exposures[i].localRegion = NullRegion;
nxagentExposeQueue.exposures[i].remoteRegion = NullRegion;
nxagentExposeQueue.exposures[i].remoteRegionIsCompleted = False;
nxagentExposeQueue.exposures[i].serial = 0;
}
nxagentExposeQueue.start = 0;
nxagentExposeQueue.length = 0;
nxagentExposeSerial = 0;
XSetWindowAttributes attributes = {.event_mask = StructureNotifyMask};
nxagentConfiguredSynchroWindow = XCreateWindow(nxagentDisplay, DefaultRootWindow(nxagentDisplay), 0, 0,
1, 1, 0, 0, InputOutput, 0, CWEventMask, &attributes);
nxagentInitRemoteExposeRegion();
nxagentExposeArrayIsInitialized = True;
}
RegionRec temp;
RegionInit(&temp, (BoxRec *) NULL, 1);
if (pRgn != NULL)
{
if (RegionNumRects(pRgn) > RECTLIMIT)
{
BoxRec box = *RegionExtents(pRgn);
RegionEmpty(pRgn);
RegionInit(pRgn, &box, 1);
}
RegionUnion(&temp, &temp, pRgn);
}
if (other_exposed != NULL)
{
RegionUnion(&temp, &temp, other_exposed);
}
if (!RegionNil(&temp))
{
RegionTranslate(&temp,
-(pWin -> drawable.x), -(pWin -> drawable.y));
if (nxagentExposeQueue.length < EXPOSED_SIZE)
{
int index = (nxagentExposeQueue.start + nxagentExposeQueue.length) % EXPOSED_SIZE;
nxagentExposeQueue.exposures[index].pWindow = pWin;
nxagentExposeQueue.exposures[index].localRegion = RegionCreate(NULL, 1);
if (nxagentOption(Rootless) && nxagentWindowPriv(pWin) &&
(nxagentWindowPriv(pWin) -> isMapped == 0 ||
nxagentWindowPriv(pWin) -> visibilityState != VisibilityUnobscured))
{
nxagentExposeQueue.exposures[index].remoteRegion = RegionCreate(NULL, 1);
RegionUnion(nxagentExposeQueue.exposures[index].remoteRegion,
nxagentExposeQueue.exposures[index].remoteRegion, &temp);
#ifdef TEST
fprintf(stderr, "nxagentWindowExposures: Added region to remoteRegion for window [%ld] to position [%d].\n",
nxagentWindow(pWin), nxagentExposeQueue.length);
#endif
}
else
{
RegionUnion(nxagentExposeQueue.exposures[index].localRegion,
nxagentExposeQueue.exposures[index].localRegion, &temp);
#ifdef TEST
fprintf(stderr, "nxagentWindowExposures: Added region to localRegion for window [%ld] to position [%d].\n",
nxagentWindow(pWin), nxagentExposeQueue.length);
#endif
}
nxagentExposeSerial = (nxagentExposeSerial - 1) % EXPOSED_SIZE;
nxagentExposeQueue.exposures[index].serial = nxagentExposeSerial;
#ifdef TEST
fprintf(stderr, "nxagentWindowExposures: Added region to queue with serial [%d].\n", nxagentExposeSerial);
#endif
/*
* Mark this region for sending a synchro, in
* nxagentFlushConfigureWindow().
*/
nxagentExposeQueue.exposures[index].synchronize = 1;
nxagentExposeQueue.length++;
if (nxagentOption(Rootless) && nxagentWindowPriv(pWin) &&
(nxagentWindowPriv(pWin) -> isMapped == 0 ||
nxagentWindowPriv(pWin) -> visibilityState != VisibilityUnobscured))
{
RegionUninit(&temp);
return;
}
}
else
{
RegionUninit(&temp);
#ifdef TEST
fprintf(stderr, "nxagentWindowExposures: WARNING! Reached maximum size of collect exposures vector.\n");
#endif
if ((pRgn != NULL && RegionNotEmpty(pRgn) != 0) ||
(other_exposed != NULL && RegionNotEmpty(other_exposed) != 0))
{
nxagentUnmarkExposedRegion(pWin, pRgn, other_exposed);
miWindowExposures(pWin, pRgn, other_exposed);
}
return;
}
}
RegionUninit(&temp);
}
if ((pRgn != NULL && RegionNotEmpty(pRgn) != 0) ||
(other_exposed != NULL && RegionNotEmpty(other_exposed) != 0))
{
nxagentUnmarkExposedRegion(pWin, pRgn, other_exposed);
miWindowExposures(pWin, pRgn, other_exposed);
}
return;
}
#ifdef SHAPE
static Bool nxagentRegionEqual(RegionPtr pReg1, RegionPtr pReg2)
{
if (pReg1 == pReg2)
{
return True;
}
if (pReg1 == NullRegion || pReg2 == NullRegion)
{
return False;
}
BoxPtr pBox1 = RegionRects(pReg1);
int n1 = RegionNumRects(pReg1);
BoxPtr pBox2 = RegionRects(pReg2);
int n2 = RegionNumRects(pReg2);
if (n1 != n2)
{
return False;
}
if (pBox1 == pBox2)
{
return True;
}
if (memcmp(pBox1, pBox2, n1 * sizeof(BoxRec)))
{
return False;
}
return True;
}
void nxagentShapeWindow(WindowPtr pWin)
{
if (NXDisplayError(nxagentDisplay) == 1)
{
return;
}
#ifdef DEBUG
fprintf(stderr, "nxagentShapeWindow: Window at [%p][%ld].\n",
(void *) pWin, nxagentWindow(pWin));
#endif
/*
FIXME: this is the same code as below, just with another shape. Maybe move
this code to a helper function?
*/
if (!nxagentRegionEqual(nxagentWindowPriv(pWin)->boundingShape,
wBoundingShape(pWin)))
{
#ifdef DEBUG
fprintf(stderr, "nxagentShapeWindow: Bounding shape differs.\n");
#endif
if (wBoundingShape(pWin))
{
#ifdef DEBUG
fprintf(stderr, "nxagentShapeWindow: wBounding shape has [%ld] rects.\n",
RegionNumRects(wBoundingShape(pWin)));
#endif
if (!nxagentWindowPriv(pWin)->boundingShape)
{
nxagentWindowPriv(pWin)->boundingShape = RegionCreate(NULL, 1);
}
RegionCopy(nxagentWindowPriv(pWin)->boundingShape, wBoundingShape(pWin));
Region reg = XCreateRegion();
BoxPtr pBox = RegionRects(nxagentWindowPriv(pWin)->boundingShape);
for (int i = 0;
i < RegionNumRects(nxagentWindowPriv(pWin)->boundingShape);
i++)
{
XRectangle rect = {
.x = pBox[i].x1,
.y = pBox[i].y1,
.width = pBox[i].x2 - pBox[i].x1,
.height = pBox[i].y2 - pBox[i].y1
};
XUnionRectWithRegion(&rect, reg, reg);
}
XShapeCombineRegion(nxagentDisplay, nxagentWindow(pWin),
ShapeBounding, 0, 0, reg, ShapeSet);
XDestroyRegion(reg);
}
else
{
#ifdef DEBUG
fprintf(stderr, "nxagentShapeWindow: wBounding shape does not exist. Removing the shape.\n");
#endif
RegionEmpty(nxagentWindowPriv(pWin)->boundingShape);
XShapeCombineMask(nxagentDisplay, nxagentWindow(pWin),
ShapeBounding, 0, 0, None, ShapeSet);
}
}
if (!nxagentRegionEqual(nxagentWindowPriv(pWin)->clipShape, wClipShape(pWin)))
{
#ifdef DEBUG
fprintf(stderr, "nxagentShapeWindow: Clip shape differs.\n");
#endif
if (wClipShape(pWin))
{
#ifdef DEBUG
fprintf(stderr, "nxagentShapeWindow: wClip shape has [%ld] rects.\n",
RegionNumRects(wClipShape(pWin)));
#endif
if (!nxagentWindowPriv(pWin)->clipShape)
{
nxagentWindowPriv(pWin)->clipShape = RegionCreate(NULL, 1);
}
RegionCopy(nxagentWindowPriv(pWin)->clipShape, wClipShape(pWin));
Region reg = XCreateRegion();
BoxPtr pBox = RegionRects(nxagentWindowPriv(pWin)->clipShape);
for (int i = 0;
i < RegionNumRects(nxagentWindowPriv(pWin)->clipShape);
i++)
{
XRectangle rect = {
.x = pBox[i].x1,
.y = pBox[i].y1,
.width = pBox[i].x2 - pBox[i].x1,
.height = pBox[i].y2 - pBox[i].y1
};
XUnionRectWithRegion(&rect, reg, reg);
}
XShapeCombineRegion(nxagentDisplay, nxagentWindow(pWin),
ShapeClip, 0, 0, reg, ShapeSet);
XDestroyRegion(reg);
}
else
{
#ifdef DEBUG
fprintf(stderr, "nxagentShapeWindow: wClip shape does not exist. Removing the shape.\n");
#endif
RegionEmpty(nxagentWindowPriv(pWin)->clipShape);
XShapeCombineMask(nxagentDisplay, nxagentWindow(pWin),
ShapeClip, 0, 0, None, ShapeSet);
}
}
}
#endif /* SHAPE */
static int nxagentForceExposure(WindowPtr pWin, void * ptr)
{
if (pWin -> drawable.class != InputOnly)
{
WindowPtr pRoot = pWin->drawable.pScreen->root;
BoxRec Box = {
.x1 = pWin->drawable.x,
.y1 = pWin->drawable.y,
.x2 = Box.x1 + pWin->drawable.width,
.y2 = Box.y1 + pWin->drawable.height,
};
RegionPtr exposedRgn = RegionCreate(&Box, 1);
RegionIntersect(exposedRgn, exposedRgn, &pRoot->winSize);
if (exposedRgn != NULL && RegionNotEmpty(exposedRgn) != 0)
{
miWindowExposures(pWin, exposedRgn, NullRegion);
}
RegionDestroy(exposedRgn);
}
return WT_WALKCHILDREN;
}
void nxagentRefreshWindows(WindowPtr pWin)
{
int action = 1;
TraverseTree(pWin, nxagentForceExposure, &action);
}
void nxagentUnmapWindows(void)
{
if (nxagentOption(Fullscreen))
{
for (int i = 0; i < screenInfo.numScreens; i++)
{
if (nxagentDefaultWindows[i])
{
XUnmapWindow(nxagentDisplay, nxagentDefaultWindows[i]);
}
}
}
NXFlushDisplay(nxagentDisplay, NXFlushLink);
}
void nxagentMapDefaultWindows(void)
{
for (int i = 0; i < screenInfo.numScreens; i++)
{
WindowPtr pWin = screenInfo.screens[i]->root;
ScreenPtr pScreen = pWin -> drawable.pScreen;
/*
* InitRootWindow does that already, but as MapWindow() is
* idempotent we keep it here, too
*/
MapWindow(pWin, serverClient);
if (!nxagentOption(Rootless))
{
/*
* Show the NX splash screen.
*/
#ifdef TEST
fprintf(stderr, "nxagentMapDefaultWindows: Showing the splash window.\n");
#endif
nxagentShowSplashWindow(nxagentDefaultWindows[pScreen->myNum]);
/*
* Map the default window. Defer the mapping if the session is
* of shadow type. If no WM is running on the remote display,
* map the window soon anyway: this avoids a flickering effect
* on the !M logo if the shadow session is displayed from a
* Windows client.
*/
if (!nxagentOption(Shadow) || !nxagentWMIsRunning)
{
#ifdef TEST
fprintf(stderr, "nxagentMapDefaultWindows: Mapping default window id [%ld].\n",
nxagentDefaultWindows[pScreen->myNum]);
#endif
XMapWindow(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum]);
if (nxagentOption(Fullscreen) && nxagentWMIsRunning)
{
nxagentMaximizeToFullScreen(pScreen);
}
}
/*
* Map and raise the input window.
*/
XMapWindow(nxagentDisplay, nxagentInputWindows[pScreen->myNum]);
/*
* At reconnection the Input Window is raised in
* nxagentReconnectAllWindows, after the Root Window is mapped.
*/
if (!nxagentReconnectTrap)
{
XRaiseWindow(nxagentDisplay, nxagentInputWindows[pScreen->myNum]);
}
}
#ifdef NXAGENT_ONSTART
/*
* Send a SetSelectionOwner request to notify of the agent start.
*/
XSetSelectionOwner(nxagentDisplay, serverTransToAgentProperty,
nxagentDefaultWindows[i], CurrentTime);
#endif
}
/*
* Map the icon window.
*/
if (nxagentIconWindow != None)
{
#ifdef TEST
fprintf(stderr, "nxagentMapDefaultWindows: Mapping icon window id [%ld].\n",
nxagentIconWindow);
#endif
XMapWindow(nxagentDisplay, nxagentIconWindow);
}
/*
* Ensure that the fullscreen window gets the focus.
*/
if (nxagentFullscreenWindow != None)
{
XSetInputFocus(nxagentDisplay, nxagentFullscreenWindow,
RevertToParent, CurrentTime);
}
#ifdef TEST
fprintf(stderr, "nxagentMapDefaultWindows: Completed mapping of default windows.\n");
#endif
}
Bool nxagentDisconnectAllWindows(void)
{
Bool succeeded = True;
#if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_WINDOW_DEBUG)
fprintf(stderr, "nxagentDisconnectAllWindows\n");
#endif
for (int i = 0; i < screenInfo.numScreens; i++)
{
nxagentTraverseWindow(screenInfo.screens[i]->root, nxagentDisconnectWindow, &succeeded);
nxagentDefaultWindows[i] = None;
}
#ifdef NXAGENT_RECONNECT_WINDOW_DEBUG
fprintf(stderr, "nxagentDisconnectAllWindows: all windows disconnected\n");
#endif
return succeeded;
}
/*
* FIXME: We are giving up reconnecting those void *
* that are not resource, and we are just disconnecting them.
* Perhaps we could do better and reconnect them.
*/
void nxagentDisconnectWindow(void * p0, XID x1, void * p2)
{
WindowPtr pWin = (WindowPtr)p0;
Bool* pBool = (Bool*)p2;
CursorPtr pCursor = wCursor(pWin);
ScreenPtr pScreen = pWin -> drawable.pScreen;
if ((pCursor = wCursor(pWin)) &&
nxagentCursorPriv(pCursor, pScreen) &&
nxagentCursor(pCursor, pScreen))
{
#ifdef NXAGENT_RECONNECT_CURSOR_DEBUG
char msg[] = "nxagentDisconnectWindow:";
nxagentPrintCursorInfo(pCursor, msg);
#endif
#ifdef NXAGENT_RECONNECT_CURSOR_DEBUG
fprintf(stderr, "nxagentDisconnectWindow: window %p - disconnecting cursor %p ID %lx\n",
pWin, pCursor, nxagentCursor(pCursor, pScreen));
#endif
nxagentDisconnectCursor(pCursor, (XID)0, pBool);
if (!*pBool)
{
#ifdef WARNING
fprintf(stderr, "nxagentDisconnectWindow: WARNING failed disconnection of cursor at [%p]"
" for window at [%p]: ignoring it.\n", (void*)pCursor, (void*)pWin);
#endif
*pBool = True;
}
}
#ifdef NXAGENT_RECONNECT_CURSOR_DEBUG
else if (pCursor)
{
fprintf(stderr, "nxagentDisconnectWindow: window %p - cursor %p already disconnected\n",
pWin, pCursor);
}
#endif
if ((nxagentRealWindowProp) && (!nxagentWindowTopLevel(pWin)))
{
Atom prop = MakeAtom("NX_REAL_WINDOW", strlen("NX_REAL_WINDOW"), True);
if (DeleteProperty(pWin, prop) != Success)
{
fprintf(stderr, "nxagentDisconnectWindow: Deleting NX_REAL_WINDOW failed.\n");
}
#ifdef DEBUG
else
{
fprintf(stderr, "nxagentDisconnectWindow: Deleting NX_REAL_WINDOW from Window ID [%x].\n", nxagentWindowPriv(pWin)->window);
}
#endif
}
nxagentWindow(pWin) = None;
if (nxagentDrawableStatus((DrawablePtr) pWin) == NotSynchronized)
{
nxagentDestroyCorruptedResource((DrawablePtr) pWin, RT_NX_CORR_WINDOW);
}
}
Bool nxagentReconnectAllWindows(void *p0)
{
/*
access the parameter like this if this function needs it in future:
int flexibility = *(int *) p0;
*/
#if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_WINDOW_DEBUG)
fprintf(stderr, "nxagentReconnectAllWindows\n");
#endif
if (screenInfo.screens[0]->root -> backgroundState == BackgroundPixmap &&
screenInfo.screens[0]->root -> background.pixmap == NULL)
{
FatalError("nxagentReconnectAllWindows: correct the FIXME\n");
}
if (nxagentOption(Fullscreen))
{
screenInfo.screens[0]->root -> origin.x = nxagentOption(RootX);
screenInfo.screens[0]->root -> origin.y = nxagentOption(RootY);
}
if (!nxagentLoopOverWindows(nxagentReconnectWindow))
{
#ifdef WARNING
fprintf(stderr, "nxagentReconnectAllWindows: couldn't recreate windows\n");
#endif
return False;
}
#ifdef NXAGENT_RECONNECT_WINDOW_DEBUG
XSync(nxagentDisplay, 0);
fprintf(stderr, "nxagentReconnectAllWindows: all windows recreated\n");
#endif
if (!nxagentLoopOverWindows(nxagentReconfigureWindow))
{
#ifdef WARNING
fprintf(stderr, "nxagentReconnectAllWindows: couldn't reconfigure windows\n");
#endif
return False;
}
/*
* After the Root Window has been mapped, the Input Windows is
* raised.
*/
if (!nxagentOption(Rootless))
{
for (int i = 0; i < screenInfo.numScreens; i++)
{
XRaiseWindow(nxagentDisplay, nxagentInputWindows[i]);
}
}
nxagentFlushConfigureWindow();
if (nxagentOption(Fullscreen))
{
screenInfo.screens[0]->root -> origin.x = 0;
screenInfo.screens[0]->root -> origin.y = 0;
}
#ifdef NXAGENT_RECONNECT_WINDOW_DEBUG
XSync(nxagentDisplay, 0);
fprintf(stderr, "nxagentReconnectAllWindows: All windows reconfigured.\n");
#endif
if (!nxagentInitClipboard(screenInfo.screens[0]->root))
{
#ifdef WARNING
fprintf(stderr, "nxagentReconnectAllWindows: WARNING! Couldn't initialize the clipboard.\n");
#endif
return False;
}
#ifdef NXAGENT_RECONNECT_WINDOW_DEBUG
XSync(nxagentDisplay, 0);
fprintf(stderr, "nxagentReconnectAllWindows: Clipboard initialized.\n");
#endif
#ifdef VIEWPORT_FRAME
/*
* We move the viewport frames out of the way on the X server side.
*/
if (nxagentViewportFrameLeft &&
nxagentViewportFrameRight &&
nxagentViewportFrameAbove &&
nxagentViewportFrameBelow)
{
XMoveWindow(nxagentDisplay, nxagentWindow(nxagentViewportFrameLeft),
-NXAGENT_FRAME_WIDTH, 0);
XMoveWindow(nxagentDisplay, nxagentWindow(nxagentViewportFrameRight),
nxagentOption(RootWidth), 0);
XMoveWindow(nxagentDisplay, nxagentWindow(nxagentViewportFrameAbove),
0, -NXAGENT_FRAME_WIDTH);
XMoveWindow(nxagentDisplay, nxagentWindow(nxagentViewportFrameBelow),
0, nxagentOption(RootHeight));
}
#endif /* #ifdef VIEWPORT_FRAME */
return True;
}
Bool nxagentSetWindowCursors(void *p0)
{
/*
access the parameter like this if this function needs it in future:
int flexibility = *(int *) p0;
*/
#if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_WINDOW_DEBUG)
fprintf(stderr, "nxagentSetWindowCursors: Going to loop over the windows.\n");
#endif
if (!nxagentLoopOverWindows(nxagentReconfigureWindowCursor))
{
#ifdef WARNING
fprintf(stderr, "nxagentSetWindowCursors: WARNING! Couldn't configure all windows' cursors.\n");
#endif
return False;
}
#ifdef NXAGENT_RECONNECT_WINDOW_DEBUG
fprintf(stderr, "nxagentSetWindowCursors: All cursors configured.\n");
#endif
nxagentReDisplayCurrentCursor();
return True;
}
static void nxagentTraverseWindow(
WindowPtr pWin,
void (*pF)(void *, XID, void *),
void * p)
{
pF(pWin, 0, p);
if (pWin -> nextSib)
{
nxagentTraverseWindow(pWin -> nextSib, pF, p);
}
if (pWin -> firstChild)
{
nxagentTraverseWindow(pWin -> firstChild, pF, p);
}
}
static Bool nxagentLoopOverWindows(void (*pF)(void *, XID, void *))
{
Bool windowSuccess = True;
for (int i = 0; i < screenInfo.numScreens; i++)
{
nxagentTraverseWindow(screenInfo.screens[i]->root, pF, &windowSuccess);
}
return windowSuccess;
}
static void nxagentReconnectWindow(void * param0, XID param1, void * data_buffer)
{
WindowPtr pWin = (WindowPtr)param0;
Bool *pBool = (Bool*)data_buffer;
Visual *visual;
unsigned long mask;
XSetWindowAttributes attributes;
ColormapPtr pCmap;
if (!pWin || !*pBool)
{
return;
}
#ifdef NXAGENT_RECONNECT_WINDOW_DEBUG
fprintf(stderr, "nxagentReconnectWindow: %p - ID %lx\n", pWin, nxagentWindow(pWin));
#endif
if (pWin->drawable.class == InputOnly)
{
mask = CWEventMask;
visual = CopyFromParent;
}
else
{
mask = CWEventMask | CWBackingStore;
attributes.backing_store = NotUseful;
if (pWin->optional)
{
mask |= CWBackingPlanes | CWBackingPixel;
attributes.backing_planes = pWin->optional->backingBitPlanes;
attributes.backing_pixel = pWin->optional->backingPixel;
}
/*
FIXME: Do we need to set save unders attribute here?
*/
if (nxagentSaveUnder)
{
mask |= CWSaveUnder;
attributes.save_under = pWin->saveUnder;
}
if (pWin->parent)
{
if (pWin->optional && pWin->optional->visual != wVisual(pWin->parent))
{
visual = nxagentVisualFromID(pWin->drawable.pScreen, wVisual(pWin));
mask |= CWColormap;
if (pWin->optional->colormap)
{
pCmap = (ColormapPtr)LookupIDByType(wColormap(pWin), RT_COLORMAP);
attributes.colormap = nxagentColormap(pCmap);
}
else
{
attributes.colormap = nxagentDefaultVisualColormap(visual);
}
}
else
{
visual = CopyFromParent;
}
}
else
{
/* root windows have their own colormaps at creation time */
visual = nxagentVisualFromID(pWin->drawable.pScreen, wVisual(pWin));
pCmap = (ColormapPtr)LookupIDByType(wColormap(pWin), RT_COLORMAP);
mask |= CWColormap;
attributes.colormap = nxagentColormap(pCmap);
}
}
if (mask & CWEventMask)
{
attributes.event_mask = nxagentGetEventMask(pWin);
}
#ifdef WARNING
else
{
attributes.event_mask = NoEventMask;
}
#endif
#ifdef TEST
fprintf(stderr, "nxagentReconnectWindow: Going to create new window.\n");
fprintf(stderr, "nxagentReconnectWindow: Recreating %swindow at %p current event mask = %lX mask & CWEventMask = %ld "
"event_mask = %lX\n",
nxagentWindowTopLevel(pWin) ? "toplevel " : "", (void*)pWin, pWin -> eventMask,
mask & CWEventMask, attributes.event_mask);
#endif
/*
* FIXME: This quick hack is intended to solve a problem of NXWin X
* server for windows. The NXWin minimize the windows moving
* them out of the screen area, this behaviour can cause
* problem when a rootless session is disconnected and an
* apps is minimized. It will be solved with new Xorg
* version of the NXWin server.
*/
if (nxagentOption(Rootless))
{
if (pWin -> drawable.x == -32000 && pWin -> drawable.y == -32000)
{
pWin -> drawable.x = (pWin -> drawable.pScreen -> width - pWin -> drawable.width) / 2;
pWin -> drawable.y = (pWin -> drawable.pScreen -> height - pWin -> drawable.height) /2;
}
if (pWin -> origin.x == -32000 && pWin -> origin.y == -32000)
{
pWin -> origin.x = (pWin -> drawable.pScreen -> width - pWin -> drawable.width) / 2;
pWin -> origin.y = (pWin -> drawable.pScreen -> height - pWin -> drawable.height) / 2;
}
}
nxagentWindow(pWin) = XCreateWindow(nxagentDisplay,
nxagentWindowParent(pWin),
pWin->origin.x -
wBorderWidth(pWin),
pWin->origin.y -
wBorderWidth(pWin),
pWin->drawable.width,
pWin->drawable.height,
pWin->borderWidth,
pWin->drawable.depth,
pWin->drawable.class,
visual,
mask,
&attributes);
if (nxagentReportPrivateWindowIds)
{
fprintf(stderr, "NXAGENT_WINDOW_ID: %s_WINDOW,WID:[0x%x],INT:[0x%x]\n",
(pWin->drawable.id == pWin->drawable.pScreen->root->drawable.id) ? "ROOT" : "PRIVATE",
nxagentWindowPriv(pWin)->window, pWin->drawable.id);
}
#ifdef DEBUG
{
char *winname = NULL;
if (-1 != asprintf(&winname, "%s %s[0x%lx]", nxagentWindowName,
(pWin->drawable.id == pWin->drawable.pScreen->root->drawable.id) ? "Root" : "Private",
pWin->drawable.id))
{
Xutf8SetWMProperties(nxagentDisplay, nxagentWindowPriv(pWin)->window,
winname, winname, NULL , 0 , NULL, NULL, NULL);
SAFE_free(winname);
}
}
#endif
#ifdef TEST
fprintf(stderr, "nxagentReconnectWindow: Created new window with id [0x%x].\n",
nxagentWindowPriv(pWin)->window);
#endif
/*
* We have to set the WM_DELETE_WINDOW protocols on every top level
* window, because we don't know if a client handles this.
*/
if (nxagentOption(Rootless) && (pWin != screenInfo.screens[0]->root))
{
if (nxagentWindowTopLevel(pWin))
{
XlibAtom prop = nxagentMakeAtom("WM_PROTOCOLS", strlen("WM_PROTOCOLS"), True);
XlibAtom atom = nxagentMakeAtom("WM_DELETE_WINDOW", strlen("WM_DELETE_WINDOW"), True);
XSetWMProtocols(nxagentDisplay, nxagentWindow(pWin), &atom, 1);
nxagentAddPropertyToList(prop, pWin);
}
nxagentExportAllProperty(pWin);
if (nxagentWindowTopLevel(pWin))
{
Atom type;
int format;
unsigned long nItems, bytesLeft;
XSizeHints hints = {0};
unsigned char *data = NULL;
#ifdef _XSERVER64
unsigned char *data64 = NULL;
#endif
int ret = GetWindowProperty(pWin,
XA_WM_NORMAL_HINTS,
0, sizeof(XSizeHints),
False, XA_WM_SIZE_HINTS,
&type, &format, &nItems, &bytesLeft, &data);
/*
* 72 is the number of bytes returned by sizeof(XSizeHints) on
* 32 bit platforms.
*/
if (ret == Success &&
((format >> 3) * nItems) == 72 &&
bytesLeft == 0 &&
type == XA_WM_SIZE_HINTS)
{
#ifdef TEST
fprintf(stderr, "nxagentReconnectWindow: setting WMSizeHints on window %p [%lx - %lx].\n",
(void*)pWin, pWin -> drawable.id, nxagentWindow(pWin));
#endif
/* FIXME: use XAllocSizeHints() */
/* FIXME: all this copying is only done because the first
element of the XSizeHints struct is a long which is of
different size on 32bit vs. 64bit platforms. We should
rewrite this to better readable and probably more robust
code */
#ifdef _XSERVER64
data64 = (unsigned char *) malloc(sizeof(XSizeHints) + 4);
if (data64)
{
for (int i = 0; i < 4; i++)
{
*(data64 + i) = *(data + i);
}
*(((int *) data64) + 1) = 0;
for (int i = 8; i < sizeof(XSizeHints) + 4; i++)
{
*(data64 + i) = *(data + i - 4);
}
XSizeHints *props = (XSizeHints *) data64;
hints = *props;
}
else
{
#ifdef WARNING
fprintf(stderr, "%s: Failed to alloc memory for XSizeHints\n", __func__);
#endif
}
#else
XSizeHints *props = (XSizeHints *) data;
hints = *props;
#endif /* _XSERVER64 */
}
else
{
#ifdef WARNING
fprintf(stderr, "nxagentReconnectWindow: Failed to get property WM_NORMAL_HINTS on window %p\n",
(void*)pWin);
#endif
}
hints.flags |= (USPosition | PWinGravity);
hints.x = pWin -> drawable.x;
hints.y = pWin -> drawable.y;
hints.win_gravity = StaticGravity;
XSetWMNormalHints(nxagentDisplay,
nxagentWindow(pWin),
&hints);
#ifdef _XSERVER64
SAFE_free(data64);
#endif
}
}
if ((nxagentRealWindowProp) && (!nxagentWindowTopLevel(pWin)))
{
Atom prop = MakeAtom("NX_REAL_WINDOW", strlen("NX_REAL_WINDOW"), True);
if (ChangeWindowProperty(pWin, prop, XA_WINDOW, 32, PropModeReplace, 1, nxagentWindowPriv(pWin), 1) != Success)
{
fprintf(stderr, "nxagentReconnectWindow: Updating NX_REAL_WINDOW failed.\n");
}
#ifdef DEBUG
else
{
fprintf(stderr, "nxagentReconnectWindow: Updated NX_REAL_WINDOW for Window ID [%x].\n", nxagentWindowPriv(pWin)->window);
}
#endif
}
if (nxagentDrawableStatus((DrawablePtr) pWin) == NotSynchronized)
{
nxagentAllocateCorruptedResource((DrawablePtr) pWin, RT_NX_CORR_WINDOW);
}
}
static void nxagentReconfigureWindowCursor(void * param0, XID param1, void * data_buffer)
{
WindowPtr pWin = (WindowPtr)param0;
Bool *pBool = (Bool*)data_buffer;
CursorPtr pCursor;
if (!pWin || !*pBool || !(pCursor = wCursor(pWin)))
{
return;
}
ScreenPtr pScreen = pWin -> drawable.pScreen;
if (!(nxagentCursorPriv(pCursor, pScreen)))
{
return;
}
#ifdef DEBUG
fprintf(stderr, "nxagentReconfigureWindowCursor: %p - ID %lx geometry (%d,%d,%d,%d) "
"cursor %p - ID %lx\n",
pWin, nxagentWindow(pWin),
pWin -> drawable.x,
pWin -> drawable.y,
pWin -> drawable.width,
pWin -> drawable.height,
pCursor, nxagentCursor(pCursor, pScreen));
#endif
if (nxagentCursor(pCursor, pScreen) == None)
{
#ifdef NXAGENT_RECONNECT_WINDOW_DEBUG
fprintf(stderr, "nxagentReconfigureWindowCursor: reconnecting valid cursor %lx\n",
(void*)pCursor);
#endif
nxagentReconnectCursor(pCursor, 0, pBool);
if (!*pBool)
{
#ifdef WARNING
fprintf(stderr, "nxagentReconfigureWindowCursor: WARNING "
"failed reconnection of cursor at [%p] for window at [%p]: ignoring it.\n",
(void*)pCursor, (void*)pWin);
#endif
*pBool = True;
}
}
if (nxagentOption(Rootless))
{
XDefineCursor(nxagentDisplay,nxagentWindow(pWin),nxagentCursor(pCursor,pScreen));
}
}
static void nxagentReconfigureWindow(void * param0, XID param1, void * data_buffer)
{
WindowPtr pWin = (WindowPtr)param0;
unsigned long mask = 0;
#ifdef DEBUG
fprintf(stderr, "nxagentReconfigureWindow: pWin %p - ID %lx\n", pWin, nxagentWindow(pWin));
#endif
if (pWin -> drawable.class == InputOnly)
{
mask = CWWinGravity | CWEventMask | CWDontPropagate | CWOverrideRedirect | CWCursor;
}
else
{
mask = CWBackPixmap | CWBackPixel | CWBorderPixmap | CWBorderPixel |
CWBitGravity | CWWinGravity | CWBackingStore | CWBackingPlanes |
CWBackingPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask |
CWDontPropagate | CWColormap | CWCursor;
}
nxagentChangeWindowAttributes(pWin, mask);
#ifdef SHAPE
if (nxagentWindowPriv(pWin) -> boundingShape)
{
RegionDestroy(nxagentWindowPriv(pWin) -> boundingShape);
nxagentWindowPriv(pWin) -> boundingShape = NULL;
}
if (nxagentWindowPriv(pWin) -> clipShape)
{
RegionDestroy(nxagentWindowPriv(pWin) -> clipShape);
nxagentWindowPriv(pWin) -> clipShape = NULL;
}
nxagentShapeWindow(pWin);
#endif
if (pWin != screenInfo.screens[0]->root)
{
if (pWin->realized)
{
nxagentRealizeWindow (pWin);
}
/*
XXX: This would break Motif menus.
If pWin is mapped but not realized, a following UnmapWindow() wouldn't
do anything, leaving this mapped window around. XMapWindow()
is called in nxagentRealizeWindow() and there it is enough.
else if (pWin->mapped)
{
XMapWindow(nxagentDisplay, nxagentWindow(pWin));
}
*/
else if (nxagentOption(Rootless) && pWin -> overrideRedirect == 0 &&
nxagentWindowTopLevel(pWin) && nxagentIsIconic(pWin))
{
MapWindow(pWin, serverClient);
XIconifyWindow(nxagentDisplay, nxagentWindow(pWin), pWin -> drawable.pScreen -> myNum);
}
}
else if (!nxagentOption(Rootless))
{
/*
* Map the root window.
*/
XMoveWindow(nxagentDisplay, nxagentWindow(pWin),
nxagentOption(RootX), nxagentOption(RootY));
XMapWindow(nxagentDisplay, nxagentWindow(pWin));
}
}
Bool nxagentCheckIllegalRootMonitoring(WindowPtr pWin, Mask mask)
{
Mask invalidMask = SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask;
if (nxagentOption(Rootless) &&
pWin == screenInfo.screens[0]->root &&
(mask & invalidMask))
{
return True;
}
return False;
}
#ifdef TEST
Bool nxagentCheckWindowIntegrity(WindowPtr pWin)
{
Bool integrity = True;
unsigned int width = pWin -> drawable.width;
unsigned int height = pWin -> drawable.height;
unsigned int depth = pWin -> drawable.depth;
int format = (depth == 1) ? XYPixmap : ZPixmap;
if (width && height)
{
unsigned int length = nxagentImageLength(width, height, format, 0, depth);
char *data = calloc(1, length);
if (data == NULL)
{
FatalError("nxagentCheckWindowIntegrity: Failed to allocate a buffer of size %d.\n", length);
}
unsigned long plane_mask = AllPlanes;
XImage *image = XGetImage(nxagentDisplay, nxagentWindow(pWin), 0, 0,
width, height, plane_mask, format);
if (image == NULL)
{
fprintf(stderr, "XGetImage: Failed.\n");
return False;
}
fbGetImage((DrawablePtr)pWin, 0, 0, width, height, format, plane_mask, data);
if (image && memcmp(image->data, data, length) != 0)
{
integrity = False;
#ifdef TEST
char *p = image->data, *q = data;
for (int i = 0; i < length; i++)
{
if (p[i] != q[i])
{
fprintf(stderr, "[%d] %d - %d !!!!!!!!!!!!!!!!!!! **************** !!!!!!!!!!!!!!!!!\n", i, p[i], q[i]);
}
else
{
fprintf(stderr, "[%d] %d - %d\n", i, p[i], q[i]);
}
}
#endif
#ifdef WARNING
fprintf(stderr, "nxagentCheckWindowIntegrity: Window %p width %d, height %d, has been realized "
"but the data buffer still differs.\n", (void*) pWin, width, height);
fprintf(stderr, "nxagentCheckWindowIntegrity: bytes_per_line = %d byte pad %d format %d.\n",
image -> bytes_per_line, nxagentImagePad(width, height, 0, depth), image->format);
fprintf(stderr, "nxagentCheckWindowIntegrity: image is corrupted!!\n");
#endif
}
else
{
#ifdef WARNING
fprintf(stderr, "nxagentCheckWindowIntegrity: Window %p has been realized "
"now remote and framebuffer data are synchronized.\n", (void*) pWin);
#endif
}
if (image)
{
XDestroyImage(image);
}
SAFE_free(data);
}
else
{
#ifdef WARNING
fprintf(stderr, "nxagentCheckWindowIntegrity: ignored window %p with geometry (%d,%d).\n",
(void*) pWin, width, height);
#endif
}
return integrity;
}
#endif /* TEST */
Bool nxagentIsIconic(WindowPtr pWin)
{
unsigned long ulReturnItems;
unsigned long ulReturnBytesLeft;
Atom atomReturnType;
int iReturnFormat;
unsigned char *pszReturnData = NULL;
if (!wUserProps (pWin))
{
return 0;
}
int iReturn = GetWindowProperty(pWin, MakeAtom("WM_STATE", 8, False), 0, sizeof(CARD32), False,
AnyPropertyType, &atomReturnType, &iReturnFormat,
&ulReturnItems, &ulReturnBytesLeft, &pszReturnData);
if (iReturn == Success)
{
return (((CARD32 *)pszReturnData)[0] == IconicState);
}
else
{
return 0;
}
}
/* pass Eventmask to the real X server (for the rootless toplevel window only) */
void nxagentSetTopLevelEventMask(WindowPtr pWin)
{
if (nxagentOption(Rootless) && nxagentWindowTopLevel(pWin))
{
XSetWindowAttributes attributes = {.event_mask = nxagentGetEventMask(pWin)};
XChangeWindowAttributes(nxagentDisplay, nxagentWindow(pWin), CWEventMask, &attributes);
}
}
/*
* Run nxagentConfigureWindow() on all windows in
* nxagentConfiguredWindowList and move them from the list
* afterwards. The list will be empty then.
*
* This is also taking care of entries in nxagentExposeQueue that need
* to be synchronized with the real X server.
*/
void nxagentFlushConfigureWindow(void)
{
ConfiguredWindowStruct *index = nxagentConfiguredWindowList;
while (index)
{
if (index -> next == NULL)
{
break;
}
index = index -> next;
}
while (index)
{
WindowPtr pWin = index -> pWin;
unsigned int valuemask = index -> valuemask;
if (pWin && valuemask)
{
nxagentConfigureWindow(pWin, valuemask);
}
if (index == nxagentConfiguredWindowList)
{
SAFE_free(index);
break;
}
else
{
ConfiguredWindowStruct *tmp = index;
index = index -> prev;
SAFE_free(tmp);
}
}
nxagentConfiguredWindowList = NULL;
for (int j = 0; j < nxagentExposeQueue.length; j++)
{
int i = (nxagentExposeQueue.start + j) % EXPOSED_SIZE;
if (nxagentExposeQueue.exposures[i].synchronize == 1)
{
XWindowChanges changes = {
.x = nxagentExposeQueue.exposures[i].serial,
.y = -2
};
#ifdef DEBUG
fprintf(stderr, "nxagentFlushConfigureWindow: Sending synch ConfigureWindow for "
"index [%d] serial [%d].\n", i, nxagentExposeQueue.exposures[i].serial);
#endif
XConfigureWindow(nxagentDisplay, nxagentConfiguredSynchroWindow,
CWX | CWY, &changes);
nxagentExposeQueue.exposures[i].synchronize = 0;
}
}
nxagentSendDeferredBackgroundExposures();
return;
}
/*
* from "Definition of the Porting Layer for X v11 Sample Server":
*
* If this routine is not NULL, DIX calls it shortly after calling
* ValidateTree, passing it the same arguments. This is useful for
* managing multi-layered framebuffers. The sample server sets this to
* NULL.
*/
void nxagentPostValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
{
/*
FIXME: Do we need this here?
nxagentFlushConfigureWindow();
*/
return;
}
/*
* Add the given window to the beginning of
* nxagentconfiguredWindowList. This list collects all windows that
* need to be reconfigured on the real X server. valuemask defines
* what changes need to be done. The required values (like position,
* size, ...) are already stored in pWin).
*
* Note that we just add the window to the list here. The actual work
* will be done by nxagentFlushConfigureWindow() later.
*/
void nxagentAddConfiguredWindow(WindowPtr pWin, unsigned int valuemask)
{
unsigned int mask;
mask = valuemask & (CWSibling | CWX | CWY | CWWidth | CWHeight |
CWBorderWidth | CWStackMode | CW_Map | CW_Update | CW_Shape);
valuemask &= ~(CWSibling | CWX | CWY | CWWidth | CWHeight | CWBorderWidth | CWStackMode);
if (mask & CWX &&
nxagentWindowPriv(pWin)->x !=
pWin->origin.x - wBorderWidth(pWin))
{
valuemask |= CWX;
}
if (mask & CWY &&
nxagentWindowPriv(pWin)->y !=
pWin->origin.y - wBorderWidth(pWin))
{
valuemask |= CWY;
}
if (mask & CWWidth &&
nxagentWindowPriv(pWin)->width !=
pWin->drawable.width)
{
valuemask |= CWWidth;
}
if (mask & CWHeight &&
nxagentWindowPriv(pWin)->height !=
pWin->drawable.height)
{
valuemask |= CWHeight;
}
if (mask & CWBorderWidth &&
nxagentWindowPriv(pWin)->borderWidth !=
pWin->borderWidth)
{
valuemask |= CWBorderWidth;
}
if (mask & CWStackMode &&
nxagentWindowPriv(pWin)->siblingAbove !=
nxagentWindowSiblingAbove(pWin))
{
valuemask |= CWStackMode;
}
{
ConfiguredWindowStruct *tmp = nxagentConfiguredWindowList;
nxagentConfiguredWindowList = malloc(sizeof(ConfiguredWindowStruct));
nxagentConfiguredWindowList -> next = tmp; /* can be NULL */
nxagentConfiguredWindowList -> prev = NULL;
nxagentConfiguredWindowList -> pWin = pWin;
nxagentConfiguredWindowList -> valuemask = valuemask;
if (tmp)
{
tmp -> prev = nxagentConfiguredWindowList;
}
}
return;
}
/*
* remove pWin from nxgentConfigureWindowList
*
* This is just updating the linked list and freeing the
* given entry. It will not perform any X stuff
*/
void nxagentDeleteConfiguredWindow(WindowPtr pWin)
{
ConfiguredWindowStruct *index, *previous, *tmp;
index = nxagentConfiguredWindowList;
while (index)
{
WindowPtr pDel = index -> pWin;
if (pDel == pWin)
{
if (index -> prev == NULL && index -> next == NULL)
{
SAFE_free(nxagentConfiguredWindowList);
return;
}
else if (index -> prev == NULL)
{
tmp = nxagentConfiguredWindowList;
index = nxagentConfiguredWindowList = tmp -> next;
SAFE_free(tmp);
nxagentConfiguredWindowList -> prev = NULL;
continue;
}
else if (index -> next == NULL)
{
tmp = index;
index = index -> prev;
SAFE_free(tmp);
index -> next = NULL;
return;
}
previous = index -> prev;
tmp = index;
index = index -> next;
previous -> next = index;
index -> prev = previous;
SAFE_free(tmp);
continue;
}
index = index -> next;
}
return;
}
void nxagentAddStaticResizedWindow(WindowPtr pWin, unsigned long sequence, int offX, int offY)
{
StaticResizedWindowStruct *tmp = nxagentStaticResizedWindowList;
nxagentStaticResizedWindowList = malloc(sizeof(StaticResizedWindowStruct));
if (!nxagentStaticResizedWindowList)
{
#ifdef WARNING
fprintf(stderr, "WARNING: could not allocate memory for nxagentStaticResizedWindowList\n");
#endif
nxagentStaticResizedWindowList = tmp;
return;
}
nxagentStaticResizedWindowList -> next = tmp;
nxagentStaticResizedWindowList -> prev = NULL;
if (tmp)
{
tmp -> prev = nxagentStaticResizedWindowList;
}
nxagentStaticResizedWindowList -> pWin = pWin;
nxagentStaticResizedWindowList -> sequence = sequence;
nxagentStaticResizedWindowList -> offX = offX;
nxagentStaticResizedWindowList -> offY = offY;
}
void nxagentDeleteStaticResizedWindow(unsigned long sequence)
{
StaticResizedWindowStruct *index, *previous, *tmp;
index = nxagentStaticResizedWindowList;
while (index)
{
if (index -> sequence <= sequence)
{
if (index -> prev == NULL && index -> next == NULL)
{
SAFE_free(nxagentStaticResizedWindowList);
return;
}
else if (index -> prev == NULL)
{
tmp = nxagentStaticResizedWindowList;
index = nxagentStaticResizedWindowList = tmp -> next;
SAFE_free(tmp);
nxagentStaticResizedWindowList -> prev = NULL;
continue;
}
else if (index -> next == NULL)
{
tmp = index;
index = index -> prev;
SAFE_free(tmp);
index -> next = NULL;
return;
}
previous = index -> prev;
tmp = index;
index = index -> next;
previous -> next = index;
index -> prev = previous;
SAFE_free(tmp);
continue;
}
index = index -> next;
}
return;
}
StaticResizedWindowStruct *nxagentFindStaticResizedWindow(unsigned long sequence)
{
StaticResizedWindowStruct *ret = NULL;
if (nxagentStaticResizedWindowList == NULL)
{
return NULL;
}
StaticResizedWindowStruct *index = nxagentStaticResizedWindowList;
while (index && index -> sequence > sequence)
{
ret = index;
index = index -> next;
}
return ret;
}
void nxagentEmptyBackingStoreRegion(void * param0, XID param1, void * data_buffer)
{
WindowPtr pWin = (WindowPtr) param0;
miBSWindowPtr pBackingStore = (miBSWindowPtr)pWin->backStorage;
if (pBackingStore != NULL)
{
RegionEmpty(&pBackingStore->SavedRegion);
#ifdef TEST
fprintf(stderr, "nxagentEmptyBackingStoreRegion: Emptying saved region for window at [%p].\n", (void*) pWin);
#endif
if (pBackingStore -> pBackingPixmap != NULL)
{
#ifdef TEST
fprintf(stderr, "nxagentEmptyBackingStoreRegion: Emptying corrupted region for drawable at [%p].\n",
(void*) pBackingStore -> pBackingPixmap);
#endif
nxagentUnmarkCorruptedRegion((DrawablePtr) pBackingStore -> pBackingPixmap, NullRegion);
}
}
}
void nxagentEmptyAllBackingStoreRegions(void)
{
if (nxagentLoopOverWindows(nxagentEmptyBackingStoreRegion) == 0)
{
#ifdef WARNING
fprintf(stderr, "nxagentEmptyAllSavedRegions: Failed to empty backing store saved regions.\n");
#endif
}
}
void nxagentInitBSPixmapList(void)
{
memset(nxagentBSPixmapList, 0, BSPIXMAPLIMIT * sizeof( StoringPixmapPtr));
}
int nxagentAddItemBSPixmapList(unsigned long id, PixmapPtr pPixmap, WindowPtr pWin, int bsx, int bsy)
{
for (int i = 0; i < BSPIXMAPLIMIT; i++)
{
if (nxagentBSPixmapList[i] == NULL)
{
nxagentBSPixmapList[i] = malloc(sizeof(StoringPixmapRec));
if (nxagentBSPixmapList[i] == NULL)
{
FatalError("nxagentAddItemBSPixmapList: Failed to allocate memory for nxagentBSPixmapList.\n");
}
nxagentBSPixmapList[i] -> storingPixmapId = id;
nxagentBSPixmapList[i] -> pStoringPixmap = pPixmap;
nxagentBSPixmapList[i] -> pSavedWindow = pWin;
nxagentBSPixmapList[i] -> backingStoreX = bsx;
nxagentBSPixmapList[i] -> backingStoreY = bsy;
#ifdef TEST
fprintf(stderr, "nxagentAddItemBSPixmapList: Added Pixmap with id [%lu] to nxagentBSPixmapList.\n", id);
#endif
return 1;
}
if (nxagentBSPixmapList[i] -> storingPixmapId == id)
{
nxagentBSPixmapList[i] -> pStoringPixmap = pPixmap;
nxagentBSPixmapList[i] -> pSavedWindow = pWin;
nxagentBSPixmapList[i] -> backingStoreX = bsx;
nxagentBSPixmapList[i] -> backingStoreY = bsy;
#ifdef TEST
fprintf(stderr, "nxagentAddItemBSPixmapList: Updated existing item for id [%lu].\n", id);
#endif
return 1;
}
}
#ifdef TEST
fprintf(stderr, "nxagentAddItemBSPixmapList: WARNING! List item full.\n");
#endif
return 0;
}
int nxagentRemoveItemBSPixmapList(unsigned long pixmapId)
{
if (pixmapId == 0 || nxagentBSPixmapList[0] == NULL)
{
return 0;
}
for (int i = 0; i < BSPIXMAPLIMIT; i++)
{
if ((nxagentBSPixmapList[i] != NULL) &&
(nxagentBSPixmapList[i] -> storingPixmapId == pixmapId))
{
SAFE_free(nxagentBSPixmapList[i]);
if (i < BSPIXMAPLIMIT - 1)
{
int j;
for (j = i; j < BSPIXMAPLIMIT -1; j++)
{
nxagentBSPixmapList[j] = nxagentBSPixmapList[j + 1];
}
if (nxagentBSPixmapList[j] == nxagentBSPixmapList[j - 1])
{
nxagentBSPixmapList[j] = NULL;
}
}
#ifdef TEST
fprintf(stderr, "nxagentRemoveItemBSPixmapList: Removed Pixmap with id [%lu] from list.\n",
pixmapId);
#endif
return 1;
}
}
#ifdef TEST
fprintf(stderr, "nxagentRemoveItemBSPixmapList: WARNING! Can't remove item [%lu]: item not found.\n",
pixmapId);
#endif
return 0;
}
int nxagentEmptyBSPixmapList(void)
{
for (int i = 0; i < BSPIXMAPLIMIT; i++)
{
SAFE_free(nxagentBSPixmapList[i]);
}
return 1;
}
StoringPixmapPtr nxagentFindItemBSPixmapList(unsigned long pixmapId)
{
for (int i = 0; i < BSPIXMAPLIMIT; i++)
{
if ((nxagentBSPixmapList[i] != NULL) &&
(nxagentBSPixmapList[i] -> storingPixmapId == pixmapId))
{
#ifdef TEST
fprintf(stderr, "%s: pixmapId [%lu].\n", __func__, pixmapId);
fprintf(stderr, "%s: nxagentBSPixmapList[%d] = [%p].\n", __func__,
i, (void *) nxagentBSPixmapList[i]);
fprintf(stderr, "%s: nxagentBSPixmapList[%d] -> storingPixmapId [%lu].\n", __func__,
i, nxagentBSPixmapList[i] -> storingPixmapId);
#endif
return nxagentBSPixmapList[i];
}
}
#ifdef TEST
fprintf(stderr, "%s: WARNING! Item not found.\n", __func__);
#endif
#ifdef TEST
fprintf(stderr, "%s: Pixmap with id [%lu] not found.\n", __func__,
pixmapId);
#endif
return NULL;
}