|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtGui module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qdesktopwidget.h" |
|
43 #include "qt_windows.h" |
|
44 #include "qapplication_p.h" |
|
45 #include "qlibrary.h" |
|
46 #include <qvector.h> |
|
47 #include <limits.h> |
|
48 #ifdef Q_WS_WINCE |
|
49 #include <sipapi.h> |
|
50 #endif |
|
51 #include "qwidget_p.h" |
|
52 #include "qdebug.h" |
|
53 |
|
54 QT_BEGIN_NAMESPACE |
|
55 |
|
56 class QDesktopWidgetPrivate : public QWidgetPrivate |
|
57 { |
|
58 public: |
|
59 QDesktopWidgetPrivate(); |
|
60 ~QDesktopWidgetPrivate(); |
|
61 |
|
62 static void init(QDesktopWidget *that); |
|
63 static void cleanup(); |
|
64 static int screenCount; |
|
65 static int primaryScreen; |
|
66 |
|
67 static QVector<QRect> *rects; |
|
68 static QVector<QRect> *workrects; |
|
69 |
|
70 struct MONITORINFO |
|
71 { |
|
72 DWORD cbSize; |
|
73 RECT rcMonitor; |
|
74 RECT rcWork; |
|
75 DWORD dwFlags; |
|
76 }; |
|
77 |
|
78 typedef BOOL (WINAPI *InfoFunc)(HMONITOR, MONITORINFO*); |
|
79 typedef BOOL (CALLBACK *EnumProc)(HMONITOR, HDC, LPRECT, LPARAM); |
|
80 typedef BOOL (WINAPI *EnumFunc)(HDC, LPCRECT, EnumProc, LPARAM); |
|
81 |
|
82 static EnumFunc enumDisplayMonitors; |
|
83 static InfoFunc getMonitorInfo; |
|
84 static int refcount; |
|
85 }; |
|
86 |
|
87 int QDesktopWidgetPrivate::screenCount = 1; |
|
88 int QDesktopWidgetPrivate::primaryScreen = 0; |
|
89 QDesktopWidgetPrivate::EnumFunc QDesktopWidgetPrivate::enumDisplayMonitors = 0; |
|
90 QDesktopWidgetPrivate::InfoFunc QDesktopWidgetPrivate::getMonitorInfo = 0; |
|
91 QVector<QRect> *QDesktopWidgetPrivate::rects = 0; |
|
92 QVector<QRect> *QDesktopWidgetPrivate::workrects = 0; |
|
93 static int screen_number = 0; |
|
94 int QDesktopWidgetPrivate::refcount = 0; |
|
95 #ifdef Q_WS_WINCE_WM |
|
96 // Use SIP information, if available |
|
97 // SipGetInfo is not supported by SSDK (no definition!). |
|
98 static inline void qt_get_sip_info(QRect &rect) |
|
99 { |
|
100 SIPINFO sip; |
|
101 memset(&sip, 0, sizeof(SIPINFO)); |
|
102 sip.cbSize = sizeof(SIPINFO); |
|
103 if (SipGetInfo(&sip)) |
|
104 rect = QRect(QPoint(sip.rcVisibleDesktop.left, sip.rcVisibleDesktop.top), |
|
105 QPoint(sip.rcVisibleDesktop.right - 1, sip.rcVisibleDesktop.bottom - 1)); |
|
106 } |
|
107 #endif |
|
108 |
|
109 |
|
110 BOOL CALLBACK enumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM) |
|
111 { |
|
112 QDesktopWidgetPrivate::screenCount++; |
|
113 QDesktopWidgetPrivate::rects->resize(QDesktopWidgetPrivate::screenCount); |
|
114 QDesktopWidgetPrivate::workrects->resize(QDesktopWidgetPrivate::screenCount); |
|
115 // Get the MONITORINFO block |
|
116 QDesktopWidgetPrivate::MONITORINFO info; |
|
117 memset(&info, 0, sizeof(QDesktopWidgetPrivate::MONITORINFO)); |
|
118 info.cbSize = sizeof(QDesktopWidgetPrivate::MONITORINFO); |
|
119 BOOL res = QDesktopWidgetPrivate::getMonitorInfo(hMonitor, &info); |
|
120 if (!res) { |
|
121 (*QDesktopWidgetPrivate::rects)[screen_number] = QRect(); |
|
122 (*QDesktopWidgetPrivate::workrects)[screen_number] = QRect(); |
|
123 return true; |
|
124 } |
|
125 |
|
126 // Fill list of rects |
|
127 RECT r = info.rcMonitor; |
|
128 QRect qr(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1)); |
|
129 (*QDesktopWidgetPrivate::rects)[screen_number] = qr; |
|
130 |
|
131 r = info.rcWork; |
|
132 qr = QRect(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1)); |
|
133 (*QDesktopWidgetPrivate::workrects)[screen_number] = qr; |
|
134 |
|
135 if (info.dwFlags & 0x00000001) //MONITORINFOF_PRIMARY |
|
136 QDesktopWidgetPrivate::primaryScreen = screen_number; |
|
137 |
|
138 ++screen_number; |
|
139 // Stop the enumeration if we have them all |
|
140 return true; |
|
141 } |
|
142 |
|
143 QDesktopWidgetPrivate::QDesktopWidgetPrivate() |
|
144 { |
|
145 ++refcount; |
|
146 } |
|
147 |
|
148 void QDesktopWidgetPrivate::init(QDesktopWidget *that) |
|
149 { |
|
150 if (rects) |
|
151 return; |
|
152 |
|
153 rects = new QVector<QRect>(); |
|
154 workrects = new QVector<QRect>(); |
|
155 screenCount = 0; |
|
156 |
|
157 #ifndef Q_OS_WINCE |
|
158 QLibrary user32Lib(QLatin1String("user32")); |
|
159 if (user32Lib.load()) { |
|
160 enumDisplayMonitors = (EnumFunc)user32Lib.resolve("EnumDisplayMonitors"); |
|
161 getMonitorInfo = (InfoFunc)user32Lib.resolve("GetMonitorInfoW"); |
|
162 } |
|
163 |
|
164 if (!enumDisplayMonitors || !getMonitorInfo) { |
|
165 screenCount = GetSystemMetrics(80); // SM_CMONITORS |
|
166 rects->resize(screenCount); |
|
167 for (int i = 0; i < screenCount; ++i) |
|
168 rects->replace(i, that->rect()); |
|
169 return; |
|
170 } |
|
171 // Calls enumCallback |
|
172 enumDisplayMonitors(0, 0, enumCallback, 0); |
|
173 enumDisplayMonitors = 0; |
|
174 getMonitorInfo = 0; |
|
175 #else |
|
176 QLibrary coreLib(QLatin1String("coredll")); |
|
177 if (coreLib.load()) { |
|
178 // CE >= 4.0 case |
|
179 enumDisplayMonitors = (EnumFunc)coreLib.resolve("EnumDisplayMonitors"); |
|
180 getMonitorInfo = (InfoFunc)coreLib.resolve("GetMonitorInfo"); |
|
181 } |
|
182 |
|
183 if ((!enumDisplayMonitors || !getMonitorInfo)) { |
|
184 screenCount = GetSystemMetrics(SM_CMONITORS); |
|
185 return; |
|
186 } |
|
187 |
|
188 if (!coreLib.isLoaded() || !enumDisplayMonitors || !getMonitorInfo) { |
|
189 rects->resize(screenCount); |
|
190 for (int i = 0; i < screenCount; ++i) |
|
191 (*rects)[i] = that->rect(); |
|
192 |
|
193 RECT r; |
|
194 SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); |
|
195 QRect qr = QRect(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1)); |
|
196 |
|
197 #if defined(Q_WS_WINCE_WM) |
|
198 qt_get_sip_info(qr); |
|
199 #endif |
|
200 |
|
201 workrects->resize(screenCount); |
|
202 for (int j = 0; j < screenCount; ++j) |
|
203 (*workrects)[j] = qr; |
|
204 return; |
|
205 } |
|
206 |
|
207 // Calls enumCallback |
|
208 enumDisplayMonitors(0, 0, enumCallback, 0); |
|
209 enumDisplayMonitors = 0; |
|
210 getMonitorInfo = 0; |
|
211 #endif // Q_WS_WINCE |
|
212 } |
|
213 |
|
214 QDesktopWidgetPrivate::~QDesktopWidgetPrivate() |
|
215 { |
|
216 if (!--refcount) |
|
217 cleanup(); |
|
218 } |
|
219 |
|
220 void QDesktopWidgetPrivate::cleanup() |
|
221 { |
|
222 screen_number = 0; |
|
223 screenCount = 1; |
|
224 primaryScreen = 0; |
|
225 enumDisplayMonitors = 0; |
|
226 getMonitorInfo = 0; |
|
227 delete rects; |
|
228 rects = 0; |
|
229 delete workrects; |
|
230 workrects = 0; |
|
231 } |
|
232 |
|
233 /* |
|
234 \omit |
|
235 Function is commented out in header |
|
236 \fn void *QDesktopWidget::handle(int screen) const |
|
237 |
|
238 Returns the window system handle of the display device with the |
|
239 index \a screen, for low-level access. Using this function is not |
|
240 portable. |
|
241 |
|
242 The return type varies with platform; see qwindowdefs.h for details. |
|
243 |
|
244 \sa x11Display(), QPaintDevice::handle() |
|
245 \endomit |
|
246 */ |
|
247 |
|
248 QDesktopWidget::QDesktopWidget() |
|
249 : QWidget(*new QDesktopWidgetPrivate, 0, Qt::Desktop) |
|
250 { |
|
251 setObjectName(QLatin1String("desktop")); |
|
252 QDesktopWidgetPrivate::init(this); |
|
253 } |
|
254 |
|
255 QDesktopWidget::~QDesktopWidget() |
|
256 { |
|
257 } |
|
258 |
|
259 bool QDesktopWidget::isVirtualDesktop() const |
|
260 { |
|
261 return true; |
|
262 } |
|
263 |
|
264 int QDesktopWidget::primaryScreen() const |
|
265 { |
|
266 return d_func()->primaryScreen; |
|
267 } |
|
268 |
|
269 int QDesktopWidget::numScreens() const |
|
270 { |
|
271 return d_func()->screenCount; |
|
272 } |
|
273 |
|
274 QWidget *QDesktopWidget::screen(int /* screen */) |
|
275 { |
|
276 // It seems that a Qt::WType_Desktop cannot be moved? |
|
277 return this; |
|
278 } |
|
279 |
|
280 // |
|
281 // MSVC 7.10 warns that d (the result of the expanded Q_D macro) as a local variable that is not referenced. |
|
282 // Therefore, we ignore that warning with the following pragmas |
|
283 // I've also tried to eliminate the macro, but to no use... |
|
284 // We pop it further down |
|
285 #ifdef Q_CC_MSVC |
|
286 # pragma warning(push) |
|
287 # pragma warning(disable : 4189) |
|
288 #endif |
|
289 const QRect QDesktopWidget::availableGeometry(int screen) const |
|
290 { |
|
291 Q_D(const QDesktopWidget); |
|
292 #ifdef Q_WS_WINCE_WM |
|
293 for(int i=0; i < d->workrects->size(); ++i) |
|
294 qt_get_sip_info((*d->workrects)[i]); |
|
295 #endif |
|
296 if (screen < 0 || screen >= d->screenCount) |
|
297 screen = d->primaryScreen; |
|
298 |
|
299 return d->workrects->at(screen); |
|
300 } |
|
301 |
|
302 const QRect QDesktopWidget::screenGeometry(int screen) const |
|
303 { |
|
304 const QDesktopWidgetPrivate *d = d_func(); |
|
305 if (screen < 0 || screen >= d->screenCount) |
|
306 screen = d->primaryScreen; |
|
307 |
|
308 return d->rects->at(screen); |
|
309 } |
|
310 |
|
311 int QDesktopWidget::screenNumber(const QWidget *widget) const |
|
312 { |
|
313 Q_D(const QDesktopWidget); |
|
314 if (!widget) |
|
315 return d->primaryScreen; |
|
316 |
|
317 QRect frame = widget->frameGeometry(); |
|
318 if (!widget->isWindow()) |
|
319 frame.moveTopLeft(widget->mapToGlobal(QPoint(0,0))); |
|
320 |
|
321 int maxSize = -1; |
|
322 int maxScreen = -1; |
|
323 |
|
324 for (int i = 0; i < d->screenCount; ++i) { |
|
325 QRect sect = d->rects->at(i).intersected(frame); |
|
326 int size = sect.width() * sect.height(); |
|
327 if (size > maxSize && sect.width() > 0 && sect.height() > 0) { |
|
328 maxSize = size; |
|
329 maxScreen = i; |
|
330 } |
|
331 } |
|
332 |
|
333 return maxScreen; |
|
334 } |
|
335 |
|
336 int QDesktopWidget::screenNumber(const QPoint &point) const |
|
337 { |
|
338 Q_D(const QDesktopWidget); |
|
339 |
|
340 int closestScreen = -1; |
|
341 int shortestDistance = INT_MAX; |
|
342 |
|
343 for (int i = 0; i < d->screenCount; ++i) { |
|
344 int thisDistance = d->pointToRect(point, d->rects->at(i)); |
|
345 if (thisDistance < shortestDistance) { |
|
346 shortestDistance = thisDistance; |
|
347 closestScreen = i; |
|
348 } |
|
349 } |
|
350 |
|
351 return closestScreen; |
|
352 } |
|
353 |
|
354 void QDesktopWidget::resizeEvent(QResizeEvent *) |
|
355 { |
|
356 Q_D(QDesktopWidget); |
|
357 const QVector<QRect> oldrects(*d->rects); |
|
358 const QVector<QRect> oldworkrects(*d->workrects); |
|
359 int oldscreencount = d->screenCount; |
|
360 |
|
361 QDesktopWidgetPrivate::cleanup(); |
|
362 QDesktopWidgetPrivate::init(this); |
|
363 #ifdef Q_WS_WINCE_WM |
|
364 for(int i=0; i < d->workrects->size(); ++i) |
|
365 qt_get_sip_info((*d->workrects)[i]); |
|
366 #endif |
|
367 |
|
368 for (int i = 0; i < qMin(oldscreencount, d->screenCount); ++i) { |
|
369 const QRect oldrect = oldrects[i]; |
|
370 const QRect newrect = d->rects->at(i); |
|
371 if (oldrect != newrect) |
|
372 emit resized(i); |
|
373 } |
|
374 |
|
375 for (int j = 0; j < qMin(oldscreencount, d->screenCount); ++j) { |
|
376 const QRect oldrect = oldworkrects[j]; |
|
377 const QRect newrect = d->workrects->at(j); |
|
378 if (oldrect != newrect) |
|
379 emit workAreaResized(j); |
|
380 } |
|
381 |
|
382 if (oldscreencount != d->screenCount) { |
|
383 emit screenCountChanged(d->screenCount); |
|
384 } |
|
385 } |
|
386 |
|
387 #ifdef Q_CC_MSVC |
|
388 # pragma warning(pop) |
|
389 #endif |
|
390 |
|
391 QT_END_NAMESPACE |