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