Coverage Report

Created: 2026-07-25 07:03

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