/**************************************************************************/ /* */ /* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ /* Copyright (c) 2008-2017 Oleksandr Shneyder */ /* Copyright (c) 2011-2022 Mike Gabriel */ /* Copyright (c) 2014-2019 Mihai Moldovan */ /* Copyright (c) 2014-2022 Ulrich Sibiller */ /* 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 #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 "Image.h" #include #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 _X_UNUSED 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, "%s: Backing store on window at [%p] is [%d].\n", __func__, (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, "%s: Going to create new window.\n", __func__); #endif #ifdef TEST fprintf(stderr, "%s: Creating %swindow at [%p][0x%x] current event mask [%X] mask & CWEventMask [%ld] " "event_mask [%lX]\n", __func__, nxagentWindowTopLevel(pWin) ? "toplevel " : "", (void*)pWin, pWin->drawable.id, pWin -> eventMask, mask & CWEventMask, attributes.event_mask); fprintf(stderr, "%s: position [%d,%d] size [%d,%d] depth [%d] border [%d] class [%d].\n", __func__, 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", nxagentWindow(pWin), pWin->drawable.id); } #ifdef DEBUG { char *winname = NULL; if (-1 != asprintf(&winname, "%s %s[0x%x]", nxagentWindowName, (pWin->drawable.id == pWin->drawable.pScreen->root->drawable.id) ? "Root" : "Private", pWin->drawable.id)) { Xutf8SetWMProperties(nxagentDisplay, nxagentWindow(pWin), winname, winname, NULL , 0 , NULL, NULL, NULL); SAFE_free(winname); } } #endif #ifdef TEST fprintf(stderr, "%s: Created new remote window with id [0x%x].\n", __func__, nxagentWindow(pWin)); #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, nxagentWindow(pWin), &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, "%s: Adding NX_REAL_WINDOW failed.\n", __func__); } #ifdef DEBUG else { fprintf(stderr, "%s: Added NX_REAL_WINDOW for Window ID [0x%x].\n", __func__, nxagentWindow(pWin)); } #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 [%p].\n", __func__, name, NX_VERSION_CURRENT_STRING, (void *)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; } #ifdef DEBUG fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin)); #endif 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, "%s: Synchronization drawable [%p] removed from resources.\n", __func__, (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, "%s: Last mapped window as been destroyed.\n", __func__); #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, "%s: Changing position of window [%p][0x%x] remote [0x%x] to [%d,%d].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin), x, y); #endif nxagentAddConfiguredWindow(pWin, CWSibling | CWX | CWY | CWWidth | CWHeight | CWBorderWidth); return True; } void nxagentRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib) { if (nxagentScreenTrap) { return; } #ifdef DEBUG fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin)); #endif 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, "%s: RootX[%i] RootY[%i], hShift[%i] vShift[%i].\n", __func__, 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, "%s: New viewport geometry: (%d, %d)-" "(%d, %d)\n", __func__, -nxagentOption(RootX), -nxagentOption(RootY), -nxagentOption(RootX) + nxagentOption(Width), -nxagentOption(RootY) + nxagentOption(Height)); fprintf(stderr, "%s: Root geometry x=[%d] y=[%d]\n", __func__, 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, "%s: hRect p1[%i, %i] - p2[%i, %i].\n", __func__, 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, "%s: vRect p1[%i, %i] - p2[%i, %i].\n", __func__, 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; if (nxagentScreenTrap) { #ifdef TEST fprintf(stderr, "%s: WARNING: Called with the screen trap set.\n", __func__); #endif return; } int offX = nxagentWindowPriv(pWin)->x - pWin->origin.x; int offY = nxagentWindowPriv(pWin)->y - pWin->origin.y; if (nxagentOption(Rootless) && nxagentWindowTopLevel(pWin)) { mask &= ~(CWSibling | CWStackMode); } else { if (mask & CW_RootlessRestack) { mask = CWStackMode; } } #ifdef TEST fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x] and mask [%x].\n", __func__, (void *) pWin, pWin->drawable.id, 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, "%s: Going to configure window [%p][0x%x] remote [0x%x] with mask [%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin), valuemask); #endif if (pWin->bitGravity == StaticGravity && ((mask & CWX) || (mask & CWY)) && ((mask & CWWidth) || (mask & CWHeight))) { #ifdef TEST fprintf(stderr, "%s: Window has StaticGravity. Going to translate Expose events by offset [%d, %d].\n", __func__, 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, "%s: Going to configure top sibling [0x%x] " "with mask [%x] and parent [0x%x].\n", __func__, 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, "%s: Going to configure other sibling [0x%x] " "with mask [%x] and parent [0x%x] below [0x%lx].\n", __func__, 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 { XlibWindow root_return; XlibWindow parent_return; XlibWindow *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, "%s: Children of the root: ", __func__); 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, "%s: Failed QueryTree request.\n", __func__); } 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, "%s: Going to configure splash window [0x%x].\n", __func__, * nxagentSplashWindow); * #endif * * XConfigureWindow(nxagentDisplay, nxagentSplashWindow, valuemask, &values); * * MAKE_SYNC_CONFIGURE_WINDOW; * } * } */ if (mask & CW_RootlessRestack) { if (!pWin -> prevSib) { #ifdef TEST fprintf(stderr, "%s: Raising window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin)); #endif XRaiseWindow(nxagentDisplay, nxagentWindow(pWin)); } else if (!pWin -> nextSib) { #ifdef TEST fprintf(stderr, "%sw: Lowering window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin)); #endif XLowerWindow(nxagentDisplay, nxagentWindow(pWin)); } else { XlibWindow windowList[2]; #ifdef TEST fprintf(stderr, "%s: Putting window [%p][0x%x] remote [0x%x] in the middle.\n", __func__, (void *) pWin, pWin->drawable.id, 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, "%s: window at [%p][0x%x] remote [0x%x] previous parent at [%p][0x%x] remote [0x%x].\n", __func__, (void*)pWin, pWin->drawable.id, nxagentWindow(pWin), (void*)pOldParent, pOldParent->drawable.id, 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, "%s: Changing attributes for window at [%p][0x%x] remote [0x%x] with mask [%lu].\n", __func__, (void*)pWin, pWin->drawable.id, nxagentWindow(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, "%s: WARNING! Window at [%p] got the " "hasTransparentChildren flag.\n", __func__, (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, "%s: The window at [%p] has the background at [%p] " "not synchronized.\n", __func__, (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, "%s: Changing backing store value to %d for window at %p.\n", __func__, 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, "%s: WARNING! Bad colormap [%lu] for window at [%p].\n", __func__, 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) { #ifdef DEBUG fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin)); #endif if (nxagentScreenTrap) { #ifdef DEBUG fprintf(stderr, "%s: doing nothing because of nxagentScreenTrap\n", __func__); #endif 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; #ifdef DEBUG fprintf(stderr, "%s: leaving...\n", __func__); #endif return True; } /* See nxagentRealizeWindow for a description */ Bool nxagentUnrealizeWindow(WindowPtr pWin) { #ifdef DEBUG fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin)); #endif 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) { #ifdef DEBUG fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin)); #endif 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) { #ifdef DEBUG fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin)); #endif 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, "%s: Saving the operation with window at [%p] not realized.\n", __func__, (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) { #ifdef DEBUG fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(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 -> 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) { #ifdef DEBUG fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin)); #endif 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) { #ifdef DEBUG fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin)); #endif /* * 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) { #ifdef DEBUG fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin)); #endif /* * The problem: we want to synthesize 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, "%s: Initializing expose queue.\n", __func__); #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, "%s: Added region to remoteRegion for window [%p][0x%x] remote [0x%x] to queue pos [%d].\n", __func__, (void *)pWin, pWin->drawable.id, nxagentWindow(pWin), nxagentExposeQueue.length); #endif } else { RegionUnion(nxagentExposeQueue.exposures[index].localRegion, nxagentExposeQueue.exposures[index].localRegion, &temp); #ifdef TEST fprintf(stderr, "%s: Added region to localRegion for window [%p][0x%x] remote [0x%x] to queue pos [%d].\n", __func__, (void *)pWin, pWin->drawable.id, nxagentWindow(pWin), nxagentExposeQueue.length); #endif } nxagentExposeSerial = (nxagentExposeSerial - 1) % EXPOSED_SIZE; nxagentExposeQueue.exposures[index].serial = nxagentExposeSerial; #ifdef TEST fprintf(stderr, "%s: Added region to queue with serial [%d].\n", __func__, 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, "%s: WARNING! Reached maximum size of collect exposures vector.\n", __func__); #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, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, 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, "%s: Bounding shape differs.\n", __func__); #endif if (wBoundingShape(pWin)) { #ifdef DEBUG fprintf(stderr, "%s: wBounding shape has [%d] rects.\n", __func__, 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, "%s: wBounding shape does not exist. Removing the shape.\n", __func__); #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, "%s: Clip shape differs.\n", __func__); #endif if (wClipShape(pWin)) { #ifdef DEBUG fprintf(stderr, "%s: wClip shape has [%d] rects.\n", __func__, 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, "%s: wClip shape does not exist. Removing the shape.\n", __func__); #endif RegionEmpty(nxagentWindowPriv(pWin)->clipShape); XShapeCombineMask(nxagentDisplay, nxagentWindow(pWin), ShapeClip, 0, 0, None, ShapeSet); } } } #endif /* SHAPE */ static int nxagentForceExposure(WindowPtr pWin, void * ptr) { #ifdef DEBUG fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin)); #endif 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, "%s: Showing the splash window.\n", __func__); #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, "%s: Mapping default window id [0x%x].\n", __func__, 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, "%s: Mapping icon window id [0x%x].\n", __func__, 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, "%s: Completed mapping of default windows.\n", __func__); #endif } Bool nxagentDisconnectAllWindows(void) { Bool succeeded = True; #if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_WINDOW_DEBUG) fprintf(stderr, "%s\n", __func__); #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, "%s: all windows disconnected\n", __func__); #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, "%s: window [%p] - disconnecting cursor [%p][0x%x]\n", __func__, (void *)pWin, (void *))pCursor, nxagentCursor(pCursor, pScreen)); #endif nxagentDisconnectCursor(pCursor, (XID)0, pBool); if (!*pBool) { #ifdef WARNING fprintf(stderr, "%s: WARNING failed disconnection of cursor at [%p]" " for window at [%p]: ignoring it.\n", __func__, (void*)pCursor, (void*)pWin); #endif *pBool = True; } } #ifdef NXAGENT_RECONNECT_CURSOR_DEBUG else if (pCursor) { fprintf(stderr, "%s: window [%p] - cursor [%p] already disconnected\n", __func__, (void *)pWin, (void *)pCursor); } #endif if ((nxagentRealWindowProp) && (!nxagentWindowTopLevel(pWin))) { Atom prop = MakeAtom("NX_REAL_WINDOW", strlen("NX_REAL_WINDOW"), True); if (DeleteProperty(pWin, prop) != Success) { fprintf(stderr, "%s: Deleting NX_REAL_WINDOW failed.\n", __func__); } #ifdef DEBUG else { fprintf(stderr, "%s: Deleting NX_REAL_WINDOW from Window ID [%x].\n", __func__, nxagentWindow(pWin)); } #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, "%s\n", __func__); #endif if (screenInfo.screens[0]->root -> backgroundState == BackgroundPixmap && screenInfo.screens[0]->root -> background.pixmap == NULL) { FatalError("%s: correct the FIXME\n", __func__); } 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, "%s: couldn't recreate windows\n", __func__); #endif return False; } #ifdef NXAGENT_RECONNECT_WINDOW_DEBUG XSync(nxagentDisplay, 0); fprintf(stderr, "%s: all windows recreated\n", __func__); #endif if (!nxagentLoopOverWindows(nxagentReconfigureWindow)) { #ifdef WARNING fprintf(stderr, "%s: couldn't reconfigure windows\n", __func__); #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, "%s: All windows reconfigured.\n", __func__); #endif if (!nxagentInitClipboard(screenInfo.screens[0]->root)) { #ifdef WARNING fprintf(stderr, "%s: WARNING! Couldn't initialize the clipboard.\n", __func__); #endif return False; } #ifdef NXAGENT_RECONNECT_WINDOW_DEBUG XSync(nxagentDisplay, 0); fprintf(stderr, "%s: Clipboard initialized.\n", __func__); #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, "%s Going to loop over the windows.\n", __func__); #endif if (!nxagentLoopOverWindows(nxagentReconfigureWindowCursor)) { #ifdef WARNING fprintf(stderr, "%s WARNING! Couldn't configure all windows' cursors.\n", __func__); #endif return False; } #ifdef NXAGENT_RECONNECT_WINDOW_DEBUG fprintf(stderr, "%s All cursors configured.\n", __func__); #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, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, 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, "%s: Going to create new remote window.\n", __func__); fprintf(stderr, "%s: Recreating %swindow at [%p][0x%x] current event mask [%X] mask & CWEventMask [%ld] " "event_mask [%lX]\n", __func__, nxagentWindowTopLevel(pWin) ? "toplevel " : "", (void*)pWin, pWin->drawable.id, 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 * app 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", nxagentWindow(pWin), pWin->drawable.id); } #ifdef DEBUG { char *winname = NULL; if (-1 != asprintf(&winname, "%s %s[0x%x]", nxagentWindowName, (pWin->drawable.id == pWin->drawable.pScreen->root->drawable.id) ? "Root" : "Private", pWin->drawable.id)) { Xutf8SetWMProperties(nxagentDisplay, nxagentWindow(pWin), winname, winname, NULL , 0 , NULL, NULL, NULL); SAFE_free(winname); } } #endif #ifdef TEST fprintf(stderr, "%s: Recreated new remote window with id [0x%x].\n", __func__, nxagentWindow(pWin)); #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, "%s: setting WMSizeHints on window %p [0x%x - 0x%x].\n", __func__, (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, "%s: Failed to get property WM_NORMAL_HINTS on window [%p]\n", __func__, (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, "%s: Updating NX_REAL_WINDOW failed.\n", __func__); } #ifdef DEBUG else { fprintf(stderr, "%s: Updated NX_REAL_WINDOW for Window ID [%x].\n", __func__, nxagentWindow(pWin)); } #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, "%s: [%p][0x%x] geometry [%d,%d,%d,%d] cursor [%p][0x%x]\n", __func__, (void *)pWin, nxagentWindow(pWin), pWin -> drawable.x, pWin -> drawable.y, pWin -> drawable.width, pWin -> drawable.height, (void *)pCursor, nxagentCursor(pCursor, pScreen)); #endif if (nxagentCursor(pCursor, pScreen) == None) { #ifdef NXAGENT_RECONNECT_WINDOW_DEBUG fprintf(stderr, "%s: reconnecting valid cursor [%p]\n", __func__, (void*)pCursor); #endif nxagentReconnectCursor(pCursor, 0, pBool); if (!*pBool) { #ifdef WARNING fprintf(stderr, "%s: WARNING " "failed reconnection of cursor at [%p] for window at [%p]: ignoring it.\n", __func__, (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, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, 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 static _X_UNUSED 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("%s: Failed to allocate a buffer of size [%d].\n", __func__, 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, "%s: Window [%p] geometry [%d,%d], has been realized " "but the data buffer still differs.\n", __func__, (void*) pWin, width, height); fprintf(stderr, "%s: bytes_per_line = [%d] byte pad [%d] format [%d].\n", __func__, image -> bytes_per_line, nxagentImagePad(width, height, 0, depth), image->format); fprintf(stderr, "%s: image is corrupted!!\n", __func__); #endif } else { #ifdef WARNING fprintf(stderr, "%s: Window [%p] has been realized " "now remote and framebuffer data are synchronized.\n", __func__ ,(void*) pWin); #endif } if (image) { XDestroyImage(image); } SAFE_free(data); } else { #ifdef WARNING fprintf(stderr, "%s: ignored window [%p] with geometry [%d,%d].\n", __func__, (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, "%s: Sending synch ConfigureWindow for " "index [%d] serial [%d].\n", __func__, 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) { #ifdef DEBUG fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x] with mask [%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin), valuemask); #endif unsigned int 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; #ifdef DEBUG fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin)); #endif 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; #ifdef DEBUG fprintf(stderr, "%s: Called with window [%p][0x%x] remote [0x%x].\n", __func__, (void *) pWin, pWin->drawable.id, nxagentWindow(pWin)); #endif 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, "%s: Emptying saved region for window at [%p].\n", __func__, (void*) pWin); #endif if (pBackingStore -> pBackingPixmap != NULL) { #ifdef TEST fprintf(stderr, "%s: Emptying corrupted region for drawable at [%p].\n", __func__, (void*) pBackingStore -> pBackingPixmap); #endif nxagentUnmarkCorruptedRegion((DrawablePtr) pBackingStore -> pBackingPixmap, NullRegion); } } } void nxagentEmptyAllBackingStoreRegions(void) { if (nxagentLoopOverWindows(nxagentEmptyBackingStoreRegion) == 0) { #ifdef WARNING fprintf(stderr, "%s: Failed to empty backing store saved regions.\n", __func__); #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("%s: Failed to allocate memory for nxagentBSPixmapList.\n", __func__); } nxagentBSPixmapList[i] -> storingPixmapId = id; nxagentBSPixmapList[i] -> pStoringPixmap = pPixmap; nxagentBSPixmapList[i] -> pSavedWindow = pWin; nxagentBSPixmapList[i] -> backingStoreX = bsx; nxagentBSPixmapList[i] -> backingStoreY = bsy; #ifdef TEST fprintf(stderr, "%s: Added Pixmap with id [%lu] to nxagentBSPixmapList.\n", __func__, 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, "%s: Updated existing item for id [%lu].\n", __func__, id); #endif return 1; } } #ifdef TEST fprintf(stderr, "%s: WARNING! List item full.\n", __func__); #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, "%s: Removed Pixmap with id [%lu] from list.\n", __func__, pixmapId); #endif return 1; } } #ifdef TEST fprintf(stderr, "%s: WARNING! Can't remove item [%lu]: item not found.\n", __func__, 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; }