1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qoffscreenwindow.h"
5#include "qoffscreencommon.h"
6
7#include <qpa/qplatformscreen.h>
8#include <qpa/qwindowsysteminterface.h>
9
10#include <private/qwindow_p.h>
11#include <private/qguiapplication_p.h>
12
13QT_BEGIN_NAMESPACE
14
15QOffscreenWindow::QOffscreenWindow(QWindow *window, bool frameMarginsEnabled)
16 : QPlatformWindow(window)
17 , m_positionIncludesFrame(false)
18 , m_visible(false)
19 , m_pendingGeometryChangeOnShow(true)
20 , m_frameMarginsRequested(frameMarginsEnabled)
21{
22 if (window->windowState() == Qt::WindowNoState) {
23 setGeometry(windowGeometry());
24 } else {
25 setWindowState(window->windowStates());
26 }
27
28 static WId counter = 0;
29 m_winId = ++counter;
30
31 m_windowForWinIdHash[m_winId] = this;
32}
33
34QOffscreenWindow::~QOffscreenWindow()
35{
36 if (QOffscreenScreen::windowContainingCursor == this)
37 QOffscreenScreen::windowContainingCursor = nullptr;
38 m_windowForWinIdHash.remove(key: m_winId);
39}
40
41void QOffscreenWindow::setGeometry(const QRect &rect)
42{
43 if (window()->windowState() != Qt::WindowNoState)
44 return;
45
46 m_positionIncludesFrame = qt_window_private(window: window())->positionPolicy == QWindowPrivate::WindowFrameInclusive;
47
48 setFrameMarginsEnabled(m_frameMarginsRequested);
49 setGeometryImpl(rect);
50
51 m_normalGeometry = geometry();
52}
53
54void QOffscreenWindow::setGeometryImpl(const QRect &rect)
55{
56 QRect adjusted = rect;
57 if (adjusted.width() <= 0)
58 adjusted.setWidth(1);
59 if (adjusted.height() <= 0)
60 adjusted.setHeight(1);
61
62 if (m_positionIncludesFrame) {
63 adjusted.translate(dx: m_margins.left(), dy: m_margins.top());
64 } else {
65 // make sure we're not placed off-screen
66 if (adjusted.left() < m_margins.left())
67 adjusted.translate(dx: m_margins.left(), dy: 0);
68 if (adjusted.top() < m_margins.top())
69 adjusted.translate(dx: 0, dy: m_margins.top());
70 }
71
72 QPlatformWindow::setGeometry(adjusted);
73
74 if (m_visible) {
75 QWindowSystemInterface::handleGeometryChange(window: window(), newRect: adjusted);
76 QWindowSystemInterface::handleExposeEvent(window: window(), region: QRect(QPoint(), adjusted.size()));
77 } else {
78 m_pendingGeometryChangeOnShow = true;
79 }
80}
81
82void QOffscreenWindow::setVisible(bool visible)
83{
84 if (visible == m_visible)
85 return;
86
87 if (visible) {
88 if (window()->type() != Qt::ToolTip)
89 QWindowSystemInterface::handleWindowActivated(window: window(), r: Qt::ActiveWindowFocusReason);
90
91 if (m_pendingGeometryChangeOnShow) {
92 m_pendingGeometryChangeOnShow = false;
93 QWindowSystemInterface::handleGeometryChange(window: window(), newRect: geometry());
94 }
95 }
96
97 const QPoint cursorPos = QCursor::pos();
98 if (visible) {
99 QRect rect(QPoint(), geometry().size());
100 QWindowSystemInterface::handleExposeEvent(window: window(), region: rect);
101 if (QWindowPrivate::get(window: window())->isPopup() && QGuiApplicationPrivate::currentMouseWindow) {
102 QWindowSystemInterface::handleLeaveEvent<QWindowSystemInterface::SynchronousDelivery>
103 (window: QGuiApplicationPrivate::currentMouseWindow);
104 }
105 if (geometry().contains(p: cursorPos))
106 QWindowSystemInterface::handleEnterEvent(window: window(),
107 local: window()->mapFromGlobal(pos: cursorPos), global: cursorPos);
108 } else {
109 QWindowSystemInterface::handleExposeEvent(window: window(), region: QRegion());
110 if (window()->type() & Qt::Window) {
111 if (QWindow *windowUnderMouse = QGuiApplication::topLevelAt(pos: cursorPos)) {
112 QWindowSystemInterface::handleEnterEvent(window: windowUnderMouse,
113 local: windowUnderMouse->mapFromGlobal(pos: cursorPos),
114 global: cursorPos);
115 }
116 }
117 }
118
119 m_visible = visible;
120}
121
122void QOffscreenWindow::requestActivateWindow()
123{
124 if (m_visible)
125 QWindowSystemInterface::handleWindowActivated(window: window(), r: Qt::ActiveWindowFocusReason);
126}
127
128WId QOffscreenWindow::winId() const
129{
130 return m_winId;
131}
132
133QMargins QOffscreenWindow::frameMargins() const
134{
135 return m_margins;
136}
137
138void QOffscreenWindow::setFrameMarginsEnabled(bool enabled)
139{
140 if (enabled
141 && !(window()->flags() & Qt::FramelessWindowHint)
142 && (parent() == nullptr)) {
143 m_margins = QMargins(2, 2, 2, 2);
144 } else {
145 m_margins = QMargins(0, 0, 0, 0);
146 }
147}
148
149void QOffscreenWindow::setWindowState(Qt::WindowStates state)
150{
151 setFrameMarginsEnabled(m_frameMarginsRequested && !(state & Qt::WindowFullScreen));
152 m_positionIncludesFrame = false;
153
154 if (state & Qt::WindowMinimized)
155 ; // nothing to do
156 else if (state & Qt::WindowFullScreen)
157 setGeometryImpl(screen()->geometry());
158 else if (state & Qt::WindowMaximized)
159 setGeometryImpl(screen()->availableGeometry().adjusted(xp1: m_margins.left(), yp1: m_margins.top(), xp2: -m_margins.right(), yp2: -m_margins.bottom()));
160 else
161 setGeometryImpl(m_normalGeometry);
162
163 QWindowSystemInterface::handleWindowStateChanged(window: window(), newState: state);
164}
165
166QOffscreenWindow *QOffscreenWindow::windowForWinId(WId id)
167{
168 return m_windowForWinIdHash.value(key: id, defaultValue: nullptr);
169}
170
171Q_CONSTINIT QHash<WId, QOffscreenWindow *> QOffscreenWindow::m_windowForWinIdHash;
172
173QT_END_NAMESPACE
174

source code of qtbase/src/plugins/platforms/offscreen/qoffscreenwindow.cpp