sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

dwm-tag-preview-6.3.diff (10565B)


      1 From 841ad7d5767f945ee9da6c5afc8cff98ca2f8231 Mon Sep 17 00:00:00 2001
      2 From: explosion-mental <explosion0mental@gmail.com>
      3 Date: Thu, 1 Sep 2022 16:21:58 -0500
      4 Subject: [PATCH] [PATCH] tag previews: free() tagmap and add previewtag func
      5 
      6 Allows you to see the contents of an already viewed tag. So a more
      7 accurate description would be to re-view a tag.
      8 
      9 Allows you to see the contents of an already viewed tag. So a more
     10 accurate description would be to re-view a tag.
     11 
     12 Compatibility with the alpha patch (replacing DefaultDepth() and
     13 DefaultVisual() with depth and visual + window masks) and hide vacants can be
     14 achieved, I left some lines to uncomment.
     15 
     16 added:
     17 * more compact structure, more probable to patch on top of other patches
     18   or easier to patch manually (like not moving the Monitor struct..)
     19 * create the window preview in updatebars()
     20 * renamed switchtag() -> takepreview(), makes more sense since it's
     21   "taking" the preview (basically a screenshot).
     22 * option previewbar, whether to show the bar in the preview or not.
     23 * previewtag which takes a tag (unsigned int from 0 to the last tag) and
     24   previews it. This allows to preview tags without using the
     25   cursor/mouse (which avoids a recursive previews preview).
     26   adding it to the TAGKEYS macro makes more sense so I've added it
     27   replacing (keybinding wise, not functionality) toggletag.
     28 ```
     29 \#define TAGKEYS(KEY,TAG) \
     30 	{ MODKEY,                       KEY,      view,           {.ui = 1 << TAG} }, \
     31 	{ MODKEY|ControlMask,           KEY,      toggleview,     {.ui = 1 << TAG} }, \
     32 	{ MODKEY|ShiftMask,             KEY,      tag,            {.ui = 1 << TAG} }, \
     33 ->	{ MODKEY|ControlMask|ShiftMask, KEY,      previewtag,     {.ui = TAG } },
     34 ```
     35 ---
     36  config.def.h |   4 +-
     37  config.mk    |   5 +-
     38  dwm.c        | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++-
     39  3 files changed, 145 insertions(+), 3 deletions(-)
     40 
     41 diff --git a/config.def.h b/config.def.h
     42 index a2ac963..eb70348 100644
     43 --- a/config.def.h
     44 +++ b/config.def.h
     45 @@ -3,6 +3,8 @@
     46  /* appearance */
     47  static const unsigned int borderpx  = 1;        /* border pixel of windows */
     48  static const unsigned int snap      = 32;       /* snap pixel */
     49 +static const int scalepreview       = 4;        /* preview scaling (display w and h / scalepreview) */
     50 +static const int previewbar         = 1;        /* show the bar in the preview window */
     51  static const int showbar            = 1;        /* 0 means no bar */
     52  static const int topbar             = 1;        /* 0 means bottom bar */
     53  static const char *fonts[]          = { "monospace:size=10" };
     54 @@ -50,7 +52,7 @@ static const Layout layouts[] = {
     55  	{ MODKEY,                       KEY,      view,           {.ui = 1 << TAG} }, \
     56  	{ MODKEY|ControlMask,           KEY,      toggleview,     {.ui = 1 << TAG} }, \
     57  	{ MODKEY|ShiftMask,             KEY,      tag,            {.ui = 1 << TAG} }, \
     58 -	{ MODKEY|ControlMask|ShiftMask, KEY,      toggletag,      {.ui = 1 << TAG} },
     59 +	{ MODKEY|ControlMask|ShiftMask, KEY,      previewtag,     {.ui = TAG } },     \
     60  
     61  /* helper for spawning shell commands in the pre dwm-5.0 fashion */
     62  #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
     63 diff --git a/config.mk b/config.mk
     64 index b6eb7e0..6f5129e 100644
     65 --- a/config.mk
     66 +++ b/config.mk
     67 @@ -20,9 +20,12 @@ FREETYPEINC = /usr/include/freetype2
     68  # OpenBSD (uncomment)
     69  #FREETYPEINC = ${X11INC}/freetype2
     70  
     71 +# Imlib2 (tag previews)
     72 +IMLIB2LIBS = -lImlib2
     73 +
     74  # includes and libs
     75  INCS = -I${X11INC} -I${FREETYPEINC}
     76 -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
     77 +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${IMLIB2LIBS}
     78  
     79  # flags
     80  CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
     81 diff --git a/dwm.c b/dwm.c
     82 index a96f33c..0c0ba12 100644
     83 --- a/dwm.c
     84 +++ b/dwm.c
     85 @@ -40,6 +40,7 @@
     86  #include <X11/extensions/Xinerama.h>
     87  #endif /* XINERAMA */
     88  #include <X11/Xft/Xft.h>
     89 +#include <Imlib2.h>
     90  
     91  #include "drw.h"
     92  #include "util.h"
     93 @@ -112,6 +113,9 @@ typedef struct {
     94  } Layout;
     95  
     96  struct Monitor {
     97 +	int previewshow;
     98 +	Window tagwin;
     99 +	Pixmap *tagmap;
    100  	char ltsymbol[16];
    101  	float mfact;
    102  	int nmaster;
    103 @@ -235,6 +239,10 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee);
    104  static int xerrorstart(Display *dpy, XErrorEvent *ee);
    105  static void zoom(const Arg *arg);
    106  
    107 +static void showtagpreview(unsigned int i);
    108 +static void takepreview(void);
    109 +static void previewtag(const Arg *arg);
    110 +
    111  /* variables */
    112  static const char broken[] = "broken";
    113  static char stext[256];
    114 @@ -438,6 +446,11 @@ buttonpress(XEvent *e)
    115  		if (i < LENGTH(tags)) {
    116  			click = ClkTagBar;
    117  			arg.ui = 1 << i;
    118 +			/* hide preview if we click the bar */
    119 +			if (selmon->previewshow) {
    120 +				selmon->previewshow = 0;
    121 +				XUnmapWindow(dpy, selmon->tagwin);
    122 +			}
    123  		} else if (ev->x < x + blw)
    124  			click = ClkLtSymbol;
    125  		else if (ev->x > selmon->ww - (int)TEXTW(stext))
    126 @@ -498,6 +511,7 @@ void
    127  cleanupmon(Monitor *mon)
    128  {
    129  	Monitor *m;
    130 +	size_t i;
    131  
    132  	if (mon == mons)
    133  		mons = mons->next;
    134 @@ -505,8 +519,14 @@ cleanupmon(Monitor *mon)
    135  		for (m = mons; m && m->next != mon; m = m->next);
    136  		m->next = mon->next;
    137  	}
    138 +	for (i = 0; i < LENGTH(tags); i++)
    139 +		if (mon->tagmap[i])
    140 +			XFreePixmap(dpy, mon->tagmap[i]);
    141 +	free(mon->tagmap);
    142  	XUnmapWindow(dpy, mon->barwin);
    143  	XDestroyWindow(dpy, mon->barwin);
    144 +	XUnmapWindow(dpy, mon->tagwin);
    145 +	XDestroyWindow(dpy, mon->tagwin);
    146  	free(mon);
    147  }
    148  
    149 @@ -641,6 +661,7 @@ createmon(void)
    150  	m->topbar = topbar;
    151  	m->lt[0] = &layouts[0];
    152  	m->lt[1] = &layouts[1 % LENGTH(layouts)];
    153 +	m->tagmap = ecalloc(LENGTH(tags), sizeof(Pixmap));
    154  	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
    155  	return m;
    156  }
    157 @@ -1125,6 +1146,36 @@ motionnotify(XEvent *e)
    158  	static Monitor *mon = NULL;
    159  	Monitor *m;
    160  	XMotionEvent *ev = &e->xmotion;
    161 +	unsigned int i, x;
    162 +
    163 +	if (ev->window == selmon->barwin) {
    164 +		i = x = 0;
    165 +		do
    166 +			x += TEXTW(tags[i]);
    167 +		while (ev->x >= x && ++i < LENGTH(tags));
    168 +	/* FIXME when hovering the mouse over the tags and we view the tag,
    169 +	 *       the preview window get's in the preview shot */
    170 +
    171 +	     	if (i < LENGTH(tags)) {
    172 +			if (selmon->previewshow != (i + 1)
    173 +			&& !(selmon->tagset[selmon->seltags] & 1 << i)) {
    174 +				selmon->previewshow = i + 1;
    175 +				showtagpreview(i);
    176 +			} else if (selmon->tagset[selmon->seltags] & 1 << i) {
    177 +				selmon->previewshow = 0;
    178 +				XUnmapWindow(dpy, selmon->tagwin);
    179 +			}
    180 +		} else if (selmon->previewshow) {
    181 +			selmon->previewshow = 0;
    182 +			XUnmapWindow(dpy, selmon->tagwin);
    183 +		}
    184 +	} else if (ev->window == selmon->tagwin) {
    185 +		selmon->previewshow = 0;
    186 +		XUnmapWindow(dpy, selmon->tagwin);
    187 +	} else if (selmon->previewshow) {
    188 +		selmon->previewshow = 0;
    189 +		XUnmapWindow(dpy, selmon->tagwin);
    190 +	}
    191  
    192  	if (ev->window != root)
    193  		return;
    194 @@ -1530,6 +1581,82 @@ setmfact(const Arg *arg)
    195  	arrange(selmon);
    196  }
    197  
    198 +void
    199 +showtagpreview(unsigned int i)
    200 +{
    201 +	if (!selmon->previewshow || !selmon->tagmap[i]) {
    202 +		XUnmapWindow(dpy, selmon->tagwin);
    203 +		return;
    204 +	}
    205 +
    206 +	XSetWindowBackgroundPixmap(dpy, selmon->tagwin, selmon->tagmap[i]);
    207 +	XCopyArea(dpy, selmon->tagmap[i], selmon->tagwin, drw->gc, 0, 0,
    208 +			selmon->mw / scalepreview, selmon->mh / scalepreview,
    209 +			0, 0);
    210 +	XSync(dpy, False);
    211 +	XMapRaised(dpy, selmon->tagwin);
    212 +}
    213 +
    214 +void
    215 +takepreview(void)
    216 +{
    217 +	Client *c;
    218 +	Imlib_Image image;
    219 +	unsigned int occ = 0, i;
    220 +
    221 +	for (c = selmon->clients; c; c = c->next)
    222 +		occ |= c->tags;
    223 +		//occ |= c->tags == 255 ? 0 : c->tags; /* hide vacants */
    224 +
    225 +	for (i = 0; i < LENGTH(tags); i++) {
    226 +		/* searching for tags that are occupied && selected */
    227 +		if (!(occ & 1 << i) || !(selmon->tagset[selmon->seltags] & 1 << i))
    228 +			continue;
    229 +
    230 +		if (selmon->tagmap[i]) { /* tagmap exist, clean it */
    231 +			XFreePixmap(dpy, selmon->tagmap[i]);
    232 +			selmon->tagmap[i] = 0;
    233 +		}
    234 +
    235 +		/* try to unmap the window so it doesn't show the preview on the preview */
    236 +		selmon->previewshow = 0;
    237 +		XUnmapWindow(dpy, selmon->tagwin);
    238 +		XSync(dpy, False);
    239 +
    240 +		if (!(image = imlib_create_image(sw, sh))) {
    241 +			fprintf(stderr, "dwm: imlib: failed to create image, skipping.");
    242 +			continue;
    243 +		}
    244 +		imlib_context_set_image(image);
    245 +		imlib_context_set_display(dpy);
    246 +		/* uncomment if using alpha patch */
    247 +		//imlib_image_set_has_alpha(1);
    248 +		//imlib_context_set_blend(0);
    249 +		//imlib_context_set_visual(visual);
    250 +		imlib_context_set_visual(DefaultVisual(dpy, screen));
    251 +		imlib_context_set_drawable(root);
    252 +
    253 +		if (previewbar)
    254 +			imlib_copy_drawable_to_image(0, selmon->wx, selmon->wy, selmon->ww, selmon->wh, 0, 0, 1);
    255 +		else
    256 +			imlib_copy_drawable_to_image(0, selmon->mx, selmon->my, selmon->mw ,selmon->mh, 0, 0, 1);
    257 +		selmon->tagmap[i] = XCreatePixmap(dpy, selmon->tagwin, selmon->mw / scalepreview, selmon->mh / scalepreview, DefaultDepth(dpy, screen));
    258 +		imlib_context_set_drawable(selmon->tagmap[i]);
    259 +		imlib_render_image_part_on_drawable_at_size(0, 0, selmon->mw, selmon->mh, 0, 0, selmon->mw / scalepreview, selmon->mh / scalepreview);
    260 +		imlib_free_image();
    261 +	}
    262 +}
    263 +
    264 +void
    265 +previewtag(const Arg *arg)
    266 +{
    267 +	if (selmon->previewshow != (arg->ui + 1))
    268 +		selmon->previewshow = arg->ui + 1;
    269 +	else
    270 +		selmon->previewshow = 0;
    271 +	showtagpreview(arg->ui);
    272 +}
    273 +
    274  void
    275  setup(void)
    276  {
    277 @@ -1746,6 +1873,7 @@ toggleview(const Arg *arg)
    278  	unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
    279  
    280  	if (newtagset) {
    281 +		takepreview();
    282  		selmon->tagset[selmon->seltags] = newtagset;
    283  		focus(NULL);
    284  		arrange(selmon);
    285 @@ -1811,10 +1939,18 @@ updatebars(void)
    286  	XSetWindowAttributes wa = {
    287  		.override_redirect = True,
    288  		.background_pixmap = ParentRelative,
    289 -		.event_mask = ButtonPressMask|ExposureMask
    290 +		.event_mask = ButtonPressMask|ExposureMask|PointerMotionMask
    291  	};
    292 +
    293  	XClassHint ch = {"dwm", "dwm"};
    294  	for (m = mons; m; m = m->next) {
    295 +		if (!m->tagwin) {
    296 +			m->tagwin = XCreateWindow(dpy, root, m->wx, m->by + bh, m->mw / scalepreview,
    297 +				m->mh / scalepreview, 0, DefaultDepth(dpy, screen), CopyFromParent,
    298 +				DefaultVisual(dpy, screen), CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
    299 +			XDefineCursor(dpy, m->tagwin, cursor[CurNormal]->cursor);
    300 +			XUnmapWindow(dpy, m->tagwin);
    301 +		}
    302  		if (m->barwin)
    303  			continue;
    304  		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
    305 @@ -2043,6 +2179,7 @@ view(const Arg *arg)
    306  {
    307  	if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
    308  		return;
    309 +	takepreview();
    310  	selmon->seltags ^= 1; /* toggle sel tagset */
    311  	if (arg->ui & TAGMASK)
    312  		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
    313 -- 
    314 2.37.3
    315