VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp

Last change on this file was 103793, checked in by vboxsync, 3 months ago

FE/Qt: UICommon: Move versioning related functionality to UIVersion / UIVersionInfo; Rework user cases accordingly.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.9 KB
Line 
1/* $Id: UIMachineWindowNormal.cpp 103793 2024-03-11 19:17:31Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIMachineWindowNormal class implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2023 Oracle and/or its affiliates.
8 *
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
26 */
27
28/* Qt includes: */
29#include <QMenuBar>
30#include <QTimerEvent>
31#include <QContextMenuEvent>
32#include <QResizeEvent>
33#include <QScrollBar>
34#ifdef VBOX_WS_NIX
35# include <QTimer>
36#endif
37
38/* GUI includes: */
39#include "UICommon.h"
40#include "UIDesktopWidgetWatchdog.h"
41#include "UIMachineWindowNormal.h"
42#include "UIActionPoolRuntime.h"
43#include "UIExtraDataManager.h"
44#include "UIIndicatorsPool.h"
45#include "UIKeyboardHandler.h"
46#include "UILoggingDefs.h"
47#include "UIMachine.h"
48#include "UIMouseHandler.h"
49#include "UIMachineLogic.h"
50#include "UIMachineView.h"
51#include "UINotificationCenter.h"
52#include "UIIconPool.h"
53#include "QIStatusBar.h"
54#include "QIStatusBarIndicator.h"
55#ifndef VBOX_WS_MAC
56# include "UIMenuBar.h"
57#else /* VBOX_WS_MAC */
58# include "VBoxUtils.h"
59# include "UIImageTools.h"
60# include "UICocoaApplication.h"
61# include "UIVersion.h"
62#endif /* VBOX_WS_MAC */
63
64/* COM includes: */
65#include "CConsole.h"
66#include "CMediumAttachment.h"
67#include "CUSBController.h"
68#include "CUSBDeviceFilters.h"
69
70
71UIMachineWindowNormal::UIMachineWindowNormal(UIMachineLogic *pMachineLogic, ulong uScreenId)
72 : UIMachineWindow(pMachineLogic, uScreenId)
73 , m_pIndicatorsPool(0)
74 , m_iGeometrySaveTimerId(-1)
75{
76}
77
78void UIMachineWindowNormal::sltMachineStateChanged()
79{
80 /* Call to base-class: */
81 UIMachineWindow::sltMachineStateChanged();
82
83 /* Update indicator-pool and virtualization stuff: */
84 updateAppearanceOf(UIVisualElement_IndicatorPool);
85}
86
87#ifndef RT_OS_DARWIN
88void UIMachineWindowNormal::sltHandleMenuBarConfigurationChange(const QUuid &uMachineID)
89{
90 /* Skip unrelated machine IDs: */
91 if (uiCommon().managedVMUuid() != uMachineID)
92 return;
93
94 /* Check whether menu-bar is enabled: */
95 const bool fEnabled = gEDataManager->menuBarEnabled(uiCommon().managedVMUuid());
96 /* Update settings action 'enable' state: */
97 QAction *pActionMenuBarSettings = actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_S_Settings);
98 pActionMenuBarSettings->setEnabled(fEnabled);
99 /* Update switch action 'checked' state: */
100 QAction *pActionMenuBarSwitch = actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_T_Visibility);
101 pActionMenuBarSwitch->blockSignals(true);
102 pActionMenuBarSwitch->setChecked(fEnabled);
103 pActionMenuBarSwitch->blockSignals(false);
104
105 /* Update menu-bar visibility: */
106 menuBar()->setVisible(pActionMenuBarSwitch->isChecked());
107 /* Update menu-bar: */
108 updateMenu();
109
110 /* Normalize geometry without moving: */
111 normalizeGeometry(false /* adjust position */, shouldResizeToGuestDisplay());
112}
113
114void UIMachineWindowNormal::sltHandleMenuBarContextMenuRequest(const QPoint &position)
115{
116 /* Raise action's context-menu: */
117 if (gEDataManager->menuBarContextMenuEnabled(uiCommon().managedVMUuid()))
118 actionPool()->action(UIActionIndexRT_M_View_M_MenuBar)->menu()->exec(menuBar()->mapToGlobal(position));
119}
120#endif /* !RT_OS_DARWIN */
121
122void UIMachineWindowNormal::sltHandleStatusBarConfigurationChange(const QUuid &uMachineID)
123{
124 /* Skip unrelated machine IDs: */
125 if (uiCommon().managedVMUuid() != uMachineID)
126 return;
127
128 /* Check whether status-bar is enabled: */
129 const bool fEnabled = gEDataManager->statusBarEnabled(uiCommon().managedVMUuid());
130 /* Update settings action 'enable' state: */
131 QAction *pActionStatusBarSettings = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_S_Settings);
132 pActionStatusBarSettings->setEnabled(fEnabled);
133 /* Update switch action 'checked' state: */
134 QAction *pActionStatusBarSwitch = actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_T_Visibility);
135 pActionStatusBarSwitch->blockSignals(true);
136 pActionStatusBarSwitch->setChecked(fEnabled);
137 pActionStatusBarSwitch->blockSignals(false);
138
139 /* Update status-bar visibility: */
140 statusBar()->setVisible(pActionStatusBarSwitch->isChecked());
141 /* Update status-bar indicators-pool: */
142 if (m_pIndicatorsPool)
143 m_pIndicatorsPool->setAutoUpdateIndicatorStates(statusBar()->isVisible() && uimachine()->isRunning());
144
145 /* Normalize geometry without moving: */
146 normalizeGeometry(false /* adjust position */, shouldResizeToGuestDisplay());
147}
148
149void UIMachineWindowNormal::sltHandleStatusBarContextMenuRequest(const QPoint &position)
150{
151 /* Raise action's context-menu: */
152 if (gEDataManager->statusBarContextMenuEnabled(uiCommon().managedVMUuid()))
153 actionPool()->action(UIActionIndexRT_M_View_M_StatusBar)->menu()->exec(statusBar()->mapToGlobal(position));
154}
155
156void UIMachineWindowNormal::sltHandleIndicatorContextMenuRequest(IndicatorType enmIndicatorType, const QPoint &indicatorPosition)
157{
158 /* Sanity check, this slot should be called if m_pIndicatorsPool present anyway: */
159 AssertPtrReturnVoid(m_pIndicatorsPool);
160 /* Determine action depending on indicator-type: */
161 UIAction *pAction = 0;
162 switch (enmIndicatorType)
163 {
164 case IndicatorType_HardDisks: pAction = actionPool()->action(UIActionIndexRT_M_Devices_M_HardDrives); break;
165 case IndicatorType_OpticalDisks: pAction = actionPool()->action(UIActionIndexRT_M_Devices_M_OpticalDevices); break;
166 case IndicatorType_FloppyDisks: pAction = actionPool()->action(UIActionIndexRT_M_Devices_M_FloppyDevices); break;
167 case IndicatorType_Audio: pAction = actionPool()->action(UIActionIndexRT_M_Devices_M_Audio); break;
168 case IndicatorType_Network: pAction = actionPool()->action(UIActionIndexRT_M_Devices_M_Network); break;
169 case IndicatorType_USB: pAction = actionPool()->action(UIActionIndexRT_M_Devices_M_USBDevices); break;
170 case IndicatorType_SharedFolders: pAction = actionPool()->action(UIActionIndexRT_M_Devices_M_SharedFolders); break;
171 case IndicatorType_Display: pAction = actionPool()->action(UIActionIndexRT_M_ViewPopup); break;
172 case IndicatorType_Recording: pAction = actionPool()->action(UIActionIndexRT_M_View_M_Recording); break;
173 case IndicatorType_Mouse: pAction = actionPool()->action(UIActionIndexRT_M_Input_M_Mouse); break;
174 case IndicatorType_Keyboard: pAction = actionPool()->action(UIActionIndexRT_M_Input_M_Keyboard); break;
175 default: break;
176 }
177 /* Raise action's context-menu: */
178 if (pAction && pAction->isEnabled())
179 pAction->menu()->exec(m_pIndicatorsPool->mapIndicatorPositionToGlobal(enmIndicatorType, indicatorPosition));
180}
181
182#ifdef VBOX_WS_MAC
183void UIMachineWindowNormal::sltActionHovered(UIAction *pAction)
184{
185 /* Show the action message for a ten seconds: */
186 statusBar()->showMessage(pAction->statusTip(), 10000);
187}
188#endif /* VBOX_WS_MAC */
189
190#ifndef VBOX_WS_MAC
191void UIMachineWindowNormal::prepareMenu()
192{
193 /* Create menu-bar: */
194 setMenuBar(new UIMenuBar);
195 AssertPtrReturnVoid(menuBar());
196 {
197 /* Configure menu-bar: */
198 menuBar()->setContextMenuPolicy(Qt::CustomContextMenu);
199 connect(menuBar(), &UIMenuBar::customContextMenuRequested,
200 this, &UIMachineWindowNormal::sltHandleMenuBarContextMenuRequest);
201 connect(gEDataManager, &UIExtraDataManager::sigMenuBarConfigurationChange,
202 this, &UIMachineWindowNormal::sltHandleMenuBarConfigurationChange);
203 /* Update menu-bar: */
204 updateMenu();
205 }
206}
207#endif /* !VBOX_WS_MAC */
208
209void UIMachineWindowNormal::prepareStatusBar()
210{
211 /* Call to base-class: */
212 UIMachineWindow::prepareStatusBar();
213
214 /* Create status-bar: */
215 setStatusBar(new QIStatusBar);
216 AssertPtrReturnVoid(statusBar());
217 {
218 /* Configure status-bar: */
219 statusBar()->setContextMenuPolicy(Qt::CustomContextMenu);
220 connect(statusBar(), &QIStatusBar::customContextMenuRequested,
221 this, &UIMachineWindowNormal::sltHandleStatusBarContextMenuRequest);
222 /* Create indicator-pool: */
223 m_pIndicatorsPool = new UIIndicatorsPool(machineLogic()->uimachine());
224 AssertPtrReturnVoid(m_pIndicatorsPool);
225 {
226 /* Configure indicator-pool: */
227 connect(m_pIndicatorsPool, &UIIndicatorsPool::sigContextMenuRequest,
228 this, &UIMachineWindowNormal::sltHandleIndicatorContextMenuRequest);
229 /* Add indicator-pool into status-bar: */
230 statusBar()->addPermanentWidget(m_pIndicatorsPool, 0);
231 }
232 /* Post-configure status-bar: */
233 connect(gEDataManager, &UIExtraDataManager::sigStatusBarConfigurationChange,
234 this, &UIMachineWindowNormal::sltHandleStatusBarConfigurationChange);
235#ifdef VBOX_WS_MAC
236 /* Make sure the status-bar is aware of action hovering: */
237 connect(actionPool(), &UIActionPool::sigActionHovered,
238 this, &UIMachineWindowNormal::sltActionHovered);
239#endif /* VBOX_WS_MAC */
240 }
241
242#ifdef VBOX_WS_MAC
243 /* For the status-bar on Cocoa: */
244 setUnifiedTitleAndToolBarOnMac(true);
245#endif /* VBOX_WS_MAC */
246}
247
248void UIMachineWindowNormal::prepareNotificationCenter()
249{
250 if (gpNotificationCenter && (m_uScreenId == 0))
251 gpNotificationCenter->setParent(centralWidget());
252}
253
254void UIMachineWindowNormal::prepareVisualState()
255{
256 /* Call to base-class: */
257 UIMachineWindow::prepareVisualState();
258
259#ifdef VBOX_GUI_WITH_CUSTOMIZATIONS1
260 /* Customer request: The background has to go black: */
261 QPalette palette(centralWidget()->palette());
262 palette.setColor(centralWidget()->backgroundRole(), Qt::black);
263 centralWidget()->setPalette(palette);
264 centralWidget()->setAutoFillBackground(true);
265 setAutoFillBackground(true);
266#endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
267
268#ifdef VBOX_WS_MAC
269 /* Beta label? */
270 if (UIVersionInfo::showBetaLabel())
271 {
272 QPixmap betaLabel = ::betaLabel(QSize(74, darwinWindowTitleHeight(this) - 1));
273 ::darwinLabelWindow(this, &betaLabel);
274 }
275
276 /* Enable fullscreen support for every screen which requires it: */
277 if (darwinScreensHaveSeparateSpaces() || m_uScreenId == 0)
278 darwinEnableFullscreenSupport(this);
279 /* Register 'Zoom' button to use our full-screen: */
280 UICocoaApplication::instance()->registerCallbackForStandardWindowButton(this, StandardWindowButtonType_Zoom,
281 UIMachineWindow::handleStandardWindowButtonCallback);
282#endif /* VBOX_WS_MAC */
283}
284
285void UIMachineWindowNormal::loadSettings()
286{
287 /* Call to base-class: */
288 UIMachineWindow::loadSettings();
289
290 /* Load GUI customizations: */
291 {
292#ifndef VBOX_WS_MAC
293 /* Update menu-bar visibility: */
294 menuBar()->setVisible(actionPool()->action(UIActionIndexRT_M_View_M_MenuBar_T_Visibility)->isChecked());
295#endif /* !VBOX_WS_MAC */
296 /* Update status-bar visibility: */
297 statusBar()->setVisible(actionPool()->action(UIActionIndexRT_M_View_M_StatusBar_T_Visibility)->isChecked());
298 if (m_pIndicatorsPool)
299 m_pIndicatorsPool->setAutoUpdateIndicatorStates(statusBar()->isVisible() && uimachine()->isRunning());
300 }
301
302#ifndef VBOX_GUI_WITH_CUSTOMIZATIONS1
303 /* Load window geometry: */
304 {
305 /* Load extra-data: */
306 QRect geo = gEDataManager->machineWindowGeometry(machineLogic()->visualStateType(),
307 m_uScreenId, uiCommon().managedVMUuid());
308
309 /* If we do have proper geometry: */
310 if (!geo.isNull())
311 {
312 /* Restore window geometry: */
313 m_geometry = geo;
314 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_geometry);
315
316 /* If actual machine-state is NOT saved => normalize window to the optimal-size: */
317 KMachineState enmActualState = KMachineState_Null;
318 uimachine()->acquireLiveMachineState(enmActualState);
319 if (enmActualState != KMachineState_Saved && enmActualState != KMachineState_AbortedSaved)
320 normalizeGeometry(false /* adjust position */, shouldResizeToGuestDisplay());
321
322 /* Maximize window (if necessary): */
323 if (gEDataManager->machineWindowShouldBeMaximized(machineLogic()->visualStateType(),
324 m_uScreenId, uiCommon().managedVMUuid()))
325 setWindowState(windowState() | Qt::WindowMaximized);
326 }
327 /* If we do NOT have proper geometry: */
328 else
329 {
330 /* Normalize window to the optimal size: */
331 normalizeGeometry(true /* adjust position */, shouldResizeToGuestDisplay());
332
333 /* Move it to the screen-center: */
334 m_geometry = geometry();
335 m_geometry.moveCenter(gpDesktop->availableGeometry(this).center());
336 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_geometry);
337 }
338
339 /* Normalize to the optimal size: */
340#ifdef VBOX_WS_NIX
341 QTimer::singleShot(0, this, SLOT(sltNormalizeGeometry()));
342#else /* !VBOX_WS_NIX */
343 normalizeGeometry(true /* adjust position */, shouldResizeToGuestDisplay());
344#endif /* !VBOX_WS_NIX */
345 }
346#endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
347}
348
349void UIMachineWindowNormal::cleanupVisualState()
350{
351#ifdef VBOX_WS_MAC
352 /* Unregister 'Zoom' button from using our full-screen: */
353 UICocoaApplication::instance()->unregisterCallbackForStandardWindowButton(this, StandardWindowButtonType_Zoom);
354#endif /* VBOX_WS_MAC */
355}
356
357void UIMachineWindowNormal::cleanupNotificationCenter()
358{
359 if (gpNotificationCenter && (gpNotificationCenter->parent() == centralWidget()))
360 gpNotificationCenter->setParent(0);
361}
362
363void UIMachineWindowNormal::cleanupStatusBar()
364{
365 delete m_pIndicatorsPool;
366 m_pIndicatorsPool = 0;
367}
368
369bool UIMachineWindowNormal::event(QEvent *pEvent)
370{
371 switch (pEvent->type())
372 {
373 case QEvent::Resize:
374 {
375#ifdef VBOX_WS_NIX
376 /* Prevent handling if fake screen detected: */
377 if (UIDesktopWidgetWatchdog::isFakeScreenDetected())
378 break;
379#endif /* VBOX_WS_NIX */
380
381 QResizeEvent *pResizeEvent = static_cast<QResizeEvent*>(pEvent);
382 if (!isMaximizedChecked())
383 {
384 m_geometry.setSize(pResizeEvent->size());
385#ifdef VBOX_WITH_DEBUGGER_GUI
386 /* Update debugger window position: */
387 updateDbgWindows();
388#endif /* VBOX_WITH_DEBUGGER_GUI */
389 }
390
391 /* Restart geometry save timer: */
392 if (m_iGeometrySaveTimerId != -1)
393 killTimer(m_iGeometrySaveTimerId);
394 m_iGeometrySaveTimerId = startTimer(300);
395
396 /* Let listeners know about geometry changes: */
397 emit sigGeometryChange(geometry());
398 break;
399 }
400 case QEvent::Move:
401 {
402#ifdef VBOX_WS_NIX
403 /* Prevent handling if fake screen detected: */
404 if (UIDesktopWidgetWatchdog::isFakeScreenDetected())
405 break;
406#endif /* VBOX_WS_NIX */
407
408 if (!isMaximizedChecked())
409 {
410 m_geometry.moveTo(geometry().x(), geometry().y());
411#ifdef VBOX_WITH_DEBUGGER_GUI
412 /* Update debugger window position: */
413 updateDbgWindows();
414#endif /* VBOX_WITH_DEBUGGER_GUI */
415 }
416
417 /* Restart geometry save timer: */
418 if (m_iGeometrySaveTimerId != -1)
419 killTimer(m_iGeometrySaveTimerId);
420 m_iGeometrySaveTimerId = startTimer(300);
421
422 /* Let listeners know about geometry changes: */
423 emit sigGeometryChange(geometry());
424 break;
425 }
426 case QEvent::WindowActivate:
427 {
428 /* Let listeners know about geometry changes: */
429 emit sigGeometryChange(geometry());
430 break;
431 }
432 /* Handle timer event started above: */
433 case QEvent::Timer:
434 {
435 QTimerEvent *pTimerEvent = static_cast<QTimerEvent*>(pEvent);
436 if (pTimerEvent->timerId() == m_iGeometrySaveTimerId)
437 {
438 killTimer(m_iGeometrySaveTimerId);
439 m_iGeometrySaveTimerId = -1;
440
441 /* HACK ALERT! Just ignore this if it arrives to late to be handled. I typically get
442 these when the COM shutdown on windows flushes pending queue events. The result
443 is typically a bunch of assertions, but sometimes a NULL pointer dereference for
444 variety. Going forward here will probably re-instantiate some global objects
445 which were already cleaned up, so generally a bad idea.
446
447 A sample assertion stack:
448 # Child-SP RetAddr Call Site
449 00 00000052`300fe370 00007fff`36ac2cc9 UICommon!CVirtualBox::GetExtraDataKeys+0x80 [E:\vbox\svn\trunk\out\win.amd64\debug\obj\UICommon\include\COMWrappers.cpp @ 3851]
450 01 00000052`300fe430 00007fff`36ac2bf8 UICommon!UIExtraDataManager::prepareGlobalExtraDataMap+0xb9 [E:\vbox\svn\trunk\src\VBox\Frontends\VirtualBox\src\extradata\UIExtraDataManager.cpp @ 4845]
451 02 00000052`300fe590 00007fff`36ab1896 UICommon!UIExtraDataManager::prepare+0x28 [E:\vbox\svn\trunk\src\VBox\Frontends\VirtualBox\src\extradata\UIExtraDataManager.cpp @ 4833]
452 03 00000052`300fe5c0 00007ff7`69db2897 UICommon!UIExtraDataManager::instance+0x66 [E:\vbox\svn\trunk\src\VBox\Frontends\VirtualBox\src\extradata\UIExtraDataManager.cpp @ 2011]
453 04 00000052`300fe610 00007fff`35274990 VirtualBoxVM!UIMachineWindowNormal::event+0x4b7 [E:\vbox\svn\trunk\src\VBox\Frontends\VirtualBox\src\runtime\normal\UIMachineWindowNormal.cpp @ 546]
454 05 00000052`300fe6e0 00007fff`35273a13 Qt5WidgetsVBox!QApplicationPrivate::notify_helper+0x110
455 06 00000052`300fe710 00007fff`3cc3240a Qt5WidgetsVBox!QApplication::notify+0x18b3
456 07 00000052`300fec50 00007fff`3cc7cd09 Qt5CoreVBox!QCoreApplication::notifyInternal2+0xba
457 08 00000052`300fecc0 00007fff`3cc7bf7a Qt5CoreVBox!QEventDispatcherWin32Private::sendTimerEvent+0xf9
458 09 00000052`300fed10 00007fff`7631e7e8 Qt5CoreVBox!QEventDispatcherWin32::processEvents+0xc4a
459 0a 00000052`300fee30 00007fff`7631e229 USER32!UserCallWinProcCheckWow+0x2f8
460 0b 00000052`300fefc0 00007fff`370c2075 USER32!DispatchMessageWorker+0x249
461 0c 00000052`300ff040 00007fff`370c20e5 UICommon!com::NativeEventQueue::dispatchMessageOnWindows+0x145 [E:\vbox\svn\trunk\src\VBox\Main\glue\NativeEventQueue.cpp @ 416]
462 0d 00000052`300ff090 00007fff`370c1b19 UICommon!com::processPendingEvents+0x55 [E:\vbox\svn\trunk\src\VBox\Main\glue\NativeEventQueue.cpp @ 435]
463 0e 00000052`300ff130 00007fff`370c1ebd UICommon!com::NativeEventQueue::processEventQueue+0x149 [E:\vbox\svn\trunk\src\VBox\Main\glue\NativeEventQueue.cpp @ 562]
464 0f 00000052`300ff1d0 00007fff`370bfa9a UICommon!com::NativeEventQueue::uninit+0x2d [E:\vbox\svn\trunk\src\VBox\Main\glue\NativeEventQueue.cpp @ 260]
465 10 00000052`300ff210 00007fff`36b098e4 UICommon!com::Shutdown+0x5a [E:\vbox\svn\trunk\src\VBox\Main\glue\initterm.cpp @ 746]
466 11 00000052`300ff250 00007fff`36b88c43 UICommon!COMBase::CleanupCOM+0x74 [E:\vbox\svn\trunk\src\VBox\Frontends\VirtualBox\src\globals\COMDefs.cpp @ 168]
467 12 00000052`300ff2c0 00007fff`36a700c8 UICommon!UICommon::cleanup+0x313 [E:\vbox\svn\trunk\src\VBox\Frontends\VirtualBox\src\globals\UICommon.cpp @ 849]
468 13 00000052`300ff340 00007fff`36a82ab1 UICommon!UICommon::sltCleanup+0x28 [E:\vbox\svn\trunk\src\VBox\Frontends\VirtualBox\src\globals\UICommon.h @ 580]
469 14 00000052`300ff370 00007fff`36a81a9c UICommon!QtPrivate::FunctorCall<QtPrivate::IndexesList<>,QtPrivate::List<>,void,void (__cdecl UIMessageCenter::*)(void)>::call+0x31 [E:\vbox\svn\trunk\tools\win.amd64\qt\v5.15.2-r349\include\QtCore\qobjectdefs_impl.h @ 152]
470 15 00000052`300ff3b0 00007fff`36a82e45 UICommon!QtPrivate::FunctionPointer<void (__cdecl UIMessageCenter::*)(void)>::call<QtPrivate::List<>,void>+0x3c [E:\vbox\svn\trunk\tools\win.amd64\qt\v5.15.2-r349\include\QtCore\qobjectdefs_impl.h @ 186]
471 16 00000052`300ff3e0 00007fff`3cc51689 UICommon!QtPrivate::QSlotObject<void (__cdecl UIMessageCenter::*)(void),QtPrivate::List<>,void>::impl+0x95 [E:\vbox\svn\trunk\tools\win.amd64\qt\v5.15.2-r349\include\QtCore\qobjectdefs_impl.h @ 419]
472 17 00000052`300ff430 00007fff`3cc31465 Qt5CoreVBox!QObject::qt_static_metacall+0x1409
473 18 00000052`300ff580 00007fff`3cc313ef Qt5CoreVBox!QCoreApplicationPrivate::execCleanup+0x55
474 19 00000052`300ff5c0 00007ff7`69ce3b7a Qt5CoreVBox!QCoreApplication::exec+0x16f
475 1a 00000052`300ff620 00007ff7`69ce4174 VirtualBoxVM!TrustedMain+0x47a [E:\vbox\svn\trunk\src\VBox\Frontends\VirtualBox\src\main.cpp @ 570]
476 1b 00000052`300ff8b0 00007ff7`69e08af8 VirtualBoxVM!main+0x4a4 [E:\vbox\svn\trunk\src\VBox\Frontends\VirtualBox\src\main.cpp @ 739]
477 1c (Inline Function) --------`-------- VirtualBoxVM!invoke_main+0x22 [d:\A01\_work\6\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 78]
478 1d 00000052`300ffa00 00007fff`75107034 VirtualBoxVM!__scrt_common_main_seh+0x10c [d:\A01\_work\6\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288]
479 1e 00000052`300ffa40 00007fff`76ae2651 KERNEL32!BaseThreadInitThunk+0x14
480 1f 00000052`300ffa70 00000000`00000000 ntdll!RtlUserThreadStart+0x21 */
481 if (!UICommon::instance()->isCleaningUp())
482 {
483 LogRel2(("GUI: UIMachineWindowNormal: Saving geometry as: Origin=%dx%d, Size=%dx%d\n",
484 m_geometry.x(), m_geometry.y(), m_geometry.width(), m_geometry.height()));
485 gEDataManager->setMachineWindowGeometry(machineLogic()->visualStateType(),
486 m_uScreenId, m_geometry,
487 isMaximizedChecked(), uiCommon().managedVMUuid());
488 }
489 else
490 LogRel2(("GUI: UIMachineWindowNormal: Ignoring geometry save timer arriving during cleanup\n"));
491 }
492 break;
493 }
494 default:
495 break;
496 }
497 return UIMachineWindow::event(pEvent);
498}
499
500void UIMachineWindowNormal::showInNecessaryMode()
501{
502 /* Make sure this window should be shown at all: */
503 if (!uimachine()->isScreenVisible(m_uScreenId))
504 return hide();
505
506 /* Make sure this window is not minimized: */
507 if (isMinimized())
508 return;
509
510 /* Show in normal mode: */
511 show();
512
513 /* Normalize machine-window geometry: */
514 normalizeGeometry(true /* adjust position */, shouldResizeToGuestDisplay());
515
516 /* Make sure machine-view have focus: */
517 m_pMachineView->setFocus();
518}
519
520void UIMachineWindowNormal::restoreCachedGeometry()
521{
522 /* Restore the geometry cached by the window: */
523 resize(m_geometry.size());
524 move(m_geometry.topLeft());
525
526 /* Adjust machine-view accordingly: */
527 adjustMachineViewSize();
528}
529
530void UIMachineWindowNormal::normalizeGeometry(bool fAdjustPosition, bool fResizeToGuestDisplay)
531{
532#ifndef VBOX_GUI_WITH_CUSTOMIZATIONS1
533 /* Skip if maximized: */
534 if (isMaximized())
535 return;
536
537 /* Calculate client window offsets: */
538 QRect frGeo = frameGeometry();
539 const QRect geo = geometry();
540 const int dl = geo.left() - frGeo.left();
541 const int dt = geo.top() - frGeo.top();
542 const int dr = frGeo.right() - geo.right();
543 const int db = frGeo.bottom() - geo.bottom();
544
545 /* Get the best size w/o scroll-bars: */
546 if (fResizeToGuestDisplay)
547 {
548 /* Get widget size-hint: */
549 QSize sh = sizeHint();
550
551 /* If guest-screen auto-resize is not enabled
552 * or guest-additions doesn't support graphics
553 * we should deduce widget's size-hint on visible scroll-bar's hint: */
554 if ( !machineView()->isGuestAutoresizeEnabled()
555 || !uimachine()->isGuestSupportsGraphics())
556 {
557 if (machineView()->verticalScrollBar()->isVisible())
558 sh -= QSize(machineView()->verticalScrollBar()->sizeHint().width(), 0);
559 if (machineView()->horizontalScrollBar()->isVisible())
560 sh -= QSize(0, machineView()->horizontalScrollBar()->sizeHint().height());
561 }
562
563 /* Resize the frame to fit the contents: */
564 sh -= size();
565 frGeo.setRight(frGeo.right() + sh.width());
566 frGeo.setBottom(frGeo.bottom() + sh.height());
567 }
568
569 /* Adjust size/position if necessary: */
570 QRect frGeoNew = fAdjustPosition
571 ? UIDesktopWidgetWatchdog::normalizeGeometry(frGeo, gpDesktop->overallAvailableRegion())
572 : frGeo;
573
574 /* If guest-screen auto-resize is not enabled
575 * or the guest-additions doesn't support graphics
576 * we should take scroll-bars size-hints into account: */
577 if ( frGeoNew != frGeo
578 && ( !machineView()->isGuestAutoresizeEnabled()
579 || !uimachine()->isGuestSupportsGraphics()))
580 {
581 /* Determine whether we need additional space for one or both scroll-bars: */
582 QSize addition;
583 if (frGeoNew.height() < frGeo.height())
584 addition += QSize(machineView()->verticalScrollBar()->sizeHint().width() + 1, 0);
585 if (frGeoNew.width() < frGeo.width())
586 addition += QSize(0, machineView()->horizontalScrollBar()->sizeHint().height() + 1);
587
588 /* Resize the frame to fit the contents: */
589 frGeoNew.setRight(frGeoNew.right() + addition.width());
590 frGeoNew.setBottom(frGeoNew.bottom() + addition.height());
591
592 /* Adjust size/position again: */
593 frGeoNew = UIDesktopWidgetWatchdog::normalizeGeometry(frGeoNew, gpDesktop->overallAvailableRegion());
594 }
595
596 /* Finally, set the frame geometry: */
597 UIDesktopWidgetWatchdog::setTopLevelGeometry(this,
598 frGeoNew.left() + dl, frGeoNew.top() + dt,
599 frGeoNew.width() - dl - dr, frGeoNew.height() - dt - db);
600#else /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
601 /* Customer request: There should no be
602 * machine-window resize/move on machine-view resize: */
603 Q_UNUSED(fAdjustPosition);
604 Q_UNUSED(fResizeToGuestDisplay);
605#endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
606}
607
608void UIMachineWindowNormal::updateAppearanceOf(int iElement)
609{
610 /* Call to base-class: */
611 UIMachineWindow::updateAppearanceOf(iElement);
612
613 /* Set status-bar indicator-pool auto update timer: */
614 if ( m_pIndicatorsPool
615 && iElement & UIVisualElement_IndicatorPool)
616 m_pIndicatorsPool->setAutoUpdateIndicatorStates(statusBar()->isVisible() && uimachine()->isRunning());
617}
618
619#ifndef VBOX_WS_MAC
620void UIMachineWindowNormal::updateMenu()
621{
622 /* Rebuild menu-bar: */
623 menuBar()->clear();
624 foreach (QMenu *pMenu, actionPool()->menus())
625 menuBar()->addMenu(pMenu);
626}
627#endif /* !VBOX_WS_MAC */
628
629bool UIMachineWindowNormal::isMaximizedChecked()
630{
631#ifdef VBOX_WS_MAC
632 /* On the Mac the WindowStateChange signal doesn't seems to be delivered
633 * when the user get out of the maximized state. So check this ourself. */
634 return ::darwinIsWindowMaximized(this);
635#else /* VBOX_WS_MAC */
636 return isMaximized();
637#endif /* !VBOX_WS_MAC */
638}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use