sites

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

dwm-6.1-tab-v2b.diff (15707B)


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