[55401] | 1 | /* $Id: seamless-x11.h 99600 2023-05-04 10:29:18Z vboxsync $ */
|
---|
[6202] | 2 | /** @file
|
---|
[79482] | 3 | * Seamless mode - X11 guests.
|
---|
[6202] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2006-2023 Oracle and/or its affiliates.
|
---|
[6202] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[6202] | 26 | */
|
---|
| 27 |
|
---|
[76563] | 28 | #ifndef GA_INCLUDED_SRC_x11_VBoxClient_seamless_x11_h
|
---|
| 29 | #define GA_INCLUDED_SRC_x11_VBoxClient_seamless_x11_h
|
---|
[76535] | 30 | #ifndef RT_WITHOUT_PRAGMA_ONCE
|
---|
| 31 | # pragma once
|
---|
| 32 | #endif
|
---|
[6202] | 33 |
|
---|
[7449] | 34 | #include <VBox/log.h>
|
---|
[36685] | 35 | #include <iprt/avl.h>
|
---|
[79482] | 36 | #ifdef RT_NEED_NEW_AND_DELETE
|
---|
| 37 | # include <iprt/mem.h>
|
---|
| 38 | # include <new>
|
---|
| 39 | #endif
|
---|
[7449] | 40 |
|
---|
[6202] | 41 | #include <X11/Xlib.h>
|
---|
[11602] | 42 | #include <X11/Xutil.h>
|
---|
[6202] | 43 | #include <X11/extensions/shape.h>
|
---|
| 44 |
|
---|
[6290] | 45 | #define WM_TYPE_PROP "_NET_WM_WINDOW_TYPE"
|
---|
| 46 | #define WM_TYPE_DESKTOP_PROP "_NET_WM_WINDOW_TYPE_DESKTOP"
|
---|
[6202] | 47 |
|
---|
[21207] | 48 | /* This is defined wrong in my X11 header files! */
|
---|
| 49 | #define VBoxShapeNotify 64
|
---|
| 50 |
|
---|
[50337] | 51 | /**
|
---|
[52564] | 52 | * Callback which provides the interface for notifying the host of changes to
|
---|
| 53 | * the X11 window configuration, mainly split out from @a VBoxGuestSeamlessHost
|
---|
| 54 | * to simplify the unit test.
|
---|
[50337] | 55 | */
|
---|
[52564] | 56 | typedef void FNSENDREGIONUPDATE(RTRECT *pRects, size_t cRects);
|
---|
| 57 | typedef FNSENDREGIONUPDATE *PFNSENDREGIONUPDATE;
|
---|
[50337] | 58 |
|
---|
[6202] | 59 | /** Structure containing information about a guest window's position and visible area.
|
---|
| 60 | Used inside of VBoxGuestWindowList. */
|
---|
[85121] | 61 | struct VBoxGuestWinInfo
|
---|
| 62 | {
|
---|
[6202] | 63 | public:
|
---|
[36685] | 64 | /** Header structure for insertion into an AVL tree */
|
---|
| 65 | AVLU32NODECORE Core;
|
---|
[6290] | 66 | /** Is the window currently mapped? */
|
---|
[7106] | 67 | bool mhasShape;
|
---|
[6202] | 68 | /** Co-ordinates in the guest screen. */
|
---|
[6290] | 69 | int mX, mY;
|
---|
[6202] | 70 | /** Window dimensions. */
|
---|
[6290] | 71 | int mWidth, mHeight;
|
---|
[6202] | 72 | /** Number of rectangles used to represent the visible area. */
|
---|
| 73 | int mcRects;
|
---|
[36662] | 74 | /** Rectangles representing the visible area. These must be allocated
|
---|
| 75 | * by XMalloc and will be freed automatically if non-null when the class
|
---|
| 76 | * is destroyed. */
|
---|
| 77 | XRectangle *mpRects;
|
---|
[6202] | 78 | /** Constructor. */
|
---|
[85121] | 79 | VBoxGuestWinInfo(bool hasShape, int x, int y, int w, int h, int cRects, XRectangle *pRects)
|
---|
| 80 | : mhasShape(hasShape), mX(x), mY(y), mWidth(w), mHeight(h)
|
---|
| 81 | , mcRects(cRects), mpRects(pRects)
|
---|
| 82 | {}
|
---|
[36662] | 83 |
|
---|
| 84 | /** Destructor */
|
---|
| 85 | ~VBoxGuestWinInfo()
|
---|
[6202] | 86 | {
|
---|
[36662] | 87 | if (mpRects)
|
---|
| 88 | XFree(mpRects);
|
---|
[6202] | 89 | }
|
---|
[79482] | 90 | #ifdef RT_NEED_NEW_AND_DELETE
|
---|
| 91 | RTMEM_IMPLEMENT_NEW_AND_DELETE();
|
---|
| 92 | #endif
|
---|
[6202] | 93 |
|
---|
| 94 | private:
|
---|
| 95 | // We don't want a copy constructor or assignment operator
|
---|
[85121] | 96 | VBoxGuestWinInfo(const VBoxGuestWinInfo &);
|
---|
| 97 | VBoxGuestWinInfo &operator=(const VBoxGuestWinInfo &);
|
---|
[6202] | 98 | };
|
---|
| 99 |
|
---|
[36685] | 100 | /** Callback type used for "DoWithAll" calls */
|
---|
[85121] | 101 | typedef DECLCALLBACKTYPE(int, FNVBOXGUESTWINCALLBACK,(VBoxGuestWinInfo *, void *));
|
---|
[36685] | 102 | /** Pointer to VBOXGUESTWINCALLBACK */
|
---|
[85121] | 103 | typedef FNVBOXGUESTWINCALLBACK *PFNVBOXGUESTWINCALLBACK;
|
---|
[36685] | 104 |
|
---|
[85121] | 105 | static inline DECLCALLBACK(int) VBoxGuestWinCleanup(VBoxGuestWinInfo *pInfo, void *)
|
---|
[36685] | 106 | {
|
---|
| 107 | delete pInfo;
|
---|
| 108 | return VINF_SUCCESS;
|
---|
| 109 | }
|
---|
| 110 |
|
---|
[6202] | 111 | /**
|
---|
[36685] | 112 | * This class is just a wrapper around a map of structures containing
|
---|
| 113 | * information about the windows on the guest system. It has a function for
|
---|
| 114 | * adding a structure (see addWindow) and one for removing it by window
|
---|
| 115 | * handle (see removeWindow).
|
---|
[6202] | 116 | */
|
---|
| 117 | class VBoxGuestWindowList
|
---|
| 118 | {
|
---|
| 119 | private:
|
---|
| 120 | // We don't want a copy constructor or an assignment operator
|
---|
| 121 | VBoxGuestWindowList(const VBoxGuestWindowList&);
|
---|
| 122 | VBoxGuestWindowList& operator=(const VBoxGuestWindowList&);
|
---|
| 123 |
|
---|
| 124 | // Private class members
|
---|
[36685] | 125 | AVLU32TREE mWindows;
|
---|
[6202] | 126 |
|
---|
| 127 | public:
|
---|
| 128 | // Constructor
|
---|
[36685] | 129 | VBoxGuestWindowList(void) : mWindows(NULL) {}
|
---|
[6202] | 130 | // Destructor
|
---|
| 131 | ~VBoxGuestWindowList()
|
---|
| 132 | {
|
---|
[36685] | 133 | /** @todo having this inside the container class hard codes that the
|
---|
| 134 | * elements have to be allocated with the "new" operator, and
|
---|
| 135 | * I don't see a need to require this. */
|
---|
| 136 | doWithAll(VBoxGuestWinCleanup, NULL);
|
---|
[6202] | 137 | }
|
---|
| 138 |
|
---|
[79482] | 139 | #ifdef RT_NEED_NEW_AND_DELETE
|
---|
| 140 | RTMEM_IMPLEMENT_NEW_AND_DELETE();
|
---|
| 141 | #endif
|
---|
| 142 |
|
---|
[6202] | 143 | // Standard operations
|
---|
[36685] | 144 | VBoxGuestWinInfo *find(Window hWin)
|
---|
| 145 | {
|
---|
| 146 | return (VBoxGuestWinInfo *)RTAvlU32Get(&mWindows, hWin);
|
---|
| 147 | }
|
---|
[6202] | 148 |
|
---|
[85121] | 149 | void detachAll(PFNVBOXGUESTWINCALLBACK pfnCallback, void *pvParam)
|
---|
[36685] | 150 | {
|
---|
[85121] | 151 | RTAvlU32Destroy(&mWindows, (PAVLU32CALLBACK)pfnCallback, pvParam);
|
---|
[36685] | 152 | }
|
---|
| 153 |
|
---|
[85121] | 154 | int doWithAll(PFNVBOXGUESTWINCALLBACK pfnCallback, void *pvParam)
|
---|
[36685] | 155 | {
|
---|
[85121] | 156 | return RTAvlU32DoWithAll(&mWindows, 1, (PAVLU32CALLBACK)pfnCallback, pvParam);
|
---|
[36685] | 157 | }
|
---|
| 158 |
|
---|
| 159 | bool addWindow(Window hWin, bool isMapped, int x, int y, int w, int h, int cRects,
|
---|
[36662] | 160 | XRectangle *pRects)
|
---|
[6202] | 161 | {
|
---|
[57208] | 162 | LogRelFlowFunc(("hWin=%lu, isMapped=%RTbool, x=%d, y=%d, w=%d, h=%d, cRects=%d\n",
|
---|
| 163 | (unsigned long) hWin, isMapped, x, y, w, h, cRects));
|
---|
[85121] | 164 | VBoxGuestWinInfo *pInfo = new VBoxGuestWinInfo(isMapped, x, y, w, h, cRects, pRects);
|
---|
[36685] | 165 | pInfo->Core.Key = hWin;
|
---|
[81040] | 166 | LogRelFlowFuncLeave();
|
---|
[36685] | 167 | return RTAvlU32Insert(&mWindows, &pInfo->Core);
|
---|
[6202] | 168 | }
|
---|
| 169 |
|
---|
[36685] | 170 | VBoxGuestWinInfo *removeWindow(Window hWin)
|
---|
[6202] | 171 | {
|
---|
[81040] | 172 | LogRelFlowFuncEnter();
|
---|
[36685] | 173 | return (VBoxGuestWinInfo *)RTAvlU32Remove(&mWindows, hWin);
|
---|
[6202] | 174 | }
|
---|
| 175 | };
|
---|
| 176 |
|
---|
[99600] | 177 | class VBClX11SeamlessMonitor
|
---|
[6202] | 178 | {
|
---|
| 179 | private:
|
---|
| 180 | // We don't want a copy constructor or assignment operator
|
---|
[99600] | 181 | VBClX11SeamlessMonitor(const VBClX11SeamlessMonitor&);
|
---|
| 182 | VBClX11SeamlessMonitor& operator=(const VBClX11SeamlessMonitor&);
|
---|
[6202] | 183 |
|
---|
| 184 | // Private member variables
|
---|
[52564] | 185 | /** Pointer to the host callback. */
|
---|
| 186 | PFNSENDREGIONUPDATE mHostCallback;
|
---|
[6202] | 187 | /** Our connection to the X11 display we are running on. */
|
---|
[36662] | 188 | Display *mDisplay;
|
---|
[6202] | 189 | /** Class to keep track of visible guest windows. */
|
---|
| 190 | VBoxGuestWindowList mGuestWindows;
|
---|
[36806] | 191 | /** The current set of seamless rectangles. */
|
---|
| 192 | RTRECT *mpRects;
|
---|
| 193 | /** The current number of seamless rectangles. */
|
---|
[6202] | 194 | int mcRects;
|
---|
[6290] | 195 | /** Do we support the X shaped window extension? */
|
---|
| 196 | bool mSupportsShape;
|
---|
[33540] | 197 | /** Is seamless mode currently enabled? */
|
---|
[6290] | 198 | bool mEnabled;
|
---|
[21441] | 199 | /** Have there been changes since the last time we sent a notification? */
|
---|
| 200 | bool mChanged;
|
---|
[6202] | 201 |
|
---|
| 202 | // Private methods
|
---|
| 203 |
|
---|
| 204 | // Methods to manage guest window information
|
---|
| 205 | /**
|
---|
| 206 | * Store information about a desktop window and register for structure events on it.
|
---|
| 207 | * If it is mapped, go through the list of it's children and add information about
|
---|
| 208 | * mapped children to the tree of visible windows, making sure that those windows are
|
---|
| 209 | * not already in our list of desktop windows.
|
---|
| 210 | *
|
---|
| 211 | * @param hWin the window concerned - should be a "desktop" window
|
---|
| 212 | */
|
---|
[6290] | 213 | void monitorClientList(void);
|
---|
| 214 | void unmonitorClientList(void);
|
---|
[6202] | 215 | void rebuildWindowTree(void);
|
---|
[7048] | 216 | void addClients(const Window hRoot);
|
---|
| 217 | bool isVirtualRoot(Window hWin);
|
---|
[6290] | 218 | void addClientWindow(Window hWin);
|
---|
[6202] | 219 | void freeWindowTree(void);
|
---|
| 220 | void updateHostSeamlessInfo(void);
|
---|
[36806] | 221 | int updateRects(void);
|
---|
[6202] | 222 |
|
---|
| 223 | public:
|
---|
| 224 | /**
|
---|
| 225 | * Initialise the guest and ensure that it is capable of handling seamless mode
|
---|
[65122] | 226 | * @param pHostCallback Host interface callback to notify of window configuration
|
---|
| 227 | * changes.
|
---|
[6202] | 228 | *
|
---|
| 229 | * @returns iprt status code
|
---|
| 230 | */
|
---|
[52564] | 231 | int init(PFNSENDREGIONUPDATE pHostCallback);
|
---|
[6202] | 232 |
|
---|
| 233 | /**
|
---|
| 234 | * Shutdown seamless event monitoring.
|
---|
| 235 | */
|
---|
[86394] | 236 | void uninit(void);
|
---|
[6202] | 237 |
|
---|
| 238 | /**
|
---|
| 239 | * Initialise seamless event reporting in the guest.
|
---|
| 240 | *
|
---|
| 241 | * @returns IPRT status code
|
---|
| 242 | */
|
---|
| 243 | int start(void);
|
---|
| 244 | /** Stop reporting seamless events. */
|
---|
| 245 | void stop(void);
|
---|
| 246 | /** Get the current list of visible rectangles. */
|
---|
[36806] | 247 | RTRECT *getRects(void);
|
---|
| 248 | /** Get the number of visible rectangles in the current list */
|
---|
| 249 | size_t getRectCount(void);
|
---|
[6202] | 250 |
|
---|
[6290] | 251 | /** Process next event in the guest event queue - called by the event thread. */
|
---|
[50346] | 252 | void nextConfigurationEvent(void);
|
---|
[6290] | 253 | /** Wake up the event thread if it is waiting for an event so that it can exit. */
|
---|
[50346] | 254 | bool interruptEventWait(void);
|
---|
[6202] | 255 |
|
---|
[21207] | 256 | /* Methods to handle X11 events. These are public so that the unit test
|
---|
| 257 | * can call them. */
|
---|
[21216] | 258 | void doConfigureEvent(Window hWin);
|
---|
| 259 | void doShapeEvent(Window hWin);
|
---|
[21207] | 260 |
|
---|
[99600] | 261 | VBClX11SeamlessMonitor(void)
|
---|
[52564] | 262 | : mHostCallback(NULL), mDisplay(NULL), mpRects(NULL), mcRects(0),
|
---|
[36806] | 263 | mSupportsShape(false), mEnabled(false), mChanged(false) {}
|
---|
[6202] | 264 |
|
---|
[99600] | 265 | ~VBClX11SeamlessMonitor()
|
---|
[6893] | 266 | {
|
---|
[37025] | 267 | uninit();
|
---|
[6893] | 268 | }
|
---|
[79482] | 269 |
|
---|
| 270 | #ifdef RT_NEED_NEW_AND_DELETE
|
---|
| 271 | RTMEM_IMPLEMENT_NEW_AND_DELETE();
|
---|
| 272 | #endif
|
---|
[6202] | 273 | };
|
---|
| 274 |
|
---|
[76563] | 275 | #endif /* !GA_INCLUDED_SRC_x11_VBoxClient_seamless_x11_h */
|
---|