File indexing completed on 2024-04-21 03:59:25

0001 /*
0002     SPDX-FileCopyrightText: 2000 Troll Tech AS
0003     SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org>
0004 
0005     SPDX-License-Identifier: MIT
0006 */
0007 
0008 //#define NETWMDEBUG
0009 #include "netwm.h"
0010 
0011 #include <xcb/xproto.h>
0012 
0013 #include "atoms_p.h"
0014 #include "netwm_p.h"
0015 
0016 #if KWINDOWSYSTEM_HAVE_X11 // FIXME
0017 
0018 #include <QGuiApplication>
0019 #include <QHash>
0020 
0021 #include <private/qtx11extras_p.h>
0022 
0023 #include <kwindowinfo.h>
0024 #include <kwindowsystem.h>
0025 #include <kx11extras.h>
0026 #include <kxutils_p.h>
0027 
0028 #include <assert.h>
0029 #include <stdio.h>
0030 #include <stdlib.h>
0031 #include <string.h>
0032 
0033 // This struct is defined here to avoid a dependency on xcb-icccm
0034 struct kde_wm_hints {
0035     uint32_t flags;
0036     uint32_t input;
0037     int32_t initial_state;
0038     xcb_pixmap_t icon_pixmap;
0039     xcb_window_t icon_window;
0040     int32_t icon_x;
0041     int32_t icon_y;
0042     xcb_pixmap_t icon_mask;
0043     xcb_window_t window_group;
0044 };
0045 
0046 typedef QHash<xcb_connection_t *, QSharedDataPointer<Atoms>> AtomHash;
0047 Q_GLOBAL_STATIC(AtomHash, s_gAtomsHash)
0048 
0049 static QSharedDataPointer<Atoms> atomsForConnection(xcb_connection_t *c)
0050 {
0051     auto it = s_gAtomsHash->constFind(c);
0052     if (it == s_gAtomsHash->constEnd()) {
0053         QSharedDataPointer<Atoms> atom(new Atoms(c));
0054         s_gAtomsHash->insert(c, atom);
0055         return atom;
0056     }
0057     return it.value();
0058 }
0059 
0060 Atoms::Atoms(xcb_connection_t *c)
0061     : QSharedData()
0062     , m_connection(c)
0063 {
0064     for (int i = 0; i < KwsAtomCount; ++i) {
0065         m_atoms[i] = XCB_ATOM_NONE;
0066     }
0067     init();
0068 }
0069 
0070 static const uint32_t netwm_sendevent_mask = (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY);
0071 
0072 const long MAX_PROP_SIZE = 100000;
0073 
0074 static char *nstrdup(const char *s1)
0075 {
0076     if (!s1) {
0077         return (char *)nullptr;
0078     }
0079 
0080     int l = strlen(s1) + 1;
0081     char *s2 = new char[l];
0082     strncpy(s2, s1, l);
0083     return s2;
0084 }
0085 
0086 static char *nstrndup(const char *s1, int l)
0087 {
0088     if (!s1 || l == 0) {
0089         return (char *)nullptr;
0090     }
0091 
0092     char *s2 = new char[l + 1];
0093     strncpy(s2, s1, l);
0094     s2[l] = '\0';
0095     return s2;
0096 }
0097 
0098 static xcb_window_t *nwindup(const xcb_window_t *w1, int n)
0099 {
0100     if (!w1 || n == 0) {
0101         return (xcb_window_t *)nullptr;
0102     }
0103 
0104     xcb_window_t *w2 = new xcb_window_t[n];
0105     while (n--) {
0106         w2[n] = w1[n];
0107     }
0108     return w2;
0109 }
0110 
0111 static void refdec_nri(NETRootInfoPrivate *p)
0112 {
0113 #ifdef NETWMDEBUG
0114     fprintf(stderr, "NET: decrementing NETRootInfoPrivate::ref (%d)\n", p->ref - 1);
0115 #endif
0116 
0117     if (!--p->ref) {
0118 #ifdef NETWMDEBUG
0119         fprintf(stderr, "NET: \tno more references, deleting\n");
0120 #endif
0121 
0122         delete[] p->name;
0123         delete[] p->stacking;
0124         delete[] p->clients;
0125         delete[] p->virtual_roots;
0126         delete[] p->temp_buf;
0127 
0128         int i;
0129         for (i = 0; i < p->desktop_names.size(); i++) {
0130             delete[] p->desktop_names[i];
0131         }
0132     }
0133 }
0134 
0135 static void refdec_nwi(NETWinInfoPrivate *p)
0136 {
0137 #ifdef NETWMDEBUG
0138     fprintf(stderr, "NET: decrementing NETWinInfoPrivate::ref (%d)\n", p->ref - 1);
0139 #endif
0140 
0141     if (!--p->ref) {
0142 #ifdef NETWMDEBUG
0143         fprintf(stderr, "NET: \tno more references, deleting\n");
0144 #endif
0145 
0146         delete[] p->name;
0147         delete[] p->visible_name;
0148         delete[] p->window_role;
0149         delete[] p->icon_name;
0150         delete[] p->visible_icon_name;
0151         delete[] p->startup_id;
0152         delete[] p->class_class;
0153         delete[] p->class_name;
0154         delete[] p->activities;
0155         delete[] p->client_machine;
0156         delete[] p->desktop_file;
0157         delete[] p->gtk_application_id;
0158         delete[] p->appmenu_object_path;
0159         delete[] p->appmenu_service_name;
0160 
0161         int i;
0162         for (i = 0; i < p->icons.size(); i++) {
0163             delete[] p->icons[i].data;
0164         }
0165         delete[] p->icon_sizes;
0166     }
0167 }
0168 
0169 template<typename T>
0170 T get_value_reply(xcb_connection_t *c, const xcb_get_property_cookie_t cookie, xcb_atom_t type, T def, bool *success = nullptr)
0171 {
0172     T value = def;
0173 
0174     xcb_get_property_reply_t *reply = xcb_get_property_reply(c, cookie, nullptr);
0175 
0176     if (success) {
0177         *success = false;
0178     }
0179 
0180     if (reply) {
0181         if (reply->type == type && reply->value_len == 1 && reply->format == sizeof(T) * 8) {
0182             value = *reinterpret_cast<T *>(xcb_get_property_value(reply));
0183 
0184             if (success) {
0185                 *success = true;
0186             }
0187         }
0188 
0189         free(reply);
0190     }
0191 
0192     return value;
0193 }
0194 
0195 template<typename T>
0196 QList<T> get_array_reply(xcb_connection_t *c, const xcb_get_property_cookie_t cookie, xcb_atom_t type)
0197 {
0198     xcb_get_property_reply_t *reply = xcb_get_property_reply(c, cookie, nullptr);
0199     if (!reply) {
0200         return QList<T>();
0201     }
0202 
0203     QList<T> vector;
0204 
0205     if (reply->type == type && reply->value_len > 0 && reply->format == sizeof(T) * 8) {
0206         T *data = reinterpret_cast<T *>(xcb_get_property_value(reply));
0207 
0208         vector.resize(reply->value_len);
0209         memcpy((void *)&vector.first(), (void *)data, reply->value_len * sizeof(T));
0210     }
0211 
0212     free(reply);
0213     return vector;
0214 }
0215 
0216 static QByteArray get_string_reply(xcb_connection_t *c, const xcb_get_property_cookie_t cookie, xcb_atom_t type)
0217 {
0218     xcb_get_property_reply_t *reply = xcb_get_property_reply(c, cookie, nullptr);
0219     if (!reply) {
0220         return QByteArray();
0221     }
0222 
0223     QByteArray value;
0224 
0225     if (reply->type == type && reply->format == 8 && reply->value_len > 0) {
0226         const char *data = (const char *)xcb_get_property_value(reply);
0227         int len = reply->value_len;
0228 
0229         if (data) {
0230             value = QByteArray(data, data[len - 1] ? len : len - 1);
0231         }
0232     }
0233 
0234     free(reply);
0235     return value;
0236 }
0237 
0238 static QList<QByteArray> get_stringlist_reply(xcb_connection_t *c, const xcb_get_property_cookie_t cookie, xcb_atom_t type)
0239 {
0240     xcb_get_property_reply_t *reply = xcb_get_property_reply(c, cookie, nullptr);
0241     if (!reply) {
0242         return QList<QByteArray>();
0243     }
0244 
0245     QList<QByteArray> list;
0246 
0247     if (reply->type == type && reply->format == 8 && reply->value_len > 0) {
0248         const char *data = (const char *)xcb_get_property_value(reply);
0249         int len = reply->value_len;
0250 
0251         if (data) {
0252             const QByteArray ba = QByteArray(data, data[len - 1] ? len : len - 1);
0253             list = ba.split('\0');
0254         }
0255     }
0256 
0257     free(reply);
0258     return list;
0259 }
0260 
0261 #ifdef NETWMDEBUG
0262 static QByteArray get_atom_name(xcb_connection_t *c, xcb_atom_t atom)
0263 {
0264     const xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(c, atom);
0265 
0266     xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(c, cookie, 0);
0267     if (!reply) {
0268         return QByteArray();
0269     }
0270 
0271     QByteArray ba(xcb_get_atom_name_name(reply));
0272     free(reply);
0273 
0274     return ba;
0275 }
0276 #endif
0277 
0278 void Atoms::init()
0279 {
0280 #define ENUM_CREATE_CHAR_ARRAY 1
0281 #include "atoms_p.h" // creates const char* array "KwsAtomStrings"
0282     // Send the intern atom requests
0283     xcb_intern_atom_cookie_t cookies[KwsAtomCount];
0284     for (int i = 0; i < KwsAtomCount; ++i) {
0285         cookies[i] = xcb_intern_atom(m_connection, false, strlen(KwsAtomStrings[i]), KwsAtomStrings[i]);
0286     }
0287 
0288     // Get the replies
0289     for (int i = 0; i < KwsAtomCount; ++i) {
0290         xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(m_connection, cookies[i], nullptr);
0291         if (!reply) {
0292             continue;
0293         }
0294 
0295         m_atoms[i] = reply->atom;
0296         free(reply);
0297     }
0298 }
0299 
0300 static void readIcon(xcb_connection_t *c, const xcb_get_property_cookie_t cookie, NETRArray<NETIcon> &icons, int &icon_count)
0301 {
0302 #ifdef NETWMDEBUG
0303     fprintf(stderr, "NET: readIcon\n");
0304 #endif
0305 
0306     // reset
0307     for (int i = 0; i < icons.size(); i++) {
0308         delete[] icons[i].data;
0309     }
0310 
0311     icons.reset();
0312     icon_count = 0;
0313 
0314     xcb_get_property_reply_t *reply = xcb_get_property_reply(c, cookie, nullptr);
0315 
0316     if (!reply || reply->value_len < 3 || reply->format != 32 || reply->type != XCB_ATOM_CARDINAL) {
0317         if (reply) {
0318             free(reply);
0319         }
0320 
0321         return;
0322     }
0323 
0324     uint32_t *data = (uint32_t *)xcb_get_property_value(reply);
0325 
0326     for (unsigned int i = 0, j = 0; j < reply->value_len - 2; i++) {
0327         uint32_t width = data[j++];
0328         uint32_t height = data[j++];
0329         uint32_t size = width * height * sizeof(uint32_t);
0330         if (j + width * height > reply->value_len) {
0331             fprintf(stderr, "Ill-encoded icon data; proposed size leads to out of bounds access. Skipping. (%d x %d)\n", width, height);
0332             break;
0333         }
0334         if (width > 1024 || height > 1024) {
0335             fprintf(stderr, "Warning: found huge icon. The icon data may be ill-encoded. (%d x %d)\n", width, height);
0336             // do not break nor continue - the data may likely be junk, but causes no harm (yet) and might actually be just a huge icon, eg. when the icon
0337             // system is abused to transfer wallpapers or such.
0338         }
0339 
0340         icons[i].size.width = width;
0341         icons[i].size.height = height;
0342         icons[i].data = new unsigned char[size];
0343 
0344         memcpy((void *)icons[i].data, (const void *)&data[j], size);
0345 
0346         j += width * height;
0347         icon_count++;
0348     }
0349 
0350     free(reply);
0351 
0352 #ifdef NETWMDEBUG
0353     fprintf(stderr, "NET: readIcon got %d icons\n", icon_count);
0354 #endif
0355 }
0356 
0357 static void send_client_message(xcb_connection_t *c, uint32_t mask, xcb_window_t destination, xcb_window_t window, xcb_atom_t message, const uint32_t data[])
0358 {
0359     xcb_client_message_event_t event;
0360     event.response_type = XCB_CLIENT_MESSAGE;
0361     event.format = 32;
0362     event.sequence = 0;
0363     event.window = window;
0364     event.type = message;
0365 
0366     for (int i = 0; i < 5; i++) {
0367         event.data.data32[i] = data[i];
0368     }
0369 
0370     xcb_send_event(c, false, destination, mask, (const char *)&event);
0371 }
0372 
0373 template<class Z>
0374 NETRArray<Z>::NETRArray()
0375     : sz(0)
0376     , capacity(2)
0377 {
0378     d = (Z *)calloc(capacity, sizeof(Z)); // allocate 2 elts and set to zero
0379 }
0380 
0381 template<class Z>
0382 NETRArray<Z>::~NETRArray()
0383 {
0384     free(d);
0385 }
0386 
0387 template<class Z>
0388 void NETRArray<Z>::reset()
0389 {
0390     sz = 0;
0391     capacity = 2;
0392     d = (Z *)realloc(d, sizeof(Z) * capacity);
0393     memset((void *)d, 0, sizeof(Z) * capacity);
0394 }
0395 
0396 template<class Z>
0397 Z &NETRArray<Z>::operator[](int index)
0398 {
0399     if (index >= capacity) {
0400         // allocate space for the new data
0401         // open table has amortized O(1) access time
0402         // when N elements appended consecutively -- exa
0403         int newcapacity = 2 * capacity > index + 1 ? 2 * capacity : index + 1; // max
0404         // copy into new larger memory block using realloc
0405         d = (Z *)realloc(d, sizeof(Z) * newcapacity);
0406         memset((void *)&d[capacity], 0, sizeof(Z) * (newcapacity - capacity));
0407         capacity = newcapacity;
0408     }
0409     if (index >= sz) { // at this point capacity>index
0410         sz = index + 1;
0411     }
0412 
0413     return d[index];
0414 }
0415 
0416 /*
0417  The viewport<->desktop matching is a bit backwards, since NET* classes are the base
0418  (and were originally even created with the intention of being the reference WM spec
0419  implementation) and KWindowSystem builds on top of it. However it's simpler to add watching
0420  whether the WM uses viewport is simpler to KWindowSystem and not having this mapping
0421  in NET* classes could result in some code using it directly and not supporting viewport.
0422  So NET* classes check if mapping is needed and if yes they forward to KWindowSystem,
0423  which will forward again back to NET* classes, but to viewport calls instead of desktop calls.
0424 */
0425 
0426 // Construct a new NETRootInfo object.
0427 
0428 NETRootInfo::NETRootInfo(xcb_connection_t *connection,
0429                          xcb_window_t supportWindow,
0430                          const char *wmName,
0431                          NET::Properties properties,
0432                          NET::WindowTypes windowTypes,
0433                          NET::States states,
0434                          NET::Properties2 properties2,
0435                          NET::Actions actions,
0436                          int screen,
0437                          bool doActivate)
0438 {
0439 #ifdef NETWMDEBUG
0440     fprintf(stderr, "NETRootInfo::NETRootInfo: using window manager constructor\n");
0441 #endif
0442 
0443     p = new NETRootInfoPrivate;
0444     p->ref = 1;
0445     p->atoms = atomsForConnection(connection);
0446 
0447     p->name = nstrdup(wmName);
0448 
0449     p->conn = connection;
0450 
0451     p->temp_buf = nullptr;
0452     p->temp_buf_size = 0;
0453 
0454     const xcb_setup_t *setup = xcb_get_setup(p->conn);
0455     xcb_screen_iterator_t it = xcb_setup_roots_iterator(setup);
0456 
0457     if (screen != -1 && screen < setup->roots_len) {
0458         for (int i = 0; i < screen; i++) {
0459             xcb_screen_next(&it);
0460         }
0461     }
0462 
0463     p->root = it.data->root;
0464     p->supportwindow = supportWindow;
0465     p->number_of_desktops = p->current_desktop = 0;
0466     p->active = XCB_WINDOW_NONE;
0467     p->clients = p->stacking = p->virtual_roots = (xcb_window_t *)nullptr;
0468     p->clients_count = p->stacking_count = p->virtual_roots_count = 0;
0469     p->showing_desktop = false;
0470     p->desktop_layout_orientation = OrientationHorizontal;
0471     p->desktop_layout_corner = DesktopLayoutCornerTopLeft;
0472     p->desktop_layout_columns = p->desktop_layout_rows = 0;
0473     setDefaultProperties();
0474     p->properties = properties;
0475     p->properties2 = properties2;
0476     p->windowTypes = windowTypes;
0477     p->states = states;
0478     p->actions = actions;
0479     // force support for Supported and SupportingWMCheck for window managers
0480     p->properties |= (Supported | SupportingWMCheck);
0481     p->clientProperties = DesktopNames // the only thing that can be changed by clients
0482         | WMPing; // or they can reply to this
0483     p->clientProperties2 = WM2DesktopLayout;
0484 
0485     p->role = WindowManager;
0486 
0487     if (doActivate) {
0488         activate();
0489     }
0490 }
0491 
0492 NETRootInfo::NETRootInfo(xcb_connection_t *connection, NET::Properties properties, NET::Properties2 properties2, int screen, bool doActivate)
0493 {
0494 #ifdef NETWMDEBUG
0495     fprintf(stderr, "NETRootInfo::NETRootInfo: using Client constructor\n");
0496 #endif
0497 
0498     p = new NETRootInfoPrivate;
0499     p->ref = 1;
0500     p->atoms = atomsForConnection(connection);
0501 
0502     p->name = nullptr;
0503 
0504     p->conn = connection;
0505 
0506     p->temp_buf = nullptr;
0507     p->temp_buf_size = 0;
0508 
0509     const xcb_setup_t *setup = xcb_get_setup(p->conn);
0510     xcb_screen_iterator_t it = xcb_setup_roots_iterator(setup);
0511 
0512     if (screen != -1 && screen < setup->roots_len) {
0513         for (int i = 0; i < screen; i++) {
0514             xcb_screen_next(&it);
0515         }
0516     }
0517 
0518     p->root = it.data->root;
0519     p->rootSize.width = it.data->width_in_pixels;
0520     p->rootSize.height = it.data->height_in_pixels;
0521 
0522     p->supportwindow = XCB_WINDOW_NONE;
0523     p->number_of_desktops = p->current_desktop = 0;
0524     p->active = XCB_WINDOW_NONE;
0525     p->clients = p->stacking = p->virtual_roots = (xcb_window_t *)nullptr;
0526     p->clients_count = p->stacking_count = p->virtual_roots_count = 0;
0527     p->showing_desktop = false;
0528     p->desktop_layout_orientation = OrientationHorizontal;
0529     p->desktop_layout_corner = DesktopLayoutCornerTopLeft;
0530     p->desktop_layout_columns = p->desktop_layout_rows = 0;
0531     setDefaultProperties();
0532     p->clientProperties = properties;
0533     p->clientProperties2 = properties2;
0534     p->properties = NET::Properties();
0535     p->properties2 = NET::Properties2();
0536     p->windowTypes = NET::WindowTypes();
0537     p->states = NET::States();
0538     p->actions = NET::Actions();
0539 
0540     p->role = Client;
0541 
0542     if (doActivate) {
0543         activate();
0544     }
0545 }
0546 
0547 // Copy an existing NETRootInfo object.
0548 
0549 NETRootInfo::NETRootInfo(const NETRootInfo &rootinfo)
0550 {
0551 #ifdef NETWMDEBUG
0552     fprintf(stderr, "NETRootInfo::NETRootInfo: using copy constructor\n");
0553 #endif
0554 
0555     p = rootinfo.p;
0556 
0557     p->ref++;
0558 }
0559 
0560 // Be gone with our NETRootInfo.
0561 
0562 NETRootInfo::~NETRootInfo()
0563 {
0564     refdec_nri(p);
0565 
0566     if (!p->ref) {
0567         delete p;
0568     }
0569 }
0570 
0571 void NETRootInfo::setDefaultProperties()
0572 {
0573     p->properties = Supported | SupportingWMCheck;
0574     p->windowTypes = NormalMask | DesktopMask | DockMask | ToolbarMask | MenuMask | DialogMask;
0575     p->states = Modal | Sticky | MaxVert | MaxHoriz | Shaded | SkipTaskbar | KeepAbove;
0576     p->properties2 = NET::Properties2();
0577     p->actions = NET::Actions();
0578     p->clientProperties = NET::Properties();
0579     p->clientProperties2 = NET::Properties2();
0580 }
0581 
0582 void NETRootInfo::activate()
0583 {
0584     if (p->role == WindowManager) {
0585 #ifdef NETWMDEBUG
0586         fprintf(stderr, "NETRootInfo::activate: setting supported properties on root\n");
0587 #endif
0588 
0589         setSupported();
0590         update(p->clientProperties, p->clientProperties2);
0591     } else {
0592 #ifdef NETWMDEBUG
0593         fprintf(stderr, "NETRootInfo::activate: updating client information\n");
0594 #endif
0595 
0596         update(p->clientProperties, p->clientProperties2);
0597     }
0598 }
0599 
0600 void NETRootInfo::setClientList(const xcb_window_t *windows, unsigned int count)
0601 {
0602     if (p->role != WindowManager) {
0603         return;
0604     }
0605 
0606     p->clients_count = count;
0607 
0608     delete[] p->clients;
0609     p->clients = nwindup(windows, count);
0610 
0611 #ifdef NETWMDEBUG
0612     fprintf(stderr, "NETRootInfo::setClientList: setting list with %ld windows\n", p->clients_count);
0613 #endif
0614 
0615     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->root, p->atom(_NET_CLIENT_LIST), XCB_ATOM_WINDOW, 32, p->clients_count, (const void *)windows);
0616 }
0617 
0618 void NETRootInfo::setClientListStacking(const xcb_window_t *windows, unsigned int count)
0619 {
0620     if (p->role != WindowManager) {
0621         return;
0622     }
0623 
0624     p->stacking_count = count;
0625     delete[] p->stacking;
0626     p->stacking = nwindup(windows, count);
0627 
0628 #ifdef NETWMDEBUG
0629     fprintf(stderr, "NETRootInfo::setClientListStacking: setting list with %ld windows\n", p->clients_count);
0630 #endif
0631 
0632     xcb_change_property(p->conn,
0633                         XCB_PROP_MODE_REPLACE,
0634                         p->root,
0635                         p->atom(_NET_CLIENT_LIST_STACKING),
0636                         XCB_ATOM_WINDOW,
0637                         32,
0638                         p->stacking_count,
0639                         (const void *)windows);
0640 }
0641 
0642 void NETRootInfo::setNumberOfDesktops(int numberOfDesktops)
0643 {
0644 #ifdef NETWMDEBUG
0645     fprintf(stderr, "NETRootInfo::setNumberOfDesktops: setting desktop count to %d (%s)\n", numberOfDesktops, (p->role == WindowManager) ? "WM" : "Client");
0646 #endif
0647 
0648     if (p->role == WindowManager) {
0649         p->number_of_desktops = numberOfDesktops;
0650         const uint32_t d = numberOfDesktops;
0651         xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->root, p->atom(_NET_NUMBER_OF_DESKTOPS), XCB_ATOM_CARDINAL, 32, 1, (const void *)&d);
0652     } else {
0653         const uint32_t data[5] = {uint32_t(numberOfDesktops), 0, 0, 0, 0};
0654 
0655         send_client_message(p->conn, netwm_sendevent_mask, p->root, p->root, p->atom(_NET_NUMBER_OF_DESKTOPS), data);
0656     }
0657 }
0658 
0659 void NETRootInfo::setCurrentDesktop(int desktop, bool ignore_viewport)
0660 {
0661 #ifdef NETWMDEBUG
0662     fprintf(stderr, "NETRootInfo::setCurrentDesktop: setting current desktop = %d (%s)\n", desktop, (p->role == WindowManager) ? "WM" : "Client");
0663 #endif
0664 
0665     if (p->role == WindowManager) {
0666         p->current_desktop = desktop;
0667         uint32_t d = p->current_desktop - 1;
0668         xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->root, p->atom(_NET_CURRENT_DESKTOP), XCB_ATOM_CARDINAL, 32, 1, (const void *)&d);
0669     } else {
0670         if (!ignore_viewport && KX11Extras::mapViewport()) {
0671             KX11Extras::setCurrentDesktop(desktop);
0672             return;
0673         }
0674 
0675         const uint32_t data[5] = {uint32_t(desktop - 1), 0, 0, 0, 0};
0676 
0677         send_client_message(p->conn, netwm_sendevent_mask, p->root, p->root, p->atom(_NET_CURRENT_DESKTOP), data);
0678     }
0679 }
0680 
0681 void NETRootInfo::setDesktopName(int desktop, const char *desktopName)
0682 {
0683     // Allow setting desktop names even for non-existent desktops, see the spec, sect.3.7.
0684     if (desktop < 1) {
0685         return;
0686     }
0687 
0688     delete[] p->desktop_names[desktop - 1];
0689     p->desktop_names[desktop - 1] = nstrdup(desktopName);
0690 
0691     unsigned int i;
0692     unsigned int proplen;
0693     unsigned int num = ((p->number_of_desktops > p->desktop_names.size()) ? p->number_of_desktops : p->desktop_names.size());
0694     for (i = 0, proplen = 0; i < num; i++) {
0695         proplen += (p->desktop_names[i] != nullptr ? strlen(p->desktop_names[i]) + 1 : 1);
0696     }
0697 
0698     char *prop = new char[proplen];
0699     char *propp = prop;
0700 
0701     for (i = 0; i < num; i++) {
0702         if (p->desktop_names[i]) {
0703             strcpy(propp, p->desktop_names[i]);
0704             propp += strlen(p->desktop_names[i]) + 1;
0705         } else {
0706             *propp++ = '\0';
0707         }
0708     }
0709 
0710 #ifdef NETWMDEBUG
0711     fprintf(stderr,
0712             "NETRootInfo::setDesktopName(%d, '%s')\n"
0713             "NETRootInfo::setDesktopName: total property length = %d",
0714             desktop,
0715             desktopName,
0716             proplen);
0717 #endif
0718 
0719     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->root, p->atom(_NET_DESKTOP_NAMES), p->atom(UTF8_STRING), 8, proplen, (const void *)prop);
0720 
0721     delete[] prop;
0722 }
0723 
0724 void NETRootInfo::setDesktopGeometry(const NETSize &geometry)
0725 {
0726 #ifdef NETWMDEBUG
0727     fprintf(stderr, "NETRootInfo::setDesktopGeometry( -- , { %d, %d }) (%s)\n", geometry.width, geometry.height, (p->role == WindowManager) ? "WM" : "Client");
0728 #endif
0729 
0730     if (p->role == WindowManager) {
0731         p->geometry = geometry;
0732 
0733         uint32_t data[2];
0734         data[0] = p->geometry.width;
0735         data[1] = p->geometry.height;
0736 
0737         xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->root, p->atom(_NET_DESKTOP_GEOMETRY), XCB_ATOM_CARDINAL, 32, 2, (const void *)data);
0738     } else {
0739         uint32_t data[5] = {uint32_t(geometry.width), uint32_t(geometry.height), 0, 0, 0};
0740 
0741         send_client_message(p->conn, netwm_sendevent_mask, p->root, p->root, p->atom(_NET_DESKTOP_GEOMETRY), data);
0742     }
0743 }
0744 
0745 void NETRootInfo::setDesktopViewport(int desktop, const NETPoint &viewport)
0746 {
0747 #ifdef NETWMDEBUG
0748     fprintf(stderr, "NETRootInfo::setDesktopViewport(%d, { %d, %d }) (%s)\n", desktop, viewport.x, viewport.y, (p->role == WindowManager) ? "WM" : "Client");
0749 #endif
0750 
0751     if (desktop < 1) {
0752         return;
0753     }
0754 
0755     if (p->role == WindowManager) {
0756         p->viewport[desktop - 1] = viewport;
0757 
0758         int d;
0759         int i;
0760         int l;
0761         l = p->number_of_desktops * 2;
0762         uint32_t *data = new uint32_t[l];
0763         for (d = 0, i = 0; d < p->number_of_desktops; d++) {
0764             data[i++] = p->viewport[d].x;
0765             data[i++] = p->viewport[d].y;
0766         }
0767 
0768         xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->root, p->atom(_NET_DESKTOP_VIEWPORT), XCB_ATOM_CARDINAL, 32, l, (const void *)data);
0769 
0770         delete[] data;
0771     } else {
0772         const uint32_t data[5] = {uint32_t(viewport.x), uint32_t(viewport.y), 0, 0, 0};
0773 
0774         send_client_message(p->conn, netwm_sendevent_mask, p->root, p->root, p->atom(_NET_DESKTOP_VIEWPORT), data);
0775     }
0776 }
0777 
0778 void NETRootInfo::setSupported()
0779 {
0780     if (p->role != WindowManager) {
0781 #ifdef NETWMDEBUG
0782         fprintf(stderr, "NETRootInfo::setSupported - role != WindowManager\n");
0783 #endif
0784 
0785         return;
0786     }
0787 
0788     xcb_atom_t atoms[KwsAtomCount];
0789     int pnum = 2;
0790 
0791     // Root window properties/messages
0792     atoms[0] = p->atom(_NET_SUPPORTED);
0793     atoms[1] = p->atom(_NET_SUPPORTING_WM_CHECK);
0794 
0795     if (p->properties & ClientList) {
0796         atoms[pnum++] = p->atom(_NET_CLIENT_LIST);
0797     }
0798 
0799     if (p->properties & ClientListStacking) {
0800         atoms[pnum++] = p->atom(_NET_CLIENT_LIST_STACKING);
0801     }
0802 
0803     if (p->properties & NumberOfDesktops) {
0804         atoms[pnum++] = p->atom(_NET_NUMBER_OF_DESKTOPS);
0805     }
0806 
0807     if (p->properties & DesktopGeometry) {
0808         atoms[pnum++] = p->atom(_NET_DESKTOP_GEOMETRY);
0809     }
0810 
0811     if (p->properties & DesktopViewport) {
0812         atoms[pnum++] = p->atom(_NET_DESKTOP_VIEWPORT);
0813     }
0814 
0815     if (p->properties & CurrentDesktop) {
0816         atoms[pnum++] = p->atom(_NET_CURRENT_DESKTOP);
0817     }
0818 
0819     if (p->properties & DesktopNames) {
0820         atoms[pnum++] = p->atom(_NET_DESKTOP_NAMES);
0821     }
0822 
0823     if (p->properties & ActiveWindow) {
0824         atoms[pnum++] = p->atom(_NET_ACTIVE_WINDOW);
0825     }
0826 
0827     if (p->properties & WorkArea) {
0828         atoms[pnum++] = p->atom(_NET_WORKAREA);
0829     }
0830 
0831     if (p->properties & VirtualRoots) {
0832         atoms[pnum++] = p->atom(_NET_VIRTUAL_ROOTS);
0833     }
0834 
0835     if (p->properties2 & WM2DesktopLayout) {
0836         atoms[pnum++] = p->atom(_NET_DESKTOP_LAYOUT);
0837     }
0838 
0839     if (p->properties & CloseWindow) {
0840         atoms[pnum++] = p->atom(_NET_CLOSE_WINDOW);
0841     }
0842 
0843     if (p->properties2 & WM2RestackWindow) {
0844         atoms[pnum++] = p->atom(_NET_RESTACK_WINDOW);
0845     }
0846 
0847     if (p->properties2 & WM2ShowingDesktop) {
0848         atoms[pnum++] = p->atom(_NET_SHOWING_DESKTOP);
0849     }
0850 
0851     // Application window properties/messages
0852     if (p->properties & WMMoveResize) {
0853         atoms[pnum++] = p->atom(_NET_WM_MOVERESIZE);
0854     }
0855 
0856     if (p->properties2 & WM2MoveResizeWindow) {
0857         atoms[pnum++] = p->atom(_NET_MOVERESIZE_WINDOW);
0858     }
0859 
0860     if (p->properties & WMName) {
0861         atoms[pnum++] = p->atom(_NET_WM_NAME);
0862     }
0863 
0864     if (p->properties & WMVisibleName) {
0865         atoms[pnum++] = p->atom(_NET_WM_VISIBLE_NAME);
0866     }
0867 
0868     if (p->properties & WMIconName) {
0869         atoms[pnum++] = p->atom(_NET_WM_ICON_NAME);
0870     }
0871 
0872     if (p->properties & WMVisibleIconName) {
0873         atoms[pnum++] = p->atom(_NET_WM_VISIBLE_ICON_NAME);
0874     }
0875 
0876     if (p->properties & WMDesktop) {
0877         atoms[pnum++] = p->atom(_NET_WM_DESKTOP);
0878     }
0879 
0880     if (p->properties & WMWindowType) {
0881         atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE);
0882 
0883         // Application window types
0884         if (p->windowTypes & NormalMask) {
0885             atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE_NORMAL);
0886         }
0887         if (p->windowTypes & DesktopMask) {
0888             atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE_DESKTOP);
0889         }
0890         if (p->windowTypes & DockMask) {
0891             atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE_DOCK);
0892         }
0893         if (p->windowTypes & ToolbarMask) {
0894             atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE_TOOLBAR);
0895         }
0896         if (p->windowTypes & MenuMask) {
0897             atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE_MENU);
0898         }
0899         if (p->windowTypes & DialogMask) {
0900             atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE_DIALOG);
0901         }
0902         if (p->windowTypes & UtilityMask) {
0903             atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE_UTILITY);
0904         }
0905         if (p->windowTypes & SplashMask) {
0906             atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE_SPLASH);
0907         }
0908         if (p->windowTypes & DropdownMenuMask) {
0909             atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU);
0910         }
0911         if (p->windowTypes & PopupMenuMask) {
0912             atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE_POPUP_MENU);
0913         }
0914         if (p->windowTypes & TooltipMask) {
0915             atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE_TOOLTIP);
0916         }
0917         if (p->windowTypes & NotificationMask) {
0918             atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE_NOTIFICATION);
0919         }
0920         if (p->windowTypes & ComboBoxMask) {
0921             atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE_COMBO);
0922         }
0923         if (p->windowTypes & DNDIconMask) {
0924             atoms[pnum++] = p->atom(_NET_WM_WINDOW_TYPE_DND);
0925         }
0926         // KDE extensions
0927         if (p->windowTypes & OverrideMask) {
0928             atoms[pnum++] = p->atom(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE);
0929         }
0930         if (p->windowTypes & TopMenuMask) {
0931             atoms[pnum++] = p->atom(_KDE_NET_WM_WINDOW_TYPE_TOPMENU);
0932         }
0933         if (p->windowTypes & OnScreenDisplayMask) {
0934             atoms[pnum++] = p->atom(_KDE_NET_WM_WINDOW_TYPE_ON_SCREEN_DISPLAY);
0935         }
0936         if (p->windowTypes & CriticalNotificationMask) {
0937             atoms[pnum++] = p->atom(_KDE_NET_WM_WINDOW_TYPE_CRITICAL_NOTIFICATION);
0938         }
0939         if (p->windowTypes & AppletPopupMask) {
0940             atoms[pnum++] = p->atom(_KDE_NET_WM_WINDOW_TYPE_APPLET_POPUP);
0941         }
0942     }
0943 
0944     if (p->properties & WMState) {
0945         atoms[pnum++] = p->atom(_NET_WM_STATE);
0946 
0947         // Application window states
0948         if (p->states & Modal) {
0949             atoms[pnum++] = p->atom(_NET_WM_STATE_MODAL);
0950         }
0951         if (p->states & Sticky) {
0952             atoms[pnum++] = p->atom(_NET_WM_STATE_STICKY);
0953         }
0954         if (p->states & MaxVert) {
0955             atoms[pnum++] = p->atom(_NET_WM_STATE_MAXIMIZED_VERT);
0956         }
0957         if (p->states & MaxHoriz) {
0958             atoms[pnum++] = p->atom(_NET_WM_STATE_MAXIMIZED_HORZ);
0959         }
0960         if (p->states & Shaded) {
0961             atoms[pnum++] = p->atom(_NET_WM_STATE_SHADED);
0962         }
0963         if (p->states & SkipTaskbar) {
0964             atoms[pnum++] = p->atom(_NET_WM_STATE_SKIP_TASKBAR);
0965         }
0966         if (p->states & SkipPager) {
0967             atoms[pnum++] = p->atom(_NET_WM_STATE_SKIP_PAGER);
0968         }
0969         if (p->states & SkipSwitcher) {
0970             atoms[pnum++] = p->atom(_KDE_NET_WM_STATE_SKIP_SWITCHER);
0971         }
0972         if (p->states & Hidden) {
0973             atoms[pnum++] = p->atom(_NET_WM_STATE_HIDDEN);
0974         }
0975         if (p->states & FullScreen) {
0976             atoms[pnum++] = p->atom(_NET_WM_STATE_FULLSCREEN);
0977         }
0978         if (p->states & KeepAbove) {
0979             atoms[pnum++] = p->atom(_NET_WM_STATE_ABOVE);
0980             // deprecated variant
0981             atoms[pnum++] = p->atom(_NET_WM_STATE_STAYS_ON_TOP);
0982         }
0983         if (p->states & KeepBelow) {
0984             atoms[pnum++] = p->atom(_NET_WM_STATE_BELOW);
0985         }
0986         if (p->states & DemandsAttention) {
0987             atoms[pnum++] = p->atom(_NET_WM_STATE_DEMANDS_ATTENTION);
0988         }
0989 
0990         if (p->states & Focused) {
0991             atoms[pnum++] = p->atom(_NET_WM_STATE_FOCUSED);
0992         }
0993     }
0994 
0995     if (p->properties & WMStrut) {
0996         atoms[pnum++] = p->atom(_NET_WM_STRUT);
0997     }
0998 
0999     if (p->properties2 & WM2ExtendedStrut) {
1000         atoms[pnum++] = p->atom(_NET_WM_STRUT_PARTIAL);
1001     }
1002 
1003     if (p->properties & WMIconGeometry) {
1004         atoms[pnum++] = p->atom(_NET_WM_ICON_GEOMETRY);
1005     }
1006 
1007     if (p->properties & WMIcon) {
1008         atoms[pnum++] = p->atom(_NET_WM_ICON);
1009     }
1010 
1011     if (p->properties & WMPid) {
1012         atoms[pnum++] = p->atom(_NET_WM_PID);
1013     }
1014 
1015     if (p->properties & WMHandledIcons) {
1016         atoms[pnum++] = p->atom(_NET_WM_HANDLED_ICONS);
1017     }
1018 
1019     if (p->properties & WMPing) {
1020         atoms[pnum++] = p->atom(_NET_WM_PING);
1021     }
1022 
1023     if (p->properties2 & WM2UserTime) {
1024         atoms[pnum++] = p->atom(_NET_WM_USER_TIME);
1025     }
1026 
1027     if (p->properties2 & WM2StartupId) {
1028         atoms[pnum++] = p->atom(_NET_STARTUP_ID);
1029     }
1030 
1031     if (p->properties2 & WM2Opacity) {
1032         atoms[pnum++] = p->atom(_NET_WM_WINDOW_OPACITY);
1033     }
1034 
1035     if (p->properties2 & WM2FullscreenMonitors) {
1036         atoms[pnum++] = p->atom(_NET_WM_FULLSCREEN_MONITORS);
1037     }
1038 
1039     if (p->properties2 & WM2AllowedActions) {
1040         atoms[pnum++] = p->atom(_NET_WM_ALLOWED_ACTIONS);
1041 
1042         // Actions
1043         if (p->actions & ActionMove) {
1044             atoms[pnum++] = p->atom(_NET_WM_ACTION_MOVE);
1045         }
1046         if (p->actions & ActionResize) {
1047             atoms[pnum++] = p->atom(_NET_WM_ACTION_RESIZE);
1048         }
1049         if (p->actions & ActionMinimize) {
1050             atoms[pnum++] = p->atom(_NET_WM_ACTION_MINIMIZE);
1051         }
1052         if (p->actions & ActionShade) {
1053             atoms[pnum++] = p->atom(_NET_WM_ACTION_SHADE);
1054         }
1055         if (p->actions & ActionStick) {
1056             atoms[pnum++] = p->atom(_NET_WM_ACTION_STICK);
1057         }
1058         if (p->actions & ActionMaxVert) {
1059             atoms[pnum++] = p->atom(_NET_WM_ACTION_MAXIMIZE_VERT);
1060         }
1061         if (p->actions & ActionMaxHoriz) {
1062             atoms[pnum++] = p->atom(_NET_WM_ACTION_MAXIMIZE_HORZ);
1063         }
1064         if (p->actions & ActionFullScreen) {
1065             atoms[pnum++] = p->atom(_NET_WM_ACTION_FULLSCREEN);
1066         }
1067         if (p->actions & ActionChangeDesktop) {
1068             atoms[pnum++] = p->atom(_NET_WM_ACTION_CHANGE_DESKTOP);
1069         }
1070         if (p->actions & ActionClose) {
1071             atoms[pnum++] = p->atom(_NET_WM_ACTION_CLOSE);
1072         }
1073     }
1074 
1075     if (p->properties & WMFrameExtents) {
1076         atoms[pnum++] = p->atom(_NET_FRAME_EXTENTS);
1077         atoms[pnum++] = p->atom(_KDE_NET_WM_FRAME_STRUT);
1078     }
1079 
1080     if (p->properties2 & WM2FrameOverlap) {
1081         atoms[pnum++] = p->atom(_NET_WM_FRAME_OVERLAP);
1082     }
1083 
1084     if (p->properties2 & WM2KDETemporaryRules) {
1085         atoms[pnum++] = p->atom(_KDE_NET_WM_TEMPORARY_RULES);
1086     }
1087     if (p->properties2 & WM2FullPlacement) {
1088         atoms[pnum++] = p->atom(_NET_WM_FULL_PLACEMENT);
1089     }
1090 
1091     if (p->properties2 & WM2Activities) {
1092         atoms[pnum++] = p->atom(_KDE_NET_WM_ACTIVITIES);
1093     }
1094 
1095     if (p->properties2 & WM2BlockCompositing) {
1096         atoms[pnum++] = p->atom(_KDE_NET_WM_BLOCK_COMPOSITING);
1097         atoms[pnum++] = p->atom(_NET_WM_BYPASS_COMPOSITOR);
1098     }
1099 
1100     if (p->properties2 & WM2KDEShadow) {
1101         atoms[pnum++] = p->atom(_KDE_NET_WM_SHADOW);
1102     }
1103 
1104     if (p->properties2 & WM2OpaqueRegion) {
1105         atoms[pnum++] = p->atom(_NET_WM_OPAQUE_REGION);
1106     }
1107 
1108     if (p->properties2 & WM2GTKFrameExtents) {
1109         atoms[pnum++] = p->atom(_GTK_FRAME_EXTENTS);
1110     }
1111 
1112     if (p->properties2 & WM2GTKShowWindowMenu) {
1113         atoms[pnum++] = p->atom(_GTK_SHOW_WINDOW_MENU);
1114     }
1115 
1116     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->root, p->atom(_NET_SUPPORTED), XCB_ATOM_ATOM, 32, pnum, (const void *)atoms);
1117 
1118     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->root, p->atom(_NET_SUPPORTING_WM_CHECK), XCB_ATOM_WINDOW, 32, 1, (const void *)&(p->supportwindow));
1119 
1120 #ifdef NETWMDEBUG
1121     fprintf(stderr,
1122             "NETRootInfo::setSupported: _NET_SUPPORTING_WM_CHECK = 0x%lx on 0x%lx\n"
1123             "                         : _NET_WM_NAME = '%s' on 0x%lx\n",
1124             p->supportwindow,
1125             p->supportwindow,
1126             p->name,
1127             p->supportwindow);
1128 #endif
1129 
1130     xcb_change_property(p->conn,
1131                         XCB_PROP_MODE_REPLACE,
1132                         p->supportwindow,
1133                         p->atom(_NET_SUPPORTING_WM_CHECK),
1134                         XCB_ATOM_WINDOW,
1135                         32,
1136                         1,
1137                         (const void *)&(p->supportwindow));
1138 
1139     xcb_change_property(p->conn,
1140                         XCB_PROP_MODE_REPLACE,
1141                         p->supportwindow,
1142                         p->atom(_NET_WM_NAME),
1143                         p->atom(UTF8_STRING),
1144                         8,
1145                         strlen(p->name),
1146                         (const void *)p->name);
1147 }
1148 
1149 void NETRootInfo::updateSupportedProperties(xcb_atom_t atom)
1150 {
1151     if (atom == p->atom(_NET_SUPPORTED)) {
1152         p->properties |= Supported;
1153     }
1154 
1155     else if (atom == p->atom(_NET_SUPPORTING_WM_CHECK)) {
1156         p->properties |= SupportingWMCheck;
1157     }
1158 
1159     else if (atom == p->atom(_NET_CLIENT_LIST)) {
1160         p->properties |= ClientList;
1161     }
1162 
1163     else if (atom == p->atom(_NET_CLIENT_LIST_STACKING)) {
1164         p->properties |= ClientListStacking;
1165     }
1166 
1167     else if (atom == p->atom(_NET_NUMBER_OF_DESKTOPS)) {
1168         p->properties |= NumberOfDesktops;
1169     }
1170 
1171     else if (atom == p->atom(_NET_DESKTOP_GEOMETRY)) {
1172         p->properties |= DesktopGeometry;
1173     }
1174 
1175     else if (atom == p->atom(_NET_DESKTOP_VIEWPORT)) {
1176         p->properties |= DesktopViewport;
1177     }
1178 
1179     else if (atom == p->atom(_NET_CURRENT_DESKTOP)) {
1180         p->properties |= CurrentDesktop;
1181     }
1182 
1183     else if (atom == p->atom(_NET_DESKTOP_NAMES)) {
1184         p->properties |= DesktopNames;
1185     }
1186 
1187     else if (atom == p->atom(_NET_ACTIVE_WINDOW)) {
1188         p->properties |= ActiveWindow;
1189     }
1190 
1191     else if (atom == p->atom(_NET_WORKAREA)) {
1192         p->properties |= WorkArea;
1193     }
1194 
1195     else if (atom == p->atom(_NET_VIRTUAL_ROOTS)) {
1196         p->properties |= VirtualRoots;
1197     }
1198 
1199     else if (atom == p->atom(_NET_DESKTOP_LAYOUT)) {
1200         p->properties2 |= WM2DesktopLayout;
1201     }
1202 
1203     else if (atom == p->atom(_NET_CLOSE_WINDOW)) {
1204         p->properties |= CloseWindow;
1205     }
1206 
1207     else if (atom == p->atom(_NET_RESTACK_WINDOW)) {
1208         p->properties2 |= WM2RestackWindow;
1209     }
1210 
1211     else if (atom == p->atom(_NET_SHOWING_DESKTOP)) {
1212         p->properties2 |= WM2ShowingDesktop;
1213     }
1214 
1215     // Application window properties/messages
1216     else if (atom == p->atom(_NET_WM_MOVERESIZE)) {
1217         p->properties |= WMMoveResize;
1218     }
1219 
1220     else if (atom == p->atom(_NET_MOVERESIZE_WINDOW)) {
1221         p->properties2 |= WM2MoveResizeWindow;
1222     }
1223 
1224     else if (atom == p->atom(_NET_WM_NAME)) {
1225         p->properties |= WMName;
1226     }
1227 
1228     else if (atom == p->atom(_NET_WM_VISIBLE_NAME)) {
1229         p->properties |= WMVisibleName;
1230     }
1231 
1232     else if (atom == p->atom(_NET_WM_ICON_NAME)) {
1233         p->properties |= WMIconName;
1234     }
1235 
1236     else if (atom == p->atom(_NET_WM_VISIBLE_ICON_NAME)) {
1237         p->properties |= WMVisibleIconName;
1238     }
1239 
1240     else if (atom == p->atom(_NET_WM_DESKTOP)) {
1241         p->properties |= WMDesktop;
1242     }
1243 
1244     else if (atom == p->atom(_NET_WM_WINDOW_TYPE)) {
1245         p->properties |= WMWindowType;
1246     }
1247 
1248     // Application window types
1249     else if (atom == p->atom(_NET_WM_WINDOW_TYPE_NORMAL)) {
1250         p->windowTypes |= NormalMask;
1251     } else if (atom == p->atom(_NET_WM_WINDOW_TYPE_DESKTOP)) {
1252         p->windowTypes |= DesktopMask;
1253     } else if (atom == p->atom(_NET_WM_WINDOW_TYPE_DOCK)) {
1254         p->windowTypes |= DockMask;
1255     } else if (atom == p->atom(_NET_WM_WINDOW_TYPE_TOOLBAR)) {
1256         p->windowTypes |= ToolbarMask;
1257     } else if (atom == p->atom(_NET_WM_WINDOW_TYPE_MENU)) {
1258         p->windowTypes |= MenuMask;
1259     } else if (atom == p->atom(_NET_WM_WINDOW_TYPE_DIALOG)) {
1260         p->windowTypes |= DialogMask;
1261     } else if (atom == p->atom(_NET_WM_WINDOW_TYPE_UTILITY)) {
1262         p->windowTypes |= UtilityMask;
1263     } else if (atom == p->atom(_NET_WM_WINDOW_TYPE_SPLASH)) {
1264         p->windowTypes |= SplashMask;
1265     } else if (atom == p->atom(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU)) {
1266         p->windowTypes |= DropdownMenuMask;
1267     } else if (atom == p->atom(_NET_WM_WINDOW_TYPE_POPUP_MENU)) {
1268         p->windowTypes |= PopupMenuMask;
1269     } else if (atom == p->atom(_NET_WM_WINDOW_TYPE_TOOLTIP)) {
1270         p->windowTypes |= TooltipMask;
1271     } else if (atom == p->atom(_NET_WM_WINDOW_TYPE_NOTIFICATION)) {
1272         p->windowTypes |= NotificationMask;
1273     } else if (atom == p->atom(_NET_WM_WINDOW_TYPE_COMBO)) {
1274         p->windowTypes |= ComboBoxMask;
1275     } else if (atom == p->atom(_NET_WM_WINDOW_TYPE_DND)) {
1276         p->windowTypes |= DNDIconMask;
1277     }
1278     // KDE extensions
1279     else if (atom == p->atom(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE)) {
1280         p->windowTypes |= OverrideMask;
1281     } else if (atom == p->atom(_KDE_NET_WM_WINDOW_TYPE_TOPMENU)) {
1282         p->windowTypes |= TopMenuMask;
1283     } else if (atom == p->atom(_KDE_NET_WM_WINDOW_TYPE_ON_SCREEN_DISPLAY)) {
1284         p->windowTypes |= OnScreenDisplayMask;
1285     } else if (atom == p->atom(_KDE_NET_WM_WINDOW_TYPE_CRITICAL_NOTIFICATION)) {
1286         p->windowTypes |= CriticalNotificationMask;
1287     } else if (atom == p->atom(_KDE_NET_WM_WINDOW_TYPE_APPLET_POPUP)) {
1288         p->windowTypes |= AppletPopupMask;
1289     }
1290 
1291     else if (atom == p->atom(_NET_WM_STATE)) {
1292         p->properties |= WMState;
1293     }
1294 
1295     // Application window states
1296     else if (atom == p->atom(_NET_WM_STATE_MODAL)) {
1297         p->states |= Modal;
1298     } else if (atom == p->atom(_NET_WM_STATE_STICKY)) {
1299         p->states |= Sticky;
1300     } else if (atom == p->atom(_NET_WM_STATE_MAXIMIZED_VERT)) {
1301         p->states |= MaxVert;
1302     } else if (atom == p->atom(_NET_WM_STATE_MAXIMIZED_HORZ)) {
1303         p->states |= MaxHoriz;
1304     } else if (atom == p->atom(_NET_WM_STATE_SHADED)) {
1305         p->states |= Shaded;
1306     } else if (atom == p->atom(_NET_WM_STATE_SKIP_TASKBAR)) {
1307         p->states |= SkipTaskbar;
1308     } else if (atom == p->atom(_NET_WM_STATE_SKIP_PAGER)) {
1309         p->states |= SkipPager;
1310     } else if (atom == p->atom(_KDE_NET_WM_STATE_SKIP_SWITCHER)) {
1311         p->states |= SkipSwitcher;
1312     } else if (atom == p->atom(_NET_WM_STATE_HIDDEN)) {
1313         p->states |= Hidden;
1314     } else if (atom == p->atom(_NET_WM_STATE_FULLSCREEN)) {
1315         p->states |= FullScreen;
1316     } else if (atom == p->atom(_NET_WM_STATE_ABOVE)) {
1317         p->states |= KeepAbove;
1318     } else if (atom == p->atom(_NET_WM_STATE_BELOW)) {
1319         p->states |= KeepBelow;
1320     } else if (atom == p->atom(_NET_WM_STATE_DEMANDS_ATTENTION)) {
1321         p->states |= DemandsAttention;
1322     } else if (atom == p->atom(_NET_WM_STATE_STAYS_ON_TOP)) {
1323         p->states |= KeepAbove;
1324     } else if (atom == p->atom(_NET_WM_STATE_FOCUSED)) {
1325         p->states |= Focused;
1326     }
1327 
1328     else if (atom == p->atom(_NET_WM_STRUT)) {
1329         p->properties |= WMStrut;
1330     }
1331 
1332     else if (atom == p->atom(_NET_WM_STRUT_PARTIAL)) {
1333         p->properties2 |= WM2ExtendedStrut;
1334     }
1335 
1336     else if (atom == p->atom(_NET_WM_ICON_GEOMETRY)) {
1337         p->properties |= WMIconGeometry;
1338     }
1339 
1340     else if (atom == p->atom(_NET_WM_ICON)) {
1341         p->properties |= WMIcon;
1342     }
1343 
1344     else if (atom == p->atom(_NET_WM_PID)) {
1345         p->properties |= WMPid;
1346     }
1347 
1348     else if (atom == p->atom(_NET_WM_HANDLED_ICONS)) {
1349         p->properties |= WMHandledIcons;
1350     }
1351 
1352     else if (atom == p->atom(_NET_WM_PING)) {
1353         p->properties |= WMPing;
1354     }
1355 
1356     else if (atom == p->atom(_NET_WM_USER_TIME)) {
1357         p->properties2 |= WM2UserTime;
1358     }
1359 
1360     else if (atom == p->atom(_NET_STARTUP_ID)) {
1361         p->properties2 |= WM2StartupId;
1362     }
1363 
1364     else if (atom == p->atom(_NET_WM_WINDOW_OPACITY)) {
1365         p->properties2 |= WM2Opacity;
1366     }
1367 
1368     else if (atom == p->atom(_NET_WM_FULLSCREEN_MONITORS)) {
1369         p->properties2 |= WM2FullscreenMonitors;
1370     }
1371 
1372     else if (atom == p->atom(_NET_WM_ALLOWED_ACTIONS)) {
1373         p->properties2 |= WM2AllowedActions;
1374     }
1375 
1376     // Actions
1377     else if (atom == p->atom(_NET_WM_ACTION_MOVE)) {
1378         p->actions |= ActionMove;
1379     } else if (atom == p->atom(_NET_WM_ACTION_RESIZE)) {
1380         p->actions |= ActionResize;
1381     } else if (atom == p->atom(_NET_WM_ACTION_MINIMIZE)) {
1382         p->actions |= ActionMinimize;
1383     } else if (atom == p->atom(_NET_WM_ACTION_SHADE)) {
1384         p->actions |= ActionShade;
1385     } else if (atom == p->atom(_NET_WM_ACTION_STICK)) {
1386         p->actions |= ActionStick;
1387     } else if (atom == p->atom(_NET_WM_ACTION_MAXIMIZE_VERT)) {
1388         p->actions |= ActionMaxVert;
1389     } else if (atom == p->atom(_NET_WM_ACTION_MAXIMIZE_HORZ)) {
1390         p->actions |= ActionMaxHoriz;
1391     } else if (atom == p->atom(_NET_WM_ACTION_FULLSCREEN)) {
1392         p->actions |= ActionFullScreen;
1393     } else if (atom == p->atom(_NET_WM_ACTION_CHANGE_DESKTOP)) {
1394         p->actions |= ActionChangeDesktop;
1395     } else if (atom == p->atom(_NET_WM_ACTION_CLOSE)) {
1396         p->actions |= ActionClose;
1397     }
1398 
1399     else if (atom == p->atom(_NET_FRAME_EXTENTS)) {
1400         p->properties |= WMFrameExtents;
1401     } else if (atom == p->atom(_KDE_NET_WM_FRAME_STRUT)) {
1402         p->properties |= WMFrameExtents;
1403     } else if (atom == p->atom(_NET_WM_FRAME_OVERLAP)) {
1404         p->properties2 |= WM2FrameOverlap;
1405     }
1406 
1407     else if (atom == p->atom(_KDE_NET_WM_TEMPORARY_RULES)) {
1408         p->properties2 |= WM2KDETemporaryRules;
1409     } else if (atom == p->atom(_NET_WM_FULL_PLACEMENT)) {
1410         p->properties2 |= WM2FullPlacement;
1411     }
1412 
1413     else if (atom == p->atom(_KDE_NET_WM_ACTIVITIES)) {
1414         p->properties2 |= WM2Activities;
1415     }
1416 
1417     else if (atom == p->atom(_KDE_NET_WM_BLOCK_COMPOSITING) || atom == p->atom(_NET_WM_BYPASS_COMPOSITOR)) {
1418         p->properties2 |= WM2BlockCompositing;
1419     }
1420 
1421     else if (atom == p->atom(_KDE_NET_WM_SHADOW)) {
1422         p->properties2 |= WM2KDEShadow;
1423     }
1424 
1425     else if (atom == p->atom(_NET_WM_OPAQUE_REGION)) {
1426         p->properties2 |= WM2OpaqueRegion;
1427     }
1428 
1429     else if (atom == p->atom(_GTK_FRAME_EXTENTS)) {
1430         p->properties2 |= WM2GTKFrameExtents;
1431     }
1432 
1433     else if (atom == p->atom(_GTK_SHOW_WINDOW_MENU)) {
1434         p->properties2 |= WM2GTKShowWindowMenu;
1435     }
1436 
1437     else if (atom == p->atom(_KDE_NET_WM_APPMENU_OBJECT_PATH)) {
1438         p->properties2 |= WM2AppMenuObjectPath;
1439     }
1440 
1441     else if (atom == p->atom(_KDE_NET_WM_APPMENU_SERVICE_NAME)) {
1442         p->properties2 |= WM2AppMenuServiceName;
1443     }
1444 }
1445 
1446 void NETRootInfo::setActiveWindow(xcb_window_t window)
1447 {
1448     setActiveWindow(window, FromUnknown, QX11Info::appUserTime(), XCB_WINDOW_NONE);
1449 }
1450 
1451 void NETRootInfo::setActiveWindow(xcb_window_t window, NET::RequestSource src, xcb_timestamp_t timestamp, xcb_window_t active_window)
1452 {
1453 #ifdef NETWMDEBUG
1454     fprintf(stderr, "NETRootInfo::setActiveWindow(0x%lx) (%s)\n", window, (p->role == WindowManager) ? "WM" : "Client");
1455 #endif
1456 
1457     if (p->role == WindowManager) {
1458         p->active = window;
1459 
1460         xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->root, p->atom(_NET_ACTIVE_WINDOW), XCB_ATOM_WINDOW, 32, 1, (const void *)&(p->active));
1461     } else {
1462         const uint32_t data[5] = {src, timestamp, active_window, 0, 0};
1463 
1464         send_client_message(p->conn, netwm_sendevent_mask, p->root, window, p->atom(_NET_ACTIVE_WINDOW), data);
1465     }
1466 }
1467 
1468 void NETRootInfo::setWorkArea(int desktop, const NETRect &workarea)
1469 {
1470 #ifdef NETWMDEBUG
1471     fprintf(stderr,
1472             "NETRootInfo::setWorkArea(%d, { %d, %d, %d, %d }) (%s)\n",
1473             desktop,
1474             workarea.pos.x,
1475             workarea.pos.y,
1476             workarea.size.width,
1477             workarea.size.height,
1478             (p->role == WindowManager) ? "WM" : "Client");
1479 #endif
1480 
1481     if (p->role != WindowManager || desktop < 1) {
1482         return;
1483     }
1484 
1485     p->workarea[desktop - 1] = workarea;
1486 
1487     uint32_t *wa = new uint32_t[p->number_of_desktops * 4];
1488     int i;
1489     int o;
1490     for (i = 0, o = 0; i < p->number_of_desktops; i++) {
1491         wa[o++] = p->workarea[i].pos.x;
1492         wa[o++] = p->workarea[i].pos.y;
1493         wa[o++] = p->workarea[i].size.width;
1494         wa[o++] = p->workarea[i].size.height;
1495     }
1496 
1497     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->root, p->atom(_NET_WORKAREA), XCB_ATOM_CARDINAL, 32, p->number_of_desktops * 4, (const void *)wa);
1498 
1499     delete[] wa;
1500 }
1501 
1502 void NETRootInfo::setVirtualRoots(const xcb_window_t *windows, unsigned int count)
1503 {
1504     if (p->role != WindowManager) {
1505         return;
1506     }
1507 
1508     p->virtual_roots_count = count;
1509     delete[] p->virtual_roots;
1510     p->virtual_roots = nwindup(windows, count);
1511 
1512 #ifdef NETWMDEBUG
1513     fprintf(stderr, "NETRootInfo::setVirtualRoots: setting list with %ld windows\n", p->virtual_roots_count);
1514 #endif
1515 
1516     xcb_change_property(p->conn,
1517                         XCB_PROP_MODE_REPLACE,
1518                         p->root,
1519                         p->atom(_NET_VIRTUAL_ROOTS),
1520                         XCB_ATOM_WINDOW,
1521                         32,
1522                         p->virtual_roots_count,
1523                         (const void *)windows);
1524 }
1525 
1526 void NETRootInfo::setDesktopLayout(NET::Orientation orientation, int columns, int rows, NET::DesktopLayoutCorner corner)
1527 {
1528     p->desktop_layout_orientation = orientation;
1529     p->desktop_layout_columns = columns;
1530     p->desktop_layout_rows = rows;
1531     p->desktop_layout_corner = corner;
1532 
1533 #ifdef NETWMDEBUG
1534     fprintf(stderr, "NETRootInfo::setDesktopLayout: %d %d %d %d\n", orientation, columns, rows, corner);
1535 #endif
1536 
1537     uint32_t data[4];
1538     data[0] = orientation;
1539     data[1] = columns;
1540     data[2] = rows;
1541     data[3] = corner;
1542 
1543     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->root, p->atom(_NET_DESKTOP_LAYOUT), XCB_ATOM_CARDINAL, 32, 4, (const void *)data);
1544 }
1545 
1546 void NETRootInfo::setShowingDesktop(bool showing)
1547 {
1548     if (p->role == WindowManager) {
1549         uint32_t d = p->showing_desktop = showing;
1550         xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->root, p->atom(_NET_SHOWING_DESKTOP), XCB_ATOM_CARDINAL, 32, 1, (const void *)&d);
1551     } else {
1552         uint32_t data[5] = {uint32_t(showing ? 1 : 0), 0, 0, 0, 0};
1553         send_client_message(p->conn, netwm_sendevent_mask, p->root, p->root, p->atom(_NET_SHOWING_DESKTOP), data);
1554     }
1555 }
1556 
1557 bool NETRootInfo::showingDesktop() const
1558 {
1559     return p->showing_desktop;
1560 }
1561 
1562 void NETRootInfo::closeWindowRequest(xcb_window_t window)
1563 {
1564 #ifdef NETWMDEBUG
1565     fprintf(stderr, "NETRootInfo::closeWindowRequest: requesting close for 0x%lx\n", window);
1566 #endif
1567 
1568     const uint32_t data[5] = {0, 0, 0, 0, 0};
1569     send_client_message(p->conn, netwm_sendevent_mask, p->root, window, p->atom(_NET_CLOSE_WINDOW), data);
1570 }
1571 
1572 void NETRootInfo::moveResizeRequest(xcb_window_t window, int x_root, int y_root, Direction direction)
1573 {
1574 #ifdef NETWMDEBUG
1575     fprintf(stderr, "NETRootInfo::moveResizeRequest: requesting resize/move for 0x%lx (%d, %d, %d)\n", window, x_root, y_root, direction);
1576 #endif
1577 
1578     const uint32_t data[5] = {uint32_t(x_root), uint32_t(y_root), uint32_t(direction), 0, 0};
1579 
1580     send_client_message(p->conn, netwm_sendevent_mask, p->root, window, p->atom(_NET_WM_MOVERESIZE), data);
1581 }
1582 
1583 void NETRootInfo::moveResizeWindowRequest(xcb_window_t window, int flags, int x, int y, int width, int height)
1584 {
1585 #ifdef NETWMDEBUG
1586     fprintf(stderr, "NETRootInfo::moveResizeWindowRequest: resizing/moving 0x%lx (%d, %d, %d, %d, %d)\n", window, flags, x, y, width, height);
1587 #endif
1588 
1589     const uint32_t data[5] = {uint32_t(flags), uint32_t(x), uint32_t(y), uint32_t(width), uint32_t(height)};
1590 
1591     send_client_message(p->conn, netwm_sendevent_mask, p->root, window, p->atom(_NET_MOVERESIZE_WINDOW), data);
1592 }
1593 
1594 void NETRootInfo::showWindowMenuRequest(xcb_window_t window, int device_id, int x_root, int y_root)
1595 {
1596 #ifdef NETWMDEBUG
1597     fprintf(stderr, "NETRootInfo::showWindowMenuRequest: requesting menu for 0x%lx (%d, %d, %d)\n", window, device_id, x_root, y_root);
1598 #endif
1599 
1600     const uint32_t data[5] = {uint32_t(device_id), uint32_t(x_root), uint32_t(y_root), 0, 0};
1601     send_client_message(p->conn, netwm_sendevent_mask, p->root, window, p->atom(_GTK_SHOW_WINDOW_MENU), data);
1602 }
1603 
1604 void NETRootInfo::restackRequest(xcb_window_t window, RequestSource src, xcb_window_t above, int detail, xcb_timestamp_t timestamp)
1605 {
1606 #ifdef NETWMDEBUG
1607     fprintf(stderr, "NETRootInfo::restackRequest: requesting restack for 0x%lx (%lx, %d)\n", window, above, detail);
1608 #endif
1609 
1610     const uint32_t data[5] = {uint32_t(src), uint32_t(above), uint32_t(detail), uint32_t(timestamp), 0};
1611 
1612     send_client_message(p->conn, netwm_sendevent_mask, p->root, window, p->atom(_NET_RESTACK_WINDOW), data);
1613 }
1614 
1615 void NETRootInfo::sendPing(xcb_window_t window, xcb_timestamp_t timestamp)
1616 {
1617     if (p->role != WindowManager) {
1618         return;
1619     }
1620 
1621 #ifdef NETWMDEBUG
1622     fprintf(stderr, "NETRootInfo::setPing: window 0x%lx, timestamp %lu\n", window, timestamp);
1623 #endif
1624 
1625     const uint32_t data[5] = {p->atom(_NET_WM_PING), timestamp, window, 0, 0};
1626 
1627     send_client_message(p->conn, 0, window, window, p->atom(WM_PROTOCOLS), data);
1628 }
1629 
1630 // assignment operator
1631 
1632 const NETRootInfo &NETRootInfo::operator=(const NETRootInfo &rootinfo)
1633 {
1634 #ifdef NETWMDEBUG
1635     fprintf(stderr, "NETRootInfo::operator=()\n");
1636 #endif
1637 
1638     if (p != rootinfo.p) {
1639         refdec_nri(p);
1640 
1641         if (!p->ref) {
1642             delete p;
1643         }
1644     }
1645 
1646     p = rootinfo.p;
1647     p->ref++;
1648 
1649     return *this;
1650 }
1651 
1652 NET::Properties NETRootInfo::event(xcb_generic_event_t *ev)
1653 {
1654     NET::Properties props;
1655     event(ev, &props);
1656     return props;
1657 }
1658 
1659 void NETRootInfo::event(xcb_generic_event_t *event, NET::Properties *properties, NET::Properties2 *properties2)
1660 {
1661     NET::Properties dirty;
1662     NET::Properties2 dirty2;
1663     bool do_update = false;
1664     const uint8_t eventType = event->response_type & ~0x80;
1665 
1666     // the window manager will be interested in client messages... no other
1667     // client should get these messages
1668     if (p->role == WindowManager && eventType == XCB_CLIENT_MESSAGE && reinterpret_cast<xcb_client_message_event_t *>(event)->format == 32) {
1669         xcb_client_message_event_t *message = reinterpret_cast<xcb_client_message_event_t *>(event);
1670 #ifdef NETWMDEBUG
1671         fprintf(stderr, "NETRootInfo::event: handling ClientMessage event\n");
1672 #endif
1673 
1674         if (message->type == p->atom(_NET_NUMBER_OF_DESKTOPS)) {
1675             dirty = NumberOfDesktops;
1676 
1677 #ifdef NETWMDEBUG
1678             fprintf(stderr, "NETRootInfo::event: changeNumberOfDesktops(%ld)\n", message->data.data32[0]);
1679 #endif
1680 
1681             changeNumberOfDesktops(message->data.data32[0]);
1682         } else if (message->type == p->atom(_NET_DESKTOP_GEOMETRY)) {
1683             dirty = DesktopGeometry;
1684 
1685             NETSize sz;
1686             sz.width = message->data.data32[0];
1687             sz.height = message->data.data32[1];
1688 
1689 #ifdef NETWMDEBUG
1690             fprintf(stderr, "NETRootInfo::event: changeDesktopGeometry( -- , { %d, %d })\n", sz.width, sz.height);
1691 #endif
1692 
1693             changeDesktopGeometry(~0, sz);
1694         } else if (message->type == p->atom(_NET_DESKTOP_VIEWPORT)) {
1695             dirty = DesktopViewport;
1696 
1697             NETPoint pt;
1698             pt.x = message->data.data32[0];
1699             pt.y = message->data.data32[1];
1700 
1701 #ifdef NETWMDEBUG
1702             fprintf(stderr, "NETRootInfo::event: changeDesktopViewport(%d, { %d, %d })\n", p->current_desktop, pt.x, pt.y);
1703 #endif
1704 
1705             changeDesktopViewport(p->current_desktop, pt);
1706         } else if (message->type == p->atom(_NET_CURRENT_DESKTOP)) {
1707             dirty = CurrentDesktop;
1708 
1709 #ifdef NETWMDEBUG
1710             fprintf(stderr, "NETRootInfo::event: changeCurrentDesktop(%ld)\n", message->data.data32[0] + 1);
1711 #endif
1712 
1713             changeCurrentDesktop(message->data.data32[0] + 1);
1714         } else if (message->type == p->atom(_NET_ACTIVE_WINDOW)) {
1715             dirty = ActiveWindow;
1716 
1717 #ifdef NETWMDEBUG
1718             fprintf(stderr, "NETRootInfo::event: changeActiveWindow(0x%lx)\n", message->window);
1719 #endif
1720 
1721             RequestSource src = FromUnknown;
1722             xcb_timestamp_t timestamp = XCB_TIME_CURRENT_TIME;
1723             xcb_window_t active_window = XCB_WINDOW_NONE;
1724             // make sure there aren't unknown values
1725             if (message->data.data32[0] >= FromUnknown && message->data.data32[0] <= FromTool) {
1726                 src = static_cast<RequestSource>(message->data.data32[0]);
1727                 timestamp = message->data.data32[1];
1728                 active_window = message->data.data32[2];
1729             }
1730             changeActiveWindow(message->window, src, timestamp, active_window);
1731         } else if (message->type == p->atom(_NET_WM_MOVERESIZE)) {
1732 #ifdef NETWMDEBUG
1733             fprintf(stderr,
1734                     "NETRootInfo::event: moveResize(%ld, %ld, %ld, %ld)\n",
1735                     message->window,
1736                     message->data.data32[0],
1737                     message->data.data32[1],
1738                     message->data.data32[2]);
1739 #endif
1740 
1741             moveResize(message->window, message->data.data32[0], message->data.data32[1], message->data.data32[2]);
1742         } else if (message->type == p->atom(_NET_MOVERESIZE_WINDOW)) {
1743 #ifdef NETWMDEBUG
1744             fprintf(stderr,
1745                     "NETRootInfo::event: moveResizeWindow(%ld, %ld, %ld, %ld, %ld, %ld)\n",
1746                     message->window,
1747                     message->data.data32[0],
1748                     message->data.data32[1],
1749                     message->data.data32[2],
1750                     message->data.data32[3],
1751                     message->data.data32[4]);
1752 #endif
1753 
1754             moveResizeWindow(message->window,
1755                              message->data.data32[0],
1756                              message->data.data32[1],
1757                              message->data.data32[2],
1758                              message->data.data32[3],
1759                              message->data.data32[4]);
1760         } else if (message->type == p->atom(_NET_CLOSE_WINDOW)) {
1761 #ifdef NETWMDEBUG
1762             fprintf(stderr, "NETRootInfo::event: closeWindow(0x%lx)\n", message->window);
1763 #endif
1764 
1765             closeWindow(message->window);
1766         } else if (message->type == p->atom(_NET_RESTACK_WINDOW)) {
1767 #ifdef NETWMDEBUG
1768             fprintf(stderr, "NETRootInfo::event: restackWindow(0x%lx)\n", message->window);
1769 #endif
1770 
1771             RequestSource src = FromUnknown;
1772             xcb_timestamp_t timestamp = XCB_TIME_CURRENT_TIME;
1773             // make sure there aren't unknown values
1774             if (message->data.data32[0] >= FromUnknown && message->data.data32[0] <= FromTool) {
1775                 src = static_cast<RequestSource>(message->data.data32[0]);
1776                 timestamp = message->data.data32[3];
1777             }
1778             restackWindow(message->window, src, message->data.data32[1], message->data.data32[2], timestamp);
1779         } else if (message->type == p->atom(WM_PROTOCOLS) && (xcb_atom_t)message->data.data32[0] == p->atom(_NET_WM_PING)) {
1780             dirty = WMPing;
1781 
1782 #ifdef NETWMDEBUG
1783             fprintf(stderr, "NETRootInfo::event: gotPing(0x%lx,%lu)\n", message->window, message->data.data32[1]);
1784 #endif
1785             gotPing(message->data.data32[2], message->data.data32[1]);
1786         } else if (message->type == p->atom(_NET_SHOWING_DESKTOP)) {
1787             dirty2 = WM2ShowingDesktop;
1788 
1789 #ifdef NETWMDEBUG
1790             fprintf(stderr, "NETRootInfo::event: changeShowingDesktop(%ld)\n", message->data.data32[0]);
1791 #endif
1792 
1793             changeShowingDesktop(message->data.data32[0]);
1794         } else if (message->type == p->atom(_GTK_SHOW_WINDOW_MENU)) {
1795 #ifdef NETWMDEBUG
1796             fprintf(stderr,
1797                     "NETRootInfo::event: showWindowMenu(%ld, %ld, %ld, %ld)\n",
1798                     message->window,
1799                     message->data.data32[0],
1800                     message->data.data32[1],
1801                     message->data.data32[2]);
1802 #endif
1803 
1804             showWindowMenu(message->window, message->data.data32[0], message->data.data32[1], message->data.data32[2]);
1805         }
1806     }
1807 
1808     if (eventType == XCB_PROPERTY_NOTIFY) {
1809 #ifdef NETWMDEBUG
1810         fprintf(stderr, "NETRootInfo::event: handling PropertyNotify event\n");
1811 #endif
1812 
1813         xcb_property_notify_event_t *pe = reinterpret_cast<xcb_property_notify_event_t *>(event);
1814         if (pe->atom == p->atom(_NET_CLIENT_LIST)) {
1815             dirty |= ClientList;
1816         } else if (pe->atom == p->atom(_NET_CLIENT_LIST_STACKING)) {
1817             dirty |= ClientListStacking;
1818         } else if (pe->atom == p->atom(_NET_DESKTOP_NAMES)) {
1819             dirty |= DesktopNames;
1820         } else if (pe->atom == p->atom(_NET_WORKAREA)) {
1821             dirty |= WorkArea;
1822         } else if (pe->atom == p->atom(_NET_NUMBER_OF_DESKTOPS)) {
1823             dirty |= NumberOfDesktops;
1824         } else if (pe->atom == p->atom(_NET_DESKTOP_GEOMETRY)) {
1825             dirty |= DesktopGeometry;
1826         } else if (pe->atom == p->atom(_NET_DESKTOP_VIEWPORT)) {
1827             dirty |= DesktopViewport;
1828         } else if (pe->atom == p->atom(_NET_CURRENT_DESKTOP)) {
1829             dirty |= CurrentDesktop;
1830         } else if (pe->atom == p->atom(_NET_ACTIVE_WINDOW)) {
1831             dirty |= ActiveWindow;
1832         } else if (pe->atom == p->atom(_NET_SHOWING_DESKTOP)) {
1833             dirty2 |= WM2ShowingDesktop;
1834         } else if (pe->atom == p->atom(_NET_SUPPORTED)) {
1835             dirty |= Supported; // update here?
1836         } else if (pe->atom == p->atom(_NET_SUPPORTING_WM_CHECK)) {
1837             dirty |= SupportingWMCheck;
1838         } else if (pe->atom == p->atom(_NET_VIRTUAL_ROOTS)) {
1839             dirty |= VirtualRoots;
1840         } else if (pe->atom == p->atom(_NET_DESKTOP_LAYOUT)) {
1841             dirty2 |= WM2DesktopLayout;
1842         }
1843 
1844         do_update = true;
1845     }
1846 
1847     if (do_update) {
1848         update(dirty, dirty2);
1849     }
1850 
1851 #ifdef NETWMDEBUG
1852     fprintf(stderr, "NETRootInfo::event: handled events, returning dirty = 0x%lx, 0x%lx\n", dirty, dirty2);
1853 #endif
1854 
1855     if (properties) {
1856         *properties = dirty;
1857     }
1858     if (properties2) {
1859         *properties2 = dirty2;
1860     }
1861 }
1862 
1863 // private functions to update the data we keep
1864 
1865 void NETRootInfo::update(NET::Properties properties, NET::Properties2 properties2)
1866 {
1867     NET::Properties dirty = properties & p->clientProperties;
1868     NET::Properties2 dirty2 = properties2 & p->clientProperties2;
1869 
1870     xcb_get_property_cookie_t cookies[255];
1871     xcb_get_property_cookie_t wm_name_cookie;
1872     int c = 0;
1873 
1874     // Send the property requests
1875     if (dirty & Supported) {
1876         cookies[c++] = xcb_get_property(p->conn, false, p->root, p->atom(_NET_SUPPORTED), XCB_ATOM_ATOM, 0, MAX_PROP_SIZE);
1877     }
1878 
1879     if (dirty & ClientList) {
1880         cookies[c++] = xcb_get_property(p->conn, false, p->root, p->atom(_NET_CLIENT_LIST), XCB_ATOM_WINDOW, 0, MAX_PROP_SIZE);
1881     }
1882 
1883     if (dirty & ClientListStacking) {
1884         cookies[c++] = xcb_get_property(p->conn, false, p->root, p->atom(_NET_CLIENT_LIST_STACKING), XCB_ATOM_WINDOW, 0, MAX_PROP_SIZE);
1885     }
1886 
1887     if (dirty & NumberOfDesktops) {
1888         cookies[c++] = xcb_get_property(p->conn, false, p->root, p->atom(_NET_NUMBER_OF_DESKTOPS), XCB_ATOM_CARDINAL, 0, 1);
1889     }
1890 
1891     if (dirty & DesktopGeometry) {
1892         cookies[c++] = xcb_get_property(p->conn, false, p->root, p->atom(_NET_DESKTOP_GEOMETRY), XCB_ATOM_CARDINAL, 0, 2);
1893     }
1894 
1895     if (dirty & DesktopViewport) {
1896         cookies[c++] = xcb_get_property(p->conn, false, p->root, p->atom(_NET_DESKTOP_VIEWPORT), XCB_ATOM_CARDINAL, 0, MAX_PROP_SIZE);
1897     }
1898 
1899     if (dirty & CurrentDesktop) {
1900         cookies[c++] = xcb_get_property(p->conn, false, p->root, p->atom(_NET_CURRENT_DESKTOP), XCB_ATOM_CARDINAL, 0, 1);
1901     }
1902 
1903     if (dirty & DesktopNames) {
1904         cookies[c++] = xcb_get_property(p->conn, false, p->root, p->atom(_NET_DESKTOP_NAMES), p->atom(UTF8_STRING), 0, MAX_PROP_SIZE);
1905     }
1906 
1907     if (dirty & ActiveWindow) {
1908         cookies[c++] = xcb_get_property(p->conn, false, p->root, p->atom(_NET_ACTIVE_WINDOW), XCB_ATOM_WINDOW, 0, 1);
1909     }
1910 
1911     if (dirty & WorkArea) {
1912         cookies[c++] = xcb_get_property(p->conn, false, p->root, p->atom(_NET_WORKAREA), XCB_ATOM_CARDINAL, 0, MAX_PROP_SIZE);
1913     }
1914 
1915     if (dirty & SupportingWMCheck) {
1916         cookies[c++] = xcb_get_property(p->conn, false, p->root, p->atom(_NET_SUPPORTING_WM_CHECK), XCB_ATOM_WINDOW, 0, 1);
1917     }
1918 
1919     if (dirty & VirtualRoots) {
1920         cookies[c++] = xcb_get_property(p->conn, false, p->root, p->atom(_NET_VIRTUAL_ROOTS), XCB_ATOM_WINDOW, 0, 1);
1921     }
1922 
1923     if (dirty2 & WM2DesktopLayout) {
1924         cookies[c++] = xcb_get_property(p->conn, false, p->root, p->atom(_NET_DESKTOP_LAYOUT), XCB_ATOM_CARDINAL, 0, MAX_PROP_SIZE);
1925     }
1926 
1927     if (dirty2 & WM2ShowingDesktop) {
1928         cookies[c++] = xcb_get_property(p->conn, false, p->root, p->atom(_NET_SHOWING_DESKTOP), XCB_ATOM_CARDINAL, 0, 1);
1929     }
1930 
1931     // Get the replies
1932     c = 0;
1933 
1934     if (dirty & Supported) {
1935         // Only in Client mode
1936         p->properties = NET::Properties();
1937         p->properties2 = NET::Properties2();
1938         p->windowTypes = NET::WindowTypes();
1939         p->states = NET::States();
1940         p->actions = NET::Actions();
1941 
1942         const QList<xcb_atom_t> atoms = get_array_reply<xcb_atom_t>(p->conn, cookies[c++], XCB_ATOM_ATOM);
1943         for (const xcb_atom_t atom : atoms) {
1944             updateSupportedProperties(atom);
1945         }
1946     }
1947 
1948     if (dirty & ClientList) {
1949         QList<xcb_window_t> clientsToRemove;
1950         QList<xcb_window_t> clientsToAdd;
1951 
1952         QList<xcb_window_t> clients = get_array_reply<xcb_window_t>(p->conn, cookies[c++], XCB_ATOM_WINDOW);
1953         std::sort(clients.begin(), clients.end());
1954 
1955         if (p->clients) {
1956             if (p->role == Client) {
1957                 int new_index = 0;
1958                 int old_index = 0;
1959                 int old_count = p->clients_count;
1960                 int new_count = clients.count();
1961 
1962                 while (old_index < old_count || new_index < new_count) {
1963                     if (old_index == old_count) {
1964                         clientsToAdd.append(clients[new_index++]);
1965                     } else if (new_index == new_count) {
1966                         clientsToRemove.append(p->clients[old_index++]);
1967                     } else {
1968                         if (p->clients[old_index] < clients[new_index]) {
1969                             clientsToRemove.append(p->clients[old_index++]);
1970                         } else if (clients[new_index] < p->clients[old_index]) {
1971                             clientsToAdd.append(clients[new_index++]);
1972                         } else {
1973                             new_index++;
1974                             old_index++;
1975                         }
1976                     }
1977                 }
1978             }
1979 
1980             delete[] p->clients;
1981             p->clients = nullptr;
1982         } else {
1983 #ifdef NETWMDEBUG
1984             fprintf(stderr, "NETRootInfo::update: client list null, creating\n");
1985 #endif
1986 
1987             clientsToAdd.reserve(clients.count());
1988             for (int i = 0; i < clients.count(); i++) {
1989                 clientsToAdd.append(clients[i]);
1990             }
1991         }
1992 
1993         if (!clients.isEmpty()) {
1994             p->clients_count = clients.count();
1995             p->clients = new xcb_window_t[clients.count()];
1996             for (int i = 0; i < clients.count(); i++) {
1997                 p->clients[i] = clients.at(i);
1998             }
1999         }
2000 
2001 #ifdef NETWMDEBUG
2002         fprintf(stderr, "NETRootInfo::update: client list updated (%ld clients)\n", p->clients_count);
2003 #endif
2004 
2005         for (int i = 0; i < clientsToRemove.size(); ++i) {
2006             removeClient(clientsToRemove.at(i));
2007         }
2008 
2009         for (int i = 0; i < clientsToAdd.size(); ++i) {
2010             addClient(clientsToAdd.at(i));
2011         }
2012     }
2013 
2014     if (dirty & ClientListStacking) {
2015         p->stacking_count = 0;
2016 
2017         delete[] p->stacking;
2018         p->stacking = nullptr;
2019 
2020         const QList<xcb_window_t> wins = get_array_reply<xcb_window_t>(p->conn, cookies[c++], XCB_ATOM_WINDOW);
2021 
2022         if (!wins.isEmpty()) {
2023             p->stacking_count = wins.count();
2024             p->stacking = new xcb_window_t[wins.count()];
2025             for (int i = 0; i < wins.count(); i++) {
2026                 p->stacking[i] = wins.at(i);
2027             }
2028         }
2029 
2030 #ifdef NETWMDEBUG
2031         fprintf(stderr, "NETRootInfo::update: client stacking updated (%ld clients)\n", p->stacking_count);
2032 #endif
2033     }
2034 
2035     if (dirty & NumberOfDesktops) {
2036         p->number_of_desktops = get_value_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL, 0);
2037 
2038 #ifdef NETWMDEBUG
2039         fprintf(stderr, "NETRootInfo::update: number of desktops = %d\n", p->number_of_desktops);
2040 #endif
2041     }
2042 
2043     if (dirty & DesktopGeometry) {
2044         p->geometry = p->rootSize;
2045 
2046         const QList<uint32_t> data = get_array_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL);
2047         if (data.count() == 2) {
2048             p->geometry.width = data.at(0);
2049             p->geometry.height = data.at(1);
2050         }
2051 
2052 #ifdef NETWMDEBUG
2053         fprintf(stderr, "NETRootInfo::update: desktop geometry updated\n");
2054 #endif
2055     }
2056 
2057     if (dirty & DesktopViewport) {
2058         for (int i = 0; i < p->viewport.size(); i++) {
2059             p->viewport[i].x = p->viewport[i].y = 0;
2060         }
2061 
2062         const QList<uint32_t> data = get_array_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL);
2063 
2064         if (data.count() >= 2) {
2065             int n = data.count() / 2;
2066             for (int d = 0, i = 0; d < n; d++) {
2067                 p->viewport[d].x = data[i++];
2068                 p->viewport[d].y = data[i++];
2069             }
2070 
2071 #ifdef NETWMDEBUG
2072             fprintf(stderr, "NETRootInfo::update: desktop viewport array updated (%d entries)\n", p->viewport.size());
2073 
2074             if (data.count() % 2 != 0) {
2075                 fprintf(stderr,
2076                         "NETRootInfo::update(): desktop viewport array "
2077                         "size not a multiple of 2\n");
2078             }
2079 #endif
2080         }
2081     }
2082 
2083     if (dirty & CurrentDesktop) {
2084         p->current_desktop = get_value_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL, 0) + 1;
2085 
2086 #ifdef NETWMDEBUG
2087         fprintf(stderr, "NETRootInfo::update: current desktop = %d\n", p->current_desktop);
2088 #endif
2089     }
2090 
2091     if (dirty & DesktopNames) {
2092         for (int i = 0; i < p->desktop_names.size(); ++i) {
2093             delete[] p->desktop_names[i];
2094         }
2095 
2096         p->desktop_names.reset();
2097 
2098         const QList<QByteArray> names = get_stringlist_reply(p->conn, cookies[c++], p->atom(UTF8_STRING));
2099         for (int i = 0; i < names.count(); i++) {
2100             p->desktop_names[i] = nstrndup(names[i].constData(), names[i].length());
2101         }
2102 
2103 #ifdef NETWMDEBUG
2104         fprintf(stderr, "NETRootInfo::update: desktop names array updated (%d entries)\n", p->desktop_names.size());
2105 #endif
2106     }
2107 
2108     if (dirty & ActiveWindow) {
2109         p->active = get_value_reply<xcb_window_t>(p->conn, cookies[c++], XCB_ATOM_WINDOW, 0);
2110 
2111 #ifdef NETWMDEBUG
2112         fprintf(stderr, "NETRootInfo::update: active window = 0x%lx\n", p->active);
2113 #endif
2114     }
2115 
2116     if (dirty & WorkArea) {
2117         p->workarea.reset();
2118 
2119         const QList<uint32_t> data = get_array_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL);
2120         if (data.count() == p->number_of_desktops * 4) {
2121             for (int i = 0, j = 0; i < p->number_of_desktops; i++) {
2122                 p->workarea[i].pos.x = data[j++];
2123                 p->workarea[i].pos.y = data[j++];
2124                 p->workarea[i].size.width = data[j++];
2125                 p->workarea[i].size.height = data[j++];
2126             }
2127         }
2128 
2129 #ifdef NETWMDEBUG
2130         fprintf(stderr, "NETRootInfo::update: work area array updated (%d entries)\n", p->workarea.size());
2131 #endif
2132     }
2133 
2134     if (dirty & SupportingWMCheck) {
2135         delete[] p->name;
2136         p->name = nullptr;
2137 
2138         p->supportwindow = get_value_reply<xcb_window_t>(p->conn, cookies[c++], XCB_ATOM_WINDOW, 0);
2139 
2140         // We'll get the reply for this request at the bottom of this function,
2141         // after we've processing the other pending replies
2142         if (p->supportwindow) {
2143             wm_name_cookie = xcb_get_property(p->conn, false, p->supportwindow, p->atom(_NET_WM_NAME), p->atom(UTF8_STRING), 0, MAX_PROP_SIZE);
2144         }
2145     }
2146 
2147     if (dirty & VirtualRoots) {
2148         p->virtual_roots_count = 0;
2149 
2150         delete[] p->virtual_roots;
2151         p->virtual_roots = nullptr;
2152 
2153         const QList<xcb_window_t> wins = get_array_reply<xcb_window_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL);
2154 
2155         if (!wins.isEmpty()) {
2156             p->virtual_roots_count = wins.count();
2157             p->virtual_roots = new xcb_window_t[wins.count()];
2158             for (int i = 0; i < wins.count(); i++) {
2159                 p->virtual_roots[i] = wins.at(i);
2160             }
2161         }
2162 
2163 #ifdef NETWMDEBUG
2164         fprintf(stderr, "NETRootInfo::updated: virtual roots updated (%ld windows)\n", p->virtual_roots_count);
2165 #endif
2166     }
2167 
2168     if (dirty2 & WM2DesktopLayout) {
2169         p->desktop_layout_orientation = OrientationHorizontal;
2170         p->desktop_layout_corner = DesktopLayoutCornerTopLeft;
2171         p->desktop_layout_columns = p->desktop_layout_rows = 0;
2172 
2173         const QList<uint32_t> data = get_array_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL);
2174 
2175         if (data.count() >= 4 && data[3] <= 3) {
2176             p->desktop_layout_corner = (NET::DesktopLayoutCorner)data[3];
2177         }
2178 
2179         if (data.count() >= 3) {
2180             if (data[0] <= 1) {
2181                 p->desktop_layout_orientation = (NET::Orientation)data[0];
2182             }
2183 
2184             p->desktop_layout_columns = data[1];
2185             p->desktop_layout_rows = data[2];
2186         }
2187 
2188 #ifdef NETWMDEBUG
2189         fprintf(stderr,
2190                 "NETRootInfo::updated: desktop layout updated (%d %d %d %d)\n",
2191                 p->desktop_layout_orientation,
2192                 p->desktop_layout_columns,
2193                 p->desktop_layout_rows,
2194                 p->desktop_layout_corner);
2195 #endif
2196     }
2197 
2198     if (dirty2 & WM2ShowingDesktop) {
2199         const uint32_t val = get_value_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL, 0);
2200         p->showing_desktop = bool(val);
2201 
2202 #ifdef NETWMDEBUG
2203         fprintf(stderr, "NETRootInfo::update: showing desktop = %d\n", p->showing_desktop);
2204 #endif
2205     }
2206 
2207     if ((dirty & SupportingWMCheck) && p->supportwindow) {
2208         const QByteArray ba = get_string_reply(p->conn, wm_name_cookie, p->atom(UTF8_STRING));
2209         if (ba.length() > 0) {
2210             p->name = nstrndup((const char *)ba.constData(), ba.length());
2211         }
2212 
2213 #ifdef NETWMDEBUG
2214         fprintf(stderr, "NETRootInfo::update: supporting window manager = '%s'\n", p->name);
2215 #endif
2216     }
2217 }
2218 
2219 xcb_connection_t *NETRootInfo::xcbConnection() const
2220 {
2221     return p->conn;
2222 }
2223 
2224 xcb_window_t NETRootInfo::rootWindow() const
2225 {
2226     return p->root;
2227 }
2228 
2229 xcb_window_t NETRootInfo::supportWindow() const
2230 {
2231     return p->supportwindow;
2232 }
2233 
2234 const char *NETRootInfo::wmName() const
2235 {
2236     return p->name;
2237 }
2238 
2239 NET::Properties NETRootInfo::supportedProperties() const
2240 {
2241     return p->properties;
2242 }
2243 
2244 NET::Properties2 NETRootInfo::supportedProperties2() const
2245 {
2246     return p->properties2;
2247 }
2248 
2249 NET::States NETRootInfo::supportedStates() const
2250 {
2251     return p->states;
2252 }
2253 
2254 NET::WindowTypes NETRootInfo::supportedWindowTypes() const
2255 {
2256     return p->windowTypes;
2257 }
2258 
2259 NET::Actions NETRootInfo::supportedActions() const
2260 {
2261     return p->actions;
2262 }
2263 
2264 NET::Properties NETRootInfo::passedProperties() const
2265 {
2266     return p->role == WindowManager ? p->properties : p->clientProperties;
2267 }
2268 
2269 NET::Properties2 NETRootInfo::passedProperties2() const
2270 {
2271     return p->role == WindowManager ? p->properties2 : p->clientProperties2;
2272 }
2273 
2274 NET::States NETRootInfo::passedStates() const
2275 {
2276     return p->role == WindowManager ? p->states : NET::States();
2277 }
2278 
2279 NET::WindowTypes NETRootInfo::passedWindowTypes() const
2280 {
2281     return p->role == WindowManager ? p->windowTypes : NET::WindowTypes();
2282 }
2283 
2284 NET::Actions NETRootInfo::passedActions() const
2285 {
2286     return p->role == WindowManager ? p->actions : NET::Actions();
2287 }
2288 
2289 void NETRootInfo::setSupported(NET::Property property, bool on)
2290 {
2291     if (p->role != WindowManager) {
2292         return;
2293     }
2294 
2295     if (on && !isSupported(property)) {
2296         p->properties |= property;
2297         setSupported();
2298     } else if (!on && isSupported(property)) {
2299         p->properties &= ~property;
2300         setSupported();
2301     }
2302 }
2303 
2304 void NETRootInfo::setSupported(NET::Property2 property, bool on)
2305 {
2306     if (p->role != WindowManager) {
2307         return;
2308     }
2309 
2310     if (on && !isSupported(property)) {
2311         p->properties2 |= property;
2312         setSupported();
2313     } else if (!on && isSupported(property)) {
2314         p->properties2 &= ~property;
2315         setSupported();
2316     }
2317 }
2318 
2319 void NETRootInfo::setSupported(NET::WindowTypeMask property, bool on)
2320 {
2321     if (p->role != WindowManager) {
2322         return;
2323     }
2324 
2325     if (on && !isSupported(property)) {
2326         p->windowTypes |= property;
2327         setSupported();
2328     } else if (!on && isSupported(property)) {
2329         p->windowTypes &= ~property;
2330         setSupported();
2331     }
2332 }
2333 
2334 void NETRootInfo::setSupported(NET::State property, bool on)
2335 {
2336     if (p->role != WindowManager) {
2337         return;
2338     }
2339 
2340     if (on && !isSupported(property)) {
2341         p->states |= property;
2342         setSupported();
2343     } else if (!on && isSupported(property)) {
2344         p->states &= ~property;
2345         setSupported();
2346     }
2347 }
2348 
2349 void NETRootInfo::setSupported(NET::Action property, bool on)
2350 {
2351     if (p->role != WindowManager) {
2352         return;
2353     }
2354 
2355     if (on && !isSupported(property)) {
2356         p->actions |= property;
2357         setSupported();
2358     } else if (!on && isSupported(property)) {
2359         p->actions &= ~property;
2360         setSupported();
2361     }
2362 }
2363 
2364 bool NETRootInfo::isSupported(NET::Property property) const
2365 {
2366     return p->properties & property;
2367 }
2368 
2369 bool NETRootInfo::isSupported(NET::Property2 property) const
2370 {
2371     return p->properties2 & property;
2372 }
2373 
2374 bool NETRootInfo::isSupported(NET::WindowTypeMask type) const
2375 {
2376     return p->windowTypes & type;
2377 }
2378 
2379 bool NETRootInfo::isSupported(NET::State state) const
2380 {
2381     return p->states & state;
2382 }
2383 
2384 bool NETRootInfo::isSupported(NET::Action action) const
2385 {
2386     return p->actions & action;
2387 }
2388 
2389 const xcb_window_t *NETRootInfo::clientList() const
2390 {
2391     return p->clients;
2392 }
2393 
2394 int NETRootInfo::clientListCount() const
2395 {
2396     return p->clients_count;
2397 }
2398 
2399 const xcb_window_t *NETRootInfo::clientListStacking() const
2400 {
2401     return p->stacking;
2402 }
2403 
2404 int NETRootInfo::clientListStackingCount() const
2405 {
2406     return p->stacking_count;
2407 }
2408 
2409 NETSize NETRootInfo::desktopGeometry() const
2410 {
2411     return p->geometry.width != 0 ? p->geometry : p->rootSize;
2412 }
2413 
2414 NETPoint NETRootInfo::desktopViewport(int desktop) const
2415 {
2416     if (desktop < 1) {
2417         NETPoint pt; // set to (0,0)
2418         return pt;
2419     }
2420 
2421     return p->viewport[desktop - 1];
2422 }
2423 
2424 NETRect NETRootInfo::workArea(int desktop) const
2425 {
2426     if (desktop < 1) {
2427         NETRect rt;
2428         return rt;
2429     }
2430 
2431     return p->workarea[desktop - 1];
2432 }
2433 
2434 const char *NETRootInfo::desktopName(int desktop) const
2435 {
2436     if (desktop < 1) {
2437         return nullptr;
2438     }
2439 
2440     return p->desktop_names[desktop - 1];
2441 }
2442 
2443 const xcb_window_t *NETRootInfo::virtualRoots() const
2444 {
2445     return p->virtual_roots;
2446 }
2447 
2448 int NETRootInfo::virtualRootsCount() const
2449 {
2450     return p->virtual_roots_count;
2451 }
2452 
2453 NET::Orientation NETRootInfo::desktopLayoutOrientation() const
2454 {
2455     return p->desktop_layout_orientation;
2456 }
2457 
2458 QSize NETRootInfo::desktopLayoutColumnsRows() const
2459 {
2460     return QSize(p->desktop_layout_columns, p->desktop_layout_rows);
2461 }
2462 
2463 NET::DesktopLayoutCorner NETRootInfo::desktopLayoutCorner() const
2464 {
2465     return p->desktop_layout_corner;
2466 }
2467 
2468 int NETRootInfo::numberOfDesktops(bool ignore_viewport) const
2469 {
2470     if (!ignore_viewport && KX11Extras::mapViewport()) {
2471         return KX11Extras::numberOfDesktops();
2472     }
2473     return p->number_of_desktops == 0 ? 1 : p->number_of_desktops;
2474 }
2475 
2476 int NETRootInfo::currentDesktop(bool ignore_viewport) const
2477 {
2478     if (!ignore_viewport && KX11Extras::mapViewport()) {
2479         return KX11Extras::currentDesktop();
2480     }
2481     return p->current_desktop == 0 ? 1 : p->current_desktop;
2482 }
2483 
2484 xcb_window_t NETRootInfo::activeWindow() const
2485 {
2486     return p->active;
2487 }
2488 
2489 // NETWinInfo stuffs
2490 
2491 const int NETWinInfo::OnAllDesktops = NET::OnAllDesktops;
2492 
2493 NETWinInfo::NETWinInfo(xcb_connection_t *connection,
2494                        xcb_window_t window,
2495                        xcb_window_t rootWindow,
2496                        NET::Properties properties,
2497                        NET::Properties2 properties2,
2498                        Role role)
2499 {
2500 #ifdef NETWMDEBUG
2501     fprintf(stderr, "NETWinInfo::NETWinInfo: constructing object with role '%s'\n", (role == WindowManager) ? "WindowManager" : "Client");
2502 #endif
2503 
2504     p = new NETWinInfoPrivate;
2505     p->ref = 1;
2506     p->atoms = atomsForConnection(connection);
2507 
2508     p->conn = connection;
2509     p->window = window;
2510     p->root = rootWindow;
2511     p->mapping_state = Withdrawn;
2512     p->mapping_state_dirty = true;
2513     p->state = NET::States();
2514     p->types[0] = Unknown;
2515     p->name = (char *)nullptr;
2516     p->visible_name = (char *)nullptr;
2517     p->icon_name = (char *)nullptr;
2518     p->visible_icon_name = (char *)nullptr;
2519     p->desktop = p->pid = 0;
2520     p->handled_icons = false;
2521     p->user_time = -1U;
2522     p->startup_id = nullptr;
2523     p->transient_for = XCB_NONE;
2524     p->opacity = 0xffffffffU;
2525     p->window_group = XCB_NONE;
2526     p->icon_pixmap = XCB_PIXMAP_NONE;
2527     p->icon_mask = XCB_PIXMAP_NONE;
2528     p->allowed_actions = NET::Actions();
2529     p->has_net_support = false;
2530     p->class_class = (char *)nullptr;
2531     p->class_name = (char *)nullptr;
2532     p->window_role = (char *)nullptr;
2533     p->client_machine = (char *)nullptr;
2534     p->icon_sizes = nullptr;
2535     p->activities = (char *)nullptr;
2536     p->desktop_file = nullptr;
2537     p->gtk_application_id = nullptr;
2538     p->appmenu_object_path = nullptr;
2539     p->appmenu_service_name = nullptr;
2540     p->blockCompositing = false;
2541     p->urgency = false;
2542     p->input = true;
2543     p->initialMappingState = NET::Withdrawn;
2544     p->protocols = NET::NoProtocol;
2545 
2546     // p->strut.left = p->strut.right = p->strut.top = p->strut.bottom = 0;
2547     // p->frame_strut.left = p->frame_strut.right = p->frame_strut.top =
2548     // p->frame_strut.bottom = 0;
2549 
2550     p->properties = properties;
2551     p->properties2 = properties2;
2552 
2553     p->icon_count = 0;
2554 
2555     p->role = role;
2556 
2557     update(p->properties, p->properties2);
2558 }
2559 
2560 NETWinInfo::NETWinInfo(const NETWinInfo &wininfo)
2561 {
2562     p = wininfo.p;
2563     p->ref++;
2564 }
2565 
2566 NETWinInfo::~NETWinInfo()
2567 {
2568     refdec_nwi(p);
2569 
2570     if (!p->ref) {
2571         delete p;
2572     }
2573 }
2574 
2575 // assignment operator
2576 
2577 const NETWinInfo &NETWinInfo::operator=(const NETWinInfo &wininfo)
2578 {
2579 #ifdef NETWMDEBUG
2580     fprintf(stderr, "NETWinInfo::operator=()\n");
2581 #endif
2582 
2583     if (p != wininfo.p) {
2584         refdec_nwi(p);
2585 
2586         if (!p->ref) {
2587             delete p;
2588         }
2589     }
2590 
2591     p = wininfo.p;
2592     p->ref++;
2593 
2594     return *this;
2595 }
2596 
2597 void NETWinInfo::setIcon(NETIcon icon, bool replace)
2598 {
2599     setIconInternal(p->icons, p->icon_count, p->atom(_NET_WM_ICON), icon, replace);
2600 }
2601 
2602 void NETWinInfo::setIconInternal(NETRArray<NETIcon> &icons, int &icon_count, xcb_atom_t property, NETIcon icon, bool replace)
2603 {
2604     if (p->role != Client) {
2605         return;
2606     }
2607 
2608     if (replace) {
2609         for (int i = 0; i < icons.size(); i++) {
2610             delete[] icons[i].data;
2611 
2612             icons[i].data = nullptr;
2613             icons[i].size.width = 0;
2614             icons[i].size.height = 0;
2615         }
2616 
2617         icon_count = 0;
2618     }
2619 
2620     // assign icon
2621     icons[icon_count] = icon;
2622     icon_count++;
2623 
2624     // do a deep copy, we want to own the data
2625     NETIcon &ni = icons[icon_count - 1];
2626     int sz = ni.size.width * ni.size.height;
2627     uint32_t *d = new uint32_t[sz];
2628     ni.data = (unsigned char *)d;
2629     memcpy(d, icon.data, sz * sizeof(uint32_t));
2630 
2631     // compute property length
2632     int proplen = 0;
2633     for (int i = 0; i < icon_count; i++) {
2634         proplen += 2 + (icons[i].size.width * icons[i].size.height);
2635     }
2636 
2637     uint32_t *prop = new uint32_t[proplen];
2638     uint32_t *pprop = prop;
2639     for (int i = 0; i < icon_count; i++) {
2640         // copy size into property
2641         *pprop++ = icons[i].size.width;
2642         *pprop++ = icons[i].size.height;
2643 
2644         // copy data into property
2645         sz = (icons[i].size.width * icons[i].size.height);
2646         uint32_t *d32 = (uint32_t *)icons[i].data;
2647         for (int j = 0; j < sz; j++) {
2648             *pprop++ = *d32++;
2649         }
2650     }
2651 
2652     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, property, XCB_ATOM_CARDINAL, 32, proplen, (const void *)prop);
2653 
2654     delete[] prop;
2655     delete[] p->icon_sizes;
2656     p->icon_sizes = nullptr;
2657 }
2658 
2659 void NETWinInfo::setIconGeometry(NETRect geometry)
2660 {
2661     if (p->role != Client) {
2662         return;
2663     }
2664 
2665     const qreal scaleFactor = qApp->devicePixelRatio();
2666     geometry.pos.x *= scaleFactor;
2667     geometry.pos.y *= scaleFactor;
2668     geometry.size.width *= scaleFactor;
2669     geometry.size.height *= scaleFactor;
2670 
2671     p->icon_geom = geometry;
2672 
2673     if (geometry.size.width == 0) { // Empty
2674         xcb_delete_property(p->conn, p->window, p->atom(_NET_WM_ICON_GEOMETRY));
2675     } else {
2676         uint32_t data[4];
2677         data[0] = geometry.pos.x;
2678         data[1] = geometry.pos.y;
2679         data[2] = geometry.size.width;
2680         data[3] = geometry.size.height;
2681 
2682         xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_ICON_GEOMETRY), XCB_ATOM_CARDINAL, 32, 4, (const void *)data);
2683     }
2684 }
2685 
2686 void NETWinInfo::setExtendedStrut(const NETExtendedStrut &extended_strut)
2687 {
2688     if (p->role != Client) {
2689         return;
2690     }
2691 
2692     p->extended_strut = extended_strut;
2693 
2694     uint32_t data[12];
2695     data[0] = extended_strut.left_width;
2696     data[1] = extended_strut.right_width;
2697     data[2] = extended_strut.top_width;
2698     data[3] = extended_strut.bottom_width;
2699     data[4] = extended_strut.left_start;
2700     data[5] = extended_strut.left_end;
2701     data[6] = extended_strut.right_start;
2702     data[7] = extended_strut.right_end;
2703     data[8] = extended_strut.top_start;
2704     data[9] = extended_strut.top_end;
2705     data[10] = extended_strut.bottom_start;
2706     data[11] = extended_strut.bottom_end;
2707 
2708     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_STRUT_PARTIAL), XCB_ATOM_CARDINAL, 32, 12, (const void *)data);
2709 }
2710 
2711 void NETWinInfo::setStrut(NETStrut strut)
2712 {
2713     if (p->role != Client) {
2714         return;
2715     }
2716 
2717     p->strut = strut;
2718 
2719     uint32_t data[4];
2720     data[0] = strut.left;
2721     data[1] = strut.right;
2722     data[2] = strut.top;
2723     data[3] = strut.bottom;
2724 
2725     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_STRUT), XCB_ATOM_CARDINAL, 32, 4, (const void *)data);
2726 }
2727 
2728 void NETWinInfo::setFullscreenMonitors(NETFullscreenMonitors topology)
2729 {
2730     if (p->role == Client) {
2731         const uint32_t data[5] = {uint32_t(topology.top), uint32_t(topology.bottom), uint32_t(topology.left), uint32_t(topology.right), 1};
2732 
2733         send_client_message(p->conn, netwm_sendevent_mask, p->root, p->window, p->atom(_NET_WM_FULLSCREEN_MONITORS), data);
2734     } else {
2735         p->fullscreen_monitors = topology;
2736 
2737         uint32_t data[4];
2738         data[0] = topology.top;
2739         data[1] = topology.bottom;
2740         data[2] = topology.left;
2741         data[3] = topology.right;
2742 
2743         xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_FULLSCREEN_MONITORS), XCB_ATOM_CARDINAL, 32, 4, (const void *)data);
2744     }
2745 }
2746 
2747 void NETWinInfo::setState(NET::States state, NET::States mask)
2748 {
2749     if (p->mapping_state_dirty) {
2750         updateWMState();
2751     }
2752 
2753     // setState() needs to know the current state, so read it even if not requested
2754     if ((p->properties & WMState) == 0) {
2755         p->properties |= WMState;
2756 
2757         update(WMState);
2758 
2759         p->properties &= ~WMState;
2760     }
2761 
2762     if (p->role == Client && p->mapping_state != Withdrawn) {
2763 #ifdef NETWMDEBUG
2764         fprintf(stderr, "NETWinInfo::setState (0x%lx, 0x%lx) (Client)\n", state, mask);
2765 #endif // NETWMDEBUG
2766 
2767         xcb_client_message_event_t event;
2768         event.response_type = XCB_CLIENT_MESSAGE;
2769         event.format = 32;
2770         event.sequence = 0;
2771         event.window = p->window;
2772         event.type = p->atom(_NET_WM_STATE);
2773         event.data.data32[3] = 0;
2774         event.data.data32[4] = 0;
2775 
2776         if ((mask & Modal) && ((p->state & Modal) != (state & Modal))) {
2777             event.data.data32[0] = (state & Modal) ? 1 : 0;
2778             event.data.data32[1] = p->atom(_NET_WM_STATE_MODAL);
2779             event.data.data32[2] = 0l;
2780 
2781             xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2782         }
2783 
2784         if ((mask & Sticky) && ((p->state & Sticky) != (state & Sticky))) {
2785             event.data.data32[0] = (state & Sticky) ? 1 : 0;
2786             event.data.data32[1] = p->atom(_NET_WM_STATE_STICKY);
2787             event.data.data32[2] = 0l;
2788 
2789             xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2790         }
2791 
2792         if ((mask & Max) && (((p->state & mask) & Max) != (state & Max))) {
2793             NET::States wishstate = (p->state & ~mask) | (state & mask);
2794             if (((wishstate & MaxHoriz) != (p->state & MaxHoriz)) && ((wishstate & MaxVert) != (p->state & MaxVert))) {
2795                 if ((wishstate & Max) == Max) {
2796                     event.data.data32[0] = 1;
2797                     event.data.data32[1] = p->atom(_NET_WM_STATE_MAXIMIZED_HORZ);
2798                     event.data.data32[2] = p->atom(_NET_WM_STATE_MAXIMIZED_VERT);
2799                     xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2800                 } else if ((wishstate & Max) == 0) {
2801                     event.data.data32[0] = 0;
2802                     event.data.data32[1] = p->atom(_NET_WM_STATE_MAXIMIZED_HORZ);
2803                     event.data.data32[2] = p->atom(_NET_WM_STATE_MAXIMIZED_VERT);
2804                     xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2805                 } else {
2806                     event.data.data32[0] = (wishstate & MaxHoriz) ? 1 : 0;
2807                     event.data.data32[1] = p->atom(_NET_WM_STATE_MAXIMIZED_HORZ);
2808                     event.data.data32[2] = 0;
2809                     xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2810 
2811                     event.data.data32[0] = (wishstate & MaxVert) ? 1 : 0;
2812                     event.data.data32[1] = p->atom(_NET_WM_STATE_MAXIMIZED_VERT);
2813                     event.data.data32[2] = 0;
2814                     xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2815                 }
2816             } else if ((wishstate & MaxVert) != (p->state & MaxVert)) {
2817                 event.data.data32[0] = (wishstate & MaxVert) ? 1 : 0;
2818                 event.data.data32[1] = p->atom(_NET_WM_STATE_MAXIMIZED_VERT);
2819                 event.data.data32[2] = 0;
2820 
2821                 xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2822             } else if ((wishstate & MaxHoriz) != (p->state & MaxHoriz)) {
2823                 event.data.data32[0] = (wishstate & MaxHoriz) ? 1 : 0;
2824                 event.data.data32[1] = p->atom(_NET_WM_STATE_MAXIMIZED_HORZ);
2825                 event.data.data32[2] = 0;
2826 
2827                 xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2828             }
2829         }
2830 
2831         if ((mask & Shaded) && ((p->state & Shaded) != (state & Shaded))) {
2832             event.data.data32[0] = (state & Shaded) ? 1 : 0;
2833             event.data.data32[1] = p->atom(_NET_WM_STATE_SHADED);
2834             event.data.data32[2] = 0l;
2835 
2836             xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2837         }
2838 
2839         if ((mask & SkipTaskbar) && ((p->state & SkipTaskbar) != (state & SkipTaskbar))) {
2840             event.data.data32[0] = (state & SkipTaskbar) ? 1 : 0;
2841             event.data.data32[1] = p->atom(_NET_WM_STATE_SKIP_TASKBAR);
2842             event.data.data32[2] = 0l;
2843 
2844             xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2845         }
2846 
2847         if ((mask & SkipPager) && ((p->state & SkipPager) != (state & SkipPager))) {
2848             event.data.data32[0] = (state & SkipPager) ? 1 : 0;
2849             event.data.data32[1] = p->atom(_NET_WM_STATE_SKIP_PAGER);
2850             event.data.data32[2] = 0l;
2851 
2852             xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2853         }
2854 
2855         if ((mask & SkipSwitcher) && ((p->state & SkipSwitcher) != (state & SkipSwitcher))) {
2856             event.data.data32[0] = (state & SkipSwitcher) ? 1 : 0;
2857             event.data.data32[1] = p->atom(_KDE_NET_WM_STATE_SKIP_SWITCHER);
2858             event.data.data32[2] = 0l;
2859 
2860             xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2861         }
2862 
2863         if ((mask & Hidden) && ((p->state & Hidden) != (state & Hidden))) {
2864             event.data.data32[0] = (state & Hidden) ? 1 : 0;
2865             event.data.data32[1] = p->atom(_NET_WM_STATE_HIDDEN);
2866             event.data.data32[2] = 0l;
2867 
2868             xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2869         }
2870 
2871         if ((mask & FullScreen) && ((p->state & FullScreen) != (state & FullScreen))) {
2872             event.data.data32[0] = (state & FullScreen) ? 1 : 0;
2873             event.data.data32[1] = p->atom(_NET_WM_STATE_FULLSCREEN);
2874             event.data.data32[2] = 0l;
2875 
2876             xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2877         }
2878 
2879         if ((mask & KeepAbove) && ((p->state & KeepAbove) != (state & KeepAbove))) {
2880             event.data.data32[0] = (state & KeepAbove) ? 1 : 0;
2881             event.data.data32[1] = p->atom(_NET_WM_STATE_ABOVE);
2882             event.data.data32[2] = 0l;
2883 
2884             xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2885 
2886             // deprecated variant
2887             event.data.data32[0] = (state & KeepAbove) ? 1 : 0;
2888             event.data.data32[1] = p->atom(_NET_WM_STATE_STAYS_ON_TOP);
2889             event.data.data32[2] = 0l;
2890 
2891             xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2892         }
2893 
2894         if ((mask & KeepBelow) && ((p->state & KeepBelow) != (state & KeepBelow))) {
2895             event.data.data32[0] = (state & KeepBelow) ? 1 : 0;
2896             event.data.data32[1] = p->atom(_NET_WM_STATE_BELOW);
2897             event.data.data32[2] = 0l;
2898 
2899             xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2900         }
2901 
2902         if ((mask & DemandsAttention) && ((p->state & DemandsAttention) != (state & DemandsAttention))) {
2903             event.data.data32[0] = (state & DemandsAttention) ? 1 : 0;
2904             event.data.data32[1] = p->atom(_NET_WM_STATE_DEMANDS_ATTENTION);
2905             event.data.data32[2] = 0l;
2906 
2907             xcb_send_event(p->conn, false, p->root, netwm_sendevent_mask, (const char *)&event);
2908         }
2909 
2910         // Focused is not added here as it is effectively "read only" set by the WM, a client setting it would be silly
2911     } else {
2912         p->state &= ~mask;
2913         p->state |= state;
2914 
2915         uint32_t data[50];
2916         int count = 0;
2917 
2918         // Hints
2919         if (p->state & Modal) {
2920             data[count++] = p->atom(_NET_WM_STATE_MODAL);
2921         }
2922         if (p->state & MaxVert) {
2923             data[count++] = p->atom(_NET_WM_STATE_MAXIMIZED_VERT);
2924         }
2925         if (p->state & MaxHoriz) {
2926             data[count++] = p->atom(_NET_WM_STATE_MAXIMIZED_HORZ);
2927         }
2928         if (p->state & Shaded) {
2929             data[count++] = p->atom(_NET_WM_STATE_SHADED);
2930         }
2931         if (p->state & Hidden) {
2932             data[count++] = p->atom(_NET_WM_STATE_HIDDEN);
2933         }
2934         if (p->state & FullScreen) {
2935             data[count++] = p->atom(_NET_WM_STATE_FULLSCREEN);
2936         }
2937         if (p->state & DemandsAttention) {
2938             data[count++] = p->atom(_NET_WM_STATE_DEMANDS_ATTENTION);
2939         }
2940         if (p->state & Focused) {
2941             data[count++] = p->atom(_NET_WM_STATE_FOCUSED);
2942         }
2943 
2944         // Policy
2945         if (p->state & KeepAbove) {
2946             data[count++] = p->atom(_NET_WM_STATE_ABOVE);
2947             // deprecated variant
2948             data[count++] = p->atom(_NET_WM_STATE_STAYS_ON_TOP);
2949         }
2950         if (p->state & KeepBelow) {
2951             data[count++] = p->atom(_NET_WM_STATE_BELOW);
2952         }
2953         if (p->state & Sticky) {
2954             data[count++] = p->atom(_NET_WM_STATE_STICKY);
2955         }
2956         if (p->state & SkipTaskbar) {
2957             data[count++] = p->atom(_NET_WM_STATE_SKIP_TASKBAR);
2958         }
2959         if (p->state & SkipPager) {
2960             data[count++] = p->atom(_NET_WM_STATE_SKIP_PAGER);
2961         }
2962         if (p->state & SkipSwitcher) {
2963             data[count++] = p->atom(_KDE_NET_WM_STATE_SKIP_SWITCHER);
2964         }
2965 
2966 #ifdef NETWMDEBUG
2967         fprintf(stderr, "NETWinInfo::setState: setting state property (%d)\n", count);
2968         for (int i = 0; i < count; i++) {
2969             const QByteArray ba = get_atom_name(p->conn, data[i]);
2970             fprintf(stderr, "NETWinInfo::setState:   state %ld '%s'\n", data[i], ba.constData());
2971         }
2972 #endif
2973 
2974         xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_STATE), XCB_ATOM_ATOM, 32, count, (const void *)data);
2975     }
2976 }
2977 
2978 void NETWinInfo::setWindowType(WindowType type)
2979 {
2980     if (p->role != Client) {
2981         return;
2982     }
2983 
2984     int len;
2985     uint32_t data[2];
2986 
2987     switch (type) {
2988     case Override:
2989         // spec extension: override window type.  we must comply with the spec
2990         // and provide a fall back (normal seems best)
2991         data[0] = p->atom(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE);
2992         data[1] = p->atom(_NET_WM_WINDOW_TYPE_NORMAL);
2993         len = 2;
2994         break;
2995 
2996     case Dialog:
2997         data[0] = p->atom(_NET_WM_WINDOW_TYPE_DIALOG);
2998         data[1] = XCB_NONE;
2999         len = 1;
3000         break;
3001 
3002     case Menu:
3003         data[0] = p->atom(_NET_WM_WINDOW_TYPE_MENU);
3004         data[1] = XCB_NONE;
3005         len = 1;
3006         break;
3007 
3008     case TopMenu:
3009         // spec extension: override window type.  we must comply with the spec
3010         // and provide a fall back (dock seems best)
3011         data[0] = p->atom(_KDE_NET_WM_WINDOW_TYPE_TOPMENU);
3012         data[1] = p->atom(_NET_WM_WINDOW_TYPE_DOCK);
3013         len = 2;
3014         break;
3015 
3016     case Toolbar:
3017         data[0] = p->atom(_NET_WM_WINDOW_TYPE_TOOLBAR);
3018         data[1] = XCB_NONE;
3019         len = 1;
3020         break;
3021 
3022     case Dock:
3023         data[0] = p->atom(_NET_WM_WINDOW_TYPE_DOCK);
3024         data[1] = XCB_NONE;
3025         len = 1;
3026         break;
3027 
3028     case Desktop:
3029         data[0] = p->atom(_NET_WM_WINDOW_TYPE_DESKTOP);
3030         data[1] = XCB_NONE;
3031         len = 1;
3032         break;
3033 
3034     case Utility:
3035         data[0] = p->atom(_NET_WM_WINDOW_TYPE_UTILITY);
3036         data[1] = p->atom(_NET_WM_WINDOW_TYPE_DIALOG); // fallback for old netwm version
3037         len = 2;
3038         break;
3039 
3040     case Splash:
3041         data[0] = p->atom(_NET_WM_WINDOW_TYPE_SPLASH);
3042         data[1] = p->atom(_NET_WM_WINDOW_TYPE_DOCK); // fallback (dock seems best)
3043         len = 2;
3044         break;
3045 
3046     case DropdownMenu:
3047         data[0] = p->atom(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU);
3048         data[1] = p->atom(_NET_WM_WINDOW_TYPE_MENU); // fallback (tearoff seems to be the best)
3049         len = 1;
3050         break;
3051 
3052     case PopupMenu:
3053         data[0] = p->atom(_NET_WM_WINDOW_TYPE_POPUP_MENU);
3054         data[1] = p->atom(_NET_WM_WINDOW_TYPE_MENU); // fallback (tearoff seems to be the best)
3055         len = 1;
3056         break;
3057 
3058     case Tooltip:
3059         data[0] = p->atom(_NET_WM_WINDOW_TYPE_TOOLTIP);
3060         data[1] = XCB_NONE;
3061         len = 1;
3062         break;
3063 
3064     case Notification:
3065         data[0] = p->atom(_NET_WM_WINDOW_TYPE_NOTIFICATION);
3066         data[1] = p->atom(_NET_WM_WINDOW_TYPE_UTILITY); // fallback (utility seems to be the best)
3067         len = 1;
3068         break;
3069 
3070     case ComboBox:
3071         data[0] = p->atom(_NET_WM_WINDOW_TYPE_COMBO);
3072         data[1] = XCB_NONE;
3073         len = 1;
3074         break;
3075 
3076     case DNDIcon:
3077         data[0] = p->atom(_NET_WM_WINDOW_TYPE_DND);
3078         data[1] = XCB_NONE;
3079         len = 1;
3080         break;
3081 
3082     case OnScreenDisplay:
3083         data[0] = p->atom(_KDE_NET_WM_WINDOW_TYPE_ON_SCREEN_DISPLAY);
3084         data[1] = p->atom(_NET_WM_WINDOW_TYPE_NOTIFICATION);
3085         len = 2;
3086         break;
3087 
3088     case CriticalNotification:
3089         data[0] = p->atom(_KDE_NET_WM_WINDOW_TYPE_CRITICAL_NOTIFICATION);
3090         data[1] = p->atom(_NET_WM_WINDOW_TYPE_NOTIFICATION);
3091         len = 2;
3092         break;
3093     
3094     case AppletPopup:
3095         data[0] = p->atom(_KDE_NET_WM_WINDOW_TYPE_APPLET_POPUP);
3096         data[1] = XCB_NONE;
3097         len = 1;
3098         break;
3099 
3100     default:
3101     case Normal:
3102         data[0] = p->atom(_NET_WM_WINDOW_TYPE_NORMAL);
3103         data[1] = XCB_NONE;
3104         len = 1;
3105         break;
3106     }
3107 
3108     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 32, len, (const void *)&data);
3109 }
3110 
3111 void NETWinInfo::setName(const char *name)
3112 {
3113     if (p->role != Client) {
3114         return;
3115     }
3116 
3117     delete[] p->name;
3118     p->name = nstrdup(name);
3119 
3120     if (p->name[0] != '\0') {
3121         xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_NAME), p->atom(UTF8_STRING), 8, strlen(p->name), (const void *)p->name);
3122     } else {
3123         xcb_delete_property(p->conn, p->window, p->atom(_NET_WM_NAME));
3124     }
3125 }
3126 
3127 void NETWinInfo::setVisibleName(const char *visibleName)
3128 {
3129     if (p->role != WindowManager) {
3130         return;
3131     }
3132 
3133     delete[] p->visible_name;
3134     p->visible_name = nstrdup(visibleName);
3135 
3136     if (p->visible_name[0] != '\0') {
3137         xcb_change_property(p->conn,
3138                             XCB_PROP_MODE_REPLACE,
3139                             p->window,
3140                             p->atom(_NET_WM_VISIBLE_NAME),
3141                             p->atom(UTF8_STRING),
3142                             8,
3143                             strlen(p->visible_name),
3144                             (const void *)p->visible_name);
3145     } else {
3146         xcb_delete_property(p->conn, p->window, p->atom(_NET_WM_VISIBLE_NAME));
3147     }
3148 }
3149 
3150 void NETWinInfo::setIconName(const char *iconName)
3151 {
3152     if (p->role != Client) {
3153         return;
3154     }
3155 
3156     delete[] p->icon_name;
3157     p->icon_name = nstrdup(iconName);
3158 
3159     if (p->icon_name[0] != '\0') {
3160         xcb_change_property(p->conn,
3161                             XCB_PROP_MODE_REPLACE,
3162                             p->window,
3163                             p->atom(_NET_WM_ICON_NAME),
3164                             p->atom(UTF8_STRING),
3165                             8,
3166                             strlen(p->icon_name),
3167                             (const void *)p->icon_name);
3168     } else {
3169         xcb_delete_property(p->conn, p->window, p->atom(_NET_WM_ICON_NAME));
3170     }
3171 }
3172 
3173 void NETWinInfo::setVisibleIconName(const char *visibleIconName)
3174 {
3175     if (p->role != WindowManager) {
3176         return;
3177     }
3178 
3179     delete[] p->visible_icon_name;
3180     p->visible_icon_name = nstrdup(visibleIconName);
3181 
3182     if (p->visible_icon_name[0] != '\0') {
3183         xcb_change_property(p->conn,
3184                             XCB_PROP_MODE_REPLACE,
3185                             p->window,
3186                             p->atom(_NET_WM_VISIBLE_ICON_NAME),
3187                             p->atom(UTF8_STRING),
3188                             8,
3189                             strlen(p->visible_icon_name),
3190                             (const void *)p->visible_icon_name);
3191     } else {
3192         xcb_delete_property(p->conn, p->window, p->atom(_NET_WM_VISIBLE_ICON_NAME));
3193     }
3194 }
3195 
3196 void NETWinInfo::setDesktop(int desktop, bool ignore_viewport)
3197 {
3198     if (p->mapping_state_dirty) {
3199         updateWMState();
3200     }
3201 
3202     if (p->role == Client && p->mapping_state != Withdrawn) {
3203         // We only send a ClientMessage if we are 1) a client and 2) managed
3204 
3205         if (desktop == 0) {
3206             return; // We can't do that while being managed
3207         }
3208 
3209         if (!ignore_viewport && KX11Extras::mapViewport()) {
3210             KX11Extras::setOnDesktop(p->window, desktop);
3211             return;
3212         }
3213 
3214         const uint32_t data[5] = {desktop == OnAllDesktops ? 0xffffffff : desktop - 1, 0, 0, 0, 0};
3215 
3216         send_client_message(p->conn, netwm_sendevent_mask, p->root, p->window, p->atom(_NET_WM_DESKTOP), data);
3217     } else {
3218         // Otherwise we just set or remove the property directly
3219         p->desktop = desktop;
3220 
3221         if (desktop == 0) {
3222             xcb_delete_property(p->conn, p->window, p->atom(_NET_WM_DESKTOP));
3223         } else {
3224             uint32_t d = (desktop == OnAllDesktops ? 0xffffffff : desktop - 1);
3225             xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_DESKTOP), XCB_ATOM_CARDINAL, 32, 1, (const void *)&d);
3226         }
3227     }
3228 }
3229 
3230 void NETWinInfo::setPid(int pid)
3231 {
3232     if (p->role != Client) {
3233         return;
3234     }
3235 
3236     p->pid = pid;
3237     uint32_t d = pid;
3238     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_PID), XCB_ATOM_CARDINAL, 32, 1, (const void *)&d);
3239 }
3240 
3241 void NETWinInfo::setHandledIcons(bool handled)
3242 {
3243     if (p->role != Client) {
3244         return;
3245     }
3246 
3247     p->handled_icons = handled;
3248     uint32_t d = handled;
3249     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_HANDLED_ICONS), XCB_ATOM_CARDINAL, 32, 1, (const void *)&d);
3250 }
3251 
3252 void NETWinInfo::setStartupId(const char *id)
3253 {
3254     if (p->role != Client) {
3255         return;
3256     }
3257 
3258     delete[] p->startup_id;
3259     p->startup_id = nstrdup(id);
3260 
3261     xcb_change_property(p->conn,
3262                         XCB_PROP_MODE_REPLACE,
3263                         p->window,
3264                         p->atom(_NET_STARTUP_ID),
3265                         p->atom(UTF8_STRING),
3266                         8,
3267                         strlen(p->startup_id),
3268                         (const void *)p->startup_id);
3269 }
3270 
3271 void NETWinInfo::setOpacity(unsigned long opacity)
3272 {
3273     //    if (p->role != Client) return;
3274 
3275     p->opacity = opacity;
3276     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_WINDOW_OPACITY), XCB_ATOM_CARDINAL, 32, 1, (const void *)&p->opacity);
3277 }
3278 
3279 void NETWinInfo::setOpacityF(qreal opacity)
3280 {
3281     setOpacity(static_cast<unsigned long>(opacity * 0xffffffff));
3282 }
3283 
3284 void NETWinInfo::setAllowedActions(NET::Actions actions)
3285 {
3286     if (p->role != WindowManager) {
3287         return;
3288     }
3289 
3290     uint32_t data[50];
3291     int count = 0;
3292 
3293     p->allowed_actions = actions;
3294     if (p->allowed_actions & ActionMove) {
3295         data[count++] = p->atom(_NET_WM_ACTION_MOVE);
3296     }
3297     if (p->allowed_actions & ActionResize) {
3298         data[count++] = p->atom(_NET_WM_ACTION_RESIZE);
3299     }
3300     if (p->allowed_actions & ActionMinimize) {
3301         data[count++] = p->atom(_NET_WM_ACTION_MINIMIZE);
3302     }
3303     if (p->allowed_actions & ActionShade) {
3304         data[count++] = p->atom(_NET_WM_ACTION_SHADE);
3305     }
3306     if (p->allowed_actions & ActionStick) {
3307         data[count++] = p->atom(_NET_WM_ACTION_STICK);
3308     }
3309     if (p->allowed_actions & ActionMaxVert) {
3310         data[count++] = p->atom(_NET_WM_ACTION_MAXIMIZE_VERT);
3311     }
3312     if (p->allowed_actions & ActionMaxHoriz) {
3313         data[count++] = p->atom(_NET_WM_ACTION_MAXIMIZE_HORZ);
3314     }
3315     if (p->allowed_actions & ActionFullScreen) {
3316         data[count++] = p->atom(_NET_WM_ACTION_FULLSCREEN);
3317     }
3318     if (p->allowed_actions & ActionChangeDesktop) {
3319         data[count++] = p->atom(_NET_WM_ACTION_CHANGE_DESKTOP);
3320     }
3321     if (p->allowed_actions & ActionClose) {
3322         data[count++] = p->atom(_NET_WM_ACTION_CLOSE);
3323     }
3324 
3325 #ifdef NETWMDEBUG
3326     fprintf(stderr, "NETWinInfo::setAllowedActions: setting property (%d)\n", count);
3327     for (int i = 0; i < count; i++) {
3328         const QByteArray ba = get_atom_name(p->conn, data[i]);
3329         fprintf(stderr, "NETWinInfo::setAllowedActions:   action %ld '%s'\n", data[i], ba.constData());
3330     }
3331 #endif
3332 
3333     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_ALLOWED_ACTIONS), XCB_ATOM_ATOM, 32, count, (const void *)data);
3334 }
3335 
3336 void NETWinInfo::setFrameExtents(NETStrut strut)
3337 {
3338     if (p->role != WindowManager) {
3339         return;
3340     }
3341 
3342     p->frame_strut = strut;
3343 
3344     uint32_t d[4];
3345     d[0] = strut.left;
3346     d[1] = strut.right;
3347     d[2] = strut.top;
3348     d[3] = strut.bottom;
3349 
3350     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_FRAME_EXTENTS), XCB_ATOM_CARDINAL, 32, 4, (const void *)d);
3351     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_KDE_NET_WM_FRAME_STRUT), XCB_ATOM_CARDINAL, 32, 4, (const void *)d);
3352 }
3353 
3354 NETStrut NETWinInfo::frameExtents() const
3355 {
3356     return p->frame_strut;
3357 }
3358 
3359 void NETWinInfo::setFrameOverlap(NETStrut strut)
3360 {
3361     if (strut.left != -1 || strut.top != -1 || strut.right != -1 || strut.bottom != -1) {
3362         strut.left = qMax(0, strut.left);
3363         strut.top = qMax(0, strut.top);
3364         strut.right = qMax(0, strut.right);
3365         strut.bottom = qMax(0, strut.bottom);
3366     }
3367 
3368     p->frame_overlap = strut;
3369 
3370     uint32_t d[4];
3371     d[0] = strut.left;
3372     d[1] = strut.right;
3373     d[2] = strut.top;
3374     d[3] = strut.bottom;
3375 
3376     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_FRAME_OVERLAP), XCB_ATOM_CARDINAL, 32, 4, (const void *)d);
3377 }
3378 
3379 NETStrut NETWinInfo::frameOverlap() const
3380 {
3381     return p->frame_overlap;
3382 }
3383 
3384 void NETWinInfo::setGtkFrameExtents(NETStrut strut)
3385 {
3386     p->gtk_frame_extents = strut;
3387 
3388     uint32_t d[4];
3389     d[0] = strut.left;
3390     d[1] = strut.right;
3391     d[2] = strut.top;
3392     d[3] = strut.bottom;
3393 
3394     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_GTK_FRAME_EXTENTS), XCB_ATOM_CARDINAL, 32, 4, (const void *)d);
3395 }
3396 
3397 NETStrut NETWinInfo::gtkFrameExtents() const
3398 {
3399     return p->gtk_frame_extents;
3400 }
3401 
3402 void NETWinInfo::setAppMenuObjectPath(const char *name)
3403 {
3404     if (p->role != Client) {
3405         return;
3406     }
3407 
3408     delete[] p->appmenu_object_path;
3409     p->appmenu_object_path = nstrdup(name);
3410 
3411     xcb_change_property(p->conn,
3412                         XCB_PROP_MODE_REPLACE,
3413                         p->window,
3414                         p->atom(_KDE_NET_WM_APPMENU_OBJECT_PATH),
3415                         XCB_ATOM_STRING,
3416                         8,
3417                         strlen(p->appmenu_object_path),
3418                         (const void *)p->appmenu_object_path);
3419 }
3420 
3421 void NETWinInfo::setAppMenuServiceName(const char *name)
3422 {
3423     if (p->role != Client) {
3424         return;
3425     }
3426 
3427     delete[] p->appmenu_service_name;
3428     p->appmenu_service_name = nstrdup(name);
3429 
3430     xcb_change_property(p->conn,
3431                         XCB_PROP_MODE_REPLACE,
3432                         p->window,
3433                         p->atom(_KDE_NET_WM_APPMENU_SERVICE_NAME),
3434                         XCB_ATOM_STRING,
3435                         8,
3436                         strlen(p->appmenu_service_name),
3437                         (const void *)p->appmenu_service_name);
3438 }
3439 
3440 const char *NETWinInfo::appMenuObjectPath() const
3441 {
3442     return p->appmenu_object_path;
3443 }
3444 
3445 const char *NETWinInfo::appMenuServiceName() const
3446 {
3447     return p->appmenu_service_name;
3448 }
3449 
3450 void NETWinInfo::kdeGeometry(NETRect &frame, NETRect &window)
3451 {
3452     if (p->win_geom.size.width == 0 || p->win_geom.size.height == 0) {
3453         const xcb_get_geometry_cookie_t geometry_cookie = xcb_get_geometry(p->conn, p->window);
3454 
3455         const xcb_translate_coordinates_cookie_t translate_cookie = xcb_translate_coordinates(p->conn, p->window, p->root, 0, 0);
3456 
3457         xcb_get_geometry_reply_t *geometry = xcb_get_geometry_reply(p->conn, geometry_cookie, nullptr);
3458         xcb_translate_coordinates_reply_t *translated = xcb_translate_coordinates_reply(p->conn, translate_cookie, nullptr);
3459 
3460         if (geometry && translated) {
3461             p->win_geom.pos.x = translated->dst_x;
3462             p->win_geom.pos.y = translated->dst_y;
3463 
3464             p->win_geom.size.width = geometry->width;
3465             p->win_geom.size.height = geometry->height;
3466         }
3467 
3468         if (geometry) {
3469             free(geometry);
3470         }
3471 
3472         if (translated) {
3473             free(translated);
3474         }
3475     }
3476 
3477     // TODO try to work also without _NET_WM_FRAME_EXTENTS
3478     window = p->win_geom;
3479 
3480     frame.pos.x = window.pos.x - p->frame_strut.left;
3481     frame.pos.y = window.pos.y - p->frame_strut.top;
3482     frame.size.width = window.size.width + p->frame_strut.left + p->frame_strut.right;
3483     frame.size.height = window.size.height + p->frame_strut.top + p->frame_strut.bottom;
3484 }
3485 
3486 NETIcon NETWinInfo::icon(int width, int height) const
3487 {
3488     return iconInternal(p->icons, p->icon_count, width, height);
3489 }
3490 
3491 const int *NETWinInfo::iconSizes() const
3492 {
3493     if (p->icon_sizes == nullptr) {
3494         p->icon_sizes = new int[p->icon_count * 2 + 2];
3495         for (int i = 0; i < p->icon_count; ++i) {
3496             p->icon_sizes[i * 2] = p->icons[i].size.width;
3497             p->icon_sizes[i * 2 + 1] = p->icons[i].size.height;
3498         }
3499         p->icon_sizes[p->icon_count * 2] = 0; // terminator
3500         p->icon_sizes[p->icon_count * 2 + 1] = 0;
3501     }
3502     return p->icon_sizes;
3503 }
3504 
3505 NETIcon NETWinInfo::iconInternal(NETRArray<NETIcon> &icons, int icon_count, int width, int height) const
3506 {
3507     NETIcon result;
3508 
3509     if (!icon_count) {
3510         result.size.width = 0;
3511         result.size.height = 0;
3512         result.data = nullptr;
3513         return result;
3514     }
3515 
3516     // find the largest icon
3517     result = icons[0];
3518     for (int i = 1; i < icons.size(); i++) {
3519         if (icons[i].size.width >= result.size.width && icons[i].size.height >= result.size.height) {
3520             result = icons[i];
3521         }
3522     }
3523 
3524     // return the largest icon if w and h are -1
3525     if (width == -1 && height == -1) {
3526         return result;
3527     }
3528 
3529     // find the icon that's closest in size to w x h...
3530     for (int i = 0; i < icons.size(); i++) {
3531         if ((icons[i].size.width >= width && icons[i].size.width < result.size.width)
3532             && (icons[i].size.height >= height && icons[i].size.height < result.size.height)) {
3533             result = icons[i];
3534         }
3535     }
3536 
3537     return result;
3538 }
3539 
3540 void NETWinInfo::setUserTime(xcb_timestamp_t time)
3541 {
3542     if (p->role != Client) {
3543         return;
3544     }
3545 
3546     p->user_time = time;
3547     uint32_t d = time;
3548 
3549     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_USER_TIME), XCB_ATOM_CARDINAL, 32, 1, (const void *)&d);
3550 }
3551 
3552 NET::Properties NETWinInfo::event(xcb_generic_event_t *ev)
3553 {
3554     NET::Properties properties;
3555     event(ev, &properties);
3556     return properties;
3557 }
3558 
3559 void NETWinInfo::event(xcb_generic_event_t *event, NET::Properties *properties, NET::Properties2 *properties2)
3560 {
3561     NET::Properties dirty;
3562     NET::Properties2 dirty2;
3563     bool do_update = false;
3564     const uint8_t eventType = event->response_type & ~0x80;
3565 
3566     if (p->role == WindowManager && eventType == XCB_CLIENT_MESSAGE && reinterpret_cast<xcb_client_message_event_t *>(event)->format == 32) {
3567         xcb_client_message_event_t *message = reinterpret_cast<xcb_client_message_event_t *>(event);
3568 #ifdef NETWMDEBUG
3569         fprintf(stderr, "NETWinInfo::event: handling ClientMessage event\n");
3570 #endif // NETWMDEBUG
3571 
3572         if (message->type == p->atom(_NET_WM_STATE)) {
3573             dirty = WMState;
3574 
3575             // we need to generate a change mask
3576 
3577 #ifdef NETWMDEBUG
3578             fprintf(stderr, "NETWinInfo::event: state client message, getting new state/mask\n");
3579 #endif
3580 
3581             int i;
3582             NET::States state = NET::States();
3583             NET::States mask = NET::States();
3584 
3585             for (i = 1; i < 3; i++) {
3586 #ifdef NETWMDEBUG
3587                 const QByteArray ba = get_atom_name(p->conn, (xcb_atom_t)message->data.data32[i]);
3588                 fprintf(stderr, "NETWinInfo::event:  message %ld '%s'\n", message->data.data32[i], ba.constData());
3589 #endif
3590 
3591                 if ((xcb_atom_t)message->data.data32[i] == p->atom(_NET_WM_STATE_MODAL)) {
3592                     mask |= Modal;
3593                 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(_NET_WM_STATE_STICKY)) {
3594                     mask |= Sticky;
3595                 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(_NET_WM_STATE_MAXIMIZED_VERT)) {
3596                     mask |= MaxVert;
3597                 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(_NET_WM_STATE_MAXIMIZED_HORZ)) {
3598                     mask |= MaxHoriz;
3599                 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(_NET_WM_STATE_SHADED)) {
3600                     mask |= Shaded;
3601                 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(_NET_WM_STATE_SKIP_TASKBAR)) {
3602                     mask |= SkipTaskbar;
3603                 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(_NET_WM_STATE_SKIP_PAGER)) {
3604                     mask |= SkipPager;
3605                 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(_KDE_NET_WM_STATE_SKIP_SWITCHER)) {
3606                     mask |= SkipSwitcher;
3607                 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(_NET_WM_STATE_HIDDEN)) {
3608                     mask |= Hidden;
3609                 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(_NET_WM_STATE_FULLSCREEN)) {
3610                     mask |= FullScreen;
3611                 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(_NET_WM_STATE_ABOVE)) {
3612                     mask |= KeepAbove;
3613                 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(_NET_WM_STATE_BELOW)) {
3614                     mask |= KeepBelow;
3615                 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(_NET_WM_STATE_DEMANDS_ATTENTION)) {
3616                     mask |= DemandsAttention;
3617                 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(_NET_WM_STATE_STAYS_ON_TOP)) {
3618                     mask |= KeepAbove;
3619                 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(_NET_WM_STATE_FOCUSED)) {
3620                     mask |= Focused;
3621                 }
3622             }
3623 
3624             // when removing, we just leave newstate == 0
3625             switch (message->data.data32[0]) {
3626             case 1: // set
3627                 // to set... the change state should be the same as the mask
3628                 state = mask;
3629                 break;
3630 
3631             case 2: // toggle
3632                 // to toggle, we need to xor the current state with the new state
3633                 state = (p->state & mask) ^ mask;
3634                 break;
3635 
3636             default:
3637                 // to clear state, the new state should stay zero
3638                 ;
3639             }
3640 
3641 #ifdef NETWMDEBUG
3642             fprintf(stderr, "NETWinInfo::event: calling changeState(%lx, %lx)\n", state, mask);
3643 #endif
3644 
3645             changeState(state, mask);
3646         } else if (message->type == p->atom(_NET_WM_DESKTOP)) {
3647             dirty = WMDesktop;
3648 
3649             if (message->data.data32[0] == (unsigned)OnAllDesktops) {
3650                 changeDesktop(OnAllDesktops);
3651             } else {
3652                 changeDesktop(message->data.data32[0] + 1);
3653             }
3654         } else if (message->type == p->atom(_NET_WM_FULLSCREEN_MONITORS)) {
3655             dirty2 = WM2FullscreenMonitors;
3656 
3657             NETFullscreenMonitors topology;
3658             topology.top = message->data.data32[0];
3659             topology.bottom = message->data.data32[1];
3660             topology.left = message->data.data32[2];
3661             topology.right = message->data.data32[3];
3662 
3663 #ifdef NETWMDEBUG
3664             fprintf(stderr,
3665                     "NETWinInfo2::event: calling changeFullscreenMonitors"
3666                     "(%ld, %ld, %ld, %ld, %ld)\n",
3667                     message->window,
3668                     message->data.data32[0],
3669                     message->data.data32[1],
3670                     message->data.data32[2],
3671                     message->data.data32[3]);
3672 #endif
3673             changeFullscreenMonitors(topology);
3674         }
3675     }
3676 
3677     if (eventType == XCB_PROPERTY_NOTIFY) {
3678 #ifdef NETWMDEBUG
3679         fprintf(stderr, "NETWinInfo::event: handling PropertyNotify event\n");
3680 #endif
3681 
3682         xcb_property_notify_event_t *pe = reinterpret_cast<xcb_property_notify_event_t *>(event);
3683 
3684         if (pe->atom == p->atom(_NET_WM_NAME)) {
3685             dirty |= WMName;
3686         } else if (pe->atom == p->atom(_NET_WM_VISIBLE_NAME)) {
3687             dirty |= WMVisibleName;
3688         } else if (pe->atom == p->atom(_NET_WM_DESKTOP)) {
3689             dirty |= WMDesktop;
3690         } else if (pe->atom == p->atom(_NET_WM_WINDOW_TYPE)) {
3691             dirty |= WMWindowType;
3692         } else if (pe->atom == p->atom(_NET_WM_STATE)) {
3693             dirty |= WMState;
3694         } else if (pe->atom == p->atom(_NET_WM_STRUT)) {
3695             dirty |= WMStrut;
3696         } else if (pe->atom == p->atom(_NET_WM_STRUT_PARTIAL)) {
3697             dirty2 |= WM2ExtendedStrut;
3698         } else if (pe->atom == p->atom(_NET_WM_ICON_GEOMETRY)) {
3699             dirty |= WMIconGeometry;
3700         } else if (pe->atom == p->atom(_NET_WM_ICON)) {
3701             dirty |= WMIcon;
3702         } else if (pe->atom == p->atom(_NET_WM_PID)) {
3703             dirty |= WMPid;
3704         } else if (pe->atom == p->atom(_NET_WM_HANDLED_ICONS)) {
3705             dirty |= WMHandledIcons;
3706         } else if (pe->atom == p->atom(_NET_STARTUP_ID)) {
3707             dirty2 |= WM2StartupId;
3708         } else if (pe->atom == p->atom(_NET_WM_WINDOW_OPACITY)) {
3709             dirty2 |= WM2Opacity;
3710         } else if (pe->atom == p->atom(_NET_WM_ALLOWED_ACTIONS)) {
3711             dirty2 |= WM2AllowedActions;
3712         } else if (pe->atom == p->atom(WM_STATE)) {
3713             dirty |= XAWMState;
3714         } else if (pe->atom == p->atom(_NET_FRAME_EXTENTS)) {
3715             dirty |= WMFrameExtents;
3716         } else if (pe->atom == p->atom(_KDE_NET_WM_FRAME_STRUT)) {
3717             dirty |= WMFrameExtents;
3718         } else if (pe->atom == p->atom(_NET_WM_FRAME_OVERLAP)) {
3719             dirty2 |= WM2FrameOverlap;
3720         } else if (pe->atom == p->atom(_NET_WM_ICON_NAME)) {
3721             dirty |= WMIconName;
3722         } else if (pe->atom == p->atom(_NET_WM_VISIBLE_ICON_NAME)) {
3723             dirty |= WMVisibleIconName;
3724         } else if (pe->atom == p->atom(_NET_WM_USER_TIME)) {
3725             dirty2 |= WM2UserTime;
3726         } else if (pe->atom == XCB_ATOM_WM_HINTS) {
3727             dirty2 |= WM2GroupLeader;
3728             dirty2 |= WM2Urgency;
3729             dirty2 |= WM2Input;
3730             dirty2 |= WM2InitialMappingState;
3731             dirty2 |= WM2IconPixmap;
3732         } else if (pe->atom == XCB_ATOM_WM_TRANSIENT_FOR) {
3733             dirty2 |= WM2TransientFor;
3734         } else if (pe->atom == XCB_ATOM_WM_CLASS) {
3735             dirty2 |= WM2WindowClass;
3736         } else if (pe->atom == p->atom(WM_WINDOW_ROLE)) {
3737             dirty2 |= WM2WindowRole;
3738         } else if (pe->atom == XCB_ATOM_WM_CLIENT_MACHINE) {
3739             dirty2 |= WM2ClientMachine;
3740         } else if (pe->atom == p->atom(_KDE_NET_WM_ACTIVITIES)) {
3741             dirty2 |= WM2Activities;
3742         } else if (pe->atom == p->atom(_KDE_NET_WM_BLOCK_COMPOSITING) || pe->atom == p->atom(_NET_WM_BYPASS_COMPOSITOR)) {
3743             dirty2 |= WM2BlockCompositing;
3744         } else if (pe->atom == p->atom(_KDE_NET_WM_SHADOW)) {
3745             dirty2 |= WM2KDEShadow;
3746         } else if (pe->atom == p->atom(WM_PROTOCOLS)) {
3747             dirty2 |= WM2Protocols;
3748         } else if (pe->atom == p->atom(_NET_WM_OPAQUE_REGION)) {
3749             dirty2 |= WM2OpaqueRegion;
3750         } else if (pe->atom == p->atom(_KDE_NET_WM_DESKTOP_FILE)) {
3751             dirty2 = WM2DesktopFileName;
3752         } else if (pe->atom == p->atom(_GTK_APPLICATION_ID)) {
3753             dirty2 = WM2GTKApplicationId;
3754         } else if (pe->atom == p->atom(_NET_WM_FULLSCREEN_MONITORS)) {
3755             dirty2 = WM2FullscreenMonitors;
3756         } else if (pe->atom == p->atom(_GTK_FRAME_EXTENTS)) {
3757             dirty2 |= WM2GTKFrameExtents;
3758         } else if (pe->atom == p->atom(_GTK_SHOW_WINDOW_MENU)) {
3759             dirty2 |= WM2GTKShowWindowMenu;
3760         } else if (pe->atom == p->atom(_KDE_NET_WM_APPMENU_SERVICE_NAME)) {
3761             dirty2 |= WM2AppMenuServiceName;
3762         } else if (pe->atom == p->atom(_KDE_NET_WM_APPMENU_OBJECT_PATH)) {
3763             dirty2 |= WM2AppMenuObjectPath;
3764         }
3765 
3766         do_update = true;
3767     } else if (eventType == XCB_CONFIGURE_NOTIFY) {
3768 #ifdef NETWMDEBUG
3769         fprintf(stderr, "NETWinInfo::event: handling ConfigureNotify event\n");
3770 #endif
3771 
3772         dirty |= WMGeometry;
3773 
3774         // update window geometry
3775         xcb_configure_notify_event_t *configure = reinterpret_cast<xcb_configure_notify_event_t *>(event);
3776         p->win_geom.pos.x = configure->x;
3777         p->win_geom.pos.y = configure->y;
3778         p->win_geom.size.width = configure->width;
3779         p->win_geom.size.height = configure->height;
3780     }
3781 
3782     if (do_update) {
3783         update(dirty, dirty2);
3784     }
3785 
3786     if (properties) {
3787         *properties = dirty;
3788     }
3789     if (properties2) {
3790         *properties2 = dirty2;
3791     }
3792 }
3793 
3794 void NETWinInfo::updateWMState()
3795 {
3796     update(XAWMState);
3797 }
3798 
3799 void NETWinInfo::update(NET::Properties dirtyProperties, NET::Properties2 dirtyProperties2)
3800 {
3801     Properties dirty = dirtyProperties & p->properties;
3802     Properties2 dirty2 = dirtyProperties2 & p->properties2;
3803 
3804     // We *always* want to update WM_STATE if set in dirty_props
3805     if (dirtyProperties & XAWMState) {
3806         dirty |= XAWMState;
3807     }
3808 
3809     xcb_get_property_cookie_t cookies[255];
3810     int c = 0;
3811 
3812     if (dirty & XAWMState) {
3813         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(WM_STATE), p->atom(WM_STATE), 0, 1);
3814     }
3815 
3816     if (dirty & WMState) {
3817         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_STATE), XCB_ATOM_ATOM, 0, 2048);
3818     }
3819 
3820     if (dirty & WMDesktop) {
3821         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_DESKTOP), XCB_ATOM_CARDINAL, 0, 1);
3822     }
3823 
3824     if (dirty & WMName) {
3825         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_NAME), p->atom(UTF8_STRING), 0, MAX_PROP_SIZE);
3826     }
3827 
3828     if (dirty & WMVisibleName) {
3829         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_VISIBLE_NAME), p->atom(UTF8_STRING), 0, MAX_PROP_SIZE);
3830     }
3831 
3832     if (dirty & WMIconName) {
3833         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_ICON_NAME), p->atom(UTF8_STRING), 0, MAX_PROP_SIZE);
3834     }
3835 
3836     if (dirty & WMVisibleIconName) {
3837         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_VISIBLE_ICON_NAME), p->atom(UTF8_STRING), 0, MAX_PROP_SIZE);
3838     }
3839 
3840     if (dirty & WMWindowType) {
3841         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 0, 2048);
3842     }
3843 
3844     if (dirty & WMStrut) {
3845         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_STRUT), XCB_ATOM_CARDINAL, 0, 4);
3846     }
3847 
3848     if (dirty2 & WM2ExtendedStrut) {
3849         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_STRUT_PARTIAL), XCB_ATOM_CARDINAL, 0, 12);
3850     }
3851 
3852     if (dirty2 & WM2FullscreenMonitors) {
3853         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_FULLSCREEN_MONITORS), XCB_ATOM_CARDINAL, 0, 4);
3854     }
3855 
3856     if (dirty & WMIconGeometry) {
3857         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_ICON_GEOMETRY), XCB_ATOM_CARDINAL, 0, 4);
3858     }
3859 
3860     if (dirty & WMIcon) {
3861         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_ICON), XCB_ATOM_CARDINAL, 0, 0xffffffff);
3862     }
3863 
3864     if (dirty & WMFrameExtents) {
3865         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_FRAME_EXTENTS), XCB_ATOM_CARDINAL, 0, 4);
3866         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_KDE_NET_WM_FRAME_STRUT), XCB_ATOM_CARDINAL, 0, 4);
3867     }
3868 
3869     if (dirty2 & WM2FrameOverlap) {
3870         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_FRAME_OVERLAP), XCB_ATOM_CARDINAL, 0, 4);
3871     }
3872 
3873     if (dirty2 & WM2Activities) {
3874         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_KDE_NET_WM_ACTIVITIES), XCB_ATOM_STRING, 0, MAX_PROP_SIZE);
3875     }
3876 
3877     if (dirty2 & WM2BlockCompositing) {
3878         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_KDE_NET_WM_BLOCK_COMPOSITING), XCB_ATOM_CARDINAL, 0, 1);
3879         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_BYPASS_COMPOSITOR), XCB_ATOM_CARDINAL, 0, 1);
3880     }
3881 
3882     if (dirty & WMPid) {
3883         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_PID), XCB_ATOM_CARDINAL, 0, 1);
3884     }
3885 
3886     if (dirty2 & WM2StartupId) {
3887         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_STARTUP_ID), p->atom(UTF8_STRING), 0, MAX_PROP_SIZE);
3888     }
3889 
3890     if (dirty2 & WM2Opacity) {
3891         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_WINDOW_OPACITY), XCB_ATOM_CARDINAL, 0, 1);
3892     }
3893 
3894     if (dirty2 & WM2AllowedActions) {
3895         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_ALLOWED_ACTIONS), XCB_ATOM_ATOM, 0, 2048);
3896     }
3897 
3898     if (dirty2 & WM2UserTime) {
3899         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_USER_TIME), XCB_ATOM_CARDINAL, 0, 1);
3900     }
3901 
3902     if (dirty2 & WM2TransientFor) {
3903         cookies[c++] = xcb_get_property(p->conn, false, p->window, XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 0, 1);
3904     }
3905 
3906     if (dirty2 & (WM2GroupLeader | WM2Urgency | WM2Input | WM2InitialMappingState | WM2IconPixmap)) {
3907         cookies[c++] = xcb_get_property(p->conn, false, p->window, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, 9);
3908     }
3909 
3910     if (dirty2 & WM2WindowClass) {
3911         cookies[c++] = xcb_get_property(p->conn, false, p->window, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 0, MAX_PROP_SIZE);
3912     }
3913 
3914     if (dirty2 & WM2WindowRole) {
3915         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(WM_WINDOW_ROLE), XCB_ATOM_STRING, 0, MAX_PROP_SIZE);
3916     }
3917 
3918     if (dirty2 & WM2ClientMachine) {
3919         cookies[c++] = xcb_get_property(p->conn, false, p->window, XCB_ATOM_WM_CLIENT_MACHINE, XCB_ATOM_STRING, 0, MAX_PROP_SIZE);
3920     }
3921 
3922     if (dirty2 & WM2Protocols) {
3923         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(WM_PROTOCOLS), XCB_ATOM_ATOM, 0, 2048);
3924     }
3925 
3926     if (dirty2 & WM2OpaqueRegion) {
3927         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_NET_WM_OPAQUE_REGION), XCB_ATOM_CARDINAL, 0, MAX_PROP_SIZE);
3928     }
3929 
3930     if (dirty2 & WM2DesktopFileName) {
3931         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_KDE_NET_WM_DESKTOP_FILE), p->atom(UTF8_STRING), 0, MAX_PROP_SIZE);
3932     }
3933 
3934     if (dirty2 & WM2GTKApplicationId) {
3935         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_GTK_APPLICATION_ID), p->atom(UTF8_STRING), 0, MAX_PROP_SIZE);
3936     }
3937 
3938     if (dirty2 & WM2GTKFrameExtents) {
3939         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_GTK_FRAME_EXTENTS), XCB_ATOM_CARDINAL, 0, 4);
3940     }
3941 
3942     if (dirty2 & WM2AppMenuObjectPath) {
3943         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_KDE_NET_WM_APPMENU_OBJECT_PATH), XCB_ATOM_STRING, 0, MAX_PROP_SIZE);
3944     }
3945 
3946     if (dirty2 & WM2AppMenuServiceName) {
3947         cookies[c++] = xcb_get_property(p->conn, false, p->window, p->atom(_KDE_NET_WM_APPMENU_SERVICE_NAME), XCB_ATOM_STRING, 0, MAX_PROP_SIZE);
3948     }
3949 
3950     c = 0;
3951 
3952     if (dirty & XAWMState) {
3953         p->mapping_state = Withdrawn;
3954 
3955         bool success;
3956         uint32_t state = get_value_reply<uint32_t>(p->conn, cookies[c++], p->atom(WM_STATE), 0, &success);
3957 
3958         if (success) {
3959             switch (state) {
3960             case 3: // IconicState
3961                 p->mapping_state = Iconic;
3962                 break;
3963 
3964             case 1: // NormalState
3965                 p->mapping_state = Visible;
3966                 break;
3967 
3968             case 0: // WithdrawnState
3969             default:
3970                 p->mapping_state = Withdrawn;
3971                 break;
3972             }
3973 
3974             p->mapping_state_dirty = false;
3975         }
3976     }
3977 
3978     if (dirty & WMState) {
3979         p->state = NET::States();
3980         const QList<xcb_atom_t> states = get_array_reply<xcb_atom_t>(p->conn, cookies[c++], XCB_ATOM_ATOM);
3981 
3982 #ifdef NETWMDEBUG
3983         fprintf(stderr, "NETWinInfo::update: updating window state (%ld)\n", states.count());
3984 #endif
3985 
3986         for (const xcb_atom_t state : states) {
3987 #ifdef NETWMDEBUG
3988             const QByteArray ba = get_atom_name(p->conn, state);
3989             fprintf(stderr, "NETWinInfo::update:   adding window state %ld '%s'\n", state, ba.constData());
3990 #endif
3991             if (state == p->atom(_NET_WM_STATE_MODAL)) {
3992                 p->state |= Modal;
3993             }
3994 
3995             else if (state == p->atom(_NET_WM_STATE_STICKY)) {
3996                 p->state |= Sticky;
3997             }
3998 
3999             else if (state == p->atom(_NET_WM_STATE_MAXIMIZED_VERT)) {
4000                 p->state |= MaxVert;
4001             }
4002 
4003             else if (state == p->atom(_NET_WM_STATE_MAXIMIZED_HORZ)) {
4004                 p->state |= MaxHoriz;
4005             }
4006 
4007             else if (state == p->atom(_NET_WM_STATE_SHADED)) {
4008                 p->state |= Shaded;
4009             }
4010 
4011             else if (state == p->atom(_NET_WM_STATE_SKIP_TASKBAR)) {
4012                 p->state |= SkipTaskbar;
4013             }
4014 
4015             else if (state == p->atom(_NET_WM_STATE_SKIP_PAGER)) {
4016                 p->state |= SkipPager;
4017             }
4018 
4019             else if (state == p->atom(_KDE_NET_WM_STATE_SKIP_SWITCHER)) {
4020                 p->state |= SkipSwitcher;
4021             }
4022 
4023             else if (state == p->atom(_NET_WM_STATE_HIDDEN)) {
4024                 p->state |= Hidden;
4025             }
4026 
4027             else if (state == p->atom(_NET_WM_STATE_FULLSCREEN)) {
4028                 p->state |= FullScreen;
4029             }
4030 
4031             else if (state == p->atom(_NET_WM_STATE_ABOVE)) {
4032                 p->state |= KeepAbove;
4033             }
4034 
4035             else if (state == p->atom(_NET_WM_STATE_BELOW)) {
4036                 p->state |= KeepBelow;
4037             }
4038 
4039             else if (state == p->atom(_NET_WM_STATE_DEMANDS_ATTENTION)) {
4040                 p->state |= DemandsAttention;
4041             }
4042 
4043             else if (state == p->atom(_NET_WM_STATE_STAYS_ON_TOP)) {
4044                 p->state |= KeepAbove;
4045             }
4046 
4047             else if (state == p->atom(_NET_WM_STATE_FOCUSED)) {
4048                 p->state |= Focused;
4049             }
4050         }
4051     }
4052 
4053     if (dirty & WMDesktop) {
4054         p->desktop = 0;
4055 
4056         bool success;
4057         uint32_t desktop = get_value_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL, 0, &success);
4058 
4059         if (success) {
4060             if (desktop != 0xffffffff) {
4061                 p->desktop = desktop + 1;
4062             } else {
4063                 p->desktop = OnAllDesktops;
4064             }
4065         }
4066     }
4067 
4068     if (dirty & WMName) {
4069         delete[] p->name;
4070         p->name = nullptr;
4071 
4072         const QByteArray str = get_string_reply(p->conn, cookies[c++], p->atom(UTF8_STRING));
4073         if (str.length() > 0) {
4074             p->name = nstrndup(str.constData(), str.length());
4075         }
4076     }
4077 
4078     if (dirty & WMVisibleName) {
4079         delete[] p->visible_name;
4080         p->visible_name = nullptr;
4081 
4082         const QByteArray str = get_string_reply(p->conn, cookies[c++], p->atom(UTF8_STRING));
4083         if (str.length() > 0) {
4084             p->visible_name = nstrndup(str.constData(), str.length());
4085         }
4086     }
4087 
4088     if (dirty & WMIconName) {
4089         delete[] p->icon_name;
4090         p->icon_name = nullptr;
4091 
4092         const QByteArray str = get_string_reply(p->conn, cookies[c++], p->atom(UTF8_STRING));
4093         if (str.length() > 0) {
4094             p->icon_name = nstrndup(str.constData(), str.length());
4095         }
4096     }
4097 
4098     if (dirty & WMVisibleIconName) {
4099         delete[] p->visible_icon_name;
4100         p->visible_icon_name = nullptr;
4101 
4102         const QByteArray str = get_string_reply(p->conn, cookies[c++], p->atom(UTF8_STRING));
4103         if (str.length() > 0) {
4104             p->visible_icon_name = nstrndup(str.constData(), str.length());
4105         }
4106     }
4107 
4108     if (dirty & WMWindowType) {
4109         p->types.reset();
4110         p->types[0] = Unknown;
4111         p->has_net_support = false;
4112 
4113         const QList<xcb_atom_t> types = get_array_reply<xcb_atom_t>(p->conn, cookies[c++], XCB_ATOM_ATOM);
4114 
4115         if (!types.isEmpty()) {
4116 #ifdef NETWMDEBUG
4117             fprintf(stderr, "NETWinInfo::update: getting window type (%ld)\n", types.count());
4118 #endif
4119             p->has_net_support = true;
4120             int pos = 0;
4121 
4122             for (const xcb_atom_t type : types) {
4123 #ifdef NETWMDEBUG
4124                 const QByteArray name = get_atom_name(p->conn, type);
4125                 fprintf(stderr, "NETWinInfo::update:   examining window type %ld %s\n", type, name.constData());
4126 #endif
4127                 if (type == p->atom(_NET_WM_WINDOW_TYPE_NORMAL)) {
4128                     p->types[pos++] = Normal;
4129                 }
4130 
4131                 else if (type == p->atom(_NET_WM_WINDOW_TYPE_DESKTOP)) {
4132                     p->types[pos++] = Desktop;
4133                 }
4134 
4135                 else if (type == p->atom(_NET_WM_WINDOW_TYPE_DOCK)) {
4136                     p->types[pos++] = Dock;
4137                 }
4138 
4139                 else if (type == p->atom(_NET_WM_WINDOW_TYPE_TOOLBAR)) {
4140                     p->types[pos++] = Toolbar;
4141                 }
4142 
4143                 else if (type == p->atom(_NET_WM_WINDOW_TYPE_MENU)) {
4144                     p->types[pos++] = Menu;
4145                 }
4146 
4147                 else if (type == p->atom(_NET_WM_WINDOW_TYPE_DIALOG)) {
4148                     p->types[pos++] = Dialog;
4149                 }
4150 
4151                 else if (type == p->atom(_NET_WM_WINDOW_TYPE_UTILITY)) {
4152                     p->types[pos++] = Utility;
4153                 }
4154 
4155                 else if (type == p->atom(_NET_WM_WINDOW_TYPE_SPLASH)) {
4156                     p->types[pos++] = Splash;
4157                 }
4158 
4159                 else if (type == p->atom(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU)) {
4160                     p->types[pos++] = DropdownMenu;
4161                 }
4162 
4163                 else if (type == p->atom(_NET_WM_WINDOW_TYPE_POPUP_MENU)) {
4164                     p->types[pos++] = PopupMenu;
4165                 }
4166 
4167                 else if (type == p->atom(_NET_WM_WINDOW_TYPE_TOOLTIP)) {
4168                     p->types[pos++] = Tooltip;
4169                 }
4170 
4171                 else if (type == p->atom(_NET_WM_WINDOW_TYPE_NOTIFICATION)) {
4172                     p->types[pos++] = Notification;
4173                 }
4174 
4175                 else if (type == p->atom(_NET_WM_WINDOW_TYPE_COMBO)) {
4176                     p->types[pos++] = ComboBox;
4177                 }
4178 
4179                 else if (type == p->atom(_NET_WM_WINDOW_TYPE_DND)) {
4180                     p->types[pos++] = DNDIcon;
4181                 }
4182 
4183                 else if (type == p->atom(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE)) {
4184                     p->types[pos++] = Override;
4185                 }
4186 
4187                 else if (type == p->atom(_KDE_NET_WM_WINDOW_TYPE_TOPMENU)) {
4188                     p->types[pos++] = TopMenu;
4189                 }
4190 
4191                 else if (type == p->atom(_KDE_NET_WM_WINDOW_TYPE_ON_SCREEN_DISPLAY)) {
4192                     p->types[pos++] = OnScreenDisplay;
4193                 }
4194 
4195                 else if (type == p->atom(_KDE_NET_WM_WINDOW_TYPE_CRITICAL_NOTIFICATION)) {
4196                     p->types[pos++] = CriticalNotification;
4197                 }
4198 
4199                 else if (type == p->atom(_KDE_NET_WM_WINDOW_TYPE_APPLET_POPUP)) {
4200                     p->types[pos++] = AppletPopup;
4201                 }
4202             }
4203         }
4204     }
4205 
4206     if (dirty & WMStrut) {
4207         p->strut = NETStrut();
4208 
4209         QList<uint32_t> data = get_array_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL);
4210         if (data.count() == 4) {
4211             p->strut.left = data[0];
4212             p->strut.right = data[1];
4213             p->strut.top = data[2];
4214             p->strut.bottom = data[3];
4215         }
4216     }
4217 
4218     if (dirty2 & WM2ExtendedStrut) {
4219         p->extended_strut = NETExtendedStrut();
4220 
4221         QList<uint32_t> data = get_array_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL);
4222         if (data.count() == 12) {
4223             p->extended_strut.left_width = data[0];
4224             p->extended_strut.right_width = data[1];
4225             p->extended_strut.top_width = data[2];
4226             p->extended_strut.bottom_width = data[3];
4227             p->extended_strut.left_start = data[4];
4228             p->extended_strut.left_end = data[5];
4229             p->extended_strut.right_start = data[6];
4230             p->extended_strut.right_end = data[7];
4231             p->extended_strut.top_start = data[8];
4232             p->extended_strut.top_end = data[9];
4233             p->extended_strut.bottom_start = data[10];
4234             p->extended_strut.bottom_end = data[11];
4235         }
4236     }
4237 
4238     if (dirty2 & WM2FullscreenMonitors) {
4239         p->fullscreen_monitors = NETFullscreenMonitors();
4240 
4241         QList<uint32_t> data = get_array_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL);
4242         if (data.count() == 4) {
4243             p->fullscreen_monitors.top = data[0];
4244             p->fullscreen_monitors.bottom = data[1];
4245             p->fullscreen_monitors.left = data[2];
4246             p->fullscreen_monitors.right = data[3];
4247         }
4248     }
4249 
4250     if (dirty & WMIconGeometry) {
4251         p->icon_geom = NETRect();
4252 
4253         QList<uint32_t> data = get_array_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL);
4254         if (data.count() == 4) {
4255             p->icon_geom.pos.x = data[0];
4256             p->icon_geom.pos.y = data[1];
4257             p->icon_geom.size.width = data[2];
4258             p->icon_geom.size.height = data[3];
4259         }
4260     }
4261 
4262     if (dirty & WMIcon) {
4263         readIcon(p->conn, cookies[c++], p->icons, p->icon_count);
4264         delete[] p->icon_sizes;
4265         p->icon_sizes = nullptr;
4266     }
4267 
4268     if (dirty & WMFrameExtents) {
4269         p->frame_strut = NETStrut();
4270 
4271         QList<uint32_t> data = get_array_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL);
4272 
4273         if (data.isEmpty()) {
4274             data = get_array_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL);
4275         } else {
4276             xcb_discard_reply(p->conn, cookies[c++].sequence);
4277         }
4278 
4279         if (data.count() == 4) {
4280             p->frame_strut.left = data[0];
4281             p->frame_strut.right = data[1];
4282             p->frame_strut.top = data[2];
4283             p->frame_strut.bottom = data[3];
4284         }
4285     }
4286 
4287     if (dirty2 & WM2FrameOverlap) {
4288         p->frame_overlap = NETStrut();
4289 
4290         QList<uint32_t> data = get_array_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL);
4291         if (data.count() == 4) {
4292             p->frame_overlap.left = data[0];
4293             p->frame_overlap.right = data[1];
4294             p->frame_overlap.top = data[2];
4295             p->frame_overlap.bottom = data[3];
4296         }
4297     }
4298 
4299     if (dirty2 & WM2Activities) {
4300         delete[] p->activities;
4301         p->activities = nullptr;
4302 
4303         const QByteArray activities = get_string_reply(p->conn, cookies[c++], XCB_ATOM_STRING);
4304         if (activities.length() > 0) {
4305             p->activities = nstrndup(activities.constData(), activities.length());
4306         }
4307     }
4308 
4309     if (dirty2 & WM2BlockCompositing) {
4310         bool success;
4311         p->blockCompositing = false;
4312 
4313         // _KDE_NET_WM_BLOCK_COMPOSITING
4314         uint32_t data = get_value_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL, 0, &success);
4315         if (success) {
4316             p->blockCompositing = bool(data);
4317         }
4318 
4319         // _NET_WM_BYPASS_COMPOSITOR
4320         data = get_value_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL, 0, &success);
4321         if (success) {
4322             switch (data) {
4323             case 1:
4324                 p->blockCompositing = true;
4325                 break;
4326             case 2:
4327                 p->blockCompositing = false;
4328                 break;
4329             default:
4330                 break; // yes, the standard /is/ that stupid.
4331             }
4332         }
4333     }
4334 
4335     if (dirty & WMPid) {
4336         p->pid = get_value_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL, 0);
4337     }
4338 
4339     if (dirty2 & WM2StartupId) {
4340         delete[] p->startup_id;
4341         p->startup_id = nullptr;
4342 
4343         const QByteArray id = get_string_reply(p->conn, cookies[c++], p->atom(UTF8_STRING));
4344         if (id.length() > 0) {
4345             p->startup_id = nstrndup(id.constData(), id.length());
4346         }
4347     }
4348 
4349     if (dirty2 & WM2Opacity) {
4350         p->opacity = get_value_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL, 0xffffffff);
4351     }
4352 
4353     if (dirty2 & WM2AllowedActions) {
4354         p->allowed_actions = NET::Actions();
4355 
4356         const QList<xcb_atom_t> actions = get_array_reply<xcb_atom_t>(p->conn, cookies[c++], XCB_ATOM_ATOM);
4357         if (!actions.isEmpty()) {
4358 #ifdef NETWMDEBUG
4359             fprintf(stderr, "NETWinInfo::update: updating allowed actions (%ld)\n", actions.count());
4360 #endif
4361 
4362             for (const xcb_atom_t action : actions) {
4363 #ifdef NETWMDEBUG
4364                 const QByteArray name = get_atom_name(p->conn, action);
4365                 fprintf(stderr, "NETWinInfo::update:   adding allowed action %ld '%s'\n", action, name.constData());
4366 #endif
4367                 if (action == p->atom(_NET_WM_ACTION_MOVE)) {
4368                     p->allowed_actions |= ActionMove;
4369                 }
4370 
4371                 else if (action == p->atom(_NET_WM_ACTION_RESIZE)) {
4372                     p->allowed_actions |= ActionResize;
4373                 }
4374 
4375                 else if (action == p->atom(_NET_WM_ACTION_MINIMIZE)) {
4376                     p->allowed_actions |= ActionMinimize;
4377                 }
4378 
4379                 else if (action == p->atom(_NET_WM_ACTION_SHADE)) {
4380                     p->allowed_actions |= ActionShade;
4381                 }
4382 
4383                 else if (action == p->atom(_NET_WM_ACTION_STICK)) {
4384                     p->allowed_actions |= ActionStick;
4385                 }
4386 
4387                 else if (action == p->atom(_NET_WM_ACTION_MAXIMIZE_VERT)) {
4388                     p->allowed_actions |= ActionMaxVert;
4389                 }
4390 
4391                 else if (action == p->atom(_NET_WM_ACTION_MAXIMIZE_HORZ)) {
4392                     p->allowed_actions |= ActionMaxHoriz;
4393                 }
4394 
4395                 else if (action == p->atom(_NET_WM_ACTION_FULLSCREEN)) {
4396                     p->allowed_actions |= ActionFullScreen;
4397                 }
4398 
4399                 else if (action == p->atom(_NET_WM_ACTION_CHANGE_DESKTOP)) {
4400                     p->allowed_actions |= ActionChangeDesktop;
4401                 }
4402 
4403                 else if (action == p->atom(_NET_WM_ACTION_CLOSE)) {
4404                     p->allowed_actions |= ActionClose;
4405                 }
4406             }
4407         }
4408     }
4409 
4410     if (dirty2 & WM2UserTime) {
4411         p->user_time = -1U;
4412 
4413         bool success;
4414         uint32_t value = get_value_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL, 0, &success);
4415 
4416         if (success) {
4417             p->user_time = value;
4418         }
4419     }
4420 
4421     if (dirty2 & WM2TransientFor) {
4422         p->transient_for = get_value_reply<xcb_window_t>(p->conn, cookies[c++], XCB_ATOM_WINDOW, 0);
4423     }
4424 
4425     if (dirty2 & (WM2GroupLeader | WM2Urgency | WM2Input | WM2InitialMappingState | WM2IconPixmap)) {
4426         xcb_get_property_reply_t *reply = xcb_get_property_reply(p->conn, cookies[c++], nullptr);
4427 
4428         if (reply && reply->format == 32 && reply->value_len == 9 && reply->type == XCB_ATOM_WM_HINTS) {
4429             kde_wm_hints *hints = reinterpret_cast<kde_wm_hints *>(xcb_get_property_value(reply));
4430 
4431             if (hints->flags & (1 << 0) /*Input*/) {
4432                 p->input = hints->input;
4433             }
4434             if (hints->flags & (1 << 1) /*StateHint*/) {
4435                 switch (hints->initial_state) {
4436                 case 3: // IconicState
4437                     p->initialMappingState = Iconic;
4438                     break;
4439 
4440                 case 1: // NormalState
4441                     p->initialMappingState = Visible;
4442                     break;
4443 
4444                 case 0: // WithdrawnState
4445                 default:
4446                     p->initialMappingState = Withdrawn;
4447                     break;
4448                 }
4449             }
4450             if (hints->flags & (1 << 2) /*IconPixmapHint*/) {
4451                 p->icon_pixmap = hints->icon_pixmap;
4452             }
4453             if (hints->flags & (1 << 5) /*IconMaskHint*/) {
4454                 p->icon_mask = hints->icon_mask;
4455             }
4456             if (hints->flags & (1 << 6) /*WindowGroupHint*/) {
4457                 p->window_group = hints->window_group;
4458             }
4459             p->urgency = (hints->flags & (1 << 8) /*UrgencyHint*/);
4460         }
4461 
4462         if (reply) {
4463             free(reply);
4464         }
4465     }
4466 
4467     if (dirty2 & WM2WindowClass) {
4468         delete[] p->class_name;
4469         delete[] p->class_class;
4470         p->class_name = nullptr;
4471         p->class_class = nullptr;
4472 
4473         const QList<QByteArray> list = get_stringlist_reply(p->conn, cookies[c++], XCB_ATOM_STRING);
4474         if (list.count() == 2) {
4475             p->class_name = nstrdup(list.at(0).constData());
4476             p->class_class = nstrdup(list.at(1).constData());
4477         } else if (list.count() == 1) { // Not fully compliant client. Provides a single string
4478             p->class_name = nstrdup(list.at(0).constData());
4479             p->class_class = nstrdup(list.at(0).constData());
4480         }
4481     }
4482 
4483     if (dirty2 & WM2WindowRole) {
4484         delete[] p->window_role;
4485         p->window_role = nullptr;
4486 
4487         const QByteArray role = get_string_reply(p->conn, cookies[c++], XCB_ATOM_STRING);
4488         if (role.length() > 0) {
4489             p->window_role = nstrndup(role.constData(), role.length());
4490         }
4491     }
4492 
4493     if (dirty2 & WM2ClientMachine) {
4494         delete[] p->client_machine;
4495         p->client_machine = nullptr;
4496 
4497         const QByteArray value = get_string_reply(p->conn, cookies[c++], XCB_ATOM_STRING);
4498         if (value.length() > 0) {
4499             p->client_machine = nstrndup(value.constData(), value.length());
4500         }
4501     }
4502 
4503     if (dirty2 & WM2Protocols) {
4504         const QList<xcb_atom_t> protocols = get_array_reply<xcb_atom_t>(p->conn, cookies[c++], XCB_ATOM_ATOM);
4505         p->protocols = NET::NoProtocol;
4506         for (auto it = protocols.begin(); it != protocols.end(); ++it) {
4507             if ((*it) == p->atom(WM_TAKE_FOCUS)) {
4508                 p->protocols |= TakeFocusProtocol;
4509             } else if ((*it) == p->atom(WM_DELETE_WINDOW)) {
4510                 p->protocols |= DeleteWindowProtocol;
4511             } else if ((*it) == p->atom(_NET_WM_PING)) {
4512                 p->protocols |= PingProtocol;
4513             } else if ((*it) == p->atom(_NET_WM_SYNC_REQUEST)) {
4514                 p->protocols |= SyncRequestProtocol;
4515             } else if ((*it) == p->atom(_NET_WM_CONTEXT_HELP)) {
4516                 p->protocols |= ContextHelpProtocol;
4517             }
4518         }
4519     }
4520 
4521     if (dirty2 & WM2OpaqueRegion) {
4522         const QList<qint32> values = get_array_reply<qint32>(p->conn, cookies[c++], XCB_ATOM_CARDINAL);
4523         p->opaqueRegion.clear();
4524         p->opaqueRegion.reserve(values.count() / 4);
4525         for (int i = 0; i < values.count() - 3; i += 4) {
4526             NETRect rect;
4527             rect.pos.x = values.at(i);
4528             rect.pos.y = values.at(i + 1);
4529             rect.size.width = values.at(i + 2);
4530             rect.size.height = values.at(i + 3);
4531             p->opaqueRegion.push_back(rect);
4532         }
4533     }
4534 
4535     if (dirty2 & WM2DesktopFileName) {
4536         delete[] p->desktop_file;
4537         p->desktop_file = nullptr;
4538 
4539         const QByteArray id = get_string_reply(p->conn, cookies[c++], p->atom(UTF8_STRING));
4540         if (id.length() > 0) {
4541             p->desktop_file = nstrndup(id.constData(), id.length());
4542         }
4543     }
4544 
4545     if (dirty2 & WM2GTKApplicationId) {
4546         delete[] p->gtk_application_id;
4547         p->gtk_application_id = nullptr;
4548 
4549         const QByteArray id = get_string_reply(p->conn, cookies[c++], p->atom(UTF8_STRING));
4550         if (id.length() > 0) {
4551             p->gtk_application_id = nstrndup(id.constData(), id.length());
4552         }
4553     }
4554 
4555     if (dirty2 & WM2GTKFrameExtents) {
4556         p->gtk_frame_extents = NETStrut();
4557 
4558         QList<uint32_t> data = get_array_reply<uint32_t>(p->conn, cookies[c++], XCB_ATOM_CARDINAL);
4559         if (data.count() == 4) {
4560             p->gtk_frame_extents.left = data[0];
4561             p->gtk_frame_extents.right = data[1];
4562             p->gtk_frame_extents.top = data[2];
4563             p->gtk_frame_extents.bottom = data[3];
4564         }
4565     }
4566 
4567     if (dirty2 & WM2AppMenuObjectPath) {
4568         delete[] p->appmenu_object_path;
4569         p->appmenu_object_path = nullptr;
4570 
4571         const QByteArray id = get_string_reply(p->conn, cookies[c++], XCB_ATOM_STRING);
4572         if (id.length() > 0) {
4573             p->appmenu_object_path = nstrndup(id.constData(), id.length());
4574         }
4575     }
4576 
4577     if (dirty2 & WM2AppMenuServiceName) {
4578         delete[] p->appmenu_service_name;
4579         p->appmenu_service_name = nullptr;
4580 
4581         const QByteArray id = get_string_reply(p->conn, cookies[c++], XCB_ATOM_STRING);
4582         if (id.length() > 0) {
4583             p->appmenu_service_name = nstrndup(id.constData(), id.length());
4584         }
4585     }
4586 }
4587 
4588 NETRect NETWinInfo::iconGeometry() const
4589 {
4590     return p->icon_geom;
4591 }
4592 
4593 NET::States NETWinInfo::state() const
4594 {
4595     return p->state;
4596 }
4597 
4598 NETStrut NETWinInfo::strut() const
4599 {
4600     return p->strut;
4601 }
4602 
4603 NETExtendedStrut NETWinInfo::extendedStrut() const
4604 {
4605     return p->extended_strut;
4606 }
4607 
4608 NETFullscreenMonitors NETWinInfo::fullscreenMonitors() const
4609 {
4610     return p->fullscreen_monitors;
4611 }
4612 
4613 bool NET::typeMatchesMask(WindowType type, WindowTypes mask)
4614 {
4615     switch (type) {
4616         // clang-format off
4617 #define CHECK_TYPE_MASK( type ) \
4618 case type: \
4619     if( mask & type##Mask ) \
4620         return true; \
4621     break;
4622         // clang-format on
4623         CHECK_TYPE_MASK(Normal)
4624         CHECK_TYPE_MASK(Desktop)
4625         CHECK_TYPE_MASK(Dock)
4626         CHECK_TYPE_MASK(Toolbar)
4627         CHECK_TYPE_MASK(Menu)
4628         CHECK_TYPE_MASK(Dialog)
4629         CHECK_TYPE_MASK(Override)
4630         CHECK_TYPE_MASK(TopMenu)
4631         CHECK_TYPE_MASK(Utility)
4632         CHECK_TYPE_MASK(Splash)
4633         CHECK_TYPE_MASK(DropdownMenu)
4634         CHECK_TYPE_MASK(PopupMenu)
4635         CHECK_TYPE_MASK(Tooltip)
4636         CHECK_TYPE_MASK(Notification)
4637         CHECK_TYPE_MASK(ComboBox)
4638         CHECK_TYPE_MASK(DNDIcon)
4639         CHECK_TYPE_MASK(OnScreenDisplay)
4640         CHECK_TYPE_MASK(CriticalNotification)
4641         CHECK_TYPE_MASK(AppletPopup)
4642 #undef CHECK_TYPE_MASK
4643     default:
4644         break;
4645     }
4646     return false;
4647 }
4648 
4649 NET::WindowType NETWinInfo::windowType(WindowTypes supported_types) const
4650 {
4651     for (int i = 0; i < p->types.size(); ++i) {
4652         // return the type only if the application supports it
4653         if (typeMatchesMask(p->types[i], supported_types)) {
4654             return p->types[i];
4655         }
4656     }
4657     return Unknown;
4658 }
4659 
4660 bool NETWinInfo::hasWindowType() const
4661 {
4662     return p->types.size() > 0;
4663 }
4664 
4665 const char *NETWinInfo::name() const
4666 {
4667     return p->name;
4668 }
4669 
4670 const char *NETWinInfo::visibleName() const
4671 {
4672     return p->visible_name;
4673 }
4674 
4675 const char *NETWinInfo::iconName() const
4676 {
4677     return p->icon_name;
4678 }
4679 
4680 const char *NETWinInfo::visibleIconName() const
4681 {
4682     return p->visible_icon_name;
4683 }
4684 
4685 int NETWinInfo::desktop(bool ignore_viewport) const
4686 {
4687     if (!ignore_viewport && KX11Extras::mapViewport()) {
4688         const KWindowInfo info(p->window, NET::WMDesktop);
4689         return info.desktop();
4690     }
4691     return p->desktop;
4692 }
4693 
4694 int NETWinInfo::pid() const
4695 {
4696     return p->pid;
4697 }
4698 
4699 xcb_timestamp_t NETWinInfo::userTime() const
4700 {
4701     return p->user_time;
4702 }
4703 
4704 const char *NETWinInfo::startupId() const
4705 {
4706     return p->startup_id;
4707 }
4708 
4709 unsigned long NETWinInfo::opacity() const
4710 {
4711     return p->opacity;
4712 }
4713 
4714 qreal NETWinInfo::opacityF() const
4715 {
4716     if (p->opacity == 0xffffffff) {
4717         return 1.0;
4718     }
4719     return p->opacity * 1.0 / 0xffffffff;
4720 }
4721 
4722 NET::Actions NETWinInfo::allowedActions() const
4723 {
4724     return p->allowed_actions;
4725 }
4726 
4727 bool NETWinInfo::hasNETSupport() const
4728 {
4729     return p->has_net_support;
4730 }
4731 
4732 xcb_window_t NETWinInfo::transientFor() const
4733 {
4734     return p->transient_for;
4735 }
4736 
4737 xcb_window_t NETWinInfo::groupLeader() const
4738 {
4739     return p->window_group;
4740 }
4741 
4742 bool NETWinInfo::urgency() const
4743 {
4744     return p->urgency;
4745 }
4746 
4747 bool NETWinInfo::input() const
4748 {
4749     return p->input;
4750 }
4751 
4752 NET::MappingState NETWinInfo::initialMappingState() const
4753 {
4754     return p->initialMappingState;
4755 }
4756 
4757 xcb_pixmap_t NETWinInfo::icccmIconPixmap() const
4758 {
4759     return p->icon_pixmap;
4760 }
4761 
4762 xcb_pixmap_t NETWinInfo::icccmIconPixmapMask() const
4763 {
4764     return p->icon_mask;
4765 }
4766 
4767 const char *NETWinInfo::windowClassClass() const
4768 {
4769     return p->class_class;
4770 }
4771 
4772 const char *NETWinInfo::windowClassName() const
4773 {
4774     return p->class_name;
4775 }
4776 
4777 const char *NETWinInfo::windowRole() const
4778 {
4779     return p->window_role;
4780 }
4781 
4782 const char *NETWinInfo::clientMachine() const
4783 {
4784     return p->client_machine;
4785 }
4786 
4787 const char *NETWinInfo::activities() const
4788 {
4789     return p->activities;
4790 }
4791 
4792 void NETWinInfo::setActivities(const char *activities)
4793 {
4794     delete[] p->activities;
4795 
4796     if (activities == (char *)nullptr || activities[0] == '\0') {
4797         // on all activities
4798         static const char nulluuid[] = KDE_ALL_ACTIVITIES_UUID;
4799 
4800         p->activities = nstrdup(nulluuid);
4801 
4802     } else {
4803         p->activities = nstrdup(activities);
4804     }
4805 
4806     xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_KDE_NET_WM_ACTIVITIES), XCB_ATOM_STRING, 8, strlen(p->activities), p->activities);
4807 }
4808 
4809 void NETWinInfo::setBlockingCompositing(bool active)
4810 {
4811     if (p->role != Client) {
4812         return;
4813     }
4814 
4815     p->blockCompositing = active;
4816     if (active) {
4817         uint32_t d = 1;
4818         xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_KDE_NET_WM_BLOCK_COMPOSITING), XCB_ATOM_CARDINAL, 32, 1, (const void *)&d);
4819         xcb_change_property(p->conn, XCB_PROP_MODE_REPLACE, p->window, p->atom(_NET_WM_BYPASS_COMPOSITOR), XCB_ATOM_CARDINAL, 32, 1, (const void *)&d);
4820     } else {
4821         xcb_delete_property(p->conn, p->window, p->atom(_KDE_NET_WM_BLOCK_COMPOSITING));
4822         xcb_delete_property(p->conn, p->window, p->atom(_NET_WM_BYPASS_COMPOSITOR));
4823     }
4824 }
4825 
4826 bool NETWinInfo::isBlockingCompositing() const
4827 {
4828     return p->blockCompositing;
4829 }
4830 
4831 bool NETWinInfo::handledIcons() const
4832 {
4833     return p->handled_icons;
4834 }
4835 
4836 NET::Properties NETWinInfo::passedProperties() const
4837 {
4838     return p->properties;
4839 }
4840 
4841 NET::Properties2 NETWinInfo::passedProperties2() const
4842 {
4843     return p->properties2;
4844 }
4845 
4846 NET::MappingState NETWinInfo::mappingState() const
4847 {
4848     return p->mapping_state;
4849 }
4850 
4851 NET::Protocols NETWinInfo::protocols() const
4852 {
4853     return p->protocols;
4854 }
4855 
4856 bool NETWinInfo::supportsProtocol(NET::Protocol protocol) const
4857 {
4858     return p->protocols.testFlag(protocol);
4859 }
4860 
4861 std::vector<NETRect> NETWinInfo::opaqueRegion() const
4862 {
4863     return p->opaqueRegion;
4864 }
4865 
4866 xcb_connection_t *NETWinInfo::xcbConnection() const
4867 {
4868     return p->conn;
4869 }
4870 
4871 void NETWinInfo::setDesktopFileName(const char *name)
4872 {
4873     if (p->role != Client) {
4874         return;
4875     }
4876 
4877     delete[] p->desktop_file;
4878     p->desktop_file = nstrdup(name);
4879 
4880     xcb_change_property(p->conn,
4881                         XCB_PROP_MODE_REPLACE,
4882                         p->window,
4883                         p->atom(_KDE_NET_WM_DESKTOP_FILE),
4884                         p->atom(UTF8_STRING),
4885                         8,
4886                         strlen(p->desktop_file),
4887                         (const void *)p->desktop_file);
4888 }
4889 
4890 const char *NETWinInfo::desktopFileName() const
4891 {
4892     return p->desktop_file;
4893 }
4894 
4895 const char *NETWinInfo::gtkApplicationId() const
4896 {
4897     return p->gtk_application_id;
4898 }
4899 
4900 void NETRootInfo::virtual_hook(int, void *)
4901 {
4902     /*BASE::virtual_hook( id, data );*/
4903 }
4904 
4905 void NETWinInfo::virtual_hook(int, void *)
4906 {
4907     /*BASE::virtual_hook( id, data );*/
4908 }
4909 
4910 int NET::timestampCompare(unsigned long time1, unsigned long time2)
4911 {
4912     return KXUtils::timestampCompare(time1, time2);
4913 }
4914 
4915 int NET::timestampDiff(unsigned long time1, unsigned long time2)
4916 {
4917     return KXUtils::timestampDiff(time1, time2);
4918 }
4919 
4920 #endif