diff options
Diffstat (limited to 'x11-wm/dwm/files/dwm-6.0-userscripts.patch')
-rw-r--r-- | x11-wm/dwm/files/dwm-6.0-userscripts.patch | 2071 |
1 files changed, 2071 insertions, 0 deletions
diff --git a/x11-wm/dwm/files/dwm-6.0-userscripts.patch b/x11-wm/dwm/files/dwm-6.0-userscripts.patch new file mode 100644 index 0000000..d22277f --- /dev/null +++ b/x11-wm/dwm/files/dwm-6.0-userscripts.patch @@ -0,0 +1,2071 @@ +From: Elijah El Lazkani <ThyArmageddon+Gentoo@Gmail.com> +Date: Thu Marh 28 21:00:00 UTC 2013 +Subject: Patching DWM adding userscripts to it from: https://bitbucket.org/jceb81/dwm-patches + + +--- config.def.h ++++ config.def.h +@@ -1,15 +1,19 @@ + /* See LICENSE file for copyright and license details. */ + + /* appearance */ +-static const char font[] = "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*"; ++static const char font[] = "-misc-fixed-medium-r-semicondensed-*-13-120-75-75-c-60-iso10646-1"; + static const char normbordercolor[] = "#444444"; + static const char normbgcolor[] = "#222222"; + static const char normfgcolor[] = "#bbbbbb"; +-static const char selbordercolor[] = "#005577"; ++static const char selbordercolor[] = "#ff0000"; + static const char selbgcolor[] = "#005577"; + static const char selfgcolor[] = "#eeeeee"; ++static const char floatnormbordercolor[] = "#885599"; ++static const char floatselbordercolor[] = "#ff0000"; + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ ++static const unsigned int systrayspacing = 2; /* systray spacing */ ++static const Bool showsystray = True; /* False means no systray */ + static const Bool showbar = True; /* False means no bar */ + static const Bool topbar = True; /* False means bottom bar */ + +@@ -17,13 +21,20 @@ static const Bool topbar = Tr + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + + static const Rule rules[] = { ++ /* xprop(1): ++ * WM_CLASS(STRING) = instance, class ++ * WM_NAME(STRING) = title ++ */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, True, -1 }, + { "Firefox", NULL, NULL, 1 << 8, False, -1 }, ++ { "Pidgin", NULL, NULL, 0, True, -1 }, ++ { "Skype", NULL, NULL, 0, True, -1 }, ++ { "Kio_uiserver", NULL, NULL, 0, True, -1 }, + }; + + /* layout(s) */ +-static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ ++static const float mfact = 0.65; /* factor of master area size [0.05..0.95] */ + static const int nmaster = 1; /* number of clients in master area */ + static const Bool resizehints = True; /* True means respect size hints in tiled resizals */ + +@@ -35,7 +46,7 @@ static const Layout layouts[] = { + }; + + /* key definitions */ +-#define MODKEY Mod1Mask ++#define MODKEY Mod4Mask + #define TAGKEYS(KEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ +@@ -47,8 +58,14 @@ static const Layout layouts[] = { + + /* commands */ + static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL }; +-static const char *termcmd[] = { "uxterm", NULL }; ++static const char *termcmd[] = { "x-terminal-emulator", NULL }; + ++#include "moveresize.c" ++#include "tagall.c" ++#include "maximize.c" ++#include "push.c" ++#include "focusmaster.c" ++#include "shifttags.c" + static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, +@@ -56,11 +73,14 @@ static Key keys[] = { + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, ++ { MODKEY|ShiftMask, XK_j, pushdown, {0} }, ++ { MODKEY|ShiftMask, XK_k, pushup, {0} }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, +- { MODKEY, XK_d, incnmaster, {.i = -1 } }, ++ { MODKEY, XK_o, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY, XK_Return, zoom, {0} }, ++ { Mod1Mask, XK_Tab, swapfocus, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY|ShiftMask, XK_c, killclient, {0} }, + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, +@@ -83,7 +103,37 @@ static Key keys[] = { + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) ++ { MODKEY, XK_q, quit, {1} }, + { MODKEY|ShiftMask, XK_q, quit, {0} }, ++ { MODKEY|ControlMask, XK_l, togglehorizontalmax, {0} }, ++ { MODKEY|ControlMask, XK_h, togglehorizontalmax, {0} }, ++ { MODKEY|ControlMask, XK_j, toggleverticalmax, {0} }, ++ { MODKEY|ControlMask, XK_k, toggleverticalmax, {0} }, ++ { MODKEY|ControlMask, XK_m, togglemaximize, {0} }, ++ { MODKEY|ShiftMask, XK_F1, tagall, {.v = "F1" } }, ++ { MODKEY|ShiftMask, XK_F2, tagall, {.v = "F2" } }, ++ { MODKEY|ShiftMask, XK_F3, tagall, {.v = "F3" } }, ++ { MODKEY|ShiftMask, XK_F4, tagall, {.v = "F4" } }, ++ { MODKEY|ShiftMask, XK_F5, tagall, {.v = "F5" } }, ++ { MODKEY|ShiftMask, XK_F6, tagall, {.v = "F6" } }, ++ { MODKEY|ShiftMask, XK_F7, tagall, {.v = "F7" } }, ++ { MODKEY|ShiftMask, XK_F8, tagall, {.v = "F8" } }, ++ { MODKEY|ShiftMask, XK_F9, tagall, {.v = "F9" } }, ++ { MODKEY, XK_a, moveresize, {.v = "-10x 0y 0w 0h" } }, ++ { MODKEY, XK_d, moveresize, {.v = "10x 0y 0w 0h" } }, ++ { MODKEY, XK_s, moveresize, {.v = "0x 10y 0w 0h" } }, ++ { MODKEY, XK_w, moveresize, {.v = "0x -10y 0w 0h" } }, ++ { MODKEY|ControlMask, XK_a, moveresize, {.v = "0X 0y 0w 0h" } }, ++ { MODKEY|ControlMask, XK_d, moveresize, {.v = "9000X 0y 0w 0h" } }, ++ { MODKEY|ControlMask, XK_s, moveresize, {.v = "0x 9000Y 0w 0h" } }, ++ { MODKEY|ControlMask, XK_w, moveresize, {.v = "0x 15Y 0w 0h" } }, ++ { MODKEY|ShiftMask, XK_a, moveresize, {.v = "0x 0y -10w 0h" } }, ++ { MODKEY|ShiftMask, XK_d, moveresize, {.v = "0x 0y 10w 0h" } }, ++ { MODKEY|ShiftMask, XK_s, moveresize, {.v = "0x 0y 0w 10h" } }, ++ { MODKEY|ShiftMask, XK_w, moveresize, {.v = "0x 0y 0w -10h" } }, ++ { MODKEY|ControlMask, XK_Return, focusmaster, {0} }, ++ { MODKEY, XK_Left, shifttags, {.i = -1} }, ++ { MODKEY, XK_Right, shifttags, {.i = +1} }, + }; + + /* button definitions */ + +--- config.mk ++++ config.mk +@@ -10,20 +10,19 @@ MANPREFIX = ${PREFIX}/share/man + X11INC = /usr/X11R6/include + X11LIB = /usr/X11R6/lib + +-# Xinerama +-XINERAMALIBS = -L${X11LIB} -lXinerama ++# Xinerama, comment if you don't want it ++XINERAMALIBS = -lXinerama + XINERAMAFLAGS = -DXINERAMA + + # includes and libs +-INCS = -I. -I/usr/include -I${X11INC} +-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS} ++INCS = -I${X11INC} ++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} + + # flags +-CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +-#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} +-CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} +-#LDFLAGS = -g ${LIBS} +-LDFLAGS = -s ${LIBS} ++CPPFLAGS = -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} ++#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} ++CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} ++LDFLAGS = -s ${LIBS} + + # Solaris + #CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" + +--- dwm.c ++++ dwm.c +@@ -36,6 +36,7 @@ + #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 */ +@@ -45,7 +46,7 @@ + #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) + #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 ISVISIBLE(C, M) ((C->tags & M->tagset[M->seltags])) + #define LENGTH(X) (sizeof X / sizeof X[0]) + #define MAX(A, B) ((A) > (B) ? (A) : (B)) + #define MIN(A, B) ((A) < (B) ? (A) : (B)) +@@ -55,12 +56,30 @@ + #define TAGMASK ((1 << LENGTH(tags)) - 1) + #define TEXTW(X) (textnw(X, strlen(X)) + dc.font.height) + ++#define SYSTEM_TRAY_REQUEST_DOCK 0 ++#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0 ++ ++/* XEMBED messages */ ++#define XEMBED_EMBEDDED_NOTIFY 0 ++#define XEMBED_WINDOW_ACTIVATE 1 ++#define XEMBED_FOCUS_IN 4 ++#define XEMBED_MODALITY_ON 10 ++ ++#define XEMBED_MAPPED (1 << 0) ++#define XEMBED_WINDOW_ACTIVATE 1 ++#define XEMBED_WINDOW_DEACTIVATE 2 ++ ++#define VERSION_MAJOR 0 ++#define VERSION_MINOR 0 ++#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR ++ + /* enums */ + enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +-enum { ColBorder, ColFG, ColBG, ColLast }; /* color */ +-enum { NetSupported, NetWMName, NetWMState, +- NetWMFullscreen, NetActiveWindow, NetWMWindowType, +- NetWMWindowTypeDialog, NetLast }; /* EWMH atoms */ ++enum { ColBorder, ColFG, ColBG, ColBorderFloat, ColLast }; /* color */ ++enum { NetSupported, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, ++ NetWMName, NetWMState, 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, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +@@ -86,11 +105,12 @@ struct Client { + char name[256]; + float mina, maxa; + int x, y, w, h; ++ int sfx, sfy, sfw, sfh; /* stored float geometry, used on mode revert */ + int oldx, oldy, oldw, oldh; + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; +- Bool isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; ++ Bool ismax, wasfloating, isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + Client *next; + Client *snext; + Monitor *mon; +@@ -124,6 +144,8 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++typedef struct Pertag Pertag; ++typedef struct Clientlist Clientlist; + struct Monitor { + char ltsymbol[16]; + float mfact; +@@ -137,12 +159,12 @@ struct Monitor { + unsigned int tagset[2]; + Bool showbar; + Bool topbar; +- Client *clients; ++ Clientlist *cl; + Client *sel; +- Client *stack; + Monitor *next; + Window barwin; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -154,12 +176,25 @@ typedef struct { + int monitor; + } Rule; + ++typedef struct Systray Systray; ++struct Systray { ++ Window win; ++ Client *icons; ++}; ++ ++struct Clientlist { ++ Client *clients; ++ Client *stack; ++}; ++ + /* function declarations */ + static void applyrules(Client *c); + 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(Client *c); ++static void attachabove(Client *c); ++static void attachclients(Monitor *m); + static void attachstack(Client *c); + static void buttonpress(XEvent *e); + static void checkotherwm(void); +@@ -186,9 +221,11 @@ static void focus(Client *c); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); ++static Atom getatomprop(Client *c, Atom prop); + static unsigned long getcolor(const char *colstr); + static Bool getrootptr(int *x, int *y); + static long getstate(Window w); ++static unsigned int getsystraywidth(); + static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, Bool focused); + static void grabkeys(void); +@@ -202,18 +239,21 @@ static void maprequest(XEvent *e); + static void monocle(Monitor *m); + static void motionnotify(XEvent *e); + static void movemouse(const Arg *arg); +-static Client *nexttiled(Client *c); ++static Client *nexttiled(Client *c, Monitor *m); + 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 removesystrayicon(Client *i); + static void resize(Client *c, int x, int y, int w, int h, Bool interact); ++static void resizebarwin(Monitor *m); + static void resizeclient(Client *c, int x, int y, int w, int h); + static void resizemouse(const Arg *arg); ++static void resizerequest(XEvent *e); + static void restack(Monitor *m); + static void run(void); + static void scan(void); +-static Bool sendevent(Client *c, Atom proto); ++static Bool sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); + static void sendmon(Client *c, Monitor *m); + static void setclientstate(Client *c, long state); + static void setfocus(Client *c); +@@ -224,6 +264,7 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static void swapfocus(); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static int textnw(const char *text, unsigned int len); +@@ -238,21 +279,30 @@ static void unmapnotify(XEvent *e); + static Bool 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); ++static void updatesystray(void); ++static void updatesystrayicongeom(Client *i, int w, int h); ++static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); + static void updatewindowtype(Client *c); + static void updatetitle(Client *c); + static void updatewmhints(Client *c); + static void view(const Arg *arg); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); ++static Client *wintosystrayicon(Window w); + static int xerror(Display *dpy, XErrorEvent *ee); + static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); + static void zoom(const Arg *arg); + + /* variables */ ++static Systray *systray = NULL; ++static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ; ++static Client *prevclient = NULL; ++static Client *prevzoom = NULL; + static const char broken[] = "broken"; + static char stext[256]; + static int screen; +@@ -274,19 +324,31 @@ static void (*handler[LASTEvent]) (XEven + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, ++ [ResizeRequest] = resizerequest, + [UnmapNotify] = unmapnotify + }; +-static Atom wmatom[WMLast], netatom[NetLast]; ++static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; + static Bool running = True; ++static Bool restart = False; + static Cursor cursor[CurLast]; + static Display *dpy; + static DC dc; + static Monitor *mons = NULL, *selmon = NULL; + static Window root; ++static Clientlist *cl; + + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++struct Pertag { ++ unsigned int curtag, prevtag; /* current and previous tag */ ++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ ++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ ++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ ++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++ Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -313,7 +375,7 @@ applyrules(Client *c) { + { + c->isfloating = r->isfloating; + c->tags |= r->tags; +- for(m = mons; m && m->num != r->monitor; m = m->next); ++ for(m = mons; m && (m->tagset[m->seltags] & c->tags) == 0; m = m->next) ; + if(m) + c->mon = m; + } +@@ -394,12 +456,13 @@ applysizehints(Client *c, int *x, int *y + void + arrange(Monitor *m) { + if(m) +- showhide(m->stack); ++ showhide(m->cl->stack); + else for(m = mons; m; m = m->next) +- showhide(m->stack); +- if(m) ++ showhide(m->cl->stack); ++ if(m) { + arrangemon(m); +- else for(m = mons; m; m = m->next) ++ restack(m); ++ } else for(m = mons; m; m = m->next) + arrangemon(m); + } + +@@ -408,19 +471,64 @@ arrangemon(Monitor *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 + attach(Client *c) { +- c->next = c->mon->clients; +- c->mon->clients = c; ++ c->next = c->mon->cl->clients; ++ c->mon->cl->clients = c; ++} ++ ++void ++attachabove(Client *c) { ++ if(c->mon->sel == NULL || c->mon->sel == c->mon->cl->clients || c->mon->sel->isfloating) { ++ attach(c); ++ return; ++ } ++ ++ Client *at; ++ for(at = c->mon->cl->clients; at->next != c->mon->sel; at = at->next); ++ c->next = at->next; ++ at->next = c; ++} ++ ++void ++attachclients(Monitor *m) { ++ /* attach clients to the specified monitor */ ++ Monitor *tm; ++ Client *c; ++ unsigned int utags = 0; ++ Bool rmons = False; ++ if(!m) ++ return; ++ ++ /* collect information about the tags in use */ ++ for(tm = mons; tm; tm = tm->next) ++ if(tm != m) ++ utags |= m->tagset[m->seltags]; ++ ++ for(c = m->cl->clients; c; c = c->next) ++ if(ISVISIBLE(c, m)) { ++ /* if client is also visible on other tags that are displayed on ++ * other monitors, remove these tags */ ++ if(c->tags & utags) { ++ c->tags = c->tags & m->tagset[m->seltags]; ++ rmons = True; ++ } ++ unfocus(c, True); ++ c->mon = m; ++ } ++ ++ if(rmons) ++ for(tm = mons; tm; tm = tm->next) ++ if(tm != m) ++ arrange(tm); + } + + void + attachstack(Client *c) { +- c->snext = c->mon->stack; +- c->mon->stack = c; ++ c->snext = c->mon->cl->stack; ++ c->mon->cl->stack = c; + } + + void +@@ -483,8 +591,8 @@ cleanup(void) { + view(&a); + selmon->lt[selmon->sellt] = &foo; + for(m = mons; m; m = m->next) +- while(m->stack) +- unmanage(m->stack, False); ++ while(m->cl->stack) ++ unmanage(m->cl->stack, False); + if(dc.font.set) + XFreeFontSet(dpy, dc.font.set); + else +@@ -497,8 +605,14 @@ cleanup(void) { + XFreeCursor(dpy, cursor[CurMove]); + while(mons) + cleanupmon(mons); ++ if(showsystray) { ++ XUnmapWindow(dpy, systray->win); ++ XDestroyWindow(dpy, systray->win); ++ free(systray); ++ } + XSync(dpy, False); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); ++ XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } + + void +@@ -530,9 +644,49 @@ clearurgent(Client *c) { + + void + clientmessage(XEvent *e) { ++ XWindowAttributes wa; ++ XSetWindowAttributes swa; + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); + ++ if(showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { ++ /* add systray icons */ ++ if(cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { ++ if(!(c = (Client *)calloc(1, sizeof(Client)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Client)); ++ c->win = cme->data.l[2]; ++ c->mon = selmon; ++ c->next = systray->icons; ++ systray->icons = c; ++ XGetWindowAttributes(dpy, c->win, &wa); ++ c->x = c->oldx = c->y = c->oldy = 0; ++ c->w = c->oldw = wa.width; ++ c->h = c->oldh = wa.height; ++ c->oldbw = wa.border_width; ++ c->bw = 0; ++ c->isfloating = True; ++ /* reuse tags field as mapped status */ ++ c->tags = 1; ++ updatesizehints(c); ++ updatesystrayicongeom(c, wa.width, wa.height); ++ XAddToSaveSet(dpy, c->win); ++ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); ++ XReparentWindow(dpy, c->win, systray->win, 0, 0); ++ /* use parents background pixmap */ ++ swa.background_pixmap = ParentRelative; ++ swa.background_pixel = dc.norm[ColBG]; ++ XChangeWindowAttributes(dpy, c->win, CWBackPixmap|CWBackPixel, &swa); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ /* FIXME not sure if I have to send these events, too */ ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ resizebarwin(selmon); ++ updatesystray(); ++ setclientstate(c, NormalState); ++ } ++ return; ++ } + if(!c) + return; + if(cme->message_type == netatom[NetWMState]) { +@@ -541,7 +695,7 @@ clientmessage(XEvent *e) { + || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); + } + else if(cme->message_type == netatom[NetActiveWindow]) { +- if(!ISVISIBLE(c)) { ++ if(!ISVISIBLE(c, c->mon)) { + c->mon->seltags ^= 1; + c->mon->tagset[c->mon->seltags] = c->tags; + } +@@ -573,8 +727,9 @@ configurenotify(XEvent *e) { + XConfigureEvent *ev = &e->xconfigure; + Bool dirty; + ++ // TODO: updategeom handling sucks, needs to be simplified + if(ev->window == root) { +- dirty = (sw != ev->width); ++ dirty = (sw != ev->width || sh != ev->height); + sw = ev->width; + sh = ev->height; + if(updategeom() || dirty) { +@@ -583,7 +738,7 @@ configurenotify(XEvent *e) { + 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); ++ resizebarwin(m); + focus(NULL); + arrange(NULL); + } +@@ -624,7 +779,7 @@ configurerequest(XEvent *e) { + c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ + if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) + configure(c); +- if(ISVISIBLE(c)) ++ if(ISVISIBLE(c, m)) + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + } + else +@@ -645,11 +800,18 @@ configurerequest(XEvent *e) { + + Monitor * + createmon(void) { +- Monitor *m; ++ Monitor *m, *tm; ++ int i; + + if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); +- m->tagset[0] = m->tagset[1] = 1; ++ m->cl = cl; ++ /* reassing tags when creating a new monitor */ ++ for(i=1, tm = mons; tm; tm = tm->next, i++) { ++ tm->seltags ^= 1; ++ tm->tagset[tm->seltags] = i; ++ } ++ m->tagset[0] = m->tagset[1] = i; + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; +@@ -657,6 +819,24 @@ createmon(void) { + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ for(i=0; i <= LENGTH(tags); i++) { ++ /* init nmaster */ ++ m->pertag->nmasters[i] = m->nmaster; ++ ++ /* init mfacts */ ++ m->pertag->mfacts[i] = m->mfact; ++ ++ /* init layouts */ ++ m->pertag->ltidxs[i][0] = m->lt[0]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ /* init showbar */ ++ m->pertag->showbars[i] = m->showbar; ++ } + return m; + } + +@@ -667,13 +847,18 @@ destroynotify(XEvent *e) { + + if((c = wintoclient(ev->window))) + unmanage(c, True); ++ else if((c = wintosystrayicon(ev->window))) { ++ removesystrayicon(c); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + } + + void + detach(Client *c) { + Client **tc; + +- for(tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next); ++ for(tc = &c->mon->cl->clients; *tc && *tc != c; tc = &(*tc)->next); + *tc = c->next; + } + +@@ -681,11 +866,11 @@ void + detachstack(Client *c) { + Client **tc, *t; + +- for(tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext); ++ for(tc = &c->mon->cl->stack; *tc && *tc != c; tc = &(*tc)->snext); + *tc = c->snext; + + if(c == c->mon->sel) { +- for(t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext); ++ for(t = c->mon->cl->stack; t && !ISVISIBLE(t, c->mon); t = t->snext); + c->mon->sel = t; + } + } +@@ -722,7 +907,8 @@ drawbar(Monitor *m) { + unsigned long *col; + Client *c; + +- for(c = m->clients; c; c = c->next) { ++ resizebarwin(m); ++ for(c = m->cl->clients; c; c = c->next) { + occ |= c->tags; + if(c->isurgent) + urg |= c->tags; +@@ -740,17 +926,16 @@ drawbar(Monitor *m) { + drawtext(m->ltsymbol, dc.norm, False); + dc.x += dc.w; + x = dc.x; +- if(m == selmon) { /* status is only drawn on selected monitor */ +- dc.w = TEXTW(stext); +- dc.x = m->ww - dc.w; +- if(dc.x < x) { +- dc.x = x; +- dc.w = m->ww - x; +- } +- drawtext(stext, dc.norm, False); ++ dc.w = TEXTW(stext); ++ dc.x = m->ww - dc.w; ++ if(showsystray && m == selmon) { ++ dc.x -= getsystraywidth(); + } +- else +- dc.x = m->ww; ++ if(dc.x < x) { ++ dc.x = x; ++ dc.w = m->ww - x; ++ } ++ drawtext(stext, dc.norm, False); + if((dc.w = dc.x - x) > bh) { + dc.x = x; + if(m->sel) { +@@ -771,6 +956,7 @@ drawbars(void) { + + for(m = mons; m; m = m->next) + drawbar(m); ++ updatesystray(); + } + + void +@@ -842,8 +1028,8 @@ expose(XEvent *e) { + + void + focus(Client *c) { +- if(!c || !ISVISIBLE(c)) +- for(c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); ++ if(!c || !ISVISIBLE(c, selmon)) ++ for(c = selmon->cl->stack; c && !ISVISIBLE(c, selmon); c = c->snext); + /* was if(selmon->sel) */ + if(selmon->sel && selmon->sel != c) + unfocus(selmon->sel, False); +@@ -855,11 +1041,16 @@ focus(Client *c) { + detachstack(c); + attachstack(c); + grabbuttons(c, True); +- XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]); ++ if(c->isfloating) ++ XSetWindowBorder(dpy, c->win, dc.sel[ColBorderFloat]); ++ else ++ 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(); + } +@@ -880,7 +1071,8 @@ focusmon(const Arg *arg) { + 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); + } +@@ -892,17 +1084,17 @@ focusstack(const Arg *arg) { + if(!selmon->sel) + return; + if(arg->i > 0) { +- for(c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); ++ for(c = selmon->sel->next; c && !ISVISIBLE(c, selmon); c = c->next); + if(!c) +- for(c = selmon->clients; c && !ISVISIBLE(c); c = c->next); ++ for(c = selmon->cl->clients; c && !ISVISIBLE(c, selmon); c = c->next); + } + else { +- for(i = selmon->clients; i != selmon->sel; i = i->next) +- if(ISVISIBLE(i)) ++ for(i = selmon->cl->clients; i != selmon->sel; i = i->next) ++ if(ISVISIBLE(i, selmon)) + c = i; + if(!c) + for(; i; i = i->next) +- if(ISVISIBLE(i)) ++ if(ISVISIBLE(i, selmon)) + c = i; + } + if(c) { +@@ -917,10 +1109,17 @@ getatomprop(Client *c, Atom prop) { + unsigned long dl; + unsigned char *p = NULL; + Atom da, atom = None; ++ /* FIXME getatomprop should return the number of items and a pointer to ++ * the stored data instead of this workaround */ ++ Atom req = XA_ATOM; ++ if(prop == xatom[XembedInfo]) ++ req = xatom[XembedInfo]; + +- if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, ++ if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, + &da, &di, &dl, &dl, &p) == Success && p) { + atom = *(Atom *)p; ++ if(da == xatom[XembedInfo] && dl == 2) ++ atom = ((Atom *)p)[1]; + XFree(p); + } + return atom; +@@ -962,6 +1161,15 @@ getstate(Window w) { + return result; + } + ++unsigned int ++getsystraywidth() { ++ unsigned int w = 0; ++ Client *i; ++ if(showsystray) ++ for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; ++ return w ? w + systrayspacing : 1; ++} ++ + Bool + gettextprop(Window w, Atom atom, char *text, unsigned int size) { + char **list = NULL; +@@ -1028,7 +1236,7 @@ grabkeys(void) { + + void + incnmaster(const Arg *arg) { +- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); + } + +@@ -1084,7 +1292,7 @@ keypress(XEvent *e) { + 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) +@@ -1096,7 +1304,7 @@ void + killclient(const Arg *arg) { + if(!selmon->sel) + return; +- if(!sendevent(selmon->sel, wmatom[WMDelete])) { ++ if(!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XSetCloseDownMode(dpy, DestroyAll); +@@ -1149,14 +1357,24 @@ manage(Window w, XWindowAttributes *wa) + updatewindowtype(c); + updatesizehints(c); + updatewmhints(c); ++ c->sfx = c->x; ++ c->sfy = c->y; ++ c->sfw = c->w; ++ c->sfh = c->h; + XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); + grabbuttons(c, False); ++ c->wasfloating = False; ++ c->ismax = False; + if(!c->isfloating) + c->isfloating = c->oldstate = trans != None || c->isfixed; + if(c->isfloating) + XRaiseWindow(dpy, c->win); +- attach(c); ++ if(c->isfloating) ++ XSetWindowBorder(dpy, w, dc.norm[ColBorderFloat]); ++ attachabove(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) +@@ -1180,6 +1398,12 @@ void + maprequest(XEvent *e) { + static XWindowAttributes wa; + XMapRequestEvent *ev = &e->xmaprequest; ++ Client *i; ++ if((i = wintosystrayicon(ev->window))) { ++ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + + if(!XGetWindowAttributes(dpy, ev->window, &wa)) + return; +@@ -1191,16 +1415,25 @@ maprequest(XEvent *e) { + + void + monocle(Monitor *m) { +- unsigned int n = 0; ++ unsigned int n = 0, r = 0; + Client *c; + +- for(c = m->clients; c; c = c->next) +- if(ISVISIBLE(c)) ++ for(c = m->cl->clients; c; c = c->next) ++ if(ISVISIBLE(c, m)) + 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 = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m)) { ++ /* remove border when in monocle layout */ ++ if(c->bw) { ++ c->oldbw = c->bw; ++ c->bw = 0; ++ r = 1; ++ } ++ resize(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw), False); ++ if(r) ++ resizeclient(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw)); ++ } + } + + void +@@ -1212,6 +1445,7 @@ motionnotify(XEvent *e) { + 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); + } +@@ -1227,6 +1461,8 @@ movemouse(const Arg *arg) { + + if(!(c = selmon->sel)) + return; ++ if(c->isfullscreen) /* no support moving fullscreen windows by mouse */ ++ return; + restack(selmon); + ocx = c->x; + ocy = c->y; +@@ -1274,8 +1510,8 @@ movemouse(const Arg *arg) { + } + + Client * +-nexttiled(Client *c) { +- for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); ++nexttiled(Client *c, Monitor *m) { ++ for(; c && (c->isfloating || !ISVISIBLE(c, m)); c = c->next); + return c; + } + +@@ -1293,6 +1529,16 @@ propertynotify(XEvent *e) { + Window trans; + XPropertyEvent *ev = &e->xproperty; + ++ if((c = wintosystrayicon(ev->window))) { ++ if(ev->atom == XA_WM_NORMAL_HINTS) { ++ updatesizehints(c); ++ updatesystrayicongeom(c, c->w, c->h); ++ } ++ else ++ updatesystrayiconstate(c, ev); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + if((ev->window == root) && (ev->atom == XA_WM_NAME)) + updatestatus(); + else if(ev->state == PropertyDelete) +@@ -1325,6 +1571,8 @@ propertynotify(XEvent *e) { + + void + quit(const Arg *arg) { ++ if(arg->i) ++ restart = True; + running = False; + } + +@@ -1342,12 +1590,33 @@ recttomon(int x, int y, int w, int h) { + } + + void ++removesystrayicon(Client *i) { ++ Client **ii; ++ ++ if(!showsystray || !i) ++ return; ++ for(ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); ++ if(ii) ++ *ii = i->next; ++ free(i); ++} ++ ++ ++void + resize(Client *c, int x, int y, int w, int h, Bool interact) { + if(applysizehints(c, &x, &y, &w, &h, interact)) + resizeclient(c, x, y, w, h); + } + + void ++resizebarwin(Monitor *m) { ++ unsigned int w = m->ww; ++ if(showsystray && m == selmon) ++ w -= getsystraywidth(); ++ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); ++} ++ ++void + resizeclient(Client *c, int x, int y, int w, int h) { + XWindowChanges wc; + +@@ -1371,6 +1640,8 @@ resizemouse(const Arg *arg) { + + if(!(c = selmon->sel)) + return; ++ if(c->isfullscreen) /* no support resizing fullscreen windows by mouse */ ++ return; + restack(selmon); + ocx = c->x; + ocy = c->y; +@@ -1412,6 +1683,18 @@ resizemouse(const Arg *arg) { + } + + void ++resizerequest(XEvent *e) { ++ XResizeRequestEvent *ev = &e->xresizerequest; ++ Client *i; ++ ++ if((i = wintosystrayicon(ev->window))) { ++ updatesystrayicongeom(i, ev->width, ev->height); ++ resizebarwin(selmon); ++ updatesystray(); ++ } ++} ++ ++void + restack(Monitor *m) { + Client *c; + XEvent ev; +@@ -1425,8 +1708,8 @@ restack(Monitor *m) { + if(m->lt[m->sellt]->arrange) { + wc.stack_mode = Below; + wc.sibling = m->barwin; +- for(c = m->stack; c; c = c->snext) +- if(!c->isfloating && ISVISIBLE(c)) { ++ for(c = m->cl->stack; c; c = c->snext) ++ if(!c->isfloating && ISVISIBLE(c, m)) { + XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); + wc.sibling = c->win; + } +@@ -1476,11 +1759,9 @@ sendmon(Client *c, Monitor *m) { + if(c->mon == m) + return; + unfocus(c, True); +- detach(c); + detachstack(c); + c->mon = m; + c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ +- attach(c); + attachstack(c); + focus(NULL); + arrange(NULL); +@@ -1495,34 +1776,48 @@ setclientstate(Client *c, long state) { + } + + Bool +-sendevent(Client *c, Atom proto) { ++sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) { + int n; +- Atom *protocols; ++ Atom *protocols, mt; + Bool exists = False; + XEvent ev; + +- if(XGetWMProtocols(dpy, c->win, &protocols, &n)) { +- while(!exists && n--) +- exists = protocols[n] == proto; +- XFree(protocols); ++ if(proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { ++ mt = wmatom[WMProtocols]; ++ if(XGetWMProtocols(dpy, w, &protocols, &n)) { ++ while(!exists && n--) ++ exists = protocols[n] == proto; ++ XFree(protocols); ++ } ++ } ++ else { ++ exists = True; ++ mt = proto; + } + if(exists) { + ev.type = ClientMessage; +- ev.xclient.window = c->win; +- ev.xclient.message_type = wmatom[WMProtocols]; ++ ev.xclient.window = w; ++ ev.xclient.message_type = mt; + ev.xclient.format = 32; +- ev.xclient.data.l[0] = proto; +- ev.xclient.data.l[1] = CurrentTime; +- XSendEvent(dpy, c->win, False, NoEventMask, &ev); ++ ev.xclient.data.l[0] = d0; ++ ev.xclient.data.l[1] = d1; ++ ev.xclient.data.l[2] = d2; ++ ev.xclient.data.l[3] = d3; ++ ev.xclient.data.l[4] = d4; ++ XSendEvent(dpy, w, False, mask, &ev); + } + return exists; + } + + void + setfocus(Client *c) { +- if(!c->neverfocus) ++ if(!c->neverfocus) { + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); +- sendevent(c, wmatom[WMTakeFocus]); ++ XChangeProperty(dpy, root, netatom[NetActiveWindow], ++ XA_WINDOW, 32, PropModeReplace, ++ (unsigned char *) &(c->win), 1); ++ } ++ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); + } + + void +@@ -1555,10 +1850,13 @@ setfullscreen(Client *c, Bool fullscreen + + void + setlayout(const Arg *arg) { +- if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) +- selmon->sellt ^= 1; ++ if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { ++ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ } + if(arg && arg->v) +- selmon->lt[selmon->sellt] = (Layout *)arg->v; ++ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if(selmon->sel) + arrange(selmon); +@@ -1576,7 +1874,7 @@ setmfact(const Arg *arg) { + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if(f < 0.1 || f > 0.9) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1594,6 +1892,8 @@ setup(void) { + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + bh = dc.h = dc.font.height + 2; ++ if(!(cl = (Clientlist *)calloc(1, sizeof(Clientlist)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Clientlist)); + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1602,11 +1902,18 @@ setup(void) { + wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); + netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); ++ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); ++ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); ++ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); + 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[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); ++ xatom[Manager] = XInternAtom(dpy, "MANAGER", False); ++ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); ++ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); + /* init cursors */ + cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); + cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); +@@ -1615,20 +1922,25 @@ setup(void) { + dc.norm[ColBorder] = getcolor(normbordercolor); + dc.norm[ColBG] = getcolor(normbgcolor); + dc.norm[ColFG] = getcolor(normfgcolor); ++ dc.norm[ColBorderFloat] = getcolor(floatnormbordercolor); + dc.sel[ColBorder] = getcolor(selbordercolor); + dc.sel[ColBG] = getcolor(selbgcolor); + dc.sel[ColFG] = getcolor(selfgcolor); ++ dc.sel[ColBorderFloat] = getcolor(floatselbordercolor); + dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen)); + dc.gc = XCreateGC(dpy, root, 0, NULL); + XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); + if(!dc.font.set) + XSetFont(dpy, dc.gc, dc.font.xfont->fid); ++ /* init system tray */ ++ updatesystray(); + /* init bars */ + updatebars(); + updatestatus(); + /* 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 +@@ -1642,7 +1954,7 @@ void + showhide(Client *c) { + if(!c) + return; +- if(ISVISIBLE(c)) { /* show clients top down */ ++ if(ISVISIBLE(c, c->mon)) { /* 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); +@@ -1675,8 +1987,31 @@ spawn(const Arg *arg) { + } + + void ++swapfocus(){ ++ Client *c; ++ for(c = selmon->cl->clients; c && c != prevclient; c = c->next) ; ++ if(c == prevclient) ++ focus(prevclient); ++} ++ ++void + tag(const Arg *arg) { ++ Monitor *m; ++ unsigned int newtags; + if(selmon->sel && arg->ui & TAGMASK) { ++ newtags = arg->ui & TAGMASK; ++ for(m = mons; m; m = m->next) ++ /* if tag is visible on another monitor, move client to the new monitor */ ++ if(m != selmon && m->tagset[m->seltags] & newtags) { ++ /* prevent moving client to all tags (MODKEY-Shift-0) when multiple monitors are connected */ ++ if(newtags & selmon->tagset[selmon->seltags]) ++ return; ++ selmon->sel->tags = newtags; ++ selmon->sel->mon = m; ++ arrange(m); ++ break; ++ } ++ /* workaround in case just one monitor is connected */ + selmon->sel->tags = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); +@@ -1703,10 +2038,10 @@ textnw(const char *text, unsigned int le + + void + tile(Monitor *m) { +- unsigned int i, n, h, mw, my, ty; ++ unsigned int i, n, h, mw, my, ty, r; + Client *c; + +- for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ for(n = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), n++); + if(n == 0) + return; + +@@ -1714,24 +2049,54 @@ tile(Monitor *m) { + mw = m->nmaster ? m->ww * m->mfact : 0; + else + mw = m->ww; +- for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ for(i = my = ty = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), i++, r = 0) { ++ if(n == 1) { ++ if (c->bw) { ++ /* remove border when only one window is on the current tag */ ++ c->oldbw = c->bw; ++ c->bw = 0; ++ r = 1; ++ } ++ } ++ else if(!c->bw && c->oldbw) { ++ /* restore border when more than one window is displayed */ ++ c->bw = c->oldbw; ++ c->oldbw = 0; ++ r = 1; ++ } + 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); ++ if(r) ++ resizeclient(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw)); + 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); ++ if(r) ++ resizeclient(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw)); + ty += HEIGHT(c); + } ++ } + } + + void + togglebar(const Arg *arg) { +- selmon->showbar = !selmon->showbar; ++ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; + updatebarpos(selmon); +- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); ++ resizebarwin(selmon); ++ if(showsystray) { ++ XWindowChanges wc; ++ if(!selmon->showbar) ++ wc.y = -bh; ++ else if(selmon->showbar) { ++ wc.y = 0; ++ if(!selmon->topbar) ++ wc.y = selmon->mh - bh; ++ } ++ XConfigureWindow(dpy, systray->win, CWY, &wc); ++ } + arrange(selmon); + } + +@@ -1739,21 +2104,46 @@ void + 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, +- selmon->sel->w, selmon->sel->h, False); ++ XSetWindowBorder(dpy, selmon->sel->win, dc.sel[ColBorderFloat]); ++ else ++ XSetWindowBorder(dpy, selmon->sel->win, dc.sel[ColBorder]); ++ if(selmon->sel->isfloating) { ++ /* restore border when moving window into floating mode */ ++ if(!selmon->sel->bw && selmon->sel->oldbw) { ++ selmon->sel->bw = selmon->sel->oldbw; ++ selmon->sel->oldbw = 0; ++ } ++ /*restore last known float dimensions*/ ++ resize(selmon->sel, selmon->sel->sfx, selmon->sel->sfy, ++ selmon->sel->sfw, selmon->sel->sfh, False); ++ } ++ else { ++ /*save last known float dimensions*/ ++ selmon->sel->sfx = selmon->sel->x; ++ selmon->sel->sfy = selmon->sel->y; ++ selmon->sel->sfw = selmon->sel->w; ++ selmon->sel->sfh = selmon->sel->h; ++ } + arrange(selmon); + } + + void + toggletag(const Arg *arg) { ++ Monitor *m; + unsigned int newtags; + + if(!selmon->sel) + return; + newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); + if(newtags) { ++ /* prevent adding tags that are in use on other monitors */ ++ for(m = mons; m; m = m->next) ++ if(m != selmon && newtags & m->tagset[m->seltags]) ++ return; + selmon->sel->tags = newtags; + focus(NULL); + arrange(selmon); +@@ -1762,10 +2152,36 @@ toggletag(const Arg *arg) { + + void + toggleview(const Arg *arg) { ++ Monitor *m; + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if(newtagset) { ++ /* prevent displaying the same tags on multiple monitors */ ++ for(m = mons; m; m = m->next) ++ if(m != selmon && newtagset & m->tagset[m->seltags]) ++ return; ++ if(newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } ++ /* test if the user did not select the same tag */ ++ if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i=0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } + selmon->tagset[selmon->seltags] = newtagset; ++ ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ attachclients(selmon); ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); + focus(NULL); + arrange(selmon); + } +@@ -1775,10 +2191,16 @@ void + unfocus(Client *c, Bool setfocus) { + if(!c) + return; ++ prevclient = c; + grabbuttons(c, False); +- XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]); +- if(setfocus) ++ if(c->isfloating) ++ XSetWindowBorder(dpy, c->win, dc.norm[ColBorderFloat]); ++ else ++ XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]); ++ if(setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); ++ XDeleteProperty(dpy, root, netatom[NetActiveWindow]); ++ } + } + + void +@@ -1802,6 +2224,7 @@ unmanage(Client *c, Bool destroyed) { + } + free(c); + focus(NULL); ++ updateclientlist(); + arrange(m); + } + +@@ -1816,21 +2239,35 @@ unmapnotify(XEvent *e) { + else + unmanage(c, False); + } ++ else if((c = wintosystrayicon(ev->window))) { ++ removesystrayicon(c); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + } + + void + updatebars(void) { ++ unsigned int w; + Monitor *m; ++ + XSetWindowAttributes wa = { + .override_redirect = True, + .background_pixmap = ParentRelative, + .event_mask = ButtonPressMask|ExposureMask + }; + for(m = mons; m; m = m->next) { +- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), ++ if (m->barwin) ++ continue; ++ w = m->ww; ++ if(showsystray && m == selmon) ++ w -= getsystraywidth(); ++ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]); ++ if(showsystray && m == selmon) ++ XMapRaised(dpy, systray->win); + XMapRaised(dpy, m->barwin); + } + } +@@ -1848,6 +2285,19 @@ updatebarpos(Monitor *m) { + m->by = -bh; + } + ++void ++updateclientlist() { ++ Client *c; ++ Monitor *m; ++ ++ XDeleteProperty(dpy, root, netatom[NetClientList]); ++ for(m = mons; m; m = m->next) ++ for(c = m->cl->clients; c; c = c->next) ++ XChangeProperty(dpy, root, netatom[NetClientList], ++ XA_WINDOW, 32, PropModeAppend, ++ (unsigned char *) &(c->win), 1); ++} ++ + Bool + updategeom(void) { + Bool dirty = False; +@@ -1872,8 +2322,10 @@ updategeom(void) { + if(n <= nn) { + for(i = 0; i < (nn - n); i++) { /* new monitors available */ + for(m = mons; m && m->next; m = m->next); +- if(m) ++ if(m) { + m->next = createmon(); ++ attachclients(m->next); ++ } + else + mons = createmon(); + } +@@ -1894,17 +2346,13 @@ updategeom(void) { + 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; ++ for(c = m->cl->clients; c; c = c->next) { ++ dirty = True; ++ if(c->mon == m) ++ c->mon = selmon; ++ } + cleanupmon(m); + } + } +@@ -2005,9 +2453,112 @@ updatetitle(Client *c) { + + void + updatestatus(void) { ++ Monitor* m; + if(!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + strcpy(stext, "dwm-"VERSION); +- drawbar(selmon); ++ for(m = mons; m; m = m->next) ++ drawbar(m); ++} ++ ++void ++updatesystrayicongeom(Client *i, int w, int h) { ++ if(i) { ++ i->h = bh; ++ if(w == h) ++ i->w = bh; ++ else if(h == bh) ++ i->w = w; ++ else ++ i->w = (int) ((float)bh * ((float)w / (float)h)); ++ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); ++ /* force icons into the systray dimenons if they don't want to */ ++ if(i->h > bh) { ++ if(i->w == i->h) ++ i->w = bh; ++ else ++ i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); ++ i->h = bh; ++ } ++ } ++} ++ ++void ++updatesystrayiconstate(Client *i, XPropertyEvent *ev) { ++ long flags; ++ int code = 0; ++ ++ if(!showsystray || !i || ev->atom != xatom[XembedInfo] || ++ !(flags = getatomprop(i, xatom[XembedInfo]))) ++ return; ++ ++ if(flags & XEMBED_MAPPED && !i->tags) { ++ i->tags = 1; ++ code = XEMBED_WINDOW_ACTIVATE; ++ XMapRaised(dpy, i->win); ++ setclientstate(i, NormalState); ++ } ++ else if(!(flags & XEMBED_MAPPED) && i->tags) { ++ i->tags = 0; ++ code = XEMBED_WINDOW_DEACTIVATE; ++ XUnmapWindow(dpy, i->win); ++ setclientstate(i, WithdrawnState); ++ } ++ else ++ return; ++ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, ++ systray->win, XEMBED_EMBEDDED_VERSION); ++} ++ ++void ++updatesystray(void) { ++ XSetWindowAttributes wa; ++ Client *i; ++ unsigned int x = selmon->mx + selmon->mw; ++ unsigned int w = 1; ++ ++ if(!showsystray) ++ return; ++ if(!systray) { ++ /* init systray */ ++ if(!(systray = (Systray *)calloc(1, sizeof(Systray)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); ++ systray->win = XCreateSimpleWindow(dpy, root, x, selmon->by, w, bh, 0, 0, dc.sel[ColBG]); ++ wa.event_mask = ButtonPressMask | ExposureMask; ++ wa.override_redirect = True; ++ wa.background_pixmap = ParentRelative; ++ wa.background_pixel = dc.norm[ColBG]; ++ XSelectInput(dpy, systray->win, SubstructureNotifyMask); ++ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, ++ PropModeReplace, (unsigned char *)&systrayorientation, 1); ++ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel|CWBackPixmap, &wa); ++ XMapRaised(dpy, systray->win); ++ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); ++ if(XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { ++ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); ++ XSync(dpy, False); ++ } ++ else { ++ fprintf(stderr, "dwm: unable to obtain system tray.\n"); ++ free(systray); ++ systray = NULL; ++ return; ++ } ++ } ++ for(w = 0, i = systray->icons; i; i = i->next) { ++ XMapRaised(dpy, i->win); ++ w += systrayspacing; ++ XMoveResizeWindow(dpy, i->win, (i->x = w), 0, i->w, i->h); ++ w += i->w; ++ if(i->mon != selmon) ++ i->mon = selmon; ++ } ++ w = w ? w + systrayspacing : 1; ++ x -= w; ++ XMoveResizeWindow(dpy, systray->win, x, selmon->by, w, bh); ++ /* redraw background */ ++ XSetForeground(dpy, dc.gc, dc.norm[ColBG]); ++ XFillRectangle(dpy, systray->win, dc.gc, 0, 0, w, bh); ++ XSync(dpy, False); + } + + void +@@ -2017,7 +2568,6 @@ updatewindowtype(Client *c) { + + if(state == netatom[NetWMFullscreen]) + setfullscreen(c, True); +- + if(wtype == netatom[NetWMWindowTypeDialog]) + c->isfloating = True; + } +@@ -2043,11 +2593,53 @@ updatewmhints(Client *c) { + + void + view(const Arg *arg) { ++ Monitor *m; ++ unsigned int newtagset = selmon->tagset[selmon->seltags ^ 1]; ++ int i; ++ unsigned int tmptag; ++ + if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; +- selmon->seltags ^= 1; /* toggle sel tagset */ ++ ++ /* swap tags when trying to display a tag from another monitor */ + if(arg->ui & TAGMASK) ++ newtagset = arg->ui & TAGMASK; ++ for(m = mons; m; m = m->next) ++ if(m != selmon && newtagset & m->tagset[m->seltags]) { ++ /* prevent displaying all tags (MODKEY-0) when multiple monitors ++ * are connected */ ++ if(newtagset & selmon->tagset[selmon->seltags]) ++ return; ++ m->seltags ^= 1; ++ m->tagset[m->seltags] = selmon->tagset[selmon->seltags]; ++ attachclients(m); ++ arrange(m); ++ break; ++ } ++ ++ selmon->seltags ^= 1; /* toggle sel tagset */ ++ if(arg->ui & TAGMASK) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ if(arg->ui == ~0) ++ selmon->pertag->curtag = 0; ++ else { ++ for (i=0; !(arg->ui & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ } else { ++ tmptag = selmon->pertag->prevtag; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = tmptag; ++ } ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ attachclients(selmon); ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); + focus(NULL); + arrange(selmon); + } +@@ -2058,7 +2650,7 @@ wintoclient(Window w) { + Monitor *m; + + for(m = mons; m; m = m->next) +- for(c = m->clients; c; c = c->next) ++ for(c = m->cl->clients; c; c = c->next) + if(c->win == w) + return c; + return NULL; +@@ -2080,6 +2672,16 @@ wintomon(Window w) { + return selmon; + } + ++Client * ++wintosystrayicon(Window w) { ++ Client *i = NULL; ++ ++ if(!showsystray || !w) ++ return i; ++ for(i = systray->icons; i && i->win != w; i = i->next) ; ++ return i; ++} ++ + /* There's no way to check accesses to destroyed windows, thus those cases are + * ignored (especially on UnmapNotify's). Other types of errors call Xlibs + * default error handler, which may call exit. */ +@@ -2116,20 +2718,43 @@ xerrorstart(Display *dpy, XErrorEvent *e + void + zoom(const Arg *arg) { + Client *c = selmon->sel; ++ prevclient = selmon->cl->clients; ++ Client *at, *tmp; + + if(!selmon->lt[selmon->sellt]->arrange + || (selmon->sel && selmon->sel->isfloating)) + return; +- if(c == nexttiled(selmon->clients)) +- if(!c || !(c = nexttiled(c->next))) +- return; ++ if(c == nexttiled(selmon->cl->clients, selmon)) { ++ for(tmp = selmon->cl->clients; tmp && tmp != prevzoom; tmp = tmp->next) ; ++ if(tmp != prevzoom) ++ prevzoom = NULL; ++ if(!c || !(c = nexttiled(prevzoom, selmon))) { ++ c = selmon->sel; ++ if(!c || !(c = nexttiled(c->next, selmon))) ++ return; ++ } ++ } ++ for(at = selmon->cl->clients; at && at->next && at != c && at->next != c; at = nexttiled(at->next, selmon)) ; + pop(c); ++ /* swap windows instead of pushing the previous one down */ ++ if(at && at != c) { ++ /* store c's next neighbor - this window needs to be moved away */ ++ tmp = prevzoom = c->next; ++ if(c->next != at) { ++ /* detach c's neighbor from the list of windows */ ++ c->next = tmp->next; ++ /* attach tmp after c's previous neighbor */ ++ tmp->next = at->next; ++ at->next = tmp; ++ arrange(c->mon); ++ } ++ } + } + + 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()) +@@ -2140,6 +2765,8 @@ main(int argc, char *argv[]) { + setup(); + scan(); + run(); ++ if(restart) ++ execvp(argv[0], argv); + cleanup(); + XCloseDisplay(dpy); + return EXIT_SUCCESS; + +--- /dev/null ++++ focusmaster.c +@@ -0,0 +1,4 @@ ++static void ++focusmaster(const Arg *arg) { ++ focus(nexttiled(selmon->cl->clients, selmon)); ++} + +--- /dev/null ++++ maximize.c +@@ -0,0 +1,45 @@ ++void ++maximize(int x, int y, int w, int h) { ++ XEvent ev; ++ ++ if(!selmon->sel || selmon->sel->isfixed) ++ return; ++ XRaiseWindow(dpy, selmon->sel->win); ++ if(!selmon->sel->ismax) { ++ if(!selmon->lt[selmon->sellt]->arrange || selmon->sel->isfloating) ++ selmon->sel->wasfloating = True; ++ else { ++ togglefloating(NULL); ++ selmon->sel->wasfloating = False; ++ } ++ selmon->sel->oldx = selmon->sel->x; ++ selmon->sel->oldy = selmon->sel->y; ++ selmon->sel->oldw = selmon->sel->w; ++ selmon->sel->oldh = selmon->sel->h; ++ resize(selmon->sel, x, y, w, h, True); ++ selmon->sel->ismax = True; ++ } ++ else { ++ resize(selmon->sel, selmon->sel->oldx, selmon->sel->oldy, selmon->sel->oldw, selmon->sel->oldh, True); ++ if(!selmon->sel->wasfloating) ++ togglefloating(NULL); ++ selmon->sel->ismax = False; ++ } ++ drawbar(selmon); ++ while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); ++} ++ ++void ++togglemaximize(const Arg *arg) { ++ maximize(selmon->wx, selmon->wy, selmon->ww - 2 * borderpx, selmon->wh - 2 * borderpx); ++} ++ ++void ++toggleverticalmax(const Arg *arg) { ++ maximize(selmon->sel->x, selmon->wy, selmon->sel->w, selmon->wh - 2 * borderpx); ++} ++ ++void ++togglehorizontalmax(const Arg *arg) { ++ maximize(selmon->wx, selmon->sel->y, selmon->ww - 2 * borderpx, selmon->sel->h); ++} + +--- /dev/null ++++ moveresize.c +@@ -0,0 +1,64 @@ ++void ++moveresize(const Arg *arg) { ++ /* only floating windows can be moved */ ++ Client *c; ++ c = selmon->sel; ++ int x, y, w, h, nx, ny, nw, nh, ox, oy, ow, oh; ++ char xAbs, yAbs, wAbs, hAbs; ++ int msx, msy, dx, dy, nmx, nmy; ++ unsigned int dui; ++ Window dummy; ++ ++ if (!c || !arg) ++ return; ++ if (selmon->lt[selmon->sellt]->arrange && !c->isfloating) ++ return; ++ if(sscanf((char *)arg->v, "%d%c %d%c %d%c %d%c", &x, &xAbs, &y, &yAbs, &w, &wAbs, &h, &hAbs) != 8) ++ return; ++ /* compute new window position; prevent window from be positioned outside the current monitor */ ++ nw = c->w + w; ++ if(wAbs == 'W') ++ nw = w < selmon->mw - 2 * c->bw ? w : selmon->mw - 2 * c->bw; ++ ++ nh = c->h + h; ++ if(hAbs == 'H') ++ nh = h < selmon->mh - 2 * c->bw ? h : selmon->mh - 2 * c->bw; ++ ++ nx = c->x + x; ++ if(xAbs == 'X') { ++ if(x < selmon->mx) ++ nx = selmon->mx; ++ else if(x > selmon->mx + selmon->mw) ++ nx = selmon->mx + selmon->mw - nw - 2 * c->bw; ++ else ++ nx = x; ++ } ++ ++ ny = c->y + y; ++ if(yAbs == 'Y') { ++ if(y < selmon->my) ++ ny = selmon->my; ++ else if(y > selmon->my + selmon->mh) ++ ny = selmon->my + selmon->mh - nh - 2 * c->bw; ++ else ++ ny = y; ++ } ++ ++ ox = c->x; ++ oy = c->y; ++ ow = c->w; ++ oh = c->h; ++ ++ XRaiseWindow(dpy, c->win); ++ Bool xqp = XQueryPointer(dpy, root, &dummy, &dummy, &msx, &msy, &dx, &dy, &dui); ++ resize(c, nx, ny, nw, nh, True); ++ ++ /* move cursor along with the window to avoid problems caused by the sloppy focus */ ++ if (xqp && ox <= msx && (ox + ow) >= msx && oy <= msy && (oy + oh) >= msy) ++ { ++ nmx = c->x - ox + c->w - ow; ++ nmy = c->y - oy + c->h - oh; ++ XWarpPointer(dpy, None, None, 0, 0, 0, 0, nmx, nmy); ++ } ++} ++ + +--- /dev/null ++++ push.c +@@ -0,0 +1,58 @@ ++static Client * ++prevtiled(Client *c) { ++ Client *p, *r; ++ ++ for(p = selmon->cl->clients, r = NULL; p && p != c; p = p->next) ++ if(!p->isfloating && ISVISIBLE(p, selmon)) ++ r = p; ++ return r; ++} ++ ++static void ++pushup(const Arg *arg) { ++ Client *sel = selmon->sel; ++ Client *c; ++ ++ if(!sel || sel->isfloating) ++ return; ++ if((c = prevtiled(sel))) { ++ /* attach before c */ ++ detach(sel); ++ sel->next = c; ++ if(selmon->cl->clients == c) ++ selmon->cl->clients = sel; ++ else { ++ for(c = selmon->cl->clients; c->next != sel->next; c = c->next); ++ c->next = sel; ++ } ++ } else { ++ /* move to the end */ ++ for(c = sel; c->next; c = c->next); ++ detach(sel); ++ sel->next = NULL; ++ c->next = sel; ++ } ++ focus(sel); ++ arrange(selmon); ++} ++ ++static void ++pushdown(const Arg *arg) { ++ Client *sel = selmon->sel; ++ Client *c; ++ ++ if(!sel || sel->isfloating) ++ return; ++ if((c = nexttiled(sel->next, selmon))) { ++ /* attach after c */ ++ detach(sel); ++ sel->next = c->next; ++ c->next = sel; ++ } else { ++ /* move to the front */ ++ detach(sel); ++ attach(sel); ++ } ++ focus(sel); ++ arrange(selmon); ++} + +--- /dev/null ++++ shifttags.c +@@ -0,0 +1,28 @@ ++static void ++shifttags(const Arg *arg) { ++ Arg shift; ++ /* wrap around tags when shifting over the ends of tagmask */ ++ /* only activate wrapping when the number of tags fits twice into an ++ * unsigned int */ ++ Bool wrap = LENGTH(tags) <= (sizeof(shift.ui) * 4) ? True : False; ++ ++ if(arg->i == 0) ++ return; ++ ++ if(arg->i > 0) ++ shift.ui = selmon->tagset[selmon->seltags] << arg->i; ++ else { ++ if(wrap) { ++ shift.ui = selmon->tagset[selmon->seltags] << LENGTH(tags); ++ shift.ui = shift.ui >> (-1 * arg->i); ++ } ++ else ++ shift.ui = selmon->tagset[selmon->seltags] >> (-1 * arg->i); ++ } ++ if(wrap) ++ shift.ui |= shift.ui >> LENGTH(tags); ++ ++ if(!(shift.ui & TAGMASK)) ++ return; ++ view(&shift); ++} + +--- /dev/null ++++ tagall.c +@@ -0,0 +1,24 @@ ++void ++tagall(const Arg *arg) { ++ if (!selmon->cl->clients) ++ return; ++ /* if parameter starts with F, just move floating windows */ ++ int floating_only = (char *)arg->v && ((char *)arg->v)[0] == 'F' ? 1 : 0; ++ int tag = (char *)arg->v ? atoi(((char *)arg->v) + floating_only) : 0; ++ int j; ++ Client* c; ++ if(tag >= 0 && tag < LENGTH(tags)) ++ for(c = selmon->cl->clients; c; c = c->next) ++ { ++ if(!floating_only || c->isfloating) ++ for(j = 0; j < LENGTH(tags); j++) ++ { ++ if(c->tags & 1 << j && selmon->tagset[selmon->seltags] & 1 << j) ++ { ++ c->tags = c->tags ^ (1 << j & TAGMASK); ++ c->tags = c->tags | 1 << (tag-1); ++ } ++ } ++ } ++ arrange(selmon); ++} + +--- /dev/null ++++ transient.c +@@ -0,0 +1,42 @@ ++/* cc transient.c -o transient -lX11 */ ++ ++#include <stdlib.h> ++#include <unistd.h> ++#include <X11/Xlib.h> ++#include <X11/Xutil.h> ++ ++int main(void) { ++ Display *d; ++ Window r, f, t = None; ++ XSizeHints h; ++ XEvent e; ++ ++ d = XOpenDisplay(NULL); ++ if (!d) ++ exit(1); ++ r = DefaultRootWindow(d); ++ ++ f = XCreateSimpleWindow(d, r, 100, 100, 400, 400, 0, 0, 0); ++ h.min_width = h.max_width = h.min_height = h.max_height = 400; ++ h.flags = PMinSize | PMaxSize; ++ XSetWMNormalHints(d, f, &h); ++ XStoreName(d, f, "floating"); ++ XMapWindow(d, f); ++ ++ XSelectInput(d, f, ExposureMask); ++ while (1) { ++ XNextEvent(d, &e); ++ ++ if (t == None) { ++ sleep(5); ++ t = XCreateSimpleWindow(d, r, 50, 50, 100, 100, 0, 0, 0); ++ XSetTransientForHint(d, t, f); ++ XStoreName(d, t, "transient"); ++ XMapWindow(d, t); ++ XSelectInput(d, t, ExposureMask); ++ } ++ } ++ ++ XCloseDisplay(d); ++ exit(0); ++} |