#include <sys/wait.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
+#include <X11/XF86keysym.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
#define TAGMASK ((1 << LENGTH(tags)) - 1)
-#define TEXTW(X) (drw_font_getexts_width(drw->font, X, strlen(X)) + drw->font->h)
+#define TEXTW_NOPAD(X) drw_font_getexts_width(drw->font, X, strlen(X))
+#define TEXTW(X) (TEXTW_NOPAD(X) + drw->font->h)
/* enums */
-enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
-enum { ColBorder, ColFG, ColBG, ColLast }; /* color */
+enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */
enum { NetSupported, NetWMName, NetWMState,
- NetWMFullscreen, NetActiveWindow, NetWMWindowType,
- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
+ NetWMFullscreen, NetWMWindowOpacity, NetActiveWindow, NetWMWindowType,
+ NetWMWindowTypeDialog, NetClientList, NetSupportingWMCheck, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
- ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
+ ClkClientWin, ClkRootWin, ClkAnywhere, ClkLast }; /* clicks */
typedef union {
int i;
int oldx, oldy, oldw, oldh;
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
int bw, oldbw;
+ int opacity;
unsigned int tags;
- Bool isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+ Bool isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, screen_hog;
Client *next;
Client *snext;
Monitor *mon;
const char *title;
unsigned int tags;
Bool isfloating;
+ Bool screen_hog;
int monitor;
} Rule;
static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact);
static void arrange(Monitor *m);
static void arrangemon(Monitor *m);
+static void attach_as_master(Client *c);
static void attach(Client *c);
static void attachstack(Client *c);
static void buttonpress(XEvent *e);
static void motionnotify(XEvent *e);
static void movemouse(const Arg *arg);
static Client *nexttiled(Client *c);
+static Client *snexttiled(Client *c);
+static Client *nextvisible(Client *c);
static void pop(Client *);
static void propertynotify(XEvent *e);
static void quit(const Arg *arg);
static Monitor *recttomon(int x, int y, int w, int h);
-static void resize(Client *c, int x, int y, int w, int h, Bool interact);
-static void resizeclient(Client *c, int x, int y, int w, int h);
+static void resize(Client *c, int x, int y, int w, int h, Bool interact, Client *base);
+static void resizeclient(Client *c, int x, int y, int w, int h, Client *base);
static void resizemouse(const Arg *arg);
static void restack(Monitor *m);
static void run(void);
static void setup(void);
static void showhide(Client *c);
static void sigchld(int unused);
+static void kbspawn(const Arg *arg);
static void spawn(const Arg *arg);
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
+static void jason_layout(Monitor *);
static void tile(Monitor *);
static void togglebar(const Arg *arg);
static void togglefloating(const Arg *arg);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);
-/* variables */
+// variables
+enum { KeyBufferingOff, KeyBufferingAwaitingWindow, KeyBufferingAwaitingFocus };
+static unsigned int key_buffering = 0;
static const char broken[] = "broken";
static char stext[256];
static int screen;
-static int sw, sh; /* X display screen geometry width, height */
-static int bh, blw = 0; /* bar geometry */
+static int sw, sh; // X display screen geometry width, height
+static int bh; // bar height
static int (*xerrorxlib)(Display *, XErrorEvent *);
static unsigned int numlockmask = 0;
static void (*handler[LASTEvent]) (XEvent *) = {
static Atom wmatom[WMLast], netatom[NetLast];
static Bool running = True;
static Cur *cursor[CurLast];
-static Theme thmnorm[ColLast];
-static Theme thmsel[ColLast];
+static ClrScheme scheme[SchemeLast];
static Display *dpy;
static Drw *drw;
static Fnt *fnt;
static Monitor *mons, *selmon;
static Window root;
+// unfocused windows get transparent (feature)
+static const unsigned long opacities[] = { 0, 0xbfffffff, 0x00000000 }; // first unused
+static void window_set_opaque(Client *c);
+static void window_set_translucent(Client *c);
+static void window_set_invisible(Client *c);
+static void window_set_opacity(Client *c, int opacity_index);
+static Client* choose_slave (Client *master, Client *focused);
+static void update_window_opacities(Monitor *m);
+void
+window_set_opacity(Client *c, int opacity_index) {
+ if (c->opacity == opacity_index) {
+ return;
+ }
+ c->opacity = opacity_index;
+ if (opacity_index == 0) {
+ XDeleteProperty(dpy, c->win, netatom[NetWMWindowOpacity]);
+ } else {
+ XChangeProperty(dpy, c->win, netatom[NetWMWindowOpacity], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)(&opacities[opacity_index]), 1);
+ }
+}
+void
+window_set_opaque(Client *c) {
+ window_set_opacity(c, 0);
+}
+void
+window_set_translucent(Client *c) {
+ window_set_opacity(c, 1);
+}
+void
+window_set_invisible(Client *c) {
+ window_set_opacity(c, 2);
+}
+void
+update_window_opacities(Monitor *m) {
+ Client *master, *slave, *focused, *c;
+ Bool focused_is_floating = False;
+ master = nexttiled(m->clients);
+ focused = (m->sel && ISVISIBLE(m->sel)) ? m->sel : NULL;
+ slave = choose_slave(master, focused);
+ // detect if the focused window is floating (and visible)
+ if (master && focused && focused != slave && focused != master) {
+ if (nexttiled(focused) != focused) {
+ focused_is_floating = True;
+ }
+ }
+ // set opacity of visible floaters, master and slave
+ for (c = nextvisible(m->clients); c; c = nextvisible(c->next)) {
+ if (c->isfloating || c == focused || (focused_is_floating && (c == master || c == slave))) {
+ window_set_opaque(c);
+ } else if (c == master || c == slave) {
+ window_set_translucent(c);
+ }
+ }
+}
+
+
/* configuration, allows nested code to access above variables */
#include "config.h"
XClassHint ch = { NULL, NULL };
/* rule matching */
- c->isfloating = c->tags = 0;
+ c->isfloating = c->tags = c->screen_hog = 0;
XGetClassHint(dpy, c->win, &ch);
class = ch.res_class ? ch.res_class : broken;
instance = ch.res_name ? ch.res_name : broken;
for(i = 0; i < LENGTH(rules); i++) {
r = &rules[i];
- if((!r->title || strstr(c->name, r->title))
+ if((!r->title || c->name == strstr(c->name, r->title))
&& (!r->class || strstr(class, r->class))
&& (!r->instance || strstr(instance, r->instance)))
{
c->isfloating = r->isfloating;
+ if(r->isfloating) {
+ c->x = -1; c->y = -2; // secret code for centered
+ }
c->tags |= r->tags;
+ c->screen_hog = r->screen_hog;
for(m = mons; m && m->num != r->monitor; m = m->next);
if(m)
c->mon = m;
Bool
applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) {
Bool baseismin;
- Monitor *m = c->mon;
+ // Monitor *m = c->mon;
/* set minimum possible */
*w = MAX(1, *w);
if(*y + *h + 2 * c->bw < 0)
*y = 0;
}
- else {
- if(*x >= m->wx + m->ww)
- *x = m->wx + m->ww - WIDTH(c);
- if(*y >= m->wy + m->wh)
- *y = m->wy + m->wh - HEIGHT(c);
- if(*x + *w + 2 * c->bw <= m->wx)
- *x = m->wx;
- if(*y + *h + 2 * c->bw <= m->wy)
- *y = m->wy;
- }
+ // jason: let windows be offscreen
+ //else {
+ // if(*x >= m->wx + m->ww)
+ // *x = m->wx + m->ww - WIDTH(c);
+ // if(*y >= m->wy + m->wh)
+ // *y = m->wy + m->wh - HEIGHT(c);
+ // if(*x + *w + 2 * c->bw <= m->wx)
+ // *x = m->wx;
+ // if(*y + *h + 2 * c->bw <= m->wy)
+ // *y = m->wy;
+ //}
if(*h < bh)
*h = bh;
if(*w < bh)
}
void
-attach(Client *c) {
+attach_as_master(Client *c) {
c->next = c->mon->clients;
c->mon->clients = c;
}
+void
+attach(Client *c) {
+ if (c->mon->sel) {
+ c->next = c->mon->sel->next;
+ c->mon->sel->next = c;
+ } else {
+ attach_as_master(c);
+ }
+}
void
attachstack(Client *c) {
void
buttonpress(XEvent *e) {
- unsigned int i, x, click;
+ unsigned int i, click;
Arg arg = {0};
Client *c;
Monitor *m;
XButtonPressedEvent *ev = &e->xbutton;
+ Bool called = False;
+
+ for(i = 0; i < LENGTH(buttons); i++) {
+ if(buttons[i].click == ClkAnywhere && buttons[i].button == ev->button
+ && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) {
+ buttons[i].func(&buttons[i].arg);
+ called = True;
+ }
+ }
+ if (called) {
+ return;
+ }
click = ClkRootWin;
/* focus monitor if necessary */
focus(NULL);
}
if(ev->window == selmon->barwin) {
- i = x = 0;
- do
- x += TEXTW(tags[i]);
- while(ev->x >= x && ++i < LENGTH(tags));
- if(i < LENGTH(tags)) {
- click = ClkTagBar;
- arg.ui = 1 << i;
- }
- else if(ev->x < x + blw)
- click = ClkLtSymbol;
- else if(ev->x > selmon->ww - TEXTW(stext))
- click = ClkStatusText;
- else
- click = ClkWinTitle;
- }
- else if((c = wintoclient(ev->window))) {
+ return;
+ } else if((c = wintoclient(ev->window))) {
focus(c);
click = ClkClientWin;
}
- for(i = 0; i < LENGTH(buttons); i++)
+ 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)) {
+ if (click == ClkTagBar && buttons[i].arg.i == 0) {
+ buttons[i].func(&arg);
+ } else {
+ buttons[i].func(&buttons[i].arg);
+ }
+ }
+ }
}
void
drw_cur_free(drw, cursor[CurResize]);
drw_cur_free(drw, cursor[CurMove]);
drw_font_free(dpy, fnt);
- drw_clr_free(thmnorm->border);
- drw_clr_free(thmnorm->bg);
- drw_clr_free(thmnorm->fg);
- drw_clr_free(thmsel->border);
- drw_clr_free(thmsel->bg);
- drw_clr_free(thmsel->fg);
+ drw_clr_free(scheme[SchemeNorm].border);
+ drw_clr_free(scheme[SchemeNorm].bg);
+ drw_clr_free(scheme[SchemeNorm].fg);
+ drw_clr_free(scheme[SchemeSel].border);
+ drw_clr_free(scheme[SchemeSel].bg);
+ drw_clr_free(scheme[SchemeSel].fg);
drw_free(drw);
XSync(dpy, False);
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
}
else if(cme->message_type == netatom[NetActiveWindow]) {
+ // Jason added this so apps can't steal focus:
+ return;
if(!ISVISIBLE(c)) {
c->mon->seltags ^= 1;
c->mon->tagset[c->mon->seltags] = c->tags;
*tc = c->next;
}
+// NOTE: the stack is for z-order and most-recently-focused
+// only mon->clients determines position in visible layout
void
detachstack(Client *c) {
- Client **tc, *t;
-
- for(tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
- *tc = c->snext;
-
+ Client *prev = NULL, *next_sel = NULL, *i;
+ for(i = c->mon->stack; i && i != c; i = i->snext) {
+ prev = i;
+ }
if(c == c->mon->sel) {
- for(t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
- c->mon->sel = t;
+ // find last visible window before c
+ // WARNING if you detach() before detachstack() this will select last visible window
+ for(i = nextvisible(c->mon->clients); i && i != c; i = nextvisible(i->next))
+ next_sel = i;
+ // failing that, find first visible window (besides c)
+ if (!next_sel) {
+ for(i = nextvisible(c->mon->clients); i && i == c; i = nextvisible(i->next));
+ if (i != c)
+ next_sel = i;
+ }
+ c->mon->sel = next_sel;
+ }
+ if (prev) {
+ prev->snext = c->snext;
+ } else {
+ c->mon->stack = c->snext;
}
}
}
x = 0;
for(i = 0; i < LENGTH(tags); i++) {
- w = TEXTW(tags[i]);
- drw_settheme(drw, m->tagset[m->seltags] & 1 << i ? thmsel : thmnorm);
- drw_text(drw, x, 0, w, bh, tags[i], urg & 1 << i);
- drw_rect(drw, x, 0, w, bh, m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
- occ & 1 << i, urg & 1 << i);
+ w = TEXTW_NOPAD(tags[i]);
+ drw_setscheme(drw, m->tagset[m->seltags] & 1 << i ? &scheme[SchemeSel] : &scheme[SchemeNorm]);
+ drw_text_nopad(drw, x, 0, w, bh, tags[i], urg & 1 << i);
x += w;
}
- w = blw = TEXTW(m->ltsymbol);
- drw_settheme(drw, thmnorm);
- drw_text(drw, x, 0, w, bh, m->ltsymbol, 0);
- x += w;
xx = x;
if(m == selmon) { /* status is only drawn on selected monitor */
w = TEXTW(stext);
if((w = x - xx) > bh) {
x = xx;
if(m->sel) {
- drw_settheme(drw, m == selmon ? thmsel : thmnorm);
+ drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]);
drw_text(drw, x, 0, w, bh, m->sel->name, 0);
drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, 0);
}
else {
- drw_settheme(drw, thmnorm);
+ drw_setscheme(drw, &scheme[SchemeNorm]);
drw_text(drw, x, 0, w, bh, NULL, 0);
}
}
Monitor *m;
XCrossingEvent *ev = &e->xcrossing;
+ return; // jason: added to stop mouse focus
+
if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
return;
c = wintoclient(ev->window);
detachstack(c);
attachstack(c);
grabbuttons(c, True);
- XSetWindowBorder(dpy, c->win, thmsel->border->rgb);
+ XSetWindowBorder(dpy, c->win, scheme[SchemeSel].border->rgb);
setfocus(c);
- }
- else {
+ } else {
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
}
selmon->sel = c;
+ arrange(selmon);
+ update_window_opacities(selmon);
drawbars();
+ if(c && (!root || (c->win!=root)) )
+ window_set_opaque(c);
}
void
if(selmon->sel && ev->window != selmon->sel->win)
setfocus(selmon->sel);
+
+ if(key_buffering == KeyBufferingAwaitingFocus) {
+ key_buffering = KeyBufferingOff;
+ // there's a few ways to release the grab, with different effects (below)
+ // In this example F2 is mapped to kbspawn
+ // XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
+ // swallows key presses while F2 is still down.
+ // XAllowEvents(dpy, ReplayKeyboard, CurrentTime);
+ // sends the F2 keydown and all the queued events
+ // XUngrabKeyboard(dpy, CurrentTime);
+ // sends everything queued and the F2 key_UP_
+ XUngrabKeyboard(dpy, CurrentTime);
+ }
}
void
if(!selmon->sel)
return;
- if(arg->i > 0) {
+ if(arg->i == 0) {
+ for(i = selmon->clients; i != selmon->sel; i = i->next) {
+ if(ISVISIBLE(i)) {
+ c = i;
+ break;
+ }
+ }
+ } else 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);
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
if(focused) {
for(i = 0; i < LENGTH(buttons); i++)
- if(buttons[i].click == ClkClientWin)
+ if(buttons[i].click == ClkClientWin || buttons[i].click == ClkAnywhere)
for(j = 0; j < LENGTH(modifiers); j++)
XGrabButton(dpy, buttons[i].button,
buttons[i].mask | modifiers[j],
c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
- }
- else
+ } else {
XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
+ }
}
}
void
grabkeys(void) {
updatenumlockmask();
+ //XUngrabKey(dpy, AnyKey, AnyModifier, root);
{
unsigned int i, j;
unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
if((code = XKeysymToKeycode(dpy, keys[i].keysym)))
for(j = 0; j < LENGTH(modifiers); j++)
XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
- True, GrabModeAsync, GrabModeAsync);
+ False, // report keys to focused window too?
+ GrabModeAsync, // mouse grab mode
+ keys[i].func == kbspawn ? GrabModeSync : GrabModeAsync);
}
}
ev = &e->xkey;
keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
- for(i = 0; i < LENGTH(keys); i++)
+ for(i = 0; i < LENGTH(keys); i++) {
if(keysym == keys[i].keysym
&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
- && keys[i].func)
+ && keys[i].func) {
keys[i].func(&(keys[i].arg));
+ }
+ }
}
void
if(!(c = calloc(1, sizeof(Client))))
die("fatal: could not malloc() %u bytes\n", sizeof(Client));
+ c->opacity = -1; // who knows
c->win = w;
updatetitle(c);
if(XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
applyrules(c);
}
/* geometry */
- c->x = c->oldx = wa->x;
- c->y = c->oldy = wa->y;
+ if(c->x == -1 && c->y == -2) { // secret code for centered
+ c->x = c->oldx = (c->mon->ww - wa->width) / 2;
+ c->y = c->oldy = (c->mon->wh - wa->height) / 2;
+ } else {
+ c->x = c->oldx = wa->x;
+ c->y = c->oldy = wa->y;
+ }
c->w = c->oldw = wa->width;
c->h = c->oldh = wa->height;
c->oldbw = wa->border_width;
wc.border_width = c->bw;
XConfigureWindow(dpy, w, CWBorderWidth, &wc);
- XSetWindowBorder(dpy, w, thmnorm->border->rgb);
+ XSetWindowBorder(dpy, w, scheme[SchemeNorm].border->rgb);
configure(c); /* propagates border_width, if size doesn't change */
updatewindowtype(c);
updatesizehints(c);
c->mon->sel = c;
arrange(c->mon);
XMapWindow(dpy, c->win);
- focus(NULL);
+ focus(c);
+ if(key_buffering == KeyBufferingAwaitingWindow) {
+ // almost there! but wait until we are notified that it has focus
+ key_buffering = KeyBufferingAwaitingFocus;
+ }
}
void
mappingnotify(XEvent *e) {
XMappingEvent *ev = &e->xmapping;
+ // fprintf(stderr, "MapNotify\n");
XRefreshKeyboardMapping(ev);
if(ev->request == MappingKeyboard)
static XWindowAttributes wa;
XMapRequestEvent *ev = &e->xmaprequest;
+ // fprintf(stderr, "MapRequest\n");
if(!XGetWindowAttributes(dpy, ev->window, &wa))
return;
- if(wa.override_redirect)
+ if(wa.override_redirect) {
return;
+ }
if(!wintoclient(ev->window))
manage(ev->window, &wa);
}
n++;
if(n > 0) /* override layout symbol */
snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
- for(c = nexttiled(m->clients); c; c = nexttiled(c->next))
- resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False);
+ for(c = snexttiled(m->stack); c; c = snexttiled(c->snext)) {
+ if (c == m->sel) {
+ resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False, 0);
+ } else {
+ // this window is should not be visible. move off top, but don't change h/w
+ resize(c, m->wx, m->wy - 4000, c->w, c->h, False, 0);
+ }
+ }
}
void
Client *c;
Monitor *m;
XEvent ev;
+ Time lasttime = 0;
if(!(c = selmon->sel))
return;
handler[ev.type](&ev);
break;
case MotionNotify:
+ if ((ev.xmotion.time - lasttime) <= (1000 / 60))
+ continue;
+ lasttime = ev.xmotion.time;
+
nx = ocx + (ev.xmotion.x - x);
ny = ocy + (ev.xmotion.y - y);
if(nx >= selmon->wx && nx <= selmon->wx + selmon->ww
togglefloating(NULL);
}
if(!selmon->lt[selmon->sellt]->arrange || c->isfloating)
- resize(c, nx, ny, c->w, c->h, True);
+ resize(c, nx, ny, c->w, c->h, True, 0);
break;
}
} while(ev.type != ButtonRelease);
return c;
}
+Client *
+snexttiled(Client *c) {
+ for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->snext);
+ return c;
+}
+
+Client *
+nextvisible(Client *c) {
+ for(; c && !ISVISIBLE(c); c = c->next);
+ return c;
+}
+
void
pop(Client *c) {
detach(c);
- attach(c);
+ attach_as_master(c);
focus(c);
arrange(c->mon);
}
}
void
-resize(Client *c, int x, int y, int w, int h, Bool interact) {
+resize(Client *c, int x, int y, int w, int h, Bool interact, Client *base) {
if(applysizehints(c, &x, &y, &w, &h, interact))
- resizeclient(c, x, y, w, h);
+ resizeclient(c, x, y, w, h, base);
}
void
-resizeclient(Client *c, int x, int y, int w, int h) {
+resizeclient(Client *c, int x, int y, int w, int h, Client *base) {
XWindowChanges wc;
+ unsigned long mask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
c->oldx = c->x; c->x = wc.x = x;
c->oldy = c->y; c->y = wc.y = y;
c->oldw = c->w; c->w = wc.width = w;
c->oldh = c->h; c->h = wc.height = h;
+ // base = 0;
+ if (base) {
+ wc.stack_mode = Above;
+ wc.sibling = base->win;
+ mask |= CWStackMode|CWSibling;
+ }
wc.border_width = c->bw;
- XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
+ XConfigureWindow(dpy, c->win, mask, &wc);
configure(c);
XSync(dpy, False);
}
void
resizemouse(const Arg *arg) {
- int ocx, ocy;
- int nw, nh;
+ int ocx, ocy, nw, nh;
Client *c;
Monitor *m;
XEvent ev;
+ Time lasttime = 0;
if(!(c = selmon->sel))
return;
handler[ev.type](&ev);
break;
case MotionNotify:
+ if ((ev.xmotion.time - lasttime) <= (1000 / 60))
+ continue;
+ lasttime = ev.xmotion.time;
+
nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
if(c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
togglefloating(NULL);
}
if(!selmon->lt[selmon->sellt]->arrange || c->isfloating)
- resize(c, c->x, c->y, nw, nh, True);
+ resize(c, c->x, c->y, nw, nh, True, 0);
break;
}
} while(ev.type != ButtonRelease);
if(m->lt[m->sellt]->arrange) {
wc.stack_mode = Below;
wc.sibling = m->barwin;
- for(c = m->stack; c; c = c->snext)
+ for(c = m->clients; c; c = c->next)
if(!c->isfloating && ISVISIBLE(c)) {
XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
wc.sibling = c->win;
+ wc.stack_mode = Above;
}
}
XSync(dpy, False);
XEvent ev;
/* main event loop */
XSync(dpy, False);
- while(running && !XNextEvent(dpy, &ev))
- if(handler[ev.type])
+ while(running && !XNextEvent(dpy, &ev)) {
+ if(handler[ev.type]) {
+ // fprintf(stderr, "handling event type %i\n", ev.type);
handler[ev.type](&ev); /* call handler */
+ } else {
+ // fprintf(stderr, "evt type %i\n", ev.type);
+ }
+ }
}
void
if(c->mon == m)
return;
unfocus(c, True);
- detach(c);
detachstack(c);
+ detach(c);
c->mon = m;
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
attach(c);
if(!c->neverfocus) {
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
XChangeProperty(dpy, root, netatom[NetActiveWindow],
- XA_WINDOW, 32, PropModeReplace,
- (unsigned char *) &(c->win), 1);
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &(c->win), 1);
}
sendevent(c, wmatom[WMTakeFocus]);
}
c->oldbw = c->bw;
c->bw = 0;
c->isfloating = True;
- resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh, 0);
XRaiseWindow(dpy, c->win);
}
else {
c->y = c->oldy;
c->w = c->oldw;
c->h = c->oldh;
- resizeclient(c, c->x, c->y, c->w, c->h);
+ resizeclient(c, c->x, c->y, c->w, c->h, 0);
arrange(c->mon);
}
}
netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
+ netatom[NetWMWindowOpacity] = XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False);
netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
+ netatom[NetSupportingWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
+ XInternAtom(dpy, "_MOTIF_WM_HINTS", False); /* clients may request borderless/fullscreen */
/* init cursors */
cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
cursor[CurMove] = drw_cur_create(drw, XC_fleur);
/* init appearance */
- thmnorm->border = drw_clr_create(drw, normbordercolor);
- thmnorm->bg = drw_clr_create(drw, normbgcolor);
- thmnorm->fg = drw_clr_create(drw, normfgcolor);
- thmsel->border = drw_clr_create(drw, selbordercolor);
- thmsel->bg = drw_clr_create(drw, selbgcolor);
- thmsel->fg = drw_clr_create(drw, selfgcolor);
+ scheme[SchemeNorm].border = drw_clr_create(drw, normbordercolor);
+ scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor);
+ scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor);
+ scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor);
+ scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor);
+ scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor);
/* init bars */
updatebars();
updatestatus();
XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
XSelectInput(dpy, root, wa.event_mask);
grabkeys();
+ focus(NULL);
}
void
if(ISVISIBLE(c)) { /* show clients top down */
XMoveWindow(dpy, c->win, c->x, c->y);
if((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
- resize(c, c->x, c->y, c->w, c->h, False);
+ resize(c, c->x, c->y, c->w, c->h, False, 0);
showhide(c->snext);
}
else { /* hide clients bottom up */
}
void
+kbspawn(const Arg *arg) {
+ key_buffering = True;
+ spawn(arg);
+}
+
+void
spawn(const Arg *arg) {
+ int tag = 0, i;
+ if(arg->v == termcmd || arg->v == belltermcmd || arg->v == runcmd) {
+ for(i = 0; i < 32; ++i) {
+ if(selmon->tagset[selmon->seltags] & (1 << i)) {
+ tag = i;
+ break;
+ }
+ }
+ WORKSPACE_NUMBER[17] = workspace_numbers_str[tag][0];
+ WORKSPACE_NUMBER[18] = workspace_numbers_str[tag][1]; // 2nd digit or null
+ }
+ if(arg->v == dmenucmd)
+ dmenumon[0] = '0' + selmon->num;
if(fork() == 0) {
if(dpy)
close(ConnectionNumber(dpy));
if(n > m->nmaster)
mw = m->nmaster ? m->ww * m->mfact : 0;
- else
- mw = m->ww;
+ else {
+ c = nexttiled(m->clients);
+ if (c && !c->screen_hog)
+ mw = m->ww * m->mfact;
+ else
+ mw = m->ww;
+ }
for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
if(i < m->nmaster) {
h = (m->wh - my) / (MIN(n, m->nmaster) - i);
- resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False);
+ resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False, 0);
my += HEIGHT(c);
}
else {
h = (m->wh - ty) / (n - i);
- resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), False);
+ resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), False, 0);
ty += HEIGHT(c);
}
}
+// search forward from start, return the last client before end
+Client*
+prev_tiled (Client *start, Client *end) {
+ Client *w, *n;
+ for (w = start; w && (n = nexttiled(w->next)); w = n) {
+ if (n == end) {
+ return w;
+ }
+ }
+ return NULL;
+}
+
+// return the window to show on the right side
+Client*
+choose_slave (Client *master, Client *focused) {
+ if (!master) {
+ return NULL;
+ }
+ if (focused) {
+ // FIXME put this same algorithm in update_window_opacities
+ if (focused->isfloating) {
+ // show the window just "under" it
+ Client *prev = prev_tiled(master, focused);
+ // fall back to the first slave
+ if (prev && prev != master) {
+ return prev;
+ } else {
+ return nexttiled(master->next);
+ }
+ } else {
+ // focused window is tiled
+ if (focused == master) {
+ // master is focused, show first slave
+ return nexttiled(master->next);
+ } else {
+ // focused window is a slave, so show that one
+ return focused;
+ }
+ }
+ }
+ // maybe we get called when there's no focused?
+ return nexttiled(master->next);
+}
+
+#define GUTTER_PX 4
+
+void
+jason_layout(Monitor *m) {
+ Client *c, *master, *slave, *focused, *base = 0;
+ unsigned int master_width, slave_width, slave_left;
+
+ // find master
+ master = nexttiled(m->clients);
+
+ // no master? nothing to do
+ if (!master) {
+ return;
+ }
+
+ // find focused and slave
+ focused = (m->sel && ISVISIBLE(m->sel)) ? m->sel : NULL;
+ slave = choose_slave(master, focused);
+
+ // calculate window widths
+ if (!slave && master->screen_hog) {
+ master_width = m->ww;
+ } else {
+ master_width = m->ww * m->mfact - GUTTER_PX / 2;
+ }
+ slave_left = m->ww * m->mfact + GUTTER_PX / 2;
+ slave_width = m->ww * (1 - m->mfact) - GUTTER_PX / 2;
+
+ // resize/reposition master
+ resize(master,
+ m->wx,
+ m->wy,
+ master_width,
+ m->wh,
+ False,
+ 0
+ );
+ // resize/reposition slaves
+ base = master; // window to be above in the stacking order
+ for (c = nexttiled(master->next); c; c = nexttiled(c->next)) {
+ resize(c,
+ slave_left,
+ c == slave ? m->wy : m->wy - m->wh,
+ slave_width,
+ m->wh,
+ False,
+ base
+ );
+ base = c;
+ }
+}
+
void
togglebar(const Arg *arg) {
selmon->showbar = !selmon->showbar;
selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
if(selmon->sel->isfloating)
resize(selmon->sel, selmon->sel->x, selmon->sel->y,
- selmon->sel->w, selmon->sel->h, False);
+ selmon->sel->w, selmon->sel->h, False, 0);
arrange(selmon);
}
if(!c)
return;
grabbuttons(c, False);
- XSetWindowBorder(dpy, c->win, thmnorm->border->rgb);
+ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->rgb);
if(setfocus) {
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
XWindowChanges wc;
/* The server grab construct avoids race conditions. */
- detach(c);
detachstack(c);
+ detach(c);
if(!destroyed) {
wc.border_width = c->oldbw;
XGrabServer(dpy);
XUngrabServer(dpy);
}
free(c);
- focus(NULL);
+ focus(selmon ? selmon->sel : NULL);
updateclientlist();
arrange(m);
}
m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
+ XChangeProperty(dpy, root, netatom[NetSupportingWMCheck], XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *) &(m->barwin), 1);
+ XChangeProperty(dpy, m->barwin, netatom[NetSupportingWMCheck], XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *) &(m->barwin), 1);
+ XChangeProperty(dpy, m->barwin, netatom[NetWMName], XA_STRING, 8,
+ PropModeReplace, (unsigned char *) "dwm", 3);
XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
XMapRaised(dpy, m->barwin);
}
int
main(int argc, char *argv[]) {
if(argc == 2 && !strcmp("-v", argv[1]))
- die("dwm-"VERSION", © 2006-2012 dwm engineers, see LICENSE for details\n");
+ die("dwm-"VERSION", © 2006-2014 dwm engineers, see LICENSE for details\n");
else if(argc != 1)
die("usage: dwm [-v]\n");
if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())