dwm-6.2-tab-v2b.diff - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) 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;