VirtualBox

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

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

FE/Qt4: fix burns

  • 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 29078 2010-05-05 13:17:30Z 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 {
106 /* If parsing was successfully, convert it to a position. */
107 bool fOk1, fOk2;
108 QPoint p(posParser.cap(1).toInt(&fOk1), posParser.cap(2).toInt(&fOk2));
109 /* Check to which screen the position belongs. */
110 cScreen = pDW->screenNumber(p);
111 if (!( fOk1 /* Valid data */
112 && fOk2 /* Valid data */
113 && cScreen >= 0 && cScreen < m_cHostScreens /* In the host screen bounds? */
114 && m_pScreenMap->key(cScreen, -1) == -1)) /* Not taken already? */
115 /* If not, simply pick the next one of the still available
116 * host screens. */
117 cScreen = availableScreens.first();
118 }
119 else
120 /* If not, simply pick the next one of the still available host
121 * screens. */
122 cScreen = availableScreens.first();
123 }
124 m_pScreenMap->insert(i, cScreen);
125 /* Remove the just selected screen from the list of available screens. */
126 availableScreens.removeOne(cScreen);
127 }
128
129 QList<QAction*> actions = m_pMachineLogic->actionsPool()->action(UIActionIndex_Menu_View)->menu()->actions();
130 for (int i = 0; i < m_pScreenMap->size(); ++i)
131 {
132 int hostScreen = m_pScreenMap->value(i);
133 QList<QAction*> actions1 = actions.at(i)->menu()->actions();
134 for (int w = 0; w < actions1.size(); ++w)
135 {
136 QAction *pTmpAction = actions1.at(w);
137 pTmpAction->blockSignals(true);
138 pTmpAction->setChecked(RT_HIWORD(pTmpAction->data().toInt()) == hostScreen);
139 pTmpAction->blockSignals(false);
140 }
141 }
142}
143
144int UIMultiScreenLayout::hostScreenCount() const
145{
146 return m_cHostScreens;
147}
148
149int UIMultiScreenLayout::guestScreenCount() const
150{
151 return m_cGuestScreens;
152}
153
154int UIMultiScreenLayout::hostScreenForGuestScreen(int screenId) const
155{
156 return m_pScreenMap->value(screenId, 0);
157}
158
159quint64 UIMultiScreenLayout::memoryRequirements() const
160{
161 return memoryRequirements(m_pScreenMap);
162}
163
164bool UIMultiScreenLayout::isHostTaskbarCovert() const
165{
166 /* Check for all screens which are in use if they have some
167 * taskbar/menubar/dock on it. Its done by comparing the available with the
168 * screen geometry. Only if they are the same for all screens, there are no
169 * host area covert. This is a little bit ugly, but there seems no other
170 * way to find out if we are on a screen where the taskbar/dock or whatever
171 * is present. */
172 QDesktopWidget *pDW = QApplication::desktop();
173 for (int i = 0; i < m_pScreenMap->size(); ++i)
174 {
175 int hostScreen = m_pScreenMap->value(i);
176 if (pDW->availableGeometry(hostScreen) != pDW->screenGeometry(hostScreen))
177 return true;
178 }
179 return false;
180}
181
182void UIMultiScreenLayout::sltScreenLayoutChanged(QAction *pAction)
183{
184 int a = pAction->data().toInt();
185 int cGuestScreen = RT_LOWORD(a);
186 int cHostScreen = RT_HIWORD(a);
187
188 CMachine machine = m_pMachineLogic->session().GetMachine();
189 QMap<int,int> *pTmpMap = new QMap<int,int>(*m_pScreenMap);
190 /* Search for the virtual screen which is currently displayed on the
191 * requested host screen. When there is one found, we swap both. */
192 int r = pTmpMap->key(cHostScreen, -1);
193 if (r != -1)
194 pTmpMap->insert(r, pTmpMap->value(cGuestScreen));
195 /* Set the new host screen */
196 pTmpMap->insert(cGuestScreen, cHostScreen);
197
198 bool fSuccess = true;
199 if (m_pMachineLogic->uisession()->isGuestAdditionsActive())
200 {
201 quint64 availBits = machine.GetVRAMSize() /* VRAM */
202 * _1M /* MiB to bytes */
203 * 8; /* to bits */
204 quint64 usedBits = memoryRequirements(pTmpMap);
205
206 fSuccess = availBits >= usedBits;
207 if (!fSuccess)
208 {
209 /* We have to little video memory for the new layout, so say it to the
210 * user and revert all changes. */
211 if (m_pMachineLogic->visualStateType() == UIVisualStateType_Seamless)
212 vboxProblem().cannotSwitchScreenInSeamless((((usedBits + 7) / 8 + _1M - 1) / _1M) * _1M);
213 else
214 fSuccess = vboxProblem().cannotSwitchScreenInFullscreen((((usedBits + 7) / 8 + _1M - 1) / _1M) * _1M) != QIMessageBox::Cancel;
215 }
216 }
217 if (fSuccess)
218 {
219 /* Swap the temporary with the previous map. */
220 delete m_pScreenMap;
221 m_pScreenMap = pTmpMap;
222 }
223
224 /* Update the menu items. Even if we can't switch we have to revert the
225 * menu items. */
226 QList<QAction*> actions = m_pMachineLogic->actionsPool()->action(UIActionIndex_Menu_View)->menu()->actions();
227 /* Update the settings. */
228 for (int i = 0; i < m_cGuestScreens; ++i)
229 {
230 int hostScreen = m_pScreenMap->value(i);
231 machine.SetExtraData(QString("%1%2").arg(VBoxDefs::GUI_VirtualScreenToHostScreen).arg(i), QString::number(hostScreen));
232 QList<QAction*> actions1 = actions.at(i)->menu()->actions();
233 for (int w = 0; w < actions1.size(); ++w)
234 {
235 QAction *pTmpAction = actions1.at(w);
236 pTmpAction->blockSignals(true);
237 pTmpAction->setChecked(RT_HIWORD(pTmpAction->data().toInt()) == hostScreen);
238 pTmpAction->blockSignals(false);
239 }
240 }
241
242 /* On success inform the observer. */
243 if (fSuccess)
244 emit screenLayoutChanged();
245}
246
247quint64 UIMultiScreenLayout::memoryRequirements(const QMap<int, int> *pScreenLayout) const
248{
249 ULONG width = 0;
250 ULONG height = 0;
251 ULONG guestBpp = 0;
252 quint64 usedBits = 0;
253 CDisplay display = m_pMachineLogic->uisession()->session().GetConsole().GetDisplay();
254 for (int i = 0; i < m_cGuestScreens; ++ i)
255 {
256 QRect screen;
257 if (m_pMachineLogic->visualStateType() == UIVisualStateType_Seamless)
258 screen = QApplication::desktop()->availableGeometry(pScreenLayout->value(i, 0));
259 else
260 screen = QApplication::desktop()->screenGeometry(pScreenLayout->value(i, 0));
261 display.GetScreenResolution(i, width, height, guestBpp);
262 usedBits += screen.width() * /* display width */
263 screen.height() * /* display height */
264 guestBpp + /* guest bits per pixel */
265 _1M * 8; /* current cache per screen - may be changed in future */
266 }
267 usedBits += 4096 * 8; /* adapter info */
268 return usedBits;
269}
270
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use