VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.cpp@ 103551

Last change on this file since 103551 was 103551, checked in by vboxsync, 7 months ago

FE/Qt: Moving UIType from UICommon to UIDefs for reuse purposes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.7 KB
RevLine 
[57480]1/* $Id: UIDesktopWidgetWatchdog.cpp 103551 2024-02-23 16:09:47Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIDesktopWidgetWatchdog class implementation.
4 */
5
6/*
[98103]7 * Copyright (C) 2015-2023 Oracle and/or its affiliates.
[57480]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
[57480]26 */
27
28/* Qt includes: */
[76606]29#include <QApplication>
[94013]30#include <QWidget>
[76606]31#include <QScreen>
32#ifdef VBOX_WS_WIN
33# include <QLibrary>
34#endif
[100064]35#ifdef VBOX_WS_NIX
[76606]36# include <QTimer>
37#endif
[97754]38#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
39# include <QDesktopWidget>
40#endif /* Qt < 5.10 */
[57480]41
42/* GUI includes: */
[76606]43#include "UIDesktopWidgetWatchdog.h"
[103538]44#include "UILoggingDefs.h"
[91114]45#ifdef VBOX_WS_MAC
46# include "VBoxUtils-darwin.h"
47#endif
[91109]48#ifdef VBOX_WS_WIN
[91114]49# include "VBoxUtils-win.h"
[91109]50#endif
[100064]51#ifdef VBOX_WS_NIX
[79365]52# include "UICommon.h"
[99479]53# include "VBoxUtils-nix.h"
[98999]54# ifndef VBOX_GUI_WITH_CUSTOMIZATIONS1
[99002]55# include "UIConverter.h"
[98999]56# endif
[91109]57#endif
[57480]58
59/* Other VBox includes: */
[76606]60#include <iprt/asm.h>
61#include <iprt/assert.h>
62#include <iprt/ldr.h>
63#ifdef VBOX_WS_WIN
64# include <iprt/win/windows.h>
65#endif
[70934]66
[91110]67/* External includes: */
[91114]68#include <math.h>
[100064]69#ifdef VBOX_WS_NIX
[91110]70# include <xcb/xcb.h>
71#endif
[58880]72
[91110]73
[70934]74#ifdef VBOX_WS_WIN
75
[72013]76# ifndef DPI_ENUMS_DECLARED
[70934]77typedef enum _MONITOR_DPI_TYPE // gently stolen from MSDN
78{
79 MDT_EFFECTIVE_DPI = 0,
80 MDT_ANGULAR_DPI = 1,
81 MDT_RAW_DPI = 2,
82 MDT_DEFAULT = MDT_EFFECTIVE_DPI
83} MONITOR_DPI_TYPE;
[72013]84# endif
[72016]85typedef void (WINAPI *PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *);
[70934]86
[72013]87/** Set when dynamic API import is reoslved. */
88static bool volatile g_fResolved;
89/** Pointer to Shcore.dll!GetDpiForMonitor, introduced in windows 8.1. */
90static PFN_GetDpiForMonitor g_pfnGetDpiForMonitor = NULL;
91
92/** @returns true if all APIs found, false if missing APIs */
93static bool ResolveDynamicImports(void)
94{
95 if (!g_fResolved)
96 {
97 PFN_GetDpiForMonitor pfn = (decltype(pfn))RTLdrGetSystemSymbol("Shcore.dll", "GetDpiForMonitor");
98 g_pfnGetDpiForMonitor = pfn;
99 ASMCompilerBarrier();
100
101 g_fResolved = true;
102 }
103 return g_pfnGetDpiForMonitor != NULL;
104}
105
[85121]106static BOOL CALLBACK MonitorEnumProcF(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lpClipRect, LPARAM dwData) RT_NOTHROW_DEF
[70934]107{
108 /* These required for clipped screens only: */
109 RT_NOREF(hdcMonitor, lpClipRect);
110
111 /* Acquire effective DPI (available since Windows 8.1): */
[72013]112 AssertReturn(g_pfnGetDpiForMonitor, false);
[72016]113 UINT uOutX = 0;
114 UINT uOutY = 0;
[72013]115 g_pfnGetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &uOutX, &uOutY);
116 reinterpret_cast<QList<QPair<int, int> >*>(dwData)->append(qMakePair(uOutX, uOutY));
[70934]117
[72013]118 return TRUE;
[70934]119}
120
121#endif /* VBOX_WS_WIN */
122
123
[100064]124#if defined(VBOX_WS_NIX) && !defined(VBOX_GUI_WITH_CUSTOMIZATIONS1)
[63003]125
[103321]126/* static */
127const QString
128UIDesktopWidgetWatchdog::s_strVBoxDesktopWatchdogPolicySynthTest = "VBOX_DESKTOPWATCHDOGPOLICY_SYNTHTEST";
129
[57480]130/** QWidget extension used as
131 * an invisible window on the basis of which we
132 * can calculate available host-screen geometry. */
133class UIInvisibleWindow : public QWidget
134{
135 Q_OBJECT;
136
137signals:
138
139 /** Notifies listeners about host-screen available-geometry was calulated.
140 * @param iHostScreenIndex holds the index of the host-screen this window created for.
141 * @param availableGeometry holds the available-geometry of the host-screen this window created for. */
142 void sigHostScreenAvailableGeometryCalculated(int iHostScreenIndex, QRect availableGeometry);
143
144public:
145
146 /** Constructs invisible window for the host-screen with @a iHostScreenIndex. */
147 UIInvisibleWindow(int iHostScreenIndex);
148
[64628]149private slots:
150
151 /** Performs fallback drop. */
152 void sltFallback();
153
[57480]154private:
155
[64627]156 /** Move @a pEvent handler. */
157 void moveEvent(QMoveEvent *pEvent);
[57480]158 /** Resize @a pEvent handler. */
159 void resizeEvent(QResizeEvent *pEvent);
160
161 /** Holds the index of the host-screen this window created for. */
[64627]162 const int m_iHostScreenIndex;
163
164 /** Holds whether the move event came. */
165 bool m_fMoveCame;
166 /** Holds whether the resize event came. */
167 bool m_fResizeCame;
[57480]168};
169
[62986]170
171/*********************************************************************************************************************************
172* Class UIInvisibleWindow implementation. *
173*********************************************************************************************************************************/
174
[57480]175UIInvisibleWindow::UIInvisibleWindow(int iHostScreenIndex)
176 : QWidget(0, Qt::Window | Qt::FramelessWindowHint)
177 , m_iHostScreenIndex(iHostScreenIndex)
[64627]178 , m_fMoveCame(false)
179 , m_fResizeCame(false)
[57480]180{
181 /* Resize to minimum size of 1 pixel: */
182 resize(1, 1);
183 /* Apply visual and mouse-event mask for that 1 pixel: */
184 setMask(QRect(0, 0, 1, 1));
185 /* For composite WMs make this 1 pixel transparent: */
[79365]186 if (uiCommon().isCompositingManagerRunning())
[57480]187 setAttribute(Qt::WA_TranslucentBackground);
[64628]188 /* Install fallback handler: */
189 QTimer::singleShot(5000, this, SLOT(sltFallback()));
[57480]190}
191
[64628]192void UIInvisibleWindow::sltFallback()
193{
[64651]194 /* Sanity check for fallback geometry: */
195 QRect fallbackGeometry(x(), y(), width(), height());
196 if ( fallbackGeometry.width() <= 1
197 || fallbackGeometry.height() <= 1)
198 fallbackGeometry = gpDesktop->screenGeometry(m_iHostScreenIndex);
[102786]199 LogRel(("GUI: UIInvisibleWindow::sltFallback: %s event missing. "
[64628]200 "Screen: %d, work area: %dx%d x %dx%d\n",
201 !m_fMoveCame ? "Move" : !m_fResizeCame ? "Resize" : "Some",
[64651]202 m_iHostScreenIndex, fallbackGeometry.x(), fallbackGeometry.y(), fallbackGeometry.width(), fallbackGeometry.height()));
203 emit sigHostScreenAvailableGeometryCalculated(m_iHostScreenIndex, fallbackGeometry);
[64628]204}
205
[64627]206void UIInvisibleWindow::moveEvent(QMoveEvent *pEvent)
207{
208 /* We do have both move and resize events,
209 * with no idea who will come first, but we need
210 * to send a final signal after last of events arrived. */
211
212 /* Call to base-class: */
213 QWidget::moveEvent(pEvent);
214
215 /* Ignore 'not-yet-shown' case: */
216 if (!isVisible())
217 return;
218
219 /* Mark move event as received: */
220 m_fMoveCame = true;
221
222 /* If the resize event already came: */
223 if (m_fResizeCame)
224 {
225 /* Notify listeners about host-screen available-geometry was calulated: */
226 LogRel2(("GUI: UIInvisibleWindow::moveEvent: Screen: %d, work area: %dx%d x %dx%d\n", m_iHostScreenIndex,
227 x(), y(), width(), height()));
228 emit sigHostScreenAvailableGeometryCalculated(m_iHostScreenIndex, QRect(x(), y(), width(), height()));
229 }
230}
231
[57480]232void UIInvisibleWindow::resizeEvent(QResizeEvent *pEvent)
233{
[64627]234 /* We do have both move and resize events,
235 * with no idea who will come first, but we need
236 * to send a final signal after last of events arrived. */
237
[57480]238 /* Call to base-class: */
239 QWidget::resizeEvent(pEvent);
240
241 /* Ignore 'not-yet-shown' case: */
242 if (!isVisible())
243 return;
244
[64627]245 /* Mark resize event as received: */
246 m_fResizeCame = true;
247
248 /* If the move event already came: */
249 if (m_fMoveCame)
250 {
251 /* Notify listeners about host-screen available-geometry was calulated: */
252 LogRel2(("GUI: UIInvisibleWindow::resizeEvent: Screen: %d, work area: %dx%d x %dx%d\n", m_iHostScreenIndex,
253 x(), y(), width(), height()));
254 emit sigHostScreenAvailableGeometryCalculated(m_iHostScreenIndex, QRect(x(), y(), width(), height()));
255 }
[57480]256}
257
[100064]258#endif /* VBOX_WS_NIX && !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
[62986]259
[63003]260
[62986]261/*********************************************************************************************************************************
262* Class UIDesktopWidgetWatchdog implementation. *
263*********************************************************************************************************************************/
264
[63044]265/* static */
[71429]266UIDesktopWidgetWatchdog *UIDesktopWidgetWatchdog::s_pInstance = 0;
[63044]267
268/* static */
269void UIDesktopWidgetWatchdog::create()
[57480]270{
[63044]271 /* Make sure instance isn't created: */
[71429]272 AssertReturnVoid(!s_pInstance);
[63044]273
274 /* Create/prepare instance: */
275 new UIDesktopWidgetWatchdog;
[71429]276 AssertReturnVoid(s_pInstance);
277 s_pInstance->prepare();
[57480]278}
279
[63044]280/* static */
281void UIDesktopWidgetWatchdog::destroy()
282{
283 /* Make sure instance is created: */
[71429]284 AssertReturnVoid(s_pInstance);
[63044]285
286 /* Cleanup/destroy instance: */
[71429]287 s_pInstance->cleanup();
288 delete s_pInstance;
289 AssertReturnVoid(!s_pInstance);
[63044]290}
291
292UIDesktopWidgetWatchdog::UIDesktopWidgetWatchdog()
[100064]293#if defined(VBOX_WS_NIX) && !defined(VBOX_GUI_WITH_CUSTOMIZATIONS1)
[98999]294 : m_enmSynthTestPolicy(DesktopWatchdogPolicy_SynthTest_Both)
295#endif
[63044]296{
297 /* Initialize instance: */
[71429]298 s_pInstance = this;
[63044]299}
300
[57510]301UIDesktopWidgetWatchdog::~UIDesktopWidgetWatchdog()
302{
[63044]303 /* Deinitialize instance: */
[71429]304 s_pInstance = 0;
[57510]305}
306
[97681]307/* static */
308int UIDesktopWidgetWatchdog::screenCount()
[62998]309{
[94015]310 return QGuiApplication::screens().size();
[62998]311}
312
[97681]313/* static */
[97706]314int UIDesktopWidgetWatchdog::primaryScreenNumber()
[75934]315{
[94015]316 return screenToIndex(QGuiApplication::primaryScreen());
[75934]317}
318
[97681]319/* static */
320int UIDesktopWidgetWatchdog::screenNumber(const QWidget *pWidget)
[63041]321{
[97706]322 QScreen *pScreen = 0;
[94015]323 if (pWidget)
[97706]324 if (QWindow *pWindow = pWidget->windowHandle())
325 pScreen = pWindow->screen();
326
327 return screenToIndex(pScreen);
[63041]328}
329
[97681]330/* static */
331int UIDesktopWidgetWatchdog::screenNumber(const QPoint &point)
[63041]332{
[97706]333#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
[94015]334 return screenToIndex(QGuiApplication::screenAt(point));
[97706]335#else /* Qt < 5.10 */
[63041]336 return QApplication::desktop()->screenNumber(point);
[97706]337#endif /* Qt < 5.10 */
[63041]338}
339
[97701]340QRect UIDesktopWidgetWatchdog::screenGeometry(QScreen *pScreen) const
341{
342 /* Just return screen geometry: */
343 return pScreen->geometry();
344}
345
[97682]346QRect UIDesktopWidgetWatchdog::screenGeometry(int iHostScreenIndex /* = -1 */) const
[57480]347{
[97701]348 /* Gather suitable screen, use primary if failed: */
349 QScreen *pScreen = QGuiApplication::screens().value(iHostScreenIndex, QGuiApplication::primaryScreen());
[57480]350
[97701]351 /* Redirect call to wrapper above: */
352 return screenGeometry(pScreen);
[57480]353}
354
[97682]355QRect UIDesktopWidgetWatchdog::screenGeometry(const QWidget *pWidget) const
[63041]356{
[97701]357 /* Gather suitable screen, use primary if failed: */
358 QScreen *pScreen = QGuiApplication::primaryScreen();
359 if (pWidget)
360 if (QWindow *pWindow = pWidget->windowHandle())
361 pScreen = pWindow->screen();
362
[63041]363 /* Redirect call to wrapper above: */
[97701]364 return screenGeometry(pScreen);
[63041]365}
366
[97682]367QRect UIDesktopWidgetWatchdog::screenGeometry(const QPoint &point) const
[63041]368{
[97702]369#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
[97701]370 /* Gather suitable screen, use primary if failed: */
371 QScreen *pScreen = QGuiApplication::screenAt(point);
372 if (!pScreen)
373 pScreen = QGuiApplication::primaryScreen();
374
[63041]375 /* Redirect call to wrapper above: */
[97701]376 return screenGeometry(pScreen);
[97702]377#else /* Qt < 5.10 */
378 /* Gather suitable screen index: */
379 const int iHostScreenIndex = QApplication::desktop()->screenNumber(point);
380
381 /* Redirect call to wrapper above: */
382 return screenGeometry(iHostScreenIndex);
383#endif /* Qt < 5.10 */
[63041]384}
385
[97703]386QRect UIDesktopWidgetWatchdog::availableGeometry(QScreen *pScreen) const
[57480]387{
[100064]388#ifdef VBOX_WS_NIX
[97703]389# ifdef VBOX_GUI_WITH_CUSTOMIZATIONS1
[84696]390 // WORKAROUND:
391 // For customer WM we don't want Qt to return wrong available geometry,
392 // so we are returning fallback screen geometry in any case..
[97703]393 return screenGeometry(pScreen);
394# else /* !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
[63328]395 /* Get cached available-geometry: */
[97703]396 const QRect availableGeometry = m_availableGeometryData.value(screenToIndex(pScreen));
[63328]397 /* Return cached available-geometry if it's valid or screen-geometry otherwise: */
[97703]398 return availableGeometry.isValid() ? availableGeometry : screenGeometry(pScreen);
399# endif /* !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
[100064]400#else /* !VBOX_WS_NIX */
[97703]401 /* Just return screen available-geometry: */
402 return pScreen->availableGeometry();
[100064]403#endif /* !VBOX_WS_NIX */
[57480]404}
405
[97703]406QRect UIDesktopWidgetWatchdog::availableGeometry(int iHostScreenIndex /* = -1 */) const
407{
408 /* Gather suitable screen, use primary if failed: */
409 QScreen *pScreen = QGuiApplication::screens().value(iHostScreenIndex, QGuiApplication::primaryScreen());
410
411 /* Redirect call to wrapper above: */
412 return availableGeometry(pScreen);
413}
414
[97682]415QRect UIDesktopWidgetWatchdog::availableGeometry(const QWidget *pWidget) const
[63041]416{
[97703]417 /* Gather suitable screen, use primary if failed: */
418 QScreen *pScreen = QGuiApplication::primaryScreen();
419 if (pWidget)
420 if (QWindow *pWindow = pWidget->windowHandle())
421 pScreen = pWindow->screen();
422
[63041]423 /* Redirect call to wrapper above: */
[97703]424 return availableGeometry(pScreen);
[63041]425}
426
[97682]427QRect UIDesktopWidgetWatchdog::availableGeometry(const QPoint &point) const
[63041]428{
[97703]429#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
430 /* Gather suitable screen, use primary if failed: */
[94015]431 QScreen *pScreen = QGuiApplication::screenAt(point);
[97703]432 if (!pScreen)
433 pScreen = QGuiApplication::primaryScreen();
434
[63041]435 /* Redirect call to wrapper above: */
[97703]436 return availableGeometry(pScreen);
437#else /* Qt < 5.10 */
438 /* Gather suitable screen index: */
439 const int iHostScreenIndex = QApplication::desktop()->screenNumber(point);
440
441 /* Redirect call to wrapper above: */
442 return availableGeometry(iHostScreenIndex);
443#endif /* Qt < 5.10 */
[63041]444}
445
[97715]446/* static */
447QRegion UIDesktopWidgetWatchdog::overallScreenRegion()
[63227]448{
449 /* Calculate region: */
450 QRegion region;
[97715]451 foreach (QScreen *pScreen, QGuiApplication::screens())
452 region += gpDesktop->screenGeometry(pScreen);
[63227]453 return region;
454}
455
[97715]456/* static */
457QRegion UIDesktopWidgetWatchdog::overallAvailableRegion()
[63227]458{
459 /* Calculate region: */
460 QRegion region;
[97715]461 foreach (QScreen *pScreen, QGuiApplication::screens())
[63227]462 {
463 /* Get enumerated screen's available area: */
[97715]464 QRect rect = gpDesktop->availableGeometry(pScreen);
[63227]465#ifdef VBOX_WS_WIN
466 /* On Windows host window can exceed the available
467 * area in maximized/sticky-borders state: */
468 rect.adjust(-10, -10, 10, 10);
469#endif /* VBOX_WS_WIN */
470 /* Append rectangle: */
471 region += rect;
472 }
473 /* Return region: */
474 return region;
475}
476
[100064]477#ifdef VBOX_WS_NIX
[97681]478/* static */
479bool UIDesktopWidgetWatchdog::isFakeScreenDetected()
[63041]480{
481 // WORKAROUND:
482 // In 5.6.1 Qt devs taught the XCB plugin to silently swap last detached screen
483 // with a fake one, and there is no API-way to distinguish fake from real one
484 // because all they do is erasing output for the last real screen, keeping
485 // all other screen attributes stale. Gladly output influencing screen name
486 // so we can use that horrible workaround to detect a fake XCB screen.
487 return qApp->screens().size() == 0 /* zero-screen case is impossible after 5.6.1 */
488 || (qApp->screens().size() == 1 && qApp->screens().first()->name() == ":0.0");
489}
[100064]490#endif /* VBOX_WS_NIX */
[63041]491
[97681]492/* static */
[70934]493double UIDesktopWidgetWatchdog::devicePixelRatio(int iHostScreenIndex /* = -1 */)
[69931]494{
495 /* First, we should check whether the screen is valid: */
496 QScreen *pScreen = iHostScreenIndex == -1
497 ? QGuiApplication::primaryScreen()
498 : QGuiApplication::screens().value(iHostScreenIndex);
499 AssertPtrReturn(pScreen, 1.0);
[70934]500
[69931]501 /* Then acquire device-pixel-ratio: */
502 return pScreen->devicePixelRatio();
503}
504
[97681]505/* static */
[69931]506double UIDesktopWidgetWatchdog::devicePixelRatio(QWidget *pWidget)
507{
508 /* Redirect call to wrapper above: */
509 return devicePixelRatio(screenNumber(pWidget));
510}
511
[97681]512/* static */
[70934]513double UIDesktopWidgetWatchdog::devicePixelRatioActual(int iHostScreenIndex /* = -1 */)
514{
515 /* First, we should check whether the screen is valid: */
[71102]516 QScreen *pScreen = 0;
517 if (iHostScreenIndex == -1)
518 {
519 pScreen = QGuiApplication::primaryScreen();
520 iHostScreenIndex = QGuiApplication::screens().indexOf(pScreen);
521 }
522 else
523 pScreen = QGuiApplication::screens().value(iHostScreenIndex);
[70934]524 AssertPtrReturn(pScreen, 1.0);
525
526#ifdef VBOX_WS_WIN
[72013]527 /* Enumerate available monitors through EnumDisplayMonitors if GetDpiForMonitor is available: */
528 if (ResolveDynamicImports())
[72011]529 {
[70934]530 QList<QPair<int, int> > listOfScreenDPI;
[72013]531 EnumDisplayMonitors(0, 0, MonitorEnumProcF, (LPARAM)&listOfScreenDPI);
[70934]532 if (iHostScreenIndex >= 0 && iHostScreenIndex < listOfScreenDPI.size())
533 {
534 const QPair<int, int> dpiPair = listOfScreenDPI.at(iHostScreenIndex);
535 if (dpiPair.first > 0)
536 return (double)dpiPair.first / 96 /* dpi unawarness value */;
537 }
538 }
539#endif /* VBOX_WS_WIN */
540
541 /* Then acquire device-pixel-ratio: */
542 return pScreen->devicePixelRatio();
543}
544
[97681]545/* static */
[70934]546double UIDesktopWidgetWatchdog::devicePixelRatioActual(QWidget *pWidget)
547{
548 /* Redirect call to wrapper above: */
549 return devicePixelRatioActual(screenNumber(pWidget));
550}
551
[91109]552/* static */
553QRect UIDesktopWidgetWatchdog::normalizeGeometry(const QRect &rectangle,
554 const QRegion &boundRegion,
555 bool fCanResize /* = true */)
556{
557 /* Perform direct and flipped search of position for @a rectangle to make sure it is fully contained
558 * inside @a boundRegion region by moving & resizing (if @a fCanResize is specified) @a rectangle if
559 * necessary. Selects the minimum shifted result between direct and flipped variants. */
560
561 /* Direct search for normalized rectangle: */
562 QRect var1(getNormalized(rectangle, boundRegion, fCanResize));
563
564 /* Flipped search for normalized rectangle: */
565 QRect var2(flip(getNormalized(flip(rectangle).boundingRect(),
566 flip(boundRegion), fCanResize)).boundingRect());
567
568 /* Calculate shift from starting position for both variants: */
569 double dLength1 = sqrt(pow((double)(var1.x() - rectangle.x()), (double)2) +
570 pow((double)(var1.y() - rectangle.y()), (double)2));
571 double dLength2 = sqrt(pow((double)(var2.x() - rectangle.x()), (double)2) +
572 pow((double)(var2.y() - rectangle.y()), (double)2));
573
574 /* Return minimum shifted variant: */
575 return dLength1 > dLength2 ? var2 : var1;
576}
577
578/* static */
579QRect UIDesktopWidgetWatchdog::getNormalized(const QRect &rectangle,
580 const QRegion &boundRegion,
581 bool /* fCanResize = true */)
582{
583 /* Ensures that the given rectangle @a rectangle is fully contained within the region @a boundRegion
584 * by moving @a rectangle if necessary. If @a rectangle is larger than @a boundRegion, top left
585 * corner of @a rectangle is aligned with the top left corner of maximum available rectangle and,
586 * if @a fCanResize is true, @a rectangle is shrinked to become fully visible. */
587
588 /* Storing available horizontal sub-rectangles & vertical shifts: */
589 const int iWindowVertical = rectangle.center().y();
590 QList<QRect> rectanglesList;
591 QList<int> shiftsList;
[94026]592 for (QRegion::const_iterator it = boundRegion.begin(); it != boundRegion.end(); ++it)
[91109]593 {
[94026]594 QRect currentItem = *it;
[91109]595 const int iCurrentDelta = qAbs(iWindowVertical - currentItem.center().y());
596 const int iShift2Top = currentItem.top() - rectangle.top();
597 const int iShift2Bot = currentItem.bottom() - rectangle.bottom();
598
599 int iTtemPosition = 0;
600 foreach (QRect item, rectanglesList)
601 {
602 const int iDelta = qAbs(iWindowVertical - item.center().y());
603 if (iDelta > iCurrentDelta)
604 break;
605 else
606 ++iTtemPosition;
607 }
608 rectanglesList.insert(iTtemPosition, currentItem);
609
610 int iShift2TopPos = 0;
611 foreach (int iShift, shiftsList)
612 if (qAbs(iShift) > qAbs(iShift2Top))
613 break;
614 else
615 ++iShift2TopPos;
616 shiftsList.insert(iShift2TopPos, iShift2Top);
617
618 int iShift2BotPos = 0;
619 foreach (int iShift, shiftsList)
620 if (qAbs(iShift) > qAbs(iShift2Bot))
621 break;
622 else
623 ++iShift2BotPos;
624 shiftsList.insert(iShift2BotPos, iShift2Bot);
625 }
626
627 /* Trying to find the appropriate place for window: */
628 QRect result;
629 for (int i = -1; i < shiftsList.size(); ++i)
630 {
631 /* Move to appropriate vertical: */
632 QRect newRectangle(rectangle);
633 if (i >= 0)
634 newRectangle.translate(0, shiftsList[i]);
635
636 /* Search horizontal shift: */
637 int iMaxShift = 0;
638 foreach (QRect item, rectanglesList)
639 {
640 QRect trectangle(newRectangle.translated(item.left() - newRectangle.left(), 0));
641 if (!item.intersects(trectangle))
642 continue;
643
644 if (newRectangle.left() < item.left())
645 {
646 const int iShift = item.left() - newRectangle.left();
647 iMaxShift = qAbs(iShift) > qAbs(iMaxShift) ? iShift : iMaxShift;
648 }
649 else if (newRectangle.right() > item.right())
650 {
651 const int iShift = item.right() - newRectangle.right();
652 iMaxShift = qAbs(iShift) > qAbs(iMaxShift) ? iShift : iMaxShift;
653 }
654 }
655
656 /* Shift across the horizontal direction: */
657 newRectangle.translate(iMaxShift, 0);
658
659 /* Check the translated rectangle to feat the rules: */
660 if (boundRegion.united(newRectangle) == boundRegion)
661 result = newRectangle;
662
663 if (!result.isNull())
664 break;
665 }
666
667 if (result.isNull())
668 {
669 /* Resize window to feat desirable size
670 * using max of available rectangles: */
671 QRect maxRectangle;
672 quint64 uMaxSquare = 0;
673 foreach (QRect item, rectanglesList)
674 {
675 const quint64 uSquare = item.width() * item.height();
676 if (uSquare > uMaxSquare)
677 {
678 uMaxSquare = uSquare;
679 maxRectangle = item;
680 }
681 }
682
683 result = rectangle;
684 result.moveTo(maxRectangle.x(), maxRectangle.y());
685 if (maxRectangle.right() < result.right())
686 result.setRight(maxRectangle.right());
687 if (maxRectangle.bottom() < result.bottom())
688 result.setBottom(maxRectangle.bottom());
689 }
690
691 return result;
692}
693
694void UIDesktopWidgetWatchdog::centerWidget(QWidget *pWidget,
695 QWidget *pRelative,
[97682]696 bool fCanResize /* = true */) const
[91109]697{
698 /* If necessary, pWidget's position is adjusted to make it fully visible within
699 * the available desktop area. If pWidget is bigger then this area, it will also
700 * be resized unless fCanResize is false or there is an inappropriate minimum
701 * size limit (in which case the top left corner will be simply aligned with the top
702 * left corner of the available desktop area). pWidget must be a top-level widget.
703 * pRelative may be any widget, but if it's not top-level itself, its top-level
704 * widget will be used for calculations. pRelative can also be NULL, in which case
705 * pWidget will be centered relative to the available desktop area. */
706
707 AssertReturnVoid(pWidget);
[100650]708 AssertReturnVoid(pWidget->isWindow());
[91109]709
710 QRect deskGeo, parentGeo;
711 if (pRelative)
712 {
713 pRelative = pRelative->window();
[97681]714 deskGeo = availableGeometry(pRelative);
[91109]715 parentGeo = pRelative->frameGeometry();
716 // WORKAROUND:
717 // On X11/Gnome, geo/frameGeo.x() and y() are always 0 for top level
718 // widgets with parents, what a shame. Use mapToGlobal() to workaround.
719 QPoint d = pRelative->mapToGlobal(QPoint(0, 0));
720 d.rx() -= pRelative->geometry().x() - pRelative->x();
721 d.ry() -= pRelative->geometry().y() - pRelative->y();
722 parentGeo.moveTopLeft(d);
723 }
724 else
725 {
[97681]726 deskGeo = availableGeometry();
[91109]727 parentGeo = deskGeo;
728 }
729
730 // WORKAROUND:
731 // On X11, there is no way to determine frame geometry (including WM
732 // decorations) before the widget is shown for the first time. Stupidly
733 // enumerate other top level widgets to find the thickest frame. The code
734 // is based on the idea taken from QDialog::adjustPositionInternal().
735
736 int iExtraW = 0;
737 int iExtraH = 0;
738
739 QWidgetList list = QApplication::topLevelWidgets();
740 QListIterator<QWidget*> it(list);
741 while ((iExtraW == 0 || iExtraH == 0) && it.hasNext())
742 {
743 int iFrameW, iFrameH;
744 QWidget *pCurrent = it.next();
745 if (!pCurrent->isVisible())
746 continue;
747
748 iFrameW = pCurrent->frameGeometry().width() - pCurrent->width();
749 iFrameH = pCurrent->frameGeometry().height() - pCurrent->height();
750
751 iExtraW = qMax(iExtraW, iFrameW);
752 iExtraH = qMax(iExtraH, iFrameH);
753 }
754
755 /* On non-X11 platforms, the following would be enough instead of the above workaround: */
756 // QRect geo = frameGeometry();
757 QRect geo = QRect(0, 0, pWidget->width() + iExtraW,
758 pWidget->height() + iExtraH);
759
760 geo.moveCenter(QPoint(parentGeo.x() + (parentGeo.width() - 1) / 2,
761 parentGeo.y() + (parentGeo.height() - 1) / 2));
762
763 /* Ensure the widget is within the available desktop area: */
764 QRect newGeo = normalizeGeometry(geo, deskGeo, fCanResize);
765#ifdef VBOX_WS_MAC
766 // WORKAROUND:
767 // No idea why, but Qt doesn't respect if there is a unified toolbar on the
768 // ::move call. So manually add the height of the toolbar before setting
769 // the position.
770 if (pRelative)
771 newGeo.translate(0, ::darwinWindowToolBarHeight(pWidget));
772#endif /* VBOX_WS_MAC */
773
774 pWidget->move(newGeo.topLeft());
775
776 if ( fCanResize
777 && (geo.width() != newGeo.width() || geo.height() != newGeo.height()))
778 pWidget->resize(newGeo.width() - iExtraW, newGeo.height() - iExtraH);
779}
780
781/* static */
[97386]782void UIDesktopWidgetWatchdog::restoreWidget(QWidget *pWidget)
783{
784 pWidget->show();
785 pWidget->setWindowState(pWidget->windowState() & ~Qt::WindowMinimized);
786 pWidget->activateWindow();
787 pWidget->raise();
788}
789
790/* static */
[91109]791void UIDesktopWidgetWatchdog::setTopLevelGeometry(QWidget *pWidget, int x, int y, int w, int h)
792{
793 AssertPtrReturnVoid(pWidget);
[100064]794#ifdef VBOX_WS_NIX
[91109]795# define QWINDOWSIZE_MAX ((1<<24)-1)
[99438]796 if (pWidget->isWindow() && pWidget->isVisible() && uiCommon().X11ServerAvailable())
[91109]797 {
798 // WORKAROUND:
799 // X11 window managers are not required to accept geometry changes on
800 // the top-level window. Unfortunately, current at Qt 5.6 and 5.7, Qt
801 // assumes that the change will succeed, and resizes all sub-windows
802 // unconditionally. By calling ConfigureWindow directly, Qt will see
803 // our change request as an externally triggered one on success and not
804 // at all if it is rejected.
[97681]805 const double dDPR = devicePixelRatio(pWidget);
[91109]806 uint16_t fMask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
807 | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
808 uint32_t values[] = { (uint32_t)(x * dDPR), (uint32_t)(y * dDPR), (uint32_t)(w * dDPR), (uint32_t)(h * dDPR) };
[94013]809 xcb_configure_window(NativeWindowSubsystem::X11GetConnection(), (xcb_window_t)pWidget->winId(),
[91109]810 fMask, values);
811 xcb_size_hints_t hints;
812 hints.flags = 1 /* XCB_ICCCM_SIZE_HINT_US_POSITION */
813 | 2 /* XCB_ICCCM_SIZE_HINT_US_SIZE */
814 | 512 /* XCB_ICCCM_SIZE_P_WIN_GRAVITY */;
815 hints.x = x * dDPR;
816 hints.y = y * dDPR;
817 hints.width = w * dDPR;
818 hints.height = h * dDPR;
819 hints.min_width = pWidget->minimumSize().width() * dDPR;
820 hints.min_height = pWidget->minimumSize().height() * dDPR;
821 hints.max_width = pWidget->maximumSize().width() * dDPR;
822 hints.max_height = pWidget->maximumSize().height() * dDPR;
823 hints.width_inc = pWidget->sizeIncrement().width() * dDPR;
824 hints.height_inc = pWidget->sizeIncrement().height() * dDPR;
825 hints.base_width = pWidget->baseSize().width() * dDPR;
826 hints.base_height = pWidget->baseSize().height() * dDPR;
827 hints.win_gravity = XCB_GRAVITY_STATIC;
828 if (hints.min_width > 0 || hints.min_height > 0)
829 hints.flags |= 16 /* XCB_ICCCM_SIZE_HINT_P_MIN_SIZE */;
830 if (hints.max_width < QWINDOWSIZE_MAX || hints.max_height < QWINDOWSIZE_MAX)
831 hints.flags |= 32 /* XCB_ICCCM_SIZE_HINT_P_MAX_SIZE */;
832 if (hints.width_inc > 0 || hints.height_inc)
833 hints.flags |= 64 /* XCB_ICCCM_SIZE_HINT_P_MIN_SIZE */
834 | 256 /* XCB_ICCCM_SIZE_HINT_BASE_SIZE */;
[94013]835 xcb_change_property(NativeWindowSubsystem::X11GetConnection(), XCB_PROP_MODE_REPLACE,
[91109]836 (xcb_window_t)pWidget->winId(), XCB_ATOM_WM_NORMAL_HINTS,
837 XCB_ATOM_WM_SIZE_HINTS, 32, sizeof(hints) >> 2, &hints);
[94013]838 xcb_flush(NativeWindowSubsystem::X11GetConnection());
[91109]839 }
840 else
841 // WORKAROUND:
842 // Call the Qt method if the window is not visible as otherwise no
843 // Configure event will arrive to tell Qt what geometry we want.
844 pWidget->setGeometry(x, y, w, h);
[100064]845# else /* !VBOX_WS_NIX */
[91109]846 pWidget->setGeometry(x, y, w, h);
[100064]847# endif /* !VBOX_WS_NIX */
[91109]848}
849
850/* static */
851void UIDesktopWidgetWatchdog::setTopLevelGeometry(QWidget *pWidget, const QRect &rect)
852{
853 UIDesktopWidgetWatchdog::setTopLevelGeometry(pWidget, rect.x(), rect.y(), rect.width(), rect.height());
854}
855
856/* static */
857bool UIDesktopWidgetWatchdog::activateWindow(WId wId, bool fSwitchDesktop /* = true */)
858{
859 Q_UNUSED(fSwitchDesktop);
860 bool fResult = true;
861
862#if defined(VBOX_WS_WIN)
863
864 fResult &= NativeWindowSubsystem::WinActivateWindow(wId, fSwitchDesktop);
865
[100064]866#elif defined(VBOX_WS_NIX)
[91109]867
[99438]868 fResult &= NativeWindowSubsystem::activateWindow(uiCommon().X11ServerAvailable(), wId, fSwitchDesktop);
[99434]869
[91109]870#else
871
872 NOREF(wId);
873 NOREF(fSwitchDesktop);
874 AssertFailed();
875 fResult = false;
876
877#endif
878
879 if (!fResult)
880 Log1WarningFunc(("Couldn't activate wId=%08X\n", wId));
881
882 return fResult;
883}
884
[64446]885void UIDesktopWidgetWatchdog::sltHostScreenAdded(QScreen *pHostScreen)
[62990]886{
[62998]887// printf("UIDesktopWidgetWatchdog::sltHostScreenAdded(%d)\n", screenCount());
[62990]888
[64446]889 /* Listen for screen signals: */
[68190]890 connect(pHostScreen, &QScreen::geometryChanged,
891 this, &UIDesktopWidgetWatchdog::sltHandleHostScreenResized);
892 connect(pHostScreen, &QScreen::availableGeometryChanged,
893 this, &UIDesktopWidgetWatchdog::sltHandleHostScreenWorkAreaResized);
[64446]894
[100064]895#if defined(VBOX_WS_NIX) && !defined(VBOX_GUI_WITH_CUSTOMIZATIONS1)
[62990]896 /* Update host-screen configuration: */
897 updateHostScreenConfiguration();
[100064]898#endif /* VBOX_WS_NIX && !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
[63040]899
900 /* Notify listeners: */
901 emit sigHostScreenCountChanged(screenCount());
[62990]902}
903
[64446]904void UIDesktopWidgetWatchdog::sltHostScreenRemoved(QScreen *pHostScreen)
[62990]905{
[62998]906// printf("UIDesktopWidgetWatchdog::sltHostScreenRemoved(%d)\n", screenCount());
[62990]907
[64446]908 /* Forget about screen signals: */
[68190]909 disconnect(pHostScreen, &QScreen::geometryChanged,
910 this, &UIDesktopWidgetWatchdog::sltHandleHostScreenResized);
911 disconnect(pHostScreen, &QScreen::availableGeometryChanged,
912 this, &UIDesktopWidgetWatchdog::sltHandleHostScreenWorkAreaResized);
[64446]913
[100064]914#if defined(VBOX_WS_NIX) && !defined(VBOX_GUI_WITH_CUSTOMIZATIONS1)
[62990]915 /* Update host-screen configuration: */
916 updateHostScreenConfiguration();
[100064]917#endif /* VBOX_WS_NIX && !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
[63040]918
919 /* Notify listeners: */
920 emit sigHostScreenCountChanged(screenCount());
[62990]921}
922
[64621]923void UIDesktopWidgetWatchdog::sltHandleHostScreenResized(const QRect &geometry)
[64446]924{
925 /* Get the screen: */
926 QScreen *pScreen = sender() ? qobject_cast<QScreen*>(sender()) : 0;
927 AssertPtrReturnVoid(pScreen);
[64440]928
[64446]929 /* Determine screen index: */
930 const int iHostScreenIndex = qApp->screens().indexOf(pScreen);
931 AssertReturnVoid(iHostScreenIndex != -1);
[64621]932 LogRel(("GUI: UIDesktopWidgetWatchdog::sltHandleHostScreenResized: "
933 "Screen %d is formally resized to: %dx%d x %dx%d\n",
934 iHostScreenIndex, geometry.x(), geometry.y(),
935 geometry.width(), geometry.height()));
[62988]936
[100064]937#if defined(VBOX_WS_NIX) && !defined(VBOX_GUI_WITH_CUSTOMIZATIONS1)
[62989]938 /* Update host-screen available-geometry: */
939 updateHostScreenAvailableGeometry(iHostScreenIndex);
[100064]940#endif /* VBOX_WS_NIX && !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
[63040]941
942 /* Notify listeners: */
943 emit sigHostScreenResized(iHostScreenIndex);
[62988]944}
945
[64621]946void UIDesktopWidgetWatchdog::sltHandleHostScreenWorkAreaResized(const QRect &availableGeometry)
[63040]947{
[64446]948 /* Get the screen: */
949 QScreen *pScreen = sender() ? qobject_cast<QScreen*>(sender()) : 0;
950 AssertPtrReturnVoid(pScreen);
951
952 /* Determine screen index: */
953 const int iHostScreenIndex = qApp->screens().indexOf(pScreen);
954 AssertReturnVoid(iHostScreenIndex != -1);
[64621]955 LogRel(("GUI: UIDesktopWidgetWatchdog::sltHandleHostScreenWorkAreaResized: "
956 "Screen %d work area is formally resized to: %dx%d x %dx%d\n",
957 iHostScreenIndex, availableGeometry.x(), availableGeometry.y(),
958 availableGeometry.width(), availableGeometry.height()));
[63040]959
[100064]960#if defined(VBOX_WS_NIX) && !defined(VBOX_GUI_WITH_CUSTOMIZATIONS1)
[64437]961 /* Update host-screen available-geometry: */
962 updateHostScreenAvailableGeometry(iHostScreenIndex);
[100064]963#endif /* VBOX_WS_NIX && !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
[64437]964
[63040]965 /* Notify listeners: */
966 emit sigHostScreenWorkAreaResized(iHostScreenIndex);
967}
968
[100064]969#if defined(VBOX_WS_NIX) && !defined(VBOX_GUI_WITH_CUSTOMIZATIONS1)
[62988]970void UIDesktopWidgetWatchdog::sltHandleHostScreenAvailableGeometryCalculated(int iHostScreenIndex, QRect availableGeometry)
971{
[64621]972 LogRel(("GUI: UIDesktopWidgetWatchdog::sltHandleHostScreenAvailableGeometryCalculated: "
973 "Screen %d work area is actually resized to: %dx%d x %dx%d\n",
974 iHostScreenIndex, availableGeometry.x(), availableGeometry.y(),
975 availableGeometry.width(), availableGeometry.height()));
[62988]976
977 /* Apply received data: */
[63328]978 const bool fSendSignal = m_availableGeometryData.value(iHostScreenIndex).isValid();
[62988]979 m_availableGeometryData[iHostScreenIndex] = availableGeometry;
980 /* Forget finished worker: */
981 AssertPtrReturnVoid(m_availableGeometryWorkers.value(iHostScreenIndex));
982 m_availableGeometryWorkers.value(iHostScreenIndex)->disconnect();
983 m_availableGeometryWorkers.value(iHostScreenIndex)->deleteLater();
984 m_availableGeometryWorkers[iHostScreenIndex] = 0;
[63040]985
986 /* Notify listeners: */
[63328]987 if (fSendSignal)
988 emit sigHostScreenWorkAreaRecalculated(iHostScreenIndex);
[62988]989}
[100064]990#endif /* VBOX_WS_NIX && !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
[62988]991
992void UIDesktopWidgetWatchdog::prepare()
993{
994 /* Prepare connections: */
[68190]995 connect(qApp, &QGuiApplication::screenAdded,
996 this, &UIDesktopWidgetWatchdog::sltHostScreenAdded);
997 connect(qApp, &QGuiApplication::screenRemoved,
998 this, &UIDesktopWidgetWatchdog::sltHostScreenRemoved);
[64446]999 foreach (QScreen *pHostScreen, qApp->screens())
1000 {
[68190]1001 connect(pHostScreen, &QScreen::geometryChanged,
1002 this, &UIDesktopWidgetWatchdog::sltHandleHostScreenResized);
1003 connect(pHostScreen, &QScreen::availableGeometryChanged,
1004 this, &UIDesktopWidgetWatchdog::sltHandleHostScreenWorkAreaResized);
[64446]1005 }
[62988]1006
[100064]1007#if defined(VBOX_WS_NIX) && !defined(VBOX_GUI_WITH_CUSTOMIZATIONS1)
[98999]1008 /* Load Synthetic Test policy: */
[103321]1009 const QString strSynthTestPolicy =
1010 QString::fromLocal8Bit(qgetenv(s_strVBoxDesktopWatchdogPolicySynthTest.toLatin1().constData()));
[98999]1011 m_enmSynthTestPolicy = gpConverter->fromInternalString<DesktopWatchdogPolicy_SynthTest>(strSynthTestPolicy);
1012
[62988]1013 /* Update host-screen configuration: */
1014 updateHostScreenConfiguration();
[100064]1015#endif /* VBOX_WS_NIX && !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
[62988]1016}
1017
1018void UIDesktopWidgetWatchdog::cleanup()
1019{
1020 /* Cleanup connections: */
[68190]1021 disconnect(qApp, &QGuiApplication::screenAdded,
1022 this, &UIDesktopWidgetWatchdog::sltHostScreenAdded);
1023 disconnect(qApp, &QGuiApplication::screenRemoved,
1024 this, &UIDesktopWidgetWatchdog::sltHostScreenRemoved);
[64446]1025 foreach (QScreen *pHostScreen, qApp->screens())
1026 {
[68190]1027 disconnect(pHostScreen, &QScreen::geometryChanged,
1028 this, &UIDesktopWidgetWatchdog::sltHandleHostScreenResized);
1029 disconnect(pHostScreen, &QScreen::availableGeometryChanged,
1030 this, &UIDesktopWidgetWatchdog::sltHandleHostScreenWorkAreaResized);
[64446]1031 }
[62988]1032
[100064]1033#if defined(VBOX_WS_NIX) && !defined(VBOX_GUI_WITH_CUSTOMIZATIONS1)
[62988]1034 /* Cleanup existing workers finally: */
1035 cleanupExistingWorkers();
[100064]1036#endif /* VBOX_WS_NIX && !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
[62988]1037}
1038
[91109]1039/* static */
[97704]1040int UIDesktopWidgetWatchdog::screenToIndex(QScreen *pScreen)
1041{
1042 if (pScreen)
1043 {
1044 unsigned iScreen = 0;
1045 foreach (QScreen *pCurScreen, QGuiApplication::screens())
1046 {
1047 if ( pCurScreen == pScreen
1048 || ( pCurScreen->geometry() == pScreen->geometry()
1049 && pCurScreen->serialNumber() == pScreen->serialNumber()))
1050 return iScreen;
1051 ++iScreen;
1052 }
1053 }
1054 return -1;
1055}
1056
1057/* static */
[91109]1058QRegion UIDesktopWidgetWatchdog::flip(const QRegion &region)
1059{
1060 QRegion result;
[94026]1061 for (QRegion::const_iterator it = region.begin(); it != region.end(); ++it)
1062 result += QRect(it->y(), it->x(),
1063 it->height(), it->width());
[91109]1064 return result;
1065}
1066
[100064]1067#if defined(VBOX_WS_NIX) && !defined(VBOX_GUI_WITH_CUSTOMIZATIONS1)
[98999]1068bool UIDesktopWidgetWatchdog::isSynchTestRestricted() const
1069{
1070 return m_enmSynthTestPolicy == DesktopWatchdogPolicy_SynthTest_Disabled
1071 || ( m_enmSynthTestPolicy == DesktopWatchdogPolicy_SynthTest_ManagerOnly
[103551]1072 && uiCommon().uiType() == UIType_RuntimeUI)
[98999]1073 || ( m_enmSynthTestPolicy == DesktopWatchdogPolicy_SynthTest_MachineOnly
[103551]1074 && uiCommon().uiType() == UIType_ManagerUI);
[98999]1075}
1076
[62988]1077void UIDesktopWidgetWatchdog::updateHostScreenConfiguration(int cHostScreenCount /* = -1 */)
1078{
[98999]1079 /* Check the policy: */
1080 if (isSynchTestRestricted())
1081 return;
1082
[57480]1083 /* Acquire new host-screen count: */
[62998]1084 if (cHostScreenCount == -1)
1085 cHostScreenCount = screenCount();
[57480]1086
[60631]1087 /* Cleanup existing workers first: */
[62987]1088 cleanupExistingWorkers();
[60631]1089
1090 /* Resize workers vectors to new host-screen count: */
[62998]1091 m_availableGeometryWorkers.resize(cHostScreenCount);
1092 m_availableGeometryData.resize(cHostScreenCount);
[57480]1093
[62989]1094 /* Update host-screen available-geometry for each particular host-screen: */
[62998]1095 for (int iHostScreenIndex = 0; iHostScreenIndex < cHostScreenCount; ++iHostScreenIndex)
[62989]1096 updateHostScreenAvailableGeometry(iHostScreenIndex);
[57480]1097}
1098
[62989]1099void UIDesktopWidgetWatchdog::updateHostScreenAvailableGeometry(int iHostScreenIndex)
[57480]1100{
[98999]1101 /* Check the policy: */
1102 if (isSynchTestRestricted())
1103 return;
1104
[57480]1105 /* Make sure index is valid: */
[62998]1106 if (iHostScreenIndex < 0 || iHostScreenIndex >= screenCount())
[94015]1107 {
[97707]1108 iHostScreenIndex = UIDesktopWidgetWatchdog::primaryScreenNumber();
[94015]1109 AssertReturnVoid(iHostScreenIndex >= 0 && iHostScreenIndex < screenCount());
1110 }
[57480]1111
1112 /* Create invisible frame-less window worker: */
1113 UIInvisibleWindow *pWorker = new UIInvisibleWindow(iHostScreenIndex);
1114 AssertPtrReturnVoid(pWorker);
1115 {
[62986]1116 /* Remember created worker (replace if necessary): */
[57510]1117 if (m_availableGeometryWorkers.value(iHostScreenIndex))
1118 delete m_availableGeometryWorkers.value(iHostScreenIndex);
1119 m_availableGeometryWorkers[iHostScreenIndex] = pWorker;
[62986]1120
[57480]1121 /* Get the screen-geometry: */
1122 const QRect hostScreenGeometry = screenGeometry(iHostScreenIndex);
[62986]1123
[57480]1124 /* Connect worker listener: */
[68190]1125 connect(pWorker, &UIInvisibleWindow::sigHostScreenAvailableGeometryCalculated,
1126 this, &UIDesktopWidgetWatchdog::sltHandleHostScreenAvailableGeometryCalculated);
[62986]1127
[57480]1128 /* Place worker to corresponding host-screen: */
[64627]1129 pWorker->move(hostScreenGeometry.center());
[57480]1130 /* And finally, maximize it: */
1131 pWorker->showMaximized();
1132 }
1133}
1134
[62987]1135void UIDesktopWidgetWatchdog::cleanupExistingWorkers()
1136{
[98999]1137 /* Check the policy: */
1138 if (isSynchTestRestricted())
1139 return;
1140
[62987]1141 /* Destroy existing workers: */
[57510]1142 qDeleteAll(m_availableGeometryWorkers);
[63328]1143 /* And clear their vector: */
[57510]1144 m_availableGeometryWorkers.clear();
1145}
1146
[63003]1147# include "UIDesktopWidgetWatchdog.moc"
[100064]1148#endif /* VBOX_WS_NIX && !VBOX_GUI_WITH_CUSTOMIZATIONS1 */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle
ContactPrivacy/Do Not Sell My InfoTerms of Use