VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMultiScreenLayout.cpp@ 29076

Last change on this file since 29076 was 29076, checked in by vboxsync, 14 years ago

FE/Qt4: new core: Make sure the seamless/fullscreen windows are opened on the
host screen the user expect until he manual overwrite this decision.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.4 KB
Line 
1/* $Id: UIMultiScreenLayout.cpp 29076 2010-05-05 13:03:29Z vboxsync $ */
2/** @file
3 *
4 * VBox frontends: Qt GUI ("VirtualBox"):
5 * UIMultiScreenLayout class implementation
6 */
7
8/*
9 * Copyright (C) 2010 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20/* Local includes */
21#include "UIMultiScreenLayout.h"
22#include "COMDefs.h"
23#include "UIActionsPool.h"
24#include "UIMachineLogic.h"
25#include "UISession.h"
26#include "VBoxProblemReporter.h"
27
28/* Global includes */
29#include <QApplication>
30#include <QDesktopWidget>
31#include <QMap>
32#include <QMenu>
33
34UIMultiScreenLayout::UIMultiScreenLayout(UIMachineLogic *pMachineLogic)
35 : m_pMachineLogic(pMachineLogic)
36 , m_pScreenMap(new QMap<int, int>())
37{
38 CMachine machine = m_pMachineLogic->session().GetMachine();
39 /* Get host/guest monitor count: */
40#if (QT_VERSION >= 0x040600)
41 m_cHostScreens = QApplication::desktop()->screenCount();
42#else /* (QT_VERSION >= 0x040600) */
43 m_cHostScreens = QApplication::desktop()->numScreens();
44#endif /* !(QT_VERSION >= 0x040600) */
45 m_cGuestScreens = machine.GetMonitorCount();
46}
47
48UIMultiScreenLayout::~UIMultiScreenLayout()
49{
50 delete m_pScreenMap;
51}
52
53void UIMultiScreenLayout::initialize(QMenu *pMenu)
54{
55 pMenu->clear();
56 for (int i = 0; i < m_cGuestScreens; ++i)
57 {
58 QMenu *pScreenMenu = pMenu->addMenu(tr("Virtual Screen %1").arg(i + 1));
59 QActionGroup *pScreenGroup = new QActionGroup(pScreenMenu);
60 pScreenGroup->setExclusive(true);
61 connect(pScreenGroup, SIGNAL(triggered(QAction*)),
62 this, SLOT(sltScreenLayoutChanged(QAction*)));
63 for (int a = 0; a < m_cHostScreens; ++a)
64 {
65 QAction *pAction = pScreenGroup->addAction(tr("Use Host Screen %1").arg(a + 1));
66 pAction->setCheckable(true);
67 pAction->setData(RT_MAKE_U32(i, a));
68 }
69 pScreenMenu->addActions(pScreenGroup->actions());
70 }
71}
72
73void UIMultiScreenLayout::update()
74{
75 CMachine machine = m_pMachineLogic->session().GetMachine();
76 /* Make a pool of available host screens. */
77 QList<int> availableScreens;
78 for (int i = 0; i < m_cHostScreens; ++i)
79 availableScreens << i;
80 /* Load all combinations stored in the settings file. We have to make sure
81 * they are valid, which means there have to be unique combinations and all
82 * guests screens need there own host screen. */
83 QDesktopWidget *pDW = QApplication::desktop();
84 for (int i = 0; i < m_cGuestScreens; ++i)
85 {
86 /* If the user ever selected a combination in the view menu, we have
87 * the following entry: */
88 QString strTest = machine.GetExtraData(QString("%1%2").arg(VBoxDefs::GUI_VirtualScreenToHostScreen).arg(i));
89 bool fOk;
90 int cScreen = strTest.toInt(&fOk);
91 /* Check if valid: */
92 if (!( fOk /* Valid data */
93 && cScreen >= 0 && cScreen < m_cHostScreens /* In the host screen bounds? */
94 && m_pScreenMap->key(cScreen, -1) == -1)) /* Not taken already? */
95 {
96 /* If not, check the position of the guest window in normal mode.
97 * This makes sure that on first use the window opens on the same
98 * screen as the normal window was before. This even works with
99 * multi-screen. The user just have to move all the normal windows
100 * to the target screens and they will magically open there in
101 * seamless/fullscreen also. */
102 QString strTest1 = machine.GetExtraData(VBoxDefs::GUI_LastWindowPosition + (i > 0 ? QString::number(i): ""));
103 QRegExp posParser("(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)");
104 if ( posParser.exactMatch(strTest1)
105 && posParser.captureCount() == 4)
106 {
107 /* If parsing was successfully, convert it to a position. */
108 bool fOk1, fOk2;
109 QPoint p(posParser.cap(1).toInt(&fOk1), posParser.cap(2).toInt(&fOk2));
110 /* Check to which screen the position belongs. */
111 cScreen = pDW->screenNumber(p);
112 if (!( fOk1 /* Valid data */
113 && fOk2 /* Valid data */
114 && cScreen >= 0 && cScreen < m_cHostScreens /* In the host screen bounds? */
115 && m_pScreenMap->key(cScreen, -1) == -1)) /* Not taken already? */
116 /* If not, simply pick the next one of the still available
117 * host screens. */
118 cScreen = availableScreens.first();
119 }
120 else
121 /* If not, simply pick the next one of the still available host
122 * screens. */
123 cScreen = availableScreens.first();
124 }
125 m_pScreenMap->insert(i, cScreen);
126 /* Remove the just selected screen from the list of available screens. */
127 availableScreens.removeOne(cScreen);
128 }
129
130 QList<QAction*> actions = m_pMachineLogic->actionsPool()->action(UIActionIndex_Menu_View)->menu()->actions();
131 for (int i = 0; i < m_pScreenMap->size(); ++i)
132 {
133 int hostScreen = m_pScreenMap->value(i);
134 QList<QAction*> actions1 = actions.at(i)->menu()->actions();
135 for (int w = 0; w < actions1.size(); ++w)
136 {
137 QAction *pTmpAction = actions1.at(w);
138 pTmpAction->blockSignals(true);
139 pTmpAction->setChecked(RT_HIWORD(pTmpAction->data().toInt()) == hostScreen);
140 pTmpAction->blockSignals(false);
141 }
142 }
143}
144
145int UIMultiScreenLayout::hostScreenCount() const
146{
147 return m_cHostScreens;
148}
149
150int UIMultiScreenLayout::guestScreenCount() const
151{
152 return m_cGuestScreens;
153}
154
155int UIMultiScreenLayout::hostScreenForGuestScreen(int screenId) const
156{
157 return m_pScreenMap->value(screenId, 0);
158}
159
160quint64 UIMultiScreenLayout::memoryRequirements() const
161{
162 return memoryRequirements(m_pScreenMap);
163}
164
165bool UIMultiScreenLayout::isHostTaskbarCovert() const
166{
167 /* Check for all screens which are in use if they have some
168 * taskbar/menubar/dock on it. Its done by comparing the available with the
169 * screen geometry. Only if they are the same for all screens, there are no
170 * host area covert. This is a little bit ugly, but there seems no other
171 * way to find out if we are on a screen where the taskbar/dock or whatever
172 * is present. */
173 QDesktopWidget *pDW = QApplication::desktop();
174 for (int i = 0; i < m_pScreenMap->size(); ++i)
175 {
176 int hostScreen = m_pScreenMap->value(i);
177 if (pDW->availableGeometry(hostScreen) != pDW->screenGeometry(hostScreen))
178 return true;
179 }
180 return false;
181}
182
183void UIMultiScreenLayout::sltScreenLayoutChanged(QAction *pAction)
184{
185 int a = pAction->data().toInt();
186 int cGuestScreen = RT_LOWORD(a);
187 int cHostScreen = RT_HIWORD(a);
188
189 CMachine machine = m_pMachineLogic->session().GetMachine();
190 QMap<int,int> *pTmpMap = new QMap<int,int>(*m_pScreenMap);
191 /* Search for the virtual screen which is currently displayed on the
192 * requested host screen. When there is one found, we swap both. */
193 int r = pTmpMap->key(cHostScreen, -1);
194 if (r != -1)
195 pTmpMap->insert(r, pTmpMap->value(cGuestScreen));
196 /* Set the new host screen */
197 pTmpMap->insert(cGuestScreen, cHostScreen);
198
199 bool fSuccess = true;
200 if (m_pMachineLogic->uisession()->isGuestAdditionsActive())
201 {
202 quint64 availBits = machine.GetVRAMSize() /* VRAM */
203 * _1M /* MiB to bytes */
204 * 8; /* to bits */
205 quint64 usedBits = memoryRequirements(pTmpMap);
206
207 fSuccess = availBits >= usedBits;
208 if (!fSuccess)
209 {
210 /* We have to little video memory for the new layout, so say it to the
211 * user and revert all changes. */
212 if (m_pMachineLogic->visualStateType() == UIVisualStateType_Seamless)
213 vboxProblem().cannotSwitchScreenInSeamless((((usedBits + 7) / 8 + _1M - 1) / _1M) * _1M);
214 else
215 fSuccess = vboxProblem().cannotSwitchScreenInFullscreen((((usedBits + 7) / 8 + _1M - 1) / _1M) * _1M) != QIMessageBox::Cancel;
216 }
217 }
218 if (fSuccess)
219 {
220 /* Swap the temporary with the previous map. */
221 delete m_pScreenMap;
222 m_pScreenMap = pTmpMap;
223 }
224
225 /* Update the menu items. Even if we can't switch we have to revert the
226 * menu items. */
227 QList<QAction*> actions = m_pMachineLogic->actionsPool()->action(UIActionIndex_Menu_View)->menu()->actions();
228 /* Update the settings. */
229 for (int i = 0; i < m_cGuestScreens; ++i)
230 {
231 int hostScreen = m_pScreenMap->value(i);
232 machine.SetExtraData(QString("%1%2").arg(VBoxDefs::GUI_VirtualScreenToHostScreen).arg(i), QString::number(hostScreen));
233 QList<QAction*> actions1 = actions.at(i)->menu()->actions();
234 for (int w = 0; w < actions1.size(); ++w)
235 {
236 QAction *pTmpAction = actions1.at(w);
237 pTmpAction->blockSignals(true);
238 pTmpAction->setChecked(RT_HIWORD(pTmpAction->data().toInt()) == hostScreen);
239 pTmpAction->blockSignals(false);
240 }
241 }
242
243 /* On success inform the observer. */
244 if (fSuccess)
245 emit screenLayoutChanged();
246}
247
248quint64 UIMultiScreenLayout::memoryRequirements(const QMap<int, int> *pScreenLayout) const
249{
250 ULONG width = 0;
251 ULONG height = 0;
252 ULONG guestBpp = 0;
253 quint64 usedBits = 0;
254 CDisplay display = m_pMachineLogic->uisession()->session().GetConsole().GetDisplay();
255 for (int i = 0; i < m_cGuestScreens; ++ i)
256 {
257 QRect screen;
258 if (m_pMachineLogic->visualStateType() == UIVisualStateType_Seamless)
259 screen = QApplication::desktop()->availableGeometry(pScreenLayout->value(i, 0));
260 else
261 screen = QApplication::desktop()->screenGeometry(pScreenLayout->value(i, 0));
262 display.GetScreenResolution(i, width, height, guestBpp);
263 usedBits += screen.width() * /* display width */
264 screen.height() * /* display height */
265 guestBpp + /* guest bits per pixel */
266 _1M * 8; /* current cache per screen - may be changed in future */
267 }
268 usedBits += 4096 * 8; /* adapter info */
269 return usedBits;
270}
271
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use