Add QWindow::setWindowModality().

Also set corresponding window manager hints in xcb plugin.
This commit is contained in:
Samuel Rødal 2011-05-18 09:32:17 +02:00
parent 10a3b10726
commit 516f4e283b
7 changed files with 151 additions and 19 deletions

View File

@ -152,6 +152,24 @@ bool QWindow::isTopLevel() const
return d->windowFlags & Qt::Window;
}
bool QWindow::isModal() const
{
Q_D(const QWindow);
return d->modality != Qt::NonModal;
}
Qt::WindowModality QWindow::windowModality() const
{
Q_D(const QWindow);
return d->modality;
}
void QWindow::setWindowModality(Qt::WindowModality windowModality)
{
Q_D(QWindow);
d->modality = windowModality;
}
void QWindow::setWindowFormat(const QWindowFormat &format)
{
Q_D(QWindow);

View File

@ -96,7 +96,9 @@ public:
bool isTopLevel() const;
QWindow *topLevelWindow() const;
bool isModal() const;
Qt::WindowModality windowModality() const;
void setWindowModality(Qt::WindowModality windowModality);
void setWindowFormat(const QWindowFormat &format);
QWindowFormat requestedWindowFormat() const;

View File

@ -92,6 +92,8 @@ public:
QSize maximumSize;
QSize baseSize;
QSize sizeIncrement;
Qt::WindowModality modality;
};

View File

@ -253,8 +253,15 @@ void QXcbWindow::show()
if (window()->isTopLevel()) {
xcb_get_property_cookie_t cookie = xcb_get_wm_hints(xcb_connection(), m_window);
xcb_generic_error_t *error;
xcb_wm_hints_t hints;
xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, 0);
xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, &error);
if (error) {
connection()->handleXcbError(error);
free(error);
}
if (window()->windowState() & Qt::WindowMinimized)
xcb_wm_hints_set_iconic(&hints);
@ -276,6 +283,9 @@ void QXcbWindow::show()
XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32,
1, &parentWindow));
}
// update _MOTIF_WM_HINTS
updateMotifWmHintsBeforeShow();
}
Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
@ -299,7 +309,7 @@ void QXcbWindow::hide()
xcb_flush(xcb_connection());
}
struct QtMWMHints {
struct QtMotifWmHints {
quint32 flags, functions, decorations;
qint32 input_mode;
quint32 status;
@ -332,6 +342,53 @@ enum {
MWM_INPUT_FULL_APPLICATION_MODAL = 3L
};
static QtMotifWmHints getMotifWmHints(QXcbConnection *c, xcb_window_t window)
{
QtMotifWmHints hints;
xcb_get_property_cookie_t get_cookie =
xcb_get_property(c->xcb_connection(), 0, window, c->atom(QXcbAtom::_MOTIF_WM_HINTS),
c->atom(QXcbAtom::_MOTIF_WM_HINTS), 0, 20);
xcb_generic_error_t *error;
xcb_get_property_reply_t *reply =
xcb_get_property_reply(c->xcb_connection(), get_cookie, &error);
if (reply && reply->format == 32 && reply->type == c->atom(QXcbAtom::_MOTIF_WM_HINTS)) {
hints = *((QtMotifWmHints *)xcb_get_property_value(reply));
} else if (error) {
c->handleXcbError(error);
free(error);
hints.flags = 0L;
hints.functions = MWM_FUNC_ALL;
hints.decorations = MWM_DECOR_ALL;
hints.input_mode = 0L;
hints.status = 0L;
}
free(reply);
return hints;
}
static void setMotifWmHints(QXcbConnection *c, xcb_window_t window, const QtMotifWmHints &hints)
{
if (hints.flags != 0l) {
Q_XCB_CALL2(xcb_change_property(c->xcb_connection(),
XCB_PROP_MODE_REPLACE,
window,
c->atom(QXcbAtom::_MOTIF_WM_HINTS),
c->atom(QXcbAtom::_MOTIF_WM_HINTS),
32,
5,
&hints), c);
} else {
Q_XCB_CALL2(xcb_delete_property(c->xcb_connection(), window, c->atom(QXcbAtom::_MOTIF_WM_HINTS)), c);
}
}
Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
{
Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
@ -358,7 +415,7 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
bool tooltip = (type == Qt::ToolTip);
QtMWMHints mwmhints;
QtMotifWmHints mwmhints;
mwmhints.flags = 0L;
mwmhints.functions = 0L;
mwmhints.decorations = 0;
@ -418,18 +475,7 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
mwmhints.decorations = 0;
}
if (mwmhints.flags != 0l) {
Q_XCB_CALL(xcb_change_property(xcb_connection(),
XCB_PROP_MODE_REPLACE,
m_window,
atom(QXcbAtom::_MOTIF_WM_HINTS),
atom(QXcbAtom::_MOTIF_WM_HINTS),
32,
5,
&mwmhints));
} else {
Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_MOTIF_WM_HINTS)));
}
setMotifWmHints(connection(), m_window, mwmhints);
if (popup || tooltip) {
const quint32 mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER;
@ -555,6 +601,62 @@ void QXcbWindow::setNetWmWindowTypes(Qt::WindowFlags flags)
windowTypes.count(), windowTypes.constData()));
}
void QXcbWindow::updateMotifWmHintsBeforeShow()
{
QtMotifWmHints mwmhints = getMotifWmHints(connection(), m_window);
if (window()->windowModality() != Qt::NonModal) {
switch (window()->windowModality()) {
case Qt::WindowModal:
mwmhints.input_mode = MWM_INPUT_PRIMARY_APPLICATION_MODAL;
break;
case Qt::ApplicationModal:
default:
mwmhints.input_mode = MWM_INPUT_FULL_APPLICATION_MODAL;
break;
}
mwmhints.flags |= MWM_HINTS_INPUT_MODE;
} else {
mwmhints.input_mode = MWM_INPUT_MODELESS;
mwmhints.flags &= ~MWM_HINTS_INPUT_MODE;
}
if (window()->minimumSize() == window()->maximumSize()) {
// fixed size, remove the resize handle (since mwm/dtwm
// isn't smart enough to do it itself)
mwmhints.flags |= MWM_HINTS_FUNCTIONS;
if (mwmhints.functions == MWM_FUNC_ALL) {
mwmhints.functions = MWM_FUNC_MOVE;
} else {
mwmhints.functions &= ~MWM_FUNC_RESIZE;
}
if (mwmhints.decorations == MWM_DECOR_ALL) {
mwmhints.flags |= MWM_HINTS_DECORATIONS;
mwmhints.decorations = (MWM_DECOR_BORDER
| MWM_DECOR_TITLE
| MWM_DECOR_MENU);
} else {
mwmhints.decorations &= ~MWM_DECOR_RESIZEH;
}
}
if (window()->windowFlags() & Qt::WindowMinimizeButtonHint) {
mwmhints.flags |= MWM_HINTS_DECORATIONS;
mwmhints.decorations |= MWM_DECOR_MINIMIZE;
mwmhints.functions |= MWM_FUNC_MINIMIZE;
}
if (window()->windowFlags() & Qt::WindowMaximizeButtonHint) {
mwmhints.flags |= MWM_HINTS_DECORATIONS;
mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
mwmhints.functions |= MWM_FUNC_MAXIMIZE;
}
if (window()->windowFlags() & Qt::WindowCloseButtonHint)
mwmhints.functions |= MWM_FUNC_CLOSE;
setMotifWmHints(connection(), m_window, mwmhints);
}
WId QXcbWindow::winId() const
{
return m_window;
@ -563,7 +665,9 @@ WId QXcbWindow::winId() const
void QXcbWindow::setParent(const QPlatformWindow *parent)
{
QPoint topLeft = geometry().topLeft();
Q_XCB_CALL(xcb_reparent_window(xcb_connection(), xcb_window(), static_cast<const QXcbWindow *>(parent)->xcb_window(), topLeft.x(), topLeft.y()));
xcb_window_t xcb_parent_id = parent ? static_cast<const QXcbWindow *>(parent)->xcb_window() : m_screen->root();
Q_XCB_CALL(xcb_reparent_window(xcb_connection(), xcb_window(), xcb_parent_id, topLeft.x(), topLeft.y()));
}
void QXcbWindow::setWindowTitle(const QString &title)

View File

@ -97,6 +97,8 @@ private:
void setNetWmWindowTypes(Qt::WindowFlags flags);
void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0);
void updateMotifWmHintsBeforeShow();
void show();
void hide();

View File

@ -763,7 +763,8 @@ void QWidgetPrivate::updateFrameStrut()
void QWidgetPrivate::setWindowOpacity_sys(qreal level)
{
Q_Q(QWidget);
q->windowHandle()->setOpacity(level);
if (q->windowHandle())
q->windowHandle()->setOpacity(level);
}
void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
@ -788,6 +789,9 @@ QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
void QWidgetPrivate::setModal_sys()
{
Q_Q(QWidget);
if (q->windowHandle())
q->windowHandle()->setWindowModality(q->windowModality());
}
#ifndef QT_NO_CURSOR

View File

@ -134,7 +134,7 @@ enum {
};
static QtMWMHints GetMWMHints(Display *display, Window window)
static QtMWMHints getMWMHints(Display *display, Window window)
{
QtMWMHints mwmhints;