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