Created
June 20, 2012 13:31
-
-
Save menski/2959895 to your computer and use it in GitHub Desktop.
dwm 6.0 patch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/.gitignore b/.gitignore | |
new file mode 100644 | |
index 0000000..37b1c60 | |
--- /dev/null | |
+++ b/.gitignore | |
@@ -0,0 +1,2 @@ | |
+dwm | |
+dwm.o | |
diff --git a/config.def.h b/config.def.h | |
index 77ff358..d22ce99 100644 | |
--- a/config.def.h | |
+++ b/config.def.h | |
@@ -1,7 +1,7 @@ | |
/* See LICENSE file for copyright and license details. */ | |
/* appearance */ | |
-static const char font[] = "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*"; | |
+static const char font[] = "Sans 8"; | |
static const char normbordercolor[] = "#444444"; | |
static const char normbgcolor[] = "#222222"; | |
static const char normfgcolor[] = "#bbbbbb"; | |
@@ -10,6 +10,8 @@ static const char selbgcolor[] = "#005577"; | |
static const char selfgcolor[] = "#eeeeee"; | |
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 */ | |
diff --git a/config.h b/config.h | |
new file mode 100644 | |
index 0000000..6888099 | |
--- /dev/null | |
+++ b/config.h | |
@@ -0,0 +1,126 @@ | |
+/* See LICENSE file for copyright and license details. */ | |
+ | |
+#include "push.c" | |
+#include <X11/XF86keysym.h> | |
+ | |
+/* appearance */ | |
+static const char font[] = "Monaco 8"; | |
+static const char normbordercolor[] = "#444444"; | |
+static const char normbgcolor[] = "#222222"; | |
+static const char normfgcolor[] = "#bbbbbb"; | |
+static const char selbordercolor[] = "#005577"; | |
+static const char selbgcolor[] = "#005577"; | |
+static const char selfgcolor[] = "#eeeeee"; | |
+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 */ | |
+ | |
+/* tagging */ | |
+static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; | |
+ | |
+static const Rule rules[] = { | |
+ /* class instance title tags mask isfloating monitor */ | |
+ { "URxvt", NULL, NULL, 5, False, -1 }, | |
+ { "Chromium", NULL, NULL, 6, False, -1 }, | |
+}; | |
+ | |
+/* layout(s) */ | |
+static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ | |
+static const int nmaster = 1; /* number of clients in master area */ | |
+static const Bool resizehints = False; /* True means respect size hints in tiled resizals */ | |
+ | |
+static const Layout layouts[] = { | |
+ /* symbol arrange function */ | |
+ { "[]=", tile }, /* first entry is default */ | |
+ { "><>", NULL }, /* no layout function means floating behavior */ | |
+ { "[M]", monocle }, | |
+}; | |
+ | |
+/* key definitions */ | |
+#define MODKEY Mod4Mask | |
+#define TAGKEYS(KEY,TAG) \ | |
+ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ | |
+ { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ | |
+ { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ | |
+ { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, | |
+ | |
+/* helper for spawning shell commands in the pre dwm-5.0 fashion */ | |
+#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } | |
+#define VOLCMD(cmd) { .v = (const char*[]){ "amixer", "-q", "-c", "0", "sset", "Master", cmd, NULL } } | |
+ | |
+/* commands */ | |
+static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL }; | |
+static const char *termcmd[] = { "urxvtc", NULL }; | |
+static const char *browsercmd[] = { "chromium", NULL }; | |
+static const char *filecmd[] = { "thunar", NULL }; | |
+static const char *sleepcmd[] = { "sudo", "pm-suspend", NULL }; | |
+static const char *screensaver[] = { "xscreensaver-command", "-lock", NULL }; | |
+ | |
+static Key keys[] = { | |
+ /* modifier key function argument */ | |
+ { MODKEY, XK_space, spawn, {.v = dmenucmd } }, | |
+ { MODKEY, XK_Return, spawn, {.v = termcmd } }, | |
+ { MODKEY, XK_BackSpace, spawn, {.v = browsercmd } }, | |
+ { MODKEY, XK_b, togglebar, {0} }, | |
+ { MODKEY, XK_j, focusstack, {.i = +1 } }, | |
+ { MODKEY|ShiftMask, XK_j, pushdown, {0} }, | |
+ { MODKEY, XK_k, focusstack, {.i = -1 } }, | |
+ { MODKEY|ShiftMask, XK_k, pushup, {0} }, | |
+ { MODKEY, XK_i, incnmaster, {.i = +1 } }, | |
+ { MODKEY, XK_d, incnmaster, {.i = -1 } }, | |
+ { MODKEY, XK_h, setmfact, {.f = -0.05} }, | |
+ { MODKEY, XK_l, setmfact, {.f = +0.05} }, | |
+ { MODKEY|ShiftMask, XK_Return, zoom, {0} }, | |
+ { MODKEY, XK_Tab, view, {0} }, | |
+ { MODKEY|ShiftMask, XK_c, killclient, {0} }, | |
+ { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, | |
+ { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, | |
+ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, | |
+ { MODKEY, XK_p, setlayout, {0} }, | |
+ { MODKEY|ShiftMask, XK_p, togglefloating, {0} }, | |
+ { MODKEY, XK_0, view, {.ui = ~0 } }, | |
+ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, | |
+ { MODKEY, XK_comma, focusmon, {.i = -1 } }, | |
+ { MODKEY, XK_period, focusmon, {.i = +1 } }, | |
+ { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, | |
+ { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, | |
+ TAGKEYS( XK_1, 0) | |
+ TAGKEYS( XK_2, 1) | |
+ TAGKEYS( XK_3, 2) | |
+ TAGKEYS( XK_4, 3) | |
+ TAGKEYS( XK_5, 4) | |
+ TAGKEYS( XK_6, 5) | |
+ TAGKEYS( XK_7, 6) | |
+ TAGKEYS( XK_8, 7) | |
+ TAGKEYS( XK_9, 8) | |
+ { MODKEY|ShiftMask, XK_q, quit, {0} }, | |
+ /* Function Keys */ | |
+ {0, XF86XK_AudioMute, spawn, VOLCMD("toggle")}, | |
+ {0, XF86XK_AudioRaiseVolume, spawn, VOLCMD("5%+")}, | |
+ {0, XF86XK_AudioLowerVolume, spawn, VOLCMD("5%-")}, | |
+ {0, XF86XK_Launch1, spawn, {.v = filecmd} }, | |
+ {0, XF86XK_ScreenSaver, spawn, {.v = screensaver} }, | |
+ {0, XF86XK_Sleep, spawn, {.v = sleepcmd } }, | |
+ | |
+}; | |
+ | |
+/* button definitions */ | |
+/* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ | |
+static Button buttons[] = { | |
+ /* click event mask button function argument */ | |
+ { ClkLtSymbol, 0, Button1, setlayout, {0} }, | |
+ { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, | |
+ { ClkWinTitle, 0, Button2, zoom, {0} }, | |
+ { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, | |
+ { ClkClientWin, MODKEY, Button1, movemouse, {0} }, | |
+ { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, | |
+ { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, | |
+ { ClkTagBar, 0, Button1, view, {0} }, | |
+ { ClkTagBar, 0, Button3, toggleview, {0} }, | |
+ { ClkTagBar, MODKEY, Button1, tag, {0} }, | |
+ { ClkTagBar, MODKEY, Button3, toggletag, {0} }, | |
+}; | |
+ | |
diff --git a/config.mk b/config.mk | |
index 484554a..48264b9 100644 | |
--- a/config.mk | |
+++ b/config.mk | |
@@ -4,7 +4,7 @@ VERSION = 6.0 | |
# Customize below to fit your system | |
# paths | |
-PREFIX = /usr/local | |
+PREFIX = /home/menski/.local/ | |
MANPREFIX = ${PREFIX}/share/man | |
X11INC = /usr/X11R6/include | |
@@ -15,8 +15,8 @@ XINERAMALIBS = -L${X11LIB} -lXinerama | |
XINERAMAFLAGS = -DXINERAMA | |
# includes and libs | |
-INCS = -I. -I/usr/include -I${X11INC} | |
-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS} | |
+INCS = -I. -I/usr/include -I${X11INC} `pkg-config --cflags xft pango pangoxft` | |
+LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS} `pkg-config --libs xft pango pangoxft` | |
# flags | |
CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} | |
diff --git a/dwm.c b/dwm.c | |
index 1d78655..4a34faa 100644 | |
--- a/dwm.c | |
+++ b/dwm.c | |
@@ -36,6 +36,10 @@ | |
#include <X11/Xlib.h> | |
#include <X11/Xproto.h> | |
#include <X11/Xutil.h> | |
+#include <X11/Xft/Xft.h> | |
+#include <pango/pango.h> | |
+#include <pango/pangoxft.h> | |
+#include <pango/pango-font.h> | |
#ifdef XINERAMA | |
#include <X11/extensions/Xinerama.h> | |
#endif /* XINERAMA */ | |
@@ -47,20 +51,42 @@ | |
* MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) | |
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) | |
#define LENGTH(X) (sizeof X / sizeof X[0]) | |
-#define MAX(A, B) ((A) > (B) ? (A) : (B)) | |
+#ifndef MAX | |
+#define MAX(A, B) ((A) > (B) ? (A) : (B)) | |
+#endif | |
+#ifndef MIN | |
#define MIN(A, B) ((A) < (B) ? (A) : (B)) | |
+#endif | |
#define MOUSEMASK (BUTTONMASK|PointerMotionMask) | |
#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) (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 { NetSupported, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, | |
+ NetWMName, NetWMState, NetWMFullscreen, NetActiveWindow, NetWMWindowType, | |
+ NetWMWindowTypeDialog, 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 */ | |
@@ -103,12 +129,19 @@ typedef struct { | |
unsigned long sel[ColLast]; | |
Drawable drawable; | |
GC gc; | |
+ | |
+ XftColor xftnorm[ColLast]; | |
+ XftColor xftsel[ColLast]; | |
+ XftDraw *xftdrawable; | |
+ | |
+ PangoContext *pgc; | |
+ PangoLayout *plo; | |
+ PangoFontDescription *pfd; | |
+ | |
struct { | |
int ascent; | |
int descent; | |
int height; | |
- XFontSet set; | |
- XFontStruct *xfont; | |
} font; | |
} DC; /* draw context */ | |
@@ -124,6 +157,7 @@ typedef struct { | |
void (*arrange)(Monitor *); | |
} Layout; | |
+typedef struct Pertag Pertag; | |
struct Monitor { | |
char ltsymbol[16]; | |
float mfact; | |
@@ -143,6 +177,7 @@ struct Monitor { | |
Monitor *next; | |
Window barwin; | |
const Layout *lt[2]; | |
+ Pertag *pertag; | |
}; | |
typedef struct { | |
@@ -154,6 +189,12 @@ typedef struct { | |
int monitor; | |
} Rule; | |
+typedef struct Systray Systray; | |
+struct Systray { | |
+ Window win; | |
+ Client *icons; | |
+}; | |
+ | |
/* function declarations */ | |
static void applyrules(Client *c); | |
static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact); | |
@@ -186,9 +227,11 @@ static void focus(Client *c); | |
static void focusin(XEvent *e); | |
static void focusmon(const Arg *arg); | |
static void focusstack(const Arg *arg); | |
-static unsigned long getcolor(const char *colstr); | |
+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); | |
@@ -207,13 +250,16 @@ 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); | |
@@ -241,18 +287,24 @@ static void updatebars(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 const char broken[] = "broken"; | |
static char stext[256]; | |
static int screen; | |
@@ -274,9 +326,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { | |
[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 Cursor cursor[CurLast]; | |
static Display *dpy; | |
@@ -287,6 +340,15 @@ static Window root; | |
/* 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]; }; | |
@@ -485,10 +547,6 @@ cleanup(void) { | |
for(m = mons; m; m = m->next) | |
while(m->stack) | |
unmanage(m->stack, False); | |
- if(dc.font.set) | |
- XFreeFontSet(dpy, dc.font.set); | |
- else | |
- XFreeFont(dpy, dc.font.xfont); | |
XUngrabKey(dpy, AnyKey, AnyModifier, root); | |
XFreePixmap(dpy, dc.drawable); | |
XFreeGC(dpy, dc.gc); | |
@@ -497,6 +555,11 @@ 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); | |
} | |
@@ -530,9 +593,48 @@ 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; | |
+ XChangeWindowAttributes(dpy, c->win, CWBackPixmap, &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]) { | |
@@ -581,9 +683,10 @@ configurenotify(XEvent *e) { | |
if(dc.drawable != 0) | |
XFreePixmap(dpy, dc.drawable); | |
dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); | |
+ XftDrawChange(dc.xftdrawable, dc.drawable); | |
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); | |
} | |
@@ -646,6 +749,7 @@ configurerequest(XEvent *e) { | |
Monitor * | |
createmon(void) { | |
Monitor *m; | |
+ int i; | |
if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) | |
die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); | |
@@ -657,6 +761,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,6 +789,11 @@ destroynotify(XEvent *e) { | |
if((c = wintoclient(ev->window))) | |
unmanage(c, True); | |
+ else if((c = wintosystrayicon(ev->window))) { | |
+ removesystrayicon(c); | |
+ resizebarwin(selmon); | |
+ updatesystray(); | |
+ } | |
} | |
void | |
@@ -722,6 +849,7 @@ drawbar(Monitor *m) { | |
unsigned long *col; | |
Client *c; | |
+ resizebarwin(m); | |
for(c = m->clients; c; c = c->next) { | |
occ |= c->tags; | |
if(c->isurgent) | |
@@ -740,17 +868,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 +898,7 @@ drawbars(void) { | |
for(m = mons; m; m = m->next) | |
drawbar(m); | |
+ updatesystray(); | |
} | |
void | |
@@ -796,7 +924,7 @@ drawtext(const char *text, unsigned long col[ColLast], Bool invert) { | |
return; | |
olen = strlen(text); | |
h = dc.font.ascent + dc.font.descent; | |
- y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; | |
+ y = dc.y; | |
x = dc.x + (h / 2); | |
/* shorten text if necessary */ | |
for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--); | |
@@ -805,11 +933,8 @@ drawtext(const char *text, unsigned long col[ColLast], Bool invert) { | |
memcpy(buf, text, len); | |
if(len < olen) | |
for(i = len; i && i > len - 3; buf[--i] = '.'); | |
- XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]); | |
- if(dc.font.set) | |
- XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len); | |
- else | |
- XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); | |
+ pango_layout_set_text(dc.plo, text, len); | |
+ pango_xft_render_layout(dc.xftdrawable, (col==dc.norm?dc.xftnorm:dc.xftsel)+(invert?ColBG:ColFG), dc.plo, x * PANGO_SCALE, y * PANGO_SCALE); | |
} | |
void | |
@@ -917,23 +1042,30 @@ 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; | |
} | |
unsigned long | |
-getcolor(const char *colstr) { | |
+getcolor(const char *colstr, XftColor *color) { | |
Colormap cmap = DefaultColormap(dpy, screen); | |
- XColor color; | |
+ Visual *vis = DefaultVisual(dpy, screen); | |
- if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) | |
+ if(!XftColorAllocName(dpy,vis,cmap,colstr, color)) | |
die("error, cannot allocate color '%s'\n", colstr); | |
- return color.pixel; | |
+ return color->pixel; | |
} | |
Bool | |
@@ -962,6 +1094,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,41 +1169,25 @@ 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); | |
} | |
void | |
initfont(const char *fontstr) { | |
- char *def, **missing; | |
- int n; | |
+ PangoFontMetrics *metrics; | |
- dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); | |
- if(missing) { | |
- while(n--) | |
- fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]); | |
- XFreeStringList(missing); | |
- } | |
- if(dc.font.set) { | |
- XFontStruct **xfonts; | |
- char **font_names; | |
- | |
- dc.font.ascent = dc.font.descent = 0; | |
- XExtentsOfFontSet(dc.font.set); | |
- n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); | |
- while(n--) { | |
- dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent); | |
- dc.font.descent = MAX(dc.font.descent,(*xfonts)->descent); | |
- xfonts++; | |
- } | |
- } | |
- else { | |
- if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)) | |
- && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed"))) | |
- die("error, cannot load font: '%s'\n", fontstr); | |
- dc.font.ascent = dc.font.xfont->ascent; | |
- dc.font.descent = dc.font.xfont->descent; | |
- } | |
+ dc.pgc = pango_xft_get_context(dpy, screen); | |
+ dc.pfd = pango_font_description_from_string(fontstr); | |
+ | |
+ metrics = pango_context_get_metrics(dc.pgc, dc.pfd, pango_language_from_string(setlocale(LC_CTYPE, ""))); | |
+ dc.font.ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; | |
+ dc.font.descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE; | |
+ | |
+ pango_font_metrics_unref(metrics); | |
+ | |
+ dc.plo = pango_layout_new(dc.pgc); | |
+ pango_layout_set_font_description(dc.plo, dc.pfd); | |
dc.font.height = dc.font.ascent + dc.font.descent; | |
} | |
@@ -1096,7 +1221,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); | |
@@ -1180,6 +1305,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; | |
@@ -1293,6 +1424,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) | |
@@ -1342,12 +1483,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; | |
@@ -1412,6 +1574,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; | |
@@ -1495,25 +1669,35 @@ 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; | |
} | |
@@ -1522,7 +1706,7 @@ void | |
setfocus(Client *c) { | |
if(!c->neverfocus) | |
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); | |
- sendevent(c, wmatom[WMTakeFocus]); | |
+ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); | |
} | |
void | |
@@ -1555,10 +1739,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 +1763,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); | |
} | |
@@ -1602,28 +1789,41 @@ 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); | |
+ 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); | |
cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); | |
+ | |
/* init appearance */ | |
- dc.norm[ColBorder] = getcolor(normbordercolor); | |
- dc.norm[ColBG] = getcolor(normbgcolor); | |
- dc.norm[ColFG] = getcolor(normfgcolor); | |
- dc.sel[ColBorder] = getcolor(selbordercolor); | |
- dc.sel[ColBG] = getcolor(selbgcolor); | |
- dc.sel[ColFG] = getcolor(selfgcolor); | |
+ dc.norm[ColBorder] = getcolor(normbordercolor, dc.xftnorm+ColBorder); | |
+ dc.norm[ColBG] = getcolor(normbgcolor, dc.xftnorm+ColBG); | |
+ dc.norm[ColFG] = getcolor(normfgcolor, dc.xftnorm+ColFG); | |
+ dc.sel[ColBorder] = getcolor(selbordercolor, dc.xftsel+ColBorder); | |
+ dc.sel[ColBG] = getcolor(selbgcolor, dc.xftsel+ColBG); | |
+ dc.sel[ColFG] = getcolor(selfgcolor, dc.xftsel+ColFG); | |
+ | |
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 bars */ | |
+ | |
+ dc.xftdrawable = XftDrawCreate(dpy, dc.drawable, DefaultVisual(dpy,screen), DefaultColormap(dpy,screen)); | |
+ if(!dc.xftdrawable) | |
+ printf("error, cannot create drawable\n"); | |
+ | |
+ /* init system tray */ | |
+ updatesystray(); | |
+ /* init bar */ | |
updatebars(); | |
updatestatus(); | |
/* EWMH support per view */ | |
@@ -1692,13 +1892,10 @@ tagmon(const Arg *arg) { | |
int | |
textnw(const char *text, unsigned int len) { | |
- XRectangle r; | |
- | |
- if(dc.font.set) { | |
- XmbTextExtents(dc.font.set, text, len, NULL, &r); | |
- return r.width; | |
- } | |
- return XTextWidth(dc.font.xfont, text, len); | |
+ PangoRectangle r; | |
+ pango_layout_set_text(dc.plo, text, len); | |
+ pango_layout_get_extents(dc.plo, &r, 0); | |
+ return r.width / PANGO_SCALE; | |
} | |
void | |
@@ -1729,9 +1926,20 @@ tile(Monitor *m) { | |
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); | |
} | |
@@ -1763,9 +1971,29 @@ toggletag(const Arg *arg) { | |
void | |
toggleview(const Arg *arg) { | |
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); | |
+ int i; | |
if(newtagset) { | |
+ 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]; | |
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) | |
+ togglebar(NULL); | |
focus(NULL); | |
arrange(selmon); | |
} | |
@@ -1816,18 +2044,28 @@ 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), | |
+ 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]); | |
@@ -2005,9 +2243,109 @@ 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, &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); | |
+ XSync(dpy, False); | |
} | |
void | |
@@ -2043,11 +2381,33 @@ updatewmhints(Client *c) { | |
void | |
view(const Arg *arg) { | |
+ int i; | |
+ unsigned int tmptag; | |
+ | |
if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) | |
return; | |
selmon->seltags ^= 1; /* toggle sel tagset */ | |
- if(arg->ui & TAGMASK) | |
+ 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]; | |
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) | |
+ togglebar(NULL); | |
focus(NULL); | |
arrange(selmon); | |
} | |
@@ -2080,6 +2440,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. */ | |
diff --git a/push.c b/push.c | |
new file mode 100644 | |
index 0000000..493613c | |
--- /dev/null | |
+++ b/push.c | |
@@ -0,0 +1,58 @@ | |
+static Client * | |
+prevtiled(Client *c) { | |
+ Client *p, *r; | |
+ | |
+ for(p = selmon->clients, r = NULL; p && p != c; p = p->next) | |
+ if(!p->isfloating && ISVISIBLE(p)) | |
+ 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->clients == c) | |
+ selmon->clients = sel; | |
+ else { | |
+ for(c = selmon->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))) { | |
+ /* 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); | |
+} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment