| 1 | // Copyright (C) 2020 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 | #ifndef QWIDGET_P_H |
| 5 | #define QWIDGET_P_H |
| 6 | |
| 7 | // |
| 8 | // W A R N I N G |
| 9 | // ------------- |
| 10 | // |
| 11 | // This file is not part of the Qt API. It exists for the convenience |
| 12 | // of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header |
| 13 | // file may change from version to version without notice, or even be removed. |
| 14 | // |
| 15 | // We mean it. |
| 16 | // |
| 17 | |
| 18 | |
| 19 | |
| 20 | #include <QtWidgets/private/qtwidgetsglobal_p.h> |
| 21 | #include "QtWidgets/qwidget.h" |
| 22 | #include "private/qobject_p.h" |
| 23 | #include "QtCore/qrect.h" |
| 24 | #include "QtCore/qlocale.h" |
| 25 | #include "QtCore/qset.h" |
| 26 | #include "QtGui/qregion.h" |
| 27 | #include "QtGui/qinputmethod.h" |
| 28 | #include "QtGui/qsurfaceformat.h" |
| 29 | #include "QtGui/qscreen.h" |
| 30 | #include "QtWidgets/qsizepolicy.h" |
| 31 | #include "QtWidgets/qstyle.h" |
| 32 | #include "QtWidgets/qapplication.h" |
| 33 | #if QT_CONFIG(graphicseffect) |
| 34 | #include <private/qgraphicseffect_p.h> |
| 35 | #endif |
| 36 | #if QT_CONFIG(graphicsview) |
| 37 | #include "QtWidgets/qgraphicsproxywidget.h" |
| 38 | #include "QtWidgets/qgraphicsscene.h" |
| 39 | #include "QtWidgets/qgraphicsview.h" |
| 40 | #endif |
| 41 | #include <private/qgesture_p.h> |
| 42 | #include <qpa/qplatformbackingstore.h> |
| 43 | #include <QtGui/private/qbackingstorerhisupport_p.h> |
| 44 | #include <private/qapplication_p.h> |
| 45 | |
| 46 | #include <QtCore/qpointer.h> |
| 47 | |
| 48 | #include <vector> |
| 49 | #include <memory> |
| 50 | |
| 51 | QT_BEGIN_NAMESPACE |
| 52 | |
| 53 | Q_DECLARE_LOGGING_CATEGORY(lcWidgetPainting); |
| 54 | Q_DECLARE_LOGGING_CATEGORY(lcWidgetShowHide); |
| 55 | |
| 56 | // Extra QWidget data |
| 57 | // - to minimize memory usage for members that are seldom used. |
| 58 | // - top-level widgets have extra extra data to reduce cost further |
| 59 | class QWidgetWindow; |
| 60 | class QPaintEngine; |
| 61 | class QPixmap; |
| 62 | class QWidgetRepaintManager; |
| 63 | class QGraphicsProxyWidget; |
| 64 | class QWidgetItemV2; |
| 65 | |
| 66 | class QStyle; |
| 67 | |
| 68 | class QUnifiedToolbarSurface; |
| 69 | |
| 70 | // implemented in qshortcut.cpp |
| 71 | bool qWidgetShortcutContextMatcher(QObject *object, Qt::ShortcutContext context); |
| 72 | void qSendWindowChangeToTextureChildrenRecursively(QWidget *widget, QEvent::Type eventType); |
| 73 | |
| 74 | class QUpdateLaterEvent : public QEvent |
| 75 | { |
| 76 | public: |
| 77 | explicit QUpdateLaterEvent(const QRegion& paintRegion) |
| 78 | : QEvent(UpdateLater), m_region(paintRegion) |
| 79 | { |
| 80 | } |
| 81 | |
| 82 | inline const QRegion ®ion() const { return m_region; } |
| 83 | |
| 84 | protected: |
| 85 | friend class QApplication; |
| 86 | QRegion m_region; |
| 87 | }; |
| 88 | |
| 89 | struct { |
| 90 | // *************************** Cross-platform variables ***************************** |
| 91 | |
| 92 | // Regular pointers (keep them together to avoid gaps on 64 bits architectures). |
| 93 | std::unique_ptr<QIcon> ; // widget icon |
| 94 | std::unique_ptr<QWidgetRepaintManager> ; |
| 95 | QBackingStore *; |
| 96 | QPainter *; |
| 97 | QWidgetWindow *; |
| 98 | |
| 99 | // Implicit pointers (shared_null). |
| 100 | QString ; // widget caption |
| 101 | QString ; // widget icon text |
| 102 | QString ; // widget role |
| 103 | QString ; // widget file path |
| 104 | |
| 105 | // Other variables. |
| 106 | short , ; // size increments |
| 107 | short , ; // base sizes |
| 108 | // frame strut, don't use these directly, use QWidgetPrivate::frameStrut() instead. |
| 109 | QRect ; |
| 110 | QRect ; // used by showMin/maximized/FullScreen |
| 111 | Qt::WindowFlags ; // Save widget flags while showing fullscreen |
| 112 | QPointer<QScreen> ; // Screen when passing a QDesktop[Screen]Widget as parent. |
| 113 | |
| 114 | std::vector<std::unique_ptr<QPlatformTextureList>> ; |
| 115 | |
| 116 | // *************************** Cross-platform bit fields **************************** |
| 117 | uint : 8; |
| 118 | uint : 1; |
| 119 | uint : 1; |
| 120 | uint : 1; |
| 121 | }; |
| 122 | |
| 123 | struct { |
| 124 | // *************************** Cross-platform variables ***************************** |
| 125 | |
| 126 | // Regular pointers (keep them together to avoid gaps on 64 bits architectures). |
| 127 | void *; // if the widget is hijacked by QGLWindowSurface |
| 128 | std::unique_ptr<QTLWExtra> ; // only useful for TLWs |
| 129 | #if QT_CONFIG(graphicsview) |
| 130 | QGraphicsProxyWidget *; // if the widget is embedded |
| 131 | #endif |
| 132 | #ifndef QT_NO_CURSOR |
| 133 | std::unique_ptr<QCursor> ; |
| 134 | #endif |
| 135 | QPointer<QStyle> ; |
| 136 | QPointer<QWidget> ; |
| 137 | |
| 138 | // Implicit pointers (shared_empty/shared_null). |
| 139 | QRegion ; // widget mask |
| 140 | QString ; |
| 141 | |
| 142 | // Other variables. |
| 143 | qint32 ; |
| 144 | qint32 ; // minimum size |
| 145 | qint32 ; |
| 146 | qint32 ; // maximum size |
| 147 | quint16 ; |
| 148 | quint16 ; |
| 149 | QSize ; |
| 150 | |
| 151 | // *************************** Cross-platform bit fields **************************** |
| 152 | uint : 2; |
| 153 | uint : 2; |
| 154 | uint : 1; |
| 155 | uint : 1; |
| 156 | uint : 1; |
| 157 | uint : 1; |
| 158 | uint : 1; |
| 159 | }; |
| 160 | |
| 161 | /*! |
| 162 | \internal |
| 163 | |
| 164 | Returns \c true if \a p or any of its parents enable the |
| 165 | Qt::BypassGraphicsProxyWidget window flag. Used in QWidget::show() and |
| 166 | QWidget::setParent() to determine whether it's necessary to embed the |
| 167 | widget into a QGraphicsProxyWidget or not. |
| 168 | */ |
| 169 | static inline bool bypassGraphicsProxyWidget(const QWidget *p) |
| 170 | { |
| 171 | while (p) { |
| 172 | if (p->windowFlags() & Qt::BypassGraphicsProxyWidget) |
| 173 | return true; |
| 174 | p = p->parentWidget(); |
| 175 | } |
| 176 | return false; |
| 177 | } |
| 178 | |
| 179 | class Q_WIDGETS_EXPORT QWidgetPrivate : public QObjectPrivate |
| 180 | { |
| 181 | Q_DECLARE_PUBLIC(QWidget) |
| 182 | Q_GADGET |
| 183 | |
| 184 | public: |
| 185 | // *************************** Cross-platform *************************************** |
| 186 | enum DrawWidgetFlag { |
| 187 | DrawAsRoot = 0x01, |
| 188 | DrawPaintOnScreen = 0x02, |
| 189 | DrawRecursive = 0x04, |
| 190 | DrawInvisible = 0x08, |
| 191 | DontSubtractOpaqueChildren = 0x10, |
| 192 | DontDrawOpaqueChildren = 0x20, |
| 193 | DontDrawNativeChildren = 0x40, |
| 194 | DontSetCompositionMode = 0x80, |
| 195 | UseEffectRegionBounds = 0x100 |
| 196 | }; |
| 197 | Q_DECLARE_FLAGS(DrawWidgetFlags, DrawWidgetFlag) |
| 198 | Q_FLAG(DrawWidgetFlags) |
| 199 | |
| 200 | enum Direction { |
| 201 | DirectionNorth = 0x01, |
| 202 | DirectionEast = 0x10, |
| 203 | DirectionSouth = 0x02, |
| 204 | DirectionWest = 0x20 |
| 205 | }; |
| 206 | Q_ENUM(Direction) |
| 207 | |
| 208 | // Functions. |
| 209 | explicit QWidgetPrivate(int version = QObjectPrivateVersion); |
| 210 | ~QWidgetPrivate(); |
| 211 | |
| 212 | static QWidgetPrivate *get(QWidget *w) { return w->d_func(); } |
| 213 | static const QWidgetPrivate *get(const QWidget *w) { return w->d_func(); } |
| 214 | |
| 215 | static void checkRestoredGeometry(const QRect &availableGeometry, QRect *restoredGeometry, |
| 216 | int frameHeight); |
| 217 | |
| 218 | QWExtra *extraData() const; |
| 219 | QTLWExtra *topData() const; |
| 220 | QTLWExtra *maybeTopData() const; |
| 221 | QPainter *sharedPainter() const; |
| 222 | void setSharedPainter(QPainter *painter); |
| 223 | QWidgetRepaintManager *maybeRepaintManager() const; |
| 224 | |
| 225 | QRhi *rhi() const; |
| 226 | |
| 227 | enum class WindowHandleMode { |
| 228 | Direct, |
| 229 | Closest, |
| 230 | TopLevel |
| 231 | }; |
| 232 | QWindow *windowHandle(WindowHandleMode mode = WindowHandleMode::Direct) const; |
| 233 | QWindow *_q_closestWindowHandle() const; // Private slot in QWidget |
| 234 | |
| 235 | QScreen *associatedScreen() const; |
| 236 | |
| 237 | template <typename T> |
| 238 | void repaint(T t); |
| 239 | |
| 240 | template <typename T> |
| 241 | void update(T t); |
| 242 | |
| 243 | void init(QWidget *desktopWidget, Qt::WindowFlags f); |
| 244 | void create(); |
| 245 | void createRecursively(); |
| 246 | void createWinId(); |
| 247 | |
| 248 | bool setScreenForPoint(const QPoint &pos); |
| 249 | bool setScreen(QScreen *screen); |
| 250 | |
| 251 | void (); |
| 252 | void (); |
| 253 | void (); |
| 254 | void (); |
| 255 | void (); |
| 256 | void (); |
| 257 | void (); |
| 258 | void updateSystemBackground(); |
| 259 | void propagatePaletteChange(); |
| 260 | |
| 261 | void setPalette_helper(const QPalette &); |
| 262 | void resolvePalette(); |
| 263 | QPalette naturalWidgetPalette(QPalette::ResolveMask inheritedMask) const; |
| 264 | |
| 265 | void setMask_sys(const QRegion &); |
| 266 | |
| 267 | void raise_sys(); |
| 268 | void lower_sys(); |
| 269 | void stackUnder_sys(QWidget *); |
| 270 | |
| 271 | QWidget *deepestFocusProxy() const; |
| 272 | void setFocus_sys(); |
| 273 | void updateFocusChild(); |
| 274 | |
| 275 | void updateFont(const QFont &); |
| 276 | inline void setFont_helper(const QFont &font) { |
| 277 | if (directFontResolveMask == font.resolveMask() && data.fnt == font) |
| 278 | return; |
| 279 | updateFont(font); |
| 280 | } |
| 281 | QFont localFont() const; |
| 282 | void resolveFont(); |
| 283 | QFont naturalWidgetFont(uint inheritedMask) const; |
| 284 | |
| 285 | void setLayoutDirection_helper(Qt::LayoutDirection); |
| 286 | void resolveLayoutDirection(); |
| 287 | |
| 288 | void setLocale_helper(const QLocale &l, bool forceUpdate = false); |
| 289 | void resolveLocale(); |
| 290 | |
| 291 | void setStyle_helper(QStyle *newStyle, bool propagate); |
| 292 | void inheritStyle(); |
| 293 | |
| 294 | void setUpdatesEnabled_helper(bool ); |
| 295 | |
| 296 | bool updateBrushOrigin(QPainter *, const QBrush &brush) const; |
| 297 | void paintBackground(QPainter *, const QRegion &, DrawWidgetFlags flags = DrawAsRoot) const; |
| 298 | bool isAboutToShow() const; |
| 299 | QRegion prepareToRender(const QRegion ®ion, QWidget::RenderFlags renderFlags); |
| 300 | void render_helper(QPainter *painter, const QPoint &targetOffset, const QRegion &sourceRegion, |
| 301 | QWidget::RenderFlags renderFlags); |
| 302 | void render(QPaintDevice *target, const QPoint &targetOffset, const QRegion &sourceRegion, |
| 303 | QWidget::RenderFlags renderFlags); |
| 304 | void drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QPoint &offset, DrawWidgetFlags flags, |
| 305 | QPainter *sharedPainter = nullptr, QWidgetRepaintManager *repaintManager = nullptr); |
| 306 | void sendPaintEvent(const QRegion &toBePainted); |
| 307 | |
| 308 | |
| 309 | void paintSiblingsRecursive(QPaintDevice *pdev, const QObjectList& children, int index, |
| 310 | const QRegion &rgn, const QPoint &offset, DrawWidgetFlags flags, |
| 311 | QPainter *sharedPainter, QWidgetRepaintManager *repaintManager); |
| 312 | |
| 313 | #if QT_CONFIG(graphicsview) |
| 314 | static QGraphicsProxyWidget * nearestGraphicsProxyWidget(const QWidget *origin); |
| 315 | #endif |
| 316 | bool shouldPaintOnScreen() const; |
| 317 | void paintOnScreen(const QRegion &rgn); |
| 318 | |
| 319 | QRect clipRect() const; |
| 320 | QRegion clipRegion() const; |
| 321 | void setSystemClip(QPaintEngine *paintEngine, qreal devicePixelRatio, const QRegion ®ion); |
| 322 | void subtractOpaqueChildren(QRegion &rgn, const QRect &clipRect) const; |
| 323 | void subtractOpaqueSiblings(QRegion &source, bool *hasDirtySiblingsAbove = nullptr, |
| 324 | bool alsoNonOpaque = false) const; |
| 325 | void clipToEffectiveMask(QRegion ®ion) const; |
| 326 | void updateIsOpaque(); |
| 327 | void setOpaque(bool opaque); |
| 328 | void updateIsTranslucent(); |
| 329 | #if QT_CONFIG(graphicseffect) |
| 330 | void invalidateGraphicsEffectsRecursively(); |
| 331 | #endif // QT_CONFIG(graphicseffect) |
| 332 | |
| 333 | const QRegion &getOpaqueChildren() const; |
| 334 | void setDirtyOpaqueRegion(); |
| 335 | |
| 336 | bool close(); |
| 337 | enum CloseMode { |
| 338 | CloseNoEvent, |
| 339 | CloseWithEvent, |
| 340 | CloseWithSpontaneousEvent |
| 341 | }; |
| 342 | Q_ENUM(CloseMode) |
| 343 | bool handleClose(CloseMode mode); |
| 344 | |
| 345 | void setWindowIcon_helper(); |
| 346 | void setWindowIcon_sys(); |
| 347 | void setWindowOpacity_sys(qreal opacity); |
| 348 | void adjustQuitOnCloseAttribute(); |
| 349 | |
| 350 | void scrollChildren(int dx, int dy); |
| 351 | void moveRect(const QRect &, int dx, int dy); |
| 352 | void scrollRect(const QRect &, int dx, int dy); |
| 353 | void invalidateBackingStore_resizeHelper(const QPoint &oldPos, const QSize &oldSize); |
| 354 | |
| 355 | template <class T> |
| 356 | void invalidateBackingStore(const T &); |
| 357 | |
| 358 | QRegion overlappedRegion(const QRect &rect, bool breakAfterFirst = false) const; |
| 359 | bool isOverlapped(const QRect &rect) const { return !overlappedRegion(rect, breakAfterFirst: true).isEmpty(); } |
| 360 | void syncBackingStore(); |
| 361 | void syncBackingStore(const QRegion ®ion); |
| 362 | |
| 363 | bool shouldDiscardSyncRequest() const; |
| 364 | |
| 365 | // tells the input method about the widgets transform |
| 366 | void updateWidgetTransform(QEvent *event); |
| 367 | |
| 368 | void reparentFocusWidgets(QWidget *oldtlw); |
| 369 | |
| 370 | void setWinId(WId); |
| 371 | void showChildren(bool spontaneous); |
| 372 | void hideChildren(bool spontaneous); |
| 373 | void setParent_sys(QWidget *parent, Qt::WindowFlags); |
| 374 | void reparentWidgetWindows(QWidget *parentWithWindow, Qt::WindowFlags windowFlags = {}); |
| 375 | void reparentWidgetWindowChildren(QWidget *parentWithWindow); |
| 376 | void scroll_sys(int dx, int dy); |
| 377 | void scroll_sys(int dx, int dy, const QRect &r); |
| 378 | void deactivateWidgetCleanup(); |
| 379 | void setGeometry_sys(int, int, int, int, bool); |
| 380 | void fixPosIncludesFrame(); |
| 381 | void sendPendingMoveAndResizeEvents(bool recursive = false, bool disableUpdates = false); |
| 382 | void activateChildLayoutsRecursively(); |
| 383 | void show_recursive(); |
| 384 | void show_helper(); |
| 385 | void show_sys(); |
| 386 | void hide_sys(); |
| 387 | void hide_helper(); |
| 388 | bool isExplicitlyHidden() const; |
| 389 | void _q_showIfNotHidden(); |
| 390 | virtual void setVisible(bool); |
| 391 | |
| 392 | void setEnabled_helper(bool); |
| 393 | static void adjustFlags(Qt::WindowFlags &flags, QWidget *w = nullptr); |
| 394 | |
| 395 | void updateFrameStrut(); |
| 396 | QRect frameStrut() const; |
| 397 | |
| 398 | #ifdef QT_KEYPAD_NAVIGATION |
| 399 | static bool navigateToDirection(Direction direction); |
| 400 | static QWidget *widgetInNavigationDirection(Direction direction); |
| 401 | static bool canKeypadNavigate(Qt::Orientation orientation); |
| 402 | static bool inTabWidget(QWidget *widget); |
| 403 | #endif |
| 404 | |
| 405 | void setWindowIconText_sys(const QString &cap); |
| 406 | void setWindowIconText_helper(const QString &cap); |
| 407 | void setWindowTitle_sys(const QString &cap); |
| 408 | void setWindowFilePath_sys(const QString &filePath); |
| 409 | |
| 410 | #ifndef QT_NO_CURSOR |
| 411 | void setCursor_sys(const QCursor &cursor); |
| 412 | void unsetCursor_sys(); |
| 413 | #endif |
| 414 | |
| 415 | void setWindowTitle_helper(const QString &cap); |
| 416 | void setWindowFilePath_helper(const QString &filePath); |
| 417 | void setWindowModified_helper(); |
| 418 | virtual void setWindowFlags(Qt::WindowFlags windowFlags); |
| 419 | |
| 420 | bool setMinimumSize_helper(int &minw, int &minh); |
| 421 | bool setMaximumSize_helper(int &maxw, int &maxh); |
| 422 | void setConstraints_sys(); |
| 423 | bool pointInsideRectAndMask(const QPointF &) const; |
| 424 | QWidget *childAt_helper(const QPointF &, bool) const; |
| 425 | QWidget *childAtRecursiveHelper(const QPointF &p, bool) const; |
| 426 | void updateGeometry_helper(bool forceUpdate); |
| 427 | |
| 428 | void getLayoutItemMargins(int *left, int *top, int *right, int *bottom) const; |
| 429 | void setLayoutItemMargins(int left, int top, int right, int bottom); |
| 430 | void setLayoutItemMargins(QStyle::SubElement element, const QStyleOption *opt = nullptr); |
| 431 | |
| 432 | void updateContentsRect(); |
| 433 | QMargins safeAreaMargins() const; |
| 434 | |
| 435 | // aboutToDestroy() is called just before the contents of |
| 436 | // QWidget::destroy() is executed. It's used to signal QWidget |
| 437 | // sub-classes that their internals are about to be released. |
| 438 | virtual void aboutToDestroy() {} |
| 439 | |
| 440 | inline QWidget *effectiveFocusWidget() { |
| 441 | QWidget *w = q_func(); |
| 442 | while (w->focusProxy()) |
| 443 | w = w->focusProxy(); |
| 444 | return w; |
| 445 | } |
| 446 | |
| 447 | void setModal_sys(); |
| 448 | |
| 449 | // These helper functions return the (available) geometry for the screen |
| 450 | // the widget is on, and takes care if this one is embedded in a QGraphicsView. |
| 451 | static QWidget *parentGraphicsView(const QWidget *widget) |
| 452 | { |
| 453 | #if QT_CONFIG(graphicsview) |
| 454 | QGraphicsProxyWidget *ancestorProxy = widget->d_func()->nearestGraphicsProxyWidget(origin: widget); |
| 455 | //It's embedded if it has an ancestor |
| 456 | if (ancestorProxy) { |
| 457 | if (!bypassGraphicsProxyWidget(p: widget) && ancestorProxy->scene() != nullptr) { |
| 458 | if (!ancestorProxy->scene()->views().empty()) { |
| 459 | return ancestorProxy->scene()->views().at(i: 0); |
| 460 | } |
| 461 | } |
| 462 | } |
| 463 | #else |
| 464 | Q_UNUSED(widget); |
| 465 | #endif |
| 466 | return nullptr; |
| 467 | } |
| 468 | |
| 469 | static QRect screenGeometry(const QWidget *widget) |
| 470 | { |
| 471 | return screenGeometry(widget, globalPosition: QPoint(), hasPosition: false); |
| 472 | } |
| 473 | |
| 474 | static QRect availableScreenGeometry(const QWidget *widget) |
| 475 | { |
| 476 | return availableScreenGeometry(widget, globalPosition: QPoint(), hasPosition: false); |
| 477 | } |
| 478 | |
| 479 | static QScreen *screen(const QWidget *widget, const QPoint &globalPosition, bool hasPosition = true) |
| 480 | { |
| 481 | while (QWidget *view = parentGraphicsView(widget)) |
| 482 | widget = view; |
| 483 | |
| 484 | QScreen *screen = nullptr; |
| 485 | if (hasPosition) |
| 486 | screen = widget->screen()->virtualSiblingAt(point: globalPosition); |
| 487 | if (!screen) |
| 488 | screen = widget->screen(); |
| 489 | |
| 490 | return screen; |
| 491 | } |
| 492 | |
| 493 | static QRect screenGeometry(const QWidget *widget, const QPoint &globalPosition, bool hasPosition = true) |
| 494 | { |
| 495 | return screen(widget, globalPosition, hasPosition)->geometry(); |
| 496 | } |
| 497 | |
| 498 | static QRect availableScreenGeometry(const QWidget *widget, const QPoint &globalPosition, bool hasPosition = true) |
| 499 | { |
| 500 | return screen(widget, globalPosition, hasPosition)->availableGeometry(); |
| 501 | } |
| 502 | |
| 503 | inline void setRedirected(QPaintDevice *replacement, const QPoint &offset) |
| 504 | { |
| 505 | Q_ASSERT(q_func()->testAttribute(Qt::WA_WState_InPaintEvent)); |
| 506 | redirectDev = replacement; |
| 507 | redirectOffset = offset; |
| 508 | } |
| 509 | |
| 510 | inline QPaintDevice *redirected(QPoint *offset) const |
| 511 | { |
| 512 | if (offset) |
| 513 | *offset = redirectDev ? redirectOffset : QPoint(); |
| 514 | return redirectDev; |
| 515 | } |
| 516 | |
| 517 | inline void restoreRedirected() |
| 518 | { redirectDev = nullptr; } |
| 519 | |
| 520 | inline void enforceNativeChildren() |
| 521 | { |
| 522 | if (!extra) |
| 523 | createExtra(); |
| 524 | |
| 525 | if (extra->nativeChildrenForced) |
| 526 | return; |
| 527 | extra->nativeChildrenForced = 1; |
| 528 | |
| 529 | for (int i = 0; i < children.size(); ++i) { |
| 530 | if (QWidget *child = qobject_cast<QWidget *>(o: children.at(i))) |
| 531 | child->setAttribute(Qt::WA_NativeWindow); |
| 532 | } |
| 533 | } |
| 534 | |
| 535 | inline bool nativeChildrenForced() const |
| 536 | { |
| 537 | return extra ? extra->nativeChildrenForced : false; |
| 538 | } |
| 539 | |
| 540 | inline QRect effectiveRectFor(const QRegion ®ion) const |
| 541 | { |
| 542 | return effectiveRectFor(rect: region.boundingRect()); |
| 543 | } |
| 544 | |
| 545 | inline QRect effectiveRectFor(const QRect &rect) const |
| 546 | { |
| 547 | #if QT_CONFIG(graphicseffect) |
| 548 | if (graphicsEffect && graphicsEffect->isEnabled()) |
| 549 | return graphicsEffect->boundingRectFor(sourceRect: rect).toAlignedRect(); |
| 550 | #endif // QT_CONFIG(graphicseffect) |
| 551 | return rect; |
| 552 | } |
| 553 | |
| 554 | QSize adjustedSize() const; |
| 555 | |
| 556 | inline void handleSoftwareInputPanel(Qt::MouseButton button, bool clickCausedFocus) |
| 557 | { |
| 558 | if (button == Qt::LeftButton) |
| 559 | handleSoftwareInputPanel(clickCausedFocus); |
| 560 | } |
| 561 | |
| 562 | inline void handleSoftwareInputPanel(bool clickCausedFocus = false) |
| 563 | { |
| 564 | Q_Q(QWidget); |
| 565 | if (qApp->autoSipEnabled()) { |
| 566 | QStyle::RequestSoftwareInputPanel behavior = QStyle::RequestSoftwareInputPanel( |
| 567 | q->style()->styleHint(stylehint: QStyle::SH_RequestSoftwareInputPanel, opt: nullptr, widget: q)); |
| 568 | if (!clickCausedFocus || behavior == QStyle::RSIP_OnMouseClick) { |
| 569 | QGuiApplication::inputMethod()->show(); |
| 570 | } |
| 571 | } |
| 572 | } |
| 573 | |
| 574 | void setWSGeometry(); |
| 575 | |
| 576 | inline QPoint mapToWS(const QPoint &p) const |
| 577 | { return p - data.wrect.topLeft(); } |
| 578 | |
| 579 | inline QPoint mapFromWS(const QPoint &p) const |
| 580 | { return p + data.wrect.topLeft(); } |
| 581 | |
| 582 | inline QRect mapToWS(const QRect &r) const |
| 583 | { return r.translated(p: -data.wrect.topLeft()); } |
| 584 | |
| 585 | inline QRect mapFromWS(const QRect &r) const |
| 586 | { return r.translated(p: data.wrect.topLeft()); } |
| 587 | |
| 588 | virtual QObject *focusObject(); |
| 589 | |
| 590 | virtual QPlatformBackingStoreRhiConfig rhiConfig() const { return {}; } |
| 591 | |
| 592 | // Note that textureRight may be null, as it's only used in stereoscopic rendering |
| 593 | struct TextureData { |
| 594 | QRhiTexture *textureLeft = nullptr; |
| 595 | QRhiTexture *textureRight = nullptr; |
| 596 | }; |
| 597 | |
| 598 | virtual TextureData texture() const { return {}; } |
| 599 | virtual QPlatformTextureList::Flags textureListFlags() { |
| 600 | Q_Q(QWidget); |
| 601 | return q->testAttribute(attribute: Qt::WA_AlwaysStackOnTop) |
| 602 | ? QPlatformTextureList::StacksOnTop |
| 603 | : QPlatformTextureList::Flags(); |
| 604 | } |
| 605 | virtual QImage grabFramebuffer() { return QImage(); } |
| 606 | virtual void beginBackingStorePainting() { } |
| 607 | virtual void endBackingStorePainting() { } |
| 608 | virtual void beginCompose() { } |
| 609 | virtual void endCompose() { } |
| 610 | void setRenderToTexture() { renderToTexture = true; setTextureChildSeen(); } |
| 611 | void setTextureChildSeen() |
| 612 | { |
| 613 | Q_Q(QWidget); |
| 614 | if (textureChildSeen) |
| 615 | return; |
| 616 | textureChildSeen = 1; |
| 617 | |
| 618 | if (!q->isWindow()) { |
| 619 | QWidget *parent = q->parentWidget(); |
| 620 | if (parent) |
| 621 | get(w: parent)->setTextureChildSeen(); |
| 622 | } |
| 623 | } |
| 624 | static void sendComposeStatus(QWidget *w, bool end); |
| 625 | // Called on setViewport(). |
| 626 | virtual void initializeViewportFramebuffer() { } |
| 627 | // When using a QOpenGLWidget as viewport with QAbstractScrollArea, resize events are |
| 628 | // filtered away from the widget. This is fine for QGLWidget but bad for QOpenGLWidget |
| 629 | // since the fbo must be resized. We need an alternative way to notify. |
| 630 | virtual void resizeViewportFramebuffer() { } |
| 631 | // Called after each paint event. |
| 632 | virtual void resolveSamples() { } |
| 633 | |
| 634 | // These two are used in QGraphicsView for supporting stereoscopic rendering with a |
| 635 | // QOpenGLWidget viewport. |
| 636 | virtual bool isStereoEnabled() { return false; } // Called in QGraphicsView::setupViewport |
| 637 | virtual bool toggleStereoTargetBuffer() { return false; } // Called in QGraphicsView::paintEvent |
| 638 | |
| 639 | static void setWidgetParentHelper(QObject *widgetAsObject, QObject *newParent); |
| 640 | |
| 641 | std::string flagsForDumping() const override; |
| 642 | |
| 643 | QWidget *closestParentWidgetWithWindowHandle() const; |
| 644 | |
| 645 | // Variables. |
| 646 | // Regular pointers (keep them together to avoid gaps on 64 bit architectures). |
| 647 | std::unique_ptr<QWExtra> ; |
| 648 | QWidget *focus_next; |
| 649 | QWidget *focus_prev; |
| 650 | QWidget *focus_child; |
| 651 | QLayout *layout; |
| 652 | QRegion *needsFlush; |
| 653 | QPaintDevice *redirectDev; |
| 654 | QWidgetItemV2 *widgetItem; |
| 655 | QPaintEngine *; |
| 656 | mutable const QMetaObject *polished; |
| 657 | QGraphicsEffect *graphicsEffect; |
| 658 | // All widgets are added into the allWidgets set. Once |
| 659 | // they receive a window id they are also added to the mapper. |
| 660 | // This should just ensure that all widgets are deleted by QApplication |
| 661 | static QWidgetMapper *mapper; |
| 662 | static QWidgetSet *allWidgets; |
| 663 | #if !defined(QT_NO_IM) |
| 664 | Qt::InputMethodHints imHints; |
| 665 | #endif |
| 666 | #ifdef QT_KEYPAD_NAVIGATION |
| 667 | static QPointer<QWidget> editingWidget; |
| 668 | #endif |
| 669 | |
| 670 | // Implicit pointers (shared_null/shared_empty). |
| 671 | QRegion opaqueChildren; |
| 672 | QRegion dirty; |
| 673 | #if QT_CONFIG(tooltip) |
| 674 | QString toolTip; |
| 675 | int toolTipDuration; |
| 676 | #endif |
| 677 | #if QT_CONFIG(statustip) |
| 678 | QString statusTip; |
| 679 | #endif |
| 680 | #if QT_CONFIG(whatsthis) |
| 681 | QString whatsThis; |
| 682 | #endif |
| 683 | #if QT_CONFIG(accessibility) |
| 684 | QString accessibleName; |
| 685 | QString accessibleDescription; |
| 686 | #endif |
| 687 | |
| 688 | // Other variables. |
| 689 | uint directFontResolveMask; |
| 690 | uint inheritedFontResolveMask; |
| 691 | decltype(std::declval<QPalette>().resolveMask()) directPaletteResolveMask; |
| 692 | QPalette::ResolveMask inheritedPaletteResolveMask; |
| 693 | short leftmargin; |
| 694 | short topmargin; |
| 695 | short rightmargin; |
| 696 | short bottommargin; |
| 697 | signed char leftLayoutItemMargin; |
| 698 | signed char topLayoutItemMargin; |
| 699 | signed char rightLayoutItemMargin; |
| 700 | signed char bottomLayoutItemMargin; |
| 701 | static int instanceCounter; // Current number of widget instances |
| 702 | static int maxInstances; // Maximum number of widget instances |
| 703 | Qt::HANDLE hd; |
| 704 | QWidgetData data; |
| 705 | QSizePolicy size_policy; |
| 706 | QLocale locale; |
| 707 | QPoint redirectOffset; |
| 708 | #ifndef QT_NO_ACTION |
| 709 | QList<QAction*> actions; |
| 710 | #endif |
| 711 | #ifndef QT_NO_GESTURES |
| 712 | QMap<Qt::GestureType, Qt::GestureFlags> gestureContext; |
| 713 | #endif |
| 714 | |
| 715 | // Bit fields. |
| 716 | uint high_attributes[4]; // the low ones are in QWidget::widget_attributes |
| 717 | QPalette::ColorRole fg_role : 8; |
| 718 | QPalette::ColorRole bg_role : 8; |
| 719 | uint dirtyOpaqueChildren : 1; |
| 720 | uint isOpaque : 1; |
| 721 | uint retainSizeWhenHiddenChanged : 1; |
| 722 | uint inDirtyList : 1; |
| 723 | uint isScrolled : 1; |
| 724 | uint isMoved : 1; |
| 725 | uint usesDoubleBufferedGLContext : 1; |
| 726 | uint mustHaveWindowHandle : 1; |
| 727 | uint renderToTexture : 1; |
| 728 | uint textureChildSeen : 1; |
| 729 | #ifndef QT_NO_IM |
| 730 | uint inheritsInputMethodHints : 1; |
| 731 | #endif |
| 732 | uint renderToTextureReallyDirty : 1; |
| 733 | uint usesRhiFlush : 1; |
| 734 | uint childrenHiddenByWState : 1; |
| 735 | uint childrenShownByExpose : 1; |
| 736 | uint dontSetExplicitShowHide : 1; |
| 737 | |
| 738 | // *************************** Focus abstraction ************************************ |
| 739 | enum class FocusDirection { |
| 740 | Previous, |
| 741 | Next, |
| 742 | }; |
| 743 | |
| 744 | enum class FocusChainRemovalRule { |
| 745 | EnsureFocusOut = 0x01, |
| 746 | AssertConsistency = 0x02, |
| 747 | }; |
| 748 | Q_DECLARE_FLAGS(FocusChainRemovalRules, FocusChainRemovalRule) |
| 749 | |
| 750 | // Getters |
| 751 | QWidget *nextPrevElementInFocusChain(FocusDirection direction) const; |
| 752 | |
| 753 | // manipulators |
| 754 | bool removeFromFocusChain(FocusChainRemovalRules rules = FocusChainRemovalRules(), |
| 755 | FocusDirection direction = FocusDirection::Next); |
| 756 | bool insertIntoFocusChain(FocusDirection direction, QWidget *position); |
| 757 | static bool insertIntoFocusChain(const QWidgetList &toBeInserted, FocusDirection direction, QWidget *position); |
| 758 | bool insertIntoFocusChainBefore(QWidget *position) |
| 759 | { return insertIntoFocusChain(direction: FocusDirection::Previous, position); } |
| 760 | bool insertIntoFocusChainAfter(QWidget *position) |
| 761 | { return insertIntoFocusChain(direction: FocusDirection::Next, position); } |
| 762 | static QWidgetList takeFromFocusChain(QWidget *from, QWidget *to, |
| 763 | FocusDirection direction = FocusDirection::Next); |
| 764 | void reparentFocusChildren(FocusDirection direction); |
| 765 | QWidget *determineLastFocusChild(QWidget *noFurtherThan); |
| 766 | |
| 767 | // Initialization and tests |
| 768 | void initFocusChain(); |
| 769 | bool isInFocusChain() const; |
| 770 | bool isFocusChainConsistent() const; |
| 771 | |
| 772 | // *************************** Platform specific ************************************ |
| 773 | #if defined(Q_OS_WIN) |
| 774 | uint noPaintOnScreen : 1; // see qwidget.cpp ::paintEngine() |
| 775 | #elif defined(Q_OS_MAC) |
| 776 | void macUpdateSizeAttribute(); |
| 777 | #endif |
| 778 | void setNetWmWindowTypes(bool skipIfMissing = false); |
| 779 | |
| 780 | bool stealKeyboardGrab(bool grab); |
| 781 | bool stealMouseGrab(bool grab); |
| 782 | bool hasChildWithFocusPolicy(Qt::FocusPolicy policy, const QWidget *excludeChildrenOf = nullptr) const; |
| 783 | }; |
| 784 | |
| 785 | Q_DECLARE_OPERATORS_FOR_FLAGS(QWidgetPrivate::DrawWidgetFlags) |
| 786 | |
| 787 | struct QWidgetPaintContext |
| 788 | { |
| 789 | inline QWidgetPaintContext(QPaintDevice *d, const QRegion &r, const QPoint &o, QWidgetPrivate::DrawWidgetFlags f, |
| 790 | QPainter *p, QWidgetRepaintManager *rpm) |
| 791 | : pdev(d), rgn(r), offset(o), flags(f), sharedPainter(p), repaintManager(rpm), painter(nullptr) {} |
| 792 | |
| 793 | QPaintDevice *pdev; |
| 794 | QRegion rgn; |
| 795 | QPoint offset; |
| 796 | QWidgetPrivate::DrawWidgetFlags flags; |
| 797 | QPainter *sharedPainter; |
| 798 | QWidgetRepaintManager *repaintManager; |
| 799 | QPainter *painter; |
| 800 | }; |
| 801 | |
| 802 | #if QT_CONFIG(graphicseffect) |
| 803 | class QWidgetEffectSourcePrivate : public QGraphicsEffectSourcePrivate |
| 804 | { |
| 805 | public: |
| 806 | QWidgetEffectSourcePrivate(QWidget *widget) |
| 807 | : QGraphicsEffectSourcePrivate(), m_widget(widget), context(nullptr), updateDueToGraphicsEffect(false) |
| 808 | {} |
| 809 | |
| 810 | void detach() override |
| 811 | { m_widget->d_func()->graphicsEffect = nullptr; } |
| 812 | |
| 813 | const QGraphicsItem *graphicsItem() const override |
| 814 | { return nullptr; } |
| 815 | |
| 816 | const QWidget *widget() const override |
| 817 | { return m_widget; } |
| 818 | |
| 819 | void update() override |
| 820 | { |
| 821 | updateDueToGraphicsEffect = true; |
| 822 | m_widget->update(); |
| 823 | updateDueToGraphicsEffect = false; |
| 824 | } |
| 825 | |
| 826 | bool isPixmap() const override |
| 827 | { return false; } |
| 828 | |
| 829 | void effectBoundingRectChanged() override |
| 830 | { |
| 831 | // ### This function should take a rect parameter; then we can avoid |
| 832 | // updating too much on the parent widget. |
| 833 | if (QWidget *parent = m_widget->parentWidget()) |
| 834 | parent->update(); |
| 835 | else |
| 836 | update(); |
| 837 | } |
| 838 | |
| 839 | const QStyleOption *styleOption() const override |
| 840 | { return nullptr; } |
| 841 | |
| 842 | QRect deviceRect() const override |
| 843 | { return m_widget->window()->rect(); } |
| 844 | |
| 845 | QRectF boundingRect(Qt::CoordinateSystem system) const override; |
| 846 | void draw(QPainter *p) override; |
| 847 | QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset, |
| 848 | QGraphicsEffect::PixmapPadMode mode) const override; |
| 849 | |
| 850 | QWidget *m_widget; |
| 851 | QWidgetPaintContext *context; |
| 852 | QTransform lastEffectTransform; |
| 853 | bool updateDueToGraphicsEffect; |
| 854 | }; |
| 855 | #endif // QT_CONFIG(graphicseffect) |
| 856 | |
| 857 | inline QWExtra *QWidgetPrivate::() const |
| 858 | { |
| 859 | return extra.get(); |
| 860 | } |
| 861 | |
| 862 | inline QTLWExtra *QWidgetPrivate::topData() const |
| 863 | { |
| 864 | const_cast<QWidgetPrivate *>(this)->createTLExtra(); |
| 865 | return extra->topextra.get(); |
| 866 | } |
| 867 | |
| 868 | inline QTLWExtra *QWidgetPrivate::maybeTopData() const |
| 869 | { |
| 870 | return extra ? extra->topextra.get() : nullptr; |
| 871 | } |
| 872 | |
| 873 | inline QPainter *QWidgetPrivate::sharedPainter() const |
| 874 | { |
| 875 | Q_Q(const QWidget); |
| 876 | QTLWExtra *x = q->window()->d_func()->maybeTopData(); |
| 877 | return x ? x->sharedPainter : nullptr; |
| 878 | } |
| 879 | |
| 880 | inline void QWidgetPrivate::setSharedPainter(QPainter *painter) |
| 881 | { |
| 882 | Q_Q(QWidget); |
| 883 | QTLWExtra *x = q->window()->d_func()->topData(); |
| 884 | x->sharedPainter = painter; |
| 885 | } |
| 886 | |
| 887 | inline bool QWidgetPrivate::pointInsideRectAndMask(const QPointF &p) const |
| 888 | { |
| 889 | Q_Q(const QWidget); |
| 890 | |
| 891 | // Use QRectF::contains so that (0, -0.1) isn't in, with p.toPoint() it would be in. |
| 892 | // The -1 on right and bottom matches QRect semantics: |
| 893 | // (160,160) isn't contained in QRect(0, 0, 160, 160) |
| 894 | QRect r = q->rect(); |
| 895 | r.setRight(qMax(a: -1, b: r.right() - 1)); |
| 896 | r.setBottom(qMax(a: -1, b: r.bottom() - 1)); |
| 897 | |
| 898 | return r.toRectF().contains(p) |
| 899 | && (!extra || !extra->hasMask || q->testAttribute(attribute: Qt::WA_MouseNoMask) |
| 900 | || extra->mask.contains(p: p.toPoint() /* incorrect for the -0.1 case */)); |
| 901 | } |
| 902 | |
| 903 | inline QWidgetRepaintManager *QWidgetPrivate::maybeRepaintManager() const |
| 904 | { |
| 905 | Q_Q(const QWidget); |
| 906 | QTLWExtra *x = q->window()->d_func()->maybeTopData(); |
| 907 | return x ? x->repaintManager.get() : nullptr; |
| 908 | } |
| 909 | |
| 910 | QT_END_NAMESPACE |
| 911 | |
| 912 | #endif // QWIDGET_P_H |
| 913 | |