VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/runtime/scale/UIMachineWindowScale.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: 9.8 KB
Line 
1/* $Id: UIMachineWindowScale.cpp 103793 2024-03-11 19:17:31Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIMachineWindowScale 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 <QMenu>
30#include <QTimerEvent>
31#include <QSpacerItem>
32#include <QResizeEvent>
33#ifdef VBOX_WS_NIX
34# include <QTimer>
35#endif
36
37/* GUI includes: */
38#include "UICommon.h"
39#include "UIDesktopWidgetWatchdog.h"
40#include "UIExtraDataManager.h"
41#include "UILoggingDefs.h"
42#include "UIMachine.h"
43#include "UIMachineLogic.h"
44#include "UIMachineWindowScale.h"
45#include "UIMachineView.h"
46#include "UINotificationCenter.h"
47#ifdef VBOX_WS_MAC
48# include "VBoxUtils.h"
49# include "UIImageTools.h"
50# include "UICocoaApplication.h"
51# include "UIVersion.h"
52#endif
53
54
55UIMachineWindowScale::UIMachineWindowScale(UIMachineLogic *pMachineLogic, ulong uScreenId)
56 : UIMachineWindow(pMachineLogic, uScreenId)
57 , m_iGeometrySaveTimerId(-1)
58{
59}
60
61void UIMachineWindowScale::prepareMainLayout()
62{
63 /* Call to base-class: */
64 UIMachineWindow::prepareMainLayout();
65
66 /* Strict spacers to hide them, they are not necessary for scale-mode: */
67 m_pTopSpacer->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed);
68 m_pBottomSpacer->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed);
69 m_pLeftSpacer->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed);
70 m_pRightSpacer->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed);
71}
72
73void UIMachineWindowScale::prepareNotificationCenter()
74{
75 if (gpNotificationCenter && (m_uScreenId == 0))
76 gpNotificationCenter->setParent(centralWidget());
77}
78
79#ifdef VBOX_WS_MAC
80void UIMachineWindowScale::prepareVisualState()
81{
82 /* Call to base-class: */
83 UIMachineWindow::prepareVisualState();
84
85 /* Beta label? */
86 if (UIVersionInfo::showBetaLabel())
87 {
88 QPixmap betaLabel = ::betaLabel(QSize(74, darwinWindowTitleHeight(this) - 1));
89 ::darwinLabelWindow(this, &betaLabel);
90 }
91
92 /* Enable fullscreen support for every screen which requires it: */
93 if (darwinScreensHaveSeparateSpaces() || m_uScreenId == 0)
94 darwinEnableFullscreenSupport(this);
95 /* Register 'Zoom' button to use our full-screen: */
96 UICocoaApplication::instance()->registerCallbackForStandardWindowButton(this, StandardWindowButtonType_Zoom,
97 UIMachineWindow::handleStandardWindowButtonCallback);
98}
99#endif /* VBOX_WS_MAC */
100
101void UIMachineWindowScale::loadSettings()
102{
103 /* Call to base-class: */
104 UIMachineWindow::loadSettings();
105
106 /* Load extra-data settings: */
107 {
108 /* Load extra-data: */
109 QRect geo = gEDataManager->machineWindowGeometry(machineLogic()->visualStateType(),
110 m_uScreenId, uiCommon().managedVMUuid());
111
112 /* If we do have proper geometry: */
113 if (!geo.isNull())
114 {
115 /* Restore window geometry: */
116 m_geometry = geo;
117 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_geometry);
118
119 /* Maximize (if necessary): */
120 if (gEDataManager->machineWindowShouldBeMaximized(machineLogic()->visualStateType(),
121 m_uScreenId, uiCommon().managedVMUuid()))
122 setWindowState(windowState() | Qt::WindowMaximized);
123 }
124 /* If we do NOT have proper geometry: */
125 else
126 {
127 /* Get available geometry, for screen with (x,y) coords if possible: */
128 QRect availableGeo = !geo.isNull() ? gpDesktop->availableGeometry(QPoint(geo.x(), geo.y())) :
129 gpDesktop->availableGeometry(this);
130
131 /* Resize to default size: */
132 resize(640, 480);
133 /* Move newly created window to the screen-center: */
134 m_geometry = geometry();
135 m_geometry.moveCenter(availableGeo.center());
136 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_geometry);
137 }
138
139 /* Normalize to the optimal size: */
140#ifdef VBOX_WS_NIX
141 QTimer::singleShot(0, this, SLOT(sltNormalizeGeometry()));
142#else /* !VBOX_WS_NIX */
143 normalizeGeometry(true /* adjust position */, true /* resize to fit guest display. ignored in scaled case */);
144#endif /* !VBOX_WS_NIX */
145 }
146}
147
148#ifdef VBOX_WS_MAC
149void UIMachineWindowScale::cleanupVisualState()
150{
151 /* Unregister 'Zoom' button from using our full-screen: */
152 UICocoaApplication::instance()->unregisterCallbackForStandardWindowButton(this, StandardWindowButtonType_Zoom);
153}
154#endif /* VBOX_WS_MAC */
155
156void UIMachineWindowScale::cleanupNotificationCenter()
157{
158 if (gpNotificationCenter && (gpNotificationCenter->parent() == centralWidget()))
159 gpNotificationCenter->setParent(0);
160}
161
162void UIMachineWindowScale::showInNecessaryMode()
163{
164 /* Make sure this window should be shown at all: */
165 if (!uimachine()->isScreenVisible(m_uScreenId))
166 return hide();
167
168 /* Make sure this window is not minimized: */
169 if (isMinimized())
170 return;
171
172 /* Show in normal mode: */
173 show();
174
175 /* Make sure machine-view have focus: */
176 m_pMachineView->setFocus();
177}
178
179void UIMachineWindowScale::restoreCachedGeometry()
180{
181 /* Restore the geometry cached by the window: */
182 resize(m_geometry.size());
183 move(m_geometry.topLeft());
184
185 /* Adjust machine-view accordingly: */
186 adjustMachineViewSize();
187}
188
189void UIMachineWindowScale::normalizeGeometry(bool fAdjustPosition, bool fResizeToGuestDisplay)
190{
191 Q_UNUSED(fResizeToGuestDisplay);
192 /* Skip if maximized: */
193 if (isMaximized())
194 return;
195
196 /* Calculate client window offsets: */
197 QRect frGeo = frameGeometry();
198 const QRect geo = geometry();
199 const int dl = geo.left() - frGeo.left();
200 const int dt = geo.top() - frGeo.top();
201 const int dr = frGeo.right() - geo.right();
202 const int db = frGeo.bottom() - geo.bottom();
203
204 /* Adjust position if necessary: */
205 if (fAdjustPosition)
206 frGeo = UIDesktopWidgetWatchdog::normalizeGeometry(frGeo, gpDesktop->overallAvailableRegion());
207
208 /* Finally, set the frame geometry: */
209 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, frGeo.left() + dl, frGeo.top() + dt,
210 frGeo.width() - dl - dr, frGeo.height() - dt - db);
211}
212
213bool UIMachineWindowScale::event(QEvent *pEvent)
214{
215 switch (pEvent->type())
216 {
217 case QEvent::Resize:
218 {
219#ifdef VBOX_WS_NIX
220 /* Prevent handling if fake screen detected: */
221 if (UIDesktopWidgetWatchdog::isFakeScreenDetected())
222 break;
223#endif /* VBOX_WS_NIX */
224
225 QResizeEvent *pResizeEvent = static_cast<QResizeEvent*>(pEvent);
226 if (!isMaximizedChecked())
227 {
228 m_geometry.setSize(pResizeEvent->size());
229#ifdef VBOX_WITH_DEBUGGER_GUI
230 /* Update debugger window position: */
231 updateDbgWindows();
232#endif /* VBOX_WITH_DEBUGGER_GUI */
233 }
234
235 /* Restart geometry save timer: */
236 if (m_iGeometrySaveTimerId != -1)
237 killTimer(m_iGeometrySaveTimerId);
238 m_iGeometrySaveTimerId = startTimer(300);
239 break;
240 }
241 case QEvent::Move:
242 {
243#ifdef VBOX_WS_NIX
244 /* Prevent handling if fake screen detected: */
245 if (UIDesktopWidgetWatchdog::isFakeScreenDetected())
246 break;
247#endif /* VBOX_WS_NIX */
248
249 if (!isMaximizedChecked())
250 {
251 m_geometry.moveTo(geometry().x(), geometry().y());
252#ifdef VBOX_WITH_DEBUGGER_GUI
253 /* Update debugger window position: */
254 updateDbgWindows();
255#endif /* VBOX_WITH_DEBUGGER_GUI */
256 }
257
258 /* Restart geometry save timer: */
259 if (m_iGeometrySaveTimerId != -1)
260 killTimer(m_iGeometrySaveTimerId);
261 m_iGeometrySaveTimerId = startTimer(300);
262 break;
263 }
264 /* Handle timer event started above: */
265 case QEvent::Timer:
266 {
267 QTimerEvent *pTimerEvent = static_cast<QTimerEvent*>(pEvent);
268 if (pTimerEvent->timerId() == m_iGeometrySaveTimerId)
269 {
270 killTimer(m_iGeometrySaveTimerId);
271 m_iGeometrySaveTimerId = -1;
272 LogRel2(("GUI: UIMachineWindowScale: Saving geometry as: Origin=%dx%d, Size=%dx%d\n",
273 m_geometry.x(), m_geometry.y(), m_geometry.width(), m_geometry.height()));
274 gEDataManager->setMachineWindowGeometry(machineLogic()->visualStateType(),
275 m_uScreenId, m_geometry,
276 isMaximizedChecked(), uiCommon().managedVMUuid());
277 }
278 break;
279 }
280 default:
281 break;
282 }
283 return UIMachineWindow::event(pEvent);
284}
285
286bool UIMachineWindowScale::isMaximizedChecked()
287{
288#ifdef VBOX_WS_MAC
289 /* On the Mac the WindowStateChange signal doesn't seems to be delivered
290 * when the user get out of the maximized state. So check this ourself. */
291 return ::darwinIsWindowMaximized(this);
292#else /* VBOX_WS_MAC */
293 return isMaximized();
294#endif /* !VBOX_WS_MAC */
295}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use