24 cairo_surface_destroy(win->
icon);
35 if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
36 DLOG(
"WM_CLASS not set.\n");
44 const size_t prop_length = xcb_get_property_value_length(prop);
45 char *new_class = xcb_get_property_value(prop);
46 const size_t class_class_index = strnlen(new_class, prop_length) + 1;
52 if (class_class_index < prop_length)
53 win->
class_class =
sstrndup(new_class + class_class_index, prop_length - class_class_index);
56 LOG(
"WM_CLASS changed to %s (instance), %s (class)\n",
68 if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
69 DLOG(
"_NET_WM_NAME not specified, not changing\n");
77 const int len = xcb_get_property_value_length(prop);
78 char *name =
sstrndup(xcb_get_property_value(prop), len);
104 if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
105 DLOG(
"WM_NAME not set (_NET_WM_NAME is what you want anyways).\n");
117 const int len = xcb_get_property_value_length(prop);
118 char *name =
sstrndup(xcb_get_property_value(prop), len);
130 LOG(
"Using legacy window title. Note that in order to get Unicode window "
131 "titles in i3, the application has to set _NET_WM_NAME (UTF-8)\n");
144 if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
153 const int len = xcb_get_property_value_length(prop);
154 char *qubes_vmname =
sstrndup(xcb_get_property_value(prop), len);
176 if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
182 win->
qubes_label = *(
int*) xcb_get_property_value(prop);
200 if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
201 DLOG(
"CLIENT_LEADER not set on window 0x%08x.\n", win->
id);
207 xcb_window_t *leader = xcb_get_property_value(prop);
208 if (leader == NULL) {
213 DLOG(
"Client leader changed to %08x\n", *leader);
225 if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
226 DLOG(
"TRANSIENT_FOR not set on window 0x%08x.\n", win->
id);
232 xcb_window_t transient_for;
233 if (!xcb_icccm_get_wm_transient_for_from_reply(&transient_for, prop)) {
238 DLOG(
"Transient for changed to 0x%08x (window 0x%08x)\n", transient_for, win->
id);
250 if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
251 DLOG(
"_NET_WM_STRUT_PARTIAL not set.\n");
257 if (!(strut = xcb_get_property_value(prop))) {
262 DLOG(
"Reserved pixels changed to: left = %d, right = %d, top = %d, bottom = %d\n",
263 strut[0], strut[1], strut[2], strut[3]);
275 if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
276 DLOG(
"WM_WINDOW_ROLE not set.\n");
282 sasprintf(&new_role,
"%.*s", xcb_get_property_value_length(prop),
283 (
char *)xcb_get_property_value(prop));
285 win->
role = new_role;
286 LOG(
"WM_WINDOW_ROLE changed to \"%s\"\n", win->
role);
298 if (new_type == XCB_NONE) {
299 DLOG(
"cannot read _NET_WM_WINDOW_TYPE from window.\n");
314 bool changed =
false;
315 xcb_size_hints_t size_hints;
320 success = xcb_icccm_get_wm_size_hints_from_reply(&size_hints, reply);
322 success = xcb_icccm_get_wm_normal_hints_reply(
conn, xcb_icccm_get_wm_normal_hints_unchecked(
conn, win->
id), &size_hints, NULL);
325 DLOG(
"Could not get WM_NORMAL_HINTS\n");
329 #define ASSIGN_IF_CHANGED(original, new) \
331 if (original != new) { \
337 if ((size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)) {
338 DLOG(
"Minimum size: %d (width) x %d (height)\n", size_hints.min_width, size_hints.min_height);
344 if ((size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE)) {
345 DLOG(
"Maximum size: %d (width) x %d (height)\n", size_hints.max_width, size_hints.max_height);
347 int max_width =
max(0, size_hints.max_width);
348 int max_height =
max(0, size_hints.max_height);
353 DLOG(
"Clearing maximum size\n");
359 if ((size_hints.flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC)) {
360 DLOG(
"Size increments: %d (width) x %d (height)\n", size_hints.width_inc, size_hints.height_inc);
362 if (size_hints.width_inc > 0 && size_hints.width_inc < 0xFFFF) {
368 if (size_hints.height_inc > 0 && size_hints.height_inc < 0xFFFF) {
374 DLOG(
"Clearing size increments\n");
381 if (size_hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE &&
383 DLOG(
"Base size: %d (width) x %d (height)\n", size_hints.base_width, size_hints.base_height);
388 DLOG(
"Clearing base size\n");
395 (size_hints.flags & XCB_ICCCM_SIZE_HINT_US_POSITION || size_hints.flags & XCB_ICCCM_SIZE_HINT_P_POSITION) &&
396 (size_hints.flags & XCB_ICCCM_SIZE_HINT_US_SIZE || size_hints.flags & XCB_ICCCM_SIZE_HINT_P_SIZE)) {
397 DLOG(
"Setting geometry x=%d y=%d w=%d h=%d\n", size_hints.x, size_hints.y, size_hints.width, size_hints.height);
398 geom->x = size_hints.x;
399 geom->y = size_hints.y;
400 geom->width = size_hints.width;
401 geom->height = size_hints.height;
405 if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_ASPECT &&
406 (size_hints.min_aspect_num >= 0) && (size_hints.min_aspect_den > 0) &&
407 (size_hints.max_aspect_num >= 0) && (size_hints.max_aspect_den > 0)) {
409 double min_aspect = (double)size_hints.min_aspect_num / size_hints.min_aspect_den;
410 double max_aspect = (
double)size_hints.max_aspect_num / size_hints.max_aspect_den;
411 DLOG(
"Aspect ratio set: minimum %f, maximum %f\n", min_aspect, max_aspect);
421 DLOG(
"Clearing aspect ratios\n");
435 if (urgency_hint != NULL)
436 *urgency_hint =
false;
438 if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
439 DLOG(
"WM_HINTS not set.\n");
444 xcb_icccm_wm_hints_t hints;
446 if (!xcb_icccm_get_wm_hints_from_reply(&hints, prop)) {
447 DLOG(
"Could not get WM_HINTS\n");
452 if (hints.flags & XCB_ICCCM_WM_HINT_INPUT) {
454 LOG(
"WM_HINTS.input changed to \"%d\"\n", hints.input);
457 if (urgency_hint != NULL)
458 *urgency_hint = (xcb_icccm_wm_hints_get_urgency(&hints) != 0);
480 #define MWM_HINTS_FLAGS_FIELD 0
481 #define MWM_HINTS_DECORATIONS_FIELD 2
483 #define MWM_HINTS_DECORATIONS (1 << 1)
484 #define MWM_DECOR_ALL (1 << 0)
485 #define MWM_DECOR_BORDER (1 << 1)
486 #define MWM_DECOR_TITLE (1 << 3)
488 if (motif_border_style != NULL)
491 if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
505 uint32_t *motif_hints = (uint32_t *)xcb_get_property_value(prop);
507 if (motif_border_style != NULL &&
521 #undef MWM_HINTS_FLAGS_FIELD
522 #undef MWM_HINTS_DECORATIONS_FIELD
523 #undef MWM_HINTS_DECORATIONS
525 #undef MWM_DECOR_BORDER
526 #undef MWM_DECOR_TITLE
534 if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
535 DLOG(
"WM_CLIENT_MACHINE not set.\n");
541 win->
machine =
sstrndup((
char *)xcb_get_property_value(prop), xcb_get_property_value_length(prop));
542 LOG(
"WM_CLIENT_MACHINE changed to \"%s\"\n", win->
machine);
548 uint32_t *data = NULL;
549 uint32_t width, height;
553 if (!prop || prop->type != XCB_ATOM_CARDINAL || prop->format != 32) {
554 DLOG(
"_NET_WM_ICON is not set\n");
559 uint32_t prop_value_len = xcb_get_property_value_length(prop);
560 uint32_t *prop_value = (uint32_t *)xcb_get_property_value(prop);
567 while (prop_value_len > (
sizeof(uint32_t) * 2) && prop_value &&
568 prop_value[0] && prop_value[1]) {
569 const uint32_t cur_width = prop_value[0];
570 const uint32_t cur_height = prop_value[1];
574 const uint64_t cur_len = cur_width * (uint64_t)cur_height;
575 const uint64_t expected_len = (cur_len + 2) * 4;
577 if (expected_len > prop_value_len) {
581 DLOG(
"Found _NET_WM_ICON of size: (%d,%d)\n", cur_width, cur_height);
583 const bool at_least_preferred_size = (cur_width >= pref_size &&
584 cur_height >= pref_size);
585 const bool smaller_than_current = (cur_width < width ||
586 cur_height < height);
587 const bool larger_than_current = (cur_width > width ||
588 cur_height > height);
589 const bool not_yet_at_preferred = (width < pref_size ||
592 (at_least_preferred_size &&
593 (smaller_than_current || not_yet_at_preferred)) ||
594 (!at_least_preferred_size &&
595 not_yet_at_preferred &&
596 larger_than_current)) {
603 if (width == pref_size && height == pref_size) {
608 prop_value_len -= expected_len;
609 prop_value = (uint32_t *)(((uint8_t *)prop_value) + expected_len);
613 DLOG(
"Could not get _NET_WM_ICON\n");
618 DLOG(
"Using icon of size (%d,%d) (preferred size: %d)\n",
619 width, height, pref_size);
623 uint32_t *icon =
smalloc(len * 4);
625 for (uint64_t i = 0; i < len; i++) {
627 const uint32_t pixel = data[2 + i];
628 a = (pixel >> 24) & 0xff;
629 r = (pixel >> 16) & 0xff;
630 g = (pixel >> 8) & 0xff;
631 b = (pixel >> 0) & 0xff;
638 icon[i] = ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;
641 if (win->
icon != NULL) {
642 cairo_surface_destroy(win->
icon);
644 win->
icon = cairo_image_surface_create_for_data(
645 (
unsigned char *)icon,
650 static cairo_user_data_key_t free_data;
651 cairo_surface_set_user_data(win->
icon, &free_data, icon, free);