From f8ae6714db02a42856c07066f689136999f6ad77 Mon Sep 17 00:00:00 2001 From: bakkeby Date: Tue, 27 Jul 2021 13:40:53 +0200 Subject: [PATCH] Adding winicon patch --- README.md | 5 ++ config.def.h | 4 ++ config.mk | 5 +- dwm.c | 23 ++++++ patch/bar_awesomebar.c | 8 +++ patch/bar_fancybar.c | 21 +++++- patch/bar_flexwintitle.c | 7 ++ patch/bar_tabgroups.c | 7 ++ patch/bar_winicon.c | 146 +++++++++++++++++++++++++++++++++++++++ patch/bar_winicon.h | 8 +++ patch/bar_wintitle.c | 19 +++-- patch/include.c | 3 + patch/include.h | 3 + patches.def.h | 18 +++++ 14 files changed, 270 insertions(+), 7 deletions(-) create mode 100644 patch/bar_winicon.c create mode 100644 patch/bar_winicon.h diff --git a/README.md b/README.md index 4de87b4..a9291c8 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ If you are experiencing issues then you may want to check out the [Known Issues] ### Changelog: +2021-07-27 - Added the winicon patch + 2021-05-30 - Added togglelayout and toggletag patches 2021-04-16 - Vanitygaps: replaced smartgaps with smartgaps\_fact, allowing gaps to be disabled or increased when there is only one client. @@ -759,6 +761,9 @@ If you are experiencing issues then you may want to check out the [Known Issues] - warps the mouse cursor to the center of the currently focused window or screen when the mouse cursor is (a) on a different screen or (b) on top of a different window + - [winicon](https://dwm.suckless.org/patches/winicon/) + - adds the window icon next to the window title in the bar + - [windowrolerule](https://github.com/bakkeby/patches/wiki/windowrolerule/) - sometimes a single application opens different windows depending on the task at hand and this is often reflected in the WM_WINDOW_ROLE(STRING) x property diff --git a/config.def.h b/config.def.h index 9b946c7..6312459 100644 --- a/config.def.h +++ b/config.def.h @@ -53,6 +53,10 @@ static const int bar_height = 0; /* 0 means derive from font, >= static const int vertpad = 10; /* vertical padding of bar */ static const int sidepad = 10; /* horizontal padding of bar */ #endif // BAR_PADDING_PATCH +#if BAR_WINICON_PATCH +#define ICONSIZE 20 /* icon size */ +#define ICONSPACING 5 /* space between icon and title */ +#endif // BAR_WINICON_PATCH #if FOCUSONCLICK_PATCH static const int focusonwheel = 0; #endif // FOCUSONCLICK_PATCH diff --git a/config.mk b/config.mk index 68a7649..62d1c84 100644 --- a/config.mk +++ b/config.mk @@ -48,9 +48,12 @@ FREETYPEINC = /usr/include/freetype2 # Uncomment this for the swallow patch / SWALLOW_PATCH #XCBLIBS = -lX11-xcb -lxcb -lxcb-res +# This is needed for the winicon patch / BAR_WINICON_PATCH +#IMLIB2LIBS = -lImlib2 + # includes and libs INCS = -I${X11INC} -I${FREETYPEINC} ${YAJLINC} ${PANGOINC} -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XRENDER} ${MPDCLIENT} ${XEXTLIB} ${XCBLIBS} ${KVMLIB} ${PANGOLIB} ${YAJLLIBS} +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XRENDER} ${MPDCLIENT} ${XEXTLIB} ${XCBLIBS} ${KVMLIB} ${PANGOLIB} ${YAJLLIBS} ${IMLIB2LIBS} # flags CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} diff --git a/dwm.c b/dwm.c index ab7f814..43b37c8 100644 --- a/dwm.c +++ b/dwm.c @@ -184,6 +184,9 @@ enum { enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetWMFullscreen, NetActiveWindow, NetWMWindowType, + #if BAR_WINICON_PATCH + NetWMIcon, + #endif // BAR_WINICON_PATCH #if BAR_SYSTRAY_PATCH NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayVisual, NetWMWindowTypeDock, NetSystemTrayOrientationHorz, @@ -388,6 +391,9 @@ struct Client { #if XKB_PATCH XkbInfo *xkb; #endif // XKB_PATCH + #if BAR_WINICON_PATCH + XImage *icon; + #endif // BAR_WINICON_PATCH }; typedef struct { @@ -2294,6 +2300,10 @@ manage(Window w, XWindowAttributes *wa) #if CFACTS_PATCH c->cfact = 1.0; #endif // CFACTS_PATCH + #if BAR_WINICON_PATCH + c->icon = NULL; + updateicon(c); + #endif // BAR_WINICON_PATCH updatetitle(c); #if XKB_PATCH @@ -2703,6 +2713,13 @@ propertynotify(XEvent *e) if (ev->atom == motifatom) updatemotifhints(c); #endif // DECORATION_HINTS_PATCH + #if BAR_WINICON_PATCH + else if (ev->atom == netatom[NetWMIcon]) { + updateicon(c); + if (c == c->mon->sel) + drawbar(c->mon); + } + #endif // BAR_WINICON_PATCH } } @@ -3526,6 +3543,9 @@ setup(void) netatom[NetCurrentDesktop] = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False); netatom[NetDesktopNames] = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False); #endif // BAR_EWMHTAGS_PATCH + #if BAR_WINICON_PATCH + netatom[NetWMIcon] = XInternAtom(dpy, "_NET_WM_ICON", False); + #endif // BAR_WINICON_PATCH netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); @@ -4134,6 +4154,9 @@ unmanage(Client *c, int destroyed) detach(c); detachstack(c); + #if BAR_WINICON_PATCH + freeicon(c); + #endif // BAR_WINICON_PATCH if (!destroyed) { wc.border_width = c->oldbw; XGrabServer(dpy); /* avoid race conditions */ diff --git a/patch/bar_awesomebar.c b/patch/bar_awesomebar.c index 9e6bc97..b02c6e7 100644 --- a/patch/bar_awesomebar.c +++ b/patch/bar_awesomebar.c @@ -46,7 +46,15 @@ draw_awesomebar(Bar *bar, BarArg *a) #endif // BAR_CENTEREDWINDOWNAME_PATCH drw_setscheme(drw, scheme[scm]); + + #if BAR_WINICON_PATCH + drw_text(drw, x, a->y, tabw + (i < remainder ? 1 : 0), a->h, pad + (c->icon ? c->icon->width + ICONSPACING : 0), c->name, 0, False); + if (c->icon) + drw_img(drw, x + pad, a->y + (a->h - c->icon->height) / 2, c->icon, tmpicon); + #else drw_text(drw, x, a->y, tabw + (i < remainder ? 1 : 0), a->h, pad, c->name, 0, False); + #endif // BAR_WINICON_PATCH + drawstateindicator(c->mon, c, 1, x, a->y, tabw + (i < remainder ? 1 : 0), a->h, 0, 0, c->isfixed); x += tabw + (i < remainder ? 1 : 0); } diff --git a/patch/bar_fancybar.c b/patch/bar_fancybar.c index 3017161..10bac83 100644 --- a/patch/bar_fancybar.c +++ b/patch/bar_fancybar.c @@ -29,6 +29,10 @@ draw_fancybar(Bar *bar, BarArg *a) if (n > 0) { ftw = TEXTW(m->sel->name); + #if BAR_WINICON_PATCH + if (m->sel->icon) + ftw += m->sel->icon->width + ICONSPACING; + #endif // BAR_WINICON_PATCH mw = (ftw >= w || n == 1) ? 0 : (w - ftw) / (n - 1); i = 0; @@ -37,6 +41,10 @@ draw_fancybar(Bar *bar, BarArg *a) if (!ISVISIBLE(c) || c == m->sel) continue; ftw = TEXTW(c->name); + #if BAR_WINICON_PATCH + if (c->icon) + ftw += c->icon->width + ICONSPACING; + #endif // BAR_WINICON_PATCH if (ftw < mw) ew += (mw - ftw); else @@ -51,8 +59,19 @@ draw_fancybar(Bar *bar, BarArg *a) continue; ftw = MIN(m->sel == c ? w : mw, TEXTW(c->name)); drw_setscheme(drw, scheme[m->sel == c ? SchemeTitleSel : SchemeTitleNorm]); - if (ftw > 0) /* trap special handling of 0 in drw_text */ + if (ftw > 0) { /* trap special handling of 0 in drw_text */ + + drw_text(drw, x, a->y, ftw, a->h, lrpad / 2, c->name, 0, False); + + #if BAR_WINICON_PATCH + drw_text(drw, x, a->y, ftw, a->h, lrpad / 2 + (c->icon ? c->icon->width + ICONSPACING : 0), c->name, 0, False); + if (c->icon) + drw_img(drw, x + lrpad / 2, a->y + (a->h - c->icon->height) / 2, c->icon, tmpicon); + #else drw_text(drw, x, a->y, ftw, a->h, lrpad / 2, c->name, 0, False); + #endif // BAR_WINICON_PATCH + + } drawstateindicator(c->mon, c, 1, x, a->y, ftw, a->h, 0, 0, c->isfixed); x += ftw; w -= ftw; diff --git a/patch/bar_flexwintitle.c b/patch/bar_flexwintitle.c index 8d650e1..0e17443 100644 --- a/patch/bar_flexwintitle.c +++ b/patch/bar_flexwintitle.c @@ -191,7 +191,14 @@ flextitledraw(Monitor *m, Client *c, int unused, int x, int w, int tabscheme, Ar pad = (w - TEXTW(c->name) + lrpad) / 2; #endif // BAR_CENTEREDWINDOWNAME_PATCH + #if BAR_WINICON_PATCH + drw_text(drw, x, barg->y, w, barg->h, pad + (c->icon ? c->icon->width + ICONSPACING : 0), c->name, 0, False); + if (c->icon) + drw_img(drw, x + pad, barg->y + (barg->h - c->icon->height) / 2, c->icon, tmpicon); + #else drw_text(drw, x, barg->y, w, barg->h, pad, c->name, 0, False); + #endif // BAR_WINICON_PATCH + drawstateindicator(m, c, 1, x + 2, barg->y, w, barg->h, 0, 0, 0); if (FLEXWINTITLE_BORDERS) { diff --git a/patch/bar_tabgroups.c b/patch/bar_tabgroups.c index 91e1393..1498bc2 100644 --- a/patch/bar_tabgroups.c +++ b/patch/bar_tabgroups.c @@ -62,7 +62,14 @@ bartabdraw(Monitor *m, Client *c, int unused, int x, int w, int groupactive, Arg pad = (w - TEXTW(c->name) + lrpad) / 2; #endif // BAR_CENTEREDWINDOWNAME_PATCH + #if BAR_WINICON_PATCH + drw_text(drw, x, barg->y, w, barg->h, pad + (c->icon ? c->icon->width + ICONSPACING : 0), c->name, 0, False); + if (c->icon) + drw_img(drw, x + pad, barg->y + (barg->h - c->icon->height) / 2, c->icon, tmpicon); + #else drw_text(drw, x, barg->y, w, barg->h, pad, c->name, 0, False); + #endif // BAR_WINICON_PATCH + drawstateindicator(m, c, 1, x, barg->y, w, barg->h, 0, 0, c->isfixed); if (BARTAB_BORDERS) { diff --git a/patch/bar_winicon.c b/patch/bar_winicon.c new file mode 100644 index 0000000..5ae7fe7 --- /dev/null +++ b/patch/bar_winicon.c @@ -0,0 +1,146 @@ +static uint32_t tmpicon[ICONSIZE * ICONSIZE]; + +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); +} + +#if BAR_ALPHA_PATCH +static uint8_t div255(uint16_t x) { return (x*0x8081u) >> 23u; } +static uint32_t blend(uint32_t p1rb, uint32_t p1g, uint8_t p1a, uint32_t p2) { + uint8_t a = p2 >> 24u; + uint32_t rb = (p2 & 0xFF00FFu) + ( (a * p1rb) >> 8u ); + uint32_t g = (p2 & 0x00FF00u) + ( (a * p1g) >> 8u ); + return (rb & 0xFF00FFu) | (g & 0x00FF00u) | div255(~a * 255u + a * p1a) << 24u; +} + +void +drw_img(Drw *drw, int x, int y, XImage *img, uint32_t *tmp) +{ + if (!drw || !drw->scheme) + return; + uint32_t *data = (uint32_t *)img->data, p = drw->scheme[ColBg].pixel, + prb = p & 0xFF00FFu, pg = p & 0x00FF00u; + uint8_t pa = p >> 24u; + int icsz = img->width * img->height, i; + for (i = 0; i < icsz; ++i) tmp[i] = blend(prb, pg, pa, data[i]); + + img->data = (char *) tmp; + XPutImage(drw->dpy, drw->drawable, drw->gc, img, 0, 0, x, y, img->width, img->height); + img->data = (char *) data; +} +#else +static uint32_t blend(uint32_t p1rb, uint32_t p1g, uint32_t p2) { + uint8_t a = p2 >> 24u; + uint32_t rb = (p2 & 0xFF00FFu) + ( (a * p1rb) >> 8u ); + uint32_t g = (p2 & 0x00FF00u) + ( (a * p1g) >> 8u ); + return (rb & 0xFF00FFu) | (g & 0x00FF00u) | ((~a) << 24u); +} + +void +drw_img(Drw *drw, int x, int y, XImage *img, uint32_t *tmp) +{ + if (!drw || !drw->scheme) + return; + uint32_t *data = (uint32_t *)img->data, p = drw->scheme[ColBg].pixel, prb = p & 0xFF00FFu, pg = p & 0x00FF00u; + int icsz = img->width * img->height, i; + for (i = 0; i < icsz; ++i) tmp[i] = blend(prb, pg, data[i]); + img->data = (char *) tmp; + XPutImage(drw->dpy, drw->drawable, drw->gc, img, 0, 0, x, y, img->width, img->height); + img->data = (char *) data; +} +#endif // BAR_ALPHA_PATCH + +XImage * +geticonprop(Window win) +{ + 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 NULL; + if (n == 0 || format != 32) { XFree(p); return NULL; } + + unsigned long *bstp = NULL; + uint32_t w, h, sz; + + { + const unsigned long *end = p + n; + unsigned long *i; + uint32_t bstd = UINT32_MAX, d, m; + for (i = p; i < end - 1; i += sz) { + if ((w = *i++) > UINT16_MAX || (h = *i++) > UINT16_MAX) { XFree(p); return NULL; } + 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++) > UINT16_MAX || (h = *i++) > UINT16_MAX) { XFree(p); return NULL; } + if ((sz = w * h) > end - i) break; + if ((d = ICONSIZE - (w > h ? w : h)) < bstd) { bstd = d; bstp = i; } + } + } + if (!bstp) { XFree(p); return NULL; } + } + + if ((w = *(bstp - 2)) == 0 || (h = *(bstp - 1)) == 0) { XFree(p); return NULL; } + + uint32_t icw, ich, icsz; + 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; + } + icsz = icw * ich; + + uint32_t i; +#if ULONG_MAX > UINT32_MAX + uint32_t *bstp32 = (uint32_t *)bstp; + for (sz = w * h, i = 0; i < sz; ++i) bstp32[i] = bstp[i]; +#endif + uint32_t *icbuf = malloc(icsz << 2); if(!icbuf) { XFree(p); return NULL; } + if (w == icw && h == ich) memcpy(icbuf, bstp, icsz << 2); + else { + Imlib_Image origin = imlib_create_image_using_data(w, h, (DATA32 *)bstp); + if (!origin) { XFree(p); free(icbuf); return NULL; } + imlib_context_set_image(origin); + imlib_image_set_has_alpha(1); + Imlib_Image scaled = imlib_create_cropped_scaled_image(0, 0, w, h, icw, ich); + imlib_free_image_and_decache(); + if (!scaled) { XFree(p); free(icbuf); return NULL; } + imlib_context_set_image(scaled); + imlib_image_set_has_alpha(1); + memcpy(icbuf, imlib_image_get_data_for_reading_only(), icsz << 2); + imlib_free_image_and_decache(); + } + XFree(p); + for (i = 0; i < icsz; ++i) icbuf[i] = prealpha(icbuf[i]); + #if BAR_ALPHA_PATCH + return XCreateImage(dpy, drw->visual, drw->depth, ZPixmap, 0, (char *)icbuf, icw, ich, 32, 0); + #else + return XCreateImage(dpy, DefaultVisual(dpy, screen), DefaultDepth(dpy, screen), ZPixmap, 0, (char *)icbuf, icw, ich, 32, 0); + #endif // BAR_ALPHA_PATCH +} + +void +freeicon(Client *c) +{ + if (c->icon) { + XDestroyImage(c->icon); + c->icon = NULL; + } +} + +void +updateicon(Client *c) +{ + freeicon(c); + c->icon = geticonprop(c->win); +} \ No newline at end of file diff --git a/patch/bar_winicon.h b/patch/bar_winicon.h new file mode 100644 index 0000000..791182e --- /dev/null +++ b/patch/bar_winicon.h @@ -0,0 +1,8 @@ +#include +#include +#include + +void drw_img(Drw *drw, int x, int y, XImage *img, uint32_t *tmp); +static XImage *geticonprop(Window win); +static void freeicon(Client *c); +static void updateicon(Client *c); \ No newline at end of file diff --git a/patch/bar_wintitle.c b/patch/bar_wintitle.c index d3b5258..d2241d2 100644 --- a/patch/bar_wintitle.c +++ b/patch/bar_wintitle.c @@ -17,9 +17,10 @@ draw_wintitle(Bar *bar, BarArg *a) int x = a->x, w = a->w; #endif // BAR_TITLE_LEFT_PAD_PATCH | BAR_TITLE_RIGHT_PAD_PATCH Monitor *m = bar->mon; + Client *c = m->sel; int pad = lrpad / 2; - if (!m->sel) { + if (!c) { drw_setscheme(drw, scheme[SchemeTitleNorm]); drw_rect(drw, x, a->y, w, a->h, 1, 1); return 0; @@ -30,15 +31,23 @@ draw_wintitle(Bar *bar, BarArg *a) XSetErrorHandler(xerrordummy); #endif // BAR_IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH #if BAR_CENTEREDWINDOWNAME_PATCH - if (TEXTW(m->sel->name) < w) - pad = (w - TEXTW(m->sel->name) + lrpad) / 2; + if (TEXTW(c->name) < w) + pad = (w - TEXTW(c->name) + lrpad) / 2; #endif // BAR_CENTEREDWINDOWNAME_PATCH - drw_text(drw, x, a->y, w, a->h, pad, m->sel->name, 0, False); + + #if BAR_WINICON_PATCH + drw_text(drw, x, a->y, w, a->h, pad + (c->icon ? c->icon->width + ICONSPACING : 0), c->name, 0, False); + if (c->icon) + drw_img(drw, x + pad, a->y + (a->h - c->icon->height) / 2, c->icon, tmpicon); + #else + drw_text(drw, x, a->y, w, a->h, pad, c->name, 0, False); + #endif // BAR_WINICON_PATCH + #if BAR_IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH XSync(dpy, False); XSetErrorHandler(xerror); #endif // BAR_IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH - drawstateindicator(m, m->sel, 1, x, a->y, w, a->h, 0, 0, m->sel->isfixed); + drawstateindicator(m, c, 1, x, a->y, w, a->h, 0, 0, c->isfixed); return 1; } diff --git a/patch/include.c b/patch/include.c index 2e7d92c..29dac83 100644 --- a/patch/include.c +++ b/patch/include.c @@ -47,6 +47,9 @@ #if BAR_STATUSCOLORS_PATCH #include "bar_statuscolors.c" #endif +#if BAR_WINICON_PATCH +#include "bar_winicon.c" +#endif #if BAR_TABGROUPS_PATCH #include "bar_tabgroups.c" #endif diff --git a/patch/include.h b/patch/include.h index 850589e..c913a27 100644 --- a/patch/include.h +++ b/patch/include.h @@ -44,6 +44,9 @@ #if BAR_STATUSCMD_PATCH #include "bar_statuscmd.h" #endif +#if BAR_WINICON_PATCH +#include "bar_winicon.h" +#endif #if BAR_TABGROUPS_PATCH #include "bar_tabgroups.h" #endif diff --git a/patches.def.h b/patches.def.h index eb6e1ee..aaaf02a 100644 --- a/patches.def.h +++ b/patches.def.h @@ -155,6 +155,24 @@ /* Show tag symbols in bar */ #define BAR_TAGS_PATCH 1 +/* This patch adds the window icon next to the window title in the bar. + * + * The patch depends on Imlib2 for icon scaling. + * You need to uncomment the corresponding line in config.mk to use the -lImlib2 library + * + * Arch Linux: + * sudo pacman -S imlib2 + * Debian: + * sudo apt install libimlib2-dev + * + * The author recommends adding the compiler flags of -O3 and -march=native to enable auto loop + * vectorize for better performance. + * + * https://github.com/AdamYuan/dwm-winicon + * https://dwm.suckless.org/patches/winicon + */ +#define BAR_WINICON_PATCH 0 + /* Show window title in bar */ #define BAR_WINTITLE_PATCH 1