VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.cpp@ 52891

Last change on this file since 52891 was 52891, checked in by vboxsync, 10 years ago

FE/Qt: X11: Runtime UI: Mini-toolbar: Rework it to be window again, fixing conflicts with Unity panels for full-screen and seamless modes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.1 KB
Line 
1/* $Id: UIMachineWindowFullscreen.cpp 52891 2014-09-29 16:52:38Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIMachineWindowFullscreen class implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifdef VBOX_WITH_PRECOMPILED_HEADERS
19# include <precomp.h>
20#else /* !VBOX_WITH_PRECOMPILED_HEADERS */
21
22/* Qt includes: */
23# include <QDesktopWidget>
24# include <QMenu>
25# include <QTimer>
26
27/* GUI includes: */
28# include "VBoxGlobal.h"
29# include "UIExtraDataManager.h"
30# include "UISession.h"
31# include "UIActionPoolRuntime.h"
32# include "UIMachineLogicFullscreen.h"
33# include "UIMachineWindowFullscreen.h"
34# include "UIMachineView.h"
35# include "UIFrameBuffer.h"
36# include "UIMachineDefs.h"
37# include "UIMiniToolBar.h"
38# ifdef Q_WS_MAC
39# include "VBoxUtils-darwin.h"
40# include "UICocoaApplication.h"
41# endif /* Q_WS_MAC */
42
43/* COM includes: */
44# include "CSnapshot.h"
45
46#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
47
48
49UIMachineWindowFullscreen::UIMachineWindowFullscreen(UIMachineLogic *pMachineLogic, ulong uScreenId)
50 : UIMachineWindow(pMachineLogic, uScreenId)
51 , m_pMiniToolBar(0)
52#ifdef Q_WS_MAC
53 , m_fIsInFullscreenTransition(false)
54#endif /* Q_WS_MAC */
55{
56}
57
58#ifdef Q_WS_MAC
59void UIMachineWindowFullscreen::handleNativeNotification(const QString &strNativeNotificationName)
60{
61 /* Make sure this method is only used for ML and next: */
62 AssertReturnVoid(vboxGlobal().osRelease() > MacOSXRelease_Lion);
63
64 /* Log all arrived notifications: */
65 LogRel(("UIMachineWindowFullscreen::handleNativeNotification: Notification '%s' received.\n",
66 strNativeNotificationName.toAscii().constData()));
67
68 /* Handle 'NSWindowWillEnterFullScreenNotification' notification: */
69 if (strNativeNotificationName == "NSWindowWillEnterFullScreenNotification")
70 {
71 LogRel(("UIMachineWindowFullscreen::handleNativeNotification: "
72 "Native fullscreen mode about to enter, notifying listener...\n"));
73 emit sigNotifyAboutNativeFullscreenWillEnter();
74 }
75 /* Handle 'NSWindowDidEnterFullScreenNotification' notification: */
76 else if (strNativeNotificationName == "NSWindowDidEnterFullScreenNotification")
77 {
78 /* Mark window transition complete: */
79 m_fIsInFullscreenTransition = false;
80 LogRel(("UIMachineWindowFullscreen::handleNativeNotification: "
81 "Native fullscreen mode entered, notifying listener...\n"));
82 emit sigNotifyAboutNativeFullscreenDidEnter();
83 }
84 /* Handle 'NSWindowWillExitFullScreenNotification' notification: */
85 else if (strNativeNotificationName == "NSWindowWillExitFullScreenNotification")
86 {
87 LogRel(("UIMachineWindowFullscreen::handleNativeNotification: "
88 "Native fullscreen mode about to exit, notifying listener...\n"));
89 emit sigNotifyAboutNativeFullscreenWillExit();
90 }
91 /* Handle 'NSWindowDidExitFullScreenNotification' notification: */
92 else if (strNativeNotificationName == "NSWindowDidExitFullScreenNotification")
93 {
94 /* Mark window transition complete: */
95 m_fIsInFullscreenTransition = false;
96 LogRel(("UIMachineWindowFullscreen::handleNativeNotification: "
97 "Native fullscreen mode exited, notifying listener...\n"));
98 emit sigNotifyAboutNativeFullscreenDidExit();
99 }
100 /* Handle 'NSWindowDidFailToEnterFullScreenNotification' notification: */
101 else if (strNativeNotificationName == "NSWindowDidFailToEnterFullScreenNotification")
102 {
103 /* Mark window transition complete: */
104 m_fIsInFullscreenTransition = false;
105 LogRel(("UIMachineWindowFullscreen::handleNativeNotification: "
106 "Native fullscreen mode fail to enter, notifying listener...\n"));
107 emit sigNotifyAboutNativeFullscreenFailToEnter();
108 }
109}
110
111void UIMachineWindowFullscreen::setMiniToolbarVisible(bool fVisible)
112{
113 /* Make sure mini-toolbar exists: */
114 if (!m_pMiniToolBar)
115 return;
116 /* Set mini-toolbar visibility to passed one: */
117 m_pMiniToolBar->setVisible(fVisible);
118}
119#endif /* Q_WS_MAC */
120
121void UIMachineWindowFullscreen::sltMachineStateChanged()
122{
123 /* Call to base-class: */
124 UIMachineWindow::sltMachineStateChanged();
125
126 /* Update mini-toolbar: */
127 updateAppearanceOf(UIVisualElement_MiniToolBar);
128}
129
130#ifdef Q_WS_MAC
131void UIMachineWindowFullscreen::sltEnterNativeFullscreen(UIMachineWindow *pMachineWindow)
132{
133 /* Make sure this slot is called only under ML and next: */
134 AssertReturnVoid(vboxGlobal().osRelease() > MacOSXRelease_Lion);
135
136 /* Make sure it is NULL or 'this' window passed: */
137 if (pMachineWindow && pMachineWindow != this)
138 return;
139
140 /* Make sure this window has fullscreen logic: */
141 UIMachineLogicFullscreen *pFullscreenLogic = qobject_cast<UIMachineLogicFullscreen*>(machineLogic());
142 AssertPtrReturnVoid(pFullscreenLogic);
143
144 /* Make sure this window should be shown and mapped to host-screen: */
145 if (!uisession()->isScreenVisible(m_uScreenId) ||
146 !pFullscreenLogic->hasHostScreenForGuestScreen(m_uScreenId))
147 return;
148
149 /* Mark window 'transitioned to fullscreen': */
150 m_fIsInFullscreenTransition = true;
151
152 /* Enter native fullscreen mode if necessary: */
153 if ( (pFullscreenLogic->screensHaveSeparateSpaces() || m_uScreenId == 0)
154 && !darwinIsInFullscreenMode(this))
155 darwinToggleFullscreenMode(this);
156}
157
158void UIMachineWindowFullscreen::sltExitNativeFullscreen(UIMachineWindow *pMachineWindow)
159{
160 /* Make sure this slot is called only under ML and next: */
161 AssertReturnVoid(vboxGlobal().osRelease() > MacOSXRelease_Lion);
162
163 /* Make sure it is NULL or 'this' window passed: */
164 if (pMachineWindow && pMachineWindow != this)
165 return;
166
167 /* Make sure this window has fullscreen logic: */
168 UIMachineLogicFullscreen *pFullscreenLogic = qobject_cast<UIMachineLogicFullscreen*>(machineLogic());
169 AssertPtrReturnVoid(pFullscreenLogic);
170
171 /* Mark window 'transitioned from fullscreen': */
172 m_fIsInFullscreenTransition = true;
173
174 /* Exit native fullscreen mode if necessary: */
175 if ( (pFullscreenLogic->screensHaveSeparateSpaces() || m_uScreenId == 0)
176 && darwinIsInFullscreenMode(this))
177 darwinToggleFullscreenMode(this);
178}
179#endif /* Q_WS_MAC */
180
181void UIMachineWindowFullscreen::sltRevokeFocus()
182{
183 /* Make sure window is visible: */
184 if (!isVisible())
185 return;
186
187#if defined(Q_WS_WIN)
188 /* Revoke stolen focus: */
189 m_pMachineView->setFocus();
190#elif defined(Q_WS_MAC) || defined(Q_WS_X11)
191 /* Revoke stolen activation: */
192 activateWindow();
193#endif /* Q_WS_MAC || Q_WS_X11 */
194}
195
196void UIMachineWindowFullscreen::prepareVisualState()
197{
198 /* Call to base-class: */
199 UIMachineWindow::prepareVisualState();
200
201 /* The background has to go black: */
202 QPalette palette(centralWidget()->palette());
203 palette.setColor(centralWidget()->backgroundRole(), Qt::black);
204 centralWidget()->setPalette(palette);
205 centralWidget()->setAutoFillBackground(true);
206 setAutoFillBackground(true);
207
208 /* Prepare mini-toolbar: */
209 prepareMiniToolbar();
210
211#ifdef Q_WS_MAC
212 /* Native fullscreen stuff on ML and next: */
213 if (vboxGlobal().osRelease() > MacOSXRelease_Lion)
214 {
215 /* Make sure this window has fullscreen logic: */
216 UIMachineLogicFullscreen *pFullscreenLogic = qobject_cast<UIMachineLogicFullscreen*>(machineLogic());
217 AssertPtrReturnVoid(pFullscreenLogic);
218 /* Enable fullscreen support for every screen which requires it: */
219 if (pFullscreenLogic->screensHaveSeparateSpaces() || m_uScreenId == 0)
220 darwinEnableFullscreenSupport(this);
221 /* Enable transience support for other screens: */
222 else
223 darwinEnableTransienceSupport(this);
224 /* Register to native fullscreen notifications: */
225 UICocoaApplication::instance()->registerToNotificationOfWindow("NSWindowWillEnterFullScreenNotification", this,
226 UIMachineWindow::handleNativeNotification);
227 UICocoaApplication::instance()->registerToNotificationOfWindow("NSWindowDidEnterFullScreenNotification", this,
228 UIMachineWindow::handleNativeNotification);
229 UICocoaApplication::instance()->registerToNotificationOfWindow("NSWindowWillExitFullScreenNotification", this,
230 UIMachineWindow::handleNativeNotification);
231 UICocoaApplication::instance()->registerToNotificationOfWindow("NSWindowDidExitFullScreenNotification", this,
232 UIMachineWindow::handleNativeNotification);
233 UICocoaApplication::instance()->registerToNotificationOfWindow("NSWindowDidFailToEnterFullScreenNotification", this,
234 UIMachineWindow::handleNativeNotification);
235 }
236#endif /* Q_WS_MAC */
237}
238
239void UIMachineWindowFullscreen::prepareMiniToolbar()
240{
241 /* Make sure mini-toolbar is not restricted: */
242 if (!gEDataManager->miniToolbarEnabled(vboxGlobal().managedVMUuid()))
243 return;
244
245 /* Create mini-toolbar: */
246 m_pMiniToolBar = new UIRuntimeMiniToolBar(this,
247 GeometryType_Full,
248 gEDataManager->miniToolbarAlignment(vboxGlobal().managedVMUuid()),
249 gEDataManager->autoHideMiniToolbar(vboxGlobal().managedVMUuid()));
250 m_pMiniToolBar->addMenus(actionPool()->menus());
251#ifdef RT_OS_DARWIN
252 connect(machineLogic(), SIGNAL(sigNotifyAbout3DOverlayVisibilityChange(bool)),
253 m_pMiniToolBar, SLOT(sltHandle3DOverlayVisibilityChange(bool)));
254#endif /* RT_OS_DARWIN */
255#ifndef RT_OS_DARWIN
256 connect(m_pMiniToolBar, SIGNAL(sigMinimizeAction()), this, SLOT(showMinimized()));
257#endif /* !RT_OS_DARWIN */
258 connect(m_pMiniToolBar, SIGNAL(sigExitAction()),
259 actionPool()->action(UIActionIndexRT_M_View_T_Fullscreen), SLOT(trigger()));
260#ifdef RT_OS_DARWIN
261 connect(m_pMiniToolBar, SIGNAL(sigCloseAction()),
262 actionPool()->action(UIActionIndex_M_Application_S_Close), SLOT(trigger()));
263#else /* !RT_OS_DARWIN */
264 connect(m_pMiniToolBar, SIGNAL(sigCloseAction()),
265 actionPool()->action(UIActionIndexRT_M_Machine_S_Close), SLOT(trigger()));
266#endif /* !RT_OS_DARWIN */
267 connect(m_pMiniToolBar, SIGNAL(sigNotifyAboutFocusStolen()),
268 this, SLOT(sltRevokeFocus()), Qt::QueuedConnection);
269}
270
271void UIMachineWindowFullscreen::cleanupMiniToolbar()
272{
273 /* Make sure mini-toolbar was created: */
274 if (!m_pMiniToolBar)
275 return;
276
277 /* Save mini-toolbar settings: */
278 gEDataManager->setAutoHideMiniToolbar(m_pMiniToolBar->autoHide(), vboxGlobal().managedVMUuid());
279 /* Delete mini-toolbar: */
280 delete m_pMiniToolBar;
281 m_pMiniToolBar = 0;
282}
283
284void UIMachineWindowFullscreen::cleanupVisualState()
285{
286#ifdef Q_WS_MAC
287 /* Native fullscreen stuff on ML and next: */
288 if (vboxGlobal().osRelease() > MacOSXRelease_Lion)
289 {
290 /* Unregister from native fullscreen notifications: */
291 UICocoaApplication::instance()->unregisterFromNotificationOfWindow("NSWindowWillEnterFullScreenNotification", this);
292 UICocoaApplication::instance()->unregisterFromNotificationOfWindow("NSWindowDidEnterFullScreenNotification", this);
293 UICocoaApplication::instance()->unregisterFromNotificationOfWindow("NSWindowWillExitFullScreenNotification", this);
294 UICocoaApplication::instance()->unregisterFromNotificationOfWindow("NSWindowDidExitFullScreenNotification", this);
295 UICocoaApplication::instance()->unregisterFromNotificationOfWindow("NSWindowDidFailToEnterFullScreenNotification", this);
296 }
297#endif /* Q_WS_MAC */
298
299 /* Cleanup mini-toolbar: */
300 cleanupMiniToolbar();
301
302 /* Call to base-class: */
303 UIMachineWindow::cleanupVisualState();
304}
305
306void UIMachineWindowFullscreen::placeOnScreen()
307{
308 /* Get corresponding screen: */
309 const int iScreen = qobject_cast<UIMachineLogicFullscreen*>(machineLogic())->hostScreenForGuestScreen(m_uScreenId);
310 /* And corresponding working area: */
311 const QRect workingArea = QApplication::desktop()->screenGeometry(iScreen);
312
313 /* Move to the appropriate position: */
314 move(workingArea.topLeft());
315
316#ifdef Q_WS_MAC
317 /* Make sure this window has fullscreen logic: */
318 UIMachineLogicFullscreen *pFullscreenLogic = qobject_cast<UIMachineLogicFullscreen*>(machineLogic());
319 AssertPtrReturnVoid(pFullscreenLogic);
320
321 /* Resize to the appropriate size on Lion and previous: */
322 if (vboxGlobal().osRelease() <= MacOSXRelease_Lion)
323 resize(workingArea.size());
324 /* Resize to the appropriate size on ML and next
325 * only if that screen has no own user-space: */
326 else if (!pFullscreenLogic->screensHaveSeparateSpaces() && m_uScreenId != 0)
327 resize(workingArea.size());
328 else
329 {
330 /* Load normal geometry first of all: */
331 QRect geo = gEDataManager->machineWindowGeometry(UIVisualStateType_Normal, m_uScreenId, vboxGlobal().managedVMUuid());
332 /* If normal geometry is null => use frame-buffer size: */
333 if (geo.isNull())
334 {
335 const UIFrameBuffer *pFrameBuffer = uisession()->frameBuffer(m_uScreenId);
336 geo = QRect(QPoint(0, 0), QSize(pFrameBuffer->width(), pFrameBuffer->height()).boundedTo(workingArea.size()));
337 }
338 /* If frame-buffer size is null => use default size: */
339 if (geo.isNull())
340 geo = QRect(QPoint(0, 0), QSize(800, 600).boundedTo(workingArea.size()));
341 /* Move window to the center of working-area: */
342 geo.moveCenter(workingArea.center());
343 setGeometry(geo);
344 }
345#else /* !Q_WS_MAC */
346 /* Resize to the appropriate size: */
347 resize(workingArea.size());
348#endif /* !Q_WS_MAC */
349}
350
351void UIMachineWindowFullscreen::showInNecessaryMode()
352{
353 /* Make sure this window has fullscreen logic: */
354 UIMachineLogicFullscreen *pFullscreenLogic = qobject_cast<UIMachineLogicFullscreen*>(machineLogic());
355 AssertPtrReturnVoid(pFullscreenLogic);
356
357#ifdef Q_WS_MAC
358 /* ML and next using native stuff: */
359 const bool fSupportsNativeFullScreen = vboxGlobal().osRelease() > MacOSXRelease_Lion;
360#endif /* Q_WS_MAC */
361
362 /* Make sure this window should be shown and mapped to some host-screen: */
363 if (!uisession()->isScreenVisible(m_uScreenId) ||
364 !pFullscreenLogic->hasHostScreenForGuestScreen(m_uScreenId))
365 {
366 /* If there is mini-toolbar: */
367 if (m_pMiniToolBar)
368 {
369#if defined(Q_WS_WIN) || defined(Q_WS_X11)
370 /* Just hide mini-toolbar: */
371 m_pMiniToolBar->hide();
372#elif defined(Q_WS_MAC)
373 /* If no native full-screen used: */
374 if (!fSupportsNativeFullScreen)
375 {
376 /* Just hide mini-toolbar: */
377 m_pMiniToolBar->hide();
378 }
379#endif /* Q_WS_MAC */
380 }
381 /* Hide window: */
382 hide();
383 return;
384 }
385
386 /* Make sure this window is not minimized: */
387 if (isMinimized())
388 return;
389
390#ifdef Q_WS_X11
391 /* On X11 calling placeOnScreen() is only needed for legacy window managers
392 * which we do not test, so this is 'best effort' code. With window managers which
393 * support the _NET_WM_FULLSCREEN_MONITORS protocol this would interfere unreliable. */
394 const bool fSupportsNativeFullScreen = VBoxGlobal::supportsFullScreenMonitorsProtocolX11() &&
395 !gEDataManager->legacyFullscreenModeRequested();
396 if (!fSupportsNativeFullScreen)
397 placeOnScreen();
398#else /* !Q_WS_X11 */
399 /* Make sure this window is maximized and placed on valid screen: */
400 placeOnScreen();
401#endif /* !Q_WS_X11 */
402
403#ifdef Q_WS_MAC
404 /* ML and next using native stuff, so we can call for simple show(),
405 * Lion and previous using Qt stuff, so we should call for showFullScreen(): */
406 if (fSupportsNativeFullScreen)
407 show();
408 else
409 showFullScreen();
410#else /* !Q_WS_MAC */
411 /* Show in fullscreen mode: */
412 showFullScreen();
413#endif /* !Q_WS_MAC */
414
415#ifdef Q_WS_X11
416 if (fSupportsNativeFullScreen)
417 {
418 /* Tell recent window managers which screen this window should be mapped to.
419 * Apparently some window managers will not respond to requests for
420 * unmapped windows, so do this *after* the call to showFullScreen(). */
421 VBoxGlobal::setFullScreenMonitorX11(this, pFullscreenLogic->hostScreenForGuestScreen(m_uScreenId));
422 }
423 else
424 {
425 /* On X11 calling placeOnScreen() is only needed for legacy window managers
426 * which we do not test, so this is 'best effort' code. With window managers which
427 * support the _NET_WM_FULLSCREEN_MONITORS protocol this would interfere unreliable. */
428 placeOnScreen();
429 }
430#endif /* Q_WS_X11 */
431
432 /* Adjust machine-view size if necessary: */
433 adjustMachineViewSize();
434
435 /* If there is mini-toolbar: */
436 if (m_pMiniToolBar)
437 {
438#if defined(Q_WS_WIN)
439 /* Just show mini-toolbar: */
440 m_pMiniToolBar->show();
441#elif defined(Q_WS_MAC)
442 /* If no native full-screen used: */
443 if (!fSupportsNativeFullScreen)
444 {
445 /* Just show mini-toolbar: */
446 m_pMiniToolBar->show();
447 }
448#elif defined(Q_WS_X11)
449 /* Allow mini-toolbar to be located on full-screen area: */
450 m_pMiniToolBar->showFullScreen();
451 /* On modern window managers: */
452 if (fSupportsNativeFullScreen)
453 {
454 /* We also can map mini-toolbar directly on corresponding machine-window: */
455 VBoxGlobal::setFullScreenMonitorX11(m_pMiniToolBar, pFullscreenLogic->hostScreenForGuestScreen(m_uScreenId));
456 }
457 /* Make sure mini-toolbar is always on top of machine-window: */
458 VBoxGlobal::setTransientFor(m_pMiniToolBar, this);
459#endif /* Q_WS_X11 */
460 }
461
462 /* Make sure machine-view have focus: */
463 m_pMachineView->setFocus();
464}
465
466void UIMachineWindowFullscreen::adjustMachineViewSize()
467{
468 /* Call to base-class: */
469 UIMachineWindow::adjustMachineViewSize();
470
471 /* If mini-toolbar present: */
472 if (m_pMiniToolBar)
473 {
474 /* Make sure this window has fullscreen logic: */
475 UIMachineLogicFullscreen *pFullscreenLogic = qobject_cast<UIMachineLogicFullscreen*>(machineLogic());
476 AssertPtrReturnVoid(pFullscreenLogic);
477
478 /* Which host-screen should that machine-window located on? */
479 const int iHostScreen = pFullscreenLogic->hostScreenForGuestScreen(m_uScreenId);
480
481#ifndef Q_WS_X11
482 /* Move mini-toolbar into appropriate place: */
483 m_pMiniToolBar->adjustGeometry(iHostScreen);
484#else /* Q_WS_X11 */
485 /* On modern WMs we are mapping mini-toolbar to corresponding host-screen directly. */
486 const bool fSupportsNativeFullScreen = VBoxGlobal::supportsFullScreenMonitorsProtocolX11() &&
487 !gEDataManager->legacyFullscreenModeRequested();
488 /* Adjust mini-toolbar and move into appropriate place if necessary: */
489 m_pMiniToolBar->adjustGeometry(fSupportsNativeFullScreen ? -1 : iHostScreen);
490#endif /* Q_WS_X11 */
491 }
492}
493
494void UIMachineWindowFullscreen::updateAppearanceOf(int iElement)
495{
496 /* Call to base-class: */
497 UIMachineWindow::updateAppearanceOf(iElement);
498
499 /* Update mini-toolbar: */
500 if (iElement & UIVisualElement_MiniToolBar)
501 {
502 if (m_pMiniToolBar)
503 {
504 /* Get machine: */
505 const CMachine &m = machine();
506 /* Get snapshot(s): */
507 QString strSnapshotName;
508 if (m.GetSnapshotCount() > 0)
509 {
510 CSnapshot snapshot = m.GetCurrentSnapshot();
511 strSnapshotName = " (" + snapshot.GetName() + ")";
512 }
513 /* Update mini-toolbar text: */
514 m_pMiniToolBar->setText(m.GetName() + strSnapshotName);
515 }
516 }
517}
518
Note: See TracBrowser for help on using the repository browser.

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