Better setWindowFlags() support in XCB window.

We need to re-create the native window in setParent, as used to be done
in QWidgetPrivate::setParent_sys in qwidget_x11.cpp.
This commit is contained in:
Samuel Rødal 2011-05-19 10:51:34 +02:00
parent e0e696dd05
commit ea7277690d
6 changed files with 100 additions and 49 deletions

View File

@ -127,9 +127,6 @@ void QWindow::setParent(QWindow *parent)
{
Q_D(QWindow);
if (d->parentWindow == parent)
return;
QObject::setParent(parent);
if (d->platformWindow) {

View File

@ -102,6 +102,26 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num
free(reply);
m_syncRequestSupported = m_windowManagerName != QLatin1String("KWin");
m_clientLeader = xcb_generate_id(xcb_connection());
Q_XCB_CALL2(xcb_create_window(xcb_connection(),
XCB_COPY_FROM_PARENT,
m_clientLeader,
m_screen->root,
0, 0, 1, 1,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
m_screen->root_visual,
0, 0), connection);
Q_XCB_CALL2(xcb_change_property(xcb_connection(),
XCB_PROP_MODE_REPLACE,
m_clientLeader,
atom(QXcbAtom::WM_CLIENT_LEADER),
XCB_ATOM_WINDOW,
32,
1,
&m_clientLeader), connection);
}
QXcbScreen::~QXcbScreen()

View File

@ -67,6 +67,8 @@ public:
xcb_screen_t *screen() const { return m_screen; }
xcb_window_t root() const { return m_screen->root; }
xcb_window_t clientLeader() const { return m_clientLeader; }
QString windowManagerName() const { return m_windowManagerName; }
bool syncRequestSupported() const { return m_syncRequestSupported; }
@ -75,6 +77,7 @@ private:
int m_number;
QString m_windowManagerName;
bool m_syncRequestSupported;
xcb_window_t m_clientLeader;
};
#endif

View File

@ -89,17 +89,35 @@ static inline bool isTransient(const QWindow *w)
QXcbWindow::QXcbWindow(QWindow *window)
: QPlatformWindow(window)
, m_window(0)
, m_context(0)
, m_windowState(Qt::WindowNoState)
, m_syncCounter(0)
{
m_screen = static_cast<QXcbScreen *>(QGuiApplicationPrivate::platformIntegration()->screens().at(0));
setConnection(m_screen->connection());
const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_EVENT_MASK;
create();
}
void QXcbWindow::create()
{
bool wasCreated = (m_window != 0);
destroy();
m_windowState = Qt::WindowNoState;
m_hasReceivedSyncRequest = false;
Qt::WindowType type = window()->windowType();
const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | XCB_CW_EVENT_MASK;
const quint32 values[] = {
// XCB_CW_BACK_PIXMAP
XCB_NONE,
// XCB_CW_OVERRIDE_REDIRECT
type == Qt::Popup,
// XCB_CW_SAVE_UNDER
type == Qt::Popup || type == Qt::Tool || type == Qt::SplashScreen || type == Qt::ToolTip || type == Qt::Drawer,
// XCB_CW_EVENT_MASK
XCB_EVENT_MASK_EXPOSURE
| XCB_EVENT_MASK_STRUCTURE_NOTIFY
@ -115,21 +133,21 @@ QXcbWindow::QXcbWindow(QWindow *window)
| XCB_EVENT_MASK_FOCUS_CHANGE
};
QRect rect = window->geometry();
QRect rect = window()->geometry();
xcb_window_t xcb_parent_id = m_screen->root();
if (parent() && !window->isTopLevel())
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
if (window()->surfaceType() == QWindow::OpenGLSurface
&& QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL))
{
#if defined(XCB_USE_GLX)
XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), window->requestedWindowFormat());
XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), window()->requestedWindowFormat());
#elif defined(XCB_USE_EGL)
EGLDisplay eglDisplay = connection()->egl_display();
EGLConfig eglConfig = q_configFromQPlatformWindowFormat(eglDisplay,window->requestedWindowFormat(),true);
EGLConfig eglConfig = q_configFromQPlatformWindowFormat(eglDisplay,window()->requestedWindowFormat(),true);
VisualID id = QXlibEglIntegration::getCompatibleVisualId(DISPLAY_FROM_XCB(this), eglDisplay, eglConfig);
XVisualInfo visualInfoTemplate;
@ -149,7 +167,7 @@ QXcbWindow::QXcbWindow(QWindow *window)
0, visualInfo->depth, InputOutput, visualInfo->visual,
CWColormap, &a);
printf("created GL window: %d\n", m_window);
printf("created GL window: %x\n", m_window);
} else {
qFatal("no window!");
}
@ -172,7 +190,7 @@ QXcbWindow::QXcbWindow(QWindow *window)
0, // value mask
0)); // value list
printf("created regular window: %d\n", m_window);
printf("created regular window: %x\n", m_window);
}
connection()->addWindow(m_window, this);
@ -188,7 +206,7 @@ QXcbWindow::QXcbWindow(QWindow *window)
if (m_screen->syncRequestSupported())
properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST);
if (window->windowFlags() & Qt::WindowContextHelpButtonHint)
if (window()->windowFlags() & Qt::WindowContextHelpButtonHint)
properties[propertyCount++] = atom(QXcbAtom::_NET_WM_CONTEXT_HELP);
Q_XCB_CALL(xcb_change_property(xcb_connection(),
@ -221,16 +239,37 @@ QXcbWindow::QXcbWindow(QWindow *window)
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
atom(QXcbAtom::_NET_WM_PID), XCB_ATOM_CARDINAL, 32,
1, &pid));
xcb_wm_hints_t hints;
memset(&hints, 0, sizeof(hints));
xcb_wm_hints_set_normal(&hints);
xcb_set_wm_hints(xcb_connection(), m_window, &hints);
xcb_window_t leader = m_screen->clientLeader();
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
atom(QXcbAtom::WM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32,
1, &leader));
if (wasCreated)
setWindowFlags(window()->windowFlags());
}
QXcbWindow::~QXcbWindow()
{
destroy();
}
void QXcbWindow::destroy()
{
delete m_context;
if (m_screen->syncRequestSupported())
if (m_syncCounter && m_screen->syncRequestSupported())
Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter));
if (m_window) {
connection()->removeWindow(m_window);
Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window));
}
}
void QXcbWindow::setGeometry(const QRect &rect)
{
@ -468,27 +507,20 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
{
Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
setNetWmWindowTypes(flags);
if (type == Qt::ToolTip)
flags |= Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint;
if (type == Qt::Popup)
flags |= Qt::X11BypassWindowManagerHint;
bool topLevel = (flags & Qt::Window);
bool popup = (type == Qt::Popup);
bool dialog = (type == Qt::Dialog
|| type == Qt::Sheet);
bool desktop = (type == Qt::Desktop);
bool tool = (type == Qt::Tool || type == Qt::SplashScreen
|| type == Qt::ToolTip || type == Qt::Drawer);
setNetWmWindowFlags(flags);
setMotifWindowFlags(flags);
Q_UNUSED(topLevel);
Q_UNUSED(dialog);
Q_UNUSED(desktop);
Q_UNUSED(tool);
return flags;
}
bool tooltip = (type == Qt::ToolTip);
void QXcbWindow::setMotifWindowFlags(Qt::WindowFlags flags)
{
Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
QtMotifWmHints mwmhints;
mwmhints.flags = 0L;
@ -551,15 +583,6 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
}
setMotifWmHints(connection(), m_window, mwmhints);
if (popup || tooltip) {
const quint32 mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER;
const quint32 values[] = { true, true };
Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values));
}
return flags;
}
void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two)
@ -640,7 +663,7 @@ Qt::WindowState QXcbWindow::setWindowState(Qt::WindowState state)
return m_windowState;
}
void QXcbWindow::setNetWmWindowTypes(Qt::WindowFlags flags)
void QXcbWindow::setNetWmWindowFlags(Qt::WindowFlags flags)
{
// in order of decreasing priority
QVector<uint> windowTypes;
@ -767,6 +790,9 @@ WId QXcbWindow::winId() const
void QXcbWindow::setParent(const QPlatformWindow *parent)
{
// re-create for compatibility
create();
QPoint topLeft = geometry().topLeft();
xcb_window_t xcb_parent_id = parent ? static_cast<const QXcbWindow *>(parent)->xcb_window() : m_screen->root();

View File

@ -94,15 +94,20 @@ public:
void updateSyncRequestCounter();
private:
void setNetWmWindowTypes(Qt::WindowFlags flags);
void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0);
QVector<xcb_atom_t> getNetWmState();
void setNetWmState(const QVector<xcb_atom_t> &atoms);
void printNetWmState(const QVector<xcb_atom_t> &state);
void setNetWmWindowFlags(Qt::WindowFlags flags);
void setMotifWindowFlags(Qt::WindowFlags flags);
void updateMotifWmHintsBeforeMap();
void updateNetWmStateBeforeMap();
void create();
void destroy();
void show();
void hide();

View File

@ -93,13 +93,14 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
QWindow *win = topData()->window;
win->setWindowFlags(data.window_flags);
win->setGeometry(q->geometry());
if (QWidget *nativeParent = q->nativeParentWidget()) {
if (nativeParent->windowHandle())
win->setParent(nativeParent->windowHandle());
}
win->setWindowFlags(data.window_flags);
win->setGeometry(q->geometry());
win->create();
data.window_flags = win->windowFlags();
@ -174,15 +175,14 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
if (parent != newparent) {
QObjectPrivate::setParent_helper(newparent); //### why does this have to be done in the _sys function???
if (q->windowHandle() && newparent) {
QWidget * parentWithWindow = newparent->windowHandle()? newparent : newparent->nativeParentWidget();
if (parentWithWindow && parentWithWindow->windowHandle()) {
q->windowHandle()->setParent(parentWithWindow->windowHandle());
if (q->windowHandle()) {
q->windowHandle()->setWindowFlags(f);
QWidget *parentWithWindow =
newparent ? (newparent->windowHandle() ? newparent : newparent->nativeParentWidget()) : 0;
q->windowHandle()->setParent(parentWithWindow ? parentWithWindow->windowHandle() : 0);
}
}
}
if (!newparent) {
f |= Qt::Window;
if (targetScreen == -1) {