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(window->geometry(), 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(), 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 = child->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
269QPointF QPlatformWindow::mapToGlobalF(const QPointF &pos) const
270{
271 const QPoint posPt = pos.toPoint();
272 const QPointF delta = pos - posPt;
273 return mapToGlobal(posPt) + delta;
274}
275
276QPointF QPlatformWindow::mapFromGlobalF(const QPointF &pos) const
277{
278 const QPoint posPt = pos.toPoint();
279 const QPointF delta = pos - posPt;
280 return mapFromGlobal(posPt) + delta;
281}
282
283/*!
284 Translates the global screen coordinate \a pos to window
285 coordinates using native methods. This is required for embedded windows,
286 where the topmost QWindow coordinates are not global screen coordinates.
287
288 Returns \a pos if there is no platform specific implementation.
289*/
290QPoint QPlatformWindow::mapFromGlobal(const QPoint &pos) const
291{
292 const QPlatformWindow *p = this;
293 QPoint result = pos;
294 while (p) {
295 result -= p->geometry().topLeft();
296 p = p->parent();
297 }
298 return result;
299}
300
301/*!
302 Requests setting the window state of this surface
303 to \a type.
304
305 Qt::WindowActive can be ignored.
306*/
307void QPlatformWindow::setWindowState(Qt::WindowStates)
308{
309}
310
311/*!
312 Reimplement in subclasses to return a handle to the native window
313*/
314WId QPlatformWindow::winId() const
315{
316 // Return anything but 0. Returning 0 would cause havoc with QWidgets on
317 // very basic platform plugins that do not reimplement this function,
318 // because the top-level widget's internalWinId() would always be 0 which
319 // would mean top-levels are never treated as native.
320 return WId(1);
321}
322
323//jl: It would be useful to have a property on the platform window which indicated if the sub-class
324// supported the setParent. If not, then geometry would be in screen coordinates.
325/*!
326 This function is called to enable native child window in QPA. It is common not to support this
327 feature in Window systems, but can be faked. When this function is called all geometry of this
328 platform window will be relative to the parent.
329*/
330void QPlatformWindow::setParent(const QPlatformWindow *parent)
331{
332 Q_UNUSED(parent);
333 qWarning("This plugin does not support setParent!");
334}
335
336/*!
337 Reimplement to set the window title to \a title.
338
339 The implementation might want to append the application display name to
340 the window title, like Windows and Linux do.
341
342 \sa QGuiApplication::applicationDisplayName()
343*/
344void QPlatformWindow::setWindowTitle(const QString &title) { Q_UNUSED(title); }
345
346/*!
347 Reimplement to set the window file path to \a filePath
348*/
349void QPlatformWindow::setWindowFilePath(const QString &filePath) { Q_UNUSED(filePath); }
350
351/*!
352 Reimplement to set the window icon to \a icon
353*/
354void QPlatformWindow::setWindowIcon(const QIcon &icon) { Q_UNUSED(icon); }
355
356/*!
357 Reimplement to let the platform handle non-spontaneous window close.
358
359 When reimplementing make sure to call the base class implementation
360 or QWindowSystemInterface::handleCloseEvent(), which will prompt the
361 user to accept the window close (if needed) and then close the QWindow.
362*/
363bool QPlatformWindow::close()
364{
365 return QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(window());
366}
367
368/*!
369 Reimplement to be able to let Qt raise windows to the top of the desktop
370*/
371void QPlatformWindow::raise() { qWarning("This plugin does not support raise()"); }
372
373/*!
374 Reimplement to be able to let Qt lower windows to the bottom of the desktop
375*/
376void QPlatformWindow::lower() { qWarning("This plugin does not support lower()"); }
377
378/*!
379 Reimplement to propagate the size hints of the QWindow.
380
381 The size hints include QWindow::minimumSize(), QWindow::maximumSize(),
382 QWindow::sizeIncrement(), and QWindow::baseSize().
383*/
384void QPlatformWindow::propagateSizeHints() {qWarning("This plugin does not support propagateSizeHints()"); }
385
386/*!
387 Reimplement to be able to let Qt set the opacity level of a window
388*/
389void QPlatformWindow::setOpacity(qreal level)
390{
391 Q_UNUSED(level);
392 qWarning("This plugin does not support setting window opacity");
393}
394
395/*!
396 Reimplement to be able to let Qt set the mask of a window
397*/
398
399void QPlatformWindow::setMask(const QRegion &region)
400{
401 Q_UNUSED(region);
402 qWarning("This plugin does not support setting window masks");
403}
404
405/*!
406 Reimplement to let Qt be able to request activation/focus for a window
407
408 Some window systems will probably not have callbacks for this functionality,
409 and then calling QWindowSystemInterface::handleWindowActivated(QWindow *w)
410 would be sufficient.
411
412 If the window system has some event handling/callbacks then call
413 QWindowSystemInterface::handleWindowActivated(QWindow *w) when the window system
414 gives the notification.
415
416 Default implementation calls QWindowSystem::handleWindowActivated(QWindow *w)
417*/
418void QPlatformWindow::requestActivateWindow()
419{
420 QWindowSystemInterface::handleWindowActivated(window());
421}
422
423/*!
424 Handle changes to the orientation of the platform window's contents.
425
426 This is a hint to the window manager in case it needs to display
427 additional content like popups, dialogs, status bars, or similar
428 in relation to the window.
429
430 \sa QWindow::reportContentOrientationChange()
431*/
432void QPlatformWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation)
433{
434 Q_UNUSED(orientation);
435}
436
437/*!
438 Reimplement this function in subclass to return the device pixel ratio
439 for the window. This is the ratio between physical pixels
440 and device-independent pixels.
441
442 \sa QPlatformWindow::devicePixelRatio();
443*/
444qreal QPlatformWindow::devicePixelRatio() const
445{
446 return 1.0;
447}
448
449bool QPlatformWindow::setKeyboardGrabEnabled(bool grab)
450{
451 Q_UNUSED(grab);
452 qWarning("This plugin does not support grabbing the keyboard");
453 return false;
454}
455
456bool QPlatformWindow::setMouseGrabEnabled(bool grab)
457{
458 Q_UNUSED(grab);
459 qWarning("This plugin does not support grabbing the mouse");
460 return false;
461}
462
463/*!
464 Reimplement to be able to let Qt indicate that the window has been
465 modified. Return true if the native window supports setting the modified
466 flag, false otherwise.
467*/
468bool QPlatformWindow::setWindowModified(bool modified)
469{
470 Q_UNUSED(modified);
471 return false;
472}
473
474/*!
475 Reimplement this method to be able to do any platform specific event
476 handling. All non-synthetic events for window() are passed to this
477 function before being sent to QWindow::event().
478
479 Return true if the event should not be passed on to the QWindow.
480
481 Subclasses should always call the base class implementation.
482*/
483bool QPlatformWindow::windowEvent(QEvent *event)
484{
485 Q_D(QPlatformWindow);
486
487 if (event->type() == QEvent::Timer) {
488 if (static_cast<QTimerEvent *>(event)->timerId() == d->updateTimer.timerId()) {
489 d->updateTimer.stop();
490 deliverUpdateRequest();
491 return true;
492 }
493 }
494
495 return false;
496}
497
498/*!
499 Reimplement this method to start a system resize operation if
500 the system supports it and return true to indicate success.
501
502 The default implementation is empty and does nothing with \a edges.
503
504 \since 5.15
505*/
506
507bool QPlatformWindow::startSystemResize(Qt::Edges edges)
508{
509 Q_UNUSED(edges);
510 return false;
511}
512
513/*!
514 Reimplement this method to start a system move operation if
515 the system supports it and return true to indicate success.
516
517 The default implementation is empty and does nothing.
518
519 \since 5.15
520*/
521
522bool QPlatformWindow::startSystemMove()
523{
524 return false;
525}
526
527/*!
528 Reimplement this method to set whether frame strut events
529 should be sent to \a enabled.
530
531 \sa frameStrutEventsEnabled
532*/
533
534void QPlatformWindow::setFrameStrutEventsEnabled(bool enabled)
535{
536 Q_UNUSED(enabled); // Do not warn as widgets enable it by default causing warnings with XCB.
537}
538
539/*!
540 Reimplement this method to return whether
541 frame strut events are enabled.
542*/
543
544bool QPlatformWindow::frameStrutEventsEnabled() const
545{
546 return false;
547}
548
549/*!
550 Call this method to put together a window title composed of
551 \a title
552 \a separator
553 the application display name
554
555 If the display name isn't set, and the title is empty, the raw app name is used.
556*/
557QString QPlatformWindow::formatWindowTitle(const QString &title, const QString &separator)
558{
559 QString fullTitle = title;
560 if (QGuiApplicationPrivate::displayName && !title.endsWith(*QGuiApplicationPrivate::displayName)) {
561 // Append display name, if set.
562 if (!fullTitle.isEmpty())
563 fullTitle += separator;
564 fullTitle += *QGuiApplicationPrivate::displayName;
565 } else if (fullTitle.isEmpty()) {
566 // Don't let the window title be completely empty, use the app name as fallback.
567 fullTitle = QCoreApplication::applicationName();
568 }
569 return fullTitle;
570}
571
572/*!
573 Helper function for finding the new screen for \a newGeometry in response to
574 a geometry changed event. Returns the new screen if the window was moved to
575 another virtual sibling. If the screen changes, the platform plugin should call
576 QWindowSystemInterface::handleWindowScreenChanged().
577 \note: The current screen will always be returned for child windows since
578 they should never signal screen changes.
579
580 \since 5.4
581 \sa QWindowSystemInterface::handleWindowScreenChanged()
582*/
583QPlatformScreen *QPlatformWindow::screenForGeometry(const QRect &newGeometry) const
584{
585 QPlatformScreen *currentScreen = screen();
586 QPlatformScreen *fallback = currentScreen;
587 // QRect::center can return a value outside the rectangle if it's empty.
588 // Apply mapToGlobal() in case it is a foreign/embedded window.
589 QPoint center = newGeometry.isEmpty() ? newGeometry.topLeft() : newGeometry.center();
590 if (isForeignWindow())
591 center = mapToGlobal(center - newGeometry.topLeft());
592
593 if (!parent() && currentScreen && !currentScreen->geometry().contains(center)) {
594 const auto screens = currentScreen->virtualSiblings();
595 for (QPlatformScreen *screen : screens) {
596 const QRect screenGeometry = screen->geometry();
597 if (screenGeometry.contains(center))
598 return screen;
599 if (screenGeometry.intersects(newGeometry))
600 fallback = screen;
601 }
602 }
603 return fallback;
604}
605
606/*!
607 Returns a size with both dimensions bounded to [0, QWINDOWSIZE_MAX]
608*/
609QSize QPlatformWindow::constrainWindowSize(const QSize &size)
610{
611 return size.expandedTo(QSize(0, 0)).boundedTo(QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX));
612}
613
614/*!
615 Reimplement this method to set whether the window demands attention
616 (for example, by flashing the taskbar icon) depending on \a enabled.
617
618 \sa isAlertState()
619 \since 5.1
620*/
621
622void QPlatformWindow::setAlertState(bool enable)
623{
624 Q_UNUSED(enable);
625}
626
627/*!
628 Reimplement this method return whether the window is in
629 an alert state.
630
631 \sa setAlertState()
632 \since 5.1
633*/
634
635bool QPlatformWindow::isAlertState() const
636{
637 return false;
638}
639
640// Return the effective screen for the initial geometry of a window. In a
641// multimonitor-setup, try to find the right screen by checking the transient
642// parent or the mouse cursor for parentless windows (cf QTBUG-34204,
643// QDialog::adjustPosition()), unless a non-primary screen has been set,
644// in which case we try to respect that.
645static inline const QScreen *effectiveScreen(const QWindow *window)
646{
647 if (!window)
648 return QGuiApplication::primaryScreen();
649 const QScreen *screen = window->screen();
650 if (!screen)
651 return QGuiApplication::primaryScreen();
652 if (screen != QGuiApplication::primaryScreen())
653 return screen;
654#ifndef QT_NO_CURSOR
655 const QList<QScreen *> siblings = screen->virtualSiblings();
656 if (siblings.size() > 1) {
657 const QPoint referencePoint = window->transientParent() ? window->transientParent()->geometry().center() : QCursor::pos();
658 for (const QScreen *sibling : siblings) {
659 if (sibling->geometry().contains(referencePoint))
660 return sibling;
661 }
662 }
663#endif
664 return screen;
665}
666
667/*!
668 Invalidates the window's surface by releasing its surface buffers.
669
670 Many platforms do not support releasing the surface memory,
671 and the default implementation does nothing.
672
673 The platform window is expected to recreate the surface again if
674 it is needed. For instance, if an OpenGL context is made current
675 on this window.
676 */
677void QPlatformWindow::invalidateSurface()
678{
679}
680
681static QSize fixInitialSize(QSize size, const QWindow *w,
682 int defaultWidth, int defaultHeight)
683{
684 if (size.width() == 0) {
685 const int minWidth = w->minimumWidth();
686 size.setWidth(minWidth > 0 ? minWidth : defaultWidth);
687 }
688 if (size.height() == 0) {
689 const int minHeight = w->minimumHeight();
690 size.setHeight(minHeight > 0 ? minHeight : defaultHeight);
691 }
692 return size;
693}
694
695/*!
696 Helper function to get initial geometry on windowing systems which do not
697 do smart positioning and also do not provide a means of centering a
698 transient window w.r.t. its parent. For example this is useful on Windows
699 and MacOS but not X11, because an X11 window manager typically tries to
700 layout new windows to optimize usage of the available desktop space.
701 However if the given window already has geometry which the application has
702 initialized, it takes priority.
703*/
704QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeometry,
705 int defaultWidth, int defaultHeight,
706 const QScreen **resultingScreenReturn)
707{
708 if (resultingScreenReturn)
709 *resultingScreenReturn = w->screen();
710 if (!w->isTopLevel()) {
711 const qreal factor = QHighDpiScaling::factor(w);
712 const QSize size = fixInitialSize(QHighDpi::fromNative(initialGeometry.size(), factor),
713 w, defaultWidth, defaultHeight);
714 return QRect(initialGeometry.topLeft(), QHighDpi::toNative(size, factor));
715 }
716 const auto *wp = qt_window_private(const_cast<QWindow*>(w));
717 const bool position = wp->positionAutomatic && w->type() != Qt::Popup;
718 if (!position && !wp->resizeAutomatic)
719 return initialGeometry;
720 const QScreen *screen = wp->positionAutomatic
721 ? effectiveScreen(w)
722 : QGuiApplication::screenAt(initialGeometry.center());
723 if (!screen)
724 return initialGeometry;
725 if (resultingScreenReturn)
726 *resultingScreenReturn = screen;
727 // initialGeometry refers to window's screen
728 QRect rect(QHighDpi::fromNativePixels(initialGeometry, w));
729 if (wp->resizeAutomatic)
730 rect.setSize(fixInitialSize(rect.size(), w, defaultWidth, defaultHeight));
731 if (position) {
732 const QRect availableGeometry = screen->availableGeometry();
733 // Center unless the geometry ( + unknown window frame) is too large for the screen).
734 if (rect.height() < (availableGeometry.height() * 8) / 9
735 && rect.width() < (availableGeometry.width() * 8) / 9) {
736 const QWindow *tp = w->transientParent();
737 if (tp) {
738 // A transient window should be centered w.r.t. its transient parent.
739 rect.moveCenter(tp->geometry().center());
740 } else {
741 // Center the window on the screen. (Only applicable on platforms
742 // which do not provide a better way.)
743 rect.moveCenter(availableGeometry.center());
744 }
745 }
746 }
747 return QHighDpi::toNativePixels(rect, screen);
748}
749
750/*!
751 Requests an QEvent::UpdateRequest event. The event will be
752 delivered to the QWindow.
753
754 QPlatformWindow subclasses can re-implement this function to
755 provide display refresh synchronized updates. The event
756 should be delivered using QPlatformWindow::deliverUpdateRequest()
757 to not get out of sync with the internal state of QWindow.
758
759 The default implementation posts an UpdateRequest event to the
760 window after 5 ms. The additional time is there to give the event
761 loop a bit of idle time to gather system events.
762
763*/
764void QPlatformWindow::requestUpdate()
765{
766 Q_D(QPlatformWindow);
767
768 static int updateInterval = []() {
769 bool ok = false;
770 int customUpdateInterval = qEnvironmentVariableIntValue("QT_QPA_UPDATE_IDLE_TIME", &ok);
771 return ok ? customUpdateInterval : 5;
772 }();
773
774 Q_ASSERT(!d->updateTimer.isActive());
775 d->updateTimer.start(updateInterval, Qt::PreciseTimer, window());
776}
777
778/*!
779 Returns true if the window has a pending update request.
780
781 \sa requestUpdate(), deliverUpdateRequest()
782*/
783bool QPlatformWindow::hasPendingUpdateRequest() const
784{
785 return qt_window_private(window())->updateRequestPending;
786}
787
788/*!
789 Delivers an QEvent::UpdateRequest event to the window.
790
791 QPlatformWindow subclasses can re-implement this function to
792 provide e.g. logging or tracing of the delivery, but should
793 always call the base class function.
794*/
795void QPlatformWindow::deliverUpdateRequest()
796{
797 Q_ASSERT(hasPendingUpdateRequest());
798
799 QWindow *w = window();
800 QWindowPrivate *wp = qt_window_private(w);
801 wp->updateRequestPending = false;
802 QEvent request(QEvent::UpdateRequest);
803 QCoreApplication::sendEvent(w, &request);
804}
805
806/*!
807 Returns the QWindow minimum size.
808*/
809QSize QPlatformWindow::windowMinimumSize() const
810{
811 return constrainWindowSize(QHighDpi::toNativePixels(window()->minimumSize(), window()));
812}
813
814/*!
815 Returns the QWindow maximum size.
816*/
817QSize QPlatformWindow::windowMaximumSize() const
818{
819 return constrainWindowSize(QHighDpi::toNativePixels(window()->maximumSize(), window()));
820}
821
822/*!
823 Returns the QWindow base size.
824*/
825QSize QPlatformWindow::windowBaseSize() const
826{
827 return QHighDpi::toNativePixels(window()->baseSize(), window());
828}
829
830/*!
831 Returns the QWindow size increment.
832*/
833QSize QPlatformWindow::windowSizeIncrement() const
834{
835 QSize increment = window()->sizeIncrement();
836 if (!QHighDpiScaling::isActive())
837 return increment;
838
839 // Normalize the increment. If not set the increment can be
840 // (-1, -1) or (0, 0). Make that (1, 1) which is scalable.
841 if (increment.isEmpty())
842 increment = QSize(1, 1);
843
844 return QHighDpi::toNativePixels(increment, window());
845}
846
847/*!
848 Returns the QWindow geometry.
849*/
850QRect QPlatformWindow::windowGeometry() const
851{
852 return QHighDpi::toNativeWindowGeometry(window()->geometry(), window());
853}
854
855/*!
856 Returns the QWindow frame geometry.
857*/
858QRect QPlatformWindow::windowFrameGeometry() const
859{
860 return QHighDpi::toNativeWindowGeometry(window()->frameGeometry(), window());
861}
862
863/*!
864 Returns the closest acceptable geometry for a given geometry before
865 a resize/move event for platforms that support it, for example to
866 implement heightForWidth().
867*/
868
869QRectF QPlatformWindow::closestAcceptableGeometry(const QWindow *qWindow, const QRectF &nativeRect)
870{
871 const QRectF rectF = QHighDpi::fromNativeWindowGeometry(nativeRect, qWindow);
872 const QRectF correctedGeometryF = qt_window_private(const_cast<QWindow *>(qWindow))->closestAcceptableGeometry(rectF);
873 return !correctedGeometryF.isEmpty() && rectF != correctedGeometryF
874 ? QHighDpi::toNativeWindowGeometry(correctedGeometryF, qWindow) : nativeRect;
875}
876
877QRectF QPlatformWindow::windowClosestAcceptableGeometry(const QRectF &nativeRect) const
878{
879 return QPlatformWindow::closestAcceptableGeometry(window(), nativeRect);
880}
881
882/*!
883 \class QPlatformWindow
884 \since 4.8
885 \internal
886 \preliminary
887 \ingroup qpa
888
889 \brief The QPlatformWindow class provides an abstraction for top-level windows.
890
891 The QPlatformWindow abstraction is used by QWindow for all its top level windows. It is being
892 created by calling the createPlatformWindow function in the loaded QPlatformIntegration
893 instance.
894
895 QPlatformWindow is used to signal to the windowing system, how Qt perceives its frame.
896 However, it is not concerned with how Qt renders into the window it represents.
897
898 Visible QWindows will always have a QPlatformWindow. However, it is not necessary for
899 all windows to have a QBackingStore. This is the case for QOpenGLWindow. And could be the case for
900 windows where some third party renders into it.
901
902 The platform specific window handle can be retrieved by the winId function.
903
904 QPlatformWindow is also the way QPA defines how native child windows should be supported
905 through the setParent function.
906
907 \section1 Implementation Aspects
908
909 \list 1
910 \li Mouse grab: Qt expects windows to automatically grab the mouse if the user presses
911 a button until the button is released.
912 Automatic grab should be released if some window is explicitly grabbed.
913 \li Enter/Leave events: If there is a window explicitly grabbing mouse events
914 (\c{setMouseGrabEnabled()}), enter and leave events should only be sent to the
915 grabbing window when mouse cursor passes over the grabbing window boundary.
916 Other windows will not receive enter or leave events while the grab is active.
917 While an automatic mouse grab caused by a mouse button press is active, no window
918 will receive enter or leave events. When the last mouse button is released, the
919 autograbbing window will receive leave event if mouse cursor is no longer within
920 the window boundary.
921 When any grab starts, the window under cursor will receive a leave event unless
922 it is the grabbing window.
923 When any grab ends, the window under cursor will receive an enter event unless it
924 was the grabbing window.
925 \li Window positioning: When calling \c{QWindow::setFramePosition()}, the flag
926 \c{QWindowPrivate::positionPolicy} is set to \c{QWindowPrivate::WindowFrameInclusive}.
927 This means the position includes the window frame, whose size is at this point
928 unknown and the geometry's topleft point is the position of the window frame.
929 \endlist
930
931 Apart from the auto-tests (\c{tests/auto/gui/kernel/qwindow},
932 \c{tests/auto/gui/kernel/qguiapplication} and \c{tests/auto/widgets/kernel/qwidget}),
933 there are a number of manual tests and examples that can help testing a platform plugin:
934
935 \list 1
936 \li \c{examples/qpa/windows}: Basic \c{QWindow} creation.
937 \li \c{examples/opengl/hellowindow}: Basic Open GL windows.
938 \li \c{tests/manual/windowflags}: Tests setting the window flags.
939 \li \c{tests/manual/windowgeometry} Tests setting the window geometry.
940 \li \c{tests/manual/windowmodality} Tests setting the window modality.
941 \li \c{tests/manual/widgetgrab} Tests mouse grab and dialogs.
942 \endlist
943
944 \sa QBackingStore, QWindow
945*/
946
947QT_END_NAMESPACE
948