1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module 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 "qplatformwindow.h"
41 #include "qplatformwindow_p.h"
42 #include "qplatformscreen.h"
43
44 #include <private/qguiapplication_p.h>
45 #include <qpa/qwindowsysteminterface.h>
46 #include <QtGui/qwindow.h>
47 #include <QtGui/qscreen.h>
48 #include <private/qhighdpiscaling_p.h>
49 #include <private/qwindow_p.h>
50
51
52 QT_BEGIN_NAMESPACE
53
54 /*!
55 Constructs a platform window with the given top level window.
56 */
57
QPlatformWindow(QWindow * window)58 QPlatformWindow::QPlatformWindow(QWindow *window)
59 : QPlatformSurface(window)
60 , d_ptr(new QPlatformWindowPrivate)
61 {
62 Q_D(QPlatformWindow);
63 d->rect = QHighDpi::toNativePixels(window->geometry(), window);
64 }
65
66 /*!
67 Virtual destructor does not delete its top level window.
68 */
~QPlatformWindow()69 QPlatformWindow::~QPlatformWindow()
70 {
71 }
72
73 /*!
74 Called as part of QWindow::create(), after constructing
75 the window. Platforms should prefer to do initialization
76 here instead of in the constructor, as the platform window
77 object will be fully constructed, and associated to the
78 corresponding QWindow, allowing synchronous event delivery.
79 */
initialize()80 void QPlatformWindow::initialize()
81 {
82 }
83
84 /*!
85 Returns the window which belongs to the QPlatformWindow
86 */
window() const87 QWindow *QPlatformWindow::window() const
88 {
89 return static_cast<QWindow *>(m_surface);
90 }
91
92 /*!
93 Returns the parent platform window (or \nullptr if orphan).
94 */
parent() const95 QPlatformWindow *QPlatformWindow::parent() const
96 {
97 return window()->parent() ? window()->parent()->handle() : nullptr;
98 }
99
100 /*!
101 Returns the platform screen handle corresponding to this platform window,
102 or null if the window is not associated with a screen.
103 */
screen() const104 QPlatformScreen *QPlatformWindow::screen() const
105 {
106 QScreen *scr = window()->screen();
107 return scr ? scr->handle() : nullptr;
108 }
109
110 /*!
111 Returns the actual surface format of the window.
112 */
format() const113 QSurfaceFormat QPlatformWindow::format() const
114 {
115 return QSurfaceFormat();
116 }
117
118 /*!
119 This function is called by Qt whenever a window is moved or resized using the QWindow API.
120
121 Unless you also override QPlatformWindow::geometry(), you need to call the baseclass
122 implementation of this function in any override of QPlatformWindow::setGeometry(), as
123 QWindow::geometry() is expected to report back the set geometry until a confirmation
124 (or rejection) of the new geometry comes back from the window manager and is reported
125 via QWindowSystemInterface::handleGeometryChange().
126
127 Window move/resizes can also be triggered spontaneously by the window manager, or as a
128 response to an earlier requested move/resize via the Qt APIs. There is no need to call
129 this function from the window manager callback, instead call
130 QWindowSystemInterface::handleGeometryChange().
131
132 The position(x, y) part of the rect might be inclusive or exclusive of the window frame
133 as returned by frameMargins(). You can detect this in the plugin by checking
134 qt_window_private(window())->positionPolicy.
135 */
setGeometry(const QRect & rect)136 void QPlatformWindow::setGeometry(const QRect &rect)
137 {
138 Q_D(QPlatformWindow);
139 d->rect = rect;
140 }
141
142 /*!
143 Returns the current geometry of a window
144 */
geometry() const145 QRect QPlatformWindow::geometry() const
146 {
147 Q_D(const QPlatformWindow);
148 return d->rect;
149 }
150
151 /*!
152 Returns the geometry of a window in 'normal' state
153 (neither maximized, fullscreen nor minimized) for saving geometries to
154 application settings.
155
156 \since 5.3
157 */
normalGeometry() const158 QRect QPlatformWindow::normalGeometry() const
159 {
160 return QRect();
161 }
162
frameMargins() const163 QMargins QPlatformWindow::frameMargins() const
164 {
165 return QMargins();
166 }
167
168 /*!
169 The safe area margins of a window represent the area that is safe to
170 place content within, without intersecting areas of the screen where
171 system UI is placed, or where a screen bezel may cover the content.
172 */
safeAreaMargins() const173 QMargins QPlatformWindow::safeAreaMargins() const
174 {
175 return QMargins();
176 }
177
178 /*!
179 Reimplemented in subclasses to show the surface
180 if \a visible is \c true, and hide it if \a visible is \c false.
181
182 The default implementation sends a synchronous expose event.
183 */
setVisible(bool visible)184 void QPlatformWindow::setVisible(bool visible)
185 {
186 Q_UNUSED(visible);
187 QRect rect(QPoint(), geometry().size());
188 QWindowSystemInterface::handleExposeEvent(window(), rect);
189 QWindowSystemInterface::flushWindowSystemEvents();
190 }
191
192 /*!
193 Requests setting the window flags of this surface
194 to \a flags.
195 */
setWindowFlags(Qt::WindowFlags flags)196 void QPlatformWindow::setWindowFlags(Qt::WindowFlags flags)
197 {
198 Q_UNUSED(flags);
199 }
200
201 /*!
202 Returns if this window is exposed in the windowing system.
203
204 An exposeEvent() is sent every time this value changes.
205 */
206
isExposed() const207 bool QPlatformWindow::isExposed() const
208 {
209 return window()->isVisible();
210 }
211
212 /*!
213 Returns \c true if the window should appear active from a style perspective.
214
215 This function can make platform-specific isActive checks, such as checking
216 if the QWindow is embedded in an active native window.
217 */
isActive() const218 bool QPlatformWindow::isActive() const
219 {
220 return false;
221 }
222
223 /*!
224 Returns \c true if the window is an ancestor of the given \a child.
225
226 Platform overrides should iterate the native window hierarchy of the child,
227 to ensure that ancestary is reflected even with native windows in the window
228 hierarchy.
229 */
isAncestorOf(const QPlatformWindow * child) const230 bool QPlatformWindow::isAncestorOf(const QPlatformWindow *child) const
231 {
232 for (const QPlatformWindow *parent = child->parent(); parent; parent = parent->parent()) {
233 if (parent == this)
234 return true;
235 }
236
237 return false;
238 }
239
240 /*!
241 Returns \c true if the window is a child of a non-Qt window.
242
243 A embedded window has no parent platform window as reflected
244 though parent(), but will have a native parent window.
245 */
isEmbedded() const246 bool QPlatformWindow::isEmbedded() const
247 {
248 return false;
249 }
250
251 /*!
252 Translates the window coordinate \a pos to global screen
253 coordinates using native methods. This is required for embedded windows,
254 where the topmost QWindow coordinates are not global screen coordinates.
255
256 Returns \a pos if there is no platform specific implementation.
257 */
mapToGlobal(const QPoint & pos) const258 QPoint QPlatformWindow::mapToGlobal(const QPoint &pos) const
259 {
260 const QPlatformWindow *p = this;
261 QPoint result = pos;
262 while (p) {
263 result += p->geometry().topLeft();
264 p = p->parent();
265 }
266 return result;
267 }
268
269 /*!
270 Translates the global screen coordinate \a pos to window
271 coordinates using native methods. This is required for embedded windows,
272 where the topmost QWindow coordinates are not global screen coordinates.
273
274 Returns \a pos if there is no platform specific implementation.
275 */
mapFromGlobal(const QPoint & pos) const276 QPoint QPlatformWindow::mapFromGlobal(const QPoint &pos) const
277 {
278 const QPlatformWindow *p = this;
279 QPoint result = pos;
280 while (p) {
281 result -= p->geometry().topLeft();
282 p = p->parent();
283 }
284 return result;
285 }
286
287 /*!
288 Requests setting the window state of this surface
289 to \a type.
290
291 Qt::WindowActive can be ignored.
292 */
setWindowState(Qt::WindowStates)293 void QPlatformWindow::setWindowState(Qt::WindowStates)
294 {
295 }
296
297 /*!
298 Reimplement in subclasses to return a handle to the native window
299 */
winId() const300 WId QPlatformWindow::winId() const
301 {
302 // Return anything but 0. Returning 0 would cause havoc with QWidgets on
303 // very basic platform plugins that do not reimplement this function,
304 // because the top-level widget's internalWinId() would always be 0 which
305 // would mean top-levels are never treated as native.
306 return WId(1);
307 }
308
309 //jl: It would be useful to have a property on the platform window which indicated if the sub-class
310 // supported the setParent. If not, then geometry would be in screen coordinates.
311 /*!
312 This function is called to enable native child window in QPA. It is common not to support this
313 feature in Window systems, but can be faked. When this function is called all geometry of this
314 platform window will be relative to the parent.
315 */
setParent(const QPlatformWindow * parent)316 void QPlatformWindow::setParent(const QPlatformWindow *parent)
317 {
318 Q_UNUSED(parent);
319 qWarning("This plugin does not support setParent!");
320 }
321
322 /*!
323 Reimplement to set the window title to \a title.
324
325 The implementation might want to append the application display name to
326 the window title, like Windows and Linux do.
327
328 \sa QGuiApplication::applicationDisplayName()
329 */
setWindowTitle(const QString & title)330 void QPlatformWindow::setWindowTitle(const QString &title) { Q_UNUSED(title); }
331
332 /*!
333 Reimplement to set the window file path to \a filePath
334 */
setWindowFilePath(const QString & filePath)335 void QPlatformWindow::setWindowFilePath(const QString &filePath) { Q_UNUSED(filePath); }
336
337 /*!
338 Reimplement to set the window icon to \a icon
339 */
setWindowIcon(const QIcon & icon)340 void QPlatformWindow::setWindowIcon(const QIcon &icon) { Q_UNUSED(icon); }
341
342 /*!
343 Reimplement to let the platform handle non-spontaneous window close.
344
345 When reimplementing make sure to call the base class implementation
346 or QWindowSystemInterface::handleCloseEvent(), which will prompt the
347 user to accept the window close (if needed) and then close the QWindow.
348 */
close()349 bool QPlatformWindow::close()
350 {
351 return QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(window());
352 }
353
354 /*!
355 Reimplement to be able to let Qt raise windows to the top of the desktop
356 */
raise()357 void QPlatformWindow::raise() { qWarning("This plugin does not support raise()"); }
358
359 /*!
360 Reimplement to be able to let Qt lower windows to the bottom of the desktop
361 */
lower()362 void QPlatformWindow::lower() { qWarning("This plugin does not support lower()"); }
363
364 /*!
365 Reimplement to propagate the size hints of the QWindow.
366
367 The size hints include QWindow::minimumSize(), QWindow::maximumSize(),
368 QWindow::sizeIncrement(), and QWindow::baseSize().
369 */
propagateSizeHints()370 void QPlatformWindow::propagateSizeHints() {qWarning("This plugin does not support propagateSizeHints()"); }
371
372 /*!
373 Reimplement to be able to let Qt set the opacity level of a window
374 */
setOpacity(qreal level)375 void QPlatformWindow::setOpacity(qreal level)
376 {
377 Q_UNUSED(level);
378 qWarning("This plugin does not support setting window opacity");
379 }
380
381 /*!
382 Reimplement to be able to let Qt set the mask of a window
383 */
384
setMask(const QRegion & region)385 void QPlatformWindow::setMask(const QRegion ®ion)
386 {
387 Q_UNUSED(region);
388 qWarning("This plugin does not support setting window masks");
389 }
390
391 /*!
392 Reimplement to let Qt be able to request activation/focus for a window
393
394 Some window systems will probably not have callbacks for this functionality,
395 and then calling QWindowSystemInterface::handleWindowActivated(QWindow *w)
396 would be sufficient.
397
398 If the window system has some event handling/callbacks then call
399 QWindowSystemInterface::handleWindowActivated(QWindow *w) when the window system
400 gives the notification.
401
402 Default implementation calls QWindowSystem::handleWindowActivated(QWindow *w)
403 */
requestActivateWindow()404 void QPlatformWindow::requestActivateWindow()
405 {
406 QWindowSystemInterface::handleWindowActivated(window());
407 }
408
409 /*!
410 Handle changes to the orientation of the platform window's contents.
411
412 This is a hint to the window manager in case it needs to display
413 additional content like popups, dialogs, status bars, or similar
414 in relation to the window.
415
416 \sa QWindow::reportContentOrientationChange()
417 */
handleContentOrientationChange(Qt::ScreenOrientation orientation)418 void QPlatformWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation)
419 {
420 Q_UNUSED(orientation);
421 }
422
423 /*!
424 Reimplement this function in subclass to return the device pixel ratio
425 for the window. This is the ratio between physical pixels
426 and device-independent pixels.
427
428 \sa QPlatformWindow::devicePixelRatio();
429 */
devicePixelRatio() const430 qreal QPlatformWindow::devicePixelRatio() const
431 {
432 return 1.0;
433 }
434
setKeyboardGrabEnabled(bool grab)435 bool QPlatformWindow::setKeyboardGrabEnabled(bool grab)
436 {
437 Q_UNUSED(grab);
438 qWarning("This plugin does not support grabbing the keyboard");
439 return false;
440 }
441
setMouseGrabEnabled(bool grab)442 bool QPlatformWindow::setMouseGrabEnabled(bool grab)
443 {
444 Q_UNUSED(grab);
445 qWarning("This plugin does not support grabbing the mouse");
446 return false;
447 }
448
449 /*!
450 Reimplement to be able to let Qt indicate that the window has been
451 modified. Return true if the native window supports setting the modified
452 flag, false otherwise.
453 */
setWindowModified(bool modified)454 bool QPlatformWindow::setWindowModified(bool modified)
455 {
456 Q_UNUSED(modified);
457 return false;
458 }
459
460 /*!
461 Reimplement this method to be able to do any platform specific event
462 handling. All non-synthetic events for window() are passed to this
463 function before being sent to QWindow::event().
464
465 Return true if the event should not be passed on to the QWindow.
466
467 Subclasses should always call the base class implementation.
468 */
windowEvent(QEvent * event)469 bool QPlatformWindow::windowEvent(QEvent *event)
470 {
471 Q_D(QPlatformWindow);
472
473 if (event->type() == QEvent::Timer) {
474 if (static_cast<QTimerEvent *>(event)->timerId() == d->updateTimer.timerId()) {
475 d->updateTimer.stop();
476 deliverUpdateRequest();
477 return true;
478 }
479 }
480
481 return false;
482 }
483
484 /*!
485 Reimplement this method to start a system resize operation if
486 the system supports it and return true to indicate success.
487
488 The default implementation is empty and does nothing with \a edges.
489
490 \since 5.15
491 */
492
startSystemResize(Qt::Edges edges)493 bool QPlatformWindow::startSystemResize(Qt::Edges edges)
494 {
495 Q_UNUSED(edges)
496 return false;
497 }
498
499 /*!
500 Reimplement this method to start a system move operation if
501 the system supports it and return true to indicate success.
502
503 The default implementation is empty and does nothing.
504
505 \since 5.15
506 */
507
startSystemMove()508 bool QPlatformWindow::startSystemMove()
509 {
510 return false;
511 }
512
513 /*!
514 Reimplement this method to set whether frame strut events
515 should be sent to \a enabled.
516
517 \sa frameStrutEventsEnabled
518 */
519
setFrameStrutEventsEnabled(bool enabled)520 void QPlatformWindow::setFrameStrutEventsEnabled(bool enabled)
521 {
522 Q_UNUSED(enabled) // Do not warn as widgets enable it by default causing warnings with XCB.
523 }
524
525 /*!
526 Reimplement this method to return whether
527 frame strut events are enabled.
528 */
529
frameStrutEventsEnabled() const530 bool QPlatformWindow::frameStrutEventsEnabled() const
531 {
532 return false;
533 }
534
535 /*!
536 Call this method to put together a window title composed of
537 \a title
538 \a separator
539 the application display name
540
541 If the display name isn't set, and the title is empty, the raw app name is used.
542 */
formatWindowTitle(const QString & title,const QString & separator)543 QString QPlatformWindow::formatWindowTitle(const QString &title, const QString &separator)
544 {
545 QString fullTitle = title;
546 if (QGuiApplicationPrivate::displayName && !title.endsWith(*QGuiApplicationPrivate::displayName)) {
547 // Append display name, if set.
548 if (!fullTitle.isEmpty())
549 fullTitle += separator;
550 fullTitle += *QGuiApplicationPrivate::displayName;
551 } else if (fullTitle.isEmpty()) {
552 // Don't let the window title be completely empty, use the app name as fallback.
553 fullTitle = QCoreApplication::applicationName();
554 }
555 return fullTitle;
556 }
557
558 /*!
559 Helper function for finding the new screen for \a newGeometry in response to
560 a geometry changed event. Returns the new screen if the window was moved to
561 another virtual sibling. If the screen changes, the platform plugin should call
562 QWindowSystemInterface::handleWindowScreenChanged().
563 \note: The current screen will always be returned for child windows since
564 they should never signal screen changes.
565
566 \since 5.4
567 \sa QWindowSystemInterface::handleWindowScreenChanged()
568 */
screenForGeometry(const QRect & newGeometry) const569 QPlatformScreen *QPlatformWindow::screenForGeometry(const QRect &newGeometry) const
570 {
571 QPlatformScreen *currentScreen = screen();
572 QPlatformScreen *fallback = currentScreen;
573 // QRect::center can return a value outside the rectangle if it's empty.
574 // Apply mapToGlobal() in case it is a foreign/embedded window.
575 QPoint center = newGeometry.isEmpty() ? newGeometry.topLeft() : newGeometry.center();
576 if (isForeignWindow())
577 center = mapToGlobal(center - newGeometry.topLeft());
578
579 if (!parent() && currentScreen && !currentScreen->geometry().contains(center)) {
580 const auto screens = currentScreen->virtualSiblings();
581 for (QPlatformScreen *screen : screens) {
582 const QRect screenGeometry = screen->geometry();
583 if (screenGeometry.contains(center))
584 return screen;
585 if (screenGeometry.intersects(newGeometry))
586 fallback = screen;
587 }
588 }
589 return fallback;
590 }
591
592 /*!
593 Returns a size with both dimensions bounded to [0, QWINDOWSIZE_MAX]
594 */
constrainWindowSize(const QSize & size)595 QSize QPlatformWindow::constrainWindowSize(const QSize &size)
596 {
597 return size.expandedTo(QSize(0, 0)).boundedTo(QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX));
598 }
599
600 /*!
601 Reimplement this method to set whether the window demands attention
602 (for example, by flashing the taskbar icon) depending on \a enabled.
603
604 \sa isAlertState()
605 \since 5.1
606 */
607
setAlertState(bool enable)608 void QPlatformWindow::setAlertState(bool enable)
609 {
610 Q_UNUSED(enable)
611 }
612
613 /*!
614 Reimplement this method return whether the window is in
615 an alert state.
616
617 \sa setAlertState()
618 \since 5.1
619 */
620
isAlertState() const621 bool QPlatformWindow::isAlertState() const
622 {
623 return false;
624 }
625
626 // Return the effective screen for the initial geometry of a window. In a
627 // multimonitor-setup, try to find the right screen by checking the transient
628 // parent or the mouse cursor for parentless windows (cf QTBUG-34204,
629 // QDialog::adjustPosition()), unless a non-primary screen has been set,
630 // in which case we try to respect that.
effectiveScreen(const QWindow * window)631 static inline const QScreen *effectiveScreen(const QWindow *window)
632 {
633 if (!window)
634 return QGuiApplication::primaryScreen();
635 const QScreen *screen = window->screen();
636 if (!screen)
637 return QGuiApplication::primaryScreen();
638 if (screen != QGuiApplication::primaryScreen())
639 return screen;
640 #ifndef QT_NO_CURSOR
641 const QList<QScreen *> siblings = screen->virtualSiblings();
642 if (siblings.size() > 1) {
643 const QPoint referencePoint = window->transientParent() ? window->transientParent()->geometry().center() : QCursor::pos();
644 for (const QScreen *sibling : siblings) {
645 if (sibling->geometry().contains(referencePoint))
646 return sibling;
647 }
648 }
649 #endif
650 return screen;
651 }
652
653 /*!
654 Invalidates the window's surface by releasing its surface buffers.
655
656 Many platforms do not support releasing the surface memory,
657 and the default implementation does nothing.
658
659 The platform window is expected to recreate the surface again if
660 it is needed. For instance, if an OpenGL context is made current
661 on this window.
662 */
invalidateSurface()663 void QPlatformWindow::invalidateSurface()
664 {
665 }
666
fixInitialSize(QSize size,const QWindow * w,int defaultWidth,int defaultHeight)667 static QSize fixInitialSize(QSize size, const QWindow *w,
668 int defaultWidth, int defaultHeight)
669 {
670 if (size.width() == 0) {
671 const int minWidth = w->minimumWidth();
672 size.setWidth(minWidth > 0 ? minWidth : defaultWidth);
673 }
674 if (size.height() == 0) {
675 const int minHeight = w->minimumHeight();
676 size.setHeight(minHeight > 0 ? minHeight : defaultHeight);
677 }
678 return size;
679 }
680
681 /*!
682 Helper function to get initial geometry on windowing systems which do not
683 do smart positioning and also do not provide a means of centering a
684 transient window w.r.t. its parent. For example this is useful on Windows
685 and MacOS but not X11, because an X11 window manager typically tries to
686 layout new windows to optimize usage of the available desktop space.
687 However if the given window already has geometry which the application has
688 initialized, it takes priority.
689 */
initialGeometry(const QWindow * w,const QRect & initialGeometry,int defaultWidth,int defaultHeight,const QScreen ** resultingScreenReturn)690 QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeometry,
691 int defaultWidth, int defaultHeight,
692 const QScreen **resultingScreenReturn)
693 {
694 if (resultingScreenReturn)
695 *resultingScreenReturn = w->screen();
696 if (!w->isTopLevel()) {
697 const qreal factor = QHighDpiScaling::factor(w);
698 const QSize size = fixInitialSize(QHighDpi::fromNative(initialGeometry.size(), factor),
699 w, defaultWidth, defaultHeight);
700 return QRect(initialGeometry.topLeft(), QHighDpi::toNative(size, factor));
701 }
702 const auto *wp = qt_window_private(const_cast<QWindow*>(w));
703 const bool position = wp->positionAutomatic && w->type() != Qt::Popup;
704 if (!position && !wp->resizeAutomatic)
705 return initialGeometry;
706 const QScreen *screen = wp->positionAutomatic
707 ? effectiveScreen(w)
708 : QGuiApplication::screenAt(initialGeometry.center());
709 if (!screen)
710 return initialGeometry;
711 if (resultingScreenReturn)
712 *resultingScreenReturn = screen;
713 // initialGeometry refers to window's screen
714 QRect rect(QHighDpi::fromNativePixels(initialGeometry, w));
715 if (wp->resizeAutomatic)
716 rect.setSize(fixInitialSize(rect.size(), w, defaultWidth, defaultHeight));
717 if (position) {
718 const QRect availableGeometry = screen->availableGeometry();
719 // Center unless the geometry ( + unknown window frame) is too large for the screen).
720 if (rect.height() < (availableGeometry.height() * 8) / 9
721 && rect.width() < (availableGeometry.width() * 8) / 9) {
722 const QWindow *tp = w->transientParent();
723 if (tp) {
724 // A transient window should be centered w.r.t. its transient parent.
725 rect.moveCenter(tp->geometry().center());
726 } else {
727 // Center the window on the screen. (Only applicable on platforms
728 // which do not provide a better way.)
729 rect.moveCenter(availableGeometry.center());
730 }
731 }
732 }
733 return QHighDpi::toNativePixels(rect, screen);
734 }
735
736 /*!
737 Requests an QEvent::UpdateRequest event. The event will be
738 delivered to the QWindow.
739
740 QPlatformWindow subclasses can re-implement this function to
741 provide display refresh synchronized updates. The event
742 should be delivered using QPlatformWindow::deliverUpdateRequest()
743 to not get out of sync with the internal state of QWindow.
744
745 The default implementation posts an UpdateRequest event to the
746 window after 5 ms. The additional time is there to give the event
747 loop a bit of idle time to gather system events.
748
749 */
requestUpdate()750 void QPlatformWindow::requestUpdate()
751 {
752 Q_D(QPlatformWindow);
753
754 static int updateInterval = []() {
755 bool ok = false;
756 int customUpdateInterval = qEnvironmentVariableIntValue("QT_QPA_UPDATE_IDLE_TIME", &ok);
757 return ok ? customUpdateInterval : 5;
758 }();
759
760 Q_ASSERT(!d->updateTimer.isActive());
761 d->updateTimer.start(updateInterval, Qt::PreciseTimer, window());
762 }
763
764 /*!
765 Returns true if the window has a pending update request.
766
767 \sa requestUpdate(), deliverUpdateRequest()
768 */
hasPendingUpdateRequest() const769 bool QPlatformWindow::hasPendingUpdateRequest() const
770 {
771 return qt_window_private(window())->updateRequestPending;
772 }
773
774 /*!
775 Delivers an QEvent::UpdateRequest event to the window.
776
777 QPlatformWindow subclasses can re-implement this function to
778 provide e.g. logging or tracing of the delivery, but should
779 always call the base class function.
780 */
deliverUpdateRequest()781 void QPlatformWindow::deliverUpdateRequest()
782 {
783 Q_ASSERT(hasPendingUpdateRequest());
784
785 QWindow *w = window();
786 QWindowPrivate *wp = qt_window_private(w);
787 wp->updateRequestPending = false;
788 QEvent request(QEvent::UpdateRequest);
789 QCoreApplication::sendEvent(w, &request);
790 }
791
792 /*!
793 Returns the QWindow minimum size.
794 */
windowMinimumSize() const795 QSize QPlatformWindow::windowMinimumSize() const
796 {
797 return constrainWindowSize(QHighDpi::toNativePixels(window()->minimumSize(), window()));
798 }
799
800 /*!
801 Returns the QWindow maximum size.
802 */
windowMaximumSize() const803 QSize QPlatformWindow::windowMaximumSize() const
804 {
805 return constrainWindowSize(QHighDpi::toNativePixels(window()->maximumSize(), window()));
806 }
807
808 /*!
809 Returns the QWindow base size.
810 */
windowBaseSize() const811 QSize QPlatformWindow::windowBaseSize() const
812 {
813 return QHighDpi::toNativePixels(window()->baseSize(), window());
814 }
815
816 /*!
817 Returns the QWindow size increment.
818 */
windowSizeIncrement() const819 QSize QPlatformWindow::windowSizeIncrement() const
820 {
821 QSize increment = window()->sizeIncrement();
822 if (!QHighDpiScaling::isActive())
823 return increment;
824
825 // Normalize the increment. If not set the increment can be
826 // (-1, -1) or (0, 0). Make that (1, 1) which is scalable.
827 if (increment.isEmpty())
828 increment = QSize(1, 1);
829
830 return QHighDpi::toNativePixels(increment, window());
831 }
832
833 /*!
834 Returns the QWindow geometry.
835 */
windowGeometry() const836 QRect QPlatformWindow::windowGeometry() const
837 {
838 return QHighDpi::toNativePixels(window()->geometry(), window());
839 }
840
841 /*!
842 Returns the QWindow frame geometry.
843 */
windowFrameGeometry() const844 QRect QPlatformWindow::windowFrameGeometry() const
845 {
846 return QHighDpi::toNativePixels(window()->frameGeometry(), window());
847 }
848
849 /*!
850 Returns the closest acceptable geometry for a given geometry before
851 a resize/move event for platforms that support it, for example to
852 implement heightForWidth().
853 */
854
closestAcceptableGeometry(const QWindow * qWindow,const QRectF & nativeRect)855 QRectF QPlatformWindow::closestAcceptableGeometry(const QWindow *qWindow, const QRectF &nativeRect)
856 {
857 const QRectF rectF = QHighDpi::fromNativePixels(nativeRect, qWindow);
858 const QRectF correctedGeometryF = qt_window_private(const_cast<QWindow *>(qWindow))->closestAcceptableGeometry(rectF);
859 return !correctedGeometryF.isEmpty() && rectF != correctedGeometryF
860 ? QHighDpi::toNativePixels(correctedGeometryF, qWindow) : nativeRect;
861 }
862
windowClosestAcceptableGeometry(const QRectF & nativeRect) const863 QRectF QPlatformWindow::windowClosestAcceptableGeometry(const QRectF &nativeRect) const
864 {
865 return QPlatformWindow::closestAcceptableGeometry(window(), nativeRect);
866 }
867
868 /*!
869 \class QPlatformWindow
870 \since 4.8
871 \internal
872 \preliminary
873 \ingroup qpa
874
875 \brief The QPlatformWindow class provides an abstraction for top-level windows.
876
877 The QPlatformWindow abstraction is used by QWindow for all its top level windows. It is being
878 created by calling the createPlatformWindow function in the loaded QPlatformIntegration
879 instance.
880
881 QPlatformWindow is used to signal to the windowing system, how Qt perceives its frame.
882 However, it is not concerned with how Qt renders into the window it represents.
883
884 Visible QWindows will always have a QPlatformWindow. However, it is not necessary for
885 all windows to have a QBackingStore. This is the case for QOpenGLWindow. And could be the case for
886 windows where some third party renders into it.
887
888 The platform specific window handle can be retrieved by the winId function.
889
890 QPlatformWindow is also the way QPA defines how native child windows should be supported
891 through the setParent function.
892
893 \section1 Implementation Aspects
894
895 \list 1
896 \li Mouse grab: Qt expects windows to automatically grab the mouse if the user presses
897 a button until the button is released.
898 Automatic grab should be released if some window is explicitly grabbed.
899 \li Enter/Leave events: If there is a window explicitly grabbing mouse events
900 (\c{setMouseGrabEnabled()}), enter and leave events should only be sent to the
901 grabbing window when mouse cursor passes over the grabbing window boundary.
902 Other windows will not receive enter or leave events while the grab is active.
903 While an automatic mouse grab caused by a mouse button press is active, no window
904 will receive enter or leave events. When the last mouse button is released, the
905 autograbbing window will receive leave event if mouse cursor is no longer within
906 the window boundary.
907 When any grab starts, the window under cursor will receive a leave event unless
908 it is the grabbing window.
909 When any grab ends, the window under cursor will receive an enter event unless it
910 was the grabbing window.
911 \li Window positioning: When calling \c{QWindow::setFramePosition()}, the flag
912 \c{QWindowPrivate::positionPolicy} is set to \c{QWindowPrivate::WindowFrameInclusive}.
913 This means the position includes the window frame, whose size is at this point
914 unknown and the geometry's topleft point is the position of the window frame.
915 \endlist
916
917 Apart from the auto-tests (\c{tests/auto/gui/kernel/qwindow},
918 \c{tests/auto/gui/kernel/qguiapplication} and \c{tests/auto/widgets/kernel/qwidget}),
919 there are a number of manual tests and examples that can help testing a platform plugin:
920
921 \list 1
922 \li \c{examples/qpa/windows}: Basic \c{QWindow} creation.
923 \li \c{examples/opengl/hellowindow}: Basic Open GL windows.
924 \li \c{tests/manual/windowflags}: Tests setting the window flags.
925 \li \c{tests/manual/windowgeometry} Tests setting the window geometry.
926 \li \c{tests/manual/windowmodality} Tests setting the window modality.
927 \li \c{tests/manual/widgetgrab} Tests mouse grab and dialogs.
928 \endlist
929
930 \sa QBackingStore, QWindow
931 */
932
933 QT_END_NAMESPACE
934