/**************************************************************************** ** ** 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 #include #include "qwindowscursor.h" #include #include #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 QMargins &margins, MINMAXINFO *mmi); static void frameSizeConstraints(const QWindow *w, 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 QRect &geometryIn, const QRect &geometry, const QMargins &customMargins, DWORD style, DWORD exStyle); void applyToMinMaxInfo(MINMAXINFO *mmi) const; const QWindow *window; 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 ¶meters, 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 ®ion) 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 ®ion, bool force=false); mutable QWindowsWindowData m_data; QPointer 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(w->handle()); } void *QWindowsWindow::userDataOf(HWND hwnd) { return reinterpret_cast(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