VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/VBoxClient/seamless-x11.cpp@ 109193

Last change on this file since 109193 was 108666, checked in by vboxsync, 8 weeks ago

Additions/x11/VBoxClient/seamless-x11.cpp: clang build fixes, bugref:10391

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 24.2 KB
Line 
1/* $Id: seamless-x11.cpp 108666 2025-03-20 17:16:26Z vboxsync $ */
2/** @file
3 * X11 Seamless mode.
4 */
5
6/*
7 * Copyright (C) 2008-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.215389.xyz.
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
26 */
27
28
29/*********************************************************************************************************************************
30* Header files *
31*********************************************************************************************************************************/
32#include <iprt/errcore.h>
33#include <iprt/assert.h>
34#include <iprt/vector.h>
35#include <iprt/thread.h>
36#include <VBox/log.h>
37
38#include "seamless.h"
39#include "seamless-x11.h"
40#include "VBoxClient.h"
41
42#include <X11/Xatom.h>
43#include <X11/Xmu/WinUtil.h>
44
45#include <limits.h>
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51#ifdef TESTCASE
52# undef DefaultRootWindow
53# define DefaultRootWindow XDefaultRootWindow
54#endif
55
56
57/*********************************************************************************************************************************
58* Internal Functions *
59*********************************************************************************************************************************/
60
61static unsigned char *XXGetProperty(Display *aDpy, Window aWnd, Atom aPropType,
62 const char *aPropName, unsigned long *nItems)
63{
64 LogRelFlowFuncEnter();
65 Atom propNameAtom = XInternAtom (aDpy, aPropName,
66 True /* only_if_exists */);
67 if (propNameAtom == None)
68 {
69 return NULL;
70 }
71
72 Atom actTypeAtom = None;
73 int actFmt = 0;
74 unsigned long nBytesAfter = 0;
75 unsigned char *propVal = 0;
76 int rc = XGetWindowProperty (aDpy, aWnd, propNameAtom,
77 0, LONG_MAX, False /* delete */,
78 aPropType, &actTypeAtom, &actFmt,
79 nItems, &nBytesAfter, &propVal);
80 if (rc != Success)
81 return NULL;
82
83 LogRelFlowFuncLeave();
84 return propVal;
85}
86
87int VBClX11SeamlessMonitor::init(PFNSENDREGIONUPDATE pHostCallback)
88{
89 int rc = VINF_SUCCESS;
90
91 LogRelFlowFuncEnter();
92 if (mHostCallback != NULL) /* Assertion */
93 {
94 VBClLogError("Attempting to initialise seamless guest object twice!\n");
95 return VERR_INTERNAL_ERROR;
96 }
97 if (!(mDisplay = XOpenDisplay(NULL)))
98 {
99 VBClLogError("Seamless guest object failed to acquire a connection to the display\n");
100 return VERR_ACCESS_DENIED;
101 }
102 mHostCallback = pHostCallback;
103 mEnabled = false;
104 unmonitorClientList();
105 LogRelFlowFuncLeaveRC(rc);
106 return rc;
107}
108
109/**
110 * Shutdown seamless event monitoring.
111 */
112void VBClX11SeamlessMonitor::uninit(void)
113{
114 if (mHostCallback)
115 stop();
116 mHostCallback = NULL;
117
118 /* Before closing a Display, make sure X11 is still running. The indicator
119 * that is when XOpenDisplay() returns non NULL. If it is not a
120 * case, XCloseDisplay() will hang on internal X11 mutex forever. */
121 Display *pDisplay = XOpenDisplay(NULL);
122 if (pDisplay)
123 {
124 XCloseDisplay(pDisplay);
125 if (mDisplay)
126 {
127 XCloseDisplay(mDisplay);
128 mDisplay = NULL;
129 }
130 }
131
132 if (mpRects)
133 {
134 RTMemFree(mpRects);
135 mpRects = NULL;
136 }
137}
138
139/**
140 * Read information about currently visible windows in the guest and subscribe to X11
141 * events about changes to this information.
142 *
143 * @note This class does not contain its own event thread, so an external thread must
144 * call nextConfigurationEvent() for as long as events are wished.
145 * @todo This function should switch the guest to fullscreen mode.
146 */
147int VBClX11SeamlessMonitor::start(void)
148{
149 int rc = VINF_SUCCESS;
150 /** Dummy values for XShapeQueryExtension */
151 int error, event;
152
153 LogRelFlowFuncEnter();
154 if (mEnabled)
155 return VINF_SUCCESS;
156 mSupportsShape = XShapeQueryExtension(mDisplay, &event, &error);
157 mEnabled = true;
158 monitorClientList();
159 rebuildWindowTree();
160 LogRelFlowFuncLeaveRC(rc);
161 return rc;
162}
163
164/** Stop reporting seamless events to the host. Free information about guest windows
165 and stop requesting updates. */
166void VBClX11SeamlessMonitor::stop(void)
167{
168 LogRelFlowFuncEnter();
169 if (!mEnabled)
170 return;
171 mEnabled = false;
172 unmonitorClientList();
173 freeWindowTree();
174 LogRelFlowFuncLeave();
175}
176
177void VBClX11SeamlessMonitor::monitorClientList(void)
178{
179 LogRelFlowFuncEnter();
180 XSelectInput(mDisplay, DefaultRootWindow(mDisplay), PropertyChangeMask | SubstructureNotifyMask);
181}
182
183void VBClX11SeamlessMonitor::unmonitorClientList(void)
184{
185 LogRelFlowFuncEnter();
186 XSelectInput(mDisplay, DefaultRootWindow(mDisplay), PropertyChangeMask);
187}
188
189/**
190 * Recreate the table of toplevel windows of clients on the default root window of the
191 * X server.
192 */
193void VBClX11SeamlessMonitor::rebuildWindowTree(void)
194{
195 LogRelFlowFuncEnter();
196 freeWindowTree();
197 addClients(DefaultRootWindow(mDisplay));
198 mChanged = true;
199}
200
201
202/**
203 * Look at the list of children of a virtual root window and add them to the list of clients
204 * if they belong to a client which is not a virtual root.
205 *
206 * @param hRoot the virtual root window to be examined
207 */
208void VBClX11SeamlessMonitor::addClients(const Window hRoot)
209{
210 /** Unused out parameters of XQueryTree */
211 Window hRealRoot, hParent;
212 /** The list of children of the root supplied, raw pointer */
213 Window *phChildrenRaw = NULL;
214 /** The list of children of the root supplied, auto-pointer */
215 Window *phChildren;
216 /** The number of children of the root supplied */
217 unsigned cChildren;
218
219 LogRelFlowFuncEnter();
220 if (!XQueryTree(mDisplay, hRoot, &hRealRoot, &hParent, &phChildrenRaw, &cChildren))
221 return;
222 phChildren = phChildrenRaw;
223 for (unsigned i = 0; i < cChildren; ++i)
224 addClientWindow(phChildren[i]);
225 XFree(phChildrenRaw);
226 LogRelFlowFuncLeave();
227}
228
229
230void VBClX11SeamlessMonitor::addClientWindow(const Window hWin)
231{
232 LogRelFlowFuncEnter();
233 XWindowAttributes winAttrib;
234 bool fAddWin = true;
235 Window hClient = XmuClientWindow(mDisplay, hWin);
236
237 if (isVirtualRoot(hClient))
238 fAddWin = false;
239 if (fAddWin && !XGetWindowAttributes(mDisplay, hWin, &winAttrib))
240 {
241 VBClLogError("Failed to get the window attributes for window %d\n", hWin);
242 fAddWin = false;
243 }
244 if (fAddWin && (winAttrib.map_state == IsUnmapped))
245 fAddWin = false;
246 XSizeHints dummyHints;
247 long dummyLong;
248 /* Apparently (?) some old kwin versions had unwanted client windows
249 * without normal hints. */
250 if (fAddWin && (!XGetWMNormalHints(mDisplay, hClient, &dummyHints,
251 &dummyLong)))
252 {
253 LogRelFlowFunc(("window %lu, client window %lu has no size hints\n", hWin, hClient));
254 fAddWin = false;
255 }
256 if (fAddWin)
257 {
258 XRectangle *pRects = NULL;
259 int cRects = 0, iOrdering;
260 bool hasShape = false;
261
262 LogRelFlowFunc(("adding window %lu, client window %lu\n", hWin,
263 hClient));
264 if (mSupportsShape)
265 {
266 XShapeSelectInput(mDisplay, hWin, ShapeNotifyMask);
267 pRects = XShapeGetRectangles(mDisplay, hWin, ShapeBounding, &cRects, &iOrdering);
268 if (!pRects)
269 cRects = 0;
270 else
271 {
272 if ( (cRects > 1)
273 || (pRects[0].x != 0)
274 || (pRects[0].y != 0)
275 || (pRects[0].width != winAttrib.width)
276 || (pRects[0].height != winAttrib.height)
277 )
278 hasShape = true;
279 }
280 }
281 mGuestWindows.addWindow(hWin, hasShape, winAttrib.x, winAttrib.y,
282 winAttrib.width, winAttrib.height, cRects,
283 pRects);
284 }
285 LogRelFlowFuncLeave();
286}
287
288
289/**
290 * Checks whether a window is a virtual root.
291 * @returns true if it is, false otherwise
292 * @param hWin the window to be examined
293 */
294bool VBClX11SeamlessMonitor::isVirtualRoot(Window hWin)
295{
296 unsigned char *windowTypeRaw = NULL;
297 Atom *windowType;
298 unsigned long ulCount;
299 bool rc = false;
300
301 LogRelFlowFuncEnter();
302 windowTypeRaw = XXGetProperty(mDisplay, hWin, XA_ATOM, WM_TYPE_PROP, &ulCount);
303 if (windowTypeRaw != NULL)
304 {
305 windowType = (Atom *)(windowTypeRaw);
306 if ( (ulCount != 0)
307 && (*windowType == XInternAtom(mDisplay, WM_TYPE_DESKTOP_PROP, True)))
308 rc = true;
309 }
310 if (windowTypeRaw)
311 XFree(windowTypeRaw);
312 LogRelFlowFunc(("returning %RTbool\n", rc));
313 return rc;
314}
315
316DECLCALLBACK(int) VBoxGuestWinFree(VBoxGuestWinInfo *pInfo, void *pvParam)
317{
318 Display *pDisplay = (Display *)pvParam;
319
320 XShapeSelectInput(pDisplay, pInfo->Core.Key, 0);
321 delete pInfo;
322 return VINF_SUCCESS;
323}
324
325/**
326 * Free all information in the tree of visible windows
327 */
328void VBClX11SeamlessMonitor::freeWindowTree(void)
329{
330 /* We use post-increment in the operation to prevent the iterator from being invalidated. */
331 LogRelFlowFuncEnter();
332 mGuestWindows.detachAll(VBoxGuestWinFree, mDisplay);
333 LogRelFlowFuncLeave();
334}
335
336
337/**
338 * Waits for a position or shape-related event from guest windows
339 *
340 * @note Called from the guest event thread.
341 */
342void VBClX11SeamlessMonitor::nextConfigurationEvent(void)
343{
344 XEvent event;
345
346 LogRelFlowFuncEnter();
347 /* Start by sending information about the current window setup to the host. We do this
348 here because we want to send all such information from a single thread. */
349 if (mChanged && mEnabled)
350 {
351 updateRects();
352 mHostCallback(mpRects, mcRects);
353 }
354 mChanged = false;
355
356 if (XPending(mDisplay) > 0)
357 {
358 /* We execute this even when seamless is disabled, as it also waits for
359 * enable and disable notification. */
360 XNextEvent(mDisplay, &event);
361 } else
362 {
363 /* This function is called in a loop by upper layer. In order to
364 * prevent CPU spinning, sleep a bit before returning. */
365 RTThreadSleep(300 /* ms */);
366 return;
367 }
368
369 if (!mEnabled)
370 return;
371 switch (event.type)
372 {
373 case ConfigureNotify:
374 {
375 XConfigureEvent *pConf = &event.xconfigure;
376 LogRelFlowFunc(("configure event, window=%lu, x=%i, y=%i, w=%i, h=%i, send_event=%RTbool\n",
377 (unsigned long) pConf->window, (int) pConf->x,
378 (int) pConf->y, (int) pConf->width,
379 (int) pConf->height, pConf->send_event));
380 }
381 doConfigureEvent(event.xconfigure.window);
382 break;
383 case MapNotify:
384 LogRelFlowFunc(("map event, window=%lu, send_event=%RTbool\n",
385 (unsigned long) event.xmap.window,
386 event.xmap.send_event));
387 rebuildWindowTree();
388 break;
389 case PropertyNotify:
390 if ( event.xproperty.atom != XInternAtom(mDisplay, "_NET_CLIENT_LIST", True /* only_if_exists */)
391 || event.xproperty.window != DefaultRootWindow(mDisplay))
392 break;
393 LogRelFlowFunc(("_NET_CLIENT_LIST property event on root window\n"));
394 rebuildWindowTree();
395 break;
396 case VBoxShapeNotify: /* This is defined wrong in my X11 header files! */
397 LogRelFlowFunc(("shape event, window=%lu, send_event=%RTbool\n",
398 (unsigned long) event.xany.window,
399 event.xany.send_event));
400 /* the window member in xany is in the same place as in the shape event */
401 doShapeEvent(event.xany.window);
402 break;
403 case UnmapNotify:
404 LogRelFlowFunc(("unmap event, window=%lu, send_event=%RTbool\n",
405 (unsigned long) event.xunmap.window,
406 event.xunmap.send_event));
407 rebuildWindowTree();
408 break;
409 default:
410 break;
411 }
412 LogRelFlowFunc(("processed event\n"));
413}
414
415/**
416 * Handle a configuration event in the seamless event thread by setting the new position.
417 *
418 * @param hWin the window to be examined
419 */
420void VBClX11SeamlessMonitor::doConfigureEvent(Window hWin)
421{
422 VBoxGuestWinInfo *pInfo = mGuestWindows.find(hWin);
423 if (pInfo)
424 {
425 XWindowAttributes winAttrib;
426
427 if (!XGetWindowAttributes(mDisplay, hWin, &winAttrib))
428 return;
429 pInfo->mX = winAttrib.x;
430 pInfo->mY = winAttrib.y;
431 pInfo->mWidth = winAttrib.width;
432 pInfo->mHeight = winAttrib.height;
433 mChanged = true;
434 }
435}
436
437/**
438 * Handle a window shape change event in the seamless event thread.
439 *
440 * @param hWin the window to be examined
441 */
442void VBClX11SeamlessMonitor::doShapeEvent(Window hWin)
443{
444 LogRelFlowFuncEnter();
445 VBoxGuestWinInfo *pInfo = mGuestWindows.find(hWin);
446 if (pInfo)
447 {
448 XRectangle *pRects;
449 int cRects = 0, iOrdering;
450
451 pRects = XShapeGetRectangles(mDisplay, hWin, ShapeBounding, &cRects,
452 &iOrdering);
453 if (!pRects)
454 cRects = 0;
455 pInfo->mhasShape = true;
456 if (pInfo->mpRects)
457 XFree(pInfo->mpRects);
458 pInfo->mcRects = cRects;
459 pInfo->mpRects = pRects;
460 mChanged = true;
461 }
462 LogRelFlowFuncLeave();
463}
464
465/**
466 * Gets the list of visible rectangles
467 */
468RTRECT *VBClX11SeamlessMonitor::getRects(void)
469{
470 return mpRects;
471}
472
473/**
474 * Gets the number of rectangles in the visible rectangle list
475 */
476size_t VBClX11SeamlessMonitor::getRectCount(void)
477{
478 return mcRects;
479}
480
481#if RT_CLANG_PREREQ(3, 4) /* Most of the defined functions are not used. */
482# pragma clang diagnostic push
483# pragma clang diagnostic ignored "-Wunused-function"
484#endif
485RTVEC_DECL(RectList, RTRECT)
486#if RT_CLANG_PREREQ(3, 4)
487# pragma clang diagnostic pop
488#endif
489
490static DECLCALLBACK(int) getRectsCallback(VBoxGuestWinInfo *pInfo, struct RectList *pRects)
491{
492 if (pInfo->mhasShape)
493 {
494 for (int i = 0; i < pInfo->mcRects; ++i)
495 {
496 RTRECT *pRect;
497
498 pRect = RectListPushBack(pRects);
499 if (!pRect)
500 return VERR_NO_MEMORY;
501 pRect->xLeft = pInfo->mX
502 + pInfo->mpRects[i].x;
503 pRect->yBottom = pInfo->mY
504 + pInfo->mpRects[i].y
505 + pInfo->mpRects[i].height;
506 pRect->xRight = pInfo->mX
507 + pInfo->mpRects[i].x
508 + pInfo->mpRects[i].width;
509 pRect->yTop = pInfo->mY
510 + pInfo->mpRects[i].y;
511 }
512 }
513 else
514 {
515 RTRECT *pRect;
516
517 pRect = RectListPushBack(pRects);
518 if (!pRect)
519 return VERR_NO_MEMORY;
520 pRect->xLeft = pInfo->mX;
521 pRect->yBottom = pInfo->mY
522 + pInfo->mHeight;
523 pRect->xRight = pInfo->mX
524 + pInfo->mWidth;
525 pRect->yTop = pInfo->mY;
526 }
527 return VINF_SUCCESS;
528}
529
530/**
531 * Updates the list of seamless rectangles
532 */
533int VBClX11SeamlessMonitor::updateRects(void)
534{
535 LogRelFlowFuncEnter();
536 struct RectList rects = RTVEC_INITIALIZER;
537
538 if (mcRects != 0)
539 {
540 int rc = RectListReserve(&rects, mcRects * 2);
541 if (RT_FAILURE(rc))
542 return rc;
543 }
544 mGuestWindows.doWithAll((PFNVBOXGUESTWINCALLBACK)getRectsCallback, &rects);
545 if (mpRects)
546 RTMemFree(mpRects);
547 mcRects = RectListSize(&rects);
548 mpRects = RectListDetach(&rects);
549 LogRelFlowFuncLeave();
550 return VINF_SUCCESS;
551}
552
553/**
554 * Send a client event to wake up the X11 seamless event loop prior to stopping it.
555 *
556 * @note This function should only be called from the host event thread.
557 */
558bool VBClX11SeamlessMonitor::interruptEventWait(void)
559{
560 LogRelFlowFuncEnter();
561
562 Display *pDisplay = XOpenDisplay(NULL);
563 if (pDisplay == NULL)
564 {
565 VBClLogError("Failed to open X11 display\n");
566 return false;
567 }
568
569 /* Message contents set to zero. */
570 XClientMessageEvent clientMessage =
571 {
572 /* .type = */ ClientMessage,
573 /* .serial = */ 0,
574 /* .send_event = */ 0,
575 /* .display = */ 0,
576 /* .window = */ 0,
577 /* .message_type = */ XInternAtom(pDisplay, "VBOX_CLIENT_SEAMLESS_HEARTBEAT", false),
578 /* .format = */ 8,
579 /* .data ... */
580 };
581
582 bool rc = false;
583 if (XSendEvent(pDisplay, DefaultRootWindow(mDisplay), false,
584 PropertyChangeMask, (XEvent *)&clientMessage))
585 rc = true;
586
587 XCloseDisplay(pDisplay);
588 LogRelFlowFunc(("returning %RTbool\n", rc));
589 return rc;
590}
591
592
593/*********************************************************************************************************************************
594 * VBClX11SeamlessSvc implementation *
595 ********************************************************************************************************************************/
596
597VBClX11SeamlessSvc::VBClX11SeamlessSvc(void)
598{
599 mX11MonitorThread = NIL_RTTHREAD;
600 mX11MonitorThreadStopping = false;
601
602 mMode = VMMDev_Seamless_Disabled;
603 mfPaused = true;
604}
605
606VBClX11SeamlessSvc::~VBClX11SeamlessSvc()
607{
608 /* Stopping will be done via main.cpp. */
609}
610
611/** @copydoc VBCLSERVICE::pfnInit */
612int VBClX11SeamlessSvc::init(void)
613{
614 int rc;
615 const char *pcszStage;
616
617 do
618 {
619 pcszStage = "Connecting to the X server";
620 rc = mX11Monitor.init(VBClSeamlessSendRegionUpdate);
621 if (RT_FAILURE(rc))
622 break;
623 pcszStage = "Setting guest IRQ filter mask";
624 rc = VbglR3CtlFilterMask(VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST, 0);
625 if (RT_FAILURE(rc))
626 break;
627 pcszStage = "Reporting support for seamless capability";
628 rc = VbglR3SeamlessSetCap(true);
629 if (RT_FAILURE(rc))
630 break;
631 rc = startX11MonitorThread();
632 if (RT_FAILURE(rc))
633 break;
634
635 } while(0);
636
637 if (RT_FAILURE(rc))
638 VBClLogError("Failed to start in stage '%s' -- error %Rrc\n", pcszStage, rc);
639
640 return rc;
641}
642
643/** @copydoc VBCLSERVICE::pfnWorker */
644int VBClX11SeamlessSvc::worker(bool volatile *pfShutdown)
645{
646 int rc = VINF_SUCCESS;
647
648 /* Let the main thread know that it can continue spawning services. */
649 RTThreadUserSignal(RTThreadSelf());
650
651 /* This will only exit if something goes wrong. */
652 for (;;)
653 {
654 if (ASMAtomicReadBool(pfShutdown))
655 break;
656
657 rc = nextStateChangeEvent();
658
659 if (rc == VERR_TRY_AGAIN)
660 rc = VINF_SUCCESS;
661
662 if (RT_FAILURE(rc))
663 break;
664
665 if (ASMAtomicReadBool(pfShutdown))
666 break;
667
668 /* If we are not stopping, sleep for a bit to avoid using up too
669 much CPU while retrying. */
670 RTThreadYield();
671 }
672
673 return rc;
674}
675
676/** @copydoc VBCLSERVICE::pfnStop */
677void VBClX11SeamlessSvc::stop(void)
678{
679 VbglR3SeamlessSetCap(false);
680 VbglR3CtlFilterMask(0, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
681 stopX11MonitorThread();
682}
683
684/** @copydoc VBCLSERVICE::pfnTerm */
685int VBClX11SeamlessSvc::term(void)
686{
687 mX11Monitor.uninit();
688 return VINF_SUCCESS;
689}
690
691/**
692 * Waits for a seamless state change events from the host and dispatch it.
693 *
694 * @returns VBox return code, or
695 * VERR_TRY_AGAIN if no new status is available and we have to try it again
696 * at some later point in time.
697 */
698int VBClX11SeamlessSvc::nextStateChangeEvent(void)
699{
700 VMMDevSeamlessMode newMode = VMMDev_Seamless_Disabled;
701
702 int rc = VbglR3SeamlessWaitEvent(&newMode);
703 if (RT_SUCCESS(rc))
704 {
705 mMode = newMode;
706 switch (newMode)
707 {
708 case VMMDev_Seamless_Visible_Region:
709 /* A simplified seamless mode, obtained by making the host VM window
710 * borderless and making the guest desktop transparent. */
711 VBClLogVerbose(2, "\"Visible region\" mode requested\n");
712 break;
713 case VMMDev_Seamless_Disabled:
714 VBClLogVerbose(2, "\"Disabled\" mode requested\n");
715 break;
716 case VMMDev_Seamless_Host_Window:
717 /* One host window represents one guest window. Not yet implemented. */
718 VBClLogVerbose(2, "Unsupported \"host window\" mode requested\n");
719 return VERR_NOT_SUPPORTED;
720 default:
721 VBClLogError("Unsupported mode %d requested\n", newMode);
722 return VERR_NOT_SUPPORTED;
723 }
724 }
725 if ( RT_SUCCESS(rc)
726 || rc == VERR_TRY_AGAIN)
727 {
728 if (mMode == VMMDev_Seamless_Visible_Region)
729 mfPaused = false;
730 else
731 mfPaused = true;
732 mX11Monitor.interruptEventWait();
733 }
734 else
735 VBClLogError("VbglR3SeamlessWaitEvent returned %Rrc\n", rc);
736
737 return rc;
738}
739
740/**
741 * The actual X11 window configuration change monitor thread function.
742 */
743DECLCALLBACK(int) VBClX11SeamlessSvc::x11MonitorThread(RTTHREAD hThreadSelf, void *pvUser)
744{
745 RT_NOREF(hThreadSelf);
746
747 VBClX11SeamlessSvc *pThis = (VBClX11SeamlessSvc *)pvUser;
748 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
749
750 int rc = VINF_SUCCESS;
751
752 RTThreadUserSignal(hThreadSelf);
753
754 VBClLogVerbose(2, "X11 monitor thread started\n");
755
756 while (!pThis->mX11MonitorThreadStopping)
757 {
758 if (!pThis->mfPaused)
759 {
760 rc = pThis->mX11Monitor.start();
761 if (RT_FAILURE(rc))
762 VBClLogFatalError("Failed to change the X11 seamless service state, mfPaused=%RTbool, rc=%Rrc\n",
763 pThis->mfPaused, rc);
764 }
765
766 pThis->mX11Monitor.nextConfigurationEvent();
767
768 if ( pThis->mfPaused
769 || pThis->mX11MonitorThreadStopping)
770 {
771 pThis->mX11Monitor.stop();
772 }
773 }
774
775 VBClLogVerbose(2, "X11 monitor thread ended\n");
776
777 return rc;
778}
779
780/**
781 * Start the X11 window configuration change monitor thread.
782 */
783int VBClX11SeamlessSvc::startX11MonitorThread(void)
784{
785 mX11MonitorThreadStopping = false;
786
787 if (isX11MonitorThreadRunning())
788 return VINF_SUCCESS;
789
790 int rc = RTThreadCreate(&mX11MonitorThread, x11MonitorThread, this, 0,
791 RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
792 "seamless x11");
793 if (RT_SUCCESS(rc))
794 rc = RTThreadUserWait(mX11MonitorThread, RT_MS_30SEC);
795
796 if (RT_FAILURE(rc))
797 VBClLogError("Failed to start X11 monitor thread, rc=%Rrc\n", rc);
798
799 return rc;
800}
801
802/**
803 * Stops the monitor thread.
804 */
805int VBClX11SeamlessSvc::stopX11MonitorThread(void)
806{
807 if (!isX11MonitorThreadRunning())
808 return VINF_SUCCESS;
809
810 mX11MonitorThreadStopping = true;
811 if (!mX11Monitor.interruptEventWait())
812 {
813 VBClLogError("Unable to notify X11 monitor thread\n");
814 return VERR_INVALID_STATE;
815 }
816
817 int rcThread;
818 int rc = RTThreadWait(mX11MonitorThread, RT_MS_30SEC, &rcThread);
819 if (RT_SUCCESS(rc))
820 rc = rcThread;
821
822 if (RT_SUCCESS(rc))
823 {
824 mX11MonitorThread = NIL_RTTHREAD;
825 }
826 else
827 VBClLogError("Waiting for X11 monitor thread to stop failed, rc=%Rrc\n", rc);
828
829 return rc;
830}
831
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette