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>
This commit is contained in:
parent
688d463f4a
commit
fc366046b4
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -74,6 +74,8 @@ public:
|
||||
|
||||
static QWindowsIntegration *instance();
|
||||
|
||||
inline void emitScreenAdded(QPlatformScreen *s) { screenAdded(s); }
|
||||
|
||||
private:
|
||||
QScopedPointer<QWindowsIntegrationPrivate> d;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user