diff options
Diffstat (limited to 'dwm.c')
| -rw-r--r-- | dwm.c | 210 |
1 files changed, 171 insertions, 39 deletions
@@ -50,7 +50,6 @@ #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) -#define LENGTH(X) (sizeof X / sizeof X[0]) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define WIDTH(X) ((X)->w + 2 * (X)->bw) #define HEIGHT(X) ((X)->h + 2 * (X)->bw) @@ -72,14 +71,14 @@ /* enums */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ -enum { SchemeNorm, SchemeSel }; /* color schemes */ +enum { SchemeNorm, SchemeSel, SchemeSelTab }; /* color schemes */ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ -enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, +enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ typedef union { @@ -107,7 +106,7 @@ struct Client { int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid; int bw, oldbw; unsigned int tags; - int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, resizehints; Client *next; Client *snext; Monitor *mon; @@ -126,24 +125,32 @@ typedef struct { void (*arrange)(Monitor *); } Layout; +#define MAXTABS 50 + struct Monitor { char ltsymbol[16]; float mfact; int nmaster; int num; int by; /* bar geometry */ + int ty; /* tab bar geometry */ int mx, my, mw, mh; /* screen size */ int wx, wy, ww, wh; /* window area */ unsigned int seltags; unsigned int sellt; unsigned int tagset[2]; int showbar; + int showtab; int topbar; + int toptab; Client *clients; Client *sel; Client *stack; Monitor *next; Window barwin; + Window tabwin; + int ntabs; + int tab_widths[MAXTABS]; const Layout *lt[2]; }; @@ -154,6 +161,7 @@ typedef struct { unsigned int tags; int isfloating; int monitor; + int resizehints; } Rule; typedef struct Systray Systray; @@ -190,6 +198,7 @@ static void focus(Client *c); static void focusin(XEvent *e); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); +static void focuswin(const Arg* arg); static Atom getatomprop(Client *c, Atom prop); static int getrootptr(int *x, int *y); static long getstate(Window w); @@ -230,6 +239,7 @@ static void setup(void); static void seturgent(Client *c, int urg); static void showhide(Client *c); static void spawn(const Arg *arg); +static void tabmode(const Arg *arg); static Monitor *systraytomon(Monitor *m); static void tag(const Arg *arg); static void tagmon(const Arg *arg); @@ -274,6 +284,7 @@ static char stext[256]; static int screen; static int sw, sh; /* X display screen geometry width, height */ static int bh; /* bar height */ +static int th = 0; /* tab bar geometry */ static int lrpad; /* sum of left and right padding for text */ static int (*xerrorxlib)(Display *, XErrorEvent *); static unsigned int numlockmask = 0; @@ -332,6 +343,7 @@ applyrules(Client *c) { c->isfloating = r->isfloating; c->tags |= r->tags; + c->resizehints = r->resizehints; for (m = mons; m && m->num != r->monitor; m = m->next); if (m) c->mon = m; @@ -376,7 +388,7 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) *h = bh; if (*w < bh) *w = bh; - if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { + if (c->resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { if (!c->hintsvalid) updatesizehints(c); /* see last two sentences in ICCCM 4.1.2.3 */ @@ -427,8 +439,9 @@ arrange(Monitor *m) } void -arrangemon(Monitor *m) -{ +arrangemon(Monitor *m) { + updatebarpos(m); + XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); @@ -494,6 +507,22 @@ buttonpress(XEvent *e) click = ClkStatusText; else click = ClkWinTitle; + } + if(ev->window == selmon->tabwin) { + i = 0; x = 0; + for(c = selmon->clients; c; c = c->next){ + if(!ISVISIBLE(c)) continue; + x += selmon->tab_widths[i]; + if (ev->x > x) + ++i; + else + break; + if(i >= m->ntabs) break; + } + if(c) { + click = ClkTabBar; + arg.ui = i; + } } else if ((c = wintoclient(ev->window))) { if (focusonwheel || (ev->button != Button4 && ev->button != Button5)) focus(c); @@ -502,8 +531,9 @@ buttonpress(XEvent *e) } for (i = 0; i < LENGTH(buttons); i++) if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button - && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) - buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){ + buttons[i].func(((click == ClkTagBar || click == ClkTabBar) && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); + } } void @@ -565,6 +595,8 @@ cleanupmon(Monitor *mon) } XUnmapWindow(dpy, mon->barwin); XDestroyWindow(dpy, mon->barwin); + XUnmapWindow(dpy, mon->tabwin); + XDestroyWindow(dpy, mon->tabwin); free(mon); } @@ -575,7 +607,6 @@ clientmessage(XEvent *e) XSetWindowAttributes swa; XClientMessageEvent *cme = &e->xclient; Client *c = wintoclient(cme->window); - unsigned int i; if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { /* add systray icons */ @@ -632,14 +663,8 @@ clientmessage(XEvent *e) setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); } else if (cme->message_type == netatom[NetActiveWindow]) { - for (i = 0; i < LENGTH(tags) && !((1 << i) & c->tags); i++); - if (i < LENGTH(tags)) { - const Arg a = {.ui = 1 << i}; - selmon = c->mon; - view(&a); - focus(c); - restack(selmon); - } + if (c != selmon->sel && !c->isurgent) + seturgent(c, 1); } } @@ -752,11 +777,13 @@ createmon(void) m->mfact = mfact; m->nmaster = nmaster; m->showbar = showbar; + m->showtab = showtab; m->topbar = topbar; + m->toptab = toptab; + m->ntabs = 0; m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); - return m; } @@ -871,6 +898,56 @@ drawbar(Monitor *m) } void +drawtabs(void) { + Monitor *m; + + for(m = mons; m; m = m->next) + drawtab(m); +} + +void +drawtab(Monitor *m) { + Client *c; + int i; + int maxsize; + int remainder = 0; + int x = 0; + int w = 0; + + /* Calculates number of labels and their width */ + m->ntabs = 0; + for(c = m->clients; c; c = c->next){ + if(!ISVISIBLE(c)) continue; + m->tab_widths[m->ntabs] = (int)TEXTW(c->name); + ++m->ntabs; + if(m->ntabs >= MAXTABS) break; + } + + if(m->ntabs > 0) remainder = m->mw % m->ntabs; + maxsize = (1.0 / (double)m->ntabs) * m->mw; + + i = 0; + int tm; /* middle of the tab*/ + for(c = m->clients; c; c = c->next){ + if(!ISVISIBLE(c)) continue; + if(i >= m->ntabs) break; + m->tab_widths[i] = maxsize; + /* add the remainder to the last tab so there is no leftover space left*/ + if(remainder && i == m->ntabs - 1) m->tab_widths[i] += remainder; + w = m->tab_widths[i]; + drw_setscheme(drw, scheme[(c == m->sel) ? SchemeSelTab : SchemeNorm]); + tm = (m->tab_widths[i] - (int)TEXTW(c->name)) / 2; + tm = (int)TEXTW(c->name) >= m->tab_widths[i] ? lrpad / 2 : tm; + drw_text(drw, x, 0, w, th, tm, c->name, 0); + x += w; + ++i; + } + + drw_setscheme(drw, scheme[SchemeNorm]); + drw_map(drw, m->tabwin, 0, 0, m->mw, th); +} + +void drawbars(void) { Monitor *m; @@ -887,6 +964,7 @@ expose(XEvent *e) if (ev->count == 0 && (m = wintomon(ev->window))) { drawbar(m); + drawtab(m); if (m == selmon) updatesystray(); } @@ -915,6 +993,7 @@ focus(Client *c) } selmon->sel = c; drawbars(); + drawtabs(); } /* there are some broken focus acquiring clients needing extra handling */ @@ -950,16 +1029,16 @@ focusstack(const Arg *arg) return; if (arg->i > 0) { for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); - if (!c) - for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); + /* if (!c) */ + /* for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); */ } else { for (i = selmon->clients; i != selmon->sel; i = i->next) if (ISVISIBLE(i)) c = i; - if (!c) - for (; i; i = i->next) - if (ISVISIBLE(i)) - c = i; + /* if (!c) */ + /* for (; i; i = i->next) */ + /* if (ISVISIBLE(i)) */ + /* c = i; */ } if (c) { focus(c); @@ -967,6 +1046,19 @@ focusstack(const Arg *arg) } } +void +focuswin(const Arg* arg){ + int iwin = arg->i; + Client* c = NULL; + for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){ + if(ISVISIBLE(c)) --iwin; + }; + if(c) { + focus(c); + restack(selmon); + } +} + Atom getatomprop(Client *c, Atom prop) { @@ -1104,7 +1196,7 @@ grabkeys(void) void incnmaster(const Arg *arg) { - selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); arrange(selmon); } @@ -1168,6 +1260,7 @@ manage(Window w, XWindowAttributes *wa) c->w = c->oldw = wa->width; c->h = c->oldh = wa->height; c->oldbw = wa->border_width; + c->resizehints = resizehints; updatetitle(c); if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { @@ -1215,7 +1308,7 @@ manage(Window w, XWindowAttributes *wa) c->mon->sel = c; arrange(c->mon); XMapWindow(dpy, c->win); - focus(NULL); + focus(NULL); } void @@ -1374,12 +1467,14 @@ propertynotify(XEvent *e) case XA_WM_HINTS: updatewmhints(c); drawbars(); + drawtabs(); break; } if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { updatetitle(c); if (c == c->mon->sel) drawbar(c->mon); + drawtab(c->mon); } if (ev->atom == netatom[NetWMWindowType]) updatewindowtype(c); @@ -1527,6 +1622,7 @@ restack(Monitor *m) XWindowChanges wc; drawbar(m); + drawtab(m); if (!m->sel) return; if (m->sel->isfloating || !m->lt[m->sellt]->arrange) @@ -1690,9 +1786,9 @@ void setlayout(const Arg *arg) { if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) - selmon->sellt ^= 1; + selmon->sellt ^= 1; if (arg && arg->v) - selmon->lt[selmon->sellt] = (Layout *)arg->v; + selmon->lt[selmon->sellt] = (Layout *)arg->v; strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); if (selmon->sel) arrange(selmon); @@ -1711,7 +1807,7 @@ setmfact(const Arg *arg) f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; if (f < 0.05 || f > 0.95) return; - selmon->mfact = f; + selmon->mfact = f; arrange(selmon); } @@ -1742,6 +1838,7 @@ setup(void) die("no fonts could be loaded."); lrpad = drw->fonts->h; bh = drw->fonts->h + 2; + th = bh; updategeom(); /* init atoms */ utf8string = XInternAtom(dpy, "UTF8_STRING", False); @@ -1925,7 +2022,7 @@ tile(Monitor *m) void togglebar(const Arg *arg) { - selmon->showbar = !selmon->showbar; + selmon->showbar = !selmon->showbar; updatebarpos(selmon); resizebarwin(selmon); if (showsystray) { @@ -1943,6 +2040,17 @@ togglebar(const Arg *arg) } void +tabmode(const Arg *arg) +{ + if(arg && arg->i >= 0) + selmon->showtab = arg->ui % showtab_nmodes; + else + selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes; + arrange(selmon); +} + + +void togglefloating(const Arg *arg) { if (!selmon->sel) @@ -2066,6 +2174,11 @@ updatebars(void) if (showsystray && m == systraytomon(m)) XMapRaised(dpy, systray->win); XMapRaised(dpy, m->barwin); + m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor); + XMapRaised(dpy, m->tabwin); XSetClassHint(dpy, m->barwin, &ch); } } @@ -2073,18 +2186,37 @@ updatebars(void) void updatebarpos(Monitor *m) { + Client *c; + int nvis = 0; + m->wy = m->my; m->wh = m->mh; if (m->showbar) { m->wh -= bh; m->by = m->topbar ? m->wy : m->wy + m->wh; - m->wy = m->topbar ? m->wy + bh : m->wy; - } else + if ( m->topbar ) + m->wy += bh; + } else { m->by = -bh; + } + + for(c = m->clients; c; c = c->next) { + if(ISVISIBLE(c)) ++nvis; + } + + if(m->showtab == showtab_always + || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))) { + m->wh -= th; + m->ty = m->toptab ? m->wy : m->wy + m->wh; + if ( m->toptab ) + m->wy += th; + } else { + m->ty = -th; + } } void -updateclientlist() +updateclientlist(void) { Client *c; Monitor *m; @@ -2148,10 +2280,10 @@ updategeom(void) m->clients = c->next; detachstack(c); c->mon = mons; - if( attachbelow ) - attachBelow(c); - else - attach(c); + if( attachbelow ) + attachBelow(c); + else + attach(c); attachstack(c); } if (m == selmon) @@ -2472,7 +2604,7 @@ wintomon(Window w) if (w == root && getrootptr(&x, &y)) return recttomon(x, y, 1, 1); for (m = mons; m; m = m->next) - if (w == m->barwin) + if (w == m->barwin || w == m->tabwin) return m; if ((c = wintoclient(w))) return c->mon; |
