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 &region)
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