blob: 1f8800272b72e74d0aac1680d1bb754516ad4d9d [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QWINDOWSWINDOW_H
#define QWINDOWSWINDOW_H
#include <QtCore/qt_windows.h>
#include <QtCore/qpointer.h>
#include "qwindowscursor.h"
#include <qpa/qplatformwindow.h>
#include <QtPlatformHeaders/qwindowswindowfunctions.h>
#if QT_CONFIG(vulkan)
#include "qwindowsvulkaninstance.h"
#endif
QT_BEGIN_NAMESPACE
class QWindowsOleDropTarget;
class QWindowsMenuBar;
class QDebug;
struct QWindowsGeometryHint
{
static QMargins frameOnPrimaryScreen(DWORD style, DWORD exStyle);
static QMargins frameOnPrimaryScreen(HWND hwnd);
static QMargins frame(DWORD style, DWORD exStyle, qreal dpi);
static QMargins frame(HWND hwnd, DWORD style, DWORD exStyle);
static QMargins frame(const QWindow *w, const QRect &geometry,
DWORD style, DWORD exStyle);
static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result);
static void applyToMinMaxInfo(const QWindow *w, const QScreen *screen,
const QMargins &margins, MINMAXINFO *mmi);
static void applyToMinMaxInfo(const QWindow *w, const QMargins &margins,
MINMAXINFO *mmi);
static void frameSizeConstraints(const QWindow *w, const QScreen *screen,
const QMargins &margins,
QSize *minimumSize, QSize *maximumSize);
static inline QPoint mapToGlobal(HWND hwnd, const QPoint &);
static inline QPoint mapToGlobal(const QWindow *w, const QPoint &);
static inline QPoint mapFromGlobal(const HWND hwnd, const QPoint &);
static inline QPoint mapFromGlobal(const QWindow *w, const QPoint &);
static bool positionIncludesFrame(const QWindow *w);
};
struct QWindowCreationContext
{
explicit QWindowCreationContext(const QWindow *w, const QScreen *s,
const QRect &geometryIn, const QRect &geometry,
const QMargins &customMargins,
DWORD style, DWORD exStyle);
void applyToMinMaxInfo(MINMAXINFO *mmi) const;
const QWindow *window;
// The screen to use to scale size constraints, etc. Might differ from the
// screen of the window after QPlatformWindow::initialGeometry() (QTBUG-77307).
const QScreen *screen;
QRect requestedGeometryIn; // QWindow scaled
QRect requestedGeometry; // after QPlatformWindow::initialGeometry()
QPoint obtainedPos;
QSize obtainedSize;
QMargins margins;
QMargins customMargins; // User-defined, additional frame for WM_NCCALCSIZE
int frameX = CW_USEDEFAULT; // Passed on to CreateWindowEx(), including frame.
int frameY = CW_USEDEFAULT;
int frameWidth = CW_USEDEFAULT;
int frameHeight = CW_USEDEFAULT;
int menuHeight = 0;
};
struct QWindowsWindowData
{
Qt::WindowFlags flags;
QRect geometry;
QMargins fullFrameMargins; // Do not use directly for windows, see FrameDirty.
QMargins customMargins; // User-defined, additional frame for NCCALCSIZE
HWND hwnd = nullptr;
bool embedded = false;
bool hasFrame = false;
static QWindowsWindowData create(const QWindow *w,
const QWindowsWindowData &parameters,
const QString &title);
};
class QWindowsBaseWindow : public QPlatformWindow
{
Q_DISABLE_COPY_MOVE(QWindowsBaseWindow)
public:
explicit QWindowsBaseWindow(QWindow *window) : QPlatformWindow(window) {}
WId winId() const override { return WId(handle()); }
QRect geometry() const override { return geometry_sys(); }
QMargins frameMargins() const override { return fullFrameMargins(); }
QPoint mapToGlobal(const QPoint &pos) const override;
QPoint mapFromGlobal(const QPoint &pos) const override;
virtual QMargins fullFrameMargins() const { return frameMargins_sys(); }
using QPlatformWindow::screenForGeometry;
virtual HWND handle() const = 0;
virtual bool isTopLevel() const { return isTopLevel_sys(); }
unsigned style() const { return GetWindowLongPtr(handle(), GWL_STYLE); }
unsigned exStyle() const { return GetWindowLongPtr(handle(), GWL_EXSTYLE); }
static bool isRtlLayout(HWND hwnd);
static QWindowsBaseWindow *baseWindowOf(const QWindow *w);
static HWND handleOf(const QWindow *w);
protected:
HWND parentHwnd() const { return GetAncestor(handle(), GA_PARENT); }
bool isTopLevel_sys() const;
QRect frameGeometry_sys() const;
QRect geometry_sys() const;
void setGeometry_sys(const QRect &rect) const;
QMargins frameMargins_sys() const;
void hide_sys();
void raise_sys();
void lower_sys();
void setWindowTitle_sys(const QString &title);
};
class QWindowsDesktopWindow : public QWindowsBaseWindow
{
public:
explicit QWindowsDesktopWindow(QWindow *window)
: QWindowsBaseWindow(window), m_hwnd(GetDesktopWindow()) {}
QMargins frameMargins() const override { return QMargins(); }
bool isTopLevel() const override { return true; }
protected:
HWND handle() const override { return m_hwnd; }
private:
const HWND m_hwnd;
};
class QWindowsForeignWindow : public QWindowsBaseWindow
{
public:
explicit QWindowsForeignWindow(QWindow *window, HWND hwnd);
void setParent(const QPlatformWindow *window) override;
void setGeometry(const QRect &rect) override { setGeometry_sys(rect); }
void setVisible(bool visible) override;
void raise() override { raise_sys(); }
void lower() override { lower_sys(); }
void setWindowTitle(const QString &title) override { setWindowTitle_sys(title); }
bool isForeignWindow() const override { return true; }
protected:
HWND handle() const override { return m_hwnd; }
private:
const HWND m_hwnd;
DWORD m_topLevelStyle;
};
class QWindowsWindow : public QWindowsBaseWindow
{
public:
enum Flags
{
AutoMouseCapture = 0x1, //! Automatic mouse capture on button press.
WithinSetParent = 0x2,
WithinSetGeometry = 0x8,
OpenGLSurface = 0x10,
OpenGL_ES2 = 0x20,
OpenGLDoubleBuffered = 0x40,
OpenGlPixelFormatInitialized = 0x80,
BlockedByModal = 0x100,
SizeGripOperation = 0x200,
FrameStrutEventsEnabled = 0x400,
SynchronousGeometryChangeEvent = 0x800,
WithinSetStyle = 0x1000,
WithinDestroy = 0x2000,
TouchRegistered = 0x4000,
AlertState = 0x8000,
Exposed = 0x10000,
WithinCreate = 0x20000,
WithinMaximize = 0x40000,
MaximizeToFullScreen = 0x80000,
Compositing = 0x100000,
HasBorderInFullScreen = 0x200000,
WithinDpiChanged = 0x400000,
VulkanSurface = 0x800000,
ResizeMoveActive = 0x1000000,
DisableNonClientScaling = 0x2000000
};
QWindowsWindow(QWindow *window, const QWindowsWindowData &data);
~QWindowsWindow() override;
void initialize() override;
using QPlatformWindow::screenForGeometry;
QSurfaceFormat format() const override { return m_format; }
void setGeometry(const QRect &rect) override;
QRect geometry() const override { return m_data.geometry; }
QRect normalGeometry() const override;
void setVisible(bool visible) override;
bool isVisible() const;
bool isExposed() const override { return testFlag(Exposed); }
bool isActive() const override;
bool isAncestorOf(const QPlatformWindow *child) const override;
bool isEmbedded() const override;
QPoint mapToGlobal(const QPoint &pos) const override;
QPoint mapFromGlobal(const QPoint &pos) const override;
void setWindowFlags(Qt::WindowFlags flags) override;
void setWindowState(Qt::WindowStates state) override;
void setParent(const QPlatformWindow *window) override;
void setWindowTitle(const QString &title) override;
void raise() override { raise_sys(); }
void lower() override { lower_sys(); }
bool windowEvent(QEvent *event) override;
void propagateSizeHints() override;
static bool handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &marginsDp);
bool handleGeometryChanging(MSG *message) const;
QMargins frameMargins() const override;
QMargins fullFrameMargins() const override;
void setFullFrameMargins(const QMargins &newMargins);
void updateFullFrameMargins();
void setOpacity(qreal level) override;
void setMask(const QRegion &region) override;
qreal opacity() const { return m_opacity; }
void requestActivateWindow() override;
bool setKeyboardGrabEnabled(bool grab) override;
bool setMouseGrabEnabled(bool grab) override;
inline bool hasMouseCapture() const { return GetCapture() == m_data.hwnd; }
bool startSystemResize(const QPoint &pos, Qt::Corner corner) override;
bool startSystemMove(const QPoint &pos) override;
void setFrameStrutEventsEnabled(bool enabled) override;
bool frameStrutEventsEnabled() const override { return testFlag(FrameStrutEventsEnabled); }
// QWindowsBaseWindow overrides
HWND handle() const override { return m_data.hwnd; }
bool isTopLevel() const override;
QWindowsMenuBar *menuBar() const;
void setMenuBar(QWindowsMenuBar *mb);
QMargins customMargins() const { return m_data.customMargins; }
void setCustomMargins(const QMargins &m);
void setStyle(unsigned s) const;
void setExStyle(unsigned s) const;
bool handleWmPaint(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
void handleMoved();
void handleResized(int wParam);
void handleHidden();
void handleCompositionSettingsChanged();
static void displayChanged();
static void settingsChanged();
static QScreen *forcedScreenForGLWindow(const QWindow *w);
static QWindowsWindow *windowsWindowOf(const QWindow *w);
static QWindow *topLevelOf(QWindow *w);
static inline void *userDataOf(HWND hwnd);
static inline void setUserDataOf(HWND hwnd, void *ud);
static bool setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qreal opacity);
bool isLayered() const;
HDC getDC();
void releaseDC();
void getSizeHints(MINMAXINFO *mmi) const;
bool handleNonClientHitTest(const QPoint &globalPos, LRESULT *result) const;
#ifndef QT_NO_CURSOR
CursorHandlePtr cursor() const { return m_cursor; }
#endif
void setCursor(const CursorHandlePtr &c);
void applyCursor();
inline bool testFlag(unsigned f) const { return (m_flags & f) != 0; }
inline void setFlag(unsigned f) const { m_flags |= f; }
inline void clearFlag(unsigned f) const { m_flags &= ~f; }
void setEnabled(bool enabled);
bool isEnabled() const;
void setWindowIcon(const QIcon &icon) override;
void *surface(void *nativeConfig, int *err);
void invalidateSurface() override;
void aboutToMakeCurrent();
void setAlertState(bool enabled) override;
bool isAlertState() const override { return testFlag(AlertState); }
void alertWindow(int durationMs = 0);
void stopAlertWindow();
enum ScreenChangeMode { FromGeometryChange, FromDpiChange };
void checkForScreenChanged(ScreenChangeMode mode = FromGeometryChange);
static void setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes);
void registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes = QWindowsWindowFunctions::NormalTouch);
static void setHasBorderInFullScreenStatic(QWindow *window, bool border);
static void setHasBorderInFullScreenDefault(bool border);
void setHasBorderInFullScreen(bool border);
static QString formatWindowTitle(const QString &title);
static const char *embeddedNativeParentHandleProperty;
static const char *hasBorderInFullScreenProperty;
private:
inline void show_sys() const;
inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const;
inline bool isFullScreen_sys() const;
inline void setWindowState_sys(Qt::WindowStates newState);
inline void setParent_sys(const QPlatformWindow *parent);
inline void updateTransientParent() const;
void destroyWindow();
inline bool isDropSiteEnabled() const { return m_dropTarget != nullptr; }
void setDropSiteEnabled(bool enabled);
void updateDropSite(bool topLevel);
void handleGeometryChange();
void handleWindowStateChange(Qt::WindowStates state);
inline void destroyIcon();
void fireExpose(const QRegion &region, bool force=false);
mutable QWindowsWindowData m_data;
QPointer<QWindowsMenuBar> m_menuBar;
mutable unsigned m_flags = WithinCreate;
HDC m_hdc = nullptr;
Qt::WindowStates m_windowState = Qt::WindowNoState;
qreal m_opacity = 1;
#ifndef QT_NO_CURSOR
CursorHandlePtr m_cursor;
#endif
QWindowsOleDropTarget *m_dropTarget = nullptr;
unsigned m_savedStyle = 0;
QRect m_savedFrameGeometry;
const QSurfaceFormat m_format;
HICON m_iconSmall = nullptr;
HICON m_iconBig = nullptr;
void *m_surface = nullptr;
static bool m_screenForGLInitialized;
#if QT_CONFIG(vulkan)
// note: intentionally not using void * in order to avoid breaking x86
VkSurfaceKHR m_vkSurface = VK_NULL_HANDLE;
#endif
static bool m_borderInFullScreenDefault;
};
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const RECT &r);
QDebug operator<<(QDebug d, const POINT &);
QDebug operator<<(QDebug d, const MINMAXINFO &i);
QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p);
QDebug operator<<(QDebug d, const WINDOWPLACEMENT &);
QDebug operator<<(QDebug d, const WINDOWPOS &);
QDebug operator<<(QDebug d, const GUID &guid);
#endif // !QT_NO_DEBUG_STREAM
static inline void clientToScreen(HWND hwnd, POINT *wP)
{
if (QWindowsBaseWindow::isRtlLayout(hwnd)) {
RECT clientArea;
GetClientRect(hwnd, &clientArea);
wP->x = clientArea.right - wP->x;
}
ClientToScreen(hwnd, wP);
}
static inline void screenToClient(HWND hwnd, POINT *wP)
{
ScreenToClient(hwnd, wP);
if (QWindowsBaseWindow::isRtlLayout(hwnd)) {
RECT clientArea;
GetClientRect(hwnd, &clientArea);
wP->x = clientArea.right - wP->x;
}
}
// ---------- QWindowsGeometryHint inline functions.
QPoint QWindowsGeometryHint::mapToGlobal(HWND hwnd, const QPoint &qp)
{
POINT p = { qp.x(), qp.y() };
clientToScreen(hwnd, &p);
return QPoint(p.x, p.y);
}
QPoint QWindowsGeometryHint::mapFromGlobal(const HWND hwnd, const QPoint &qp)
{
POINT p = { qp.x(), qp.y() };
screenToClient(hwnd, &p);
return QPoint(p.x, p.y);
}
QPoint QWindowsGeometryHint::mapToGlobal(const QWindow *w, const QPoint &p)
{ return QWindowsGeometryHint::mapToGlobal(QWindowsWindow::handleOf(w), p); }
QPoint QWindowsGeometryHint::mapFromGlobal(const QWindow *w, const QPoint &p)
{ return QWindowsGeometryHint::mapFromGlobal(QWindowsWindow::handleOf(w), p); }
// ---------- QWindowsBaseWindow inline functions.
inline QWindowsWindow *QWindowsWindow::windowsWindowOf(const QWindow *w)
{
if (!w || !w->handle())
return nullptr;
const Qt::WindowType type = w->type();
if (type == Qt::Desktop || w->handle()->isForeignWindow())
return nullptr;
return static_cast<QWindowsWindow *>(w->handle());
}
void *QWindowsWindow::userDataOf(HWND hwnd)
{
return reinterpret_cast<void *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
}
void QWindowsWindow::setUserDataOf(HWND hwnd, void *ud)
{
SetWindowLongPtr(hwnd, GWLP_USERDATA, LONG_PTR(ud));
}
inline void QWindowsWindow::destroyIcon()
{
if (m_iconBig) {
DestroyIcon(m_iconBig);
m_iconBig = nullptr;
}
if (m_iconSmall) {
DestroyIcon(m_iconSmall);
m_iconSmall = nullptr;
}
}
inline bool QWindowsWindow::isLayered() const
{
return GetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE) & WS_EX_LAYERED;
}
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QMargins)
#endif // QWINDOWSWINDOW_H