URI: 
       dwm-6.0-pertag-tab.diff - sites - public wiki contents of suckless.org
  HTML git clone git://git.suckless.org/sites
   DIR Log
   DIR Files
   DIR Refs
       ---
       dwm-6.0-pertag-tab.diff (23754B)
       ---
            1 diff -u dwm-6.0-orig/config.def.h dwm-6.0-pertag-tab/config.def.h
            2 --- dwm-6.0-orig/config.def.h        2011-12-19 16:02:46.000000000 +0100
            3 +++ dwm-6.0-pertag-tab/config.def.h        2013-06-23 00:06:48.000000000 +0200
            4 @@ -12,6 +12,9 @@
            5  static const unsigned int snap      = 32;       /* snap pixel */
            6  static const Bool showbar           = True;     /* False means no bar */
            7  static const Bool topbar            = True;     /* False means bottom bar */
            8 +static const Bool showtab           = True;     /* False means no tab bar */
            9 +static const Bool toptab            = False;    /* False means bottom tab bar */
           10 +
           11  
           12  /* tagging */
           13  static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
           14 @@ -25,7 +28,7 @@
           15  /* layout(s) */
           16  static const float mfact      = 0.55; /* factor of master area size [0.05..0.95] */
           17  static const int nmaster      = 1;    /* number of clients in master area */
           18 -static const Bool resizehints = True; /* True means respect size hints in tiled resizals */
           19 +static const Bool resizehints = False; /* True means respect size hints in tiled resizals */
           20  
           21  static const Layout layouts[] = {
           22          /* symbol     arrange function */
           23 @@ -54,6 +57,7 @@
           24          { MODKEY,                       XK_p,      spawn,          {.v = dmenucmd } },
           25          { MODKEY|ShiftMask,             XK_Return, spawn,          {.v = termcmd } },
           26          { MODKEY,                       XK_b,      togglebar,      {0} },
           27 +        { MODKEY,                       XK_w,      toggletab,      {0} },
           28          { MODKEY,                       XK_j,      focusstack,     {.i = +1 } },
           29          { MODKEY,                       XK_k,      focusstack,     {.i = -1 } },
           30          { MODKEY,                       XK_i,      incnmaster,     {.i = +1 } },
           31 @@ -101,5 +105,6 @@
           32          { ClkTagBar,            0,              Button3,        toggleview,     {0} },
           33          { ClkTagBar,            MODKEY,         Button1,        tag,            {0} },
           34          { ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} },
           35 +        { ClkTabBar,            0,              Button1,        focuswin,       {0} },
           36  };
           37  
           38 diff -u dwm-6.0-orig/dwm.1 dwm-6.0-pertag-tab/dwm.1
           39 --- dwm-6.0-orig/dwm.1        2011-12-19 16:02:46.000000000 +0100
           40 +++ dwm-6.0-pertag-tab/dwm.1        2013-06-23 00:21:16.000000000 +0200
           41 @@ -19,14 +19,16 @@
           42  Windows are grouped by tags. Each window can be tagged with one or multiple
           43  tags. Selecting certain tags displays all windows with these tags.
           44  .P
           45 -Each screen contains a small status bar which displays all available tags, the
           46 -layout, the title of the focused window, and the text read from the root window
           47 -name property, if the screen is focused. A floating window is indicated with an
           48 -empty square and a maximised floating window is indicated with a filled square
           49 -before the windows title.  The selected tags are indicated with a different
           50 -color. The tags of the focused window are indicated with a filled square in the
           51 -top left corner.  The tags which are applied to one or more windows are
           52 -indicated with an empty square in the top left corner.
           53 +Each screen contains two bars. A small status bar displays all available tags,
           54 +the layout, the title of the focused window, and the text read from the root
           55 +window name property, if the screen is focused. A small tab bar lists the
           56 +windows in the current view and allows navigation from window to window,
           57 +especially in the monocle mode. A floating window is indicated with an empty
           58 +square and a maximised floating window is indicated with a filled square before
           59 +the windows title.  The selected tags are indicated with a different color. The
           60 +tags of the focused window are indicated with a filled square in the top left
           61 +corner.  The tags which are applied to one or more windows are indicated with an
           62 +empty square in the top left corner.
           63  .P
           64  dwm draws a small border around windows to indicate the focus state.
           65  .SH OPTIONS
           66 @@ -43,7 +45,8 @@
           67  .TP
           68  .B Button1
           69  click on a tag label to display all windows with that tag, click on the layout
           70 -label toggles between tiled and floating layout.
           71 +label toggles between tiled and floating layout, click on a window name in the
           72 +tab bar brings focus to that window.
           73  .TP
           74  .B Button3
           75  click on a tag label adds/removes all windows with that tag to/from the view.
           76 @@ -104,6 +107,9 @@
           77  .B Mod1\-h
           78  Decrease master area size.
           79  .TP
           80 +.B Mod1\-w
           81 +Toggle the tab bar.
           82 +.TP
           83  .B Mod1\-Return
           84  Zooms/cycles focused window to/from master area (tiled layouts only).
           85  .TP
           86 diff -u dwm-6.0-orig/dwm.c dwm-6.0-pertag-tab/dwm.c
           87 --- dwm-6.0-orig/dwm.c        2011-12-19 16:02:46.000000000 +0100
           88 +++ dwm-6.0-pertag-tab/dwm.c        2013-06-23 16:57:10.000000000 +0200
           89 @@ -62,7 +62,7 @@
           90         NetWMFullscreen, NetActiveWindow, NetWMWindowType,
           91         NetWMWindowTypeDialog, NetLast };     /* EWMH atoms */
           92  enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
           93 -enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
           94 +enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
           95         ClkClientWin, ClkRootWin, ClkLast };             /* clicks */
           96  
           97  typedef union {
           98 @@ -102,6 +102,7 @@
           99          unsigned long norm[ColLast];
          100          unsigned long sel[ColLast];
          101          Drawable drawable;
          102 +        Drawable tabdrawable;
          103          GC gc;
          104          struct {
          105                  int ascent;
          106 @@ -124,25 +125,36 @@
          107          void (*arrange)(Monitor *);
          108  } Layout;
          109  
          110 +typedef struct Pertag Pertag;
          111 +
          112 +#define MAXTABS 50
          113 +
          114  struct Monitor {
          115          char ltsymbol[16];
          116          float mfact;
          117          int nmaster;
          118          int num;
          119          int by;               /* bar geometry */
          120 +        int ty;               /* tab bar geometry */
          121          int mx, my, mw, mh;   /* screen size */
          122          int wx, wy, ww, wh;   /* window area  */
          123          unsigned int seltags;
          124          unsigned int sellt;
          125          unsigned int tagset[2];
          126          Bool showbar;
          127 +        Bool showtab;
          128          Bool topbar;
          129 +        Bool toptab;
          130          Client *clients;
          131          Client *sel;
          132          Client *stack;
          133          Monitor *next;
          134          Window barwin;
          135 +        Window tabwin;
          136 +        int ntabs;
          137 +        int tab_widths[MAXTABS];
          138          const Layout *lt[2];
          139 +        Pertag *pertag;
          140  };
          141  
          142  typedef struct {
          143 @@ -178,11 +190,15 @@
          144  static Monitor *dirtomon(int dir);
          145  static void drawbar(Monitor *m);
          146  static void drawbars(void);
          147 +static void drawtab(Monitor *m);
          148 +static void drawtabs(void);
          149  static void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]);
          150 -static void drawtext(const char *text, unsigned long col[ColLast], Bool invert);
          151 +static void drawtext(Drawable drawable, const char *text, unsigned long col[ColLast], Bool invert);
          152 +//static void drawtabtext(const char *text, unsigned long col[ColLast], Bool invert);
          153  static void enternotify(XEvent *e);
          154  static void expose(XEvent *e);
          155  static void focus(Client *c);
          156 +static void focuswin(const Arg* arg);
          157  static void focusin(XEvent *e);
          158  static void focusmon(const Arg *arg);
          159  static void focusstack(const Arg *arg);
          160 @@ -229,6 +245,7 @@
          161  static int textnw(const char *text, unsigned int len);
          162  static void tile(Monitor *);
          163  static void togglebar(const Arg *arg);
          164 +static void toggletab(const Arg *arg);
          165  static void togglefloating(const Arg *arg);
          166  static void toggletag(const Arg *arg);
          167  static void toggleview(const Arg *arg);
          168 @@ -258,6 +275,7 @@
          169  static int screen;
          170  static int sw, sh;           /* X display screen geometry width, height */
          171  static int bh, blw = 0;      /* bar geometry */
          172 +static int th = 0;           /* tab bar geometry */
          173  static int (*xerrorxlib)(Display *, XErrorEvent *);
          174  static unsigned int numlockmask = 0;
          175  static void (*handler[LASTEvent]) (XEvent *) = {
          176 @@ -287,6 +305,16 @@
          177  /* configuration, allows nested code to access above variables */
          178  #include "config.h"
          179  
          180 +struct Pertag {
          181 +        unsigned int curtag, prevtag; /* current and previous tag */
          182 +        int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
          183 +        float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
          184 +        unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
          185 +        const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes  */
          186 +        Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
          187 +        Bool showtabs[LENGTH(tags) + 1]; /* display tab bar for the current tag */
          188 +};
          189 +
          190  /* compile-time check if all tags fit into an unsigned int bit array. */
          191  struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
          192  
          193 @@ -454,14 +482,32 @@
          194                  else
          195                          click = ClkWinTitle;
          196          }
          197 +        if(ev->window == selmon->tabwin) {
          198 +                i = 0; x = 0;
          199 +                for(c = selmon->clients; c; c = c->next){
          200 +                  if(!ISVISIBLE(c)) continue;
          201 +                  x += selmon->tab_widths[i];
          202 +                  if (ev->x > x)
          203 +                    ++i;
          204 +                  else
          205 +                    break;
          206 +                  if(i >= m->ntabs) break;
          207 +                }
          208 +                if(c) {
          209 +                  click = ClkTabBar;
          210 +                  arg.ui = i;
          211 +                }
          212 +        }
          213          else if((c = wintoclient(ev->window))) {
          214                  focus(c);
          215                  click = ClkClientWin;
          216          }
          217          for(i = 0; i < LENGTH(buttons); i++)
          218                  if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
          219 -                && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
          220 -                        buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
          221 +                   && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){
          222 +                  buttons[i].func(((click == ClkTagBar || click == ClkTabBar)
          223 +                                   && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg);
          224 +                }
          225  }
          226  
          227  void
          228 @@ -491,6 +537,7 @@
          229                  XFreeFont(dpy, dc.font.xfont);
          230          XUngrabKey(dpy, AnyKey, AnyModifier, root);
          231          XFreePixmap(dpy, dc.drawable);
          232 +        XFreePixmap(dpy, dc.tabdrawable);
          233          XFreeGC(dpy, dc.gc);
          234          XFreeCursor(dpy, cursor[CurNormal]);
          235          XFreeCursor(dpy, cursor[CurResize]);
          236 @@ -513,6 +560,8 @@
          237          }
          238          XUnmapWindow(dpy, mon->barwin);
          239          XDestroyWindow(dpy, mon->barwin);
          240 +        XUnmapWindow(dpy, mon->tabwin);
          241 +        XDestroyWindow(dpy, mon->tabwin);
          242          free(mon);
          243  }
          244  
          245 @@ -581,9 +630,14 @@
          246                          if(dc.drawable != 0)
          247                                  XFreePixmap(dpy, dc.drawable);
          248                          dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
          249 +                        if(dc.tabdrawable != 0)
          250 +                                XFreePixmap(dpy, dc.tabdrawable);
          251 +                        dc.tabdrawable = XCreatePixmap(dpy, root, sw, th, DefaultDepth(dpy, screen));
          252                          updatebars();
          253 -                        for(m = mons; m; m = m->next)
          254 +                        for(m = mons; m; m = m->next){
          255                                  XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
          256 +                                 XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th);
          257 +                        }
          258                          focus(NULL);
          259                          arrange(NULL);
          260                  }
          261 @@ -646,6 +700,7 @@
          262  Monitor *
          263  createmon(void) {
          264          Monitor *m;
          265 +        int i;
          266  
          267          if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
          268                  die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
          269 @@ -653,10 +708,34 @@
          270          m->mfact = mfact;
          271          m->nmaster = nmaster;
          272          m->showbar = showbar;
          273 +        m->showtab = showtab;
          274          m->topbar = topbar;
          275 +        m->toptab = toptab;
          276 +        m->ntabs = 0;
          277          m->lt[0] = &layouts[0];
          278          m->lt[1] = &layouts[1 % LENGTH(layouts)];
          279          strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
          280 +        if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
          281 +                die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
          282 +        m->pertag->curtag = m->pertag->prevtag = 1;
          283 +        for(i=0; i <= LENGTH(tags); i++) {
          284 +                /* init nmaster */
          285 +                m->pertag->nmasters[i] = m->nmaster;
          286 +
          287 +                /* init mfacts */
          288 +                m->pertag->mfacts[i] = m->mfact;
          289 +
          290 +                /* init layouts */
          291 +                m->pertag->ltidxs[i][0] = m->lt[0];
          292 +                m->pertag->ltidxs[i][1] = m->lt[1];
          293 +                m->pertag->sellts[i] = m->sellt;
          294 +
          295 +                /* init showbar */
          296 +                m->pertag->showbars[i] = m->showbar;
          297 +
          298 +                /* init showtab */
          299 +                m->pertag->showtabs[i] = m->showtab;
          300 +        }
          301          return m;
          302  }
          303  
          304 @@ -731,13 +810,13 @@
          305          for(i = 0; i < LENGTH(tags); i++) {
          306                  dc.w = TEXTW(tags[i]);
          307                  col = m->tagset[m->seltags] & 1 << i ? dc.sel : dc.norm;
          308 -                drawtext(tags[i], col, urg & 1 << i);
          309 +                drawtext(dc.drawable, tags[i], col, urg & 1 << i);
          310                  drawsquare(m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
          311                             occ & 1 << i, urg & 1 << i, col);
          312                  dc.x += dc.w;
          313          }
          314          dc.w = blw = TEXTW(m->ltsymbol);
          315 -        drawtext(m->ltsymbol, dc.norm, False);
          316 +        drawtext(dc.drawable, m->ltsymbol, dc.norm, False);
          317          dc.x += dc.w;
          318          x = dc.x;
          319          if(m == selmon) { /* status is only drawn on selected monitor */
          320 @@ -747,19 +826,20 @@
          321                          dc.x = x;
          322                          dc.w = m->ww - x;
          323                  }
          324 -                drawtext(stext, dc.norm, False);
          325 +                drawtext(dc.drawable, stext, dc.norm, False);
          326          }
          327          else
          328                  dc.x = m->ww;
          329          if((dc.w = dc.x - x) > bh) {
          330                  dc.x = x;
          331                  if(m->sel) {
          332 -                        col = m == selmon ? dc.sel : dc.norm;
          333 -                        drawtext(m->sel->name, col, False);
          334 +                  //                        col = m == selmon ? dc.sel : dc.norm;
          335 +                  //        drawtext(dc.drawable, m->sel->name, col, False);
          336 +                  drawtext(dc.drawable, m->sel->name, dc.norm, False);
          337                          drawsquare(m->sel->isfixed, m->sel->isfloating, False, col);
          338                  }
          339                  else
          340 -                        drawtext(NULL, dc.norm, False);
          341 +                  drawtext(dc.drawable, NULL, dc.norm, False);
          342          }
          343          XCopyArea(dpy, dc.drawable, m->barwin, dc.gc, 0, 0, m->ww, bh, 0, 0);
          344          XSync(dpy, False);
          345 @@ -774,6 +854,104 @@
          346  }
          347  
          348  void
          349 +drawtabs(void) {
          350 +        Monitor *m;
          351 +
          352 +        for(m = mons; m; m = m->next)
          353 +                drawtab(m);
          354 +}
          355 +
          356 +static int
          357 +cmpint(const void *p1, const void *p2) {
          358 +  /* The actual arguments to this function are "pointers to
          359 +     pointers to char", but strcmp(3) arguments are "pointers
          360 +     to char", hence the following cast plus dereference */
          361 +  return *((int*) p1) > * (int*) p2;
          362 +}
          363 +
          364 +
          365 +void
          366 +drawtab(Monitor *m) {
          367 +        unsigned long *col;
          368 +        Client *c;
          369 +        int i;
          370 +        int itag = -1;
          371 +        char view_info[50];
          372 +        int view_info_w = 0;
          373 +        int sorted_label_widths[MAXTABS];
          374 +        int tot_width;
          375 +        int maxsize = bh;
          376 +        dc.x = 0;
          377 +
          378 +        //view_info: indicate the tag which is displayed in the view
          379 +        for(i = 0; i < LENGTH(tags); ++i){
          380 +          if((selmon->tagset[selmon->seltags] >> i) & 1) {
          381 +            if(itag >=0){ //more than one tag selected
          382 +              itag = -1;
          383 +              break;
          384 +            }
          385 +            itag = i;
          386 +          }
          387 +        }
          388 +        if(0 <= itag  && itag < LENGTH(tags)){
          389 +          snprintf(view_info, sizeof view_info, "[%s]", tags[itag]);
          390 +        } else {
          391 +          strncpy(view_info, "[...]", sizeof view_info);
          392 +        }
          393 +        view_info[sizeof(view_info) - 1 ] = 0;
          394 +        view_info_w = TEXTW(view_info);
          395 +        tot_width = view_info_w;
          396 +
          397 +        /* Calculates number of labels and their width */
          398 +        m->ntabs = 0;
          399 +        for(c = m->clients; c; c = c->next){
          400 +          if(!ISVISIBLE(c)) continue;
          401 +          m->tab_widths[m->ntabs] = TEXTW(c->name);
          402 +          tot_width += m->tab_widths[m->ntabs];
          403 +          ++m->ntabs;
          404 +          if(m->ntabs >= MAXTABS) break;
          405 +        }
          406 +
          407 +        if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated
          408 +          memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs);
          409 +          qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint);
          410 +          tot_width = view_info_w;
          411 +          for(i = 0; i < m->ntabs; ++i){
          412 +            if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww)
          413 +              break;
          414 +            tot_width += sorted_label_widths[i];
          415 +          }
          416 +          maxsize = (m->ww - tot_width) / (m->ntabs - i);
          417 +        } else{
          418 +          maxsize = m->ww;
          419 +        }
          420 +        i = 0;
          421 +        for(c = m->clients; c; c = c->next){
          422 +          if(!ISVISIBLE(c)) continue;
          423 +          if(i >= m->ntabs) break;
          424 +          if(m->tab_widths[i] >  maxsize) m->tab_widths[i] = maxsize;
          425 +          dc.w = m->tab_widths[i];
          426 +          col = (c == m->sel)  ? dc.sel : dc.norm;
          427 +          drawtext(dc.tabdrawable, c->name, col, 0);
          428 +          dc.x += dc.w;
          429 +          ++i;
          430 +        }
          431 +
          432 +        /* cleans interspace between window names and current viewed tag label */
          433 +        dc.w = m->ww - view_info_w - dc.x;
          434 +        drawtext(dc.tabdrawable, NULL, dc.norm, 0);
          435 +
          436 +        /* view info */
          437 +        dc.x += dc.w;
          438 +        dc.w = view_info_w;
          439 +        drawtext(dc.tabdrawable, view_info, dc.norm, 0);
          440 +
          441 +        XCopyArea(dpy, dc.tabdrawable, m->tabwin, dc.gc, 0, 0, m->ww, th, 0, 0);
          442 +        XSync(dpy, False);
          443 +}
          444 +
          445 +
          446 +void
          447  drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
          448          int x;
          449  
          450 @@ -785,13 +963,14 @@
          451                  XDrawRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x, x);
          452  }
          453  
          454 +
          455  void
          456 -drawtext(const char *text, unsigned long col[ColLast], Bool invert) {
          457 +drawtext(Drawable drawable, const char *text, unsigned long col[ColLast], Bool invert) {
          458          char buf[256];
          459          int i, x, y, h, len, olen;
          460  
          461          XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]);
          462 -        XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h);
          463 +        XFillRectangle(dpy, drawable, dc.gc, dc.x, dc.y, dc.w, dc.h);
          464          if(!text)
          465                  return;
          466          olen = strlen(text);
          467 @@ -807,11 +986,12 @@
          468                  for(i = len; i && i > len - 3; buf[--i] = '.');
          469          XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]);
          470          if(dc.font.set)
          471 -                XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
          472 +                XmbDrawString(dpy, drawable, dc.font.set, dc.gc, x, y, buf, len);
          473          else
          474 -                XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
          475 +                XDrawString(dpy, drawable, dc.gc, x, y, buf, len);
          476  }
          477  
          478 +
          479  void
          480  enternotify(XEvent *e) {
          481          Client *c;
          482 @@ -836,8 +1016,10 @@
          483          Monitor *m;
          484          XExposeEvent *ev = &e->xexpose;
          485  
          486 -        if(ev->count == 0 && (m = wintomon(ev->window)))
          487 +        if(ev->count == 0 && (m = wintomon(ev->window))){
          488                  drawbar(m);
          489 +                drawtab(m);
          490 +        }
          491  }
          492  
          493  void
          494 @@ -862,6 +1044,7 @@
          495                  XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
          496          selmon->sel = c;
          497          drawbars();
          498 +        drawtabs();
          499  }
          500  
          501  void
          502 @@ -911,6 +1094,19 @@
          503          }
          504  }
          505  
          506 +void
          507 +focuswin(const Arg* arg){
          508 +  int iwin = arg->i;
          509 +  Client* c = NULL;
          510 +  for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){
          511 +    if(ISVISIBLE(c)) --iwin;
          512 +  };
          513 +  if(c) {
          514 +    focus(c);
          515 +    restack(selmon);
          516 +  }
          517 +}
          518 +
          519  Atom
          520  getatomprop(Client *c, Atom prop) {
          521          int di;
          522 @@ -1028,7 +1224,7 @@
          523  
          524  void
          525  incnmaster(const Arg *arg) {
          526 -        selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
          527 +        selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
          528          arrange(selmon);
          529  }
          530  
          531 @@ -1311,12 +1507,14 @@
          532                  case XA_WM_HINTS:
          533                          updatewmhints(c);
          534                          drawbars();
          535 +                        drawtabs();
          536                          break;
          537                  }
          538                  if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
          539                          updatetitle(c);
          540                          if(c == c->mon->sel)
          541                                  drawbar(c->mon);
          542 +                        drawtab(c->mon);
          543                  }
          544                  if(ev->atom == netatom[NetWMWindowType])
          545                          updatewindowtype(c);
          546 @@ -1418,6 +1616,7 @@
          547          XWindowChanges wc;
          548  
          549          drawbar(m);
          550 +        drawtab(m);
          551          if(!m->sel)
          552                  return;
          553          if(m->sel->isfloating || !m->lt[m->sellt]->arrange)
          554 @@ -1555,10 +1754,13 @@
          555  
          556  void
          557  setlayout(const Arg *arg) {
          558 -        if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
          559 -                selmon->sellt ^= 1;
          560 +        if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
          561 +                selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
          562 +                selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
          563 +        }
          564          if(arg && arg->v)
          565 -                selmon->lt[selmon->sellt] = (Layout *)arg->v;
          566 +                selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
          567 +        selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
          568          strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
          569          if(selmon->sel)
          570                  arrange(selmon);
          571 @@ -1576,7 +1778,7 @@
          572          f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
          573          if(f < 0.1 || f > 0.9)
          574                  return;
          575 -        selmon->mfact = f;
          576 +        selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
          577          arrange(selmon);
          578  }
          579  
          580 @@ -1594,6 +1796,7 @@
          581          sw = DisplayWidth(dpy, screen);
          582          sh = DisplayHeight(dpy, screen);
          583          bh = dc.h = dc.font.height + 2;
          584 +        th = bh;
          585          updategeom();
          586          /* init atoms */
          587          wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
          588 @@ -1619,6 +1822,7 @@
          589          dc.sel[ColBG] = getcolor(selbgcolor);
          590          dc.sel[ColFG] = getcolor(selfgcolor);
          591          dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen));
          592 +        dc.tabdrawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), th, DefaultDepth(dpy, screen));
          593          dc.gc = XCreateGC(dpy, root, 0, NULL);
          594          XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
          595          if(!dc.font.set)
          596 @@ -1729,13 +1933,22 @@
          597  
          598  void
          599  togglebar(const Arg *arg) {
          600 -        selmon->showbar = !selmon->showbar;
          601 +        selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
          602          updatebarpos(selmon);
          603          XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
          604          arrange(selmon);
          605  }
          606  
          607  void
          608 +toggletab(const Arg *arg) {
          609 +        selmon->showtab = selmon->pertag->showtabs[selmon->pertag->curtag] = !selmon->showtab;
          610 +        updatebarpos(selmon);
          611 +        XMoveResizeWindow(dpy, selmon->tabwin, selmon->wx, selmon->ty, selmon->ww, th);
          612 +        arrange(selmon);
          613 +}
          614 +
          615 +
          616 +void
          617  togglefloating(const Arg *arg) {
          618          if(!selmon->sel)
          619                  return;
          620 @@ -1763,9 +1976,31 @@
          621  void
          622  toggleview(const Arg *arg) {
          623          unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
          624 +        int i;
          625  
          626          if(newtagset) {
          627 +                if(newtagset == ~0) {
          628 +                        selmon->pertag->prevtag = selmon->pertag->curtag;
          629 +                        selmon->pertag->curtag = 0;
          630 +                }
          631 +                /* test if the user did not select the same tag */
          632 +                if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
          633 +                        selmon->pertag->prevtag = selmon->pertag->curtag;
          634 +                        for (i=0; !(newtagset & 1 << i); i++) ;
          635 +                        selmon->pertag->curtag = i + 1;
          636 +                }
          637                  selmon->tagset[selmon->seltags] = newtagset;
          638 +
          639 +                /* apply settings for this view */
          640 +                selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
          641 +                selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
          642 +                selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
          643 +                selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
          644 +                selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
          645 +                if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
          646 +                        togglebar(NULL);
          647 +                if (selmon->showtab != selmon->pertag->showtabs[selmon->pertag->curtag])
          648 +                        toggletab(NULL);
          649                  focus(NULL);
          650                  arrange(selmon);
          651          }
          652 @@ -1832,6 +2067,11 @@
          653                                            CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
          654                  XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
          655                  XMapRaised(dpy, m->barwin);
          656 +                m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen),
          657 +                                          CopyFromParent, DefaultVisual(dpy, screen),
          658 +                                          CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
          659 +                XDefineCursor(dpy, m->tabwin, cursor[CurNormal]);
          660 +                XMapRaised(dpy, m->tabwin);
          661          }
          662  }
          663  
          664 @@ -1842,10 +2082,20 @@
          665          if(m->showbar) {
          666                  m->wh -= bh;
          667                  m->by = m->topbar ? m->wy : m->wy + m->wh;
          668 -                m->wy = m->topbar ? m->wy + bh : m->wy;
          669 +                if ( m->topbar )
          670 +                        m->wy += bh;
          671 +        } else {
          672 +                m->by = -bh;
          673 +        }
          674 +
          675 +        if(m->showtab) {
          676 +                m->wh -= th;
          677 +                m->ty = m->toptab ? m->wy : m->wy + m->wh;
          678 +                if ( m->toptab )
          679 +                        m->wy += th;
          680 +        } else {
          681 +                m->ty = -th;
          682          }
          683 -        else
          684 -                m->by = -bh;
          685  }
          686  
          687  Bool
          688 @@ -2043,11 +2293,35 @@
          689  
          690  void
          691  view(const Arg *arg) {
          692 +        int i;
          693 +        unsigned int tmptag;
          694 +
          695          if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
          696                  return;
          697          selmon->seltags ^= 1; /* toggle sel tagset */
          698 -        if(arg->ui & TAGMASK)
          699 +        if(arg->ui & TAGMASK) {
          700 +                selmon->pertag->prevtag = selmon->pertag->curtag;
          701                  selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
          702 +                if(arg->ui == ~0)
          703 +                        selmon->pertag->curtag = 0;
          704 +                else {
          705 +                        for (i=0; !(arg->ui & 1 << i); i++) ;
          706 +                        selmon->pertag->curtag = i + 1;
          707 +                }
          708 +        } else {
          709 +                tmptag = selmon->pertag->prevtag;
          710 +                selmon->pertag->prevtag = selmon->pertag->curtag;
          711 +                selmon->pertag->curtag = tmptag;
          712 +        }
          713 +        selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
          714 +        selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
          715 +        selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
          716 +        selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
          717 +        selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
          718 +        if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
          719 +                togglebar(NULL);
          720 +        if (selmon->showtab != selmon->pertag->showtabs[selmon->pertag->curtag])
          721 +                toggletab(NULL);
          722          focus(NULL);
          723          arrange(selmon);
          724  }
          725 @@ -2073,7 +2347,7 @@
          726          if(w == root && getrootptr(&x, &y))
          727                  return recttomon(x, y, 1, 1);
          728          for(m = mons; m; m = m->next)
          729 -                if(w == m->barwin)
          730 +                if(w == m->barwin || w == m->tabwin)
          731                          return m;
          732          if((c = wintoclient(w)))
          733                  return c->mon;