diff options
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 2 | ||||
-rw-r--r-- | src/gui/kernel/qplatformwindow.cpp | 39 | ||||
-rw-r--r-- | src/gui/kernel/qplatformwindow.h | 3 | ||||
-rw-r--r-- | src/gui/kernel/qwindow.cpp | 17 | ||||
-rw-r--r-- | src/gui/kernel/qwindow_p.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.mm | 8 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowswindow.cpp | 12 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 49 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget_qpa.cpp | 28 | ||||
-rw-r--r-- | tests/auto/opengl/qgl/tst_qgl.cpp | 8 | ||||
-rw-r--r-- | tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp | 2 | ||||
-rw-r--r-- | tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp | 5 |
12 files changed, 135 insertions, 40 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index c155ecfe0c..d0b37b7f1b 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1559,6 +1559,8 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate } QGuiApplicationPrivate::focus_window = newFocus; + if (!qApp) + return; if (previous) { QFocusEvent focusOut(QEvent::FocusOut); diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp index b710701e7f..79e4cbf674 100644 --- a/src/gui/kernel/qplatformwindow.cpp +++ b/src/gui/kernel/qplatformwindow.cpp @@ -41,11 +41,13 @@ #include "qplatformwindow.h" #include "qplatformwindow_p.h" +#include "qplatformscreen.h" #include <private/qguiapplication_p.h> #include <qpa/qwindowsysteminterface.h> #include <QtGui/qwindow.h> #include <QtGui/qscreen.h> +#include <private/qwindow_p.h> QT_BEGIN_NAMESPACE @@ -449,6 +451,43 @@ QString QPlatformWindow::formatWindowTitle(const QString &title, const QString & } /*! + Helper function to get initial geometry on windowing systems which do not + do smart positioning and also do not provide a means of centering a + transient window w.r.t. its parent. For example this is useful on Windows + and MacOS but not X11, because an X11 window manager typically tries to + layout new windows to optimize usage of the available desktop space. + However if the given window already has geometry which the application has + initialized, it takes priority. +*/ +QRect QPlatformWindow::initialGeometry(const QWindow *w, + const QRect &initialGeometry, int defaultWidth, int defaultHeight) +{ + QRect rect(initialGeometry); + if (rect.isNull()) { + QSize minimumSize = w->minimumSize(); + if (minimumSize.width() > 0 || minimumSize.height() > 0) { + rect.setSize(minimumSize); + } else { + rect.setWidth(defaultWidth); + rect.setHeight(defaultHeight); + } + } + if (w->isTopLevel() && qt_window_private(const_cast<QWindow*>(w))->positionAutomatic) { + const QWindow *tp = w->transientParent(); + if (tp) { + // A transient window should be centered w.r.t. its transient parent. + rect.moveCenter(tp->geometry().center()); + } else { + // Center the window on the screen. (Only applicable on platforms + // which do not provide a better way.) + QPlatformScreen *scr = QPlatformScreen::platformScreenForWindow(w); + rect.moveCenter(scr->availableGeometry().center()); + } + } + return rect; +} + +/*! \class QPlatformWindow \since 4.8 \internal diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h index fe62d7b67b..410e7ea9bb 100644 --- a/src/gui/kernel/qplatformwindow.h +++ b/src/gui/kernel/qplatformwindow.h @@ -130,6 +130,9 @@ public: virtual void setFrameStrutEventsEnabled(bool enabled); virtual bool frameStrutEventsEnabled() const; + static QRect initialGeometry(const QWindow *w, + const QRect &initialGeometry, int defaultWidth, int defaultHeight); + protected: static QString formatWindowTitle(const QString &title, const QString &separator); diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 2fcad5706f..2a2e30634a 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -126,6 +126,18 @@ QT_BEGIN_NAMESPACE and can keep rendering until it isExposed() returns false. To find out when isExposed() changes, reimplement exposeEvent(). The window will always get a resize event before the first expose event. + + \section1 Initial geometry + + If the window's width and height are left uninitialized, the window will + get a reasonable default geometry from the platform window. If the position + is left uninitialized, then the platform window will allow the windowing + system to position the window. For example on X11, the window manager + usually does some kind of smart positioning to try to avoid having new + windows completely obscure existing windows. However setGeometry() + initializes both the position and the size, so if you want a fixed size but + an automatic position, you should call resize() or setWidth() and + setHeight() instead. */ /*! @@ -962,7 +974,7 @@ void QWindow::setY(int arg) void QWindow::setWidth(int arg) { if (width() != arg) - setGeometry(QRect(x(), y(), arg, height())); + resize(arg, height()); } /*! @@ -972,7 +984,7 @@ void QWindow::setWidth(int arg) void QWindow::setHeight(int arg) { if (height() != arg) - setGeometry(QRect(x(), y(), width(), arg)); + resize(width(), arg); } /*! @@ -1095,6 +1107,7 @@ void QWindow::setGeometry(int posx, int posy, int w, int h) void QWindow::setGeometry(const QRect &rect) { Q_D(QWindow); + d->positionAutomatic = false; if (rect == geometry()) return; QRect oldRect = geometry(); diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 6933c892a0..26bf0700f2 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -88,6 +88,7 @@ public: , resizeEventPending(true) , receivedExpose(false) , positionPolicy(WindowFrameExclusive) + , positionAutomatic(true) , contentOrientation(Qt::PrimaryOrientation) , opacity(qreal(1.0)) , minimumSize(0, 0) @@ -137,6 +138,7 @@ public: bool resizeEventPending; bool receivedExpose; PositionPolicy positionPolicy; + bool positionAutomatic; Qt::ScreenOrientation contentOrientation; qreal opacity; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 489c229187..2adf0d24a1 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -58,6 +58,11 @@ #include <QDebug> +enum { + defaultWindowWidth = 160, + defaultWindowHeight = 160 +}; + static bool isMouseEvent(NSEvent *ev) { switch ([ev type]) { @@ -683,7 +688,8 @@ NSWindow * QCocoaWindow::createNSWindow() { QCocoaAutoReleasePool pool; - NSRect frame = qt_mac_flipRect(window()->geometry(), window()); + QRect rect = initialGeometry(window(), window()->geometry(), defaultWindowWidth, defaultWindowHeight); + NSRect frame = qt_mac_flipRect(rect, window()); Qt::WindowType type = window()->type(); Qt::WindowFlags flags = window()->flags(); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 07dc668b3f..20000ea0a9 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -64,6 +64,11 @@ QT_BEGIN_NAMESPACE +enum { + defaultWindowWidth = 160, + defaultWindowHeight = 160 +}; + Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &); static QByteArray debugWinStyle(DWORD style) @@ -468,6 +473,8 @@ QWindowsWindow::WindowData const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w, isGL); + QRect rect = QPlatformWindow::initialGeometry(w, geometry, defaultWindowWidth, defaultWindowHeight); + if (title.isEmpty() && (result.flags & Qt::WindowTitleHint)) title = topLevel ? qAppName() : w->objectName(); @@ -475,14 +482,14 @@ QWindowsWindow::WindowData const wchar_t *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16()); // Capture events before CreateWindowEx() returns. - const QWindowCreationContextPtr context(new QWindowCreationContext(w, geometry, style, exStyle)); + const QWindowCreationContextPtr context(new QWindowCreationContext(w, rect, style, exStyle)); QWindowsContext::instance()->setWindowCreationContext(context); if (QWindowsContext::verboseWindows) qDebug().nospace() << "CreateWindowEx: " << w << *this << " class=" <<windowClassName << " title=" << title - << "\nrequested: " << geometry << ": " + << "\nrequested: " << rect << ": " << context->frameWidth << 'x' << context->frameHeight << '+' << context->frameX << '+' << context->frameY; @@ -775,6 +782,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) : QWindowsWindow::~QWindowsWindow() { #ifndef Q_OS_WINCE + QWindowSystemInterface::flushWindowSystemEvents(); if (QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch) QWindowsContext::user32dll.unregisterTouchWindow(m_data.hwnd); #endif // !Q_OS_WINCE diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index c0ddf5c0ae..abd2f7a147 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -113,6 +113,10 @@ #endif #define XCOORD_MAX 16383 +enum { + defaultWindowWidth = 160, + defaultWindowHeight = 160 +}; //#ifdef NET_WM_STATE_DEBUG @@ -219,8 +223,16 @@ void QXcbWindow::create() QRect rect = window()->geometry(); QPlatformWindow::setGeometry(rect); - rect.setWidth(qBound(1, rect.width(), XCOORD_MAX)); - rect.setHeight(qBound(1, rect.height(), XCOORD_MAX)); + QSize minimumSize = window()->minimumSize(); + if (rect.width() > 0 || rect.height() > 0) { + rect.setWidth(qBound(1, rect.width(), XCOORD_MAX)); + rect.setHeight(qBound(1, rect.height(), XCOORD_MAX)); + } else if (minimumSize.width() > 0 || minimumSize.height() > 0) { + rect.setSize(minimumSize); + } else { + rect.setWidth(defaultWindowWidth); + rect.setHeight(defaultWindowHeight); + } xcb_window_t xcb_parent_id = m_screen->root(); if (parent()) @@ -436,15 +448,23 @@ void QXcbWindow::setGeometry(const QRect &rect) propagateSizeHints(); const QRect wmGeometry = windowToWmGeometry(rect); - const quint32 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; - const qint32 values[] = { - qBound<qint32>(-XCOORD_MAX, wmGeometry.x(), XCOORD_MAX), - qBound<qint32>(-XCOORD_MAX, wmGeometry.y(), XCOORD_MAX), - qBound<qint32>(1, wmGeometry.width(), XCOORD_MAX), - qBound<qint32>(1, wmGeometry.height(), XCOORD_MAX), - }; - - Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, reinterpret_cast<const quint32*>(values))); + if (qt_window_private(window())->positionAutomatic) { + const quint32 mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; + const qint32 values[] = { + qBound<qint32>(1, wmGeometry.width(), XCOORD_MAX), + qBound<qint32>(1, wmGeometry.height(), XCOORD_MAX), + }; + Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, reinterpret_cast<const quint32*>(values))); + } else { + const quint32 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; + const qint32 values[] = { + qBound<qint32>(-XCOORD_MAX, wmGeometry.x(), XCOORD_MAX), + qBound<qint32>(-XCOORD_MAX, wmGeometry.y(), XCOORD_MAX), + qBound<qint32>(1, wmGeometry.width(), XCOORD_MAX), + qBound<qint32>(1, wmGeometry.height(), XCOORD_MAX), + }; + Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, reinterpret_cast<const quint32*>(values))); + } xcb_flush(xcb_connection()); } @@ -563,6 +583,7 @@ void QXcbWindow::show() if (!transientXcbParent) transientXcbParent = static_cast<QXcbScreen *>(screen())->clientLeader(); if (transientXcbParent) { // ICCCM 4.1.2.6 + m_gravity = XCB_GRAVITY_CENTER; Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, 1, &transientXcbParent)); @@ -1221,8 +1242,10 @@ void QXcbWindow::propagateSizeHints() QWindow *win = window(); - xcb_size_hints_set_position(&hints, true, rect.x(), rect.y()); - xcb_size_hints_set_size(&hints, true, rect.width(), rect.height()); + if (!qt_window_private(win)->positionAutomatic) + xcb_size_hints_set_position(&hints, true, rect.x(), rect.y()); + if (rect.width() < QWINDOWSIZE_MAX || rect.height() < QWINDOWSIZE_MAX) + xcb_size_hints_set_size(&hints, true, rect.width(), rect.height()); xcb_size_hints_set_win_gravity(&hints, m_gravity); QSize minimumSize = win->minimumSize(); diff --git a/src/widgets/kernel/qwidget_qpa.cpp b/src/widgets/kernel/qwidget_qpa.cpp index 84693d02a5..2ffe9c5de5 100644 --- a/src/widgets/kernel/qwidget_qpa.cpp +++ b/src/widgets/kernel/qwidget_qpa.cpp @@ -109,7 +109,10 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO win->setFlags(data.window_flags); fixPosIncludesFrame(); - win->setGeometry(q->geometry()); + if (q->testAttribute(Qt::WA_Moved)) + win->setGeometry(q->geometry()); + else + win->resize(q->size()); win->setScreen(QGuiApplication::screens().value(topData()->screenIndex, 0)); if (q->testAttribute(Qt::WA_TranslucentBackground)) { @@ -466,19 +469,6 @@ void QWidget::activateWindow() wnd->requestActivate(); } -// Position top level windows at the center, avoid showing -// Windows at the default 0,0 position excluding the frame. -static inline QRect positionTopLevelWindow(QRect geometry, const QScreen *screen) -{ - if (screen && geometry.x() == 0 && geometry.y() == 0) { - const QRect availableGeometry = screen->availableGeometry(); - if (availableGeometry.width() > geometry.width() - && availableGeometry.height() > geometry.height()) - geometry.moveCenter(availableGeometry.center()); - } - return geometry; -} - // move() was invoked with Qt::WA_WState_Created not set (frame geometry // unknown), that is, crect has a position including the frame. // If we can determine the frame strut, fix that and clear the flag. @@ -529,16 +519,16 @@ void QWidgetPrivate::show_sys() if (q->isWindow()) fixPosIncludesFrame(); QRect geomRect = q->geometry(); - if (q->isWindow()) { - if (!q->testAttribute(Qt::WA_Moved)) - geomRect = positionTopLevelWindow(geomRect, window->screen()); - } else { + if (!q->isWindow()) { QPoint topLeftOfWindow = q->mapTo(q->nativeParentWidget(),QPoint()); geomRect.moveTopLeft(topLeftOfWindow); } const QRect windowRect = window->geometry(); if (windowRect != geomRect) { - window->setGeometry(geomRect); + if (q->testAttribute(Qt::WA_Moved)) + window->setGeometry(geomRect); + else + window->resize(geomRect.size()); } if (QBackingStore *store = q->backingStore()) { diff --git a/tests/auto/opengl/qgl/tst_qgl.cpp b/tests/auto/opengl/qgl/tst_qgl.cpp index 6c5c90d737..3bae5d5103 100644 --- a/tests/auto/opengl/qgl/tst_qgl.cpp +++ b/tests/auto/opengl/qgl/tst_qgl.cpp @@ -78,7 +78,6 @@ private slots: void shareRegister(); void textureCleanup(); #endif - void graphicsViewClipping(); void partialGLWidgetUpdates_data(); void partialGLWidgetUpdates(); void glWidgetWithAlpha(); @@ -98,6 +97,7 @@ private slots: void destroyFBOAfterContext(); void threadImages(); void nullRectCrash(); + void graphicsViewClipping(); }; tst_QGL::tst_QGL() @@ -865,7 +865,11 @@ void tst_QGL::graphicsViewClipping() scene.setSceneRect(view.viewport()->rect()); - QVERIFY(QTest::qWaitForWindowActive(&view)); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + #ifdef Q_OS_MAC + // The black rectangle jumps from the center to the upper left for some reason. + QTest::qWait(100); + #endif QImage image = viewport->grabFrameBuffer(); QImage expected = image; diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index c1927c9d1f..78fce7661e 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -5430,7 +5430,7 @@ void tst_QWidget::setToolTip() QScopedPointer<QWidget> popup(new QWidget(0, Qt::Popup)); popup->setObjectName(QString::fromLatin1("tst_qwidget setToolTip #%1").arg(pass)); popup->setWindowTitle(popup->objectName()); - popup->resize(150, 50); + popup->setGeometry(50, 50, 150, 50); QFrame *frame = new QFrame(popup.data()); frame->setGeometry(0, 0, 50, 50); frame->setFrameStyle(QFrame::Box | QFrame::Plain); diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index 210e52f0aa..3fa669c1fb 100644 --- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp @@ -3902,6 +3902,11 @@ void tst_QLineEdit::inputMethod() // removing focus allows input method to commit preedit testWidget->setText(""); testWidget->activateWindow(); + // TODO setFocus should not be necessary here, because activateWindow + // should focus it, and the window is the QLineEdit. But the test can fail + // on Windows if we don't do this. If each test had a unique QLineEdit + // instance, maybe such problems would go away. + testWidget->setFocus(); QTRY_VERIFY(testWidget->hasFocus()); QTRY_COMPARE(qApp->focusObject(), testWidget); |