diff options
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbwindow.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 137 |
1 files changed, 33 insertions, 104 deletions
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index dfc9c7d7a3..bffad0fac5 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -93,6 +93,8 @@ enum { QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window"); + Q_DECLARE_TYPEINFO(xcb_rectangle_t, Q_PRIMITIVE_TYPE); #undef FocusIn @@ -555,6 +557,7 @@ void QXcbWindow::destroy() } m_mapped = false; + m_recreationReasons = RecreationNotNeeded; if (m_pendingSyncRequest) m_pendingSyncRequest->invalidate(); @@ -564,11 +567,6 @@ void QXcbWindow::setGeometry(const QRect &rect) { QPlatformWindow::setGeometry(rect); - if (shouldDeferTask(Task::SetGeometry)) { - m_deferredGeometry = rect; - return; - } - propagateSizeHints(); QXcbScreen *currentScreen = xcbScreen(); @@ -693,10 +691,12 @@ void QXcbWindow::setVisible(bool visible) void QXcbWindow::show() { - if (shouldDeferTask(Task::Map)) - return; - if (window()->isTopLevel()) { + if (m_recreationReasons != RecreationNotNeeded) { + qCDebug(lcQpaWindow) << "QXcbWindow: need to recreate window" << window() << m_recreationReasons; + create(); + m_recreationReasons = RecreationNotNeeded; + } // update WM_NORMAL_HINTS propagateSizeHints(); @@ -706,7 +706,7 @@ void QXcbWindow::show() if (isTransient(window())) { const QWindow *tp = window()->transientParent(); if (tp && tp->handle()) - transientXcbParent = static_cast<const QXcbWindow *>(tp->handle())->winId(); + transientXcbParent = tp->handle()->winId(); // Default to client leader if there is no transient parent, else modal dialogs can // be hidden by their parents. if (!transientXcbParent) @@ -746,10 +746,6 @@ void QXcbWindow::show() void QXcbWindow::hide() { - if (shouldDeferTask(Task::Unmap)) - return; - - m_wmStateValid = false; xcb_unmap_window(xcb_connection(), m_window); // send synthetic UnmapNotify event according to icccm 4.1.4 @@ -909,9 +905,6 @@ QXcbWindow::NetWmStates QXcbWindow::netWmStates() void QXcbWindow::setWindowFlags(Qt::WindowFlags flags) { - if (shouldDeferTask(Task::SetWindowFlags)) - return; - Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask)); if (type == Qt::ToolTip) @@ -919,6 +912,12 @@ void QXcbWindow::setWindowFlags(Qt::WindowFlags flags) if (type == Qt::Popup) flags |= Qt::X11BypassWindowManagerHint; + Qt::WindowFlags oldflags = window()->flags(); + if ((oldflags & Qt::WindowStaysOnTopHint) != (flags & Qt::WindowStaysOnTopHint)) + m_recreationReasons |= WindowStaysOnTopHintChanged; + if ((oldflags & Qt::WindowStaysOnBottomHint) != (flags & Qt::WindowStaysOnBottomHint)) + m_recreationReasons |= WindowStaysOnBottomHintChanged; + const quint32 mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; const quint32 values[] = { // XCB_CW_OVERRIDE_REDIRECT @@ -941,8 +940,6 @@ void QXcbWindow::setWindowFlags(Qt::WindowFlags flags) setTransparentForMouseEvents(flags & Qt::WindowTransparentForInput); updateDoesNotAcceptFocus(flags & Qt::WindowDoesNotAcceptFocus); - - m_isWmManagedWindow = !(flags & Qt::X11BypassWindowManagerHint); } void QXcbWindow::setMotifWmHints(Qt::WindowFlags flags) @@ -1142,9 +1139,6 @@ void QXcbWindow::setWindowState(Qt::WindowStates state) if (state == m_windowState) return; - if (shouldDeferTask(Task::SetWindowState)) - return; - // unset old state if (m_windowState & Qt::WindowMinimized) xcb_map_window(xcb_connection(), m_window); @@ -1350,6 +1344,12 @@ void QXcbWindow::setWindowIcon(const QIcon &icon) } if (!icon_data.isEmpty()) { + // Ignore icon exceeding maximum xcb request length + if (size_t(icon_data.size()) > xcb_get_maximum_request_length(xcb_connection())) { + qWarning("Ignoring window icon: Size %d exceeds maximum xcb request length %u.", + icon_data.size(), xcb_get_maximum_request_length(xcb_connection())); + return; + } xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, @@ -1894,10 +1894,6 @@ void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event) if (event->window == m_window) { m_mapped = false; QWindowSystemInterface::handleExposeEvent(window(), QRegion()); - if (!m_isWmManagedWindow || parent()) { - m_wmStateValid = true; - handleDeferredTasks(); - } } } @@ -2212,98 +2208,30 @@ void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event) handleLeaveNotifyEvent(event->root_x, event->root_y, event->mode, event->detail, event->time); } -bool QXcbWindow::shouldDeferTask(Task task) -{ - if (m_wmStateValid) - return false; - - m_deferredTasks.append(task); - return true; -} - -void QXcbWindow::handleDeferredTasks() -{ - Q_ASSERT(m_wmStateValid == true); - if (m_deferredTasks.isEmpty()) - return; - - bool map = false; - bool unmap = false; - - QVector<Task> tasks; - for (auto taskIt = m_deferredTasks.rbegin(); taskIt != m_deferredTasks.rend(); ++taskIt) { - if (!tasks.contains(*taskIt)) - tasks.prepend(*taskIt); - } - - for (Task task : tasks) { - switch (task) { - case Task::Map: - map = true; - unmap = false; - break; - case Task::Unmap: - unmap = true; - map = false; - break; - case Task::SetGeometry: - setGeometry(m_deferredGeometry); - break; - case Task::SetWindowFlags: - setWindowFlags(window()->flags()); - break; - case Task::SetWindowState: - setWindowState(window()->windowState()); - break; - } - } - m_deferredTasks.clear(); - - if (map) { - Q_ASSERT(unmap == false); - show(); - } - if (unmap) { - Q_ASSERT(map == false); - hide(); - } -} - void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) { connection()->setTime(event->time); - const bool wmStateChanged = event->atom == atom(QXcbAtom::WM_STATE); - const bool netWmStateChanged = event->atom == atom(QXcbAtom::_NET_WM_STATE); - if (netWmStateChanged || wmStateChanged) { - if (wmStateChanged && !m_wmStateValid && m_isWmManagedWindow) { - // ICCCM 4.1.4 - // Clients that want to re-use a client window (e.g. by mapping it again) - // after withdrawing it must wait for the withdrawal to be complete before - // proceeding. The preferred method for doing this is for clients to wait for - // a window manager to update or remove the WM_STATE property. - m_wmStateValid = true; - handleDeferredTasks(); - } - if (event->state == XCB_PROPERTY_DELETE) + const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE; + + if (event->atom == atom(QXcbAtom::_NET_WM_STATE) || event->atom == atom(QXcbAtom::WM_STATE)) { + if (propertyDeleted) return; - if (wmStateChanged) { + Qt::WindowStates newState = Qt::WindowNoState; + + if (event->atom == atom(QXcbAtom::WM_STATE)) { // WM_STATE: Quick check for 'Minimize'. auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), 0, m_window, atom(QXcbAtom::WM_STATE), XCB_ATOM_ANY, 0, 1024); if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) { - auto data = static_cast<const quint32 *>(xcb_get_property_value(reply.get())); - if (reply->length != 0) { - const bool changedToWithdrawn = data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN; - const bool changedToIconic = data[0] == XCB_ICCCM_WM_STATE_ICONIC; - m_minimized = changedToIconic || (changedToWithdrawn && m_minimized); - } + const quint32 *data = (const quint32 *)xcb_get_property_value(reply.get()); + if (reply->length != 0) + m_minimized = (data[0] == XCB_ICCCM_WM_STATE_ICONIC + || (data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN && m_minimized)); } } - // _NET_WM_STATE handling - Qt::WindowStates newState = Qt::WindowNoState; const NetWmStates states = netWmStates(); // _NET_WM_STATE_HIDDEN should be set by the Window Manager to indicate that a window would // not be visible on the screen if its desktop/viewport were active and its coordinates were @@ -2325,6 +2253,7 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev if ((m_windowState & Qt::WindowMinimized) && connection()->mouseGrabber() == this) connection()->setMouseGrabber(nullptr); } + return; } else if (event->atom == atom(QXcbAtom::_NET_FRAME_EXTENTS)) { m_dirtyFrameMargins = true; } |