Coverage Report

Created: 2025-07-16 07:53

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