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