sites

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

dwm-6.2-tab-v2b.diff (15540B)


      1 diff -up dwm-6.2.1/config.def.h dwm-6.2/config.def.h
      2 --- dwm-6.2.1/config.def.h	2019-02-02 04:55:28.000000000 -0800
      3 +++ dwm-6.2/config.def.h	2019-07-12 11:40:50.530164308 -0700
      4 @@ -5,6 +5,13 @@ static const unsigned int borderpx  = 1;
      5  static const unsigned int snap      = 32;       /* snap pixel */
      6  static const int showbar            = 1;        /* 0 means no bar */
      7  static const int topbar             = 1;        /* 0 means bottom bar */
      8 +/*  Display modes of the tab bar: never shown, always shown, shown only in  */
      9 +/*  monocle mode in the presence of several windows.                        */
     10 +/*  Modes after showtab_nmodes are disabled.                                */
     11 +enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always};
     12 +static const int showtab			= showtab_auto;        /* Default tab bar show mode */
     13 +static const int toptab				= False;               /* False means bottom tab bar */
     14 +
     15  static const char *fonts[]          = { "monospace:size=10" };
     16  static const char dmenufont[]       = "monospace:size=10";
     17  static const char col_gray1[]       = "#222222";
     18 @@ -64,6 +71,7 @@ static Key keys[] = {
     19  	{ MODKEY,                       XK_p,      spawn,          {.v = dmenucmd } },
     20  	{ MODKEY|ShiftMask,             XK_Return, spawn,          {.v = termcmd } },
     21  	{ MODKEY,                       XK_b,      togglebar,      {0} },
     22 +	{ MODKEY,                       XK_w,      tabmode,        {-1} },
     23  	{ MODKEY,                       XK_j,      focusstack,     {.i = +1 } },
     24  	{ MODKEY,                       XK_k,      focusstack,     {.i = -1 } },
     25  	{ MODKEY,                       XK_i,      incnmaster,     {.i = +1 } },
     26 @@ -111,5 +119,6 @@ static Button buttons[] = {
     27  	{ ClkTagBar,            0,              Button3,        toggleview,     {0} },
     28  	{ ClkTagBar,            MODKEY,         Button1,        tag,            {0} },
     29  	{ ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} },
     30 +	{ ClkTabBar,            0,              Button1,        focuswin,       {0} },
     31  };
     32  
     33 diff -up dwm-6.2.1/dwm.1 dwm-6.2/dwm.1
     34 --- dwm-6.2.1/dwm.1	2019-02-02 04:55:28.000000000 -0800
     35 +++ dwm-6.2/dwm.1	2019-07-12 11:36:25.453487700 -0700
     36 @@ -20,14 +20,22 @@ layout applied.
     37  Windows are grouped by tags. Each window can be tagged with one or multiple
     38  tags. Selecting certain tags displays all windows with these tags.
     39  .P
     40 -Each screen contains a small status bar which displays all available tags, the
     41 -layout, the title of the focused window, and the text read from the root window
     42 -name property, if the screen is focused. A floating window is indicated with an
     43 -empty square and a maximised floating window is indicated with a filled square
     44 -before the windows title.  The selected tags are indicated with a different
     45 -color. The tags of the focused window are indicated with a filled square in the
     46 -top left corner.  The tags which are applied to one or more windows are
     47 -indicated with an empty square in the top left corner.
     48 +Each screen contains two small status bars.
     49 +.P
     50 +One bar displays all available tags, the layout, the title of the focused
     51 +window, and the text read from the root window name property, if the screen is
     52 +focused. A floating window is indicated with an empty square and a maximised
     53 +floating window is indicated with a filled square before the windows title.  The
     54 +selected tags are indicated with a different color. The tags of the focused
     55 +window are indicated with a filled square in the top left corner.  The tags
     56 +which are applied to one or more windows are indicated with an empty square in
     57 +the top left corner.
     58 +.P
     59 +Another bar contains a tab for each window of the current view and allows
     60 +navigation between windows, especially in the monocle mode. The different
     61 +display modes of this bar are described under the Mod1\-w Keybord command
     62 +section.  When a single tag is selected, this tag is indicated in the left corner
     63 +of the tab bar.
     64  .P
     65  dwm draws a small border around windows to indicate the focus state.
     66  .SH OPTIONS
     67 @@ -44,7 +52,8 @@ command.
     68  .TP
     69  .B Button1
     70  click on a tag label to display all windows with that tag, click on the layout
     71 -label toggles between tiled and floating layout.
     72 +label toggles between tiled and floating layout, click on a window name in the
     73 +tab bar brings focus to that window.
     74  .TP
     75  .B Button3
     76  click on a tag label adds/removes all windows with that tag to/from the view.
     77 @@ -110,6 +119,12 @@ Increase master area size.
     78  .B Mod1\-h
     79  Decrease master area size.
     80  .TP
     81 +.B Mod1\-w
     82 +Cycle over the tab bar display modes: never displayed, always displayed,
     83 +displayed only in monocle mode when the view contains more than one window (auto
     84 +mode). Some display modes can be disabled in the configuration, config.h. In
     85 +the default configuration only "never" and "auto" display modes are enabled.
     86 +.TP
     87  .B Mod1\-Return
     88  Zooms/cycles focused window to/from master area (tiled layouts only).
     89  .TP
     90 diff -up dwm-6.2.1/dwm.c dwm-6.2/dwm.c
     91 --- dwm-6.2.1/dwm.c	2019-02-02 04:55:28.000000000 -0800
     92 +++ dwm-6.2/dwm.c	2019-07-12 11:47:37.726846244 -0700
     93 @@ -64,7 +64,7 @@ enum { NetSupported, NetWMName, NetWMSta
     94         NetWMFullscreen, NetActiveWindow, NetWMWindowType,
     95         NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
     96  enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
     97 -enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
     98 +enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
     99         ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
    100  
    101  typedef union {
    102 @@ -111,24 +111,32 @@ typedef struct {
    103  	void (*arrange)(Monitor *);
    104  } Layout;
    105  
    106 +#define MAXTABS 50
    107 +
    108  struct Monitor {
    109  	char ltsymbol[16];
    110  	float mfact;
    111  	int nmaster;
    112  	int num;
    113  	int by;               /* bar geometry */
    114 +	int ty;               /* tab bar geometry */
    115  	int mx, my, mw, mh;   /* screen size */
    116  	int wx, wy, ww, wh;   /* window area  */
    117  	unsigned int seltags;
    118  	unsigned int sellt;
    119  	unsigned int tagset[2];
    120  	int showbar;
    121 +	int showtab;
    122  	int topbar;
    123 +	int toptab;
    124  	Client *clients;
    125  	Client *sel;
    126  	Client *stack;
    127  	Monitor *next;
    128  	Window barwin;
    129 +	Window tabwin;
    130 +	int ntabs;
    131 +	int tab_widths[MAXTABS];
    132  	const Layout *lt[2];
    133  };
    134  
    135 @@ -163,12 +171,15 @@ static void detachstack(Client *c);
    136  static Monitor *dirtomon(int dir);
    137  static void drawbar(Monitor *m);
    138  static void drawbars(void);
    139 +static void drawtab(Monitor *m);
    140 +static void drawtabs(void);
    141  static void enternotify(XEvent *e);
    142  static void expose(XEvent *e);
    143  static void focus(Client *c);
    144  static void focusin(XEvent *e);
    145  static void focusmon(const Arg *arg);
    146  static void focusstack(const Arg *arg);
    147 +static void focuswin(const Arg* arg);
    148  static int getrootptr(int *x, int *y);
    149  static long getstate(Window w);
    150  static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
    151 @@ -206,6 +217,7 @@ static void seturgent(Client *c, int urg
    152  static void showhide(Client *c);
    153  static void sigchld(int unused);
    154  static void spawn(const Arg *arg);
    155 +static void tabmode(const Arg *arg);
    156  static void tag(const Arg *arg);
    157  static void tagmon(const Arg *arg);
    158  static void tile(Monitor *);
    159 @@ -240,6 +252,7 @@ static char stext[256];
    160  static int screen;
    161  static int sw, sh;           /* X display screen geometry width, height */
    162  static int bh, blw = 0;      /* bar geometry */
    163 +static int th = 0;           /* tab bar geometry */
    164  static int lrpad;            /* sum of left and right padding for text */
    165  static int (*xerrorxlib)(Display *, XErrorEvent *);
    166  static unsigned int numlockmask = 0;
    167 @@ -392,8 +405,9 @@ arrange(Monitor *m)
    168  }
    169  
    170  void
    171 -arrangemon(Monitor *m)
    172 -{
    173 +arrangemon(Monitor *m) {
    174 +	updatebarpos(m);
    175 +	XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th);
    176  	strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
    177  	if (m->lt[m->sellt]->arrange)
    178  		m->lt[m->sellt]->arrange(m);
    179 @@ -443,7 +457,24 @@ buttonpress(XEvent *e)
    180  			click = ClkStatusText;
    181  		else
    182  			click = ClkWinTitle;
    183 -	} else if ((c = wintoclient(ev->window))) {
    184 +	}
    185 +	if(ev->window == selmon->tabwin) {
    186 +		i = 0; x = 0;
    187 +		for(c = selmon->clients; c; c = c->next){
    188 +			if(!ISVISIBLE(c)) continue;
    189 +			x += selmon->tab_widths[i];
    190 +			if (ev->x > x)
    191 +				++i;
    192 +			else
    193 +				break;
    194 +			if(i >= m->ntabs) break;
    195 +		}
    196 +		if(c) {
    197 +			click = ClkTabBar;
    198 +			arg.ui = i;
    199 +		}
    200 +	}
    201 +	else if((c = wintoclient(ev->window))) {
    202  		focus(c);
    203  		restack(selmon);
    204  		XAllowEvents(dpy, ReplayPointer, CurrentTime);
    205 @@ -451,8 +482,9 @@ buttonpress(XEvent *e)
    206  	}
    207  	for (i = 0; i < LENGTH(buttons); i++)
    208  		if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
    209 -		&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
    210 -			buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
    211 +		&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){
    212 +			buttons[i].func(((click == ClkTagBar || click == ClkTabBar) && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg);
    213 +		}
    214  }
    215  
    216  void
    217 @@ -506,6 +538,8 @@ cleanupmon(Monitor *mon)
    218  	}
    219  	XUnmapWindow(dpy, mon->barwin);
    220  	XDestroyWindow(dpy, mon->barwin);
    221 +	XUnmapWindow(dpy, mon->tabwin);
    222 +	XDestroyWindow(dpy, mon->tabwin);
    223  	free(mon);
    224  }
    225  
    226 @@ -637,7 +671,10 @@ createmon(void)
    227  	m->mfact = mfact;
    228  	m->nmaster = nmaster;
    229  	m->showbar = showbar;
    230 +	m->showtab = showtab;
    231  	m->topbar = topbar;
    232 +	m->toptab = toptab;
    233 +	m->ntabs = 0;
    234  	m->lt[0] = &layouts[0];
    235  	m->lt[1] = &layouts[1 % LENGTH(layouts)];
    236  	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
    237 @@ -752,6 +789,105 @@ drawbars(void)
    238  }
    239  
    240  void
    241 +drawtabs(void) {
    242 +	Monitor *m;
    243 +
    244 +	for(m = mons; m; m = m->next)
    245 +		drawtab(m);
    246 +}
    247 +
    248 +static int
    249 +cmpint(const void *p1, const void *p2) {
    250 +  /* The actual arguments to this function are "pointers to
    251 +     pointers to char", but strcmp(3) arguments are "pointers
    252 +     to char", hence the following cast plus dereference */
    253 +  return *((int*) p1) > * (int*) p2;
    254 +}
    255 +
    256 +
    257 +void
    258 +drawtab(Monitor *m) {
    259 +	Client *c;
    260 +	int i;
    261 +	int itag = -1;
    262 +	char view_info[50];
    263 +	int view_info_w = 0;
    264 +	int sorted_label_widths[MAXTABS];
    265 +	int tot_width;
    266 +	int maxsize = bh;
    267 +	int x = 0;
    268 +	int w = 0;
    269 +
    270 +	//view_info: indicate the tag which is displayed in the view
    271 +	for(i = 0; i < LENGTH(tags); ++i){
    272 +	  if((selmon->tagset[selmon->seltags] >> i) & 1) {
    273 +	    if(itag >=0){ //more than one tag selected
    274 +	      itag = -1;
    275 +	      break;
    276 +	    }
    277 +	    itag = i;
    278 +	  }
    279 +	}
    280 +
    281 +	if(0 <= itag  && itag < LENGTH(tags)){
    282 +	  snprintf(view_info, sizeof view_info, "[%s]", tags[itag]);
    283 +	} else {
    284 +	  strncpy(view_info, "[...]", sizeof view_info);
    285 +	}
    286 +	view_info[sizeof(view_info) - 1 ] = 0;
    287 +	view_info_w = TEXTW(view_info);
    288 +	tot_width = view_info_w;
    289 +
    290 +	/* Calculates number of labels and their width */
    291 +	m->ntabs = 0;
    292 +	for(c = m->clients; c; c = c->next){
    293 +	  if(!ISVISIBLE(c)) continue;
    294 +	  m->tab_widths[m->ntabs] = TEXTW(c->name);
    295 +	  tot_width += m->tab_widths[m->ntabs];
    296 +	  ++m->ntabs;
    297 +	  if(m->ntabs >= MAXTABS) break;
    298 +	}
    299 +
    300 +	if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated
    301 +	  memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs);
    302 +	  qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint);
    303 +	  tot_width = view_info_w;
    304 +	  for(i = 0; i < m->ntabs; ++i){
    305 +	    if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww)
    306 +	      break;
    307 +	    tot_width += sorted_label_widths[i];
    308 +	  }
    309 +	  maxsize = (m->ww - tot_width) / (m->ntabs - i);
    310 +	} else{
    311 +	  maxsize = m->ww;
    312 +	}
    313 +	i = 0;
    314 +	for(c = m->clients; c; c = c->next){
    315 +	  if(!ISVISIBLE(c)) continue;
    316 +	  if(i >= m->ntabs) break;
    317 +	  if(m->tab_widths[i] >  maxsize) m->tab_widths[i] = maxsize;
    318 +	  w = m->tab_widths[i];
    319 +	  drw_setscheme(drw, scheme[(c == m->sel) ? SchemeSel : SchemeNorm]);
    320 +	  drw_text(drw, x, 0, w, th, 0, c->name, 0);
    321 +	  x += w;
    322 +	  ++i;
    323 +	}
    324 +
    325 +	drw_setscheme(drw, scheme[SchemeNorm]);
    326 +
    327 +	/* cleans interspace between window names and current viewed tag label */
    328 +	w = m->ww - view_info_w - x;
    329 +	drw_text(drw, x, 0, w, th, 0, "", 0);
    330 +
    331 +	/* view info */
    332 +	x += w;
    333 +	w = view_info_w;
    334 +	drw_text(drw, x, 0, w, th, 0, view_info, 0);
    335 +
    336 +	drw_map(drw, m->tabwin, 0, 0, m->ww, th);
    337 +}
    338 +
    339 +void
    340  enternotify(XEvent *e)
    341  {
    342  	Client *c;
    343 @@ -776,8 +912,10 @@ expose(XEvent *e)
    344  	Monitor *m;
    345  	XExposeEvent *ev = &e->xexpose;
    346  
    347 -	if (ev->count == 0 && (m = wintomon(ev->window)))
    348 +	if(ev->count == 0 && (m = wintomon(ev->window))){
    349  		drawbar(m);
    350 +		drawtab(m);
    351 +	}
    352  }
    353  
    354  void
    355 @@ -803,6 +941,7 @@ focus(Client *c)
    356  	}
    357  	selmon->sel = c;
    358  	drawbars();
    359 +	drawtabs();
    360  }
    361  
    362  /* there are some broken focus acquiring clients needing extra handling */
    363 @@ -855,6 +994,19 @@ focusstack(const Arg *arg)
    364  	}
    365  }
    366  
    367 +void
    368 +focuswin(const Arg* arg){
    369 +  int iwin = arg->i;
    370 +  Client* c = NULL;
    371 +  for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){
    372 +    if(ISVISIBLE(c)) --iwin;
    373 +  };
    374 +  if(c) {
    375 +    focus(c);
    376 +    restack(selmon);
    377 +  }
    378 +}
    379 +
    380  Atom
    381  getatomprop(Client *c, Atom prop)
    382  {
    383 @@ -1233,12 +1385,14 @@ propertynotify(XEvent *e)
    384  		case XA_WM_HINTS:
    385  			updatewmhints(c);
    386  			drawbars();
    387 +			drawtabs();
    388  			break;
    389  		}
    390  		if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
    391  			updatetitle(c);
    392  			if (c == c->mon->sel)
    393  				drawbar(c->mon);
    394 +			drawtab(c->mon);
    395  		}
    396  		if (ev->atom == netatom[NetWMWindowType])
    397  			updatewindowtype(c);
    398 @@ -1352,6 +1506,7 @@ restack(Monitor *m)
    399  	XWindowChanges wc;
    400  
    401  	drawbar(m);
    402 +	drawtab(m);
    403  	if (!m->sel)
    404  		return;
    405  	if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
    406 @@ -1546,6 +1701,7 @@ setup(void)
    407  		die("no fonts could be loaded.");
    408  	lrpad = drw->fonts->h;
    409  	bh = drw->fonts->h + 2;
    410 +	th = bh;
    411  	updategeom();
    412  	/* init atoms */
    413  	utf8string = XInternAtom(dpy, "UTF8_STRING", False);
    414 @@ -1706,6 +1862,17 @@ togglebar(const Arg *arg)
    415  }
    416  
    417  void
    418 +tabmode(const Arg *arg)
    419 +{
    420 +	if(arg && arg->i >= 0)
    421 +		selmon->showtab = arg->ui % showtab_nmodes;
    422 +	else
    423 +		selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes;
    424 +	arrange(selmon);
    425 +}
    426 +
    427 +
    428 +void
    429  togglefloating(const Arg *arg)
    430  {
    431  	if (!selmon->sel)
    432 @@ -1816,6 +1983,11 @@ updatebars(void)
    433  				CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
    434  		XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
    435  		XMapRaised(dpy, m->barwin);
    436 +		m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen),
    437 +						CopyFromParent, DefaultVisual(dpy, screen),
    438 +						CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
    439 +		XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor);
    440 +		XMapRaised(dpy, m->tabwin);
    441  		XSetClassHint(dpy, m->barwin, &ch);
    442  	}
    443  }
    444 @@ -1823,14 +1995,33 @@ updatebars(void)
    445  void
    446  updatebarpos(Monitor *m)
    447  {
    448 +	Client *c;
    449 +	int nvis = 0;
    450 +
    451  	m->wy = m->my;
    452  	m->wh = m->mh;
    453  	if (m->showbar) {
    454  		m->wh -= bh;
    455  		m->by = m->topbar ? m->wy : m->wy + m->wh;
    456 -		m->wy = m->topbar ? m->wy + bh : m->wy;
    457 -	} else
    458 +		if ( m->topbar )
    459 +			m->wy += bh;
    460 +	} else {
    461  		m->by = -bh;
    462 +	}
    463 +
    464 +	for(c = m->clients; c; c = c->next) {
    465 +		if(ISVISIBLE(c)) ++nvis;
    466 +	}
    467 +
    468 +	if(m->showtab == showtab_always
    469 +	   || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))) {
    470 +		m->wh -= th;
    471 +		m->ty = m->toptab ? m->wy : m->wy + m->wh;
    472 +		if ( m->toptab )
    473 +			m->wy += th;
    474 +	} else {
    475 +		m->ty = -th;
    476 +	}
    477  }
    478  
    479  void
    480 @@ -2067,7 +2258,7 @@ wintomon(Window w)
    481  	if (w == root && getrootptr(&x, &y))
    482  		return recttomon(x, y, 1, 1);
    483  	for (m = mons; m; m = m->next)
    484 -		if (w == m->barwin)
    485 +		if (w == m->barwin || w == m->tabwin)
    486  			return m;
    487  	if ((c = wintoclient(w)))
    488  		return c->mon;