summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>2012-01-20 11:34:09 +0100
committerQt by Nokia <qt-info@nokia.com>2012-01-20 14:17:41 +0100
commitfc366046b42e4aa9f10efa81b978c89cfb7206a2 (patch)
treea25f5077c49c1b265e8785a1fa57d744ac0a9f2c
parent688d463f4ad4ebe62533d416c956d3a30ccfc0a6 (diff)
Windows: Work on QPlatformScreen implementation.
Implement virtual desktops (which is the default for EnumDisplayMonitors) and change notifications. Change-Id: Id24a1b6d9766903901ddf1ded8e9933aa03589d4 Reviewed-by: Oliver Wolff <oliver.wolff@nokia.com>
-rw-r--r--src/plugins/platforms/windows/qtwindowsglobal.h3
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp9
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp3
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp3
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp212
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.h43
8 files changed, 239 insertions, 38 deletions
diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h
index 599fb0d201..02e29fbd7f 100644
--- a/src/plugins/platforms/windows/qtwindowsglobal.h
+++ b/src/plugins/platforms/windows/qtwindowsglobal.h
@@ -95,6 +95,7 @@ enum WindowsEventType // Simplify event types
InputMethodOpenCandidateWindowEvent = InputMethodEventFlag + 4,
InputMethodCloseCandidateWindowEvent = InputMethodEventFlag + 5,
InputMethodRequest = InputMethodEventFlag + 6,
+ DisplayChangedEvent = 437,
UnknownEvent = 542
};
@@ -169,6 +170,8 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
}
case WM_GETOBJECT:
return QtWindows::AccessibleObjectFromWindowRequest;
+ case WM_DISPLAYCHANGE:
+ return QtWindows::DisplayChangedEvent;
default:
break;
}
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 4f42f7fa3b..d0d9279d0a 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -48,6 +48,7 @@
#include "qwindowsmime.h"
#include "qwindowsinputcontext.h"
#include "qwindowsaccessibility.h"
+#include "qwindowsscreen.h"
#include <QtGui/QWindow>
#include <QtGui/QWindowSystemInterface>
@@ -228,6 +229,7 @@ struct QWindowsContextPrivate {
QWindowsKeyMapper m_keyMapper;
QWindowsMouseHandler m_mouseHandler;
QWindowsMimeConverter m_mimeConverter;
+ QWindowsScreenManager m_screenManager;
QSharedPointer<QWindowCreationContext> m_creationContext;
const HRESULT m_oleInitializeResult;
};
@@ -541,6 +543,11 @@ QWindowsMimeConverter &QWindowsContext::mimeConverter() const
return d->m_mimeConverter;
}
+QWindowsScreenManager &QWindowsContext::screenManager()
+{
+ return d->m_screenManager;
+}
+
/*!
\brief Convenience to create a non-visible, message-only dummy
window for example used as clipboard watcher or for GL.
@@ -641,6 +648,8 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
return false;
case QtWindows::AccessibleObjectFromWindowRequest:
return QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(hwnd, wParam, lParam, result);
+ case QtWindows::DisplayChangedEvent:
+ return d->m_screenManager.handleDisplayChange(wParam, lParam);
default:
break;
}
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
index 9a8acbbb51..c6b3d46e13 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -52,6 +52,7 @@ QT_BEGIN_NAMESPACE
class QWindow;
class QPlatformScreen;
+class QWindowsScreenManager;
class QWindowsWindow;
class QWindowsMimeConverter;
struct QWindowCreationContext;
@@ -162,6 +163,7 @@ public:
unsigned systemInfo() const;
QWindowsMimeConverter &mimeConverter() const;
+ QWindowsScreenManager &screenManager();
static QWindowsUser32DLL user32dll;
static QWindowsShell32DLL shell32dll;
diff --git a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp
index 4dd409a2ab..f5447798c2 100644
--- a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp
+++ b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp
@@ -202,7 +202,8 @@ messageDebugEntries[] = {
{WM_IME_COMPOSITION, "WM_IME_COMPOSITION"},
{WM_IME_ENDCOMPOSITION, "WM_IME_ENDCOMPOSITION"},
{WM_IME_NOTIFY, "WM_IME_NOTIFY"},
- {WM_IME_REQUEST, "WM_IME_REQUEST"}
+ {WM_IME_REQUEST, "WM_IME_REQUEST"},
+ {WM_DISPLAYCHANGE, "WM_DISPLAYCHANGE"}
};
static inline const MessageDebugEntry *messageDebugEntry(UINT msg)
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 8bb8bafe74..41990e7529 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -178,8 +178,7 @@ QWindowsIntegration::QWindowsIntegration() :
{
QGuiApplicationPrivate::instance()->setEventDispatcher(d->m_eventDispatcher);
d->m_clipboard.registerViewer();
- foreach (QPlatformScreen *pscr, QWindowsScreen::screens())
- screenAdded(pscr);
+ d->m_context.screenManager().handleScreenChanges();
}
QWindowsIntegration::~QWindowsIntegration()
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index fa133fa5de..d09605a30d 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -74,6 +74,8 @@ public:
static QWindowsIntegration *instance();
+ inline void emitScreenAdded(QPlatformScreen *s) { screenAdded(s); }
+
private:
QScopedPointer<QWindowsIntegrationPrivate> d;
};
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index aadc6ec986..d47dc08f39 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -42,12 +42,15 @@
#include "qwindowsscreen.h"
#include "qwindowscontext.h"
#include "qwindowswindow.h"
+#include "qwindowsintegration.h"
#include "qwindowscursor.h"
+#include "qwindowscontext.h"
#include "qtwindows_additional.h"
#include <QtGui/QPixmap>
#include <QtGui/QGuiApplication>
+#include <QtGui/QWindowSystemInterface>
#include <QtGui/QScreen>
#include <QtCore/QDebug>
@@ -55,9 +58,8 @@
QT_BEGIN_NAMESPACE
QWindowsScreenData::QWindowsScreenData() :
- dpi(96, 96),
- depth(32),
- format(QImage::Format_ARGB32_Premultiplied), primary(false)
+ dpi(96, 96), depth(32), format(QImage::Format_ARGB32_Premultiplied),
+ flags(VirtualDesktop), orientation(Qt::LandscapeOrientation)
{
}
@@ -98,6 +100,8 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM
data.geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1));
if (HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL)) {
data.dpi = deviceDPI(hdc);
+ data.depth = GetDeviceCaps(hdc, BITSPIXEL);
+ data.format = data.depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32;
data.physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE));
DeleteDC(hdc);
} else {
@@ -107,16 +111,47 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM
}
data.geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1));
data.availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1));
- data.primary = (info.dwFlags & MONITORINFOF_PRIMARY) != 0;
+ data.orientation = data.geometry.height() > data.geometry.width() ?
+ Qt::PortraitOrientation : Qt::LandscapeOrientation;
+ // EnumDisplayMonitors (as opposed to EnumDisplayDevices) enumerates only
+ // virtual desktop screens.
+ data.flags = QWindowsScreenData::VirtualDesktop;
+ if (info.dwFlags & MONITORINFOF_PRIMARY)
+ data.flags |= QWindowsScreenData::PrimaryScreen;
data.name = QString::fromWCharArray(info.szDevice);
result->append(data);
return TRUE;
}
+static inline WindowsScreenDataList monitorData()
+{
+ WindowsScreenDataList result;
+ EnumDisplayMonitors(0, 0, monitorEnumCallback, (LPARAM)&result);
+ return result;
+}
+
+static QDebug operator<<(QDebug dbg, const QWindowsScreenData &d)
+{
+ QDebug nospace = dbg.nospace();
+ nospace << "Screen " << d.name << ' '
+ << d.geometry.width() << 'x' << d.geometry.height() << '+' << d.geometry.x() << '+' << d.geometry.y()
+ << " avail: "
+ << d.availableGeometry.width() << 'x' << d.availableGeometry.height() << '+' << d.availableGeometry.x() << '+' << d.availableGeometry.y()
+ << " physical: " << d.physicalSizeMM.width() << 'x' << d.physicalSizeMM.height()
+ << " DPI: " << d.dpi.first << 'x' << d.dpi.second << " Depth: " << d.depth
+ << " Format: " << d.format;
+ if (d.flags & QWindowsScreenData::PrimaryScreen)
+ nospace << " primary";
+ if (d.flags & QWindowsScreenData::VirtualDesktop)
+ nospace << " virtual desktop";
+ return dbg;
+}
+
/*!
\class QWindowsScreen
\brief Windows screen.
\ingroup qt-lighthouse-win
+ \sa QWindowsScreenManager
*/
QWindowsScreen::QWindowsScreen(const QWindowsScreenData &data) :
@@ -124,30 +159,6 @@ QWindowsScreen::QWindowsScreen(const QWindowsScreenData &data) :
{
}
-QList<QPlatformScreen *> QWindowsScreen::screens()
-{
- // Retrieve monitors and add static depth information to each.
- WindowsScreenDataList data;
- EnumDisplayMonitors(0, 0, monitorEnumCallback, (LPARAM)&data);
-
- const int depth = QWindowsContext::instance()->screenDepth();
- const QImage::Format format = depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32;
- QList<QPlatformScreen *> result;
-
- const WindowsScreenDataList::const_iterator scend = data.constEnd();
- for (WindowsScreenDataList::const_iterator it = data.constBegin(); it != scend; ++it) {
- QWindowsScreenData d = *it;
- d.depth = depth;
- d.format = format;
- if (QWindowsContext::verboseIntegration)
- qDebug() << "Screen" << d.geometry << d.availableGeometry << d.primary
- << " physical " << d.physicalSizeMM << " DPI" << d.dpi
- << "Depth: " << d.depth << " Format: " << d.format;
- result.append(new QWindowsScreen(d));
- }
- return result;
-}
-
QPixmap QWindowsScreen::grabWindow(WId window, int x, int y, int width, int height) const
{
Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0);
@@ -227,4 +238,149 @@ QWindowsScreen *QWindowsScreen::screenOf(const QWindow *w)
return 0;
}
+/*!
+ \brief Determine siblings in a virtual desktop system.
+
+ Self is by definition a sibling, else collect all screens
+ within virtual desktop.
+*/
+
+QList<QPlatformScreen *> QWindowsScreen::virtualSiblings() const
+{
+ QList<QPlatformScreen *> result;
+ if (m_data.flags & QWindowsScreenData::VirtualDesktop) {
+ foreach (QWindowsScreen *screen, QWindowsContext::instance()->screenManager().screens())
+ if (screen->data().flags & QWindowsScreenData::VirtualDesktop)
+ result.push_back(screen);
+ } else {
+ result.push_back(const_cast<QWindowsScreen *>(this));
+ }
+ return result;
+}
+
+/*!
+ \brief Notify QWindowSystemInterface about changes of a screen and synchronize data.
+*/
+
+void QWindowsScreen::handleChanges(const QWindowsScreenData &newData)
+{
+ if (m_data.geometry != newData.geometry) {
+ m_data.geometry = newData.geometry;
+ QWindowSystemInterface::handleScreenGeometryChange(screen(),
+ newData.geometry);
+ }
+ if (m_data.availableGeometry != newData.availableGeometry) {
+ m_data.availableGeometry = newData.availableGeometry;
+ QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(),
+ newData.availableGeometry);
+ }
+ if (!qFuzzyCompare(m_data.dpi.first, newData.dpi.first)
+ || !qFuzzyCompare(m_data.dpi.second, newData.dpi.second)) {
+ m_data.dpi = newData.dpi;
+ QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(),
+ newData.dpi.first,
+ newData.dpi.second);
+ }
+ if (m_data.orientation != newData.orientation) {
+ m_data.orientation = newData.orientation;
+ QWindowSystemInterface::handleScreenOrientationChange(screen(),
+ newData.orientation);
+ }
+}
+
+/*!
+ \class QWindowsScreenManager
+ \brief Manages a list of QWindowsScreen.
+
+ Listens for changes and notifies QWindowSystemInterface about changed/
+ added/deleted screens.
+
+ \ingroup qt-lighthouse-win
+ \sa QWindowsScreen
+*/
+
+QWindowsScreenManager::QWindowsScreenManager() :
+ m_lastDepth(-1), m_lastHorizontalResolution(0), m_lastVerticalResolution(0)
+{
+}
+
+QWindowsScreenManager::~QWindowsScreenManager()
+{
+ qDeleteAll(m_screens);
+}
+
+/*!
+ \brief Triggers synchronization of screens (WM_DISPLAYCHANGE).
+
+ Subsequent events are compressed since WM_DISPLAYCHANGE is sent to
+ each top level window.
+*/
+
+bool QWindowsScreenManager::handleDisplayChange(WPARAM wParam, LPARAM lParam)
+{
+ const int newDepth = (int)wParam;
+ const WORD newHorizontalResolution = LOWORD(lParam);
+ const WORD newVerticalResolution = HIWORD(lParam);
+ if (newDepth != m_lastDepth || newHorizontalResolution != m_lastHorizontalResolution
+ || newVerticalResolution != m_lastVerticalResolution) {
+ m_lastDepth = newDepth;
+ m_lastHorizontalResolution = newHorizontalResolution;
+ m_lastVerticalResolution = newVerticalResolution;
+ if (QWindowsContext::verboseWindows)
+ qDebug("%s: Depth=%d, resolution=%hux%hu",
+ __FUNCTION__, newDepth, newHorizontalResolution, newVerticalResolution);
+ handleScreenChanges();
+ }
+ return false;
+}
+
+static inline int indexOfMonitor(const QList<QWindowsScreen *> &screens,
+ const QString &monitorName)
+{
+ for (int i= 0; i < screens.size(); ++i)
+ if (screens.at(i)->data().name == monitorName)
+ return i;
+ return -1;
+}
+
+static inline int indexOfMonitor(const QList<QWindowsScreenData> &screenData,
+ const QString &monitorName)
+{
+ for (int i = 0; i < screenData.size(); ++i)
+ if (screenData.at(i).name == monitorName)
+ return i;
+ return -1;
+}
+
+/*!
+ \brief Synchronizes the screen list, adds new screens, removes deleted
+ ones and propagates resolution changes to QWindowSystemInterface.
+*/
+
+void QWindowsScreenManager::handleScreenChanges()
+{
+ // Look for changed monitors, add new ones
+ const WindowsScreenDataList newDataList = monitorData();
+ foreach (const QWindowsScreenData &newData, newDataList) {
+ const int existingIndex = indexOfMonitor(m_screens, newData.name);
+ if (existingIndex != -1) {
+ m_screens.at(existingIndex)->handleChanges(newData);
+ } else {
+ QWindowsScreen *newScreen = new QWindowsScreen(newData);
+ m_screens.push_back(newScreen);
+ QWindowsIntegration::instance()->emitScreenAdded(newScreen);
+ if (QWindowsContext::verboseWindows)
+ qDebug() << "New Monitor: " << newData;
+ } // exists
+ } // for new screens.
+ // Remove deleted ones.
+ for (int i = m_screens.size() - 1; i >= 0; --i) {
+ if (indexOfMonitor(newDataList, m_screens.at(i)->data().name) == -1) {
+ if (QWindowsContext::verboseWindows)
+ qDebug() << "Removing Monitor: " << m_screens.at(i) ->data();
+ delete m_screens.takeAt(i);
+ } // not found
+ } // for existing screens
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h
index a7b9ba7fcc..bf81087e39 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.h
+++ b/src/plugins/platforms/windows/qwindowsscreen.h
@@ -52,6 +52,12 @@ QT_BEGIN_NAMESPACE
struct QWindowsScreenData
{
+ enum Flags
+ {
+ PrimaryScreen = 0x1,
+ VirtualDesktop = 0x2
+ };
+
QWindowsScreenData();
QRect geometry;
@@ -60,8 +66,9 @@ struct QWindowsScreenData
QSizeF physicalSizeMM;
int depth;
QImage::Format format;
- bool primary;
+ unsigned flags;
QString name;
+ Qt::ScreenOrientation orientation;
};
class QWindowsScreen : public QPlatformScreen
@@ -78,7 +85,8 @@ public:
virtual QSizeF physicalSize() const { return m_data.physicalSizeMM; }
virtual QDpi logicalDpi() const { return m_data.dpi; }
virtual QString name() const { return m_data.name; }
-
+ virtual Qt::ScreenOrientation primaryOrientation() { return m_data.orientation; }
+ virtual QList<QPlatformScreen *> virtualSiblings() const;
virtual QWindow *topLevelAt(const QPoint &point) const
{ return QWindowsScreen::findTopLevelAt(point, CWP_SKIPINVISIBLE); }
@@ -86,18 +94,39 @@ public:
static QWindow *windowAt(const QPoint &point, unsigned flags = CWP_SKIPINVISIBLE);
static QWindow *windowUnderMouse(unsigned flags = CWP_SKIPINVISIBLE);
- static QList<QPlatformScreen *> screens();
-
virtual QPixmap grabWindow(WId window, int x, int y, int width, int height) const;
- const QWindowsCursor &cursor() const { return m_cursor; }
- QWindowsCursor &cursor() { return m_cursor; }
+ inline void handleChanges(const QWindowsScreenData &newData);
+
+ const QWindowsCursor &cursor() const { return m_cursor; }
+ QWindowsCursor &cursor() { return m_cursor; }
+
+ const QWindowsScreenData &data() const { return m_data; }
private:
- const QWindowsScreenData m_data;
+ QWindowsScreenData m_data;
QWindowsCursor m_cursor;
};
+class QWindowsScreenManager
+{
+public:
+ typedef QList<QWindowsScreen *> WindowsScreenList;
+
+ QWindowsScreenManager();
+ ~QWindowsScreenManager();
+
+ void handleScreenChanges();
+ bool handleDisplayChange(WPARAM wParam, LPARAM lParam);
+ const WindowsScreenList &screens() const { return m_screens; }
+
+private:
+ WindowsScreenList m_screens;
+ int m_lastDepth;
+ WORD m_lastHorizontalResolution;
+ WORD m_lastVerticalResolution;
+};
+
QT_END_NAMESPACE
#endif // QWINDOWSSCREEN_H