1 /***************************************************************************
2 **
3 ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qhaikuwindow.h"
41
42 #include "private/qguiapplication_p.h"
43
44 #include <QCoreApplication>
45 #include <QThread>
46 #include <QWindow>
47 #include <qpa/qwindowsysteminterface.h>
48
49 #include <Rect.h>
50 #include <Window.h>
51
52 QT_BEGIN_NAMESPACE
53
54 enum {
55 DefaultWindowWidth = 160,
56 DefaultWindowHeight = 160
57 };
58
HaikuWindowProxy(QWindow * window,const QRect & rect,QObject * parent)59 HaikuWindowProxy::HaikuWindowProxy(QWindow *window, const QRect &rect, QObject *parent)
60 : QObject(parent)
61 , BWindow(BRect(rect.x(), rect.y(), rect.right() - 1, rect.bottom() - 1),
62 window->title().toUtf8(), B_NO_BORDER_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 0)
63 , m_qtCalledZoom(false)
64 , m_zoomInProgress(false)
65 {
66 }
67
FrameMoved(BPoint pos)68 void HaikuWindowProxy::FrameMoved(BPoint pos)
69 {
70 Q_EMIT moved(QPoint(pos.x, pos.y));
71 }
72
FrameResized(float width,float height)73 void HaikuWindowProxy::FrameResized(float width, float height)
74 {
75 Q_EMIT resized(QSize(static_cast<int>(width), static_cast<int>(height)), m_zoomInProgress);
76
77 m_zoomInProgress = false;
78 }
79
WindowActivated(bool activated)80 void HaikuWindowProxy::WindowActivated(bool activated)
81 {
82 Q_EMIT windowActivated(activated);
83 }
84
Minimize(bool minimize)85 void HaikuWindowProxy::Minimize(bool minimize)
86 {
87 BWindow::Minimize(minimize);
88
89 Q_EMIT minimized(minimize);
90 }
91
Zoom(BPoint pos,float width,float height)92 void HaikuWindowProxy::Zoom(BPoint pos, float width, float height)
93 {
94 m_zoomInProgress = true;
95 BWindow::Zoom(pos, width, height);
96
97 // Only notify about Zoom invocations from the Haiku windowing system
98 if (!m_qtCalledZoom)
99 Q_EMIT zoomed();
100 }
101
QuitRequested()102 bool HaikuWindowProxy::QuitRequested()
103 {
104 Q_EMIT quitRequested();
105
106 // Return false to prevent Haiku windowing system to clean up
107 // the BWindow and BView instances. We will do that ourself when
108 // Qt invokes the dtor of QHaikuWindow
109 return false;
110 }
111
zoomByQt()112 void HaikuWindowProxy::zoomByQt()
113 {
114 m_qtCalledZoom = true;
115 BWindow::Zoom();
116 m_qtCalledZoom = false;
117 }
118
QHaikuWindow(QWindow * window)119 QHaikuWindow::QHaikuWindow(QWindow *window)
120 : QPlatformWindow(window)
121 , m_window(nullptr)
122 , m_windowState(Qt::WindowNoState)
123 {
124 const QRect rect = initialGeometry(window, window->geometry(), DefaultWindowWidth, DefaultWindowHeight);
125
126 HaikuWindowProxy *haikuWindow = new HaikuWindowProxy(window, rect, nullptr);
127 connect(haikuWindow, SIGNAL(moved(QPoint)), SLOT(haikuWindowMoved(QPoint)));
128 connect(haikuWindow, SIGNAL(resized(QSize,bool)), SLOT(haikuWindowResized(QSize,bool)));
129 connect(haikuWindow, SIGNAL(windowActivated(bool)), SLOT(haikuWindowActivated(bool)));
130 connect(haikuWindow, SIGNAL(minimized(bool)), SLOT(haikuWindowMinimized(bool)));
131 connect(haikuWindow, SIGNAL(zoomed()), SLOT(haikuWindowZoomed()));
132 connect(haikuWindow, SIGNAL(quitRequested()), SLOT(haikuWindowQuitRequested()), Qt::BlockingQueuedConnection);
133
134 m_window = haikuWindow;
135
136 if (Q_UNLIKELY(!m_window))
137 qFatal("QHaikuWindow: failed to create window");
138
139 setGeometry(rect);
140 setWindowFlags(window->flags());
141 }
142
~QHaikuWindow()143 QHaikuWindow::~QHaikuWindow()
144 {
145 m_window->LockLooper();
146 m_window->Quit();
147
148 m_window = nullptr;
149 }
150
setGeometry(const QRect & rect)151 void QHaikuWindow::setGeometry(const QRect &rect)
152 {
153 QPlatformWindow::setGeometry(rect);
154
155 m_window->MoveTo(rect.x(), rect.y());
156 m_window->ResizeTo(rect.width(), rect.height());
157 }
158
frameMargins() const159 QMargins QHaikuWindow::frameMargins() const
160 {
161 const BRect decoratorFrame = m_window->DecoratorFrame();
162 const BRect frame = m_window->Frame();
163
164 return QMargins(frame.left - decoratorFrame.left,
165 frame.top - decoratorFrame.top,
166 decoratorFrame.right - frame.right,
167 decoratorFrame.bottom - frame.bottom);
168 }
169
setVisible(bool visible)170 void QHaikuWindow::setVisible(bool visible)
171 {
172 if (visible) {
173 m_window->Show();
174
175 window()->requestActivate();
176
177 QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), window()->geometry().size()));
178 } else {
179 m_window->Hide();
180 }
181 }
182
isExposed() const183 bool QHaikuWindow::isExposed() const
184 {
185 return !m_window->IsHidden();
186 }
187
isActive() const188 bool QHaikuWindow::isActive() const
189 {
190 return m_window->IsActive();
191 }
192
winId() const193 WId QHaikuWindow::winId() const
194 {
195 return (WId)static_cast<BWindow*>(m_window);
196 }
197
nativeHandle() const198 BWindow* QHaikuWindow::nativeHandle() const
199 {
200 return m_window;
201 }
202
requestActivateWindow()203 void QHaikuWindow::requestActivateWindow()
204 {
205 m_window->Activate(true);
206 }
207
setWindowState(Qt::WindowStates state)208 void QHaikuWindow::setWindowState(Qt::WindowStates state)
209 {
210 if (m_windowState == state)
211 return;
212
213 const Qt::WindowStates oldState = m_windowState;
214
215 m_windowState = state;
216
217 if (m_windowState & Qt::WindowMinimized)
218 m_window->Minimize(true);
219 else if (m_windowState & Qt::WindowMaximized)
220 m_window->zoomByQt();
221 else if (oldState & Qt::WindowMinimized)
222 m_window->Minimize(false); // undo minimize
223 else if (oldState & Qt::WindowMaximized)
224 m_window->zoomByQt(); // undo zoom
225 }
226
setWindowFlags(Qt::WindowFlags flags)227 void QHaikuWindow::setWindowFlags(Qt::WindowFlags flags)
228 {
229 const Qt::WindowType type = static_cast<Qt::WindowType>(static_cast<int>(flags & Qt::WindowType_Mask));
230
231 const bool isPopup = (type == Qt::Popup);
232 const bool isSplashScreen = (type == Qt::SplashScreen);
233 const bool isDialog = ((type == Qt::Dialog) || (type == Qt::Sheet) || (type == Qt::MSWindowsFixedSizeDialogHint));
234 const bool isTool = ((type == Qt::Tool) || (type == Qt::Drawer));
235 const bool isToolTip = (type == Qt::ToolTip);
236
237 window_look wlook = B_TITLED_WINDOW_LOOK;
238 window_feel wfeel = B_NORMAL_WINDOW_FEEL;
239 uint32 wflag = (B_NO_WORKSPACE_ACTIVATION | B_NOT_ANCHORED_ON_ACTIVATE);
240
241 if (isTool) {
242 wlook = B_FLOATING_WINDOW_LOOK;
243 wflag |= B_WILL_ACCEPT_FIRST_CLICK;
244 }
245
246 if (isSplashScreen) {
247 wlook = B_NO_BORDER_WINDOW_LOOK;
248 }
249
250 if (isPopup) {
251 wlook = B_NO_BORDER_WINDOW_LOOK;
252 wflag |= (B_WILL_ACCEPT_FIRST_CLICK | B_AVOID_FRONT | B_AVOID_FOCUS);
253 flags |= Qt::WindowStaysOnTopHint;
254 }
255
256 if (isDialog) {
257 if (window()->modality() == Qt::WindowModal)
258 wfeel = B_MODAL_SUBSET_WINDOW_FEEL;
259 else if (window()->modality() == Qt::ApplicationModal)
260 wfeel = B_MODAL_APP_WINDOW_FEEL;
261 }
262
263 if (isToolTip) {
264 wlook = B_NO_BORDER_WINDOW_LOOK;
265 wflag |= (B_WILL_ACCEPT_FIRST_CLICK | B_AVOID_FOCUS);
266 flags |= Qt::WindowStaysOnTopHint;
267 }
268
269 if (flags & Qt::FramelessWindowHint)
270 wlook = B_NO_BORDER_WINDOW_LOOK;
271
272 if (flags & Qt::MSWindowsFixedSizeDialogHint)
273 wflag |= (B_NOT_RESIZABLE | B_NOT_ZOOMABLE);
274
275 if (flags & Qt::CustomizeWindowHint) {
276 if (!(flags & Qt::WindowMinimizeButtonHint))
277 wflag |= B_NOT_MINIMIZABLE;
278 if (!(flags & Qt::WindowMaximizeButtonHint))
279 wflag |= B_NOT_ZOOMABLE;
280 if (!(flags & Qt::WindowCloseButtonHint))
281 wflag |= B_NOT_CLOSABLE;
282 }
283
284 if (flags & Qt::WindowStaysOnTopHint)
285 wfeel = B_FLOATING_ALL_WINDOW_FEEL;
286
287 m_window->SetLook(wlook);
288 m_window->SetFeel(wfeel);
289 m_window->SetFlags(wflag);
290 }
291
setWindowTitle(const QString & title)292 void QHaikuWindow::setWindowTitle(const QString &title)
293 {
294 m_window->SetTitle(title.toLocal8Bit().constData());
295 }
296
propagateSizeHints()297 void QHaikuWindow::propagateSizeHints()
298 {
299 m_window->SetSizeLimits(window()->minimumSize().width(),
300 window()->maximumSize().width(),
301 window()->minimumSize().height(),
302 window()->maximumSize().height());
303
304 m_window->SetZoomLimits(window()->maximumSize().width(),
305 window()->maximumSize().height());
306 }
307
haikuWindowMoved(const QPoint & pos)308 void QHaikuWindow::haikuWindowMoved(const QPoint &pos)
309 {
310 const QRect newGeometry(pos, geometry().size());
311
312 QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
313 QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), newGeometry.size()));
314 }
315
haikuWindowResized(const QSize & size,bool zoomInProgress)316 void QHaikuWindow::haikuWindowResized(const QSize &size, bool zoomInProgress)
317 {
318 const QRect newGeometry(geometry().topLeft(), size);
319
320 QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
321 QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), newGeometry.size()));
322
323 if ((m_windowState == Qt::WindowMaximized) && !zoomInProgress) {
324 // the user has resized the window while maximized -> reset maximized flag
325 m_windowState = Qt::WindowNoState;
326
327 QWindowSystemInterface::handleWindowStateChanged(window(), m_windowState);
328 }
329 }
330
haikuWindowActivated(bool activated)331 void QHaikuWindow::haikuWindowActivated(bool activated)
332 {
333 QWindowSystemInterface::handleWindowActivated(activated ? window() : nullptr);
334 }
335
haikuWindowMinimized(bool minimize)336 void QHaikuWindow::haikuWindowMinimized(bool minimize)
337 {
338 m_windowState = (minimize ? Qt::WindowMinimized : Qt::WindowNoState);
339
340 QWindowSystemInterface::handleWindowStateChanged(window(), m_windowState);
341 }
342
haikuWindowZoomed()343 void QHaikuWindow::haikuWindowZoomed()
344 {
345 m_windowState = (m_windowState == Qt::WindowMaximized ? Qt::WindowNoState : Qt::WindowMaximized);
346
347 QWindowSystemInterface::handleWindowStateChanged(window(), m_windowState);
348 }
349
haikuWindowQuitRequested()350 void QHaikuWindow::haikuWindowQuitRequested()
351 {
352 QWindowSystemInterface::handleCloseEvent(window());
353 }
354
haikuMouseEvent(const QPoint & localPosition,const QPoint & globalPosition,Qt::MouseButtons buttons,Qt::KeyboardModifiers modifiers,Qt::MouseEventSource source)355 void QHaikuWindow::haikuMouseEvent(const QPoint &localPosition, const QPoint &globalPosition, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Qt::MouseEventSource source)
356 {
357 QWindowSystemInterface::handleMouseEvent(window(), localPosition, globalPosition,
358 buttons, modifiers, source);
359 }
360
haikuWheelEvent(const QPoint & localPosition,const QPoint & globalPosition,int delta,Qt::Orientation orientation,Qt::KeyboardModifiers modifiers)361 void QHaikuWindow::haikuWheelEvent(const QPoint &localPosition, const QPoint &globalPosition, int delta, Qt::Orientation orientation, Qt::KeyboardModifiers modifiers)
362 {
363 QWindowSystemInterface::handleWheelEvent(window(), localPosition, globalPosition, delta, orientation, modifiers);
364 }
365
haikuKeyEvent(QEvent::Type type,int key,Qt::KeyboardModifiers modifiers,const QString & text)366 void QHaikuWindow::haikuKeyEvent(QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, const QString &text)
367 {
368 QWindowSystemInterface::handleKeyEvent(window(), type, key, modifiers, text);
369 }
370
haikuEnteredView()371 void QHaikuWindow::haikuEnteredView()
372 {
373 QWindowSystemInterface::handleEnterEvent(window());
374 }
375
haikuExitedView()376 void QHaikuWindow::haikuExitedView()
377 {
378 QWindowSystemInterface::handleLeaveEvent(window());
379 }
380
haikuDrawRequest(const QRect & rect)381 void QHaikuWindow::haikuDrawRequest(const QRect &rect)
382 {
383 QWindowSystemInterface::handleExposeEvent(window(), QRegion(rect));
384 }
385
386 QT_END_NAMESPACE
387