diff --git a/bar/title-basic.c b/bar/title-basic.c index efb11c6..4ff1473 100644 --- a/bar/title-basic.c +++ b/bar/title-basic.c @@ -13,7 +13,11 @@ draw_title_basic(Bar *bar, BarDrawArg *a) Monitor *m = bar->mon; if (m->sel) { - drw_setscheme(drw, scheme[m == selmon ? SchemeTitleSel : SchemeTitleNorm]); + if (colorselectedtitle) + drw_setscheme(drw, scheme[m == selmon ? SchemeTitleSel : SchemeTitleNorm]); + else + drw_setscheme(drw, scheme[m == selmon ? SchemeTitleNorm : SchemeTitleNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0, False); if (m->sel->isfloating) drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); diff --git a/bar/title.c b/bar/title.c index c5d1e24..8e1c7cb 100644 --- a/bar/title.c +++ b/bar/title.c @@ -22,8 +22,10 @@ draw_title(Bar *bar, BarDrawArg *a) for (i = 0, c = bar->mon->clients; c; c = c->next, i++) { if (!ISVISIBLE(c)) continue; - if (bar->mon->sel == c) + if (bar->mon->sel == c && colorselectedtitle) scm = SchemeTitleSel; + else if (!colorselectedtitle) + scm = SchemeTitleNorm; else if (HIDDEN(c)) scm = SchemeTitleHidden; else @@ -34,7 +36,13 @@ draw_title(Bar *bar, BarDrawArg *a) padding = (tabw - TEXTW(c->name) + lrpad) / 2; drw_setscheme(drw, scheme[scm]); - drw_text(drw, x, 0, tabw + (i < remainder ? 1 : 0), bh, padding, c->name, 0, False); + #if USEWINICON + drw_text(drw, x, 0, tabw + (i < remainder ? 1 : 0), bh, padding + (c->name ? c->icw + iconspacing : 0), c->name, 0, False); + if (c->icon) + drw_pic(drw, x + padding, (bh - c->ich) / 2, c->icw, c->ich, c->icon); + #else + drw_text(drw, x, 0, tabw + padding (i < remainder ? 1 : 0), bh, padding, c->name, 0, False); + #endif x += tabw + (i < remainder ? 1 : 0); } } diff --git a/draw.c b/draw.c index fdc6c0c..6ca063e 100644 --- a/draw.c +++ b/draw.c @@ -24,13 +24,12 @@ /* toggle */ #include "toggle.h" -/* imlib - for rendering window icons */ +unsigned int ew; + #if USEWINICON #include #endif -unsigned int ew; - /* transition scheme for powerlines */ Clr transcheme[3]; @@ -49,9 +48,9 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h drw->depth = depth; drw->cmap = cmap; drw->drawable = XCreatePixmap(dpy, root, w, h, depth); -#if USEWINICON - drw->picture = XRenderCreatePicture(dpy, drw->drawable, XRenderFindVisualFormat(dpy, visual), 0, NULL); -#endif + #if USEWINICON + drw->picture = XRenderCreatePicture(dpy, drw->drawable, XRenderFindVisualFormat(dpy, visual), 0, NULL); + #endif drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL); XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); @@ -67,18 +66,89 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h) drw->w = w; drw->h = h; -#if USEWINICON - if (drw->picture) - XRenderFreePicture(drw->dpy, drw->picture); -#endif + #if USEWINICON + if (drw->picture) + XRenderFreePicture(drw->dpy, drw->picture); + #endif if (drw->drawable) XFreePixmap(drw->dpy, drw->drawable); drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth); -#if USEWINICON + #if USEWINICON drw->picture = XRenderCreatePicture(drw->dpy, drw->drawable, XRenderFindVisualFormat(drw->dpy, drw->visual), 0, NULL); -#endif + #endif } +#if USEWINICON +Picture +drw_picture_create_resized(Drw *drw, char *src, unsigned int srcw, unsigned int srch, unsigned int dstw, unsigned int dsth) { + Pixmap pm; + Picture pic; + GC gc; + + if (srcw <= (dstw << 1u) && srch <= (dsth << 1u)) { + XImage img = { + srcw, srch, 0, ZPixmap, src, + ImageByteOrder(drw->dpy), BitmapUnit(drw->dpy), BitmapBitOrder(drw->dpy), 32, + 32, 0, 32, + 0, 0, 0 + }; + XInitImage(&img); + + pm = XCreatePixmap(drw->dpy, drw->root, srcw, srch, 32); + gc = XCreateGC(drw->dpy, pm, 0, NULL); + XPutImage(drw->dpy, pm, gc, &img, 0, 0, 0, 0, srcw, srch); + XFreeGC(drw->dpy, gc); + + pic = XRenderCreatePicture(drw->dpy, pm, XRenderFindStandardFormat(drw->dpy, PictStandardARGB32), 0, NULL); + XFreePixmap(drw->dpy, pm); + + XRenderSetPictureFilter(drw->dpy, pic, FilterBilinear, NULL, 0); + XTransform xf; + xf.matrix[0][0] = (srcw << 16u) / dstw; xf.matrix[0][1] = 0; xf.matrix[0][2] = 0; + xf.matrix[1][0] = 0; xf.matrix[1][1] = (srch << 16u) / dsth; xf.matrix[1][2] = 0; + xf.matrix[2][0] = 0; xf.matrix[2][1] = 0; xf.matrix[2][2] = 65536; + XRenderSetPictureTransform(drw->dpy, pic, &xf); + } else { + Imlib_Image origin = imlib_create_image_using_data(srcw, srch, (DATA32 *)src); + if (!origin) return None; + imlib_context_set_image(origin); + imlib_image_set_has_alpha(1); + Imlib_Image scaled = imlib_create_cropped_scaled_image(0, 0, srcw, srch, dstw, dsth); + imlib_free_image_and_decache(); + if (!scaled) return None; + imlib_context_set_image(scaled); + imlib_image_set_has_alpha(1); + + XImage img = { + dstw, dsth, 0, ZPixmap, (char *)imlib_image_get_data_for_reading_only(), + ImageByteOrder(drw->dpy), BitmapUnit(drw->dpy), BitmapBitOrder(drw->dpy), 32, + 32, 0, 32, + 0, 0, 0 + }; + XInitImage(&img); + + pm = XCreatePixmap(drw->dpy, drw->root, dstw, dsth, 32); + gc = XCreateGC(drw->dpy, pm, 0, NULL); + XPutImage(drw->dpy, pm, gc, &img, 0, 0, 0, 0, dstw, dsth); + imlib_free_image_and_decache(); + XFreeGC(drw->dpy, gc); + + pic = XRenderCreatePicture(drw->dpy, pm, XRenderFindStandardFormat(drw->dpy, PictStandardARGB32), 0, NULL); + XFreePixmap(drw->dpy, pm); + } + + return pic; +} + +void +drw_pic(Drw *drw, int x, int y, unsigned int w, unsigned int h, Picture pic) +{ + if (!drw) + return; + XRenderComposite(drw->dpy, PictOpOver, pic, None, drw->picture, 0, 0, 0, 0, x, y, w, h); +} +#endif + /* drawing powerline arrows */ void drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash) @@ -238,68 +308,6 @@ drw_setscheme(Drw *drw, Clr *scm) drw->scheme = scm; } -#if USEWINICON -Picture -drw_picture_create_resized(Drw *drw, char *src, unsigned int srcw, unsigned int srch, unsigned int dstw, unsigned int dsth) { - Pixmap pm; - Picture pic; - GC gc; - - if (srcw <= (dstw << 1u) && srch <= (dsth << 1u)) { - XImage img = { - srcw, srch, 0, ZPixmap, src, - ImageByteOrder(drw->dpy), BitmapUnit(drw->dpy), BitmapBitOrder(drw->dpy), 32, - 32, 0, 32, - 0, 0, 0 - }; - XInitImage(&img); - - pm = XCreatePixmap(drw->dpy, drw->root, srcw, srch, 32); - gc = XCreateGC(drw->dpy, pm, 0, NULL); - XPutImage(drw->dpy, pm, gc, &img, 0, 0, 0, 0, srcw, srch); - XFreeGC(drw->dpy, gc); - - pic = XRenderCreatePicture(drw->dpy, pm, XRenderFindStandardFormat(drw->dpy, PictStandardARGB32), 0, NULL); - XFreePixmap(drw->dpy, pm); - - XRenderSetPictureFilter(drw->dpy, pic, FilterBilinear, NULL, 0); - XTransform xf; - xf.matrix[0][0] = (srcw << 16u) / dstw; xf.matrix[0][1] = 0; xf.matrix[0][2] = 0; - xf.matrix[1][0] = 0; xf.matrix[1][1] = (srch << 16u) / dsth; xf.matrix[1][2] = 0; - xf.matrix[2][0] = 0; xf.matrix[2][1] = 0; xf.matrix[2][2] = 65536; - XRenderSetPictureTransform(drw->dpy, pic, &xf); - } else { - Imlib_Image origin = imlib_create_image_using_data(srcw, srch, (DATA32 *)src); - if (!origin) return None; - imlib_context_set_image(origin); - imlib_image_set_has_alpha(1); - Imlib_Image scaled = imlib_create_cropped_scaled_image(0, 0, srcw, srch, dstw, dsth); - imlib_free_image_and_decache(); - if (!scaled) return None; - imlib_context_set_image(scaled); - imlib_image_set_has_alpha(1); - - XImage img = { - dstw, dsth, 0, ZPixmap, (char *)imlib_image_get_data_for_reading_only(), - ImageByteOrder(drw->dpy), BitmapUnit(drw->dpy), BitmapBitOrder(drw->dpy), 32, - 32, 0, 32, - 0, 0, 0 - }; - XInitImage(&img); - - pm = XCreatePixmap(drw->dpy, drw->root, dstw, dsth, 32); - gc = XCreateGC(drw->dpy, pm, 0, NULL); - XPutImage(drw->dpy, pm, gc, &img, 0, 0, 0, 0, dstw, dsth); - imlib_free_image_and_decache(); - XFreeGC(drw->dpy, gc); - - pic = XRenderCreatePicture(drw->dpy, pm, XRenderFindStandardFormat(drw->dpy, PictStandardARGB32), 0, NULL); - XFreePixmap(drw->dpy, pm); - } - - return pic; -} -#endif void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) @@ -402,17 +410,6 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp return x + (render ? w : 0); } -/* draw image */ -#if USEWINICON -void -drw_pic(Drw *drw, int x, int y, unsigned int w, unsigned int h, Picture pic) -{ - if (!drw) - return; - XRenderComposite(drw->dpy, PictOpOver, pic, None, drw->picture, 0, 0, 0, 0, x, y, w, h); -} -#endif - /* map out area */ void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) diff --git a/draw.h b/draw.h index c79c8c2..1e1d2fb 100644 --- a/draw.h +++ b/draw.h @@ -24,14 +24,18 @@ typedef struct { unsigned int depth; Colormap cmap; Drawable drawable; -#if USEWINICON + #if USEWINICON Picture picture; -#endif + #endif GC gc; Clr *scheme; Fnt *font; } Drw; +#if USEWINICON +Picture drw_picture_create_resized(Drw *drw, char *src, unsigned int src_w, unsigned int src_h, unsigned int dst_w, unsigned int dst_h); +#endif + /* Drawable abstraction */ Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap); void drw_resize(Drw *drw, unsigned int w, unsigned int h); @@ -43,6 +47,10 @@ void drw_font_free(Fnt* set); unsigned int drw_font_getwidth(Drw *drw, const char *text, Bool markup); void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup); +#if USEWINICON +void drw_pic(Drw *drw, int x, int y, unsigned int w, unsigned int h, Picture pic); +#endif + /* Colorscheme abstraction */ void drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha); Clr *drw_scm_create(Drw *drw, char *clrnames[], const unsigned int alphas[], size_t clrcount); @@ -55,18 +63,11 @@ void drw_cur_free(Drw *drw, Cur *cursor); void drw_setscheme(Drw *drw, Clr *scm); void drw_settrans(Drw *drw, Clr *psc, Clr *nsc); -#if USEWINICON -Picture drw_picture_create_resized(Drw *drw, char *src, unsigned int src_w, unsigned int src_h, unsigned int dst_w, unsigned int dst_h); -#endif - /* Drawing functions */ void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); void drw_polygon(Drw *drw, int x, int y, int ow, int oh, int sw, int sh, const XPoint *points, int npoints, int shape, int filled); int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup); void drw_arrow(Drw* drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash); -#if USEWINICON -void drw_pic(Drw *drw, int x, int y, unsigned int w, unsigned int h, Picture pic); -#endif /* Map functions */ void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); diff --git a/speedwm.c b/speedwm.c index c17f980..c5460d5 100644 --- a/speedwm.c +++ b/speedwm.c @@ -102,13 +102,16 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMWindowTypeDesktop, NetWMWindowTypeDialog, NetClientList, NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop, -#if USEFADE + #if USEFADE NetWMWindowsOpacity, -#endif -#if USESYSTRAY + #endif + #if USESYSTRAY NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayVisual, NetWMWindowTypeDock, NetSystemTrayOrientationHorz, -#endif + #endif + #if USEWINICON + NetWMIcon, + #endif NetClientListStacking, NetClientInfo, NetLast }; /* EWMH atoms */ enum { WMClass, WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ @@ -210,6 +213,9 @@ struct Client { int hintsvalid; /* https://git.suckless.org/dwm/commit/8806b6e2379372900e3d9e0bf6604bc7f727350b.html */ int bw, oldbw; unsigned int tags; /* tags */ + #if USEWINICON + unsigned int icw, ich; Picture icon; + #endif int isfixed, ispermanent, isfloating, @@ -464,6 +470,12 @@ static int getrootptr(int *x, int *y); static long getstate(Window w); static unsigned int getsystraywidth(); +#if USEWINICON +static Picture geticonprop(Window w, unsigned int *icw, unsigned int *ich); +static void freeicon(Client *c); +static void updateicon(Client *c); +#endif + #if USESYSTRAY static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); #else @@ -2534,6 +2546,85 @@ getatomprop(Client *c, Atom prop) return atom; } +#if USEWINICON +static uint32_t prealpha(uint32_t p) { + uint8_t a = p >> 24u; + uint32_t rb = (a * (p & 0xFF00FFu)) >> 8u; + uint32_t g = (a * (p & 0x00FF00u)) >> 8u; + return (rb & 0xFF00FFu) | (g & 0x00FF00u) | (a << 24u); +} + +Picture +geticonprop(Window win, unsigned int *picw, unsigned int *pich) +{ + int format; + unsigned long n, extra, *p = NULL; + Atom real; + + if (XGetWindowProperty(dpy, win, netatom[NetWMIcon], 0L, LONG_MAX, False, AnyPropertyType, + &real, &format, &n, &extra, (unsigned char **)&p) != Success) + return None; + if (n == 0 || format != 32) { XFree(p); return None; } + + unsigned long *bstp = NULL; + uint32_t w, h, sz; + { + unsigned long *i; const unsigned long *end = p + n; + uint32_t bstd = UINT32_MAX, d, m; + for (i = p; i < end - 1; i += sz) { + if ((w = *i++) >= 16384 || (h = *i++) >= 16384) { XFree(p); return None; } + if ((sz = w * h) > end - i) break; + if ((m = w > h ? w : h) >= iconsize && (d = m - iconsize) < bstd) { bstd = d; bstp = i; } + } + if (!bstp) { + for (i = p; i < end - 1; i += sz) { + if ((w = *i++) >= 16384 || (h = *i++) >= 16384) { XFree(p); return None; } + if ((sz = w * h) > end - i) break; + if ((d = iconsize - (w > h ? w : h)) < bstd) { bstd = d; bstp = i; } + } + } + if (!bstp) { XFree(p); return None; } + } + + if ((w = *(bstp - 2)) == 0 || (h = *(bstp - 1)) == 0) { XFree(p); return None; } + + uint32_t icw, ich; + if (w <= h) { + ich = iconsize; icw = w * iconsize / h; + if (icw == 0) icw = 1; + } + else { + icw = iconsize; ich = h * iconsize / w; + if (ich == 0) ich = 1; + } + *picw = icw; *pich = ich; + + uint32_t i, *bstp32 = (uint32_t *)bstp; + for (sz = w * h, i = 0; i < sz; ++i) bstp32[i] = prealpha(bstp[i]); + + Picture ret = drw_picture_create_resized(drw, (char *)bstp, w, h, icw, ich); + XFree(p); + + return ret; +} + +void +freeicon(Client *c) +{ + if (c->icon) { + XRenderFreePicture(dpy, c->icon); + c->icon = None; + } +} + +void +updateicon(Client *c) +{ + freeicon(c); + c->icon = geticonprop(c->win, &c->icw, &c->ich); +} +#endif + int getrootptr(int *x, int *y) { @@ -3259,6 +3350,9 @@ manage(Window w, XWindowAttributes *wa) c->oldbw = wa->border_width; c->cfact = 1.0; + #if USEWINICON + updateicon(c); + #endif updatetitle(c); if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { c->mon = t->mon; @@ -4316,7 +4410,11 @@ propertynotify(XEvent *e) if (c == c->mon->sel && !selmon->hidetitle) drawbaritems(c->mon); } - if (ev->atom == netatom[NetWMWindowType]) + else if (ev->atom == netatom[NetWMIcon]) { + updateicon(c); + if (c == c->mon->sel) + drawbaritems(c->mon); + } if (ev->atom == netatom[NetWMWindowType]) updatewindowtype(c); if (ev->atom == motifatom) updatemotifhints(c); @@ -5172,6 +5270,9 @@ setup(void) netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); + #if USEWINICON + netatom[NetWMIcon] = XInternAtom(dpy, "_NET_WM_ICON", False); + #endif netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); #if USESYSTRAY @@ -5791,6 +5892,9 @@ unmanage(Client *c, int destroyed) detach(c); detachstack(c); + #if USEWINICON + freeicon(c); + #endif if (!destroyed) { wc.border_width = c->oldbw; XGrabServer(dpy); /* avoid race conditions */ diff --git a/toggle.h b/toggle.h index 4202760..1ffc552 100644 --- a/toggle.h +++ b/toggle.h @@ -31,5 +31,5 @@ Not compatible with BSDs so for those, set this to 0. */ * If you wish to disable them though, set them to 0. */ #define USEIMLIB2 1 /* Whether or not to include imlib2. Required by USEWINICON and USETAGPREVIEW. */ -#define USEWINICON 0 /* Whether or not to include window icons. Requires imlib to be enabled in toggle.mk and it must be installed. */ +#define USEWINICON 1 /* Whether or not to include window icons. Requires imlib to be enabled in toggle.mk and it must be installed. */ #define USETAGPREVIEW 0 /* Whether or not to include tag previews. Requires imlib to be enabled in toggle.mk and it must be installed. */