/**************************************************************************** ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this ** file. Please review the following information to ensure the GNU Lesser ** General Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qdesktopwidget.h" #include "qt_windows.h" #include "qapplication_p.h" #include #include #include #ifdef Q_WS_WINCE #include #endif #include "qwidget_p.h" #include "qdebug.h" QT_BEGIN_NAMESPACE class QDesktopWidgetPrivate : public QWidgetPrivate { public: QDesktopWidgetPrivate(); ~QDesktopWidgetPrivate(); static void init(QDesktopWidget *that); static void cleanup(); static int screenCount; static int primaryScreen; static QVector *rects; static QVector *workrects; struct MONITORINFO { DWORD cbSize; RECT rcMonitor; RECT rcWork; DWORD dwFlags; }; typedef BOOL (WINAPI *InfoFunc)(HMONITOR, MONITORINFO*); typedef BOOL (QT_WIN_CALLBACK *EnumProc)(HMONITOR, HDC, LPRECT, LPARAM); typedef BOOL (WINAPI *EnumFunc)(HDC, LPCRECT, EnumProc, LPARAM); static EnumFunc enumDisplayMonitors; static InfoFunc getMonitorInfo; static int refcount; }; int QDesktopWidgetPrivate::screenCount = 1; int QDesktopWidgetPrivate::primaryScreen = 0; QDesktopWidgetPrivate::EnumFunc QDesktopWidgetPrivate::enumDisplayMonitors = 0; QDesktopWidgetPrivate::InfoFunc QDesktopWidgetPrivate::getMonitorInfo = 0; QVector *QDesktopWidgetPrivate::rects = 0; QVector *QDesktopWidgetPrivate::workrects = 0; static int screen_number = 0; int QDesktopWidgetPrivate::refcount = 0; #ifdef Q_WS_WINCE_WM // Use SIP information, if available // SipGetInfo is not supported by SSDK (no definition!). static inline void qt_get_sip_info(QRect &rect) { SIPINFO sip; memset(&sip, 0, sizeof(SIPINFO)); sip.cbSize = sizeof(SIPINFO); if (SipGetInfo(&sip)) rect = QRect(QPoint(sip.rcVisibleDesktop.left, sip.rcVisibleDesktop.top), QPoint(sip.rcVisibleDesktop.right - 1, sip.rcVisibleDesktop.bottom - 1)); } #endif BOOL QT_WIN_CALLBACK enumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM) { QDesktopWidgetPrivate::screenCount++; QDesktopWidgetPrivate::rects->resize(QDesktopWidgetPrivate::screenCount); QDesktopWidgetPrivate::workrects->resize(QDesktopWidgetPrivate::screenCount); // Get the MONITORINFO block QDesktopWidgetPrivate::MONITORINFO info; memset(&info, 0, sizeof(QDesktopWidgetPrivate::MONITORINFO)); info.cbSize = sizeof(QDesktopWidgetPrivate::MONITORINFO); BOOL res = QDesktopWidgetPrivate::getMonitorInfo(hMonitor, &info); if (!res) { (*QDesktopWidgetPrivate::rects)[screen_number] = QRect(); (*QDesktopWidgetPrivate::workrects)[screen_number] = QRect(); return true; } // Fill list of rects RECT r = info.rcMonitor; QRect qr(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1)); (*QDesktopWidgetPrivate::rects)[screen_number] = qr; r = info.rcWork; qr = QRect(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1)); (*QDesktopWidgetPrivate::workrects)[screen_number] = qr; if (info.dwFlags & 0x00000001) //MONITORINFOF_PRIMARY QDesktopWidgetPrivate::primaryScreen = screen_number; ++screen_number; // Stop the enumeration if we have them all return true; } QDesktopWidgetPrivate::QDesktopWidgetPrivate() { ++refcount; } void QDesktopWidgetPrivate::init(QDesktopWidget *that) { if (rects) return; rects = new QVector(); workrects = new QVector(); screenCount = 0; #ifndef Q_OS_WINCE QSystemLibrary user32Lib(QLatin1String("user32")); enumDisplayMonitors = (EnumFunc)user32Lib.resolve("EnumDisplayMonitors"); getMonitorInfo = (InfoFunc)user32Lib.resolve("GetMonitorInfoW"); if (!enumDisplayMonitors || !getMonitorInfo) { screenCount = GetSystemMetrics(80); // SM_CMONITORS rects->resize(screenCount); for (int i = 0; i < screenCount; ++i) rects->replace(i, that->rect()); return; } // Calls enumCallback enumDisplayMonitors(0, 0, enumCallback, 0); enumDisplayMonitors = 0; getMonitorInfo = 0; #else QSystemLibrary coreLib(QLatin1String("coredll")); // CE >= 4.0 case enumDisplayMonitors = (EnumFunc)coreLib.resolve("EnumDisplayMonitors"); getMonitorInfo = (InfoFunc)coreLib.resolve("GetMonitorInfo"); if ((!enumDisplayMonitors || !getMonitorInfo)) { screenCount = GetSystemMetrics(SM_CMONITORS); return; } if (!coreLib.isLoaded() || !enumDisplayMonitors || !getMonitorInfo) { rects->resize(screenCount); for (int i = 0; i < screenCount; ++i) (*rects)[i] = that->rect(); RECT r; SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); QRect qr = QRect(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1)); #if defined(Q_WS_WINCE_WM) qt_get_sip_info(qr); #endif workrects->resize(screenCount); for (int j = 0; j < screenCount; ++j) (*workrects)[j] = qr; return; } // Calls enumCallback enumDisplayMonitors(0, 0, enumCallback, 0); enumDisplayMonitors = 0; getMonitorInfo = 0; #endif // Q_WS_WINCE } QDesktopWidgetPrivate::~QDesktopWidgetPrivate() { if (!--refcount) cleanup(); } void QDesktopWidgetPrivate::cleanup() { screen_number = 0; screenCount = 1; primaryScreen = 0; enumDisplayMonitors = 0; getMonitorInfo = 0; delete rects; rects = 0; delete workrects; workrects = 0; } /* \omit Function is commented out in header \fn void *QDesktopWidget::handle(int screen) const Returns the window system handle of the display device with the index \a screen, for low-level access. Using this function is not portable. The return type varies with platform; see qwindowdefs.h for details. \sa x11Display(), QPaintDevice::handle() \endomit */ QDesktopWidget::QDesktopWidget() : QWidget(*new QDesktopWidgetPrivate, 0, Qt::Desktop) { setObjectName(QLatin1String("desktop")); QDesktopWidgetPrivate::init(this); } QDesktopWidget::~QDesktopWidget() { } bool QDesktopWidget::isVirtualDesktop() const { return true; } int QDesktopWidget::primaryScreen() const { return d_func()->primaryScreen; } int QDesktopWidget::numScreens() const { return d_func()->screenCount; } QWidget *QDesktopWidget::screen(int /* screen */) { // It seems that a Qt::WType_Desktop cannot be moved? return this; } // // MSVC 7.10 warns that d (the result of the expanded Q_D macro) as a local variable that is not referenced. // Therefore, we ignore that warning with the following pragmas // I've also tried to eliminate the macro, but to no use... // We pop it further down #ifdef Q_CC_MSVC # pragma warning(push) # pragma warning(disable : 4189) #endif const QRect QDesktopWidget::availableGeometry(int screen) const { Q_D(const QDesktopWidget); #ifdef Q_WS_WINCE_WM for(int i=0; i < d->workrects->size(); ++i) qt_get_sip_info((*d->workrects)[i]); #endif if (screen < 0 || screen >= d->screenCount) screen = d->primaryScreen; return d->workrects->at(screen); } const QRect QDesktopWidget::screenGeometry(int screen) const { const QDesktopWidgetPrivate *d = d_func(); if (screen < 0 || screen >= d->screenCount) screen = d->primaryScreen; return d->rects->at(screen); } int QDesktopWidget::screenNumber(const QWidget *widget) const { Q_D(const QDesktopWidget); if (!widget) return d->primaryScreen; QRect frame = widget->frameGeometry(); if (!widget->isWindow()) frame.moveTopLeft(widget->mapToGlobal(QPoint(0,0))); int maxSize = -1; int maxScreen = -1; for (int i = 0; i < d->screenCount; ++i) { QRect sect = d->rects->at(i).intersected(frame); int size = sect.width() * sect.height(); if (size > maxSize && sect.width() > 0 && sect.height() > 0) { maxSize = size; maxScreen = i; } } return maxScreen; } int QDesktopWidget::screenNumber(const QPoint &point) const { Q_D(const QDesktopWidget); int closestScreen = -1; int shortestDistance = INT_MAX; for (int i = 0; i < d->screenCount; ++i) { int thisDistance = d->pointToRect(point, d->rects->at(i)); if (thisDistance < shortestDistance) { shortestDistance = thisDistance; closestScreen = i; } } return closestScreen; } void QDesktopWidget::resizeEvent(QResizeEvent *) { Q_D(QDesktopWidget); const QVector oldrects(*d->rects); const QVector oldworkrects(*d->workrects); int oldscreencount = d->screenCount; QDesktopWidgetPrivate::cleanup(); QDesktopWidgetPrivate::init(this); #ifdef Q_WS_WINCE_WM for(int i=0; i < d->workrects->size(); ++i) qt_get_sip_info((*d->workrects)[i]); #endif for (int i = 0; i < qMin(oldscreencount, d->screenCount); ++i) { const QRect oldrect = oldrects[i]; const QRect newrect = d->rects->at(i); if (oldrect != newrect) emit resized(i); } for (int j = 0; j < qMin(oldscreencount, d->screenCount); ++j) { const QRect oldrect = oldworkrects[j]; const QRect newrect = d->workrects->at(j); if (oldrect != newrect) emit workAreaResized(j); } if (oldscreencount != d->screenCount) { emit screenCountChanged(d->screenCount); } } #ifdef Q_CC_MSVC # pragma warning(pop) #endif QT_END_NAMESPACE