1/*
2 SPDX-FileCopyrightText: 2000 Troll Tech AS
3 SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org>
4
5 SPDX-License-Identifier: MIT
6*/
7
8//#define NETWMDEBUG
9#include "netwm.h"
10
11#include <xcb/xproto.h>
12
13#include "atoms_p.h"
14#include "netwm_p.h"
15#include "kxcbevent_p.h"
16
17#if KWINDOWSYSTEM_HAVE_X11 // FIXME
18
19#include <QGuiApplication>
20#include <QHash>
21
22#include <private/qtx11extras_p.h>
23
24#include <kwindowinfo.h>
25#include <kwindowsystem.h>
26#include <kx11extras.h>
27#include <kxutils_p.h>
28
29#include <assert.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33
34// This struct is defined here to avoid a dependency on xcb-icccm
35struct kde_wm_hints {
36 uint32_t flags;
37 uint32_t input;
38 int32_t initial_state;
39 xcb_pixmap_t icon_pixmap;
40 xcb_window_t icon_window;
41 int32_t icon_x;
42 int32_t icon_y;
43 xcb_pixmap_t icon_mask;
44 xcb_window_t window_group;
45};
46
47typedef QHash<xcb_connection_t *, QSharedDataPointer<Atoms>> AtomHash;
48Q_GLOBAL_STATIC(AtomHash, s_gAtomsHash)
49
50static QSharedDataPointer<Atoms> atomsForConnection(xcb_connection_t *c)
51{
52 auto it = s_gAtomsHash->constFind(key: c);
53 if (it == s_gAtomsHash->constEnd()) {
54 QSharedDataPointer<Atoms> atom(new Atoms(c));
55 s_gAtomsHash->insert(key: c, value: atom);
56 return atom;
57 }
58 return it.value();
59}
60
61Atoms::Atoms(xcb_connection_t *c)
62 : QSharedData()
63 , m_connection(c)
64{
65 for (int i = 0; i < KwsAtomCount; ++i) {
66 m_atoms[i] = XCB_ATOM_NONE;
67 }
68 init();
69}
70
71static const uint32_t netwm_sendevent_mask = (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY);
72
73const long MAX_PROP_SIZE = 100000;
74
75static char *nstrdup(const char *s1)
76{
77 if (!s1) {
78 return (char *)nullptr;
79 }
80
81 int l = strlen(s: s1) + 1;
82 char *s2 = new char[l];
83 strncpy(dest: s2, src: s1, n: l);
84 return s2;
85}
86
87static char *nstrndup(const char *s1, int l)
88{
89 if (!s1 || l == 0) {
90 return (char *)nullptr;
91 }
92
93 char *s2 = new char[l + 1];
94 strncpy(dest: s2, src: s1, n: l);
95 s2[l] = '\0';
96 return s2;
97}
98
99static xcb_window_t *nwindup(const xcb_window_t *w1, int n)
100{
101 if (!w1 || n == 0) {
102 return (xcb_window_t *)nullptr;
103 }
104
105 xcb_window_t *w2 = new xcb_window_t[n];
106 while (n--) {
107 w2[n] = w1[n];
108 }
109 return w2;
110}
111
112static void refdec_nri(NETRootInfoPrivate *p)
113{
114#ifdef NETWMDEBUG
115 fprintf(stderr, "NET: decrementing NETRootInfoPrivate::ref (%d)\n", p->ref - 1);
116#endif
117
118 if (!--p->ref) {
119#ifdef NETWMDEBUG
120 fprintf(stderr, "NET: \tno more references, deleting\n");
121#endif
122
123 delete[] p->name;
124 delete[] p->stacking;
125 delete[] p->clients;
126 delete[] p->virtual_roots;
127 delete[] p->temp_buf;
128
129 int i;
130 for (i = 0; i < p->desktop_names.size(); i++) {
131 delete[] p->desktop_names[i];
132 }
133 }
134}
135
136static void refdec_nwi(NETWinInfoPrivate *p)
137{
138#ifdef NETWMDEBUG
139 fprintf(stderr, "NET: decrementing NETWinInfoPrivate::ref (%d)\n", p->ref - 1);
140#endif
141
142 if (!--p->ref) {
143#ifdef NETWMDEBUG
144 fprintf(stderr, "NET: \tno more references, deleting\n");
145#endif
146
147 delete[] p->name;
148 delete[] p->visible_name;
149 delete[] p->window_role;
150 delete[] p->icon_name;
151 delete[] p->visible_icon_name;
152 delete[] p->startup_id;
153 delete[] p->class_class;
154 delete[] p->class_name;
155 delete[] p->activities;
156 delete[] p->client_machine;
157 delete[] p->desktop_file;
158 delete[] p->gtk_application_id;
159 delete[] p->appmenu_object_path;
160 delete[] p->appmenu_service_name;
161
162 int i;
163 for (i = 0; i < p->icons.size(); i++) {
164 delete[] p->icons[i].data;
165 }
166 delete[] p->icon_sizes;
167 }
168}
169
170template<typename T>
171T get_value_reply(xcb_connection_t *c, const xcb_get_property_cookie_t cookie, xcb_atom_t type, T def, bool *success = nullptr)
172{
173 T value = def;
174
175 xcb_get_property_reply_t *reply = xcb_get_property_reply(c, cookie, e: nullptr);
176
177 if (success) {
178 *success = false;
179 }
180
181 if (reply) {
182 if (reply->type == type && reply->value_len == 1 && reply->format == sizeof(T) * 8) {
183 value = *reinterpret_cast<T *>(xcb_get_property_value(R: reply));
184
185 if (success) {
186 *success = true;
187 }
188 }
189
190 free(ptr: reply);
191 }
192
193 return value;
194}
195
196template<typename T>
197QList<T> get_array_reply(xcb_connection_t *c, const xcb_get_property_cookie_t cookie, xcb_atom_t type)
198{
199 xcb_get_property_reply_t *reply = xcb_get_property_reply(c, cookie, e: nullptr);
200 if (!reply) {
201 return QList<T>();
202 }
203
204 QList<T> vector;
205
206 if (reply->type == type && reply->value_len > 0 && reply->format == sizeof(T) * 8) {
207 T *data = reinterpret_cast<T *>(xcb_get_property_value(R: reply));
208
209 vector.resize(reply->value_len);
210 memcpy(dest: (void *)&vector.first(), src: (void *)data, n: reply->value_len * sizeof(T));
211 }
212
213 free(ptr: reply);
214 return vector;
215}
216
217static QByteArray get_string_reply(xcb_connection_t *c, const xcb_get_property_cookie_t cookie, xcb_atom_t type)
218{
219 xcb_get_property_reply_t *reply = xcb_get_property_reply(c, cookie, e: nullptr);
220 if (!reply) {
221 return QByteArray();
222 }
223
224 QByteArray value;
225
226 if (reply->type == type && reply->format == 8 && reply->value_len > 0) {
227 const char *data = (const char *)xcb_get_property_value(R: reply);
228 int len = reply->value_len;
229
230 if (data) {
231 value = QByteArray(data, data[len - 1] ? len : len - 1);
232 }
233 }
234
235 free(ptr: reply);
236 return value;
237}
238
239static QList<QByteArray> get_stringlist_reply(xcb_connection_t *c, const xcb_get_property_cookie_t cookie, xcb_atom_t type)
240{
241 xcb_get_property_reply_t *reply = xcb_get_property_reply(c, cookie, e: nullptr);
242 if (!reply) {
243 return QList<QByteArray>();
244 }
245
246 QList<QByteArray> list;
247
248 if (reply->type == type && reply->format == 8 && reply->value_len > 0) {
249 const char *data = (const char *)xcb_get_property_value(R: reply);
250 int len = reply->value_len;
251
252 if (data) {
253 const QByteArray ba = QByteArray(data, data[len - 1] ? len : len - 1);
254 list = ba.split(sep: '\0');
255 }
256 }
257
258 free(ptr: reply);
259 return list;
260}
261
262#ifdef NETWMDEBUG
263static QByteArray get_atom_name(xcb_connection_t *c, xcb_atom_t atom)
264{
265 const xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(c, atom);
266
267 xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(c, cookie, 0);
268 if (!reply) {
269 return QByteArray();
270 }
271
272 QByteArray ba(xcb_get_atom_name_name(reply));
273 free(reply);
274
275 return ba;
276}
277#endif
278
279void Atoms::init()
280{
281#define ENUM_CREATE_CHAR_ARRAY 1
282#include "atoms_p.h" // creates const char* array "KwsAtomStrings"
283 // Send the intern atom requests
284 xcb_intern_atom_cookie_t cookies[KwsAtomCount];
285 for (int i = 0; i < KwsAtomCount; ++i) {
286 cookies[i] = xcb_intern_atom(c: m_connection, only_if_exists: false, name_len: strlen(s: KwsAtomStrings[i]), name: KwsAtomStrings[i]);
287 }
288
289 // Get the replies
290 for (int i = 0; i < KwsAtomCount; ++i) {
291 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(c: m_connection, cookie: cookies[i], e: nullptr);
292 if (!reply) {
293 continue;
294 }
295
296 m_atoms[i] = reply->atom;
297 free(ptr: reply);
298 }
299}
300
301static void readIcon(xcb_connection_t *c, const xcb_get_property_cookie_t cookie, NETRArray<NETIcon> &icons, int &icon_count)
302{
303#ifdef NETWMDEBUG
304 fprintf(stderr, "NET: readIcon\n");
305#endif
306
307 // reset
308 for (int i = 0; i < icons.size(); i++) {
309 delete[] icons[i].data;
310 }
311
312 icons.reset();
313 icon_count = 0;
314
315 xcb_get_property_reply_t *reply = xcb_get_property_reply(c, cookie, e: nullptr);
316
317 if (!reply || reply->value_len < 3 || reply->format != 32 || reply->type != XCB_ATOM_CARDINAL) {
318 if (reply) {
319 free(ptr: reply);
320 }
321
322 return;
323 }
324
325 uint32_t *data = (uint32_t *)xcb_get_property_value(R: reply);
326
327 for (unsigned int i = 0, j = 0; j < reply->value_len - 2; i++) {
328 uint32_t width = data[j++];
329 uint32_t height = data[j++];
330 uint32_t size = width * height * sizeof(uint32_t);
331 if (j + width * height > reply->value_len) {
332 fprintf(stderr, format: "Ill-encoded icon data; proposed size leads to out of bounds access. Skipping. (%d x %d)\n", width, height);
333 break;
334 }
335 if (width > 1024 || height > 1024) {
336 fprintf(stderr, format: "Warning: found huge icon. The icon data may be ill-encoded. (%d x %d)\n", width, height);
337 // 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
338 // system is abused to transfer wallpapers or such.
339 }
340
341 icons[i].size.width = width;
342 icons[i].size.height = height;
343 icons[i].data = new unsigned char[size];
344
345 memcpy(dest: (void *)icons[i].data, src: (const void *)&data[j], n: size);
346
347 j += width * height;
348 icon_count++;
349 }
350
351 free(ptr: reply);
352
353#ifdef NETWMDEBUG
354 fprintf(stderr, "NET: readIcon got %d icons\n", icon_count);
355#endif
356}
357
358static 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[])
359{
360 KXcbEvent<xcb_client_message_event_t> event;
361 event.response_type = XCB_CLIENT_MESSAGE;
362 event.format = 32;
363 event.sequence = 0;
364 event.window = window;
365 event.type = message;
366
367 for (int i = 0; i < 5; i++) {
368 event.data.data32[i] = data[i];
369 }
370
371 xcb_send_event(c, propagate: false, destination, event_mask: mask, event: event.buffer());
372}
373
374template<class Z>
375NETRArray<Z>::NETRArray()
376 : sz(0)
377 , capacity(2)
378{
379 d = (Z *)calloc(nmemb: capacity, size: sizeof(Z)); // allocate 2 elts and set to zero
380}
381
382template<class Z>
383NETRArray<Z>::~NETRArray()
384{
385 free(d);
386}
387
388template<class Z>
389void NETRArray<Z>::reset()
390{
391 sz = 0;
392 capacity = 2;
393 d = (Z *)realloc(d, sizeof(Z) * capacity);
394 memset(s: (void *)d, c: 0, n: sizeof(Z) * capacity);
395}
396
397template<class Z>
398Z &NETRArray<Z>::operator[](int index)
399{
400 if (index >= capacity) {
401 // allocate space for the new data
402 // open table has amortized O(1) access time
403 // when N elements appended consecutively -- exa
404 int newcapacity = 2 * capacity > index + 1 ? 2 * capacity : index + 1; // max
405 // copy into new larger memory block using realloc
406 d = (Z *)realloc(d, sizeof(Z) * newcapacity);
407 memset(s: (void *)&d[capacity], c: 0, n: sizeof(Z) * (newcapacity - capacity));
408 capacity = newcapacity;
409 }
410 if (index >= sz) { // at this point capacity>index
411 sz = index + 1;
412 }
413
414 return d[index];
415}
416
417/*
418 The viewport<->desktop matching is a bit backwards, since NET* classes are the base
419 (and were originally even created with the intention of being the reference WM spec
420 implementation) and KWindowSystem builds on top of it. However it's simpler to add watching
421 whether the WM uses viewport is simpler to KWindowSystem and not having this mapping
422 in NET* classes could result in some code using it directly and not supporting viewport.
423 So NET* classes check if mapping is needed and if yes they forward to KWindowSystem,
424 which will forward again back to NET* classes, but to viewport calls instead of desktop calls.
425*/
426
427// Construct a new NETRootInfo object.
428
429NETRootInfo::NETRootInfo(xcb_connection_t *connection,
430 xcb_window_t supportWindow,
431 const char *wmName,
432 NET::Properties properties,
433 NET::WindowTypes windowTypes,
434 NET::States states,
435 NET::Properties2 properties2,
436 NET::Actions actions,
437 int screen,
438 bool doActivate)
439{
440#ifdef NETWMDEBUG
441 fprintf(stderr, "NETRootInfo::NETRootInfo: using window manager constructor\n");
442#endif
443
444 p = new NETRootInfoPrivate;
445 p->ref = 1;
446 p->atoms = atomsForConnection(c: connection);
447
448 p->name = nstrdup(s1: wmName);
449
450 p->conn = connection;
451
452 p->temp_buf = nullptr;
453 p->temp_buf_size = 0;
454
455 const xcb_setup_t *setup = xcb_get_setup(c: p->conn);
456 xcb_screen_iterator_t it = xcb_setup_roots_iterator(R: setup);
457
458 if (screen != -1 && screen < setup->roots_len) {
459 for (int i = 0; i < screen; i++) {
460 xcb_screen_next(i: &it);
461 }
462 }
463
464 p->root = it.data->root;
465 p->supportwindow = supportWindow;
466 p->number_of_desktops = p->current_desktop = 0;
467 p->active = XCB_WINDOW_NONE;
468 p->clients = p->stacking = p->virtual_roots = (xcb_window_t *)nullptr;
469 p->clients_count = p->stacking_count = p->virtual_roots_count = 0;
470 p->showing_desktop = false;
471 p->desktop_layout_orientation = OrientationHorizontal;
472 p->desktop_layout_corner = DesktopLayoutCornerTopLeft;
473 p->desktop_layout_columns = p->desktop_layout_rows = 0;
474 setDefaultProperties();
475 p->properties = properties;
476 p->properties2 = properties2;
477 p->windowTypes = windowTypes;
478 p->states = states;
479 p->actions = actions;
480 // force support for Supported and SupportingWMCheck for window managers
481 p->properties |= (Supported | SupportingWMCheck);
482 p->clientProperties = DesktopNames // the only thing that can be changed by clients
483 | WMPing; // or they can reply to this
484 p->clientProperties2 = WM2DesktopLayout;
485
486 p->role = WindowManager;
487
488 if (doActivate) {
489 activate();
490 }
491}
492
493NETRootInfo::NETRootInfo(xcb_connection_t *connection, NET::Properties properties, NET::Properties2 properties2, int screen, bool doActivate)
494{
495#ifdef NETWMDEBUG
496 fprintf(stderr, "NETRootInfo::NETRootInfo: using Client constructor\n");
497#endif
498
499 p = new NETRootInfoPrivate;
500 p->ref = 1;
501 p->atoms = atomsForConnection(c: connection);
502
503 p->name = nullptr;
504
505 p->conn = connection;
506
507 p->temp_buf = nullptr;
508 p->temp_buf_size = 0;
509
510 const xcb_setup_t *setup = xcb_get_setup(c: p->conn);
511 xcb_screen_iterator_t it = xcb_setup_roots_iterator(R: setup);
512
513 if (screen != -1 && screen < setup->roots_len) {
514 for (int i = 0; i < screen; i++) {
515 xcb_screen_next(i: &it);
516 }
517 }
518
519 p->root = it.data->root;
520 p->rootSize.width = it.data->width_in_pixels;
521 p->rootSize.height = it.data->height_in_pixels;
522
523 p->supportwindow = XCB_WINDOW_NONE;
524 p->number_of_desktops = p->current_desktop = 0;
525 p->active = XCB_WINDOW_NONE;
526 p->clients = p->stacking = p->virtual_roots = (xcb_window_t *)nullptr;
527 p->clients_count = p->stacking_count = p->virtual_roots_count = 0;
528 p->showing_desktop = false;
529 p->desktop_layout_orientation = OrientationHorizontal;
530 p->desktop_layout_corner = DesktopLayoutCornerTopLeft;
531 p->desktop_layout_columns = p->desktop_layout_rows = 0;
532 setDefaultProperties();
533 p->clientProperties = properties;
534 p->clientProperties2 = properties2;
535 p->properties = NET::Properties();
536 p->properties2 = NET::Properties2();
537 p->windowTypes = NET::WindowTypes();
538 p->states = NET::States();
539 p->actions = NET::Actions();
540
541 p->role = Client;
542
543 if (doActivate) {
544 activate();
545 }
546}
547
548// Copy an existing NETRootInfo object.
549
550NETRootInfo::NETRootInfo(const NETRootInfo &rootinfo)
551{
552#ifdef NETWMDEBUG
553 fprintf(stderr, "NETRootInfo::NETRootInfo: using copy constructor\n");
554#endif
555
556 p = rootinfo.p;
557
558 p->ref++;
559}
560
561// Be gone with our NETRootInfo.
562
563NETRootInfo::~NETRootInfo()
564{
565 refdec_nri(p);
566
567 if (!p->ref) {
568 delete p;
569 }
570}
571
572void NETRootInfo::setDefaultProperties()
573{
574 p->properties = Supported | SupportingWMCheck;
575 p->windowTypes = NormalMask | DesktopMask | DockMask | ToolbarMask | MenuMask | DialogMask;
576 p->states = Modal | Sticky | MaxVert | MaxHoriz | Shaded | SkipTaskbar | KeepAbove;
577 p->properties2 = NET::Properties2();
578 p->actions = NET::Actions();
579 p->clientProperties = NET::Properties();
580 p->clientProperties2 = NET::Properties2();
581}
582
583void NETRootInfo::activate()
584{
585 if (p->role == WindowManager) {
586#ifdef NETWMDEBUG
587 fprintf(stderr, "NETRootInfo::activate: setting supported properties on root\n");
588#endif
589
590 setSupported();
591 update(properties: p->clientProperties, properties2: p->clientProperties2);
592 } else {
593#ifdef NETWMDEBUG
594 fprintf(stderr, "NETRootInfo::activate: updating client information\n");
595#endif
596
597 update(properties: p->clientProperties, properties2: p->clientProperties2);
598 }
599}
600
601void NETRootInfo::setClientList(const xcb_window_t *windows, unsigned int count)
602{
603 if (p->role != WindowManager) {
604 return;
605 }
606
607 p->clients_count = count;
608
609 delete[] p->clients;
610 p->clients = nwindup(w1: windows, n: count);
611
612#ifdef NETWMDEBUG
613 fprintf(stderr, "NETRootInfo::setClientList: setting list with %ld windows\n", p->clients_count);
614#endif
615
616 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->root, property: p->atom(atom: _NET_CLIENT_LIST), type: XCB_ATOM_WINDOW, format: 32, data_len: p->clients_count, data: (const void *)windows);
617}
618
619void NETRootInfo::setClientListStacking(const xcb_window_t *windows, unsigned int count)
620{
621 if (p->role != WindowManager) {
622 return;
623 }
624
625 p->stacking_count = count;
626 delete[] p->stacking;
627 p->stacking = nwindup(w1: windows, n: count);
628
629#ifdef NETWMDEBUG
630 fprintf(stderr, "NETRootInfo::setClientListStacking: setting list with %ld windows\n", p->clients_count);
631#endif
632
633 xcb_change_property(c: p->conn,
634 mode: XCB_PROP_MODE_REPLACE,
635 window: p->root,
636 property: p->atom(atom: _NET_CLIENT_LIST_STACKING),
637 type: XCB_ATOM_WINDOW,
638 format: 32,
639 data_len: p->stacking_count,
640 data: (const void *)windows);
641}
642
643void NETRootInfo::setNumberOfDesktops(int numberOfDesktops)
644{
645#ifdef NETWMDEBUG
646 fprintf(stderr, "NETRootInfo::setNumberOfDesktops: setting desktop count to %d (%s)\n", numberOfDesktops, (p->role == WindowManager) ? "WM" : "Client");
647#endif
648
649 if (p->role == WindowManager) {
650 p->number_of_desktops = numberOfDesktops;
651 const uint32_t d = numberOfDesktops;
652 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->root, property: p->atom(atom: _NET_NUMBER_OF_DESKTOPS), type: XCB_ATOM_CARDINAL, format: 32, data_len: 1, data: (const void *)&d);
653 } else {
654 const uint32_t data[5] = {uint32_t(numberOfDesktops), 0, 0, 0, 0};
655
656 send_client_message(c: p->conn, mask: netwm_sendevent_mask, destination: p->root, window: p->root, message: p->atom(atom: _NET_NUMBER_OF_DESKTOPS), data);
657 }
658}
659
660void NETRootInfo::setCurrentDesktop(int desktop, bool ignore_viewport)
661{
662#ifdef NETWMDEBUG
663 fprintf(stderr, "NETRootInfo::setCurrentDesktop: setting current desktop = %d (%s)\n", desktop, (p->role == WindowManager) ? "WM" : "Client");
664#endif
665
666 if (p->role == WindowManager) {
667 p->current_desktop = desktop;
668 uint32_t d = p->current_desktop - 1;
669 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->root, property: p->atom(atom: _NET_CURRENT_DESKTOP), type: XCB_ATOM_CARDINAL, format: 32, data_len: 1, data: (const void *)&d);
670 } else {
671 if (!ignore_viewport && KX11Extras::mapViewport()) {
672 KX11Extras::setCurrentDesktop(desktop);
673 return;
674 }
675
676 const uint32_t data[5] = {uint32_t(desktop - 1), 0, 0, 0, 0};
677
678 send_client_message(c: p->conn, mask: netwm_sendevent_mask, destination: p->root, window: p->root, message: p->atom(atom: _NET_CURRENT_DESKTOP), data);
679 }
680}
681
682void NETRootInfo::setDesktopName(int desktop, const char *desktopName)
683{
684 // Allow setting desktop names even for non-existent desktops, see the spec, sect.3.7.
685 if (desktop < 1) {
686 return;
687 }
688
689 delete[] p->desktop_names[desktop - 1];
690 p->desktop_names[desktop - 1] = nstrdup(s1: desktopName);
691
692 unsigned int i;
693 unsigned int proplen;
694 unsigned int num = ((p->number_of_desktops > p->desktop_names.size()) ? p->number_of_desktops : p->desktop_names.size());
695 for (i = 0, proplen = 0; i < num; i++) {
696 proplen += (p->desktop_names[i] != nullptr ? strlen(s: p->desktop_names[i]) + 1 : 1);
697 }
698
699 char *prop = new char[proplen];
700 char *propp = prop;
701
702 for (i = 0; i < num; i++) {
703 if (p->desktop_names[i]) {
704 strcpy(dest: propp, src: p->desktop_names[i]);
705 propp += strlen(s: p->desktop_names[i]) + 1;
706 } else {
707 *propp++ = '\0';
708 }
709 }
710
711#ifdef NETWMDEBUG
712 fprintf(stderr,
713 "NETRootInfo::setDesktopName(%d, '%s')\n"
714 "NETRootInfo::setDesktopName: total property length = %d",
715 desktop,
716 desktopName,
717 proplen);
718#endif
719
720 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->root, property: p->atom(atom: _NET_DESKTOP_NAMES), type: p->atom(atom: UTF8_STRING), format: 8, data_len: proplen, data: (const void *)prop);
721
722 delete[] prop;
723}
724
725void NETRootInfo::setDesktopGeometry(const NETSize &geometry)
726{
727#ifdef NETWMDEBUG
728 fprintf(stderr, "NETRootInfo::setDesktopGeometry( -- , { %d, %d }) (%s)\n", geometry.width, geometry.height, (p->role == WindowManager) ? "WM" : "Client");
729#endif
730
731 if (p->role == WindowManager) {
732 p->geometry = geometry;
733
734 uint32_t data[2];
735 data[0] = p->geometry.width;
736 data[1] = p->geometry.height;
737
738 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->root, property: p->atom(atom: _NET_DESKTOP_GEOMETRY), type: XCB_ATOM_CARDINAL, format: 32, data_len: 2, data: (const void *)data);
739 } else {
740 uint32_t data[5] = {uint32_t(geometry.width), uint32_t(geometry.height), 0, 0, 0};
741
742 send_client_message(c: p->conn, mask: netwm_sendevent_mask, destination: p->root, window: p->root, message: p->atom(atom: _NET_DESKTOP_GEOMETRY), data);
743 }
744}
745
746void NETRootInfo::setDesktopViewport(int desktop, const NETPoint &viewport)
747{
748#ifdef NETWMDEBUG
749 fprintf(stderr, "NETRootInfo::setDesktopViewport(%d, { %d, %d }) (%s)\n", desktop, viewport.x, viewport.y, (p->role == WindowManager) ? "WM" : "Client");
750#endif
751
752 if (desktop < 1) {
753 return;
754 }
755
756 if (p->role == WindowManager) {
757 p->viewport[desktop - 1] = viewport;
758
759 int d;
760 int i;
761 int l;
762 l = p->number_of_desktops * 2;
763 uint32_t *data = new uint32_t[l];
764 for (d = 0, i = 0; d < p->number_of_desktops; d++) {
765 data[i++] = p->viewport[d].x;
766 data[i++] = p->viewport[d].y;
767 }
768
769 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->root, property: p->atom(atom: _NET_DESKTOP_VIEWPORT), type: XCB_ATOM_CARDINAL, format: 32, data_len: l, data: (const void *)data);
770
771 delete[] data;
772 } else {
773 const uint32_t data[5] = {uint32_t(viewport.x), uint32_t(viewport.y), 0, 0, 0};
774
775 send_client_message(c: p->conn, mask: netwm_sendevent_mask, destination: p->root, window: p->root, message: p->atom(atom: _NET_DESKTOP_VIEWPORT), data);
776 }
777}
778
779void NETRootInfo::setSupported()
780{
781 if (p->role != WindowManager) {
782#ifdef NETWMDEBUG
783 fprintf(stderr, "NETRootInfo::setSupported - role != WindowManager\n");
784#endif
785
786 return;
787 }
788
789 xcb_atom_t atoms[KwsAtomCount];
790 int pnum = 2;
791
792 // Root window properties/messages
793 atoms[0] = p->atom(atom: _NET_SUPPORTED);
794 atoms[1] = p->atom(atom: _NET_SUPPORTING_WM_CHECK);
795
796 if (p->properties & ClientList) {
797 atoms[pnum++] = p->atom(atom: _NET_CLIENT_LIST);
798 }
799
800 if (p->properties & ClientListStacking) {
801 atoms[pnum++] = p->atom(atom: _NET_CLIENT_LIST_STACKING);
802 }
803
804 if (p->properties & NumberOfDesktops) {
805 atoms[pnum++] = p->atom(atom: _NET_NUMBER_OF_DESKTOPS);
806 }
807
808 if (p->properties & DesktopGeometry) {
809 atoms[pnum++] = p->atom(atom: _NET_DESKTOP_GEOMETRY);
810 }
811
812 if (p->properties & DesktopViewport) {
813 atoms[pnum++] = p->atom(atom: _NET_DESKTOP_VIEWPORT);
814 }
815
816 if (p->properties & CurrentDesktop) {
817 atoms[pnum++] = p->atom(atom: _NET_CURRENT_DESKTOP);
818 }
819
820 if (p->properties & DesktopNames) {
821 atoms[pnum++] = p->atom(atom: _NET_DESKTOP_NAMES);
822 }
823
824 if (p->properties & ActiveWindow) {
825 atoms[pnum++] = p->atom(atom: _NET_ACTIVE_WINDOW);
826 }
827
828 if (p->properties & WorkArea) {
829 atoms[pnum++] = p->atom(atom: _NET_WORKAREA);
830 }
831
832 if (p->properties & VirtualRoots) {
833 atoms[pnum++] = p->atom(atom: _NET_VIRTUAL_ROOTS);
834 }
835
836 if (p->properties2 & WM2DesktopLayout) {
837 atoms[pnum++] = p->atom(atom: _NET_DESKTOP_LAYOUT);
838 }
839
840 if (p->properties & CloseWindow) {
841 atoms[pnum++] = p->atom(atom: _NET_CLOSE_WINDOW);
842 }
843
844 if (p->properties2 & WM2RestackWindow) {
845 atoms[pnum++] = p->atom(atom: _NET_RESTACK_WINDOW);
846 }
847
848 if (p->properties2 & WM2ShowingDesktop) {
849 atoms[pnum++] = p->atom(atom: _NET_SHOWING_DESKTOP);
850 }
851
852 // Application window properties/messages
853 if (p->properties & WMMoveResize) {
854 atoms[pnum++] = p->atom(atom: _NET_WM_MOVERESIZE);
855 }
856
857 if (p->properties2 & WM2MoveResizeWindow) {
858 atoms[pnum++] = p->atom(atom: _NET_MOVERESIZE_WINDOW);
859 }
860
861 if (p->properties & WMName) {
862 atoms[pnum++] = p->atom(atom: _NET_WM_NAME);
863 }
864
865 if (p->properties & WMVisibleName) {
866 atoms[pnum++] = p->atom(atom: _NET_WM_VISIBLE_NAME);
867 }
868
869 if (p->properties & WMIconName) {
870 atoms[pnum++] = p->atom(atom: _NET_WM_ICON_NAME);
871 }
872
873 if (p->properties & WMVisibleIconName) {
874 atoms[pnum++] = p->atom(atom: _NET_WM_VISIBLE_ICON_NAME);
875 }
876
877 if (p->properties & WMDesktop) {
878 atoms[pnum++] = p->atom(atom: _NET_WM_DESKTOP);
879 }
880
881 if (p->properties & WMWindowType) {
882 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE);
883
884 // Application window types
885 if (p->windowTypes & NormalMask) {
886 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE_NORMAL);
887 }
888 if (p->windowTypes & DesktopMask) {
889 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE_DESKTOP);
890 }
891 if (p->windowTypes & DockMask) {
892 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE_DOCK);
893 }
894 if (p->windowTypes & ToolbarMask) {
895 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE_TOOLBAR);
896 }
897 if (p->windowTypes & MenuMask) {
898 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE_MENU);
899 }
900 if (p->windowTypes & DialogMask) {
901 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE_DIALOG);
902 }
903 if (p->windowTypes & UtilityMask) {
904 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE_UTILITY);
905 }
906 if (p->windowTypes & SplashMask) {
907 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE_SPLASH);
908 }
909 if (p->windowTypes & DropdownMenuMask) {
910 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE_DROPDOWN_MENU);
911 }
912 if (p->windowTypes & PopupMenuMask) {
913 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE_POPUP_MENU);
914 }
915 if (p->windowTypes & TooltipMask) {
916 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE_TOOLTIP);
917 }
918 if (p->windowTypes & NotificationMask) {
919 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE_NOTIFICATION);
920 }
921 if (p->windowTypes & ComboBoxMask) {
922 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE_COMBO);
923 }
924 if (p->windowTypes & DNDIconMask) {
925 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_TYPE_DND);
926 }
927 // KDE extensions
928 if (p->windowTypes & OverrideMask) {
929 atoms[pnum++] = p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_OVERRIDE);
930 }
931 if (p->windowTypes & TopMenuMask) {
932 atoms[pnum++] = p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_TOPMENU);
933 }
934 if (p->windowTypes & OnScreenDisplayMask) {
935 atoms[pnum++] = p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_ON_SCREEN_DISPLAY);
936 }
937 if (p->windowTypes & CriticalNotificationMask) {
938 atoms[pnum++] = p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_CRITICAL_NOTIFICATION);
939 }
940 if (p->windowTypes & AppletPopupMask) {
941 atoms[pnum++] = p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_APPLET_POPUP);
942 }
943 }
944
945 if (p->properties & WMState) {
946 atoms[pnum++] = p->atom(atom: _NET_WM_STATE);
947
948 // Application window states
949 if (p->states & Modal) {
950 atoms[pnum++] = p->atom(atom: _NET_WM_STATE_MODAL);
951 }
952 if (p->states & Sticky) {
953 atoms[pnum++] = p->atom(atom: _NET_WM_STATE_STICKY);
954 }
955 if (p->states & MaxVert) {
956 atoms[pnum++] = p->atom(atom: _NET_WM_STATE_MAXIMIZED_VERT);
957 }
958 if (p->states & MaxHoriz) {
959 atoms[pnum++] = p->atom(atom: _NET_WM_STATE_MAXIMIZED_HORZ);
960 }
961 if (p->states & Shaded) {
962 atoms[pnum++] = p->atom(atom: _NET_WM_STATE_SHADED);
963 }
964 if (p->states & SkipTaskbar) {
965 atoms[pnum++] = p->atom(atom: _NET_WM_STATE_SKIP_TASKBAR);
966 }
967 if (p->states & SkipPager) {
968 atoms[pnum++] = p->atom(atom: _NET_WM_STATE_SKIP_PAGER);
969 }
970 if (p->states & SkipSwitcher) {
971 atoms[pnum++] = p->atom(atom: _KDE_NET_WM_STATE_SKIP_SWITCHER);
972 }
973 if (p->states & Hidden) {
974 atoms[pnum++] = p->atom(atom: _NET_WM_STATE_HIDDEN);
975 }
976 if (p->states & FullScreen) {
977 atoms[pnum++] = p->atom(atom: _NET_WM_STATE_FULLSCREEN);
978 }
979 if (p->states & KeepAbove) {
980 atoms[pnum++] = p->atom(atom: _NET_WM_STATE_ABOVE);
981 // deprecated variant
982 atoms[pnum++] = p->atom(atom: _NET_WM_STATE_STAYS_ON_TOP);
983 }
984 if (p->states & KeepBelow) {
985 atoms[pnum++] = p->atom(atom: _NET_WM_STATE_BELOW);
986 }
987 if (p->states & DemandsAttention) {
988 atoms[pnum++] = p->atom(atom: _NET_WM_STATE_DEMANDS_ATTENTION);
989 }
990
991 if (p->states & Focused) {
992 atoms[pnum++] = p->atom(atom: _NET_WM_STATE_FOCUSED);
993 }
994 }
995
996 if (p->properties & WMStrut) {
997 atoms[pnum++] = p->atom(atom: _NET_WM_STRUT);
998 }
999
1000 if (p->properties2 & WM2ExtendedStrut) {
1001 atoms[pnum++] = p->atom(atom: _NET_WM_STRUT_PARTIAL);
1002 }
1003
1004 if (p->properties & WMIconGeometry) {
1005 atoms[pnum++] = p->atom(atom: _NET_WM_ICON_GEOMETRY);
1006 }
1007
1008 if (p->properties & WMIcon) {
1009 atoms[pnum++] = p->atom(atom: _NET_WM_ICON);
1010 }
1011
1012 if (p->properties & WMPid) {
1013 atoms[pnum++] = p->atom(atom: _NET_WM_PID);
1014 }
1015
1016 if (p->properties & WMHandledIcons) {
1017 atoms[pnum++] = p->atom(atom: _NET_WM_HANDLED_ICONS);
1018 }
1019
1020 if (p->properties & WMPing) {
1021 atoms[pnum++] = p->atom(atom: _NET_WM_PING);
1022 }
1023
1024 if (p->properties2 & WM2UserTime) {
1025 atoms[pnum++] = p->atom(atom: _NET_WM_USER_TIME);
1026 }
1027
1028 if (p->properties2 & WM2StartupId) {
1029 atoms[pnum++] = p->atom(atom: _NET_STARTUP_ID);
1030 }
1031
1032 if (p->properties2 & WM2Opacity) {
1033 atoms[pnum++] = p->atom(atom: _NET_WM_WINDOW_OPACITY);
1034 }
1035
1036 if (p->properties2 & WM2FullscreenMonitors) {
1037 atoms[pnum++] = p->atom(atom: _NET_WM_FULLSCREEN_MONITORS);
1038 }
1039
1040 if (p->properties2 & WM2AllowedActions) {
1041 atoms[pnum++] = p->atom(atom: _NET_WM_ALLOWED_ACTIONS);
1042
1043 // Actions
1044 if (p->actions & ActionMove) {
1045 atoms[pnum++] = p->atom(atom: _NET_WM_ACTION_MOVE);
1046 }
1047 if (p->actions & ActionResize) {
1048 atoms[pnum++] = p->atom(atom: _NET_WM_ACTION_RESIZE);
1049 }
1050 if (p->actions & ActionMinimize) {
1051 atoms[pnum++] = p->atom(atom: _NET_WM_ACTION_MINIMIZE);
1052 }
1053 if (p->actions & ActionShade) {
1054 atoms[pnum++] = p->atom(atom: _NET_WM_ACTION_SHADE);
1055 }
1056 if (p->actions & ActionStick) {
1057 atoms[pnum++] = p->atom(atom: _NET_WM_ACTION_STICK);
1058 }
1059 if (p->actions & ActionMaxVert) {
1060 atoms[pnum++] = p->atom(atom: _NET_WM_ACTION_MAXIMIZE_VERT);
1061 }
1062 if (p->actions & ActionMaxHoriz) {
1063 atoms[pnum++] = p->atom(atom: _NET_WM_ACTION_MAXIMIZE_HORZ);
1064 }
1065 if (p->actions & ActionFullScreen) {
1066 atoms[pnum++] = p->atom(atom: _NET_WM_ACTION_FULLSCREEN);
1067 }
1068 if (p->actions & ActionChangeDesktop) {
1069 atoms[pnum++] = p->atom(atom: _NET_WM_ACTION_CHANGE_DESKTOP);
1070 }
1071 if (p->actions & ActionClose) {
1072 atoms[pnum++] = p->atom(atom: _NET_WM_ACTION_CLOSE);
1073 }
1074 }
1075
1076 if (p->properties & WMFrameExtents) {
1077 atoms[pnum++] = p->atom(atom: _NET_FRAME_EXTENTS);
1078 atoms[pnum++] = p->atom(atom: _KDE_NET_WM_FRAME_STRUT);
1079 }
1080
1081 if (p->properties2 & WM2FrameOverlap) {
1082 atoms[pnum++] = p->atom(atom: _NET_WM_FRAME_OVERLAP);
1083 }
1084
1085 if (p->properties2 & WM2KDETemporaryRules) {
1086 atoms[pnum++] = p->atom(atom: _KDE_NET_WM_TEMPORARY_RULES);
1087 }
1088 if (p->properties2 & WM2FullPlacement) {
1089 atoms[pnum++] = p->atom(atom: _NET_WM_FULL_PLACEMENT);
1090 }
1091
1092 if (p->properties2 & WM2Activities) {
1093 atoms[pnum++] = p->atom(atom: _KDE_NET_WM_ACTIVITIES);
1094 }
1095
1096 if (p->properties2 & WM2BlockCompositing) {
1097 atoms[pnum++] = p->atom(atom: _KDE_NET_WM_BLOCK_COMPOSITING);
1098 atoms[pnum++] = p->atom(atom: _NET_WM_BYPASS_COMPOSITOR);
1099 }
1100
1101 if (p->properties2 & WM2KDEShadow) {
1102 atoms[pnum++] = p->atom(atom: _KDE_NET_WM_SHADOW);
1103 }
1104
1105 if (p->properties2 & WM2OpaqueRegion) {
1106 atoms[pnum++] = p->atom(atom: _NET_WM_OPAQUE_REGION);
1107 }
1108
1109 if (p->properties2 & WM2GTKFrameExtents) {
1110 atoms[pnum++] = p->atom(atom: _GTK_FRAME_EXTENTS);
1111 }
1112
1113 if (p->properties2 & WM2GTKShowWindowMenu) {
1114 atoms[pnum++] = p->atom(atom: _GTK_SHOW_WINDOW_MENU);
1115 }
1116
1117 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->root, property: p->atom(atom: _NET_SUPPORTED), type: XCB_ATOM_ATOM, format: 32, data_len: pnum, data: (const void *)atoms);
1118
1119 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->root, property: p->atom(atom: _NET_SUPPORTING_WM_CHECK), type: XCB_ATOM_WINDOW, format: 32, data_len: 1, data: (const void *)&(p->supportwindow));
1120
1121#ifdef NETWMDEBUG
1122 fprintf(stderr,
1123 "NETRootInfo::setSupported: _NET_SUPPORTING_WM_CHECK = 0x%lx on 0x%lx\n"
1124 " : _NET_WM_NAME = '%s' on 0x%lx\n",
1125 p->supportwindow,
1126 p->supportwindow,
1127 p->name,
1128 p->supportwindow);
1129#endif
1130
1131 xcb_change_property(c: p->conn,
1132 mode: XCB_PROP_MODE_REPLACE,
1133 window: p->supportwindow,
1134 property: p->atom(atom: _NET_SUPPORTING_WM_CHECK),
1135 type: XCB_ATOM_WINDOW,
1136 format: 32,
1137 data_len: 1,
1138 data: (const void *)&(p->supportwindow));
1139
1140 xcb_change_property(c: p->conn,
1141 mode: XCB_PROP_MODE_REPLACE,
1142 window: p->supportwindow,
1143 property: p->atom(atom: _NET_WM_NAME),
1144 type: p->atom(atom: UTF8_STRING),
1145 format: 8,
1146 data_len: strlen(s: p->name),
1147 data: (const void *)p->name);
1148}
1149
1150void NETRootInfo::updateSupportedProperties(xcb_atom_t atom)
1151{
1152 if (atom == p->atom(atom: _NET_SUPPORTED)) {
1153 p->properties |= Supported;
1154 }
1155
1156 else if (atom == p->atom(atom: _NET_SUPPORTING_WM_CHECK)) {
1157 p->properties |= SupportingWMCheck;
1158 }
1159
1160 else if (atom == p->atom(atom: _NET_CLIENT_LIST)) {
1161 p->properties |= ClientList;
1162 }
1163
1164 else if (atom == p->atom(atom: _NET_CLIENT_LIST_STACKING)) {
1165 p->properties |= ClientListStacking;
1166 }
1167
1168 else if (atom == p->atom(atom: _NET_NUMBER_OF_DESKTOPS)) {
1169 p->properties |= NumberOfDesktops;
1170 }
1171
1172 else if (atom == p->atom(atom: _NET_DESKTOP_GEOMETRY)) {
1173 p->properties |= DesktopGeometry;
1174 }
1175
1176 else if (atom == p->atom(atom: _NET_DESKTOP_VIEWPORT)) {
1177 p->properties |= DesktopViewport;
1178 }
1179
1180 else if (atom == p->atom(atom: _NET_CURRENT_DESKTOP)) {
1181 p->properties |= CurrentDesktop;
1182 }
1183
1184 else if (atom == p->atom(atom: _NET_DESKTOP_NAMES)) {
1185 p->properties |= DesktopNames;
1186 }
1187
1188 else if (atom == p->atom(atom: _NET_ACTIVE_WINDOW)) {
1189 p->properties |= ActiveWindow;
1190 }
1191
1192 else if (atom == p->atom(atom: _NET_WORKAREA)) {
1193 p->properties |= WorkArea;
1194 }
1195
1196 else if (atom == p->atom(atom: _NET_VIRTUAL_ROOTS)) {
1197 p->properties |= VirtualRoots;
1198 }
1199
1200 else if (atom == p->atom(atom: _NET_DESKTOP_LAYOUT)) {
1201 p->properties2 |= WM2DesktopLayout;
1202 }
1203
1204 else if (atom == p->atom(atom: _NET_CLOSE_WINDOW)) {
1205 p->properties |= CloseWindow;
1206 }
1207
1208 else if (atom == p->atom(atom: _NET_RESTACK_WINDOW)) {
1209 p->properties2 |= WM2RestackWindow;
1210 }
1211
1212 else if (atom == p->atom(atom: _NET_SHOWING_DESKTOP)) {
1213 p->properties2 |= WM2ShowingDesktop;
1214 }
1215
1216 // Application window properties/messages
1217 else if (atom == p->atom(atom: _NET_WM_MOVERESIZE)) {
1218 p->properties |= WMMoveResize;
1219 }
1220
1221 else if (atom == p->atom(atom: _NET_MOVERESIZE_WINDOW)) {
1222 p->properties2 |= WM2MoveResizeWindow;
1223 }
1224
1225 else if (atom == p->atom(atom: _NET_WM_NAME)) {
1226 p->properties |= WMName;
1227 }
1228
1229 else if (atom == p->atom(atom: _NET_WM_VISIBLE_NAME)) {
1230 p->properties |= WMVisibleName;
1231 }
1232
1233 else if (atom == p->atom(atom: _NET_WM_ICON_NAME)) {
1234 p->properties |= WMIconName;
1235 }
1236
1237 else if (atom == p->atom(atom: _NET_WM_VISIBLE_ICON_NAME)) {
1238 p->properties |= WMVisibleIconName;
1239 }
1240
1241 else if (atom == p->atom(atom: _NET_WM_DESKTOP)) {
1242 p->properties |= WMDesktop;
1243 }
1244
1245 else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE)) {
1246 p->properties |= WMWindowType;
1247 }
1248
1249 // Application window types
1250 else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE_NORMAL)) {
1251 p->windowTypes |= NormalMask;
1252 } else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE_DESKTOP)) {
1253 p->windowTypes |= DesktopMask;
1254 } else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE_DOCK)) {
1255 p->windowTypes |= DockMask;
1256 } else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE_TOOLBAR)) {
1257 p->windowTypes |= ToolbarMask;
1258 } else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE_MENU)) {
1259 p->windowTypes |= MenuMask;
1260 } else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE_DIALOG)) {
1261 p->windowTypes |= DialogMask;
1262 } else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE_UTILITY)) {
1263 p->windowTypes |= UtilityMask;
1264 } else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE_SPLASH)) {
1265 p->windowTypes |= SplashMask;
1266 } else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE_DROPDOWN_MENU)) {
1267 p->windowTypes |= DropdownMenuMask;
1268 } else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE_POPUP_MENU)) {
1269 p->windowTypes |= PopupMenuMask;
1270 } else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE_TOOLTIP)) {
1271 p->windowTypes |= TooltipMask;
1272 } else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE_NOTIFICATION)) {
1273 p->windowTypes |= NotificationMask;
1274 } else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE_COMBO)) {
1275 p->windowTypes |= ComboBoxMask;
1276 } else if (atom == p->atom(atom: _NET_WM_WINDOW_TYPE_DND)) {
1277 p->windowTypes |= DNDIconMask;
1278 }
1279 // KDE extensions
1280 else if (atom == p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_OVERRIDE)) {
1281 p->windowTypes |= OverrideMask;
1282 } else if (atom == p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_TOPMENU)) {
1283 p->windowTypes |= TopMenuMask;
1284 } else if (atom == p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_ON_SCREEN_DISPLAY)) {
1285 p->windowTypes |= OnScreenDisplayMask;
1286 } else if (atom == p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_CRITICAL_NOTIFICATION)) {
1287 p->windowTypes |= CriticalNotificationMask;
1288 } else if (atom == p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_APPLET_POPUP)) {
1289 p->windowTypes |= AppletPopupMask;
1290 }
1291
1292 else if (atom == p->atom(atom: _NET_WM_STATE)) {
1293 p->properties |= WMState;
1294 }
1295
1296 // Application window states
1297 else if (atom == p->atom(atom: _NET_WM_STATE_MODAL)) {
1298 p->states |= Modal;
1299 } else if (atom == p->atom(atom: _NET_WM_STATE_STICKY)) {
1300 p->states |= Sticky;
1301 } else if (atom == p->atom(atom: _NET_WM_STATE_MAXIMIZED_VERT)) {
1302 p->states |= MaxVert;
1303 } else if (atom == p->atom(atom: _NET_WM_STATE_MAXIMIZED_HORZ)) {
1304 p->states |= MaxHoriz;
1305 } else if (atom == p->atom(atom: _NET_WM_STATE_SHADED)) {
1306 p->states |= Shaded;
1307 } else if (atom == p->atom(atom: _NET_WM_STATE_SKIP_TASKBAR)) {
1308 p->states |= SkipTaskbar;
1309 } else if (atom == p->atom(atom: _NET_WM_STATE_SKIP_PAGER)) {
1310 p->states |= SkipPager;
1311 } else if (atom == p->atom(atom: _KDE_NET_WM_STATE_SKIP_SWITCHER)) {
1312 p->states |= SkipSwitcher;
1313 } else if (atom == p->atom(atom: _NET_WM_STATE_HIDDEN)) {
1314 p->states |= Hidden;
1315 } else if (atom == p->atom(atom: _NET_WM_STATE_FULLSCREEN)) {
1316 p->states |= FullScreen;
1317 } else if (atom == p->atom(atom: _NET_WM_STATE_ABOVE)) {
1318 p->states |= KeepAbove;
1319 } else if (atom == p->atom(atom: _NET_WM_STATE_BELOW)) {
1320 p->states |= KeepBelow;
1321 } else if (atom == p->atom(atom: _NET_WM_STATE_DEMANDS_ATTENTION)) {
1322 p->states |= DemandsAttention;
1323 } else if (atom == p->atom(atom: _NET_WM_STATE_STAYS_ON_TOP)) {
1324 p->states |= KeepAbove;
1325 } else if (atom == p->atom(atom: _NET_WM_STATE_FOCUSED)) {
1326 p->states |= Focused;
1327 }
1328
1329 else if (atom == p->atom(atom: _NET_WM_STRUT)) {
1330 p->properties |= WMStrut;
1331 }
1332
1333 else if (atom == p->atom(atom: _NET_WM_STRUT_PARTIAL)) {
1334 p->properties2 |= WM2ExtendedStrut;
1335 }
1336
1337 else if (atom == p->atom(atom: _NET_WM_ICON_GEOMETRY)) {
1338 p->properties |= WMIconGeometry;
1339 }
1340
1341 else if (atom == p->atom(atom: _NET_WM_ICON)) {
1342 p->properties |= WMIcon;
1343 }
1344
1345 else if (atom == p->atom(atom: _NET_WM_PID)) {
1346 p->properties |= WMPid;
1347 }
1348
1349 else if (atom == p->atom(atom: _NET_WM_HANDLED_ICONS)) {
1350 p->properties |= WMHandledIcons;
1351 }
1352
1353 else if (atom == p->atom(atom: _NET_WM_PING)) {
1354 p->properties |= WMPing;
1355 }
1356
1357 else if (atom == p->atom(atom: _NET_WM_USER_TIME)) {
1358 p->properties2 |= WM2UserTime;
1359 }
1360
1361 else if (atom == p->atom(atom: _NET_STARTUP_ID)) {
1362 p->properties2 |= WM2StartupId;
1363 }
1364
1365 else if (atom == p->atom(atom: _NET_WM_WINDOW_OPACITY)) {
1366 p->properties2 |= WM2Opacity;
1367 }
1368
1369 else if (atom == p->atom(atom: _NET_WM_FULLSCREEN_MONITORS)) {
1370 p->properties2 |= WM2FullscreenMonitors;
1371 }
1372
1373 else if (atom == p->atom(atom: _NET_WM_ALLOWED_ACTIONS)) {
1374 p->properties2 |= WM2AllowedActions;
1375 }
1376
1377 // Actions
1378 else if (atom == p->atom(atom: _NET_WM_ACTION_MOVE)) {
1379 p->actions |= ActionMove;
1380 } else if (atom == p->atom(atom: _NET_WM_ACTION_RESIZE)) {
1381 p->actions |= ActionResize;
1382 } else if (atom == p->atom(atom: _NET_WM_ACTION_MINIMIZE)) {
1383 p->actions |= ActionMinimize;
1384 } else if (atom == p->atom(atom: _NET_WM_ACTION_SHADE)) {
1385 p->actions |= ActionShade;
1386 } else if (atom == p->atom(atom: _NET_WM_ACTION_STICK)) {
1387 p->actions |= ActionStick;
1388 } else if (atom == p->atom(atom: _NET_WM_ACTION_MAXIMIZE_VERT)) {
1389 p->actions |= ActionMaxVert;
1390 } else if (atom == p->atom(atom: _NET_WM_ACTION_MAXIMIZE_HORZ)) {
1391 p->actions |= ActionMaxHoriz;
1392 } else if (atom == p->atom(atom: _NET_WM_ACTION_FULLSCREEN)) {
1393 p->actions |= ActionFullScreen;
1394 } else if (atom == p->atom(atom: _NET_WM_ACTION_CHANGE_DESKTOP)) {
1395 p->actions |= ActionChangeDesktop;
1396 } else if (atom == p->atom(atom: _NET_WM_ACTION_CLOSE)) {
1397 p->actions |= ActionClose;
1398 }
1399
1400 else if (atom == p->atom(atom: _NET_FRAME_EXTENTS)) {
1401 p->properties |= WMFrameExtents;
1402 } else if (atom == p->atom(atom: _KDE_NET_WM_FRAME_STRUT)) {
1403 p->properties |= WMFrameExtents;
1404 } else if (atom == p->atom(atom: _NET_WM_FRAME_OVERLAP)) {
1405 p->properties2 |= WM2FrameOverlap;
1406 }
1407
1408 else if (atom == p->atom(atom: _KDE_NET_WM_TEMPORARY_RULES)) {
1409 p->properties2 |= WM2KDETemporaryRules;
1410 } else if (atom == p->atom(atom: _NET_WM_FULL_PLACEMENT)) {
1411 p->properties2 |= WM2FullPlacement;
1412 }
1413
1414 else if (atom == p->atom(atom: _KDE_NET_WM_ACTIVITIES)) {
1415 p->properties2 |= WM2Activities;
1416 }
1417
1418 else if (atom == p->atom(atom: _KDE_NET_WM_BLOCK_COMPOSITING) || atom == p->atom(atom: _NET_WM_BYPASS_COMPOSITOR)) {
1419 p->properties2 |= WM2BlockCompositing;
1420 }
1421
1422 else if (atom == p->atom(atom: _KDE_NET_WM_SHADOW)) {
1423 p->properties2 |= WM2KDEShadow;
1424 }
1425
1426 else if (atom == p->atom(atom: _NET_WM_OPAQUE_REGION)) {
1427 p->properties2 |= WM2OpaqueRegion;
1428 }
1429
1430 else if (atom == p->atom(atom: _GTK_FRAME_EXTENTS)) {
1431 p->properties2 |= WM2GTKFrameExtents;
1432 }
1433
1434 else if (atom == p->atom(atom: _GTK_SHOW_WINDOW_MENU)) {
1435 p->properties2 |= WM2GTKShowWindowMenu;
1436 }
1437
1438 else if (atom == p->atom(atom: _KDE_NET_WM_APPMENU_OBJECT_PATH)) {
1439 p->properties2 |= WM2AppMenuObjectPath;
1440 }
1441
1442 else if (atom == p->atom(atom: _KDE_NET_WM_APPMENU_SERVICE_NAME)) {
1443 p->properties2 |= WM2AppMenuServiceName;
1444 }
1445}
1446
1447void NETRootInfo::setActiveWindow(xcb_window_t window)
1448{
1449 setActiveWindow(window, src: FromUnknown, timestamp: QX11Info::appUserTime(), active_window: XCB_WINDOW_NONE);
1450}
1451
1452void NETRootInfo::setActiveWindow(xcb_window_t window, NET::RequestSource src, xcb_timestamp_t timestamp, xcb_window_t active_window)
1453{
1454#ifdef NETWMDEBUG
1455 fprintf(stderr, "NETRootInfo::setActiveWindow(0x%lx) (%s)\n", window, (p->role == WindowManager) ? "WM" : "Client");
1456#endif
1457
1458 if (p->role == WindowManager) {
1459 p->active = window;
1460
1461 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->root, property: p->atom(atom: _NET_ACTIVE_WINDOW), type: XCB_ATOM_WINDOW, format: 32, data_len: 1, data: (const void *)&(p->active));
1462 } else {
1463 const uint32_t data[5] = {src, timestamp, active_window, 0, 0};
1464
1465 send_client_message(c: p->conn, mask: netwm_sendevent_mask, destination: p->root, window, message: p->atom(atom: _NET_ACTIVE_WINDOW), data);
1466 }
1467}
1468
1469void NETRootInfo::setWorkArea(int desktop, const NETRect &workarea)
1470{
1471#ifdef NETWMDEBUG
1472 fprintf(stderr,
1473 "NETRootInfo::setWorkArea(%d, { %d, %d, %d, %d }) (%s)\n",
1474 desktop,
1475 workarea.pos.x,
1476 workarea.pos.y,
1477 workarea.size.width,
1478 workarea.size.height,
1479 (p->role == WindowManager) ? "WM" : "Client");
1480#endif
1481
1482 if (p->role != WindowManager || desktop < 1) {
1483 return;
1484 }
1485
1486 p->workarea[desktop - 1] = workarea;
1487
1488 uint32_t *wa = new uint32_t[p->number_of_desktops * 4];
1489 int i;
1490 int o;
1491 for (i = 0, o = 0; i < p->number_of_desktops; i++) {
1492 wa[o++] = p->workarea[i].pos.x;
1493 wa[o++] = p->workarea[i].pos.y;
1494 wa[o++] = p->workarea[i].size.width;
1495 wa[o++] = p->workarea[i].size.height;
1496 }
1497
1498 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->root, property: p->atom(atom: _NET_WORKAREA), type: XCB_ATOM_CARDINAL, format: 32, data_len: p->number_of_desktops * 4, data: (const void *)wa);
1499
1500 delete[] wa;
1501}
1502
1503void NETRootInfo::setVirtualRoots(const xcb_window_t *windows, unsigned int count)
1504{
1505 if (p->role != WindowManager) {
1506 return;
1507 }
1508
1509 p->virtual_roots_count = count;
1510 delete[] p->virtual_roots;
1511 p->virtual_roots = nwindup(w1: windows, n: count);
1512
1513#ifdef NETWMDEBUG
1514 fprintf(stderr, "NETRootInfo::setVirtualRoots: setting list with %ld windows\n", p->virtual_roots_count);
1515#endif
1516
1517 xcb_change_property(c: p->conn,
1518 mode: XCB_PROP_MODE_REPLACE,
1519 window: p->root,
1520 property: p->atom(atom: _NET_VIRTUAL_ROOTS),
1521 type: XCB_ATOM_WINDOW,
1522 format: 32,
1523 data_len: p->virtual_roots_count,
1524 data: (const void *)windows);
1525}
1526
1527void NETRootInfo::setDesktopLayout(NET::Orientation orientation, int columns, int rows, NET::DesktopLayoutCorner corner)
1528{
1529 p->desktop_layout_orientation = orientation;
1530 p->desktop_layout_columns = columns;
1531 p->desktop_layout_rows = rows;
1532 p->desktop_layout_corner = corner;
1533
1534#ifdef NETWMDEBUG
1535 fprintf(stderr, "NETRootInfo::setDesktopLayout: %d %d %d %d\n", orientation, columns, rows, corner);
1536#endif
1537
1538 uint32_t data[4];
1539 data[0] = orientation;
1540 data[1] = columns;
1541 data[2] = rows;
1542 data[3] = corner;
1543
1544 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->root, property: p->atom(atom: _NET_DESKTOP_LAYOUT), type: XCB_ATOM_CARDINAL, format: 32, data_len: 4, data: (const void *)data);
1545}
1546
1547void NETRootInfo::setShowingDesktop(bool showing)
1548{
1549 if (p->role == WindowManager) {
1550 uint32_t d = p->showing_desktop = showing;
1551 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->root, property: p->atom(atom: _NET_SHOWING_DESKTOP), type: XCB_ATOM_CARDINAL, format: 32, data_len: 1, data: (const void *)&d);
1552 } else {
1553 uint32_t data[5] = {uint32_t(showing ? 1 : 0), 0, 0, 0, 0};
1554 send_client_message(c: p->conn, mask: netwm_sendevent_mask, destination: p->root, window: p->root, message: p->atom(atom: _NET_SHOWING_DESKTOP), data);
1555 }
1556}
1557
1558bool NETRootInfo::showingDesktop() const
1559{
1560 return p->showing_desktop;
1561}
1562
1563void NETRootInfo::closeWindowRequest(xcb_window_t window)
1564{
1565#ifdef NETWMDEBUG
1566 fprintf(stderr, "NETRootInfo::closeWindowRequest: requesting close for 0x%lx\n", window);
1567#endif
1568
1569 const uint32_t data[5] = {0, 0, 0, 0, 0};
1570 send_client_message(c: p->conn, mask: netwm_sendevent_mask, destination: p->root, window, message: p->atom(atom: _NET_CLOSE_WINDOW), data);
1571}
1572
1573void NETRootInfo::moveResizeRequest(xcb_window_t window, int x_root, int y_root, Direction direction, xcb_button_t button, RequestSource source)
1574{
1575#ifdef NETWMDEBUG
1576 fprintf(stderr,
1577 "NETRootInfo::moveResizeRequest: requesting resize/move for 0x%lx (%d, %d, %d, %d, %d)\n",
1578 window,
1579 x_root,
1580 y_root,
1581 direction,
1582 button,
1583 source);
1584#endif
1585
1586 const uint32_t data[5] = {uint32_t(x_root), uint32_t(y_root), uint32_t(direction), uint32_t(button), uint32_t(source)};
1587
1588 send_client_message(c: p->conn, mask: netwm_sendevent_mask, destination: p->root, window, message: p->atom(atom: _NET_WM_MOVERESIZE), data);
1589}
1590
1591void NETRootInfo::moveResizeWindowRequest(xcb_window_t window, int flags, int x, int y, int width, int height)
1592{
1593#ifdef NETWMDEBUG
1594 fprintf(stderr, "NETRootInfo::moveResizeWindowRequest: resizing/moving 0x%lx (%d, %d, %d, %d, %d)\n", window, flags, x, y, width, height);
1595#endif
1596
1597 const uint32_t data[5] = {uint32_t(flags), uint32_t(x), uint32_t(y), uint32_t(width), uint32_t(height)};
1598
1599 send_client_message(c: p->conn, mask: netwm_sendevent_mask, destination: p->root, window, message: p->atom(atom: _NET_MOVERESIZE_WINDOW), data);
1600}
1601
1602void NETRootInfo::showWindowMenuRequest(xcb_window_t window, int device_id, int x_root, int y_root)
1603{
1604#ifdef NETWMDEBUG
1605 fprintf(stderr, "NETRootInfo::showWindowMenuRequest: requesting menu for 0x%lx (%d, %d, %d)\n", window, device_id, x_root, y_root);
1606#endif
1607
1608 const uint32_t data[5] = {uint32_t(device_id), uint32_t(x_root), uint32_t(y_root), 0, 0};
1609 send_client_message(c: p->conn, mask: netwm_sendevent_mask, destination: p->root, window, message: p->atom(atom: _GTK_SHOW_WINDOW_MENU), data);
1610}
1611
1612void NETRootInfo::restackRequest(xcb_window_t window, RequestSource src, xcb_window_t above, int detail, xcb_timestamp_t timestamp)
1613{
1614#ifdef NETWMDEBUG
1615 fprintf(stderr, "NETRootInfo::restackRequest: requesting restack for 0x%lx (%lx, %d)\n", window, above, detail);
1616#endif
1617
1618 const uint32_t data[5] = {uint32_t(src), uint32_t(above), uint32_t(detail), uint32_t(timestamp), 0};
1619
1620 send_client_message(c: p->conn, mask: netwm_sendevent_mask, destination: p->root, window, message: p->atom(atom: _NET_RESTACK_WINDOW), data);
1621}
1622
1623void NETRootInfo::sendPing(xcb_window_t window, xcb_timestamp_t timestamp)
1624{
1625 if (p->role != WindowManager) {
1626 return;
1627 }
1628
1629#ifdef NETWMDEBUG
1630 fprintf(stderr, "NETRootInfo::setPing: window 0x%lx, timestamp %lu\n", window, timestamp);
1631#endif
1632
1633 const uint32_t data[5] = {p->atom(atom: _NET_WM_PING), timestamp, window, 0, 0};
1634
1635 send_client_message(c: p->conn, mask: 0, destination: window, window, message: p->atom(atom: WM_PROTOCOLS), data);
1636}
1637
1638// assignment operator
1639
1640const NETRootInfo &NETRootInfo::operator=(const NETRootInfo &rootinfo)
1641{
1642#ifdef NETWMDEBUG
1643 fprintf(stderr, "NETRootInfo::operator=()\n");
1644#endif
1645
1646 if (p != rootinfo.p) {
1647 refdec_nri(p);
1648
1649 if (!p->ref) {
1650 delete p;
1651 }
1652 }
1653
1654 p = rootinfo.p;
1655 p->ref++;
1656
1657 return *this;
1658}
1659
1660NET::Properties NETRootInfo::event(xcb_generic_event_t *ev)
1661{
1662 NET::Properties props;
1663 event(event: ev, properties: &props);
1664 return props;
1665}
1666
1667void NETRootInfo::event(xcb_generic_event_t *event, NET::Properties *properties, NET::Properties2 *properties2)
1668{
1669 NET::Properties dirty;
1670 NET::Properties2 dirty2;
1671 bool do_update = false;
1672 const uint8_t eventType = event->response_type & ~0x80;
1673
1674 // the window manager will be interested in client messages... no other
1675 // client should get these messages
1676 if (p->role == WindowManager && eventType == XCB_CLIENT_MESSAGE && reinterpret_cast<xcb_client_message_event_t *>(event)->format == 32) {
1677 xcb_client_message_event_t *message = reinterpret_cast<xcb_client_message_event_t *>(event);
1678#ifdef NETWMDEBUG
1679 fprintf(stderr, "NETRootInfo::event: handling ClientMessage event\n");
1680#endif
1681
1682 if (message->type == p->atom(atom: _NET_NUMBER_OF_DESKTOPS)) {
1683 dirty = NumberOfDesktops;
1684
1685#ifdef NETWMDEBUG
1686 fprintf(stderr, "NETRootInfo::event: changeNumberOfDesktops(%ld)\n", message->data.data32[0]);
1687#endif
1688
1689 changeNumberOfDesktops(numberOfDesktops: message->data.data32[0]);
1690 } else if (message->type == p->atom(atom: _NET_DESKTOP_GEOMETRY)) {
1691 dirty = DesktopGeometry;
1692
1693 NETSize sz;
1694 sz.width = message->data.data32[0];
1695 sz.height = message->data.data32[1];
1696
1697#ifdef NETWMDEBUG
1698 fprintf(stderr, "NETRootInfo::event: changeDesktopGeometry( -- , { %d, %d })\n", sz.width, sz.height);
1699#endif
1700
1701 changeDesktopGeometry(desktop: ~0, geom: sz);
1702 } else if (message->type == p->atom(atom: _NET_DESKTOP_VIEWPORT)) {
1703 dirty = DesktopViewport;
1704
1705 NETPoint pt;
1706 pt.x = message->data.data32[0];
1707 pt.y = message->data.data32[1];
1708
1709#ifdef NETWMDEBUG
1710 fprintf(stderr, "NETRootInfo::event: changeDesktopViewport(%d, { %d, %d })\n", p->current_desktop, pt.x, pt.y);
1711#endif
1712
1713 changeDesktopViewport(desktop: p->current_desktop, viewport: pt);
1714 } else if (message->type == p->atom(atom: _NET_CURRENT_DESKTOP)) {
1715 dirty = CurrentDesktop;
1716
1717#ifdef NETWMDEBUG
1718 fprintf(stderr, "NETRootInfo::event: changeCurrentDesktop(%ld)\n", message->data.data32[0] + 1);
1719#endif
1720
1721 changeCurrentDesktop(desktop: message->data.data32[0] + 1);
1722 } else if (message->type == p->atom(atom: _NET_ACTIVE_WINDOW)) {
1723 dirty = ActiveWindow;
1724
1725#ifdef NETWMDEBUG
1726 fprintf(stderr, "NETRootInfo::event: changeActiveWindow(0x%lx)\n", message->window);
1727#endif
1728
1729 RequestSource src = FromUnknown;
1730 xcb_timestamp_t timestamp = XCB_TIME_CURRENT_TIME;
1731 xcb_window_t active_window = XCB_WINDOW_NONE;
1732 // make sure there aren't unknown values
1733 if (message->data.data32[0] >= FromUnknown && message->data.data32[0] <= FromTool) {
1734 src = static_cast<RequestSource>(message->data.data32[0]);
1735 timestamp = message->data.data32[1];
1736 active_window = message->data.data32[2];
1737 }
1738 changeActiveWindow(window: message->window, src, timestamp, active_window);
1739 } else if (message->type == p->atom(atom: _NET_WM_MOVERESIZE)) {
1740#ifdef NETWMDEBUG
1741 fprintf(stderr,
1742 "NETRootInfo::event: moveResize(%ld, %ld, %ld, %ld, %ld, %ld)\n",
1743 message->window,
1744 message->data.data32[0],
1745 message->data.data32[1],
1746 message->data.data32[2],
1747 message->data.data32[3],
1748 message->data.data32[4]);
1749#endif
1750
1751 moveResize(window: message->window,
1752 x_root: message->data.data32[0],
1753 y_root: message->data.data32[1],
1754 direction: message->data.data32[2],
1755 button: message->data.data32[3],
1756 source: RequestSource(message->data.data32[4]));
1757 } else if (message->type == p->atom(atom: _NET_MOVERESIZE_WINDOW)) {
1758#ifdef NETWMDEBUG
1759 fprintf(stderr,
1760 "NETRootInfo::event: moveResizeWindow(%ld, %ld, %ld, %ld, %ld, %ld)\n",
1761 message->window,
1762 message->data.data32[0],
1763 message->data.data32[1],
1764 message->data.data32[2],
1765 message->data.data32[3],
1766 message->data.data32[4]);
1767#endif
1768
1769 moveResizeWindow(window: message->window,
1770 flags: message->data.data32[0],
1771 x: message->data.data32[1],
1772 y: message->data.data32[2],
1773 width: message->data.data32[3],
1774 height: message->data.data32[4]);
1775 } else if (message->type == p->atom(atom: _NET_CLOSE_WINDOW)) {
1776#ifdef NETWMDEBUG
1777 fprintf(stderr, "NETRootInfo::event: closeWindow(0x%lx)\n", message->window);
1778#endif
1779
1780 closeWindow(window: message->window);
1781 } else if (message->type == p->atom(atom: _NET_RESTACK_WINDOW)) {
1782#ifdef NETWMDEBUG
1783 fprintf(stderr, "NETRootInfo::event: restackWindow(0x%lx)\n", message->window);
1784#endif
1785
1786 RequestSource src = FromUnknown;
1787 xcb_timestamp_t timestamp = XCB_TIME_CURRENT_TIME;
1788 // make sure there aren't unknown values
1789 if (message->data.data32[0] >= FromUnknown && message->data.data32[0] <= FromTool) {
1790 src = static_cast<RequestSource>(message->data.data32[0]);
1791 timestamp = message->data.data32[3];
1792 }
1793 restackWindow(window: message->window, source: src, above: message->data.data32[1], detail: message->data.data32[2], timestamp);
1794 } else if (message->type == p->atom(atom: WM_PROTOCOLS) && (xcb_atom_t)message->data.data32[0] == p->atom(atom: _NET_WM_PING)) {
1795 dirty = WMPing;
1796
1797#ifdef NETWMDEBUG
1798 fprintf(stderr, "NETRootInfo::event: gotPing(0x%lx,%lu)\n", message->window, message->data.data32[1]);
1799#endif
1800 gotPing(window: message->data.data32[2], timestamp: message->data.data32[1]);
1801 } else if (message->type == p->atom(atom: _NET_SHOWING_DESKTOP)) {
1802 dirty2 = WM2ShowingDesktop;
1803
1804#ifdef NETWMDEBUG
1805 fprintf(stderr, "NETRootInfo::event: changeShowingDesktop(%ld)\n", message->data.data32[0]);
1806#endif
1807
1808 changeShowingDesktop(showing: message->data.data32[0]);
1809 } else if (message->type == p->atom(atom: _GTK_SHOW_WINDOW_MENU)) {
1810#ifdef NETWMDEBUG
1811 fprintf(stderr,
1812 "NETRootInfo::event: showWindowMenu(%ld, %ld, %ld, %ld)\n",
1813 message->window,
1814 message->data.data32[0],
1815 message->data.data32[1],
1816 message->data.data32[2]);
1817#endif
1818
1819 showWindowMenu(window: message->window, device_id: message->data.data32[0], x_root: message->data.data32[1], y_root: message->data.data32[2]);
1820 }
1821 }
1822
1823 if (eventType == XCB_PROPERTY_NOTIFY) {
1824#ifdef NETWMDEBUG
1825 fprintf(stderr, "NETRootInfo::event: handling PropertyNotify event\n");
1826#endif
1827
1828 xcb_property_notify_event_t *pe = reinterpret_cast<xcb_property_notify_event_t *>(event);
1829 if (pe->atom == p->atom(atom: _NET_CLIENT_LIST)) {
1830 dirty |= ClientList;
1831 } else if (pe->atom == p->atom(atom: _NET_CLIENT_LIST_STACKING)) {
1832 dirty |= ClientListStacking;
1833 } else if (pe->atom == p->atom(atom: _NET_DESKTOP_NAMES)) {
1834 dirty |= DesktopNames;
1835 } else if (pe->atom == p->atom(atom: _NET_WORKAREA)) {
1836 dirty |= WorkArea;
1837 } else if (pe->atom == p->atom(atom: _NET_NUMBER_OF_DESKTOPS)) {
1838 dirty |= NumberOfDesktops;
1839 } else if (pe->atom == p->atom(atom: _NET_DESKTOP_GEOMETRY)) {
1840 dirty |= DesktopGeometry;
1841 } else if (pe->atom == p->atom(atom: _NET_DESKTOP_VIEWPORT)) {
1842 dirty |= DesktopViewport;
1843 } else if (pe->atom == p->atom(atom: _NET_CURRENT_DESKTOP)) {
1844 dirty |= CurrentDesktop;
1845 } else if (pe->atom == p->atom(atom: _NET_ACTIVE_WINDOW)) {
1846 dirty |= ActiveWindow;
1847 } else if (pe->atom == p->atom(atom: _NET_SHOWING_DESKTOP)) {
1848 dirty2 |= WM2ShowingDesktop;
1849 } else if (pe->atom == p->atom(atom: _NET_SUPPORTED)) {
1850 dirty |= Supported; // update here?
1851 } else if (pe->atom == p->atom(atom: _NET_SUPPORTING_WM_CHECK)) {
1852 dirty |= SupportingWMCheck;
1853 } else if (pe->atom == p->atom(atom: _NET_VIRTUAL_ROOTS)) {
1854 dirty |= VirtualRoots;
1855 } else if (pe->atom == p->atom(atom: _NET_DESKTOP_LAYOUT)) {
1856 dirty2 |= WM2DesktopLayout;
1857 }
1858
1859 do_update = true;
1860 }
1861
1862 if (do_update) {
1863 update(properties: dirty, properties2: dirty2);
1864 }
1865
1866#ifdef NETWMDEBUG
1867 fprintf(stderr, "NETRootInfo::event: handled events, returning dirty = 0x%lx, 0x%lx\n", dirty, dirty2);
1868#endif
1869
1870 if (properties) {
1871 *properties = dirty;
1872 }
1873 if (properties2) {
1874 *properties2 = dirty2;
1875 }
1876}
1877
1878// private functions to update the data we keep
1879
1880void NETRootInfo::update(NET::Properties properties, NET::Properties2 properties2)
1881{
1882 NET::Properties dirty = properties & p->clientProperties;
1883 NET::Properties2 dirty2 = properties2 & p->clientProperties2;
1884
1885 xcb_get_property_cookie_t cookies[255];
1886 xcb_get_property_cookie_t wm_name_cookie;
1887 int c = 0;
1888
1889 // Send the property requests
1890 if (dirty & Supported) {
1891 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->root, property: p->atom(atom: _NET_SUPPORTED), type: XCB_ATOM_ATOM, long_offset: 0, long_length: MAX_PROP_SIZE);
1892 }
1893
1894 if (dirty & ClientList) {
1895 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->root, property: p->atom(atom: _NET_CLIENT_LIST), type: XCB_ATOM_WINDOW, long_offset: 0, long_length: MAX_PROP_SIZE);
1896 }
1897
1898 if (dirty & ClientListStacking) {
1899 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->root, property: p->atom(atom: _NET_CLIENT_LIST_STACKING), type: XCB_ATOM_WINDOW, long_offset: 0, long_length: MAX_PROP_SIZE);
1900 }
1901
1902 if (dirty & NumberOfDesktops) {
1903 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->root, property: p->atom(atom: _NET_NUMBER_OF_DESKTOPS), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 1);
1904 }
1905
1906 if (dirty & DesktopGeometry) {
1907 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->root, property: p->atom(atom: _NET_DESKTOP_GEOMETRY), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 2);
1908 }
1909
1910 if (dirty & DesktopViewport) {
1911 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->root, property: p->atom(atom: _NET_DESKTOP_VIEWPORT), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: MAX_PROP_SIZE);
1912 }
1913
1914 if (dirty & CurrentDesktop) {
1915 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->root, property: p->atom(atom: _NET_CURRENT_DESKTOP), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 1);
1916 }
1917
1918 if (dirty & DesktopNames) {
1919 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->root, property: p->atom(atom: _NET_DESKTOP_NAMES), type: p->atom(atom: UTF8_STRING), long_offset: 0, long_length: MAX_PROP_SIZE);
1920 }
1921
1922 if (dirty & ActiveWindow) {
1923 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->root, property: p->atom(atom: _NET_ACTIVE_WINDOW), type: XCB_ATOM_WINDOW, long_offset: 0, long_length: 1);
1924 }
1925
1926 if (dirty & WorkArea) {
1927 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->root, property: p->atom(atom: _NET_WORKAREA), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: MAX_PROP_SIZE);
1928 }
1929
1930 if (dirty & SupportingWMCheck) {
1931 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->root, property: p->atom(atom: _NET_SUPPORTING_WM_CHECK), type: XCB_ATOM_WINDOW, long_offset: 0, long_length: 1);
1932 }
1933
1934 if (dirty & VirtualRoots) {
1935 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->root, property: p->atom(atom: _NET_VIRTUAL_ROOTS), type: XCB_ATOM_WINDOW, long_offset: 0, long_length: 1);
1936 }
1937
1938 if (dirty2 & WM2DesktopLayout) {
1939 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->root, property: p->atom(atom: _NET_DESKTOP_LAYOUT), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: MAX_PROP_SIZE);
1940 }
1941
1942 if (dirty2 & WM2ShowingDesktop) {
1943 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->root, property: p->atom(atom: _NET_SHOWING_DESKTOP), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 1);
1944 }
1945
1946 // Get the replies
1947 c = 0;
1948
1949 if (dirty & Supported) {
1950 // Only in Client mode
1951 p->properties = NET::Properties();
1952 p->properties2 = NET::Properties2();
1953 p->windowTypes = NET::WindowTypes();
1954 p->states = NET::States();
1955 p->actions = NET::Actions();
1956
1957 const QList<xcb_atom_t> atoms = get_array_reply<xcb_atom_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_ATOM);
1958 for (const xcb_atom_t atom : atoms) {
1959 updateSupportedProperties(atom);
1960 }
1961 }
1962
1963 if (dirty & ClientList) {
1964 QList<xcb_window_t> clientsToRemove;
1965 QList<xcb_window_t> clientsToAdd;
1966
1967 QList<xcb_window_t> clients = get_array_reply<xcb_window_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_WINDOW);
1968 std::sort(first: clients.begin(), last: clients.end());
1969
1970 if (p->clients) {
1971 if (p->role == Client) {
1972 int new_index = 0;
1973 int old_index = 0;
1974 int old_count = p->clients_count;
1975 int new_count = clients.count();
1976
1977 while (old_index < old_count || new_index < new_count) {
1978 if (old_index == old_count) {
1979 clientsToAdd.append(t: clients[new_index++]);
1980 } else if (new_index == new_count) {
1981 clientsToRemove.append(t: p->clients[old_index++]);
1982 } else {
1983 if (p->clients[old_index] < clients[new_index]) {
1984 clientsToRemove.append(t: p->clients[old_index++]);
1985 } else if (clients[new_index] < p->clients[old_index]) {
1986 clientsToAdd.append(t: clients[new_index++]);
1987 } else {
1988 new_index++;
1989 old_index++;
1990 }
1991 }
1992 }
1993 }
1994
1995 delete[] p->clients;
1996 p->clients = nullptr;
1997 } else {
1998#ifdef NETWMDEBUG
1999 fprintf(stderr, "NETRootInfo::update: client list null, creating\n");
2000#endif
2001
2002 clientsToAdd.reserve(asize: clients.count());
2003 for (int i = 0; i < clients.count(); i++) {
2004 clientsToAdd.append(t: clients[i]);
2005 }
2006 }
2007
2008 if (!clients.isEmpty()) {
2009 p->clients_count = clients.count();
2010 p->clients = new xcb_window_t[clients.count()];
2011 for (int i = 0; i < clients.count(); i++) {
2012 p->clients[i] = clients.at(i);
2013 }
2014 }
2015
2016#ifdef NETWMDEBUG
2017 fprintf(stderr, "NETRootInfo::update: client list updated (%ld clients)\n", p->clients_count);
2018#endif
2019
2020 for (int i = 0; i < clientsToRemove.size(); ++i) {
2021 removeClient(window: clientsToRemove.at(i));
2022 }
2023
2024 for (int i = 0; i < clientsToAdd.size(); ++i) {
2025 addClient(window: clientsToAdd.at(i));
2026 }
2027 }
2028
2029 if (dirty & ClientListStacking) {
2030 p->stacking_count = 0;
2031
2032 delete[] p->stacking;
2033 p->stacking = nullptr;
2034
2035 const QList<xcb_window_t> wins = get_array_reply<xcb_window_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_WINDOW);
2036
2037 if (!wins.isEmpty()) {
2038 p->stacking_count = wins.count();
2039 p->stacking = new xcb_window_t[wins.count()];
2040 for (int i = 0; i < wins.count(); i++) {
2041 p->stacking[i] = wins.at(i);
2042 }
2043 }
2044
2045#ifdef NETWMDEBUG
2046 fprintf(stderr, "NETRootInfo::update: client stacking updated (%ld clients)\n", p->stacking_count);
2047#endif
2048 }
2049
2050 if (dirty & NumberOfDesktops) {
2051 p->number_of_desktops = get_value_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL, def: 0);
2052
2053#ifdef NETWMDEBUG
2054 fprintf(stderr, "NETRootInfo::update: number of desktops = %d\n", p->number_of_desktops);
2055#endif
2056 }
2057
2058 if (dirty & DesktopGeometry) {
2059 p->geometry = p->rootSize;
2060
2061 const QList<uint32_t> data = get_array_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL);
2062 if (data.count() == 2) {
2063 p->geometry.width = data.at(i: 0);
2064 p->geometry.height = data.at(i: 1);
2065 }
2066
2067#ifdef NETWMDEBUG
2068 fprintf(stderr, "NETRootInfo::update: desktop geometry updated\n");
2069#endif
2070 }
2071
2072 if (dirty & DesktopViewport) {
2073 for (int i = 0; i < p->viewport.size(); i++) {
2074 p->viewport[i].x = p->viewport[i].y = 0;
2075 }
2076
2077 const QList<uint32_t> data = get_array_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL);
2078
2079 if (data.count() >= 2) {
2080 int n = data.count() / 2;
2081 for (int d = 0, i = 0; d < n; d++) {
2082 p->viewport[d].x = data[i++];
2083 p->viewport[d].y = data[i++];
2084 }
2085
2086#ifdef NETWMDEBUG
2087 fprintf(stderr, "NETRootInfo::update: desktop viewport array updated (%d entries)\n", p->viewport.size());
2088
2089 if (data.count() % 2 != 0) {
2090 fprintf(stderr,
2091 "NETRootInfo::update(): desktop viewport array "
2092 "size not a multiple of 2\n");
2093 }
2094#endif
2095 }
2096 }
2097
2098 if (dirty & CurrentDesktop) {
2099 p->current_desktop = get_value_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL, def: 0) + 1;
2100
2101#ifdef NETWMDEBUG
2102 fprintf(stderr, "NETRootInfo::update: current desktop = %d\n", p->current_desktop);
2103#endif
2104 }
2105
2106 if (dirty & DesktopNames) {
2107 for (int i = 0; i < p->desktop_names.size(); ++i) {
2108 delete[] p->desktop_names[i];
2109 }
2110
2111 p->desktop_names.reset();
2112
2113 const QList<QByteArray> names = get_stringlist_reply(c: p->conn, cookie: cookies[c++], type: p->atom(atom: UTF8_STRING));
2114 for (int i = 0; i < names.count(); i++) {
2115 p->desktop_names[i] = nstrndup(s1: names[i].constData(), l: names[i].length());
2116 }
2117
2118#ifdef NETWMDEBUG
2119 fprintf(stderr, "NETRootInfo::update: desktop names array updated (%d entries)\n", p->desktop_names.size());
2120#endif
2121 }
2122
2123 if (dirty & ActiveWindow) {
2124 p->active = get_value_reply<xcb_window_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_WINDOW, def: 0);
2125
2126#ifdef NETWMDEBUG
2127 fprintf(stderr, "NETRootInfo::update: active window = 0x%lx\n", p->active);
2128#endif
2129 }
2130
2131 if (dirty & WorkArea) {
2132 p->workarea.reset();
2133
2134 const QList<uint32_t> data = get_array_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL);
2135 if (data.count() == p->number_of_desktops * 4) {
2136 for (int i = 0, j = 0; i < p->number_of_desktops; i++) {
2137 p->workarea[i].pos.x = data[j++];
2138 p->workarea[i].pos.y = data[j++];
2139 p->workarea[i].size.width = data[j++];
2140 p->workarea[i].size.height = data[j++];
2141 }
2142 }
2143
2144#ifdef NETWMDEBUG
2145 fprintf(stderr, "NETRootInfo::update: work area array updated (%d entries)\n", p->workarea.size());
2146#endif
2147 }
2148
2149 if (dirty & SupportingWMCheck) {
2150 delete[] p->name;
2151 p->name = nullptr;
2152
2153 p->supportwindow = get_value_reply<xcb_window_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_WINDOW, def: 0);
2154
2155 // We'll get the reply for this request at the bottom of this function,
2156 // after we've processing the other pending replies
2157 if (p->supportwindow) {
2158 wm_name_cookie = xcb_get_property(c: p->conn, delete: false, window: p->supportwindow, property: p->atom(atom: _NET_WM_NAME), type: p->atom(atom: UTF8_STRING), long_offset: 0, long_length: MAX_PROP_SIZE);
2159 }
2160 }
2161
2162 if (dirty & VirtualRoots) {
2163 p->virtual_roots_count = 0;
2164
2165 delete[] p->virtual_roots;
2166 p->virtual_roots = nullptr;
2167
2168 const QList<xcb_window_t> wins = get_array_reply<xcb_window_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL);
2169
2170 if (!wins.isEmpty()) {
2171 p->virtual_roots_count = wins.count();
2172 p->virtual_roots = new xcb_window_t[wins.count()];
2173 for (int i = 0; i < wins.count(); i++) {
2174 p->virtual_roots[i] = wins.at(i);
2175 }
2176 }
2177
2178#ifdef NETWMDEBUG
2179 fprintf(stderr, "NETRootInfo::updated: virtual roots updated (%ld windows)\n", p->virtual_roots_count);
2180#endif
2181 }
2182
2183 if (dirty2 & WM2DesktopLayout) {
2184 p->desktop_layout_orientation = OrientationHorizontal;
2185 p->desktop_layout_corner = DesktopLayoutCornerTopLeft;
2186 p->desktop_layout_columns = p->desktop_layout_rows = 0;
2187
2188 const QList<uint32_t> data = get_array_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL);
2189
2190 if (data.count() >= 4 && data[3] <= 3) {
2191 p->desktop_layout_corner = (NET::DesktopLayoutCorner)data[3];
2192 }
2193
2194 if (data.count() >= 3) {
2195 if (data[0] <= 1) {
2196 p->desktop_layout_orientation = (NET::Orientation)data[0];
2197 }
2198
2199 p->desktop_layout_columns = data[1];
2200 p->desktop_layout_rows = data[2];
2201 }
2202
2203#ifdef NETWMDEBUG
2204 fprintf(stderr,
2205 "NETRootInfo::updated: desktop layout updated (%d %d %d %d)\n",
2206 p->desktop_layout_orientation,
2207 p->desktop_layout_columns,
2208 p->desktop_layout_rows,
2209 p->desktop_layout_corner);
2210#endif
2211 }
2212
2213 if (dirty2 & WM2ShowingDesktop) {
2214 const uint32_t val = get_value_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL, def: 0);
2215 p->showing_desktop = bool(val);
2216
2217#ifdef NETWMDEBUG
2218 fprintf(stderr, "NETRootInfo::update: showing desktop = %d\n", p->showing_desktop);
2219#endif
2220 }
2221
2222 if ((dirty & SupportingWMCheck) && p->supportwindow) {
2223 const QByteArray ba = get_string_reply(c: p->conn, cookie: wm_name_cookie, type: p->atom(atom: UTF8_STRING));
2224 if (ba.length() > 0) {
2225 p->name = nstrndup(s1: (const char *)ba.constData(), l: ba.length());
2226 }
2227
2228#ifdef NETWMDEBUG
2229 fprintf(stderr, "NETRootInfo::update: supporting window manager = '%s'\n", p->name);
2230#endif
2231 }
2232}
2233
2234xcb_connection_t *NETRootInfo::xcbConnection() const
2235{
2236 return p->conn;
2237}
2238
2239xcb_window_t NETRootInfo::rootWindow() const
2240{
2241 return p->root;
2242}
2243
2244xcb_window_t NETRootInfo::supportWindow() const
2245{
2246 return p->supportwindow;
2247}
2248
2249const char *NETRootInfo::wmName() const
2250{
2251 return p->name;
2252}
2253
2254NET::Properties NETRootInfo::supportedProperties() const
2255{
2256 return p->properties;
2257}
2258
2259NET::Properties2 NETRootInfo::supportedProperties2() const
2260{
2261 return p->properties2;
2262}
2263
2264NET::States NETRootInfo::supportedStates() const
2265{
2266 return p->states;
2267}
2268
2269NET::WindowTypes NETRootInfo::supportedWindowTypes() const
2270{
2271 return p->windowTypes;
2272}
2273
2274NET::Actions NETRootInfo::supportedActions() const
2275{
2276 return p->actions;
2277}
2278
2279NET::Properties NETRootInfo::passedProperties() const
2280{
2281 return p->role == WindowManager ? p->properties : p->clientProperties;
2282}
2283
2284NET::Properties2 NETRootInfo::passedProperties2() const
2285{
2286 return p->role == WindowManager ? p->properties2 : p->clientProperties2;
2287}
2288
2289NET::States NETRootInfo::passedStates() const
2290{
2291 return p->role == WindowManager ? p->states : NET::States();
2292}
2293
2294NET::WindowTypes NETRootInfo::passedWindowTypes() const
2295{
2296 return p->role == WindowManager ? p->windowTypes : NET::WindowTypes();
2297}
2298
2299NET::Actions NETRootInfo::passedActions() const
2300{
2301 return p->role == WindowManager ? p->actions : NET::Actions();
2302}
2303
2304void NETRootInfo::setSupported(NET::Property property, bool on)
2305{
2306 if (p->role != WindowManager) {
2307 return;
2308 }
2309
2310 if (on && !isSupported(property)) {
2311 p->properties |= property;
2312 setSupported();
2313 } else if (!on && isSupported(property)) {
2314 p->properties &= ~property;
2315 setSupported();
2316 }
2317}
2318
2319void NETRootInfo::setSupported(NET::Property2 property, bool on)
2320{
2321 if (p->role != WindowManager) {
2322 return;
2323 }
2324
2325 if (on && !isSupported(property)) {
2326 p->properties2 |= property;
2327 setSupported();
2328 } else if (!on && isSupported(property)) {
2329 p->properties2 &= ~property;
2330 setSupported();
2331 }
2332}
2333
2334void NETRootInfo::setSupported(NET::WindowTypeMask property, bool on)
2335{
2336 if (p->role != WindowManager) {
2337 return;
2338 }
2339
2340 if (on && !isSupported(type: property)) {
2341 p->windowTypes |= property;
2342 setSupported();
2343 } else if (!on && isSupported(type: property)) {
2344 p->windowTypes &= ~property;
2345 setSupported();
2346 }
2347}
2348
2349void NETRootInfo::setSupported(NET::State property, bool on)
2350{
2351 if (p->role != WindowManager) {
2352 return;
2353 }
2354
2355 if (on && !isSupported(state: property)) {
2356 p->states |= property;
2357 setSupported();
2358 } else if (!on && isSupported(state: property)) {
2359 p->states &= ~property;
2360 setSupported();
2361 }
2362}
2363
2364void NETRootInfo::setSupported(NET::Action property, bool on)
2365{
2366 if (p->role != WindowManager) {
2367 return;
2368 }
2369
2370 if (on && !isSupported(action: property)) {
2371 p->actions |= property;
2372 setSupported();
2373 } else if (!on && isSupported(action: property)) {
2374 p->actions &= ~property;
2375 setSupported();
2376 }
2377}
2378
2379bool NETRootInfo::isSupported(NET::Property property) const
2380{
2381 return p->properties & property;
2382}
2383
2384bool NETRootInfo::isSupported(NET::Property2 property) const
2385{
2386 return p->properties2 & property;
2387}
2388
2389bool NETRootInfo::isSupported(NET::WindowTypeMask type) const
2390{
2391 return p->windowTypes & type;
2392}
2393
2394bool NETRootInfo::isSupported(NET::State state) const
2395{
2396 return p->states & state;
2397}
2398
2399bool NETRootInfo::isSupported(NET::Action action) const
2400{
2401 return p->actions & action;
2402}
2403
2404const xcb_window_t *NETRootInfo::clientList() const
2405{
2406 return p->clients;
2407}
2408
2409int NETRootInfo::clientListCount() const
2410{
2411 return p->clients_count;
2412}
2413
2414const xcb_window_t *NETRootInfo::clientListStacking() const
2415{
2416 return p->stacking;
2417}
2418
2419int NETRootInfo::clientListStackingCount() const
2420{
2421 return p->stacking_count;
2422}
2423
2424NETSize NETRootInfo::desktopGeometry() const
2425{
2426 return p->geometry.width != 0 ? p->geometry : p->rootSize;
2427}
2428
2429NETPoint NETRootInfo::desktopViewport(int desktop) const
2430{
2431 if (desktop < 1) {
2432 NETPoint pt; // set to (0,0)
2433 return pt;
2434 }
2435
2436 return p->viewport[desktop - 1];
2437}
2438
2439NETRect NETRootInfo::workArea(int desktop) const
2440{
2441 if (desktop < 1) {
2442 NETRect rt;
2443 return rt;
2444 }
2445
2446 return p->workarea[desktop - 1];
2447}
2448
2449const char *NETRootInfo::desktopName(int desktop) const
2450{
2451 if (desktop < 1) {
2452 return nullptr;
2453 }
2454
2455 return p->desktop_names[desktop - 1];
2456}
2457
2458const xcb_window_t *NETRootInfo::virtualRoots() const
2459{
2460 return p->virtual_roots;
2461}
2462
2463int NETRootInfo::virtualRootsCount() const
2464{
2465 return p->virtual_roots_count;
2466}
2467
2468NET::Orientation NETRootInfo::desktopLayoutOrientation() const
2469{
2470 return p->desktop_layout_orientation;
2471}
2472
2473QSize NETRootInfo::desktopLayoutColumnsRows() const
2474{
2475 return QSize(p->desktop_layout_columns, p->desktop_layout_rows);
2476}
2477
2478NET::DesktopLayoutCorner NETRootInfo::desktopLayoutCorner() const
2479{
2480 return p->desktop_layout_corner;
2481}
2482
2483int NETRootInfo::numberOfDesktops(bool ignore_viewport) const
2484{
2485 if (!ignore_viewport && KX11Extras::mapViewport()) {
2486 return KX11Extras::numberOfDesktops();
2487 }
2488 return p->number_of_desktops == 0 ? 1 : p->number_of_desktops;
2489}
2490
2491int NETRootInfo::currentDesktop(bool ignore_viewport) const
2492{
2493 if (!ignore_viewport && KX11Extras::mapViewport()) {
2494 return KX11Extras::currentDesktop();
2495 }
2496 return p->current_desktop == 0 ? 1 : p->current_desktop;
2497}
2498
2499xcb_window_t NETRootInfo::activeWindow() const
2500{
2501 return p->active;
2502}
2503
2504// NETWinInfo stuffs
2505
2506const int NETWinInfo::OnAllDesktops = NET::OnAllDesktops;
2507
2508NETWinInfo::NETWinInfo(xcb_connection_t *connection,
2509 xcb_window_t window,
2510 xcb_window_t rootWindow,
2511 NET::Properties properties,
2512 NET::Properties2 properties2,
2513 Role role)
2514{
2515#ifdef NETWMDEBUG
2516 fprintf(stderr, "NETWinInfo::NETWinInfo: constructing object with role '%s'\n", (role == WindowManager) ? "WindowManager" : "Client");
2517#endif
2518
2519 p = new NETWinInfoPrivate;
2520 p->ref = 1;
2521 p->atoms = atomsForConnection(c: connection);
2522
2523 p->conn = connection;
2524 p->window = window;
2525 p->root = rootWindow;
2526 p->mapping_state = Withdrawn;
2527 p->mapping_state_dirty = true;
2528 p->state = NET::States();
2529 p->types[0] = Unknown;
2530 p->name = (char *)nullptr;
2531 p->visible_name = (char *)nullptr;
2532 p->icon_name = (char *)nullptr;
2533 p->visible_icon_name = (char *)nullptr;
2534 p->desktop = p->pid = 0;
2535 p->handled_icons = false;
2536 p->user_time = -1U;
2537 p->startup_id = nullptr;
2538 p->transient_for = XCB_NONE;
2539 p->opacity = 0xffffffffU;
2540 p->window_group = XCB_NONE;
2541 p->icon_pixmap = XCB_PIXMAP_NONE;
2542 p->icon_mask = XCB_PIXMAP_NONE;
2543 p->allowed_actions = NET::Actions();
2544 p->has_net_support = false;
2545 p->class_class = (char *)nullptr;
2546 p->class_name = (char *)nullptr;
2547 p->window_role = (char *)nullptr;
2548 p->client_machine = (char *)nullptr;
2549 p->icon_sizes = nullptr;
2550 p->activities = (char *)nullptr;
2551 p->desktop_file = nullptr;
2552 p->gtk_application_id = nullptr;
2553 p->appmenu_object_path = nullptr;
2554 p->appmenu_service_name = nullptr;
2555 p->blockCompositing = false;
2556 p->urgency = false;
2557 p->input = true;
2558 p->initialMappingState = NET::Withdrawn;
2559 p->protocols = NET::NoProtocol;
2560
2561 // p->strut.left = p->strut.right = p->strut.top = p->strut.bottom = 0;
2562 // p->frame_strut.left = p->frame_strut.right = p->frame_strut.top =
2563 // p->frame_strut.bottom = 0;
2564
2565 p->properties = properties;
2566 p->properties2 = properties2;
2567
2568 p->icon_count = 0;
2569
2570 p->role = role;
2571
2572 update(dirtyProperties: p->properties, dirtyProperties2: p->properties2);
2573}
2574
2575NETWinInfo::NETWinInfo(const NETWinInfo &wininfo)
2576{
2577 p = wininfo.p;
2578 p->ref++;
2579}
2580
2581NETWinInfo::~NETWinInfo()
2582{
2583 refdec_nwi(p);
2584
2585 if (!p->ref) {
2586 delete p;
2587 }
2588}
2589
2590// assignment operator
2591
2592const NETWinInfo &NETWinInfo::operator=(const NETWinInfo &wininfo)
2593{
2594#ifdef NETWMDEBUG
2595 fprintf(stderr, "NETWinInfo::operator=()\n");
2596#endif
2597
2598 if (p != wininfo.p) {
2599 refdec_nwi(p);
2600
2601 if (!p->ref) {
2602 delete p;
2603 }
2604 }
2605
2606 p = wininfo.p;
2607 p->ref++;
2608
2609 return *this;
2610}
2611
2612void NETWinInfo::setIcon(NETIcon icon, bool replace)
2613{
2614 setIconInternal(icons&: p->icons, icon_count&: p->icon_count, property: p->atom(atom: _NET_WM_ICON), icon, replace);
2615}
2616
2617void NETWinInfo::setIconInternal(NETRArray<NETIcon> &icons, int &icon_count, xcb_atom_t property, NETIcon icon, bool replace)
2618{
2619 if (p->role != Client) {
2620 return;
2621 }
2622
2623 if (replace) {
2624 for (int i = 0; i < icons.size(); i++) {
2625 delete[] icons[i].data;
2626
2627 icons[i].data = nullptr;
2628 icons[i].size.width = 0;
2629 icons[i].size.height = 0;
2630 }
2631
2632 icon_count = 0;
2633 }
2634
2635 // assign icon
2636 icons[icon_count] = icon;
2637 icon_count++;
2638
2639 // do a deep copy, we want to own the data
2640 NETIcon &ni = icons[icon_count - 1];
2641 int sz = ni.size.width * ni.size.height;
2642 uint32_t *d = new uint32_t[sz];
2643 ni.data = (unsigned char *)d;
2644 memcpy(dest: d, src: icon.data, n: sz * sizeof(uint32_t));
2645
2646 // compute property length
2647 int proplen = 0;
2648 for (int i = 0; i < icon_count; i++) {
2649 proplen += 2 + (icons[i].size.width * icons[i].size.height);
2650 }
2651
2652 uint32_t *prop = new uint32_t[proplen];
2653 uint32_t *pprop = prop;
2654 for (int i = 0; i < icon_count; i++) {
2655 // copy size into property
2656 *pprop++ = icons[i].size.width;
2657 *pprop++ = icons[i].size.height;
2658
2659 // copy data into property
2660 sz = (icons[i].size.width * icons[i].size.height);
2661 uint32_t *d32 = (uint32_t *)icons[i].data;
2662 for (int j = 0; j < sz; j++) {
2663 *pprop++ = *d32++;
2664 }
2665 }
2666
2667 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property, type: XCB_ATOM_CARDINAL, format: 32, data_len: proplen, data: (const void *)prop);
2668
2669 delete[] prop;
2670 delete[] p->icon_sizes;
2671 p->icon_sizes = nullptr;
2672}
2673
2674void NETWinInfo::setIconGeometry(NETRect geometry)
2675{
2676 if (p->role != Client) {
2677 return;
2678 }
2679
2680 const qreal scaleFactor = qApp->devicePixelRatio();
2681 geometry.pos.x *= scaleFactor;
2682 geometry.pos.y *= scaleFactor;
2683 geometry.size.width *= scaleFactor;
2684 geometry.size.height *= scaleFactor;
2685
2686 p->icon_geom = geometry;
2687
2688 if (geometry.size.width == 0) { // Empty
2689 xcb_delete_property(c: p->conn, window: p->window, property: p->atom(atom: _NET_WM_ICON_GEOMETRY));
2690 } else {
2691 uint32_t data[4];
2692 data[0] = geometry.pos.x;
2693 data[1] = geometry.pos.y;
2694 data[2] = geometry.size.width;
2695 data[3] = geometry.size.height;
2696
2697 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_ICON_GEOMETRY), type: XCB_ATOM_CARDINAL, format: 32, data_len: 4, data: (const void *)data);
2698 }
2699}
2700
2701void NETWinInfo::setExtendedStrut(const NETExtendedStrut &extended_strut)
2702{
2703 if (p->role != Client) {
2704 return;
2705 }
2706
2707 p->extended_strut = extended_strut;
2708
2709 uint32_t data[12];
2710 data[0] = extended_strut.left_width;
2711 data[1] = extended_strut.right_width;
2712 data[2] = extended_strut.top_width;
2713 data[3] = extended_strut.bottom_width;
2714 data[4] = extended_strut.left_start;
2715 data[5] = extended_strut.left_end;
2716 data[6] = extended_strut.right_start;
2717 data[7] = extended_strut.right_end;
2718 data[8] = extended_strut.top_start;
2719 data[9] = extended_strut.top_end;
2720 data[10] = extended_strut.bottom_start;
2721 data[11] = extended_strut.bottom_end;
2722
2723 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_STRUT_PARTIAL), type: XCB_ATOM_CARDINAL, format: 32, data_len: 12, data: (const void *)data);
2724}
2725
2726void NETWinInfo::setStrut(NETStrut strut)
2727{
2728 if (p->role != Client) {
2729 return;
2730 }
2731
2732 p->strut = strut;
2733
2734 uint32_t data[4];
2735 data[0] = strut.left;
2736 data[1] = strut.right;
2737 data[2] = strut.top;
2738 data[3] = strut.bottom;
2739
2740 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_STRUT), type: XCB_ATOM_CARDINAL, format: 32, data_len: 4, data: (const void *)data);
2741}
2742
2743void NETWinInfo::setFullscreenMonitors(NETFullscreenMonitors topology)
2744{
2745 if (p->role == Client) {
2746 const uint32_t data[5] = {uint32_t(topology.top), uint32_t(topology.bottom), uint32_t(topology.left), uint32_t(topology.right), 1};
2747
2748 send_client_message(c: p->conn, mask: netwm_sendevent_mask, destination: p->root, window: p->window, message: p->atom(atom: _NET_WM_FULLSCREEN_MONITORS), data);
2749 } else {
2750 p->fullscreen_monitors = topology;
2751
2752 uint32_t data[4];
2753 data[0] = topology.top;
2754 data[1] = topology.bottom;
2755 data[2] = topology.left;
2756 data[3] = topology.right;
2757
2758 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_FULLSCREEN_MONITORS), type: XCB_ATOM_CARDINAL, format: 32, data_len: 4, data: (const void *)data);
2759 }
2760}
2761
2762void NETWinInfo::setState(NET::States state, NET::States mask)
2763{
2764 if (p->mapping_state_dirty) {
2765 updateWMState();
2766 }
2767
2768 // setState() needs to know the current state, so read it even if not requested
2769 if ((p->properties & WMState) == 0) {
2770 p->properties |= WMState;
2771
2772 update(dirtyProperties: WMState);
2773
2774 p->properties &= ~WMState;
2775 }
2776
2777 if (p->role == Client && p->mapping_state != Withdrawn) {
2778#ifdef NETWMDEBUG
2779 fprintf(stderr, "NETWinInfo::setState (0x%lx, 0x%lx) (Client)\n", state, mask);
2780#endif // NETWMDEBUG
2781
2782 KXcbEvent<xcb_client_message_event_t> event;
2783 event.response_type = XCB_CLIENT_MESSAGE;
2784 event.format = 32;
2785 event.sequence = 0;
2786 event.window = p->window;
2787 event.type = p->atom(atom: _NET_WM_STATE);
2788 event.data.data32[3] = 0;
2789 event.data.data32[4] = 0;
2790
2791 if ((mask & Modal) && ((p->state & Modal) != (state & Modal))) {
2792 event.data.data32[0] = (state & Modal) ? 1 : 0;
2793 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_MODAL);
2794 event.data.data32[2] = 0l;
2795
2796 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2797 }
2798
2799 if ((mask & Sticky) && ((p->state & Sticky) != (state & Sticky))) {
2800 event.data.data32[0] = (state & Sticky) ? 1 : 0;
2801 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_STICKY);
2802 event.data.data32[2] = 0l;
2803
2804 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2805 }
2806
2807 if ((mask & Max) && (((p->state & mask) & Max) != (state & Max))) {
2808 NET::States wishstate = (p->state & ~mask) | (state & mask);
2809 if (((wishstate & MaxHoriz) != (p->state & MaxHoriz)) && ((wishstate & MaxVert) != (p->state & MaxVert))) {
2810 if ((wishstate & Max) == Max) {
2811 event.data.data32[0] = 1;
2812 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_MAXIMIZED_HORZ);
2813 event.data.data32[2] = p->atom(atom: _NET_WM_STATE_MAXIMIZED_VERT);
2814 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2815 } else if ((wishstate & Max) == 0) {
2816 event.data.data32[0] = 0;
2817 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_MAXIMIZED_HORZ);
2818 event.data.data32[2] = p->atom(atom: _NET_WM_STATE_MAXIMIZED_VERT);
2819 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2820 } else {
2821 event.data.data32[0] = (wishstate & MaxHoriz) ? 1 : 0;
2822 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_MAXIMIZED_HORZ);
2823 event.data.data32[2] = 0;
2824 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2825
2826 event.data.data32[0] = (wishstate & MaxVert) ? 1 : 0;
2827 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_MAXIMIZED_VERT);
2828 event.data.data32[2] = 0;
2829 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2830 }
2831 } else if ((wishstate & MaxVert) != (p->state & MaxVert)) {
2832 event.data.data32[0] = (wishstate & MaxVert) ? 1 : 0;
2833 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_MAXIMIZED_VERT);
2834 event.data.data32[2] = 0;
2835
2836 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2837 } else if ((wishstate & MaxHoriz) != (p->state & MaxHoriz)) {
2838 event.data.data32[0] = (wishstate & MaxHoriz) ? 1 : 0;
2839 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_MAXIMIZED_HORZ);
2840 event.data.data32[2] = 0;
2841
2842 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2843 }
2844 }
2845
2846 if ((mask & Shaded) && ((p->state & Shaded) != (state & Shaded))) {
2847 event.data.data32[0] = (state & Shaded) ? 1 : 0;
2848 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_SHADED);
2849 event.data.data32[2] = 0l;
2850
2851 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2852 }
2853
2854 if ((mask & SkipTaskbar) && ((p->state & SkipTaskbar) != (state & SkipTaskbar))) {
2855 event.data.data32[0] = (state & SkipTaskbar) ? 1 : 0;
2856 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_SKIP_TASKBAR);
2857 event.data.data32[2] = 0l;
2858
2859 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2860 }
2861
2862 if ((mask & SkipPager) && ((p->state & SkipPager) != (state & SkipPager))) {
2863 event.data.data32[0] = (state & SkipPager) ? 1 : 0;
2864 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_SKIP_PAGER);
2865 event.data.data32[2] = 0l;
2866
2867 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2868 }
2869
2870 if ((mask & SkipSwitcher) && ((p->state & SkipSwitcher) != (state & SkipSwitcher))) {
2871 event.data.data32[0] = (state & SkipSwitcher) ? 1 : 0;
2872 event.data.data32[1] = p->atom(atom: _KDE_NET_WM_STATE_SKIP_SWITCHER);
2873 event.data.data32[2] = 0l;
2874
2875 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2876 }
2877
2878 if ((mask & Hidden) && ((p->state & Hidden) != (state & Hidden))) {
2879 event.data.data32[0] = (state & Hidden) ? 1 : 0;
2880 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_HIDDEN);
2881 event.data.data32[2] = 0l;
2882
2883 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2884 }
2885
2886 if ((mask & FullScreen) && ((p->state & FullScreen) != (state & FullScreen))) {
2887 event.data.data32[0] = (state & FullScreen) ? 1 : 0;
2888 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_FULLSCREEN);
2889 event.data.data32[2] = 0l;
2890
2891 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2892 }
2893
2894 if ((mask & KeepAbove) && ((p->state & KeepAbove) != (state & KeepAbove))) {
2895 event.data.data32[0] = (state & KeepAbove) ? 1 : 0;
2896 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_ABOVE);
2897 event.data.data32[2] = 0l;
2898
2899 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2900
2901 // deprecated variant
2902 event.data.data32[0] = (state & KeepAbove) ? 1 : 0;
2903 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_STAYS_ON_TOP);
2904 event.data.data32[2] = 0l;
2905
2906 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2907 }
2908
2909 if ((mask & KeepBelow) && ((p->state & KeepBelow) != (state & KeepBelow))) {
2910 event.data.data32[0] = (state & KeepBelow) ? 1 : 0;
2911 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_BELOW);
2912 event.data.data32[2] = 0l;
2913
2914 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2915 }
2916
2917 if ((mask & DemandsAttention) && ((p->state & DemandsAttention) != (state & DemandsAttention))) {
2918 event.data.data32[0] = (state & DemandsAttention) ? 1 : 0;
2919 event.data.data32[1] = p->atom(atom: _NET_WM_STATE_DEMANDS_ATTENTION);
2920 event.data.data32[2] = 0l;
2921
2922 xcb_send_event(c: p->conn, propagate: false, destination: p->root, event_mask: netwm_sendevent_mask, event: event.buffer());
2923 }
2924
2925 // Focused is not added here as it is effectively "read only" set by the WM, a client setting it would be silly
2926 } else {
2927 p->state &= ~mask;
2928 p->state |= state;
2929
2930 uint32_t data[50];
2931 int count = 0;
2932
2933 // Hints
2934 if (p->state & Modal) {
2935 data[count++] = p->atom(atom: _NET_WM_STATE_MODAL);
2936 }
2937 if (p->state & MaxVert) {
2938 data[count++] = p->atom(atom: _NET_WM_STATE_MAXIMIZED_VERT);
2939 }
2940 if (p->state & MaxHoriz) {
2941 data[count++] = p->atom(atom: _NET_WM_STATE_MAXIMIZED_HORZ);
2942 }
2943 if (p->state & Shaded) {
2944 data[count++] = p->atom(atom: _NET_WM_STATE_SHADED);
2945 }
2946 if (p->state & Hidden) {
2947 data[count++] = p->atom(atom: _NET_WM_STATE_HIDDEN);
2948 }
2949 if (p->state & FullScreen) {
2950 data[count++] = p->atom(atom: _NET_WM_STATE_FULLSCREEN);
2951 }
2952 if (p->state & DemandsAttention) {
2953 data[count++] = p->atom(atom: _NET_WM_STATE_DEMANDS_ATTENTION);
2954 }
2955 if (p->state & Focused) {
2956 data[count++] = p->atom(atom: _NET_WM_STATE_FOCUSED);
2957 }
2958
2959 // Policy
2960 if (p->state & KeepAbove) {
2961 data[count++] = p->atom(atom: _NET_WM_STATE_ABOVE);
2962 // deprecated variant
2963 data[count++] = p->atom(atom: _NET_WM_STATE_STAYS_ON_TOP);
2964 }
2965 if (p->state & KeepBelow) {
2966 data[count++] = p->atom(atom: _NET_WM_STATE_BELOW);
2967 }
2968 if (p->state & Sticky) {
2969 data[count++] = p->atom(atom: _NET_WM_STATE_STICKY);
2970 }
2971 if (p->state & SkipTaskbar) {
2972 data[count++] = p->atom(atom: _NET_WM_STATE_SKIP_TASKBAR);
2973 }
2974 if (p->state & SkipPager) {
2975 data[count++] = p->atom(atom: _NET_WM_STATE_SKIP_PAGER);
2976 }
2977 if (p->state & SkipSwitcher) {
2978 data[count++] = p->atom(atom: _KDE_NET_WM_STATE_SKIP_SWITCHER);
2979 }
2980
2981#ifdef NETWMDEBUG
2982 fprintf(stderr, "NETWinInfo::setState: setting state property (%d)\n", count);
2983 for (int i = 0; i < count; i++) {
2984 const QByteArray ba = get_atom_name(p->conn, data[i]);
2985 fprintf(stderr, "NETWinInfo::setState: state %ld '%s'\n", data[i], ba.constData());
2986 }
2987#endif
2988
2989 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_STATE), type: XCB_ATOM_ATOM, format: 32, data_len: count, data: (const void *)data);
2990 }
2991}
2992
2993void NETWinInfo::setWindowType(WindowType type)
2994{
2995 if (p->role != Client) {
2996 return;
2997 }
2998
2999 int len;
3000 uint32_t data[2];
3001
3002 switch (type) {
3003 case Override:
3004 // spec extension: override window type. we must comply with the spec
3005 // and provide a fall back (normal seems best)
3006 data[0] = p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_OVERRIDE);
3007 data[1] = p->atom(atom: _NET_WM_WINDOW_TYPE_NORMAL);
3008 len = 2;
3009 break;
3010
3011 case Dialog:
3012 data[0] = p->atom(atom: _NET_WM_WINDOW_TYPE_DIALOG);
3013 data[1] = XCB_NONE;
3014 len = 1;
3015 break;
3016
3017 case Menu:
3018 data[0] = p->atom(atom: _NET_WM_WINDOW_TYPE_MENU);
3019 data[1] = XCB_NONE;
3020 len = 1;
3021 break;
3022
3023 case TopMenu:
3024 // spec extension: override window type. we must comply with the spec
3025 // and provide a fall back (dock seems best)
3026 data[0] = p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_TOPMENU);
3027 data[1] = p->atom(atom: _NET_WM_WINDOW_TYPE_DOCK);
3028 len = 2;
3029 break;
3030
3031 case Toolbar:
3032 data[0] = p->atom(atom: _NET_WM_WINDOW_TYPE_TOOLBAR);
3033 data[1] = XCB_NONE;
3034 len = 1;
3035 break;
3036
3037 case Dock:
3038 data[0] = p->atom(atom: _NET_WM_WINDOW_TYPE_DOCK);
3039 data[1] = XCB_NONE;
3040 len = 1;
3041 break;
3042
3043 case Desktop:
3044 data[0] = p->atom(atom: _NET_WM_WINDOW_TYPE_DESKTOP);
3045 data[1] = XCB_NONE;
3046 len = 1;
3047 break;
3048
3049 case Utility:
3050 data[0] = p->atom(atom: _NET_WM_WINDOW_TYPE_UTILITY);
3051 data[1] = p->atom(atom: _NET_WM_WINDOW_TYPE_DIALOG); // fallback for old netwm version
3052 len = 2;
3053 break;
3054
3055 case Splash:
3056 data[0] = p->atom(atom: _NET_WM_WINDOW_TYPE_SPLASH);
3057 data[1] = p->atom(atom: _NET_WM_WINDOW_TYPE_DOCK); // fallback (dock seems best)
3058 len = 2;
3059 break;
3060
3061 case DropdownMenu:
3062 data[0] = p->atom(atom: _NET_WM_WINDOW_TYPE_DROPDOWN_MENU);
3063 data[1] = p->atom(atom: _NET_WM_WINDOW_TYPE_MENU); // fallback (tearoff seems to be the best)
3064 len = 1;
3065 break;
3066
3067 case PopupMenu:
3068 data[0] = p->atom(atom: _NET_WM_WINDOW_TYPE_POPUP_MENU);
3069 data[1] = p->atom(atom: _NET_WM_WINDOW_TYPE_MENU); // fallback (tearoff seems to be the best)
3070 len = 1;
3071 break;
3072
3073 case Tooltip:
3074 data[0] = p->atom(atom: _NET_WM_WINDOW_TYPE_TOOLTIP);
3075 data[1] = XCB_NONE;
3076 len = 1;
3077 break;
3078
3079 case Notification:
3080 data[0] = p->atom(atom: _NET_WM_WINDOW_TYPE_NOTIFICATION);
3081 data[1] = p->atom(atom: _NET_WM_WINDOW_TYPE_UTILITY); // fallback (utility seems to be the best)
3082 len = 1;
3083 break;
3084
3085 case ComboBox:
3086 data[0] = p->atom(atom: _NET_WM_WINDOW_TYPE_COMBO);
3087 data[1] = XCB_NONE;
3088 len = 1;
3089 break;
3090
3091 case DNDIcon:
3092 data[0] = p->atom(atom: _NET_WM_WINDOW_TYPE_DND);
3093 data[1] = XCB_NONE;
3094 len = 1;
3095 break;
3096
3097 case OnScreenDisplay:
3098 data[0] = p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_ON_SCREEN_DISPLAY);
3099 data[1] = p->atom(atom: _NET_WM_WINDOW_TYPE_NOTIFICATION);
3100 len = 2;
3101 break;
3102
3103 case CriticalNotification:
3104 data[0] = p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_CRITICAL_NOTIFICATION);
3105 data[1] = p->atom(atom: _NET_WM_WINDOW_TYPE_NOTIFICATION);
3106 len = 2;
3107 break;
3108
3109 case AppletPopup:
3110 data[0] = p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_APPLET_POPUP);
3111 data[1] = XCB_NONE;
3112 len = 1;
3113 break;
3114
3115 default:
3116 case Normal:
3117 data[0] = p->atom(atom: _NET_WM_WINDOW_TYPE_NORMAL);
3118 data[1] = XCB_NONE;
3119 len = 1;
3120 break;
3121 }
3122
3123 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_WINDOW_TYPE), type: XCB_ATOM_ATOM, format: 32, data_len: len, data: (const void *)&data);
3124}
3125
3126void NETWinInfo::setName(const char *name)
3127{
3128 if (p->role != Client) {
3129 return;
3130 }
3131
3132 delete[] p->name;
3133 p->name = nstrdup(s1: name);
3134
3135 if (p->name[0] != '\0') {
3136 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_NAME), type: p->atom(atom: UTF8_STRING), format: 8, data_len: strlen(s: p->name), data: (const void *)p->name);
3137 } else {
3138 xcb_delete_property(c: p->conn, window: p->window, property: p->atom(atom: _NET_WM_NAME));
3139 }
3140}
3141
3142void NETWinInfo::setVisibleName(const char *visibleName)
3143{
3144 if (p->role != WindowManager) {
3145 return;
3146 }
3147
3148 delete[] p->visible_name;
3149 p->visible_name = nstrdup(s1: visibleName);
3150
3151 if (p->visible_name[0] != '\0') {
3152 xcb_change_property(c: p->conn,
3153 mode: XCB_PROP_MODE_REPLACE,
3154 window: p->window,
3155 property: p->atom(atom: _NET_WM_VISIBLE_NAME),
3156 type: p->atom(atom: UTF8_STRING),
3157 format: 8,
3158 data_len: strlen(s: p->visible_name),
3159 data: (const void *)p->visible_name);
3160 } else {
3161 xcb_delete_property(c: p->conn, window: p->window, property: p->atom(atom: _NET_WM_VISIBLE_NAME));
3162 }
3163}
3164
3165void NETWinInfo::setIconName(const char *iconName)
3166{
3167 if (p->role != Client) {
3168 return;
3169 }
3170
3171 delete[] p->icon_name;
3172 p->icon_name = nstrdup(s1: iconName);
3173
3174 if (p->icon_name[0] != '\0') {
3175 xcb_change_property(c: p->conn,
3176 mode: XCB_PROP_MODE_REPLACE,
3177 window: p->window,
3178 property: p->atom(atom: _NET_WM_ICON_NAME),
3179 type: p->atom(atom: UTF8_STRING),
3180 format: 8,
3181 data_len: strlen(s: p->icon_name),
3182 data: (const void *)p->icon_name);
3183 } else {
3184 xcb_delete_property(c: p->conn, window: p->window, property: p->atom(atom: _NET_WM_ICON_NAME));
3185 }
3186}
3187
3188void NETWinInfo::setVisibleIconName(const char *visibleIconName)
3189{
3190 if (p->role != WindowManager) {
3191 return;
3192 }
3193
3194 delete[] p->visible_icon_name;
3195 p->visible_icon_name = nstrdup(s1: visibleIconName);
3196
3197 if (p->visible_icon_name[0] != '\0') {
3198 xcb_change_property(c: p->conn,
3199 mode: XCB_PROP_MODE_REPLACE,
3200 window: p->window,
3201 property: p->atom(atom: _NET_WM_VISIBLE_ICON_NAME),
3202 type: p->atom(atom: UTF8_STRING),
3203 format: 8,
3204 data_len: strlen(s: p->visible_icon_name),
3205 data: (const void *)p->visible_icon_name);
3206 } else {
3207 xcb_delete_property(c: p->conn, window: p->window, property: p->atom(atom: _NET_WM_VISIBLE_ICON_NAME));
3208 }
3209}
3210
3211void NETWinInfo::setDesktop(int desktop, bool ignore_viewport)
3212{
3213 if (p->mapping_state_dirty) {
3214 updateWMState();
3215 }
3216
3217 if (p->role == Client && p->mapping_state != Withdrawn) {
3218 // We only send a ClientMessage if we are 1) a client and 2) managed
3219
3220 if (desktop == 0) {
3221 return; // We can't do that while being managed
3222 }
3223
3224 if (!ignore_viewport && KX11Extras::mapViewport()) {
3225 KX11Extras::setOnDesktop(win: p->window, desktop);
3226 return;
3227 }
3228
3229 const uint32_t data[5] = {desktop == OnAllDesktops ? 0xffffffff : desktop - 1, 0, 0, 0, 0};
3230
3231 send_client_message(c: p->conn, mask: netwm_sendevent_mask, destination: p->root, window: p->window, message: p->atom(atom: _NET_WM_DESKTOP), data);
3232 } else {
3233 // Otherwise we just set or remove the property directly
3234 p->desktop = desktop;
3235
3236 if (desktop == 0) {
3237 xcb_delete_property(c: p->conn, window: p->window, property: p->atom(atom: _NET_WM_DESKTOP));
3238 } else {
3239 uint32_t d = (desktop == OnAllDesktops ? 0xffffffff : desktop - 1);
3240 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_DESKTOP), type: XCB_ATOM_CARDINAL, format: 32, data_len: 1, data: (const void *)&d);
3241 }
3242 }
3243}
3244
3245void NETWinInfo::setPid(int pid)
3246{
3247 if (p->role != Client) {
3248 return;
3249 }
3250
3251 p->pid = pid;
3252 uint32_t d = pid;
3253 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_PID), type: XCB_ATOM_CARDINAL, format: 32, data_len: 1, data: (const void *)&d);
3254}
3255
3256void NETWinInfo::setHandledIcons(bool handled)
3257{
3258 if (p->role != Client) {
3259 return;
3260 }
3261
3262 p->handled_icons = handled;
3263 uint32_t d = handled;
3264 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_HANDLED_ICONS), type: XCB_ATOM_CARDINAL, format: 32, data_len: 1, data: (const void *)&d);
3265}
3266
3267void NETWinInfo::setStartupId(const char *id)
3268{
3269 if (p->role != Client) {
3270 return;
3271 }
3272
3273 delete[] p->startup_id;
3274 p->startup_id = nstrdup(s1: id);
3275
3276 xcb_change_property(c: p->conn,
3277 mode: XCB_PROP_MODE_REPLACE,
3278 window: p->window,
3279 property: p->atom(atom: _NET_STARTUP_ID),
3280 type: p->atom(atom: UTF8_STRING),
3281 format: 8,
3282 data_len: strlen(s: p->startup_id),
3283 data: (const void *)p->startup_id);
3284}
3285
3286void NETWinInfo::setOpacity(unsigned long opacity)
3287{
3288 // if (p->role != Client) return;
3289
3290 p->opacity = opacity;
3291 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_WINDOW_OPACITY), type: XCB_ATOM_CARDINAL, format: 32, data_len: 1, data: (const void *)&p->opacity);
3292}
3293
3294void NETWinInfo::setOpacityF(qreal opacity)
3295{
3296 setOpacity(static_cast<unsigned long>(opacity * 0xffffffff));
3297}
3298
3299void NETWinInfo::setAllowedActions(NET::Actions actions)
3300{
3301 if (p->role != WindowManager) {
3302 return;
3303 }
3304
3305 uint32_t data[50];
3306 int count = 0;
3307
3308 p->allowed_actions = actions;
3309 if (p->allowed_actions & ActionMove) {
3310 data[count++] = p->atom(atom: _NET_WM_ACTION_MOVE);
3311 }
3312 if (p->allowed_actions & ActionResize) {
3313 data[count++] = p->atom(atom: _NET_WM_ACTION_RESIZE);
3314 }
3315 if (p->allowed_actions & ActionMinimize) {
3316 data[count++] = p->atom(atom: _NET_WM_ACTION_MINIMIZE);
3317 }
3318 if (p->allowed_actions & ActionShade) {
3319 data[count++] = p->atom(atom: _NET_WM_ACTION_SHADE);
3320 }
3321 if (p->allowed_actions & ActionStick) {
3322 data[count++] = p->atom(atom: _NET_WM_ACTION_STICK);
3323 }
3324 if (p->allowed_actions & ActionMaxVert) {
3325 data[count++] = p->atom(atom: _NET_WM_ACTION_MAXIMIZE_VERT);
3326 }
3327 if (p->allowed_actions & ActionMaxHoriz) {
3328 data[count++] = p->atom(atom: _NET_WM_ACTION_MAXIMIZE_HORZ);
3329 }
3330 if (p->allowed_actions & ActionFullScreen) {
3331 data[count++] = p->atom(atom: _NET_WM_ACTION_FULLSCREEN);
3332 }
3333 if (p->allowed_actions & ActionChangeDesktop) {
3334 data[count++] = p->atom(atom: _NET_WM_ACTION_CHANGE_DESKTOP);
3335 }
3336 if (p->allowed_actions & ActionClose) {
3337 data[count++] = p->atom(atom: _NET_WM_ACTION_CLOSE);
3338 }
3339
3340#ifdef NETWMDEBUG
3341 fprintf(stderr, "NETWinInfo::setAllowedActions: setting property (%d)\n", count);
3342 for (int i = 0; i < count; i++) {
3343 const QByteArray ba = get_atom_name(p->conn, data[i]);
3344 fprintf(stderr, "NETWinInfo::setAllowedActions: action %ld '%s'\n", data[i], ba.constData());
3345 }
3346#endif
3347
3348 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_ALLOWED_ACTIONS), type: XCB_ATOM_ATOM, format: 32, data_len: count, data: (const void *)data);
3349}
3350
3351void NETWinInfo::setFrameExtents(NETStrut strut)
3352{
3353 if (p->role != WindowManager) {
3354 return;
3355 }
3356
3357 p->frame_strut = strut;
3358
3359 uint32_t d[4];
3360 d[0] = strut.left;
3361 d[1] = strut.right;
3362 d[2] = strut.top;
3363 d[3] = strut.bottom;
3364
3365 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_FRAME_EXTENTS), type: XCB_ATOM_CARDINAL, format: 32, data_len: 4, data: (const void *)d);
3366 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _KDE_NET_WM_FRAME_STRUT), type: XCB_ATOM_CARDINAL, format: 32, data_len: 4, data: (const void *)d);
3367}
3368
3369NETStrut NETWinInfo::frameExtents() const
3370{
3371 return p->frame_strut;
3372}
3373
3374void NETWinInfo::setFrameOverlap(NETStrut strut)
3375{
3376 if (strut.left != -1 || strut.top != -1 || strut.right != -1 || strut.bottom != -1) {
3377 strut.left = qMax(a: 0, b: strut.left);
3378 strut.top = qMax(a: 0, b: strut.top);
3379 strut.right = qMax(a: 0, b: strut.right);
3380 strut.bottom = qMax(a: 0, b: strut.bottom);
3381 }
3382
3383 p->frame_overlap = strut;
3384
3385 uint32_t d[4];
3386 d[0] = strut.left;
3387 d[1] = strut.right;
3388 d[2] = strut.top;
3389 d[3] = strut.bottom;
3390
3391 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_FRAME_OVERLAP), type: XCB_ATOM_CARDINAL, format: 32, data_len: 4, data: (const void *)d);
3392}
3393
3394NETStrut NETWinInfo::frameOverlap() const
3395{
3396 return p->frame_overlap;
3397}
3398
3399void NETWinInfo::setGtkFrameExtents(NETStrut strut)
3400{
3401 p->gtk_frame_extents = strut;
3402
3403 uint32_t d[4];
3404 d[0] = strut.left;
3405 d[1] = strut.right;
3406 d[2] = strut.top;
3407 d[3] = strut.bottom;
3408
3409 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _GTK_FRAME_EXTENTS), type: XCB_ATOM_CARDINAL, format: 32, data_len: 4, data: (const void *)d);
3410}
3411
3412NETStrut NETWinInfo::gtkFrameExtents() const
3413{
3414 return p->gtk_frame_extents;
3415}
3416
3417void NETWinInfo::setAppMenuObjectPath(const char *name)
3418{
3419 if (p->role != Client) {
3420 return;
3421 }
3422
3423 delete[] p->appmenu_object_path;
3424 p->appmenu_object_path = nstrdup(s1: name);
3425
3426 xcb_change_property(c: p->conn,
3427 mode: XCB_PROP_MODE_REPLACE,
3428 window: p->window,
3429 property: p->atom(atom: _KDE_NET_WM_APPMENU_OBJECT_PATH),
3430 type: XCB_ATOM_STRING,
3431 format: 8,
3432 data_len: strlen(s: p->appmenu_object_path),
3433 data: (const void *)p->appmenu_object_path);
3434}
3435
3436void NETWinInfo::setAppMenuServiceName(const char *name)
3437{
3438 if (p->role != Client) {
3439 return;
3440 }
3441
3442 delete[] p->appmenu_service_name;
3443 p->appmenu_service_name = nstrdup(s1: name);
3444
3445 xcb_change_property(c: p->conn,
3446 mode: XCB_PROP_MODE_REPLACE,
3447 window: p->window,
3448 property: p->atom(atom: _KDE_NET_WM_APPMENU_SERVICE_NAME),
3449 type: XCB_ATOM_STRING,
3450 format: 8,
3451 data_len: strlen(s: p->appmenu_service_name),
3452 data: (const void *)p->appmenu_service_name);
3453}
3454
3455const char *NETWinInfo::appMenuObjectPath() const
3456{
3457 return p->appmenu_object_path;
3458}
3459
3460const char *NETWinInfo::appMenuServiceName() const
3461{
3462 return p->appmenu_service_name;
3463}
3464
3465void NETWinInfo::kdeGeometry(NETRect &frame, NETRect &window)
3466{
3467 if (p->win_geom.size.width == 0 || p->win_geom.size.height == 0) {
3468 const xcb_get_geometry_cookie_t geometry_cookie = xcb_get_geometry(c: p->conn, drawable: p->window);
3469
3470 const xcb_translate_coordinates_cookie_t translate_cookie = xcb_translate_coordinates(c: p->conn, src_window: p->window, dst_window: p->root, src_x: 0, src_y: 0);
3471
3472 xcb_get_geometry_reply_t *geometry = xcb_get_geometry_reply(c: p->conn, cookie: geometry_cookie, e: nullptr);
3473 xcb_translate_coordinates_reply_t *translated = xcb_translate_coordinates_reply(c: p->conn, cookie: translate_cookie, e: nullptr);
3474
3475 if (geometry && translated) {
3476 p->win_geom.pos.x = translated->dst_x;
3477 p->win_geom.pos.y = translated->dst_y;
3478
3479 p->win_geom.size.width = geometry->width;
3480 p->win_geom.size.height = geometry->height;
3481 }
3482
3483 if (geometry) {
3484 free(ptr: geometry);
3485 }
3486
3487 if (translated) {
3488 free(ptr: translated);
3489 }
3490 }
3491
3492 // TODO try to work also without _NET_WM_FRAME_EXTENTS
3493 window = p->win_geom;
3494
3495 frame.pos.x = window.pos.x - p->frame_strut.left;
3496 frame.pos.y = window.pos.y - p->frame_strut.top;
3497 frame.size.width = window.size.width + p->frame_strut.left + p->frame_strut.right;
3498 frame.size.height = window.size.height + p->frame_strut.top + p->frame_strut.bottom;
3499}
3500
3501NETIcon NETWinInfo::icon(int width, int height) const
3502{
3503 return iconInternal(icons&: p->icons, icon_count: p->icon_count, width, height);
3504}
3505
3506const int *NETWinInfo::iconSizes() const
3507{
3508 if (p->icon_sizes == nullptr) {
3509 p->icon_sizes = new int[p->icon_count * 2 + 2];
3510 for (int i = 0; i < p->icon_count; ++i) {
3511 p->icon_sizes[i * 2] = p->icons[i].size.width;
3512 p->icon_sizes[i * 2 + 1] = p->icons[i].size.height;
3513 }
3514 p->icon_sizes[p->icon_count * 2] = 0; // terminator
3515 p->icon_sizes[p->icon_count * 2 + 1] = 0;
3516 }
3517 return p->icon_sizes;
3518}
3519
3520NETIcon NETWinInfo::iconInternal(NETRArray<NETIcon> &icons, int icon_count, int width, int height) const
3521{
3522 NETIcon result;
3523
3524 if (!icon_count) {
3525 result.size.width = 0;
3526 result.size.height = 0;
3527 result.data = nullptr;
3528 return result;
3529 }
3530
3531 // find the largest icon
3532 result = icons[0];
3533 for (int i = 1; i < icons.size(); i++) {
3534 if (icons[i].size.width >= result.size.width && icons[i].size.height >= result.size.height) {
3535 result = icons[i];
3536 }
3537 }
3538
3539 // return the largest icon if w and h are -1
3540 if (width == -1 && height == -1) {
3541 return result;
3542 }
3543
3544 // find the icon that's closest in size to w x h...
3545 for (int i = 0; i < icons.size(); i++) {
3546 if ((icons[i].size.width >= width && icons[i].size.width < result.size.width)
3547 && (icons[i].size.height >= height && icons[i].size.height < result.size.height)) {
3548 result = icons[i];
3549 }
3550 }
3551
3552 return result;
3553}
3554
3555void NETWinInfo::setUserTime(xcb_timestamp_t time)
3556{
3557 if (p->role != Client) {
3558 return;
3559 }
3560
3561 p->user_time = time;
3562 uint32_t d = time;
3563
3564 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_USER_TIME), type: XCB_ATOM_CARDINAL, format: 32, data_len: 1, data: (const void *)&d);
3565}
3566
3567NET::Properties NETWinInfo::event(xcb_generic_event_t *ev)
3568{
3569 NET::Properties properties;
3570 event(event: ev, properties: &properties);
3571 return properties;
3572}
3573
3574void NETWinInfo::event(xcb_generic_event_t *event, NET::Properties *properties, NET::Properties2 *properties2)
3575{
3576 NET::Properties dirty;
3577 NET::Properties2 dirty2;
3578 bool do_update = false;
3579 const uint8_t eventType = event->response_type & ~0x80;
3580
3581 if (p->role == WindowManager && eventType == XCB_CLIENT_MESSAGE && reinterpret_cast<xcb_client_message_event_t *>(event)->format == 32) {
3582 xcb_client_message_event_t *message = reinterpret_cast<xcb_client_message_event_t *>(event);
3583#ifdef NETWMDEBUG
3584 fprintf(stderr, "NETWinInfo::event: handling ClientMessage event\n");
3585#endif // NETWMDEBUG
3586
3587 if (message->type == p->atom(atom: _NET_WM_STATE)) {
3588 dirty = WMState;
3589
3590 // we need to generate a change mask
3591
3592#ifdef NETWMDEBUG
3593 fprintf(stderr, "NETWinInfo::event: state client message, getting new state/mask\n");
3594#endif
3595
3596 int i;
3597 NET::States state = NET::States();
3598 NET::States mask = NET::States();
3599
3600 for (i = 1; i < 3; i++) {
3601#ifdef NETWMDEBUG
3602 const QByteArray ba = get_atom_name(p->conn, (xcb_atom_t)message->data.data32[i]);
3603 fprintf(stderr, "NETWinInfo::event: message %ld '%s'\n", message->data.data32[i], ba.constData());
3604#endif
3605
3606 if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _NET_WM_STATE_MODAL)) {
3607 mask |= Modal;
3608 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _NET_WM_STATE_STICKY)) {
3609 mask |= Sticky;
3610 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _NET_WM_STATE_MAXIMIZED_VERT)) {
3611 mask |= MaxVert;
3612 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _NET_WM_STATE_MAXIMIZED_HORZ)) {
3613 mask |= MaxHoriz;
3614 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _NET_WM_STATE_SHADED)) {
3615 mask |= Shaded;
3616 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _NET_WM_STATE_SKIP_TASKBAR)) {
3617 mask |= SkipTaskbar;
3618 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _NET_WM_STATE_SKIP_PAGER)) {
3619 mask |= SkipPager;
3620 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _KDE_NET_WM_STATE_SKIP_SWITCHER)) {
3621 mask |= SkipSwitcher;
3622 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _NET_WM_STATE_HIDDEN)) {
3623 mask |= Hidden;
3624 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _NET_WM_STATE_FULLSCREEN)) {
3625 mask |= FullScreen;
3626 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _NET_WM_STATE_ABOVE)) {
3627 mask |= KeepAbove;
3628 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _NET_WM_STATE_BELOW)) {
3629 mask |= KeepBelow;
3630 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _NET_WM_STATE_DEMANDS_ATTENTION)) {
3631 mask |= DemandsAttention;
3632 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _NET_WM_STATE_STAYS_ON_TOP)) {
3633 mask |= KeepAbove;
3634 } else if ((xcb_atom_t)message->data.data32[i] == p->atom(atom: _NET_WM_STATE_FOCUSED)) {
3635 mask |= Focused;
3636 }
3637 }
3638
3639 // when removing, we just leave newstate == 0
3640 switch (message->data.data32[0]) {
3641 case 1: // set
3642 // to set... the change state should be the same as the mask
3643 state = mask;
3644 break;
3645
3646 case 2: // toggle
3647 // to toggle, we need to xor the current state with the new state
3648 state = (p->state & mask) ^ mask;
3649 break;
3650
3651 default:
3652 // to clear state, the new state should stay zero
3653 ;
3654 }
3655
3656#ifdef NETWMDEBUG
3657 fprintf(stderr, "NETWinInfo::event: calling changeState(%lx, %lx)\n", state, mask);
3658#endif
3659
3660 changeState(state, mask);
3661 } else if (message->type == p->atom(atom: _NET_WM_DESKTOP)) {
3662 dirty = WMDesktop;
3663
3664 if (message->data.data32[0] == (unsigned)OnAllDesktops) {
3665 changeDesktop(desktop: OnAllDesktops);
3666 } else {
3667 changeDesktop(desktop: message->data.data32[0] + 1);
3668 }
3669 } else if (message->type == p->atom(atom: _NET_WM_FULLSCREEN_MONITORS)) {
3670 dirty2 = WM2FullscreenMonitors;
3671
3672 NETFullscreenMonitors topology;
3673 topology.top = message->data.data32[0];
3674 topology.bottom = message->data.data32[1];
3675 topology.left = message->data.data32[2];
3676 topology.right = message->data.data32[3];
3677
3678#ifdef NETWMDEBUG
3679 fprintf(stderr,
3680 "NETWinInfo2::event: calling changeFullscreenMonitors"
3681 "(%ld, %ld, %ld, %ld, %ld)\n",
3682 message->window,
3683 message->data.data32[0],
3684 message->data.data32[1],
3685 message->data.data32[2],
3686 message->data.data32[3]);
3687#endif
3688 changeFullscreenMonitors(topology);
3689 }
3690 }
3691
3692 if (eventType == XCB_PROPERTY_NOTIFY) {
3693#ifdef NETWMDEBUG
3694 fprintf(stderr, "NETWinInfo::event: handling PropertyNotify event\n");
3695#endif
3696
3697 xcb_property_notify_event_t *pe = reinterpret_cast<xcb_property_notify_event_t *>(event);
3698
3699 if (pe->atom == p->atom(atom: _NET_WM_NAME)) {
3700 dirty |= WMName;
3701 } else if (pe->atom == p->atom(atom: _NET_WM_VISIBLE_NAME)) {
3702 dirty |= WMVisibleName;
3703 } else if (pe->atom == p->atom(atom: _NET_WM_DESKTOP)) {
3704 dirty |= WMDesktop;
3705 } else if (pe->atom == p->atom(atom: _NET_WM_WINDOW_TYPE)) {
3706 dirty |= WMWindowType;
3707 } else if (pe->atom == p->atom(atom: _NET_WM_STATE)) {
3708 dirty |= WMState;
3709 } else if (pe->atom == p->atom(atom: _NET_WM_STRUT)) {
3710 dirty |= WMStrut;
3711 } else if (pe->atom == p->atom(atom: _NET_WM_STRUT_PARTIAL)) {
3712 dirty2 |= WM2ExtendedStrut;
3713 } else if (pe->atom == p->atom(atom: _NET_WM_ICON_GEOMETRY)) {
3714 dirty |= WMIconGeometry;
3715 } else if (pe->atom == p->atom(atom: _NET_WM_ICON)) {
3716 dirty |= WMIcon;
3717 } else if (pe->atom == p->atom(atom: _NET_WM_PID)) {
3718 dirty |= WMPid;
3719 } else if (pe->atom == p->atom(atom: _NET_WM_HANDLED_ICONS)) {
3720 dirty |= WMHandledIcons;
3721 } else if (pe->atom == p->atom(atom: _NET_STARTUP_ID)) {
3722 dirty2 |= WM2StartupId;
3723 } else if (pe->atom == p->atom(atom: _NET_WM_WINDOW_OPACITY)) {
3724 dirty2 |= WM2Opacity;
3725 } else if (pe->atom == p->atom(atom: _NET_WM_ALLOWED_ACTIONS)) {
3726 dirty2 |= WM2AllowedActions;
3727 } else if (pe->atom == p->atom(atom: WM_STATE)) {
3728 dirty |= XAWMState;
3729 } else if (pe->atom == p->atom(atom: _NET_FRAME_EXTENTS)) {
3730 dirty |= WMFrameExtents;
3731 } else if (pe->atom == p->atom(atom: _KDE_NET_WM_FRAME_STRUT)) {
3732 dirty |= WMFrameExtents;
3733 } else if (pe->atom == p->atom(atom: _NET_WM_FRAME_OVERLAP)) {
3734 dirty2 |= WM2FrameOverlap;
3735 } else if (pe->atom == p->atom(atom: _NET_WM_ICON_NAME)) {
3736 dirty |= WMIconName;
3737 } else if (pe->atom == p->atom(atom: _NET_WM_VISIBLE_ICON_NAME)) {
3738 dirty |= WMVisibleIconName;
3739 } else if (pe->atom == p->atom(atom: _NET_WM_USER_TIME)) {
3740 dirty2 |= WM2UserTime;
3741 } else if (pe->atom == XCB_ATOM_WM_HINTS) {
3742 dirty2 |= WM2GroupLeader;
3743 dirty2 |= WM2Urgency;
3744 dirty2 |= WM2Input;
3745 dirty2 |= WM2InitialMappingState;
3746 dirty2 |= WM2IconPixmap;
3747 } else if (pe->atom == XCB_ATOM_WM_TRANSIENT_FOR) {
3748 dirty2 |= WM2TransientFor;
3749 } else if (pe->atom == XCB_ATOM_WM_CLASS) {
3750 dirty2 |= WM2WindowClass;
3751 } else if (pe->atom == p->atom(atom: WM_WINDOW_ROLE)) {
3752 dirty2 |= WM2WindowRole;
3753 } else if (pe->atom == XCB_ATOM_WM_CLIENT_MACHINE) {
3754 dirty2 |= WM2ClientMachine;
3755 } else if (pe->atom == p->atom(atom: _KDE_NET_WM_ACTIVITIES)) {
3756 dirty2 |= WM2Activities;
3757 } else if (pe->atom == p->atom(atom: _KDE_NET_WM_BLOCK_COMPOSITING) || pe->atom == p->atom(atom: _NET_WM_BYPASS_COMPOSITOR)) {
3758 dirty2 |= WM2BlockCompositing;
3759 } else if (pe->atom == p->atom(atom: _KDE_NET_WM_SHADOW)) {
3760 dirty2 |= WM2KDEShadow;
3761 } else if (pe->atom == p->atom(atom: WM_PROTOCOLS)) {
3762 dirty2 |= WM2Protocols;
3763 } else if (pe->atom == p->atom(atom: _NET_WM_OPAQUE_REGION)) {
3764 dirty2 |= WM2OpaqueRegion;
3765 } else if (pe->atom == p->atom(atom: _KDE_NET_WM_DESKTOP_FILE)) {
3766 dirty2 = WM2DesktopFileName;
3767 } else if (pe->atom == p->atom(atom: _GTK_APPLICATION_ID)) {
3768 dirty2 = WM2GTKApplicationId;
3769 } else if (pe->atom == p->atom(atom: _NET_WM_FULLSCREEN_MONITORS)) {
3770 dirty2 = WM2FullscreenMonitors;
3771 } else if (pe->atom == p->atom(atom: _GTK_FRAME_EXTENTS)) {
3772 dirty2 |= WM2GTKFrameExtents;
3773 } else if (pe->atom == p->atom(atom: _GTK_SHOW_WINDOW_MENU)) {
3774 dirty2 |= WM2GTKShowWindowMenu;
3775 } else if (pe->atom == p->atom(atom: _KDE_NET_WM_APPMENU_SERVICE_NAME)) {
3776 dirty2 |= WM2AppMenuServiceName;
3777 } else if (pe->atom == p->atom(atom: _KDE_NET_WM_APPMENU_OBJECT_PATH)) {
3778 dirty2 |= WM2AppMenuObjectPath;
3779 }
3780
3781 do_update = true;
3782 } else if (eventType == XCB_CONFIGURE_NOTIFY) {
3783#ifdef NETWMDEBUG
3784 fprintf(stderr, "NETWinInfo::event: handling ConfigureNotify event\n");
3785#endif
3786
3787 dirty |= WMGeometry;
3788
3789 // update window geometry
3790 xcb_configure_notify_event_t *configure = reinterpret_cast<xcb_configure_notify_event_t *>(event);
3791 p->win_geom.pos.x = configure->x;
3792 p->win_geom.pos.y = configure->y;
3793 p->win_geom.size.width = configure->width;
3794 p->win_geom.size.height = configure->height;
3795 }
3796
3797 if (do_update) {
3798 update(dirtyProperties: dirty, dirtyProperties2: dirty2);
3799 }
3800
3801 if (properties) {
3802 *properties = dirty;
3803 }
3804 if (properties2) {
3805 *properties2 = dirty2;
3806 }
3807}
3808
3809void NETWinInfo::updateWMState()
3810{
3811 update(dirtyProperties: XAWMState);
3812}
3813
3814void NETWinInfo::update(NET::Properties dirtyProperties, NET::Properties2 dirtyProperties2)
3815{
3816 Properties dirty = dirtyProperties & p->properties;
3817 Properties2 dirty2 = dirtyProperties2 & p->properties2;
3818
3819 // We *always* want to update WM_STATE if set in dirty_props
3820 if (dirtyProperties & XAWMState) {
3821 dirty |= XAWMState;
3822 }
3823
3824 xcb_get_property_cookie_t cookies[255];
3825 int c = 0;
3826
3827 if (dirty & XAWMState) {
3828 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: WM_STATE), type: p->atom(atom: WM_STATE), long_offset: 0, long_length: 1);
3829 }
3830
3831 if (dirty & WMState) {
3832 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_STATE), type: XCB_ATOM_ATOM, long_offset: 0, long_length: 2048);
3833 }
3834
3835 if (dirty & WMDesktop) {
3836 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_DESKTOP), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 1);
3837 }
3838
3839 if (dirty & WMName) {
3840 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_NAME), type: p->atom(atom: UTF8_STRING), long_offset: 0, long_length: MAX_PROP_SIZE);
3841 }
3842
3843 if (dirty & WMVisibleName) {
3844 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_VISIBLE_NAME), type: p->atom(atom: UTF8_STRING), long_offset: 0, long_length: MAX_PROP_SIZE);
3845 }
3846
3847 if (dirty & WMIconName) {
3848 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_ICON_NAME), type: p->atom(atom: UTF8_STRING), long_offset: 0, long_length: MAX_PROP_SIZE);
3849 }
3850
3851 if (dirty & WMVisibleIconName) {
3852 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_VISIBLE_ICON_NAME), type: p->atom(atom: UTF8_STRING), long_offset: 0, long_length: MAX_PROP_SIZE);
3853 }
3854
3855 if (dirty & WMWindowType) {
3856 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_WINDOW_TYPE), type: XCB_ATOM_ATOM, long_offset: 0, long_length: 2048);
3857 }
3858
3859 if (dirty & WMStrut) {
3860 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_STRUT), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 4);
3861 }
3862
3863 if (dirty2 & WM2ExtendedStrut) {
3864 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_STRUT_PARTIAL), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 12);
3865 }
3866
3867 if (dirty2 & WM2FullscreenMonitors) {
3868 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_FULLSCREEN_MONITORS), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 4);
3869 }
3870
3871 if (dirty & WMIconGeometry) {
3872 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_ICON_GEOMETRY), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 4);
3873 }
3874
3875 if (dirty & WMIcon) {
3876 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_ICON), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 0xffffffff);
3877 }
3878
3879 if (dirty & WMFrameExtents) {
3880 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_FRAME_EXTENTS), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 4);
3881 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _KDE_NET_WM_FRAME_STRUT), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 4);
3882 }
3883
3884 if (dirty2 & WM2FrameOverlap) {
3885 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_FRAME_OVERLAP), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 4);
3886 }
3887
3888 if (dirty2 & WM2Activities) {
3889 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _KDE_NET_WM_ACTIVITIES), type: XCB_ATOM_STRING, long_offset: 0, long_length: MAX_PROP_SIZE);
3890 }
3891
3892 if (dirty2 & WM2BlockCompositing) {
3893 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _KDE_NET_WM_BLOCK_COMPOSITING), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 1);
3894 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_BYPASS_COMPOSITOR), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 1);
3895 }
3896
3897 if (dirty & WMPid) {
3898 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_PID), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 1);
3899 }
3900
3901 if (dirty2 & WM2StartupId) {
3902 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_STARTUP_ID), type: p->atom(atom: UTF8_STRING), long_offset: 0, long_length: MAX_PROP_SIZE);
3903 }
3904
3905 if (dirty2 & WM2Opacity) {
3906 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_WINDOW_OPACITY), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 1);
3907 }
3908
3909 if (dirty2 & WM2AllowedActions) {
3910 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_ALLOWED_ACTIONS), type: XCB_ATOM_ATOM, long_offset: 0, long_length: 2048);
3911 }
3912
3913 if (dirty2 & WM2UserTime) {
3914 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_USER_TIME), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 1);
3915 }
3916
3917 if (dirty2 & WM2TransientFor) {
3918 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: XCB_ATOM_WM_TRANSIENT_FOR, type: XCB_ATOM_WINDOW, long_offset: 0, long_length: 1);
3919 }
3920
3921 if (dirty2 & (WM2GroupLeader | WM2Urgency | WM2Input | WM2InitialMappingState | WM2IconPixmap)) {
3922 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: XCB_ATOM_WM_HINTS, type: XCB_ATOM_WM_HINTS, long_offset: 0, long_length: 9);
3923 }
3924
3925 if (dirty2 & WM2WindowClass) {
3926 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: XCB_ATOM_WM_CLASS, type: XCB_ATOM_STRING, long_offset: 0, long_length: MAX_PROP_SIZE);
3927 }
3928
3929 if (dirty2 & WM2WindowRole) {
3930 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: WM_WINDOW_ROLE), type: XCB_ATOM_STRING, long_offset: 0, long_length: MAX_PROP_SIZE);
3931 }
3932
3933 if (dirty2 & WM2ClientMachine) {
3934 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: XCB_ATOM_WM_CLIENT_MACHINE, type: XCB_ATOM_STRING, long_offset: 0, long_length: MAX_PROP_SIZE);
3935 }
3936
3937 if (dirty2 & WM2Protocols) {
3938 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: WM_PROTOCOLS), type: XCB_ATOM_ATOM, long_offset: 0, long_length: 2048);
3939 }
3940
3941 if (dirty2 & WM2OpaqueRegion) {
3942 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _NET_WM_OPAQUE_REGION), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: MAX_PROP_SIZE);
3943 }
3944
3945 if (dirty2 & WM2DesktopFileName) {
3946 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _KDE_NET_WM_DESKTOP_FILE), type: p->atom(atom: UTF8_STRING), long_offset: 0, long_length: MAX_PROP_SIZE);
3947 }
3948
3949 if (dirty2 & WM2GTKApplicationId) {
3950 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _GTK_APPLICATION_ID), type: p->atom(atom: UTF8_STRING), long_offset: 0, long_length: MAX_PROP_SIZE);
3951 }
3952
3953 if (dirty2 & WM2GTKFrameExtents) {
3954 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _GTK_FRAME_EXTENTS), type: XCB_ATOM_CARDINAL, long_offset: 0, long_length: 4);
3955 }
3956
3957 if (dirty2 & WM2AppMenuObjectPath) {
3958 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _KDE_NET_WM_APPMENU_OBJECT_PATH), type: XCB_ATOM_STRING, long_offset: 0, long_length: MAX_PROP_SIZE);
3959 }
3960
3961 if (dirty2 & WM2AppMenuServiceName) {
3962 cookies[c++] = xcb_get_property(c: p->conn, delete: false, window: p->window, property: p->atom(atom: _KDE_NET_WM_APPMENU_SERVICE_NAME), type: XCB_ATOM_STRING, long_offset: 0, long_length: MAX_PROP_SIZE);
3963 }
3964
3965 c = 0;
3966
3967 if (dirty & XAWMState) {
3968 p->mapping_state = Withdrawn;
3969
3970 bool success;
3971 uint32_t state = get_value_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: p->atom(atom: WM_STATE), def: 0, success: &success);
3972
3973 if (success) {
3974 switch (state) {
3975 case 3: // IconicState
3976 p->mapping_state = Iconic;
3977 break;
3978
3979 case 1: // NormalState
3980 p->mapping_state = Visible;
3981 break;
3982
3983 case 0: // WithdrawnState
3984 default:
3985 p->mapping_state = Withdrawn;
3986 break;
3987 }
3988
3989 p->mapping_state_dirty = false;
3990 }
3991 }
3992
3993 if (dirty & WMState) {
3994 p->state = NET::States();
3995 const QList<xcb_atom_t> states = get_array_reply<xcb_atom_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_ATOM);
3996
3997#ifdef NETWMDEBUG
3998 fprintf(stderr, "NETWinInfo::update: updating window state (%ld)\n", states.count());
3999#endif
4000
4001 for (const xcb_atom_t state : states) {
4002#ifdef NETWMDEBUG
4003 const QByteArray ba = get_atom_name(p->conn, state);
4004 fprintf(stderr, "NETWinInfo::update: adding window state %ld '%s'\n", state, ba.constData());
4005#endif
4006 if (state == p->atom(atom: _NET_WM_STATE_MODAL)) {
4007 p->state |= Modal;
4008 }
4009
4010 else if (state == p->atom(atom: _NET_WM_STATE_STICKY)) {
4011 p->state |= Sticky;
4012 }
4013
4014 else if (state == p->atom(atom: _NET_WM_STATE_MAXIMIZED_VERT)) {
4015 p->state |= MaxVert;
4016 }
4017
4018 else if (state == p->atom(atom: _NET_WM_STATE_MAXIMIZED_HORZ)) {
4019 p->state |= MaxHoriz;
4020 }
4021
4022 else if (state == p->atom(atom: _NET_WM_STATE_SHADED)) {
4023 p->state |= Shaded;
4024 }
4025
4026 else if (state == p->atom(atom: _NET_WM_STATE_SKIP_TASKBAR)) {
4027 p->state |= SkipTaskbar;
4028 }
4029
4030 else if (state == p->atom(atom: _NET_WM_STATE_SKIP_PAGER)) {
4031 p->state |= SkipPager;
4032 }
4033
4034 else if (state == p->atom(atom: _KDE_NET_WM_STATE_SKIP_SWITCHER)) {
4035 p->state |= SkipSwitcher;
4036 }
4037
4038 else if (state == p->atom(atom: _NET_WM_STATE_HIDDEN)) {
4039 p->state |= Hidden;
4040 }
4041
4042 else if (state == p->atom(atom: _NET_WM_STATE_FULLSCREEN)) {
4043 p->state |= FullScreen;
4044 }
4045
4046 else if (state == p->atom(atom: _NET_WM_STATE_ABOVE)) {
4047 p->state |= KeepAbove;
4048 }
4049
4050 else if (state == p->atom(atom: _NET_WM_STATE_BELOW)) {
4051 p->state |= KeepBelow;
4052 }
4053
4054 else if (state == p->atom(atom: _NET_WM_STATE_DEMANDS_ATTENTION)) {
4055 p->state |= DemandsAttention;
4056 }
4057
4058 else if (state == p->atom(atom: _NET_WM_STATE_STAYS_ON_TOP)) {
4059 p->state |= KeepAbove;
4060 }
4061
4062 else if (state == p->atom(atom: _NET_WM_STATE_FOCUSED)) {
4063 p->state |= Focused;
4064 }
4065 }
4066 }
4067
4068 if (dirty & WMDesktop) {
4069 p->desktop = 0;
4070
4071 bool success;
4072 uint32_t desktop = get_value_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL, def: 0, success: &success);
4073
4074 if (success) {
4075 if (desktop != 0xffffffff) {
4076 p->desktop = desktop + 1;
4077 } else {
4078 p->desktop = OnAllDesktops;
4079 }
4080 }
4081 }
4082
4083 if (dirty & WMName) {
4084 delete[] p->name;
4085 p->name = nullptr;
4086
4087 const QByteArray str = get_string_reply(c: p->conn, cookie: cookies[c++], type: p->atom(atom: UTF8_STRING));
4088 if (str.length() > 0) {
4089 p->name = nstrndup(s1: str.constData(), l: str.length());
4090 }
4091 }
4092
4093 if (dirty & WMVisibleName) {
4094 delete[] p->visible_name;
4095 p->visible_name = nullptr;
4096
4097 const QByteArray str = get_string_reply(c: p->conn, cookie: cookies[c++], type: p->atom(atom: UTF8_STRING));
4098 if (str.length() > 0) {
4099 p->visible_name = nstrndup(s1: str.constData(), l: str.length());
4100 }
4101 }
4102
4103 if (dirty & WMIconName) {
4104 delete[] p->icon_name;
4105 p->icon_name = nullptr;
4106
4107 const QByteArray str = get_string_reply(c: p->conn, cookie: cookies[c++], type: p->atom(atom: UTF8_STRING));
4108 if (str.length() > 0) {
4109 p->icon_name = nstrndup(s1: str.constData(), l: str.length());
4110 }
4111 }
4112
4113 if (dirty & WMVisibleIconName) {
4114 delete[] p->visible_icon_name;
4115 p->visible_icon_name = nullptr;
4116
4117 const QByteArray str = get_string_reply(c: p->conn, cookie: cookies[c++], type: p->atom(atom: UTF8_STRING));
4118 if (str.length() > 0) {
4119 p->visible_icon_name = nstrndup(s1: str.constData(), l: str.length());
4120 }
4121 }
4122
4123 if (dirty & WMWindowType) {
4124 p->types.reset();
4125 p->types[0] = Unknown;
4126 p->has_net_support = false;
4127
4128 const QList<xcb_atom_t> types = get_array_reply<xcb_atom_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_ATOM);
4129
4130 if (!types.isEmpty()) {
4131#ifdef NETWMDEBUG
4132 fprintf(stderr, "NETWinInfo::update: getting window type (%ld)\n", types.count());
4133#endif
4134 p->has_net_support = true;
4135 int pos = 0;
4136
4137 for (const xcb_atom_t type : types) {
4138#ifdef NETWMDEBUG
4139 const QByteArray name = get_atom_name(p->conn, type);
4140 fprintf(stderr, "NETWinInfo::update: examining window type %ld %s\n", type, name.constData());
4141#endif
4142 if (type == p->atom(atom: _NET_WM_WINDOW_TYPE_NORMAL)) {
4143 p->types[pos++] = Normal;
4144 }
4145
4146 else if (type == p->atom(atom: _NET_WM_WINDOW_TYPE_DESKTOP)) {
4147 p->types[pos++] = Desktop;
4148 }
4149
4150 else if (type == p->atom(atom: _NET_WM_WINDOW_TYPE_DOCK)) {
4151 p->types[pos++] = Dock;
4152 }
4153
4154 else if (type == p->atom(atom: _NET_WM_WINDOW_TYPE_TOOLBAR)) {
4155 p->types[pos++] = Toolbar;
4156 }
4157
4158 else if (type == p->atom(atom: _NET_WM_WINDOW_TYPE_MENU)) {
4159 p->types[pos++] = Menu;
4160 }
4161
4162 else if (type == p->atom(atom: _NET_WM_WINDOW_TYPE_DIALOG)) {
4163 p->types[pos++] = Dialog;
4164 }
4165
4166 else if (type == p->atom(atom: _NET_WM_WINDOW_TYPE_UTILITY)) {
4167 p->types[pos++] = Utility;
4168 }
4169
4170 else if (type == p->atom(atom: _NET_WM_WINDOW_TYPE_SPLASH)) {
4171 p->types[pos++] = Splash;
4172 }
4173
4174 else if (type == p->atom(atom: _NET_WM_WINDOW_TYPE_DROPDOWN_MENU)) {
4175 p->types[pos++] = DropdownMenu;
4176 }
4177
4178 else if (type == p->atom(atom: _NET_WM_WINDOW_TYPE_POPUP_MENU)) {
4179 p->types[pos++] = PopupMenu;
4180 }
4181
4182 else if (type == p->atom(atom: _NET_WM_WINDOW_TYPE_TOOLTIP)) {
4183 p->types[pos++] = Tooltip;
4184 }
4185
4186 else if (type == p->atom(atom: _NET_WM_WINDOW_TYPE_NOTIFICATION)) {
4187 p->types[pos++] = Notification;
4188 }
4189
4190 else if (type == p->atom(atom: _NET_WM_WINDOW_TYPE_COMBO)) {
4191 p->types[pos++] = ComboBox;
4192 }
4193
4194 else if (type == p->atom(atom: _NET_WM_WINDOW_TYPE_DND)) {
4195 p->types[pos++] = DNDIcon;
4196 }
4197
4198 else if (type == p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_OVERRIDE)) {
4199 p->types[pos++] = Override;
4200 }
4201
4202 else if (type == p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_TOPMENU)) {
4203 p->types[pos++] = TopMenu;
4204 }
4205
4206 else if (type == p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_ON_SCREEN_DISPLAY)) {
4207 p->types[pos++] = OnScreenDisplay;
4208 }
4209
4210 else if (type == p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_CRITICAL_NOTIFICATION)) {
4211 p->types[pos++] = CriticalNotification;
4212 }
4213
4214 else if (type == p->atom(atom: _KDE_NET_WM_WINDOW_TYPE_APPLET_POPUP)) {
4215 p->types[pos++] = AppletPopup;
4216 }
4217 }
4218 }
4219 }
4220
4221 if (dirty & WMStrut) {
4222 p->strut = NETStrut();
4223
4224 QList<uint32_t> data = get_array_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL);
4225 if (data.count() == 4) {
4226 p->strut.left = data[0];
4227 p->strut.right = data[1];
4228 p->strut.top = data[2];
4229 p->strut.bottom = data[3];
4230 }
4231 }
4232
4233 if (dirty2 & WM2ExtendedStrut) {
4234 p->extended_strut = NETExtendedStrut();
4235
4236 QList<uint32_t> data = get_array_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL);
4237 if (data.count() == 12) {
4238 p->extended_strut.left_width = data[0];
4239 p->extended_strut.right_width = data[1];
4240 p->extended_strut.top_width = data[2];
4241 p->extended_strut.bottom_width = data[3];
4242 p->extended_strut.left_start = data[4];
4243 p->extended_strut.left_end = data[5];
4244 p->extended_strut.right_start = data[6];
4245 p->extended_strut.right_end = data[7];
4246 p->extended_strut.top_start = data[8];
4247 p->extended_strut.top_end = data[9];
4248 p->extended_strut.bottom_start = data[10];
4249 p->extended_strut.bottom_end = data[11];
4250 }
4251 }
4252
4253 if (dirty2 & WM2FullscreenMonitors) {
4254 p->fullscreen_monitors = NETFullscreenMonitors();
4255
4256 QList<uint32_t> data = get_array_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL);
4257 if (data.count() == 4) {
4258 p->fullscreen_monitors.top = data[0];
4259 p->fullscreen_monitors.bottom = data[1];
4260 p->fullscreen_monitors.left = data[2];
4261 p->fullscreen_monitors.right = data[3];
4262 }
4263 }
4264
4265 if (dirty & WMIconGeometry) {
4266 p->icon_geom = NETRect();
4267
4268 QList<uint32_t> data = get_array_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL);
4269 if (data.count() == 4) {
4270 p->icon_geom.pos.x = data[0];
4271 p->icon_geom.pos.y = data[1];
4272 p->icon_geom.size.width = data[2];
4273 p->icon_geom.size.height = data[3];
4274 }
4275 }
4276
4277 if (dirty & WMIcon) {
4278 readIcon(c: p->conn, cookie: cookies[c++], icons&: p->icons, icon_count&: p->icon_count);
4279 delete[] p->icon_sizes;
4280 p->icon_sizes = nullptr;
4281 }
4282
4283 if (dirty & WMFrameExtents) {
4284 p->frame_strut = NETStrut();
4285
4286 QList<uint32_t> data = get_array_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL);
4287
4288 if (data.isEmpty()) {
4289 data = get_array_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL);
4290 } else {
4291 xcb_discard_reply(c: p->conn, sequence: cookies[c++].sequence);
4292 }
4293
4294 if (data.count() == 4) {
4295 p->frame_strut.left = data[0];
4296 p->frame_strut.right = data[1];
4297 p->frame_strut.top = data[2];
4298 p->frame_strut.bottom = data[3];
4299 }
4300 }
4301
4302 if (dirty2 & WM2FrameOverlap) {
4303 p->frame_overlap = NETStrut();
4304
4305 QList<uint32_t> data = get_array_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL);
4306 if (data.count() == 4) {
4307 p->frame_overlap.left = data[0];
4308 p->frame_overlap.right = data[1];
4309 p->frame_overlap.top = data[2];
4310 p->frame_overlap.bottom = data[3];
4311 }
4312 }
4313
4314 if (dirty2 & WM2Activities) {
4315 delete[] p->activities;
4316 p->activities = nullptr;
4317
4318 const QByteArray activities = get_string_reply(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_STRING);
4319 if (activities.length() > 0) {
4320 p->activities = nstrndup(s1: activities.constData(), l: activities.length());
4321 }
4322 }
4323
4324 if (dirty2 & WM2BlockCompositing) {
4325 bool success;
4326 p->blockCompositing = false;
4327
4328 // _KDE_NET_WM_BLOCK_COMPOSITING
4329 uint32_t data = get_value_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL, def: 0, success: &success);
4330 if (success) {
4331 p->blockCompositing = bool(data);
4332 }
4333
4334 // _NET_WM_BYPASS_COMPOSITOR
4335 data = get_value_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL, def: 0, success: &success);
4336 if (success) {
4337 switch (data) {
4338 case 1:
4339 p->blockCompositing = true;
4340 break;
4341 case 2:
4342 p->blockCompositing = false;
4343 break;
4344 default:
4345 break; // yes, the standard /is/ that stupid.
4346 }
4347 }
4348 }
4349
4350 if (dirty & WMPid) {
4351 p->pid = get_value_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL, def: 0);
4352 }
4353
4354 if (dirty2 & WM2StartupId) {
4355 delete[] p->startup_id;
4356 p->startup_id = nullptr;
4357
4358 const QByteArray id = get_string_reply(c: p->conn, cookie: cookies[c++], type: p->atom(atom: UTF8_STRING));
4359 if (id.length() > 0) {
4360 p->startup_id = nstrndup(s1: id.constData(), l: id.length());
4361 }
4362 }
4363
4364 if (dirty2 & WM2Opacity) {
4365 p->opacity = get_value_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL, def: 0xffffffff);
4366 }
4367
4368 if (dirty2 & WM2AllowedActions) {
4369 p->allowed_actions = NET::Actions();
4370
4371 const QList<xcb_atom_t> actions = get_array_reply<xcb_atom_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_ATOM);
4372 if (!actions.isEmpty()) {
4373#ifdef NETWMDEBUG
4374 fprintf(stderr, "NETWinInfo::update: updating allowed actions (%ld)\n", actions.count());
4375#endif
4376
4377 for (const xcb_atom_t action : actions) {
4378#ifdef NETWMDEBUG
4379 const QByteArray name = get_atom_name(p->conn, action);
4380 fprintf(stderr, "NETWinInfo::update: adding allowed action %ld '%s'\n", action, name.constData());
4381#endif
4382 if (action == p->atom(atom: _NET_WM_ACTION_MOVE)) {
4383 p->allowed_actions |= ActionMove;
4384 }
4385
4386 else if (action == p->atom(atom: _NET_WM_ACTION_RESIZE)) {
4387 p->allowed_actions |= ActionResize;
4388 }
4389
4390 else if (action == p->atom(atom: _NET_WM_ACTION_MINIMIZE)) {
4391 p->allowed_actions |= ActionMinimize;
4392 }
4393
4394 else if (action == p->atom(atom: _NET_WM_ACTION_SHADE)) {
4395 p->allowed_actions |= ActionShade;
4396 }
4397
4398 else if (action == p->atom(atom: _NET_WM_ACTION_STICK)) {
4399 p->allowed_actions |= ActionStick;
4400 }
4401
4402 else if (action == p->atom(atom: _NET_WM_ACTION_MAXIMIZE_VERT)) {
4403 p->allowed_actions |= ActionMaxVert;
4404 }
4405
4406 else if (action == p->atom(atom: _NET_WM_ACTION_MAXIMIZE_HORZ)) {
4407 p->allowed_actions |= ActionMaxHoriz;
4408 }
4409
4410 else if (action == p->atom(atom: _NET_WM_ACTION_FULLSCREEN)) {
4411 p->allowed_actions |= ActionFullScreen;
4412 }
4413
4414 else if (action == p->atom(atom: _NET_WM_ACTION_CHANGE_DESKTOP)) {
4415 p->allowed_actions |= ActionChangeDesktop;
4416 }
4417
4418 else if (action == p->atom(atom: _NET_WM_ACTION_CLOSE)) {
4419 p->allowed_actions |= ActionClose;
4420 }
4421 }
4422 }
4423 }
4424
4425 if (dirty2 & WM2UserTime) {
4426 p->user_time = -1U;
4427
4428 bool success;
4429 uint32_t value = get_value_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL, def: 0, success: &success);
4430
4431 if (success) {
4432 p->user_time = value;
4433 }
4434 }
4435
4436 if (dirty2 & WM2TransientFor) {
4437 p->transient_for = get_value_reply<xcb_window_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_WINDOW, def: 0);
4438 }
4439
4440 if (dirty2 & (WM2GroupLeader | WM2Urgency | WM2Input | WM2InitialMappingState | WM2IconPixmap)) {
4441 xcb_get_property_reply_t *reply = xcb_get_property_reply(c: p->conn, cookie: cookies[c++], e: nullptr);
4442
4443 if (reply && reply->format == 32 && reply->value_len == 9 && reply->type == XCB_ATOM_WM_HINTS) {
4444 kde_wm_hints *hints = reinterpret_cast<kde_wm_hints *>(xcb_get_property_value(R: reply));
4445
4446 if (hints->flags & (1 << 0) /*Input*/) {
4447 p->input = hints->input;
4448 }
4449 if (hints->flags & (1 << 1) /*StateHint*/) {
4450 switch (hints->initial_state) {
4451 case 3: // IconicState
4452 p->initialMappingState = Iconic;
4453 break;
4454
4455 case 1: // NormalState
4456 p->initialMappingState = Visible;
4457 break;
4458
4459 case 0: // WithdrawnState
4460 default:
4461 p->initialMappingState = Withdrawn;
4462 break;
4463 }
4464 }
4465 if (hints->flags & (1 << 2) /*IconPixmapHint*/) {
4466 p->icon_pixmap = hints->icon_pixmap;
4467 }
4468 if (hints->flags & (1 << 5) /*IconMaskHint*/) {
4469 p->icon_mask = hints->icon_mask;
4470 }
4471 if (hints->flags & (1 << 6) /*WindowGroupHint*/) {
4472 p->window_group = hints->window_group;
4473 }
4474 p->urgency = (hints->flags & (1 << 8) /*UrgencyHint*/);
4475 }
4476
4477 if (reply) {
4478 free(ptr: reply);
4479 }
4480 }
4481
4482 if (dirty2 & WM2WindowClass) {
4483 delete[] p->class_name;
4484 delete[] p->class_class;
4485 p->class_name = nullptr;
4486 p->class_class = nullptr;
4487
4488 const QList<QByteArray> list = get_stringlist_reply(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_STRING);
4489 if (list.count() == 2) {
4490 p->class_name = nstrdup(s1: list.at(i: 0).constData());
4491 p->class_class = nstrdup(s1: list.at(i: 1).constData());
4492 } else if (list.count() == 1) { // Not fully compliant client. Provides a single string
4493 p->class_name = nstrdup(s1: list.at(i: 0).constData());
4494 p->class_class = nstrdup(s1: list.at(i: 0).constData());
4495 }
4496 }
4497
4498 if (dirty2 & WM2WindowRole) {
4499 delete[] p->window_role;
4500 p->window_role = nullptr;
4501
4502 const QByteArray role = get_string_reply(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_STRING);
4503 if (role.length() > 0) {
4504 p->window_role = nstrndup(s1: role.constData(), l: role.length());
4505 }
4506 }
4507
4508 if (dirty2 & WM2ClientMachine) {
4509 delete[] p->client_machine;
4510 p->client_machine = nullptr;
4511
4512 const QByteArray value = get_string_reply(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_STRING);
4513 if (value.length() > 0) {
4514 p->client_machine = nstrndup(s1: value.constData(), l: value.length());
4515 }
4516 }
4517
4518 if (dirty2 & WM2Protocols) {
4519 const QList<xcb_atom_t> protocols = get_array_reply<xcb_atom_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_ATOM);
4520 p->protocols = NET::NoProtocol;
4521 for (auto it = protocols.begin(); it != protocols.end(); ++it) {
4522 if ((*it) == p->atom(atom: WM_TAKE_FOCUS)) {
4523 p->protocols |= TakeFocusProtocol;
4524 } else if ((*it) == p->atom(atom: WM_DELETE_WINDOW)) {
4525 p->protocols |= DeleteWindowProtocol;
4526 } else if ((*it) == p->atom(atom: _NET_WM_PING)) {
4527 p->protocols |= PingProtocol;
4528 } else if ((*it) == p->atom(atom: _NET_WM_SYNC_REQUEST)) {
4529 p->protocols |= SyncRequestProtocol;
4530 } else if ((*it) == p->atom(atom: _NET_WM_CONTEXT_HELP)) {
4531 p->protocols |= ContextHelpProtocol;
4532 }
4533 }
4534 }
4535
4536 if (dirty2 & WM2OpaqueRegion) {
4537 const QList<qint32> values = get_array_reply<qint32>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL);
4538 p->opaqueRegion.clear();
4539 p->opaqueRegion.reserve(n: values.count() / 4);
4540 for (int i = 0; i < values.count() - 3; i += 4) {
4541 NETRect rect;
4542 rect.pos.x = values.at(i);
4543 rect.pos.y = values.at(i: i + 1);
4544 rect.size.width = values.at(i: i + 2);
4545 rect.size.height = values.at(i: i + 3);
4546 p->opaqueRegion.push_back(x: rect);
4547 }
4548 }
4549
4550 if (dirty2 & WM2DesktopFileName) {
4551 delete[] p->desktop_file;
4552 p->desktop_file = nullptr;
4553
4554 const QByteArray id = get_string_reply(c: p->conn, cookie: cookies[c++], type: p->atom(atom: UTF8_STRING));
4555 if (id.length() > 0) {
4556 p->desktop_file = nstrndup(s1: id.constData(), l: id.length());
4557 }
4558 }
4559
4560 if (dirty2 & WM2GTKApplicationId) {
4561 delete[] p->gtk_application_id;
4562 p->gtk_application_id = nullptr;
4563
4564 const QByteArray id = get_string_reply(c: p->conn, cookie: cookies[c++], type: p->atom(atom: UTF8_STRING));
4565 if (id.length() > 0) {
4566 p->gtk_application_id = nstrndup(s1: id.constData(), l: id.length());
4567 }
4568 }
4569
4570 if (dirty2 & WM2GTKFrameExtents) {
4571 p->gtk_frame_extents = NETStrut();
4572
4573 QList<uint32_t> data = get_array_reply<uint32_t>(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_CARDINAL);
4574 if (data.count() == 4) {
4575 p->gtk_frame_extents.left = data[0];
4576 p->gtk_frame_extents.right = data[1];
4577 p->gtk_frame_extents.top = data[2];
4578 p->gtk_frame_extents.bottom = data[3];
4579 }
4580 }
4581
4582 if (dirty2 & WM2AppMenuObjectPath) {
4583 delete[] p->appmenu_object_path;
4584 p->appmenu_object_path = nullptr;
4585
4586 const QByteArray id = get_string_reply(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_STRING);
4587 if (id.length() > 0) {
4588 p->appmenu_object_path = nstrndup(s1: id.constData(), l: id.length());
4589 }
4590 }
4591
4592 if (dirty2 & WM2AppMenuServiceName) {
4593 delete[] p->appmenu_service_name;
4594 p->appmenu_service_name = nullptr;
4595
4596 const QByteArray id = get_string_reply(c: p->conn, cookie: cookies[c++], type: XCB_ATOM_STRING);
4597 if (id.length() > 0) {
4598 p->appmenu_service_name = nstrndup(s1: id.constData(), l: id.length());
4599 }
4600 }
4601}
4602
4603NETRect NETWinInfo::iconGeometry() const
4604{
4605 return p->icon_geom;
4606}
4607
4608NET::States NETWinInfo::state() const
4609{
4610 return p->state;
4611}
4612
4613NETStrut NETWinInfo::strut() const
4614{
4615 return p->strut;
4616}
4617
4618NETExtendedStrut NETWinInfo::extendedStrut() const
4619{
4620 return p->extended_strut;
4621}
4622
4623NETFullscreenMonitors NETWinInfo::fullscreenMonitors() const
4624{
4625 return p->fullscreen_monitors;
4626}
4627
4628bool NET::typeMatchesMask(WindowType type, WindowTypes mask)
4629{
4630 switch (type) {
4631 // clang-format off
4632#define CHECK_TYPE_MASK( type ) \
4633case type: \
4634 if( mask & type##Mask ) \
4635 return true; \
4636 break;
4637 // clang-format on
4638 CHECK_TYPE_MASK(Normal)
4639 CHECK_TYPE_MASK(Desktop)
4640 CHECK_TYPE_MASK(Dock)
4641 CHECK_TYPE_MASK(Toolbar)
4642 CHECK_TYPE_MASK(Menu)
4643 CHECK_TYPE_MASK(Dialog)
4644 CHECK_TYPE_MASK(Override)
4645 CHECK_TYPE_MASK(TopMenu)
4646 CHECK_TYPE_MASK(Utility)
4647 CHECK_TYPE_MASK(Splash)
4648 CHECK_TYPE_MASK(DropdownMenu)
4649 CHECK_TYPE_MASK(PopupMenu)
4650 CHECK_TYPE_MASK(Tooltip)
4651 CHECK_TYPE_MASK(Notification)
4652 CHECK_TYPE_MASK(ComboBox)
4653 CHECK_TYPE_MASK(DNDIcon)
4654 CHECK_TYPE_MASK(OnScreenDisplay)
4655 CHECK_TYPE_MASK(CriticalNotification)
4656 CHECK_TYPE_MASK(AppletPopup)
4657#undef CHECK_TYPE_MASK
4658 default:
4659 break;
4660 }
4661 return false;
4662}
4663
4664NET::WindowType NETWinInfo::windowType(WindowTypes supported_types) const
4665{
4666 for (int i = 0; i < p->types.size(); ++i) {
4667 // return the type only if the application supports it
4668 if (typeMatchesMask(type: p->types[i], mask: supported_types)) {
4669 return p->types[i];
4670 }
4671 }
4672 return Unknown;
4673}
4674
4675bool NETWinInfo::hasWindowType() const
4676{
4677 return p->types.size() > 0;
4678}
4679
4680const char *NETWinInfo::name() const
4681{
4682 return p->name;
4683}
4684
4685const char *NETWinInfo::visibleName() const
4686{
4687 return p->visible_name;
4688}
4689
4690const char *NETWinInfo::iconName() const
4691{
4692 return p->icon_name;
4693}
4694
4695const char *NETWinInfo::visibleIconName() const
4696{
4697 return p->visible_icon_name;
4698}
4699
4700int NETWinInfo::desktop(bool ignore_viewport) const
4701{
4702 if (!ignore_viewport && KX11Extras::mapViewport()) {
4703 const KWindowInfo info(p->window, NET::WMDesktop);
4704 return info.desktop();
4705 }
4706 return p->desktop;
4707}
4708
4709int NETWinInfo::pid() const
4710{
4711 return p->pid;
4712}
4713
4714xcb_timestamp_t NETWinInfo::userTime() const
4715{
4716 return p->user_time;
4717}
4718
4719const char *NETWinInfo::startupId() const
4720{
4721 return p->startup_id;
4722}
4723
4724unsigned long NETWinInfo::opacity() const
4725{
4726 return p->opacity;
4727}
4728
4729qreal NETWinInfo::opacityF() const
4730{
4731 if (p->opacity == 0xffffffff) {
4732 return 1.0;
4733 }
4734 return p->opacity * 1.0 / 0xffffffff;
4735}
4736
4737NET::Actions NETWinInfo::allowedActions() const
4738{
4739 return p->allowed_actions;
4740}
4741
4742bool NETWinInfo::hasNETSupport() const
4743{
4744 return p->has_net_support;
4745}
4746
4747xcb_window_t NETWinInfo::transientFor() const
4748{
4749 return p->transient_for;
4750}
4751
4752xcb_window_t NETWinInfo::groupLeader() const
4753{
4754 return p->window_group;
4755}
4756
4757bool NETWinInfo::urgency() const
4758{
4759 return p->urgency;
4760}
4761
4762bool NETWinInfo::input() const
4763{
4764 return p->input;
4765}
4766
4767NET::MappingState NETWinInfo::initialMappingState() const
4768{
4769 return p->initialMappingState;
4770}
4771
4772xcb_pixmap_t NETWinInfo::icccmIconPixmap() const
4773{
4774 return p->icon_pixmap;
4775}
4776
4777xcb_pixmap_t NETWinInfo::icccmIconPixmapMask() const
4778{
4779 return p->icon_mask;
4780}
4781
4782const char *NETWinInfo::windowClassClass() const
4783{
4784 return p->class_class;
4785}
4786
4787const char *NETWinInfo::windowClassName() const
4788{
4789 return p->class_name;
4790}
4791
4792const char *NETWinInfo::windowRole() const
4793{
4794 return p->window_role;
4795}
4796
4797const char *NETWinInfo::clientMachine() const
4798{
4799 return p->client_machine;
4800}
4801
4802const char *NETWinInfo::activities() const
4803{
4804 return p->activities;
4805}
4806
4807void NETWinInfo::setActivities(const char *activities)
4808{
4809 delete[] p->activities;
4810
4811 if (activities == (char *)nullptr || activities[0] == '\0') {
4812 // on all activities
4813 static const char nulluuid[] = KDE_ALL_ACTIVITIES_UUID;
4814
4815 p->activities = nstrdup(s1: nulluuid);
4816
4817 } else {
4818 p->activities = nstrdup(s1: activities);
4819 }
4820
4821 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _KDE_NET_WM_ACTIVITIES), type: XCB_ATOM_STRING, format: 8, data_len: strlen(s: p->activities), data: p->activities);
4822}
4823
4824void NETWinInfo::setBlockingCompositing(bool active)
4825{
4826 if (p->role != Client) {
4827 return;
4828 }
4829
4830 p->blockCompositing = active;
4831 if (active) {
4832 uint32_t d = 1;
4833 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _KDE_NET_WM_BLOCK_COMPOSITING), type: XCB_ATOM_CARDINAL, format: 32, data_len: 1, data: (const void *)&d);
4834 xcb_change_property(c: p->conn, mode: XCB_PROP_MODE_REPLACE, window: p->window, property: p->atom(atom: _NET_WM_BYPASS_COMPOSITOR), type: XCB_ATOM_CARDINAL, format: 32, data_len: 1, data: (const void *)&d);
4835 } else {
4836 xcb_delete_property(c: p->conn, window: p->window, property: p->atom(atom: _KDE_NET_WM_BLOCK_COMPOSITING));
4837 xcb_delete_property(c: p->conn, window: p->window, property: p->atom(atom: _NET_WM_BYPASS_COMPOSITOR));
4838 }
4839}
4840
4841bool NETWinInfo::isBlockingCompositing() const
4842{
4843 return p->blockCompositing;
4844}
4845
4846bool NETWinInfo::handledIcons() const
4847{
4848 return p->handled_icons;
4849}
4850
4851NET::Properties NETWinInfo::passedProperties() const
4852{
4853 return p->properties;
4854}
4855
4856NET::Properties2 NETWinInfo::passedProperties2() const
4857{
4858 return p->properties2;
4859}
4860
4861NET::MappingState NETWinInfo::mappingState() const
4862{
4863 return p->mapping_state;
4864}
4865
4866NET::Protocols NETWinInfo::protocols() const
4867{
4868 return p->protocols;
4869}
4870
4871bool NETWinInfo::supportsProtocol(NET::Protocol protocol) const
4872{
4873 return p->protocols.testFlag(flag: protocol);
4874}
4875
4876std::vector<NETRect> NETWinInfo::opaqueRegion() const
4877{
4878 return p->opaqueRegion;
4879}
4880
4881xcb_connection_t *NETWinInfo::xcbConnection() const
4882{
4883 return p->conn;
4884}
4885
4886void NETWinInfo::setDesktopFileName(const char *name)
4887{
4888 if (p->role != Client) {
4889 return;
4890 }
4891
4892 delete[] p->desktop_file;
4893 p->desktop_file = nstrdup(s1: name);
4894
4895 xcb_change_property(c: p->conn,
4896 mode: XCB_PROP_MODE_REPLACE,
4897 window: p->window,
4898 property: p->atom(atom: _KDE_NET_WM_DESKTOP_FILE),
4899 type: p->atom(atom: UTF8_STRING),
4900 format: 8,
4901 data_len: strlen(s: p->desktop_file),
4902 data: (const void *)p->desktop_file);
4903}
4904
4905const char *NETWinInfo::desktopFileName() const
4906{
4907 return p->desktop_file;
4908}
4909
4910const char *NETWinInfo::gtkApplicationId() const
4911{
4912 return p->gtk_application_id;
4913}
4914
4915void NETRootInfo::virtual_hook(int, void *)
4916{
4917 /*BASE::virtual_hook( id, data );*/
4918}
4919
4920void NETWinInfo::virtual_hook(int, void *)
4921{
4922 /*BASE::virtual_hook( id, data );*/
4923}
4924
4925int NET::timestampCompare(unsigned long time1, unsigned long time2)
4926{
4927 return KXUtils::timestampCompare(time1, time2);
4928}
4929
4930int NET::timestampDiff(unsigned long time1, unsigned long time2)
4931{
4932 return KXUtils::timestampDiff(time1, time2);
4933}
4934
4935#endif
4936

source code of kwindowsystem/src/platforms/xcb/netwm.cpp