XCB: Compress window state change events.
- Avoid sending Window State change events from WM_STATE/NET_WM_STATE changes irrelevant to Qt::WindowState. - Introduce QFlags for the NetWmState getter and setter to avoid passing QVector<> around. Change-Id: I74730928c7fffca0fa1cab3b90ded90b06304c06 Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com>bb10
parent
9839474e19
commit
54f718e552
|
|
@ -149,6 +149,7 @@ QXcbWindow::QXcbWindow(QWindow *window)
|
|||
#if defined(XCB_USE_EGL)
|
||||
, m_eglSurface(0)
|
||||
#endif
|
||||
, m_lastWindowStateEvent(-1)
|
||||
{
|
||||
m_screen = static_cast<QXcbScreen *>(window->screen()->handle());
|
||||
|
||||
|
|
@ -636,29 +637,9 @@ static void setMotifWmHints(QXcbConnection *c, xcb_window_t window, const QtMoti
|
|||
}
|
||||
}
|
||||
|
||||
void QXcbWindow::printNetWmState(const QVector<xcb_atom_t> &state)
|
||||
QXcbWindow::NetWmStates QXcbWindow::netWmStates()
|
||||
{
|
||||
printf("_NET_WM_STATE (%d): ", state.size());
|
||||
for (int i = 0; i < state.size(); ++i) {
|
||||
#define CHECK_WM_STATE(state_atom) \
|
||||
if (state.at(i) == atom(QXcbAtom::state_atom))\
|
||||
printf(#state_atom " ");
|
||||
CHECK_WM_STATE(_NET_WM_STATE_ABOVE)
|
||||
CHECK_WM_STATE(_NET_WM_STATE_BELOW)
|
||||
CHECK_WM_STATE(_NET_WM_STATE_FULLSCREEN)
|
||||
CHECK_WM_STATE(_NET_WM_STATE_MAXIMIZED_HORZ)
|
||||
CHECK_WM_STATE(_NET_WM_STATE_MAXIMIZED_VERT)
|
||||
CHECK_WM_STATE(_NET_WM_STATE_MODAL)
|
||||
CHECK_WM_STATE(_NET_WM_STATE_STAYS_ON_TOP)
|
||||
CHECK_WM_STATE(_NET_WM_STATE_DEMANDS_ATTENTION)
|
||||
#undef CHECK_WM_STATE
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
QVector<xcb_atom_t> QXcbWindow::getNetWmState()
|
||||
{
|
||||
QVector<xcb_atom_t> result;
|
||||
NetWmStates result(0);
|
||||
|
||||
xcb_get_property_cookie_t get_cookie =
|
||||
xcb_get_property_unchecked(xcb_connection(), 0, m_window, atom(QXcbAtom::_NET_WM_STATE),
|
||||
|
|
@ -668,15 +649,24 @@ QVector<xcb_atom_t> QXcbWindow::getNetWmState()
|
|||
xcb_get_property_reply(xcb_connection(), get_cookie, NULL);
|
||||
|
||||
if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) {
|
||||
result.resize(reply->length);
|
||||
|
||||
memcpy(result.data(), xcb_get_property_value(reply), reply->length * sizeof(xcb_atom_t));
|
||||
|
||||
#ifdef NET_WM_STATE_DEBUG
|
||||
printf("getting net wm state (%x)\n", m_window);
|
||||
printNetWmState(result);
|
||||
#endif
|
||||
|
||||
const xcb_atom_t *states = static_cast<const xcb_atom_t *>(xcb_get_property_value(reply));
|
||||
const xcb_atom_t *statesEnd = states + reply->length;
|
||||
if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_ABOVE)))
|
||||
result |= NetWmStateAbove;
|
||||
if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_BELOW)))
|
||||
result |= NetWmStateBelow;
|
||||
if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)))
|
||||
result |= NetWmStateFullScreen;
|
||||
if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ)))
|
||||
result |= NetWmStateMaximizedHorz;
|
||||
if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)))
|
||||
result |= NetWmStateMaximizedVert;
|
||||
if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MODAL)))
|
||||
result |= NetWmStateModal;
|
||||
if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)))
|
||||
result |= NetWmStateStaysOnTop;
|
||||
if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)))
|
||||
result |= NetWmStateDemandsAttention;
|
||||
free(reply);
|
||||
} else {
|
||||
#ifdef NET_WM_STATE_DEBUG
|
||||
|
|
@ -687,8 +677,26 @@ QVector<xcb_atom_t> QXcbWindow::getNetWmState()
|
|||
return result;
|
||||
}
|
||||
|
||||
void QXcbWindow::setNetWmState(const QVector<xcb_atom_t> &atoms)
|
||||
void QXcbWindow::setNetWmStates(NetWmStates states)
|
||||
{
|
||||
QVector<xcb_atom_t> atoms;
|
||||
if (states & NetWmStateAbove)
|
||||
atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_ABOVE));
|
||||
if (states & NetWmStateBelow)
|
||||
atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_BELOW));
|
||||
if (states & NetWmStateFullScreen)
|
||||
atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
|
||||
if (states & NetWmStateMaximizedHorz)
|
||||
atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ));
|
||||
if (states & NetWmStateMaximizedVert)
|
||||
atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
|
||||
if (states & NetWmStateModal)
|
||||
atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MODAL));
|
||||
if (states & NetWmStateStaysOnTop)
|
||||
atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP));
|
||||
if (states & NetWmStateDemandsAttention)
|
||||
atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION));
|
||||
|
||||
if (atoms.isEmpty()) {
|
||||
Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_STATE)));
|
||||
} else {
|
||||
|
|
@ -699,7 +707,6 @@ void QXcbWindow::setNetWmState(const QVector<xcb_atom_t> &atoms)
|
|||
xcb_flush(xcb_connection());
|
||||
}
|
||||
|
||||
|
||||
Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
|
||||
{
|
||||
Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
|
||||
|
|
@ -966,30 +973,28 @@ void QXcbWindow::updateMotifWmHintsBeforeMap()
|
|||
|
||||
void QXcbWindow::updateNetWmStateBeforeMap()
|
||||
{
|
||||
QVector<xcb_atom_t> netWmState;
|
||||
NetWmStates states(0);
|
||||
|
||||
Qt::WindowFlags flags = window()->windowFlags();
|
||||
const Qt::WindowFlags flags = window()->windowFlags();
|
||||
if (flags & Qt::WindowStaysOnTopHint) {
|
||||
netWmState.append(atom(QXcbAtom::_NET_WM_STATE_ABOVE));
|
||||
netWmState.append(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP));
|
||||
states |= NetWmStateAbove;
|
||||
states |= NetWmStateStaysOnTop;
|
||||
} else if (flags & Qt::WindowStaysOnBottomHint) {
|
||||
netWmState.append(atom(QXcbAtom::_NET_WM_STATE_BELOW));
|
||||
states |= NetWmStateBelow;
|
||||
}
|
||||
|
||||
if (window()->windowState() & Qt::WindowFullScreen) {
|
||||
netWmState.append(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
|
||||
}
|
||||
if (window()->windowState() & Qt::WindowFullScreen)
|
||||
states |= NetWmStateFullScreen;
|
||||
|
||||
if (window()->windowState() & Qt::WindowMaximized) {
|
||||
netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ));
|
||||
netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
|
||||
states |= NetWmStateMaximizedHorz;
|
||||
states |= NetWmStateMaximizedVert;
|
||||
}
|
||||
|
||||
if (window()->windowModality() != Qt::NonModal) {
|
||||
netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MODAL));
|
||||
}
|
||||
if (window()->windowModality() != Qt::NonModal)
|
||||
states |= NetWmStateModal;
|
||||
|
||||
setNetWmState(netWmState);
|
||||
setNetWmStates(states);
|
||||
}
|
||||
|
||||
void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp)
|
||||
|
|
@ -1452,41 +1457,42 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
|
|||
{
|
||||
connection()->setTime(event->time);
|
||||
|
||||
bool propertyDeleted = event->state == XCB_PROPERTY_DELETE;
|
||||
const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE;
|
||||
const xcb_atom_t netWmStateAtom = atom(QXcbAtom::_NET_WM_STATE);
|
||||
const xcb_atom_t wmStateAtom = atom(QXcbAtom::WM_STATE);
|
||||
|
||||
if (event->atom == atom(QXcbAtom::_NET_WM_STATE) || event->atom == atom(QXcbAtom::WM_STATE)) {
|
||||
if (event->atom == netWmStateAtom || event->atom == wmStateAtom) {
|
||||
if (propertyDeleted)
|
||||
return;
|
||||
|
||||
xcb_get_property_cookie_t get_cookie =
|
||||
xcb_get_property(xcb_connection(), 0, m_window, atom(QXcbAtom::WM_STATE),
|
||||
XCB_ATOM_ANY, 0, 1024);
|
||||
Qt::WindowState newState = Qt::WindowNoState;
|
||||
if (event->atom == wmStateAtom) { // WM_STATE: Quick check for 'Minimize'.
|
||||
const xcb_get_property_cookie_t get_cookie =
|
||||
xcb_get_property(xcb_connection(), 0, m_window, wmStateAtom,
|
||||
XCB_ATOM_ANY, 0, 1024);
|
||||
|
||||
xcb_get_property_reply_t *reply =
|
||||
xcb_get_property_reply(xcb_connection(), get_cookie, NULL);
|
||||
xcb_get_property_reply_t *reply =
|
||||
xcb_get_property_reply(xcb_connection(), get_cookie, NULL);
|
||||
|
||||
xcb_atom_t wm_state = XCB_WM_STATE_WITHDRAWN;
|
||||
if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) {
|
||||
if (reply->length != 0)
|
||||
wm_state = ((long *)xcb_get_property_value(reply))[0];
|
||||
free(reply);
|
||||
if (reply && reply->format == 32 && reply->type == wmStateAtom) {
|
||||
const long *data = (const long *)xcb_get_property_value(reply);
|
||||
if (reply->length != 0 && XCB_WM_STATE_ICONIC == data[0])
|
||||
newState = Qt::WindowMinimized;
|
||||
free(reply);
|
||||
}
|
||||
} // WM_STATE: Quick check for 'Minimize'.
|
||||
if (newState != Qt::WindowMinimized) { // Something else changed, get _NET_WM_STATE.
|
||||
const NetWmStates states = netWmStates();
|
||||
if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert))
|
||||
newState = Qt::WindowMaximized;
|
||||
else if (states & NetWmStateFullScreen)
|
||||
newState = Qt::WindowFullScreen;
|
||||
}
|
||||
// Send Window state, compress events in case other flags (modality, etc) are changed.
|
||||
if (m_lastWindowStateEvent != newState) {
|
||||
QWindowSystemInterface::handleWindowStateChanged(window(), newState);
|
||||
m_lastWindowStateEvent = newState;
|
||||
}
|
||||
|
||||
QVector<xcb_atom_t> netWmState = getNetWmState();
|
||||
|
||||
bool maximized = netWmState.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ))
|
||||
&& netWmState.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
|
||||
bool fullscreen = netWmState.contains(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
|
||||
|
||||
Qt::WindowState state = Qt::WindowNoState;
|
||||
if (wm_state == XCB_WM_STATE_ICONIC)
|
||||
state = Qt::WindowMinimized;
|
||||
else if (maximized)
|
||||
state = Qt::WindowMaximized;
|
||||
else if (fullscreen)
|
||||
state = Qt::WindowFullScreen;
|
||||
|
||||
QWindowSystemInterface::handleWindowStateChanged(window(), state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,19 @@ class QXcbEGLSurface;
|
|||
class QXcbWindow : public QXcbObject, public QPlatformWindow
|
||||
{
|
||||
public:
|
||||
enum NetWmState {
|
||||
NetWmStateAbove = 0x1,
|
||||
NetWmStateBelow = 0x2,
|
||||
NetWmStateFullScreen = 0x4,
|
||||
NetWmStateMaximizedHorz = 0x8,
|
||||
NetWmStateMaximizedVert = 0x10,
|
||||
NetWmStateModal = 0x20,
|
||||
NetWmStateStaysOnTop = 0x40,
|
||||
NetWmStateDemandsAttention = 0x80
|
||||
};
|
||||
|
||||
Q_DECLARE_FLAGS(NetWmStates, NetWmState)
|
||||
|
||||
QXcbWindow(QWindow *window);
|
||||
~QXcbWindow();
|
||||
|
||||
|
|
@ -121,9 +134,8 @@ public:
|
|||
|
||||
private:
|
||||
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);
|
||||
NetWmStates netWmStates();
|
||||
void setNetWmStates(NetWmStates);
|
||||
|
||||
void setNetWmWindowFlags(Qt::WindowFlags flags);
|
||||
void setMotifWindowFlags(Qt::WindowFlags flags);
|
||||
|
|
@ -169,6 +181,7 @@ private:
|
|||
QRegion m_exposeRegion;
|
||||
|
||||
xcb_visualid_t m_visualId;
|
||||
int m_lastWindowStateEvent;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
Loading…
Reference in New Issue