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
{
@ -78,6 +78,15 @@ QWindow *QPlatformWindow::window() const
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
can happen programatically(from ie. user application) or by the window manager. This means that

View File

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

View File

@ -97,7 +97,7 @@ void QWindow::create()
QObject *object = childObjects.at(i);
if(object->isWindowType()) {
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);
}
}
@ -133,9 +133,9 @@ void QWindow::setParent(QWindow *parent)
QObject::setParent(parent);
if (d->platformWindow) {
if (parent && parent->d_func()->platformWindow) {
if (parent && parent->d_func()->platformWindow && !isTopLevel()) {
d->platformWindow->setParent(parent->d_func()->platformWindow);
} else if (!parent) {
} else {
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
{
Q_D(const QWindow);
return d->parentWindow == 0;
return d->windowFlags & Qt::Window;
}
void QWindow::setWindowFormat(const QWindowFormat &format)
@ -196,6 +196,12 @@ Qt::WindowFlags QWindow::windowFlags() const
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)
{
Q_D(QWindow);

View File

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

View File

@ -73,20 +73,17 @@
#include "../eglconvenience/qxlibeglintegration.h"
#endif
#if 0
// 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
|| w->windowType() == Qt::Sheet
|| w->windowType() == Qt::Tool
|| w->windowType() == Qt::SplashScreen
|| w->windowType() == Qt::ToolTip
|| w->windowType() == Qt::Drawer
|| w->windowType() == Qt::Popup)
&& !w->testAttribute(Qt::WA_X11BypassTransientForHint));
return w->windowType() == Qt::Dialog
|| w->windowType() == Qt::Sheet
|| w->windowType() == Qt::Tool
|| w->windowType() == Qt::SplashScreen
|| w->windowType() == Qt::ToolTip
|| w->windowType() == Qt::Drawer
|| w->windowType() == Qt::Popup;
}
#endif
QXcbWindow::QXcbWindow(QWindow *window)
: QPlatformWindow(window)
@ -119,8 +116,8 @@ QXcbWindow::QXcbWindow(QWindow *window)
QRect rect = window->geometry();
xcb_window_t xcb_parent_id = m_screen->root();
if (window->parent() && window->parent()->handle())
xcb_parent_id = static_cast<QXcbWindow *>(window->parent()->handle())->xcb_window();
if (parent() && !window->isTopLevel())
xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
#if defined(XCB_USE_GLX) || defined(XCB_USE_EGL)
if (window->surfaceType() == QWindow::OpenGLSurface
@ -217,18 +214,6 @@ QXcbWindow::QXcbWindow(QWindow *window)
&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
long pid = getpid();
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);
// update WM_NORMAL_HINTS
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));
@ -598,6 +595,7 @@ void QXcbWindow::lower()
void QXcbWindow::propagateSizeHints()
{
// update WM_NORMAL_HINTS
xcb_size_hints_t hints;
QRect rect = geometry();

View File

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