#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
+#include <X11/XKBlib.h>
#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
#endif /* XINERAMA */
enum { ColBorder, ColFG, ColBG, ColLast }; /* color */
enum { NetSupported, NetWMName, NetWMState,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
- NetWMWindowTypeDialog, NetLast }; /* EWMH atoms */
+ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
static void unfocus(Client *c, Bool setfocus);
static void unmanage(Client *c, Bool destroyed);
static void unmapnotify(XEvent *e);
-static Bool updategeom(void);
+static void updategeom(void);
static void updatebarpos(Monitor *m);
static void updatebars(void);
+static void updateclientlist(void);
static void updatenumlockmask(void);
static void updatesizehints(Client *c);
static void updatestatus(void);
showhide(m->stack);
else for(m = mons; m; m = m->next)
showhide(m->stack);
- if(m)
+ if(m) {
arrangemon(m);
- else for(m = mons; m; m = m->next)
+ restack(m);
+ } else for(m = mons; m; m = m->next)
arrangemon(m);
}
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
if(m->lt[m->sellt]->arrange)
m->lt[m->sellt]->arrange(m);
- restack(m);
}
void
cleanupmon(mons);
XSync(dpy, False);
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
}
void
configurenotify(XEvent *e) {
Monitor *m;
XConfigureEvent *ev = &e->xconfigure;
- Bool dirty;
if(ev->window == root) {
- dirty = (sw != ev->width);
sw = ev->width;
sh = ev->height;
- if(updategeom() || dirty) {
- if(dc.drawable != 0)
- XFreePixmap(dpy, dc.drawable);
- dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
- updatebars();
- for(m = mons; m; m = m->next)
- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
- focus(NULL);
- arrange(NULL);
- }
+ if(dc.drawable != 0)
+ XFreePixmap(dpy, dc.drawable);
+ dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
+ updatebars();
+ for(m = mons; m; m = m->next)
+ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
+ focus(NULL);
+ arrange(NULL);
}
}
XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
setfocus(c);
}
- else
+ else {
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+ }
selmon->sel = c;
drawbars();
}
return;
if((m = dirtomon(arg->i)) == selmon)
return;
- unfocus(selmon->sel, True);
+ unfocus(selmon->sel, False); /* s/True/False/ fixes input focus issues
+ in gedit and anjuta */
selmon = m;
focus(NULL);
}
static Bool
isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) {
while(n--)
- if(unique[n].x_org == info->x_org && unique[n].y_org == info->y_org
- && unique[n].width == info->width && unique[n].height == info->height)
+ /* treat origin (x, y) as fixpoint for uniqueness only, first screen wins */
+ if(unique[n].x_org == info->x_org && unique[n].y_org == info->y_org)
return False;
return True;
}
XKeyEvent *ev;
ev = &e->xkey;
- keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
+ keysym = XkbKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0, 0);
for(i = 0; i < LENGTH(keys); i++)
if(keysym == keys[i].keysym
&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
XRaiseWindow(dpy, c->win);
attach(c);
attachstack(c);
+ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
+ (unsigned char *) &(c->win), 1);
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
setclientstate(c, NormalState);
if (c->mon == selmon)
if(ev->window != root)
return;
if((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
+ unfocus(selmon->sel, True);
selmon = m;
focus(NULL);
}
if(!(c = selmon->sel))
return;
+ if(c->isfullscreen) /* no support moving fullscreen windows by mouse */
+ return;
restack(selmon);
ocx = c->x;
ocy = c->y;
if(!(c = selmon->sel))
return;
+ if(c->isfullscreen) /* no support resizing fullscreen windows by mouse */
+ return;
restack(selmon);
ocx = c->x;
ocy = c->y;
void
setfocus(Client *c) {
- if(!c->neverfocus)
+ if(!c->neverfocus) {
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
+ XChangeProperty(dpy, root, netatom[NetActiveWindow],
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &(c->win), 1);
+ }
sendevent(c, wmatom[WMTakeFocus]);
}
netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", 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);
/* init cursors */
cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
/* EWMH support per view */
XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
PropModeReplace, (unsigned char *) netatom, NetLast);
+ XDeleteProperty(dpy, root, netatom[NetClientList]);
/* select for events */
wa.cursor = cursor[CurNormal];
wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask
togglefloating(const Arg *arg) {
if(!selmon->sel)
return;
+ if(selmon->sel->isfullscreen) /* no support for fullscreen windows */
+ return;
selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
if(selmon->sel->isfloating)
resize(selmon->sel, selmon->sel->x, selmon->sel->y,
return;
grabbuttons(c, False);
XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]);
- if(setfocus)
+ if(setfocus) {
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+ }
}
void
}
free(c);
focus(NULL);
+ updateclientlist();
arrange(m);
}
.event_mask = ButtonPressMask|ExposureMask
};
for(m = mons; m; m = m->next) {
+ if (m->barwin)
+ continue;
m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
m->by = -bh;
}
-Bool
+void
+updateclientlist() {
+ Client *c;
+ Monitor *m;
+
+ XDeleteProperty(dpy, root, netatom[NetClientList]);
+ for(m = mons; m; m = m->next)
+ for(c = m->clients; c; c = c->next)
+ XChangeProperty(dpy, root, netatom[NetClientList],
+ XA_WINDOW, 32, PropModeAppend,
+ (unsigned char *) &(c->win), 1);
+}
+
+void
updategeom(void) {
- Bool dirty = False;
+ /* Starting with dwm 6.1 this function uses a new (simpler) strategy:
+ * whenever screen changes are reported, we destroy all monitors
+ * and recreate all unique origin monitors and add all clients to
+ * the first monitor, only. In several circumstances this may suck,
+ * but dealing with all corner-cases sucks even more.*/
#ifdef XINERAMA
if(XineramaIsActive(dpy)) {
- int i, j, n, nn;
+ int i, j, n;
Client *c;
- Monitor *m;
- XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn);
+ Monitor *m, *oldmons = mons;
+ XineramaScreenInfo *info = XineramaQueryScreens(dpy, &n);
XineramaScreenInfo *unique = NULL;
- for(n = 0, m = mons; m; m = m->next, n++);
/* only consider unique geometries as separate screens */
- if(!(unique = (XineramaScreenInfo *)malloc(sizeof(XineramaScreenInfo) * nn)))
- die("fatal: could not malloc() %u bytes\n", sizeof(XineramaScreenInfo) * nn);
- for(i = 0, j = 0; i < nn; i++)
+ if(!(unique = (XineramaScreenInfo *)malloc(sizeof(XineramaScreenInfo) * n)))
+ die("fatal: could not malloc() %u bytes\n", sizeof(XineramaScreenInfo) * n);
+ for(i = 0, j = 0; i < n; i++)
if(isuniquegeom(unique, j, &info[i]))
memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
XFree(info);
- nn = j;
- if(n <= nn) {
- for(i = 0; i < (nn - n); i++) { /* new monitors available */
- for(m = mons; m && m->next; m = m->next);
- if(m)
- m->next = createmon();
- else
- mons = createmon();
- }
- for(i = 0, m = mons; i < nn && m; m = m->next, i++)
- if(i >= n
- || (unique[i].x_org != m->mx || unique[i].y_org != m->my
- || unique[i].width != m->mw || unique[i].height != m->mh))
- {
- dirty = True;
- m->num = i;
- m->mx = m->wx = unique[i].x_org;
- m->my = m->wy = unique[i].y_org;
- m->mw = m->ww = unique[i].width;
- m->mh = m->wh = unique[i].height;
- updatebarpos(m);
- }
+ /* create new monitor structure */
+ n = j;
+ mons = m = createmon(); /* new first monitor */
+ for(i = 1; i < n; i++) {
+ m->next = createmon();
+ m = m->next;
}
- else { /* less monitors available nn < n */
- for(i = nn; i < n; i++) {
- for(m = mons; m && m->next; m = m->next);
- while(m->clients) {
- dirty = True;
- c = m->clients;
- m->clients = c->next;
- detachstack(c);
- c->mon = mons;
- attach(c);
- attachstack(c);
- }
- if(m == selmon)
- selmon = mons;
- cleanupmon(m);
- }
+ for(i = 0, m = mons; i < n && m; m = m->next, i++) {
+ m->num = i;
+ m->mx = m->wx = unique[i].x_org;
+ m->my = m->wy = unique[i].y_org;
+ m->mw = m->ww = unique[i].width;
+ m->mh = m->wh = unique[i].height;
+ updatebarpos(m);
}
free(unique);
+ /* re-attach old clients and cleanup old monitor structure */
+ while(oldmons) {
+ m = oldmons;
+ while(m->clients) {
+ c = m->clients;
+ m->clients = c->next;
+ detachstack(c);
+ c->mon = mons;
+ attach(c);
+ attachstack(c);
+ }
+ oldmons = m->next;
+ cleanupmon(m);
+ }
}
else
#endif /* XINERAMA */
/* default monitor setup */
{
- if(!mons)
+ if(!mons) /* only true if !XINERAMA compile flag */
mons = createmon();
if(mons->mw != sw || mons->mh != sh) {
- dirty = True;
mons->mw = mons->ww = sw;
mons->mh = mons->wh = sh;
updatebarpos(mons);
}
}
- if(dirty) {
- selmon = mons;
- selmon = wintomon(root);
- }
- return dirty;
+ selmon = mons;
+ selmon = wintomon(root);
}
void
if(state == netatom[NetWMFullscreen])
setfullscreen(c, True);
-
if(wtype == netatom[NetWMWindowTypeDialog])
c->isfloating = True;
}
int
main(int argc, char *argv[]) {
if(argc == 2 && !strcmp("-v", argv[1]))
- die("dwm-"VERSION", © 2006-2011 dwm engineers, see LICENSE for details\n");
+ die("dwm-"VERSION", © 2006-2012 dwm engineers, see LICENSE for details\n");
else if(argc != 1)
die("usage: dwm [-v]\n");
if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())