Add QPlatformWindow::initialize() for two-step window creation
The QWindow::create method calls createPlatformWindow, and assigns the result to d->platformWindow. If the platform sends any sort of events synchronously during the creation, the event will be delivered to a QWindow that doesn't have a handle() yet, resulting in noop handling of the event, or crashes. To mitigate this situations, platforms should do as little a possible in the QPlatformWindow constructor, and leave initialization to the new method, where the QWindow will have a handle(). The macOS platform plugin still has a m_initialized guard, to prevent sending geometry changes during initialization, as this will result in a resize event before a show event. This forced behavior seems dubious, but is left for a followup patch. Task-number: QTBUG-61977 Change-Id: I04d32d93391e89d068752b719270438e7024ad46 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io> Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>bb10
parent
1e8a687a3a
commit
4c855a9f9f
|
|
@ -70,6 +70,17 @@ QPlatformWindow::~QPlatformWindow()
|
|||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Called as part of QWindow::create(), after constructing
|
||||
the window. Platforms should prefer to do initialization
|
||||
here instead of in the constructor, as the platform window
|
||||
object will be fully constructed, and associated to the
|
||||
corresponding QWindow, allowing synchronous event delivery.
|
||||
*/
|
||||
void QPlatformWindow::initialize()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the window which belongs to the QPlatformWindow
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ public:
|
|||
explicit QPlatformWindow(QWindow *window);
|
||||
virtual ~QPlatformWindow();
|
||||
|
||||
virtual void initialize();
|
||||
|
||||
QWindow *window() const;
|
||||
QPlatformWindow *parent() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -509,6 +509,8 @@ void QWindowPrivate::create(bool recursive, WId nativeHandle)
|
|||
return;
|
||||
}
|
||||
|
||||
platformWindow->initialize();
|
||||
|
||||
QObjectList childObjects = q->children();
|
||||
for (int i = 0; i < childObjects.size(); i ++) {
|
||||
QObject *object = childObjects.at(i);
|
||||
|
|
|
|||
|
|
@ -95,6 +95,8 @@ public:
|
|||
QCocoaWindow(QWindow *tlw, WId nativeHandle = 0);
|
||||
~QCocoaWindow();
|
||||
|
||||
void initialize() override;
|
||||
|
||||
void setGeometry(const QRect &rect) Q_DECL_OVERRIDE;
|
||||
QRect geometry() const Q_DECL_OVERRIDE;
|
||||
void setCocoaGeometry(const QRect &rect);
|
||||
|
|
@ -250,7 +252,7 @@ public: // for QNSView
|
|||
QPointer<QWindow> m_enterLeaveTargetWindow;
|
||||
bool m_windowUnderMouse;
|
||||
|
||||
bool m_inConstructor;
|
||||
bool m_initialized;
|
||||
bool m_inSetVisible;
|
||||
bool m_inSetGeometry;
|
||||
bool m_inSetStyleMask;
|
||||
|
|
|
|||
|
|
@ -132,8 +132,8 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterNotificationCallbacks)
|
|||
|
||||
const int QCocoaWindow::NoAlertRequest = -1;
|
||||
|
||||
QCocoaWindow::QCocoaWindow(QWindow *tlw, WId nativeHandle)
|
||||
: QPlatformWindow(tlw)
|
||||
QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle)
|
||||
: QPlatformWindow(win)
|
||||
, m_view(nil)
|
||||
, m_nsWindow(0)
|
||||
, m_viewIsEmbedded(false)
|
||||
|
|
@ -141,7 +141,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw, WId nativeHandle)
|
|||
, m_lastReportedWindowState(Qt::WindowNoState)
|
||||
, m_windowModality(Qt::NonModal)
|
||||
, m_windowUnderMouse(false)
|
||||
, m_inConstructor(true)
|
||||
, m_initialized(false)
|
||||
, m_inSetVisible(false)
|
||||
, m_inSetGeometry(false)
|
||||
, m_inSetStyleMask(false)
|
||||
|
|
@ -165,24 +165,31 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw, WId nativeHandle)
|
|||
{
|
||||
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::QCocoaWindow" << window();
|
||||
|
||||
QMacAutoReleasePool pool;
|
||||
|
||||
if (nativeHandle) {
|
||||
m_view = reinterpret_cast<NSView *>(nativeHandle);
|
||||
[m_view retain];
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
void QCocoaWindow::initialize()
|
||||
{
|
||||
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::initialize" << window();
|
||||
|
||||
QMacAutoReleasePool pool;
|
||||
|
||||
if (!m_view) {
|
||||
m_view = [[QNSView alloc] initWithCocoaWindow:this];
|
||||
// Enable high-dpi OpenGL for retina displays. Enabling has the side
|
||||
// effect that Cocoa will start calling glViewport(0, 0, width, height),
|
||||
// overriding any glViewport calls in application code. This is usually not a
|
||||
// problem, except if the appilcation wants to have a "custom" viewport.
|
||||
// (like the hellogl example)
|
||||
if (tlw->supportsOpenGL()) {
|
||||
BOOL enable = qt_mac_resolveOption(YES, tlw, "_q_mac_wantsBestResolutionOpenGLSurface",
|
||||
if (window()->supportsOpenGL()) {
|
||||
BOOL enable = qt_mac_resolveOption(YES, window(), "_q_mac_wantsBestResolutionOpenGLSurface",
|
||||
"QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE");
|
||||
[m_view setWantsBestResolutionOpenGLSurface:enable];
|
||||
}
|
||||
BOOL enable = qt_mac_resolveOption(NO, tlw, "_q_mac_wantsLayer",
|
||||
BOOL enable = qt_mac_resolveOption(NO, window(), "_q_mac_wantsLayer",
|
||||
"QT_MAC_WANTS_LAYER");
|
||||
[m_view setWantsLayer:enable];
|
||||
}
|
||||
|
|
@ -190,10 +197,11 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw, WId nativeHandle)
|
|||
setGeometry(initialGeometry(window(), windowGeometry(), defaultWindowWidth, defaultWindowHeight));
|
||||
|
||||
recreateWindowIfNeeded();
|
||||
tlw->setGeometry(geometry());
|
||||
if (tlw->isTopLevel())
|
||||
setWindowIcon(tlw->icon());
|
||||
m_inConstructor = false;
|
||||
window()->setGeometry(geometry());
|
||||
if (window()->isTopLevel())
|
||||
setWindowIcon(window()->icon());
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
QCocoaWindow::~QCocoaWindow()
|
||||
|
|
@ -1021,8 +1029,10 @@ bool QCocoaWindow::windowShouldClose()
|
|||
|
||||
void QCocoaWindow::handleGeometryChange()
|
||||
{
|
||||
// Don't send geometry change event to Qt unless it's ready to handle events
|
||||
if (m_inConstructor)
|
||||
// Prevent geometry change during initialization, as that will result
|
||||
// in a resize event, and Qt expects those to come after the show event.
|
||||
// FIXME: Remove once we've clarified the Qt behavior for this.
|
||||
if (!m_initialized)
|
||||
return;
|
||||
|
||||
// Don't send the geometry change if the QWindow is designated to be
|
||||
|
|
|
|||
Loading…
Reference in New Issue