Re-implement transient window support in XCB backend.

If a QWindow has a parent but is top-level the corresponding
QPlatformWindow should not be re-parented but instead be made transient
for the parent window if possible.
This commit is contained in:
Samuel Rødal 2011-05-16 17:28:56 +02:00
parent 25f70314e0
commit 10a3b10726
6 changed files with 50 additions and 36 deletions

View File

@ -70,7 +70,7 @@ QPlatformWindow::~QPlatformWindow()
} }
/*! /*!
Returnes the window which belongs to the QPlatformWindow Returns the window which belongs to the QPlatformWindow
*/ */
QWindow *QPlatformWindow::window() const QWindow *QPlatformWindow::window() const
{ {
@ -78,6 +78,15 @@ QWindow *QPlatformWindow::window() const
return d->window; return d->window;
} }
/*!
Returns the parent platform window (or 0 if orphan).
*/
QPlatformWindow *QPlatformWindow::parent() const
{
Q_D(const QPlatformWindow);
return d->window->parent() ? d->window->parent()->handle() : 0;
}
/*! /*!
This function is called by Qt whenever a window is moved or the window is resized. The resize This function is called by Qt whenever a window is moved or the window is resized. The resize
can happen programatically(from ie. user application) or by the window manager. This means that can happen programatically(from ie. user application) or by the window manager. This means that

View File

@ -66,6 +66,8 @@ public:
virtual ~QPlatformWindow(); virtual ~QPlatformWindow();
QWindow *window() const; QWindow *window() const;
QPlatformWindow *parent() const;
virtual void setGeometry(const QRect &rect); virtual void setGeometry(const QRect &rect);
virtual QRect geometry() const; virtual QRect geometry() const;

View File

@ -97,7 +97,7 @@ void QWindow::create()
QObject *object = childObjects.at(i); QObject *object = childObjects.at(i);
if(object->isWindowType()) { if(object->isWindowType()) {
QWindow *window = static_cast<QWindow *>(object); QWindow *window = static_cast<QWindow *>(object);
if (window->d_func()->platformWindow) if (window->d_func()->platformWindow && !window->isTopLevel())
window->d_func()->platformWindow->setParent(d->platformWindow); window->d_func()->platformWindow->setParent(d->platformWindow);
} }
} }
@ -133,9 +133,9 @@ void QWindow::setParent(QWindow *parent)
QObject::setParent(parent); QObject::setParent(parent);
if (d->platformWindow) { if (d->platformWindow) {
if (parent && parent->d_func()->platformWindow) { if (parent && parent->d_func()->platformWindow && !isTopLevel()) {
d->platformWindow->setParent(parent->d_func()->platformWindow); d->platformWindow->setParent(parent->d_func()->platformWindow);
} else if (!parent) { } else {
d->platformWindow->setParent(0); d->platformWindow->setParent(0);
} }
} }
@ -144,12 +144,12 @@ void QWindow::setParent(QWindow *parent)
} }
/*! /*!
Returns whether the window is top level, i.e. parent-less. Returns whether the window is top level.
*/ */
bool QWindow::isTopLevel() const bool QWindow::isTopLevel() const
{ {
Q_D(const QWindow); Q_D(const QWindow);
return d->parentWindow == 0; return d->windowFlags & Qt::Window;
} }
void QWindow::setWindowFormat(const QWindowFormat &format) void QWindow::setWindowFormat(const QWindowFormat &format)
@ -196,6 +196,12 @@ Qt::WindowFlags QWindow::windowFlags() const
return d->windowFlags; return d->windowFlags;
} }
Qt::WindowType QWindow::windowType() const
{
Q_D(const QWindow);
return static_cast<Qt::WindowType>(int(d->windowFlags & Qt::WindowType_Mask));
}
void QWindow::setWindowTitle(const QString &title) void QWindow::setWindowTitle(const QString &title)
{ {
Q_D(QWindow); Q_D(QWindow);

View File

@ -107,6 +107,7 @@ public:
void setWindowFlags(Qt::WindowFlags flags); void setWindowFlags(Qt::WindowFlags flags);
Qt::WindowFlags windowFlags() const; Qt::WindowFlags windowFlags() const;
Qt::WindowType windowType() const;
QString windowTitle() const; QString windowTitle() const;

View File

@ -73,20 +73,17 @@
#include "../eglconvenience/qxlibeglintegration.h" #include "../eglconvenience/qxlibeglintegration.h"
#endif #endif
#if 0
// Returns true if we should set WM_TRANSIENT_FOR on \a w // Returns true if we should set WM_TRANSIENT_FOR on \a w
static inline bool isTransient(const QWidget *w) static inline bool isTransient(const QWindow *w)
{ {
return ((w->windowType() == Qt::Dialog return w->windowType() == Qt::Dialog
|| w->windowType() == Qt::Sheet || w->windowType() == Qt::Sheet
|| w->windowType() == Qt::Tool || w->windowType() == Qt::Tool
|| w->windowType() == Qt::SplashScreen || w->windowType() == Qt::SplashScreen
|| w->windowType() == Qt::ToolTip || w->windowType() == Qt::ToolTip
|| w->windowType() == Qt::Drawer || w->windowType() == Qt::Drawer
|| w->windowType() == Qt::Popup) || w->windowType() == Qt::Popup;
&& !w->testAttribute(Qt::WA_X11BypassTransientForHint));
} }
#endif
QXcbWindow::QXcbWindow(QWindow *window) QXcbWindow::QXcbWindow(QWindow *window)
: QPlatformWindow(window) : QPlatformWindow(window)
@ -119,8 +116,8 @@ QXcbWindow::QXcbWindow(QWindow *window)
QRect rect = window->geometry(); QRect rect = window->geometry();
xcb_window_t xcb_parent_id = m_screen->root(); xcb_window_t xcb_parent_id = m_screen->root();
if (window->parent() && window->parent()->handle()) if (parent() && !window->isTopLevel())
xcb_parent_id = static_cast<QXcbWindow *>(window->parent()->handle())->xcb_window(); xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
#if defined(XCB_USE_GLX) || defined(XCB_USE_EGL) #if defined(XCB_USE_GLX) || defined(XCB_USE_EGL)
if (window->surfaceType() == QWindow::OpenGLSurface if (window->surfaceType() == QWindow::OpenGLSurface
@ -217,18 +214,6 @@ QXcbWindow::QXcbWindow(QWindow *window)
&m_syncCounter)); &m_syncCounter));
} }
#if 0
if (tlw && isTransient(tlw) && tlw->parentWidget()) {
// ICCCM 4.1.2.6
QWidget *p = tlw->parentWidget()->window();
xcb_window_t parentWindow = p->winId();
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32,
1, &parentWindow));
}
#endif
// set the PID to let the WM kill the application if unresponsive // set the PID to let the WM kill the application if unresponsive
long pid = getpid(); long pid = getpid();
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
@ -278,7 +263,19 @@ void QXcbWindow::show()
xcb_set_wm_hints(xcb_connection(), m_window, &hints); xcb_set_wm_hints(xcb_connection(), m_window, &hints);
// update WM_NORMAL_HINTS
propagateSizeHints(); propagateSizeHints();
// update WM_TRANSIENT_FOR
if (isTransient(window()) && parent()) {
// ICCCM 4.1.2.6
xcb_window_t parentWindow = static_cast<QXcbWindow *>(parent())->xcb_window();
// todo: set transient for group (wm_client_leader) if no parent, a la qwidget_x11.cpp
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32,
1, &parentWindow));
}
} }
Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window)); Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
@ -598,6 +595,7 @@ void QXcbWindow::lower()
void QXcbWindow::propagateSizeHints() void QXcbWindow::propagateSizeHints()
{ {
// update WM_NORMAL_HINTS
xcb_size_hints_t hints; xcb_size_hints_t hints;
QRect rect = geometry(); QRect rect = geometry();

View File

@ -93,11 +93,9 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
QWindow *win = topData()->window; QWindow *win = topData()->window;
if (!q->isWindow()) { if (QWidget *nativeParent = q->nativeParentWidget()) {
if (QWidget *nativeParent = q->nativeParentWidget()) { if (nativeParent->windowHandle())
if (nativeParent->windowHandle()) win->setParent(nativeParent->windowHandle());
win->setParent(nativeParent->windowHandle());
}
} }
win->setWindowFlags(data.window_flags); win->setWindowFlags(data.window_flags);