File indexing completed on 2024-05-05 16:19:56

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