summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@digia.com>2012-12-10 14:48:19 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-02-24 20:41:05 +0100
commit153d613353863987322db81f3c31e33541ef7226 (patch)
treead2e8a3793641bc10cc8bbae2d0adefb70025b53
parentd9ff510f02bba63dabe7a081a68296056a89ae4c (diff)
Transient QWindows centered; default-constructed geometry
Default-constructed geometry does not mean put the window at 0,0, and it does not mean center the window on the screen: it means let the window manager position the window. If the window is explicitly positioned at 0,0 though, that is a higher priority than the transient hint; without this change, the transientFor property had no effect. On X11, transient means use center "gravity" to make the transient window exactly centered. But the user can still override the geometry of a transient window, as with any window. On OSX and Windows, neither transient window functionality nor smart initial positioning are provided, so a window with no position set will be centered on the screen, and a transient window will be put at the center of its transientParent. Change-Id: I4f5e37480eef5d105e45ffd60362a57f13ec55f5 Task-number: QTBUG-26903 Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com>
-rw-r--r--src/gui/kernel/qguiapplication.cpp2
-rw-r--r--src/gui/kernel/qplatformwindow.cpp39
-rw-r--r--src/gui/kernel/qplatformwindow.h3
-rw-r--r--src/gui/kernel/qwindow.cpp17
-rw-r--r--src/gui/kernel/qwindow_p.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm8
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp12
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp49
-rw-r--r--src/widgets/kernel/qwidget_qpa.cpp28
-rw-r--r--tests/auto/opengl/qgl/tst_qgl.cpp8
-rw-r--r--tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp2
-rw-r--r--tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp5
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);