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
52QT_BEGIN_NAMESPACE
53
54/*!
55 Constructs a platform window with the given top level window.
56*/
57
58QPlatformWindow::QPlatformWindow(QWindow *window)
59 : QPlatformSurface(window)
60 , d_ptr(new QPlatformWindowPrivate)
61{
62 Q_D(QPlatformWindow);
63 d->rect = QHighDpi::toNativePixels(value: window->geometry(), context: window);
64}
65
66/*!
67 Virtual destructor does not delete its top level window.
68*/
69QPlatformWindow::~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*/
80void QPlatformWindow::initialize()
81{
82}
83
84/*!
85 Returns the window which belongs to the QPlatformWindow
86*/
87QWindow *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*/
95QPlatformWindow *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*/
104QPlatformScreen *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*/
113QSurfaceFormat 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*/
136void 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*/
145QRect 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*/
158QRect QPlatformWindow::normalGeometry() const
159{
160 return QRect();
161}
162
163QMargins 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*/
173QMargins 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*/
184void QPlatformWindow::setVisible(bool visible)
185{
186 Q_UNUSED(visible);
187 QRect rect(QPoint(), geometry().size());
188 QWindowSystemInterface::handleExposeEvent(window: window(), region: rect);
189 QWindowSystemInterface::flushWindowSystemEvents();
190}
191
192/*!
193 Requests setting the window flags of this surface
194 to \a flags.
195*/
196void 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
207bool 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*/
218bool 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*/
230bool 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*/
246bool 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*/
258QPoint 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*/
276QPoint 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*/
293void QPlatformWindow::setWindowState(Qt::WindowStates)
294{
295}
296
297/*!
298 Reimplement in subclasses to return a handle to the native window
299*/
300WId 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*/
316void QPlatformWindow::setParent(const QPlatformWindow *parent)
317{
318 Q_UNUSED(parent);
319 qWarning(msg: "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*/
330void QPlatformWindow::setWindowTitle(const QString &title) { Q_UNUSED(title); }
331
332/*!
333 Reimplement to set the window file path to \a filePath
334*/
335void QPlatformWindow::setWindowFilePath(const QString &filePath) { Q_UNUSED(filePath); }
336
337/*!
338 Reimplement to set the window icon to \a icon
339*/
340void 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*/
349bool QPlatformWindow::close()
350{
351 return QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(window: window());
352}
353
354/*!
355 Reimplement to be able to let Qt raise windows to the top of the desktop
356*/
357void QPlatformWindow::raise() { qWarning(msg: "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*/
362void QPlatformWindow::lower() { qWarning(msg: "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*/
370void QPlatformWindow::propagateSizeHints() {qWarning(msg: "This plugin does not support propagateSizeHints()"); }
371
372/*!
373 Reimplement to be able to let Qt set the opacity level of a window
374*/
375void QPlatformWindow::setOpacity(qreal level)
376{
377 Q_UNUSED(level);
378 qWarning(msg: "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
385void QPlatformWindow::setMask(const QRegion &region)
386{
387 Q_UNUSED(region);
388 qWarning(msg: "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*/
404void QPlatformWindow::requestActivateWindow()
405{
406 QWindowSystemInterface::handleWindowActivated(window: 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*/
418void 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*/
430qreal QPlatformWindow::devicePixelRatio() const
431{
432 return 1.0;
433}
434
435bool QPlatformWindow::setKeyboardGrabEnabled(bool grab)
436{
437 Q_UNUSED(grab);
438 qWarning(msg: "This plugin does not support grabbing the keyboard");
439 return false;
440}
441
442bool QPlatformWindow::setMouseGrabEnabled(bool grab)
443{
444 Q_UNUSED(grab);
445 qWarning(msg: "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*/
454bool 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*/
469bool 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
493bool 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
508bool 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
520void 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
530bool 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*/
543QString QPlatformWindow::formatWindowTitle(const QString &title, const QString &separator)
544{
545 QString fullTitle = title;
546 if (QGuiApplicationPrivate::displayName && !title.endsWith(s: *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*/
569QPlatformScreen *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(pos: center - newGeometry.topLeft());
578
579 if (!parent() && currentScreen && !currentScreen->geometry().contains(p: center)) {
580 const auto screens = currentScreen->virtualSiblings();
581 for (QPlatformScreen *screen : screens) {
582 const QRect screenGeometry = screen->geometry();
583 if (screenGeometry.contains(p: center))
584 return screen;
585 if (screenGeometry.intersects(r: 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*/
595QSize QPlatformWindow::constrainWindowSize(const QSize &size)
596{
597 return size.expandedTo(otherSize: QSize(0, 0)).boundedTo(otherSize: 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
608void 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
621bool 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.
631static 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(p: 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 */
663void QPlatformWindow::invalidateSurface()
664{
665}
666
667static QSize fixInitialSize(QSize size, const QWindow *w, int deviceIndependentDefaultWidth,
668 int deviceIndependentDefaultHeight)
669{
670 if (size.width() == 0) {
671 const int minWidth = w->minimumWidth();
672 size.setWidth(minWidth > 0 ? minWidth : deviceIndependentDefaultWidth);
673 }
674 if (size.height() == 0) {
675 const int minHeight = w->minimumHeight();
676 size.setHeight(minHeight > 0 ? minHeight : deviceIndependentDefaultHeight);
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
690 \a initialGeometry has to be provided in native pixels.
691 \a defaultWidth has to be provided in device independent pixels
692 \a defaultHeight has to be provided in device independent pixels
693*/
694QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeometry,
695 int defaultWidth, int defaultHeight,
696 const QScreen **resultingScreenReturn)
697{
698 if (resultingScreenReturn)
699 *resultingScreenReturn = w->screen();
700 if (!w->isTopLevel()) {
701 const qreal factor = QHighDpiScaling::factor(context: w);
702 const QSize deviceIndependentSize =
703 fixInitialSize(size: QHighDpi::fromNative(value: initialGeometry.size(), scaleFactor: factor), w,
704 deviceIndependentDefaultWidth: defaultWidth, deviceIndependentDefaultHeight: defaultHeight);
705 return QRect(initialGeometry.topLeft(), QHighDpi::toNative(value: deviceIndependentSize, scaleFactor: factor));
706 }
707 const auto *wp = qt_window_private(window: const_cast<QWindow*>(w));
708 const bool position = wp->positionAutomatic && w->type() != Qt::Popup;
709 if (!position && !wp->resizeAutomatic)
710 return initialGeometry;
711 const QScreen *screen = wp->positionAutomatic
712 ? effectiveScreen(window: w)
713 : QGuiApplication::screenAt(point: initialGeometry.center());
714 if (!screen)
715 return initialGeometry;
716 if (resultingScreenReturn)
717 *resultingScreenReturn = screen;
718 // initialGeometry refers to window's screen
719 QRect deviceIndependentRect(QHighDpi::fromNativePixels(value: initialGeometry, context: w));
720 if (wp->resizeAutomatic)
721 deviceIndependentRect.setSize(
722 fixInitialSize(size: deviceIndependentRect.size(), w, deviceIndependentDefaultWidth: defaultWidth, deviceIndependentDefaultHeight: defaultHeight));
723 if (position) {
724 const QRect availableDeviceIndependentGeometry = screen->availableGeometry();
725 // Center unless the geometry ( + unknown window frame) is too large for the screen).
726 if (deviceIndependentRect.height() < (availableDeviceIndependentGeometry.height() * 8) / 9
727 && deviceIndependentRect.width()
728 < (availableDeviceIndependentGeometry.width() * 8) / 9) {
729 const QWindow *tp = w->transientParent();
730 if (tp) {
731 // A transient window should be centered w.r.t. its transient parent.
732 deviceIndependentRect.moveCenter(p: tp->geometry().center());
733 } else {
734 // Center the window on the screen. (Only applicable on platforms
735 // which do not provide a better way.)
736 deviceIndependentRect.moveCenter(p: availableDeviceIndependentGeometry.center());
737 }
738 }
739 }
740 return QHighDpi::toNativePixels(value: deviceIndependentRect, context: screen);
741}
742
743/*!
744 Requests an QEvent::UpdateRequest event. The event will be
745 delivered to the QWindow.
746
747 QPlatformWindow subclasses can re-implement this function to
748 provide display refresh synchronized updates. The event
749 should be delivered using QPlatformWindow::deliverUpdateRequest()
750 to not get out of sync with the internal state of QWindow.
751
752 The default implementation posts an UpdateRequest event to the
753 window after 5 ms. The additional time is there to give the event
754 loop a bit of idle time to gather system events.
755
756*/
757void QPlatformWindow::requestUpdate()
758{
759 Q_D(QPlatformWindow);
760
761 static int updateInterval = []() {
762 bool ok = false;
763 int customUpdateInterval = qEnvironmentVariableIntValue(varName: "QT_QPA_UPDATE_IDLE_TIME", ok: &ok);
764 return ok ? customUpdateInterval : 5;
765 }();
766
767 Q_ASSERT(!d->updateTimer.isActive());
768 d->updateTimer.start(msec: updateInterval, timerType: Qt::PreciseTimer, obj: window());
769}
770
771/*!
772 Returns true if the window has a pending update request.
773
774 \sa requestUpdate(), deliverUpdateRequest()
775*/
776bool QPlatformWindow::hasPendingUpdateRequest() const
777{
778 return qt_window_private(window: window())->updateRequestPending;
779}
780
781/*!
782 Delivers an QEvent::UpdateRequest event to the window.
783
784 QPlatformWindow subclasses can re-implement this function to
785 provide e.g. logging or tracing of the delivery, but should
786 always call the base class function.
787*/
788void QPlatformWindow::deliverUpdateRequest()
789{
790 Q_ASSERT(hasPendingUpdateRequest());
791
792 QWindow *w = window();
793 QWindowPrivate *wp = qt_window_private(window: w);
794 wp->updateRequestPending = false;
795 QEvent request(QEvent::UpdateRequest);
796 QCoreApplication::sendEvent(receiver: w, event: &request);
797}
798
799/*!
800 Returns the QWindow minimum size.
801*/
802QSize QPlatformWindow::windowMinimumSize() const
803{
804 return constrainWindowSize(size: QHighDpi::toNativePixels(value: window()->minimumSize(), context: window()));
805}
806
807/*!
808 Returns the QWindow maximum size.
809*/
810QSize QPlatformWindow::windowMaximumSize() const
811{
812 return constrainWindowSize(size: QHighDpi::toNativePixels(value: window()->maximumSize(), context: window()));
813}
814
815/*!
816 Returns the QWindow base size.
817*/
818QSize QPlatformWindow::windowBaseSize() const
819{
820 return QHighDpi::toNativePixels(value: window()->baseSize(), context: window());
821}
822
823/*!
824 Returns the QWindow size increment.
825*/
826QSize QPlatformWindow::windowSizeIncrement() const
827{
828 QSize increment = window()->sizeIncrement();
829 if (!QHighDpiScaling::isActive())
830 return increment;
831
832 // Normalize the increment. If not set the increment can be
833 // (-1, -1) or (0, 0). Make that (1, 1) which is scalable.
834 if (increment.isEmpty())
835 increment = QSize(1, 1);
836
837 return QHighDpi::toNativePixels(value: increment, context: window());
838}
839
840/*!
841 Returns the QWindow geometry.
842*/
843QRect QPlatformWindow::windowGeometry() const
844{
845 return QHighDpi::toNativePixels(value: window()->geometry(), context: window());
846}
847
848/*!
849 Returns the QWindow frame geometry.
850*/
851QRect QPlatformWindow::windowFrameGeometry() const
852{
853 return QHighDpi::toNativePixels(value: window()->frameGeometry(), context: window());
854}
855
856/*!
857 Returns the closest acceptable geometry for a given geometry before
858 a resize/move event for platforms that support it, for example to
859 implement heightForWidth().
860*/
861
862QRectF QPlatformWindow::closestAcceptableGeometry(const QWindow *qWindow, const QRectF &nativeRect)
863{
864 const QRectF rectF = QHighDpi::fromNativePixels(value: nativeRect, context: qWindow);
865 const QRectF correctedGeometryF = qt_window_private(window: const_cast<QWindow *>(qWindow))->closestAcceptableGeometry(rect: rectF);
866 return !correctedGeometryF.isEmpty() && rectF != correctedGeometryF
867 ? QHighDpi::toNativePixels(value: correctedGeometryF, context: qWindow) : nativeRect;
868}
869
870QRectF QPlatformWindow::windowClosestAcceptableGeometry(const QRectF &nativeRect) const
871{
872 return QPlatformWindow::closestAcceptableGeometry(qWindow: window(), nativeRect);
873}
874
875/*!
876 \class QPlatformWindow
877 \since 4.8
878 \internal
879 \preliminary
880 \ingroup qpa
881
882 \brief The QPlatformWindow class provides an abstraction for top-level windows.
883
884 The QPlatformWindow abstraction is used by QWindow for all its top level windows. It is being
885 created by calling the createPlatformWindow function in the loaded QPlatformIntegration
886 instance.
887
888 QPlatformWindow is used to signal to the windowing system, how Qt perceives its frame.
889 However, it is not concerned with how Qt renders into the window it represents.
890
891 Visible QWindows will always have a QPlatformWindow. However, it is not necessary for
892 all windows to have a QBackingStore. This is the case for QOpenGLWindow. And could be the case for
893 windows where some third party renders into it.
894
895 The platform specific window handle can be retrieved by the winId function.
896
897 QPlatformWindow is also the way QPA defines how native child windows should be supported
898 through the setParent function.
899
900 \section1 Implementation Aspects
901
902 \list 1
903 \li Mouse grab: Qt expects windows to automatically grab the mouse if the user presses
904 a button until the button is released.
905 Automatic grab should be released if some window is explicitly grabbed.
906 \li Enter/Leave events: If there is a window explicitly grabbing mouse events
907 (\c{setMouseGrabEnabled()}), enter and leave events should only be sent to the
908 grabbing window when mouse cursor passes over the grabbing window boundary.
909 Other windows will not receive enter or leave events while the grab is active.
910 While an automatic mouse grab caused by a mouse button press is active, no window
911 will receive enter or leave events. When the last mouse button is released, the
912 autograbbing window will receive leave event if mouse cursor is no longer within
913 the window boundary.
914 When any grab starts, the window under cursor will receive a leave event unless
915 it is the grabbing window.
916 When any grab ends, the window under cursor will receive an enter event unless it
917 was the grabbing window.
918 \li Window positioning: When calling \c{QWindow::setFramePosition()}, the flag
919 \c{QWindowPrivate::positionPolicy} is set to \c{QWindowPrivate::WindowFrameInclusive}.
920 This means the position includes the window frame, whose size is at this point
921 unknown and the geometry's topleft point is the position of the window frame.
922 \endlist
923
924 Apart from the auto-tests (\c{tests/auto/gui/kernel/qwindow},
925 \c{tests/auto/gui/kernel/qguiapplication} and \c{tests/auto/widgets/kernel/qwidget}),
926 there are a number of manual tests and examples that can help testing a platform plugin:
927
928 \list 1
929 \li \c{examples/qpa/windows}: Basic \c{QWindow} creation.
930 \li \c{examples/opengl/hellowindow}: Basic Open GL windows.
931 \li \c{tests/manual/windowflags}: Tests setting the window flags.
932 \li \c{tests/manual/windowgeometry} Tests setting the window geometry.
933 \li \c{tests/manual/windowmodality} Tests setting the window modality.
934 \li \c{tests/manual/widgetgrab} Tests mouse grab and dialogs.
935 \endlist
936
937 \sa QBackingStore, QWindow
938*/
939
940QT_END_NAMESPACE
941

source code of qtbase/src/gui/kernel/qplatformwindow.cpp