From 1a9fcf5fdd6e9adccd46b0cec15ad57f77f5b6dd Mon Sep 17 00:00:00 2001 From: xAlpharax <42233094+xAlpharax@users.noreply.github.com> Date: Wed, 16 Aug 2023 23:49:08 +0300 Subject: Patching better gaps with fullgaps. Everything is stable in this commit. Changes to be committed: modified: config.def.h modified: config.def.h.orig modified: config.def.h.rej modified: config.h modified: drw.c modified: drw.c.orig deleted: dwm.1.orig modified: dwm.c modified: dwm.c.orig modified: dwm.c.rej renamed: patches_new/dwm-fullgaps-6.4.diff -> patches/dwm-fullgaps-6.4.diff deleted: patches/dwm-uselessgap-20211119-58414bee958f2.diff renamed: patches_new/dwm-tag-preview-6.3.diff -> patches_huge/dwm-tag-preview-6.3.diff renamed: patches_new/dwm-winicon-6.3-v2.1.diff -> patches_huge/dwm-winicon-6.3-v2.1.diff modified: patches_new/dwm-noborderflicker-20211227-8657affa2a61.diff --- patches_huge/dwm-tag-preview-6.3.diff | 315 ++++++++++++++++++++++++++++ patches_huge/dwm-winicon-6.3-v2.1.diff | 371 +++++++++++++++++++++++++++++++++ 2 files changed, 686 insertions(+) create mode 100644 patches_huge/dwm-tag-preview-6.3.diff create mode 100644 patches_huge/dwm-winicon-6.3-v2.1.diff (limited to 'patches_huge') diff --git a/patches_huge/dwm-tag-preview-6.3.diff b/patches_huge/dwm-tag-preview-6.3.diff new file mode 100644 index 0000000..dbee35d --- /dev/null +++ b/patches_huge/dwm-tag-preview-6.3.diff @@ -0,0 +1,315 @@ +From 841ad7d5767f945ee9da6c5afc8cff98ca2f8231 Mon Sep 17 00:00:00 2001 +From: explosion-mental +Date: Thu, 1 Sep 2022 16:21:58 -0500 +Subject: [PATCH] [PATCH] tag previews: free() tagmap and add previewtag func + +Allows you to see the contents of an already viewed tag. So a more +accurate description would be to re-view a tag. + +Allows you to see the contents of an already viewed tag. So a more +accurate description would be to re-view a tag. + +Compatibility with the alpha patch (replacing DefaultDepth() and +DefaultVisual() with depth and visual + window masks) and hide vacants can be +achieved, I left some lines to uncomment. + +added: +* more compact structure, more probable to patch on top of other patches + or easier to patch manually (like not moving the Monitor struct..) +* create the window preview in updatebars() +* renamed switchtag() -> takepreview(), makes more sense since it's + "taking" the preview (basically a screenshot). +* option previewbar, whether to show the bar in the preview or not. +* previewtag which takes a tag (unsigned int from 0 to the last tag) and + previews it. This allows to preview tags without using the + cursor/mouse (which avoids a recursive previews preview). + adding it to the TAGKEYS macro makes more sense so I've added it + replacing (keybinding wise, not functionality) toggletag. +``` +\#define TAGKEYS(KEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ + { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ +-> { MODKEY|ControlMask|ShiftMask, KEY, previewtag, {.ui = TAG } }, +``` +--- + config.def.h | 4 +- + config.mk | 5 +- + dwm.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++- + 3 files changed, 145 insertions(+), 3 deletions(-) + +diff --git a/config.def.h b/config.def.h +index a2ac963..eb70348 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -3,6 +3,8 @@ + /* appearance */ + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ ++static const int scalepreview = 4; /* preview scaling (display w and h / scalepreview) */ ++static const int previewbar = 1; /* show the bar in the preview window */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ + static const char *fonts[] = { "monospace:size=10" }; +@@ -50,7 +52,7 @@ static const Layout layouts[] = { + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ + { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ +- { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, ++ { MODKEY|ControlMask|ShiftMask, KEY, previewtag, {.ui = TAG } }, \ + + /* helper for spawning shell commands in the pre dwm-5.0 fashion */ + #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } +diff --git a/config.mk b/config.mk +index b6eb7e0..6f5129e 100644 +--- a/config.mk ++++ b/config.mk +@@ -20,9 +20,12 @@ FREETYPEINC = /usr/include/freetype2 + # OpenBSD (uncomment) + #FREETYPEINC = ${X11INC}/freetype2 + ++# Imlib2 (tag previews) ++IMLIB2LIBS = -lImlib2 ++ + # includes and libs + INCS = -I${X11INC} -I${FREETYPEINC} +-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${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 a96f33c..0c0ba12 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -40,6 +40,7 @@ + #include + #endif /* XINERAMA */ + #include ++#include + + #include "drw.h" + #include "util.h" +@@ -112,6 +113,9 @@ typedef struct { + } Layout; + + struct Monitor { ++ int previewshow; ++ Window tagwin; ++ Pixmap *tagmap; + char ltsymbol[16]; + float mfact; + int nmaster; +@@ -235,6 +239,10 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); + static void zoom(const Arg *arg); + ++static void showtagpreview(unsigned int i); ++static void takepreview(void); ++static void previewtag(const Arg *arg); ++ + /* variables */ + static const char broken[] = "broken"; + static char stext[256]; +@@ -438,6 +446,11 @@ buttonpress(XEvent *e) + if (i < LENGTH(tags)) { + click = ClkTagBar; + arg.ui = 1 << i; ++ /* hide preview if we click the bar */ ++ if (selmon->previewshow) { ++ selmon->previewshow = 0; ++ XUnmapWindow(dpy, selmon->tagwin); ++ } + } else if (ev->x < x + blw) + click = ClkLtSymbol; + else if (ev->x > selmon->ww - (int)TEXTW(stext)) +@@ -498,6 +511,7 @@ void + cleanupmon(Monitor *mon) + { + Monitor *m; ++ size_t i; + + if (mon == mons) + mons = mons->next; +@@ -505,8 +519,14 @@ cleanupmon(Monitor *mon) + for (m = mons; m && m->next != mon; m = m->next); + m->next = mon->next; + } ++ for (i = 0; i < LENGTH(tags); i++) ++ if (mon->tagmap[i]) ++ XFreePixmap(dpy, mon->tagmap[i]); ++ free(mon->tagmap); + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tagwin); ++ XDestroyWindow(dpy, mon->tagwin); + free(mon); + } + +@@ -641,6 +661,7 @@ createmon(void) + m->topbar = topbar; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; ++ m->tagmap = ecalloc(LENGTH(tags), sizeof(Pixmap)); + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + return m; + } +@@ -1125,6 +1146,36 @@ motionnotify(XEvent *e) + static Monitor *mon = NULL; + Monitor *m; + XMotionEvent *ev = &e->xmotion; ++ unsigned int i, x; ++ ++ if (ev->window == selmon->barwin) { ++ i = x = 0; ++ do ++ x += TEXTW(tags[i]); ++ while (ev->x >= x && ++i < LENGTH(tags)); ++ /* FIXME when hovering the mouse over the tags and we view the tag, ++ * the preview window get's in the preview shot */ ++ ++ if (i < LENGTH(tags)) { ++ if (selmon->previewshow != (i + 1) ++ && !(selmon->tagset[selmon->seltags] & 1 << i)) { ++ selmon->previewshow = i + 1; ++ showtagpreview(i); ++ } else if (selmon->tagset[selmon->seltags] & 1 << i) { ++ selmon->previewshow = 0; ++ XUnmapWindow(dpy, selmon->tagwin); ++ } ++ } else if (selmon->previewshow) { ++ selmon->previewshow = 0; ++ XUnmapWindow(dpy, selmon->tagwin); ++ } ++ } else if (ev->window == selmon->tagwin) { ++ selmon->previewshow = 0; ++ XUnmapWindow(dpy, selmon->tagwin); ++ } else if (selmon->previewshow) { ++ selmon->previewshow = 0; ++ XUnmapWindow(dpy, selmon->tagwin); ++ } + + if (ev->window != root) + return; +@@ -1530,6 +1581,82 @@ setmfact(const Arg *arg) + arrange(selmon); + } + ++void ++showtagpreview(unsigned int i) ++{ ++ if (!selmon->previewshow || !selmon->tagmap[i]) { ++ XUnmapWindow(dpy, selmon->tagwin); ++ return; ++ } ++ ++ XSetWindowBackgroundPixmap(dpy, selmon->tagwin, selmon->tagmap[i]); ++ XCopyArea(dpy, selmon->tagmap[i], selmon->tagwin, drw->gc, 0, 0, ++ selmon->mw / scalepreview, selmon->mh / scalepreview, ++ 0, 0); ++ XSync(dpy, False); ++ XMapRaised(dpy, selmon->tagwin); ++} ++ ++void ++takepreview(void) ++{ ++ Client *c; ++ Imlib_Image image; ++ unsigned int occ = 0, i; ++ ++ for (c = selmon->clients; c; c = c->next) ++ occ |= c->tags; ++ //occ |= c->tags == 255 ? 0 : c->tags; /* hide vacants */ ++ ++ for (i = 0; i < LENGTH(tags); i++) { ++ /* searching for tags that are occupied && selected */ ++ if (!(occ & 1 << i) || !(selmon->tagset[selmon->seltags] & 1 << i)) ++ continue; ++ ++ if (selmon->tagmap[i]) { /* tagmap exist, clean it */ ++ XFreePixmap(dpy, selmon->tagmap[i]); ++ selmon->tagmap[i] = 0; ++ } ++ ++ /* try to unmap the window so it doesn't show the preview on the preview */ ++ selmon->previewshow = 0; ++ XUnmapWindow(dpy, selmon->tagwin); ++ XSync(dpy, False); ++ ++ if (!(image = imlib_create_image(sw, sh))) { ++ fprintf(stderr, "dwm: imlib: failed to create image, skipping."); ++ continue; ++ } ++ imlib_context_set_image(image); ++ imlib_context_set_display(dpy); ++ /* uncomment if using alpha patch */ ++ //imlib_image_set_has_alpha(1); ++ //imlib_context_set_blend(0); ++ //imlib_context_set_visual(visual); ++ imlib_context_set_visual(DefaultVisual(dpy, screen)); ++ imlib_context_set_drawable(root); ++ ++ if (previewbar) ++ imlib_copy_drawable_to_image(0, selmon->wx, selmon->wy, selmon->ww, selmon->wh, 0, 0, 1); ++ else ++ imlib_copy_drawable_to_image(0, selmon->mx, selmon->my, selmon->mw ,selmon->mh, 0, 0, 1); ++ selmon->tagmap[i] = XCreatePixmap(dpy, selmon->tagwin, selmon->mw / scalepreview, selmon->mh / scalepreview, DefaultDepth(dpy, screen)); ++ imlib_context_set_drawable(selmon->tagmap[i]); ++ imlib_render_image_part_on_drawable_at_size(0, 0, selmon->mw, selmon->mh, 0, 0, selmon->mw / scalepreview, selmon->mh / scalepreview); ++ imlib_free_image(); ++ } ++} ++ ++void ++previewtag(const Arg *arg) ++{ ++ if (selmon->previewshow != (arg->ui + 1)) ++ selmon->previewshow = arg->ui + 1; ++ else ++ selmon->previewshow = 0; ++ showtagpreview(arg->ui); ++} ++ + void + setup(void) + { +@@ -1746,6 +1873,7 @@ toggleview(const Arg *arg) + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + + if (newtagset) { ++ takepreview(); + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); + arrange(selmon); +@@ -1811,10 +1939,18 @@ updatebars(void) + XSetWindowAttributes wa = { + .override_redirect = True, + .background_pixmap = ParentRelative, +- .event_mask = ButtonPressMask|ExposureMask ++ .event_mask = ButtonPressMask|ExposureMask|PointerMotionMask + }; ++ + XClassHint ch = {"dwm", "dwm"}; + for (m = mons; m; m = m->next) { ++ if (!m->tagwin) { ++ m->tagwin = XCreateWindow(dpy, root, m->wx, m->by + bh, m->mw / scalepreview, ++ m->mh / scalepreview, 0, DefaultDepth(dpy, screen), CopyFromParent, ++ DefaultVisual(dpy, screen), CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ XDefineCursor(dpy, m->tagwin, cursor[CurNormal]->cursor); ++ XUnmapWindow(dpy, m->tagwin); ++ } + if (m->barwin) + continue; + m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), +@@ -2043,6 +2179,7 @@ view(const Arg *arg) + { + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; ++ takepreview(); + selmon->seltags ^= 1; /* toggle sel tagset */ + if (arg->ui & TAGMASK) + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; +-- +2.37.3 + diff --git a/patches_huge/dwm-winicon-6.3-v2.1.diff b/patches_huge/dwm-winicon-6.3-v2.1.diff new file mode 100644 index 0000000..4278431 --- /dev/null +++ b/patches_huge/dwm-winicon-6.3-v2.1.diff @@ -0,0 +1,371 @@ +diff --git a/config.def.h b/config.def.h +index a2ac963..322d181 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -5,6 +5,8 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ ++#define ICONSIZE 16 /* icon size */ ++#define ICONSPACING 5 /* space between icon and title */ + static const char *fonts[] = { "monospace:size=10" }; + static const char dmenufont[] = "monospace:size=10"; + static const char col_gray1[] = "#222222"; +diff --git a/config.mk b/config.mk +index b6eb7e0..f3c01b0 100644 +--- a/config.mk ++++ b/config.mk +@@ -22,7 +22,7 @@ FREETYPEINC = /usr/include/freetype2 + + # includes and libs + INCS = -I${X11INC} -I${FREETYPEINC} +-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender -lImlib2 + + # flags + CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +diff --git a/drw.c b/drw.c +index 4cdbcbe..9b474c5 100644 +--- a/drw.c ++++ b/drw.c +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + + #include "drw.h" + #include "util.h" +@@ -71,6 +72,7 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h + drw->w = w; + drw->h = h; + drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); ++ drw->picture = XRenderCreatePicture(dpy, drw->drawable, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, screen)), 0, NULL); + drw->gc = XCreateGC(dpy, root, 0, NULL); + XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); + +@@ -85,14 +87,18 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h) + + drw->w = w; + drw->h = h; ++ if (drw->picture) ++ XRenderFreePicture(drw->dpy, drw->picture); + if (drw->drawable) + XFreePixmap(drw->dpy, drw->drawable); + drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen)); ++ drw->picture = XRenderCreatePicture(drw->dpy, drw->drawable, XRenderFindVisualFormat(drw->dpy, DefaultVisual(drw->dpy, drw->screen)), 0, NULL); + } + + void + drw_free(Drw *drw) + { ++ XRenderFreePicture(drw->dpy, drw->picture); + XFreePixmap(drw->dpy, drw->drawable); + XFreeGC(drw->dpy, drw->gc); + drw_fontset_free(drw->fonts); +@@ -236,6 +242,67 @@ drw_setscheme(Drw *drw, Clr *scm) + drw->scheme = scm; + } + ++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_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) + { +@@ -379,6 +446,14 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp + return x + (render ? w : 0); + } + ++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); ++} ++ + void + drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) + { +diff --git a/drw.h b/drw.h +index 4bcd5ad..71aefa2 100644 +--- a/drw.h ++++ b/drw.h +@@ -21,6 +21,7 @@ typedef struct { + int screen; + Window root; + Drawable drawable; ++ Picture picture; + GC gc; + Clr *scheme; + Fnt *fonts; +@@ -49,9 +50,12 @@ void drw_cur_free(Drw *drw, Cur *cursor); + void drw_setfontset(Drw *drw, Fnt *set); + void drw_setscheme(Drw *drw, Clr *scm); + ++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); ++ + /* Drawing functions */ + void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); + int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); ++void drw_pic(Drw *drw, int x, int y, unsigned int w, unsigned int h, Picture pic); + + /* Map functions */ + void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); +diff --git a/dwm.c b/dwm.c +index a96f33c..033ccec 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -28,6 +28,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -60,7 +62,7 @@ + /* enums */ + enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ + enum { SchemeNorm, SchemeSel }; /* color schemes */ +-enum { NetSupported, NetWMName, NetWMState, NetWMCheck, ++enum { NetSupported, NetWMName, NetWMIcon, NetWMState, NetWMCheck, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +@@ -93,6 +95,7 @@ struct Client { + int bw, oldbw; + unsigned int tags; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; ++ unsigned int icw, ich; Picture icon; + Client *next; + Client *snext; + Monitor *mon; +@@ -170,6 +173,7 @@ static void focusin(XEvent *e); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); + static Atom getatomprop(Client *c, Atom prop); ++static Picture geticonprop(Window w, unsigned int *icw, unsigned int *ich); + static int getrootptr(int *x, int *y); + static long getstate(Window w); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -214,6 +218,7 @@ static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); ++static void freeicon(Client *c); + static void unfocus(Client *c, int setfocus); + static void unmanage(Client *c, int destroyed); + static void unmapnotify(XEvent *e); +@@ -225,6 +230,7 @@ static void updatenumlockmask(void); + static void updatesizehints(Client *c); + static void updatestatus(void); + static void updatetitle(Client *c); ++static void updateicon(Client *c); + static void updatewindowtype(Client *c); + static void updatewmhints(Client *c); + static void view(const Arg *arg); +@@ -735,7 +741,8 @@ drawbar(Monitor *m) + if ((w = m->ww - tw - x) > bh) { + if (m->sel) { + drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); +- drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); ++ drw_text(drw, x, 0, w, bh, lrpad / 2 + (m->sel->icon ? m->sel->icw + ICONSPACING : 0), m->sel->name, 0); ++ if (m->sel->icon) drw_pic(drw, x + lrpad / 2, (bh - m->sel->ich) / 2, m->sel->icw, m->sel->ich, m->sel->icon); + if (m->sel->isfloating) + drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); + } else { +@@ -875,6 +882,67 @@ getatomprop(Client *c, Atom prop) + return atom; + } + ++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; ++} ++ + int + getrootptr(int *x, int *y) + { +@@ -1034,6 +1102,7 @@ manage(Window w, XWindowAttributes *wa) + c->h = c->oldh = wa->height; + c->oldbw = wa->border_width; + ++ updateicon(c); + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { + c->mon = t->mon; +@@ -1244,6 +1313,11 @@ propertynotify(XEvent *e) + if (c == c->mon->sel) + drawbar(c->mon); + } ++ else if (ev->atom == netatom[NetWMIcon]) { ++ updateicon(c); ++ if (c == c->mon->sel) ++ drawbar(c->mon); ++ } + if (ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); + } +@@ -1560,6 +1634,7 @@ 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); ++ netatom[NetWMIcon] = XInternAtom(dpy, "_NET_WM_ICON", False); + netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); + netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); + netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); +@@ -1752,6 +1827,15 @@ toggleview(const Arg *arg) + } + } + ++void ++freeicon(Client *c) ++{ ++ if (c->icon) { ++ XRenderFreePicture(dpy, c->icon); ++ c->icon = None; ++ } ++} ++ + void + unfocus(Client *c, int setfocus) + { +@@ -1773,6 +1857,7 @@ unmanage(Client *c, int destroyed) + + detach(c); + detachstack(c); ++ freeicon(c); + if (!destroyed) { + wc.border_width = c->oldbw; + XGrabServer(dpy); /* avoid race conditions */ +@@ -2007,6 +2092,13 @@ updatetitle(Client *c) + strcpy(c->name, broken); + } + ++void ++updateicon(Client *c) ++{ ++ freeicon(c); ++ c->icon = geticonprop(c->win, &c->icw, &c->ich); ++} ++ + void + updatewindowtype(Client *c) + { -- cgit v1.2.3