sites

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

dwm-awesomebarwithhover-20230431-6.4.diff (15829B)


      1 diff --git a/config.def.h b/config.def.h
      2 index 061ad66..82a3ed2 100644
      3 --- a/config.def.h
      4 +++ b/config.def.h
      5 @@ -16,6 +16,8 @@ static const char *colors[][3]      = {
      6  	/*               fg         bg         border   */
      7  	[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
      8  	[SchemeSel]  = { col_gray4, col_cyan,  col_cyan  },
      9 +	[SchemeHov]  = { col_gray4, col_cyan,  col_cyan  },
     10 +	[SchemeHid]  = { col_cyan,  col_gray1, col_cyan  },
     11  };
     12  
     13  /* tagging */
     14 @@ -64,8 +66,10 @@ static const Key keys[] = {
     15  	{ MODKEY,                       XK_p,      spawn,          {.v = dmenucmd } },
     16  	{ MODKEY|ShiftMask,             XK_Return, spawn,          {.v = termcmd } },
     17  	{ MODKEY,                       XK_b,      togglebar,      {0} },
     18 -	{ MODKEY,                       XK_j,      focusstack,     {.i = +1 } },
     19 -	{ MODKEY,                       XK_k,      focusstack,     {.i = -1 } },
     20 +	{ MODKEY,                       XK_j,      focusstackvis,  {.i = +1 } },
     21 +	{ MODKEY,                       XK_k,      focusstackvis,  {.i = -1 } },
     22 +	{ MODKEY|ShiftMask,             XK_j,      focusstackhid,  {.i = +1 } },
     23 +	{ MODKEY|ShiftMask,             XK_k,      focusstackhid,  {.i = -1 } },
     24  	{ MODKEY,                       XK_i,      incnmaster,     {.i = +1 } },
     25  	{ MODKEY,                       XK_d,      incnmaster,     {.i = -1 } },
     26  	{ MODKEY,                       XK_h,      setmfact,       {.f = -0.05} },
     27 @@ -84,6 +88,9 @@ static const Key keys[] = {
     28  	{ MODKEY,                       XK_period, focusmon,       {.i = +1 } },
     29  	{ MODKEY|ShiftMask,             XK_comma,  tagmon,         {.i = -1 } },
     30  	{ MODKEY|ShiftMask,             XK_period, tagmon,         {.i = +1 } },
     31 +	{ MODKEY,                       XK_s,      show,           {0} },
     32 +	{ MODKEY|ShiftMask,             XK_s,      showall,        {0} },
     33 +	{ MODKEY,                       XK_h,      hide,           {0} },
     34  	TAGKEYS(                        XK_1,                      0)
     35  	TAGKEYS(                        XK_2,                      1)
     36  	TAGKEYS(                        XK_3,                      2)
     37 @@ -102,6 +109,7 @@ static const Button buttons[] = {
     38  	/* click                event mask      button          function        argument */
     39  	{ ClkLtSymbol,          0,              Button1,        setlayout,      {0} },
     40  	{ ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} },
     41 +	{ ClkWinTitle,          0,              Button1,        togglewin,      {0} },
     42  	{ ClkWinTitle,          0,              Button2,        zoom,           {0} },
     43  	{ ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } },
     44  	{ ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} },
     45 diff --git a/dwm.c b/dwm.c
     46 index e5efb6a..8cb5171 100644
     47 --- a/dwm.c
     48 +++ b/dwm.c
     49 @@ -50,6 +50,7 @@
     50  #define INTERSECT(x,y,w,h,m)    (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
     51                                 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
     52  #define ISVISIBLE(C)            ((C->tags & C->mon->tagset[C->mon->seltags]))
     53 +#define HIDDEN(C)               ((getstate(C->win) == IconicState))
     54  #define LENGTH(X)               (sizeof X / sizeof X[0])
     55  #define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
     56  #define WIDTH(X)                ((X)->w + 2 * (X)->bw)
     57 @@ -59,7 +60,7 @@
     58  
     59  /* enums */
     60  enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
     61 -enum { SchemeNorm, SchemeSel }; /* color schemes */
     62 +enum { SchemeNorm, SchemeSel, SchemeHov, SchemeHid }; /* color schemes */
     63  enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
     64         NetWMFullscreen, NetActiveWindow, NetWMWindowType,
     65         NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
     66 @@ -117,6 +118,8 @@ struct Monitor {
     67  	int nmaster;
     68  	int num;
     69  	int by;               /* bar geometry */
     70 +	int btw;              /* width of tasks portion of bar */
     71 +	int bt;               /* number of tasks */
     72  	int mx, my, mw, mh;   /* screen size */
     73  	int wx, wy, ww, wh;   /* window area  */
     74  	unsigned int seltags;
     75 @@ -124,8 +127,10 @@ struct Monitor {
     76  	unsigned int tagset[2];
     77  	int showbar;
     78  	int topbar;
     79 +	int hidsel;
     80  	Client *clients;
     81  	Client *sel;
     82 +	Client *hov;
     83  	Client *stack;
     84  	Monitor *next;
     85  	Window barwin;
     86 @@ -168,13 +173,17 @@ static void expose(XEvent *e);
     87  static void focus(Client *c);
     88  static void focusin(XEvent *e);
     89  static void focusmon(const Arg *arg);
     90 -static void focusstack(const Arg *arg);
     91 +static void focusstackvis(const Arg *arg);
     92 +static void focusstackhid(const Arg *arg);
     93 +static void focusstack(int inc, int vis);
     94  static Atom getatomprop(Client *c, Atom prop);
     95  static int getrootptr(int *x, int *y);
     96  static long getstate(Window w);
     97  static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
     98  static void grabbuttons(Client *c, int focused);
     99  static void grabkeys(void);
    100 +static void hide(const Arg *arg);
    101 +static void hidewin(Client *c);
    102  static void incnmaster(const Arg *arg);
    103  static void keypress(XEvent *e);
    104  static void killclient(const Arg *arg);
    105 @@ -204,6 +213,9 @@ static void setlayout(const Arg *arg);
    106  static void setmfact(const Arg *arg);
    107  static void setup(void);
    108  static void seturgent(Client *c, int urg);
    109 +static void show(const Arg *arg);
    110 +static void showall(const Arg *arg);
    111 +static void showwin(Client *c);
    112  static void showhide(Client *c);
    113  static void sigchld(int unused);
    114  static void spawn(const Arg *arg);
    115 @@ -214,6 +226,7 @@ static void togglebar(const Arg *arg);
    116  static void togglefloating(const Arg *arg);
    117  static void toggletag(const Arg *arg);
    118  static void toggleview(const Arg *arg);
    119 +static void togglewin(const Arg *arg);
    120  static void unfocus(Client *c, int setfocus);
    121  static void unmanage(Client *c, int destroyed);
    122  static void unmapnotify(XEvent *e);
    123 @@ -442,10 +455,25 @@ buttonpress(XEvent *e)
    124  			arg.ui = 1 << i;
    125  		} else if (ev->x < x + TEXTW(selmon->ltsymbol))
    126  			click = ClkLtSymbol;
    127 -		else if (ev->x > selmon->ww - (int)TEXTW(stext))
    128 +		/* 2px right padding */
    129 +		else if (ev->x > selmon->ww - TEXTW(stext) + lrpad - 2)
    130  			click = ClkStatusText;
    131 -		else
    132 -			click = ClkWinTitle;
    133 +		else {
    134 +			x += TEXTW(selmon->ltsymbol);
    135 +			c = m->clients;
    136 +
    137 +			if (c) {
    138 +				do {
    139 +					if (!ISVISIBLE(c))
    140 +						continue;
    141 +					else
    142 +						x +=(1.0 / (double)m->bt) * m->btw;
    143 +				} while (ev->x > x && (c = c->next));
    144 +
    145 +				click = ClkWinTitle;
    146 +				arg.v = c;
    147 +			}
    148 +		}
    149  	} else if ((c = wintoclient(ev->window))) {
    150  		focus(c);
    151  		restack(selmon);
    152 @@ -455,7 +483,7 @@ buttonpress(XEvent *e)
    153  	for (i = 0; i < LENGTH(buttons); i++)
    154  		if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
    155  		&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
    156 -			buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
    157 +			buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
    158  }
    159  
    160  void
    161 @@ -699,7 +727,7 @@ dirtomon(int dir)
    162  void
    163  drawbar(Monitor *m)
    164  {
    165 -	int x, w, tw = 0;
    166 +	int x, w, tw = 0, n = 0, scm;
    167  	int boxs = drw->fonts->h / 9;
    168  	int boxw = drw->fonts->h / 6 + 2;
    169  	unsigned int i, occ = 0, urg = 0;
    170 @@ -716,6 +744,8 @@ drawbar(Monitor *m)
    171  	}
    172  
    173  	for (c = m->clients; c; c = c->next) {
    174 +		if (ISVISIBLE(c))
    175 +			n++;
    176  		occ |= c->tags;
    177  		if (c->isurgent)
    178  			urg |= c->tags;
    179 @@ -736,16 +766,38 @@ drawbar(Monitor *m)
    180  	x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
    181  
    182  	if ((w = m->ww - tw - x) > bh) {
    183 -		if (m->sel) {
    184 -			drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
    185 -			drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
    186 -			if (m->sel->isfloating)
    187 -				drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
    188 +		if (n > 0) {
    189 +			int remainder = w % n;
    190 +			int tabw = (1.0 / (double)n) * w + 1;
    191 +			for (c = m->clients; c; c = c->next) {
    192 +				if (!ISVISIBLE(c))
    193 +					continue;
    194 +				if (m->hov == c)
    195 +					scm = SchemeHov;
    196 +				else if (m->sel == c)
    197 +					scm = SchemeSel;
    198 +				else if (HIDDEN(c))
    199 +					scm = SchemeHid;
    200 +				else
    201 +					scm = SchemeNorm;
    202 +				drw_setscheme(drw, scheme[scm]);
    203 +
    204 +				if (remainder >= 0) {
    205 +					if (remainder == 0) {
    206 +						tabw--;
    207 +					}
    208 +					remainder--;
    209 +				}
    210 +				drw_text(drw, x, 0, tabw, bh, lrpad / 2, c->name, 0);
    211 +				x += tabw;
    212 +			}
    213  		} else {
    214  			drw_setscheme(drw, scheme[SchemeNorm]);
    215  			drw_rect(drw, x, 0, w, bh, 1, 1);
    216  		}
    217  	}
    218 +	m->bt = n;
    219 +	m->btw = w;
    220  	drw_map(drw, m->barwin, 0, 0, m->ww, bh);
    221  }
    222  
    223 @@ -791,9 +843,17 @@ void
    224  focus(Client *c)
    225  {
    226  	if (!c || !ISVISIBLE(c))
    227 -		for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
    228 -	if (selmon->sel && selmon->sel != c)
    229 +		for (c = selmon->stack; c && (!ISVISIBLE(c) || HIDDEN(c)); c = c->snext);
    230 +	if (selmon->sel && selmon->sel != c) {
    231  		unfocus(selmon->sel, 0);
    232 +
    233 +		if (selmon->hidsel) {
    234 +			hidewin(selmon->sel);
    235 +			if (c)
    236 +				arrange(c->mon);
    237 +			selmon->hidsel = 0;
    238 +		}
    239 +	}
    240  	if (c) {
    241  		if (c->mon != selmon)
    242  			selmon = c->mon;
    243 @@ -837,28 +897,52 @@ focusmon(const Arg *arg)
    244  }
    245  
    246  void
    247 -focusstack(const Arg *arg)
    248 +focusstackvis(const Arg *arg) {
    249 +	focusstack(arg->i, 0);
    250 +}
    251 +
    252 +void
    253 +focusstackhid(const Arg *arg) {
    254 +	focusstack(arg->i, 1);
    255 +}
    256 +
    257 +void
    258 +focusstack(int inc, int hid)
    259  {
    260  	Client *c = NULL, *i;
    261 -
    262 -	if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
    263 +	// if no client selected AND exclude hidden client; if client selected but fullscreened
    264 +	if ((!selmon->sel && !hid) || (selmon->sel && selmon->sel->isfullscreen && lockfullscreen))
    265 +		return;
    266 +	if (!selmon->clients)
    267  		return;
    268 -	if (arg->i > 0) {
    269 -		for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
    270 +	if (inc > 0) {
    271 +		if (selmon->sel)
    272 +			for (c = selmon->sel->next;
    273 +					c && (!ISVISIBLE(c) || (!hid && HIDDEN(c)));
    274 +					c = c->next);
    275  		if (!c)
    276 -			for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
    277 +			for (c = selmon->clients;
    278 +					c && (!ISVISIBLE(c) || (!hid && HIDDEN(c)));
    279 +					c = c->next);
    280  	} else {
    281 -		for (i = selmon->clients; i != selmon->sel; i = i->next)
    282 -			if (ISVISIBLE(i))
    283 -				c = i;
    284 +		if (selmon->sel) {
    285 +			for (i = selmon->clients; i != selmon->sel; i = i->next)
    286 +				if (ISVISIBLE(i) && !(!hid && HIDDEN(i)))
    287 +					c = i;
    288 +		} else
    289 +			c = selmon->clients;
    290  		if (!c)
    291  			for (; i; i = i->next)
    292 -				if (ISVISIBLE(i))
    293 +				if (ISVISIBLE(i) && !(!hid && HIDDEN(i)))
    294  					c = i;
    295  	}
    296  	if (c) {
    297  		focus(c);
    298  		restack(selmon);
    299 +		if (HIDDEN(c)) {
    300 +			showwin(c);
    301 +			c->mon->hidsel = 1;
    302 +		}
    303  	}
    304  }
    305  
    306 @@ -968,6 +1052,36 @@ grabkeys(void)
    307  	}
    308  }
    309  
    310 +void
    311 +hide(const Arg *arg)
    312 +{
    313 +	hidewin(selmon->sel);
    314 +	focus(NULL);
    315 +	arrange(selmon);
    316 +}
    317 +
    318 +void
    319 +hidewin(Client *c) {
    320 +	if (!c || HIDDEN(c))
    321 +		return;
    322 +
    323 +	Window w = c->win;
    324 +	static XWindowAttributes ra, ca;
    325 +
    326 +	// more or less taken directly from blackbox's hide() function
    327 +	XGrabServer(dpy);
    328 +	XGetWindowAttributes(dpy, root, &ra);
    329 +	XGetWindowAttributes(dpy, w, &ca);
    330 +	// prevent UnmapNotify events
    331 +	XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask);
    332 +	XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask);
    333 +	XUnmapWindow(dpy, w);
    334 +	setclientstate(c, IconicState);
    335 +	XSelectInput(dpy, root, ra.your_event_mask);
    336 +	XSelectInput(dpy, w, ca.your_event_mask);
    337 +	XUngrabServer(dpy);
    338 +}
    339 +
    340  void
    341  incnmaster(const Arg *arg)
    342  {
    343 @@ -1070,12 +1184,14 @@ manage(Window w, XWindowAttributes *wa)
    344  	XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
    345  		(unsigned char *) &(c->win), 1);
    346  	XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
    347 -	setclientstate(c, NormalState);
    348 +	if (!HIDDEN(c))
    349 +		setclientstate(c, NormalState);
    350  	if (c->mon == selmon)
    351  		unfocus(selmon->sel, 0);
    352  	c->mon->sel = c;
    353  	arrange(c->mon);
    354 -	XMapWindow(dpy, c->win);
    355 +	if (!HIDDEN(c))
    356 +		XMapWindow(dpy, c->win);
    357  	focus(NULL);
    358  }
    359  
    360 @@ -1119,18 +1235,76 @@ monocle(Monitor *m)
    361  void
    362  motionnotify(XEvent *e)
    363  {
    364 +	int x, i;
    365  	static Monitor *mon = NULL;
    366 +	Client *c;
    367  	Monitor *m;
    368  	XMotionEvent *ev = &e->xmotion;
    369  
    370 -	if (ev->window != root)
    371 +	if (ev->window != selmon->barwin) {
    372 +		if (selmon->hov) {
    373 +			if (selmon->hov != selmon->sel)
    374 +				XSetWindowBorder(dpy, selmon->hov->win, scheme[SchemeNorm][ColBorder].pixel);
    375 +			else
    376 +				XSetWindowBorder(dpy, selmon->hov->win, scheme[SchemeSel][ColBorder].pixel);
    377 +			
    378 +			selmon->hov = NULL;
    379 +			c = wintoclient(ev->window);
    380 +			m = c ? c->mon : wintomon(ev->window);
    381 +			drawbar(m);
    382 +		}
    383 +
    384 +		if (ev->window == root) {
    385 +			if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
    386 +				unfocus(selmon->sel, 1);
    387 +				selmon = m;
    388 +				focus(NULL);
    389 +			}
    390 +			mon = m;
    391 +		}
    392 +	
    393  		return;
    394 -	if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
    395 -		unfocus(selmon->sel, 1);
    396 -		selmon = m;
    397 -		focus(NULL);
    398  	}
    399 -	mon = m;
    400 +
    401 +	c = wintoclient(ev->window);
    402 +	m = c ? c->mon : wintomon(ev->window);
    403 +	c = m->clients;
    404 +
    405 +	x = 0, i = 0;
    406 +	do
    407 +		x += TEXTW(tags[i]);
    408 +	while (ev->x >= x && ++i < LENGTH(tags));
    409 +	if (i < LENGTH(tags) || ev->x < x + TEXTW(selmon->ltsymbol) || ev->x > selmon->ww - TEXTW(stext) + lrpad - 2) {
    410 +		if (selmon->hov) {
    411 +			if (selmon->hov != selmon->sel)
    412 +				XSetWindowBorder(dpy, selmon->hov->win, scheme[SchemeNorm][ColBorder].pixel);
    413 +			else
    414 +				XSetWindowBorder(dpy, selmon->hov->win, scheme[SchemeSel][ColBorder].pixel);
    415 +			selmon->hov = NULL;
    416 +			drawbar(m);
    417 +		}
    418 +	} else {
    419 +		x += TEXTW(selmon->ltsymbol);
    420 +		if (c) {
    421 +			do {
    422 +				if (!ISVISIBLE(c))
    423 +					continue;
    424 +				else
    425 +					x +=(1.0 / (double)m->bt) * m->btw;
    426 +			} while (ev->x > x && (c = c->next));
    427 +			if (c) {
    428 +				if (selmon->hov) {
    429 +					if (selmon->hov != selmon->sel)
    430 +						XSetWindowBorder(dpy, selmon->hov->win, scheme[SchemeNorm][ColBorder].pixel);
    431 +					else
    432 +						XSetWindowBorder(dpy, selmon->hov->win, scheme[SchemeSel][ColBorder].pixel);
    433 +				}
    434 +				selmon->hov = c;
    435 +				XSetWindowBorder(dpy, c->win, scheme[SchemeHov][ColBorder].pixel);
    436 +			}
    437 +		}
    438 +		drawbar(m);
    439 +	}
    440  }
    441  
    442  void
    443 @@ -1196,7 +1370,7 @@ movemouse(const Arg *arg)
    444  Client *
    445  nexttiled(Client *c)
    446  {
    447 -	for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
    448 +	for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next);
    449  	return c;
    450  }
    451  
    452 @@ -1249,6 +1423,16 @@ propertynotify(XEvent *e)
    453  void
    454  quit(const Arg *arg)
    455  {
    456 +	// fix: reloading dwm keeps all the hidden clients hidden
    457 +	Monitor *m;
    458 +	Client *c;
    459 +	for (m = mons; m; m = m->next) {
    460 +		if (m) {
    461 +			for (c = m->stack; c; c = c->next)
    462 +				if (c && HIDDEN(c)) showwin(c);
    463 +		}
    464 +	}
    465 +
    466  	running = 0;
    467  }
    468  
    469 @@ -1610,6 +1794,42 @@ seturgent(Client *c, int urg)
    470  	XFree(wmh);
    471  }
    472  
    473 +void
    474 +show(const Arg *arg)
    475 +{
    476 +	if (selmon->hidsel)
    477 +		selmon->hidsel = 0;
    478 +	showwin(selmon->sel);
    479 +}
    480 +
    481 +void
    482 +showall(const Arg *arg)
    483 +{
    484 +	Client *c = NULL;
    485 +	selmon->hidsel = 0;
    486 +	for (c = selmon->clients; c; c = c->next) {
    487 +		if (ISVISIBLE(c))
    488 +			showwin(c);
    489 +	}
    490 +	if (!selmon->sel) {
    491 +		for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
    492 +		if (c)
    493 +			focus(c);
    494 +	}
    495 +	restack(selmon);
    496 +}
    497 +
    498 +void
    499 +showwin(Client *c)
    500 +{
    501 +	if (!c || !HIDDEN(c))
    502 +		return;
    503 +
    504 +	XMapWindow(dpy, c->win);
    505 +	setclientstate(c, NormalState);
    506 +	arrange(c->mon);
    507 +}
    508 +
    509  void
    510  showhide(Client *c)
    511  {
    512 @@ -1744,6 +1964,23 @@ toggleview(const Arg *arg)
    513  	}
    514  }
    515  
    516 +void
    517 +togglewin(const Arg *arg)
    518 +{
    519 +	Client *c = (Client*)arg->v;
    520 +
    521 +	if (c == selmon->sel) {
    522 +		hidewin(c);
    523 +		focus(NULL);
    524 +		arrange(c->mon);
    525 +	} else {
    526 +		if (HIDDEN(c))
    527 +			showwin(c);
    528 +		focus(c);
    529 +		restack(selmon);
    530 +	}
    531 +}
    532 +
    533  void
    534  unfocus(Client *c, int setfocus)
    535  {
    536 @@ -1815,6 +2052,7 @@ updatebars(void)
    537  				CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
    538  		XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
    539  		XMapRaised(dpy, m->barwin);
    540 +		XSelectInput(dpy, m->barwin, ButtonPressMask|PointerMotionMask);
    541  		XSetClassHint(dpy, m->barwin, &ch);
    542  	}
    543  }