/** * @brief Set basic properties on a window. */ void wm_wid_set_info(session_t *ps, Window wid, const char *name, Atom window_type) { // Set window name { char *textcpy = mstrjoin("skippy-xd ", name); { XTextProperty text_prop = { }; if (Success == XmbTextListToTextProperty(ps->dpy, &textcpy, 1, XStdICCTextStyle, &text_prop)) XSetWMName(ps->dpy, wid, &text_prop); sxfree(text_prop.value); } wm_wid_set_prop_utf8(ps, wid, _NET_WM_NAME, textcpy); free(textcpy); } // Set window class { XClassHint *classh = allocchk(XAllocClassHint()); classh->res_name = "skippy-xd"; classh->res_class = "skippy-xd"; XSetClassHint(ps->dpy, wid, classh); XFree(classh); } // Set window type { if (!window_type) window_type = _NET_WM_WINDOW_TYPE_NORMAL; long val = window_type; XChangeProperty(ps->dpy, wid, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *) &val, 1); } }
/** * @brief Set a UTF-8 string property on a window. */ bool wm_wid_set_prop_utf8(session_t *ps, Window wid, Atom prop, char *text) { XTextProperty text_prop = { }; bool success = (Success == XmbTextListToTextProperty(ps->dpy, &text, 1, XUTF8StringStyle, &text_prop)); if (success) XSetTextProperty(ps->dpy, wid, &text_prop, prop); sxfree(text_prop.value); return success; }
/** * @brief Get the first string in a UTF-8 string property on a window. */ char * wm_wid_get_prop_utf8(session_t *ps, Window wid, Atom prop) { XTextProperty text_prop = { }; char *ret = NULL; if (XGetTextProperty(ps->dpy, wid, &text_prop, prop)) { char **strlst = NULL; int cstr = 0; Xutf8TextPropertyToTextList(ps->dpy, &text_prop, &strlst, &cstr); if (cstr) ret = mstrdup(strlst[0]); if (strlst) XFreeStringList(strlst); } sxfree(text_prop.value); return ret; }
/** * @brief Get the raw string from a string property. */ char * wm_wid_get_prop_rstr(session_t *ps, Window wid, Atom prop) { Atom type_ret = None; int fmt_ret = 0; unsigned long nitems = 0; unsigned long bytes_after_ret = 0; unsigned char *data = NULL; char *ret = NULL; if (Success == XGetWindowProperty(ps->dpy, wid, prop, 0, BUF_LEN, False, AnyPropertyType, &type_ret, &fmt_ret, &nitems, &bytes_after_ret, &data) && nitems && 8 == fmt_ret) ret = mstrdup((char *) data); sxfree(data); return ret; }
/** * @brief Find out the WM frame of a client window by querying X. * * @param ps current session * @param wid window ID * @return window ID of the frame window */ static Window wm_find_frame(session_t *ps, Window wid) { // We traverse through its ancestors to find out the frame for (Window cwid = wid; cwid && cwid != ps->root; ) { Window rroot = None; Window *children = NULL; unsigned nchildren = 0; wid = cwid; if (!XQueryTree(ps->dpy, cwid, &rroot, &cwid, &children, &nchildren)) cwid = 0; sxfree(children); } return wid; }
pictw_t * simg_load_icon(session_t *ps, Window wid, int desired_size) { pictw_t *pictw = NULL; bool processed = false; { // _NET_WM_ICON int best_width = 0, best_height = 0; float best_scale = 1.0f, best_area = 0.0f; const unsigned char *best_data = NULL; winprop_t prop = wid_get_prop_adv(ps, wid, _NET_WM_ICON, 0, ICON_PROP_MAXLEN, XA_CARDINAL, 32); if (prop.nitems) { int width = 0, height = 0; const long *end = prop.data32 + prop.nitems; // Format: WIDTH HEIGHT DATA (32-bit) int wanted_bytes = 0; for (const long *p = prop.data32; p < end; p += wanted_bytes) { if (p + 2 >= end) { printfef("(%#010lx): %d trailing byte(s).", wid, (int) (end - p)); break; } width = p[0]; height = p[1]; if (width <= 0 || height <= 0) { printfef("(%#010lx): (offset %d, width %d, height %d) Invalid width/height.", wid, (int) (p - prop.data32), width, height); break; } wanted_bytes = 2 + width * height; if ((end - p) < wanted_bytes) { printfef("(%#010lx): (offset %d, width %d, height %d) Not enough bytes (%d/%d).", wid, (int) (p - prop.data32), width, height, (int) (end - p), wanted_bytes); break; } // Prefer larger ones if possible if (best_width >= desired_size && best_height >= desired_size && (width < desired_size || height < desired_size)) continue; float scale = MAX(1.0f, MIN((float) best_height / height, (float) best_width / width)); float area = width * height * scale * scale; if (area > best_area) { best_width = width; best_height = height; best_scale = scale; best_area = area; best_data = (const unsigned char *) (p + 2); } } } if (best_data) { { unsigned char *converted_data = simg_data32_from_long( (const long *) best_data, best_width * best_height); simg_data32_premultiply(converted_data, best_width * best_height); pictw = simg_data_to_pictw(ps, best_width, best_height, 32, converted_data, 0); if (converted_data != best_data) free(converted_data); } if (!pictw) printfef("(%#010lx): Failed to create picture.", wid); /* if (pictw) printfdf("(%#010lx): (offset %d, width %d, height %d) Loaded.", wid, (int) (best_data - prop.data8), pictw->width, pictw->height); */ } free_winprop(&prop); } if (pictw) goto simg_load_icon_end; // WM_HINTS // Our method probably fills 1-8 bit pixmaps as black instead of using // "suitable background/foreground". I hope it isn't a problem, though. { XWMHints *h = XGetWMHints(ps->dpy, wid); if (h && (IconPixmapHint & h->flags) && h->icon_pixmap) pictw = simg_pixmap_to_pictw(ps, 0, 0, 0, h->icon_pixmap, h->icon_mask); sxfree(h); } if (pictw) goto simg_load_icon_end; // KWM_WIN_ICON // Same issue as above. { winprop_t prop = wid_get_prop_adv(ps, wid, KWM_WIN_ICON, 0, 2, KWM_WIN_ICON, 32); if (prop.nitems) { Pixmap pxmap = prop.data32[0], mask = (prop.nitems >= 2 ? prop.data32[1]: None); if (pxmap) pictw = simg_pixmap_to_pictw(ps, 0, 0, 0, pxmap, mask); } free_winprop(&prop); } if (pictw) goto simg_load_icon_end; simg_load_icon_end: // Post-processing if (pictw && !processed) { pictw = simg_postprocess(ps, pictw, PICTPOSP_SCALEK, desired_size, desired_size, ALIGN_MID, ALIGN_MID, NULL); /* printfdf("(%#010lx): (width %d, height %d) Processed.", wid, pictw->width, pictw->height); */ } return pictw; }