KWindowSystem

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