/** * Match a window against a single leaf window condition. * * For internal use. */ static inline void c2_match_once_leaf(session_t *ps, win *w, const c2_l_t *pleaf, bool *pres, bool *perr) { assert(pleaf); const Window wid = (pleaf->tgt_onframe ? w->client_win: w->id); // Return if wid is missing if (!pleaf->predef && !wid) return; const int idx = (pleaf->index < 0 ? 0: pleaf->index); switch (pleaf->ptntype) { // Deal with integer patterns case C2_L_PTINT: { long tgt = 0; // Get the value // A predefined target if (pleaf->predef) { *perr = false; switch (pleaf->predef) { case C2_L_PID: tgt = wid; break; case C2_L_PX: tgt = w->a.x; break; case C2_L_PY: tgt = w->a.y; break; case C2_L_PX2: tgt = w->a.x + w->widthb; break; case C2_L_PY2: tgt = w->a.y + w->heightb; break; case C2_L_PWIDTH: tgt = w->a.width; break; case C2_L_PHEIGHT: tgt = w->a.height; break; case C2_L_PWIDTHB: tgt = w->widthb; break; case C2_L_PHEIGHTB: tgt = w->heightb; break; case C2_L_PBDW: tgt = w->a.border_width; break; case C2_L_PFULLSCREEN: tgt = win_is_fullscreen(ps, w); break; case C2_L_POVREDIR: tgt = w->a.override_redirect; break; case C2_L_PARGB: tgt = (WMODE_ARGB == w->mode); break; case C2_L_PFOCUSED: tgt = w->focused_real; break; case C2_L_PWMWIN: tgt = w->wmwin; break; case C2_L_PCLIENT: tgt = w->client_win; break; case C2_L_PLEADER: tgt = w->leader; break; default: *perr = true; assert(0); break; } } // A raw window property else { winprop_t prop = wid_get_prop_adv(ps, wid, pleaf->tgtatom, idx, 1L, c2_get_atom_type(pleaf), pleaf->format); if (prop.nitems) { *perr = false; tgt = winprop_get_int(prop); } free_winprop(&prop); } if (*perr) return; // Do comparison switch (pleaf->op) { case C2_L_OEXISTS: *pres = (pleaf->predef ? tgt: true); break; case C2_L_OEQ: *pres = (tgt == pleaf->ptnint); break; case C2_L_OGT: *pres = (tgt > pleaf->ptnint); break; case C2_L_OGTEQ: *pres = (tgt >= pleaf->ptnint); break; case C2_L_OLT: *pres = (tgt < pleaf->ptnint); break; case C2_L_OLTEQ: *pres = (tgt <= pleaf->ptnint); break; default: *perr = true; assert(0); break; } } break; // String patterns case C2_L_PTSTRING: { const char *tgt = NULL; char *tgt_free = NULL; // A predefined target if (pleaf->predef) { switch (pleaf->predef) { case C2_L_PWINDOWTYPE: tgt = WINTYPES[w->window_type]; break; case C2_L_PNAME: tgt = w->name; break; case C2_L_PCLASSG: tgt = w->class_general; break; case C2_L_PCLASSI: tgt = w->class_instance; break; case C2_L_PROLE: tgt = w->role; break; default: assert(0); break; } } // If it's an atom type property, convert atom to string else if (C2_L_TATOM == pleaf->type) { winprop_t prop = wid_get_prop_adv(ps, wid, pleaf->tgtatom, idx, 1L, c2_get_atom_type(pleaf), pleaf->format); Atom atom = winprop_get_int(prop); if (atom) { tgt_free = XGetAtomName(ps->dpy, atom); } if (tgt_free) { tgt = tgt_free; } free_winprop(&prop); } // Otherwise, just fetch the string list else { char **strlst = NULL; int nstr; if (wid_get_text_prop(ps, wid, pleaf->tgtatom, &strlst, &nstr) && nstr > idx) { tgt_free = mstrcpy(strlst[idx]); tgt = tgt_free; } if (strlst) XFreeStringList(strlst); } if (tgt) { *perr = false; } else { return; } // Actual matching switch (pleaf->op) { case C2_L_OEXISTS: *pres = true; break; case C2_L_OEQ: switch (pleaf->match) { case C2_L_MEXACT: if (pleaf->match_ignorecase) *pres = !strcasecmp(tgt, pleaf->ptnstr); else *pres = !strcmp(tgt, pleaf->ptnstr); break; case C2_L_MCONTAINS: if (pleaf->match_ignorecase) *pres = strcasestr(tgt, pleaf->ptnstr); else *pres = strstr(tgt, pleaf->ptnstr); break; case C2_L_MSTART: if (pleaf->match_ignorecase) *pres = !strncasecmp(tgt, pleaf->ptnstr, strlen(pleaf->ptnstr)); else *pres = !strncmp(tgt, pleaf->ptnstr, strlen(pleaf->ptnstr)); break; case C2_L_MWILDCARD: { int flags = 0; if (pleaf->match_ignorecase) flags |= FNM_CASEFOLD; *pres = !fnmatch(pleaf->ptnstr, tgt, flags); } break; case C2_L_MPCRE: #ifdef CONFIG_REGEX_PCRE *pres = (pcre_exec(pleaf->regex_pcre, pleaf->regex_pcre_extra, tgt, strlen(tgt), 0, 0, NULL, 0) >= 0); #else assert(0); #endif break; } break; default: *perr = true; assert(0); } // Free the string after usage, if necessary if (tgt_free) { if (C2_L_TATOM == pleaf->type) cxfree(tgt_free); else free(tgt_free); } } break; default: assert(0); break; } }
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; }