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