summaryrefslogtreecommitdiff
path: root/dwm.c
diff options
context:
space:
mode:
Diffstat (limited to 'dwm.c')
-rw-r--r--dwm.c210
1 files changed, 171 insertions, 39 deletions
diff --git a/dwm.c b/dwm.c
index 50e4551..7cb9c03 100644
--- a/dwm.c
+++ b/dwm.c
@@ -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;