diff options
| author | LM-LCL <hello@exaltedelite.club> | 2024-02-21 16:02:02 +0100 |
|---|---|---|
| committer | LM-LCL <hello@exaltedelite.club> | 2024-02-21 16:02:02 +0100 |
| commit | 00d1bbc05e5573123de9d8d02ffb97e616f623ec (patch) | |
| tree | 4e326ad4efa33d49ed8aa26d3cae69627f4aa29c | |
| parent | 0fd213f02ef7504a1df91712e2099a5e0145655b (diff) | |
dwm-6.4-v2
| -rw-r--r-- | config.def.h | 55 | ||||
| -rw-r--r-- | config.h | 56 | ||||
| -rw-r--r-- | dwm.1 | 3 | ||||
| -rw-r--r-- | dwm.c | 468 | ||||
| -rw-r--r-- | movestack.c | 49 | ||||
| -rw-r--r-- | patches/dwm-alwayscenter-20200625-f04cac6.diff | 12 | ||||
| -rw-r--r-- | patches/dwm-attachbelow-6.2.diff | 96 | ||||
| -rw-r--r-- | patches/dwm-movestack-6.1.diff | 73 | ||||
| -rw-r--r-- | patches/dwm-pertag-20200914-61bb8b2.diff (renamed from patches/dwm-pertag-6.2.diff) | 22 | ||||
| -rw-r--r-- | patches/dwm-splitstatus-20201114-61bb8b2.diff | 77 | ||||
| -rw-r--r-- | patches/dwm-systray-6.4.diff | 746 |
11 files changed, 1214 insertions, 443 deletions
diff --git a/config.def.h b/config.def.h index deba5ad..ef4400a 100644 --- a/config.def.h +++ b/config.def.h @@ -1,24 +1,25 @@ /* See LICENSE file for copyright and license details. */ /* appearance */ -static const unsigned int borderpx = 1; /* border pixel of windows */ -static const unsigned int snap = 32; /* snap pixel */ -static const int showbar = 1; /* 0 means no bar */ -static const int topbar = 1; /* 0 means bottom bar */ -static const int focusonwheel = 0; /* 0 means focus on click */ -static const int splitstatus = 1; /* 1 for split status items */ -static const char *splitdelim = ";"; /* Character used for separating status */ -static const char *fonts[] = { "monospace:size=10" }; -static const char dmenufont[] = "monospace:size=10"; -static const char col_gray1[] = "#222222"; -static const char col_gray2[] = "#444444"; -static const char col_gray3[] = "#bbbbbb"; -static const char col_gray4[] = "#eeeeee"; -static const char col_cyan[] = "#005577"; -static const char *colors[][3] = { +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const unsigned int snap = 32; /* snap pixel */ +static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ +static const unsigned int systrayonleft = 1; /* 0: systray in the right corner, >0: systray on left of status text */ +static const unsigned int systrayspacing = 2; /* systray spacing */ +static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ +static const int showsystray = 1; /* 0 means no systray */ +static const int showbar = 1; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ +static const int focusonwheel = 0; +static const char *fonts[] = { "monospace:size=12" }; +static const char dmenufont[] = "monospace:size=12"; +static const char col_gray1[] = "#282c34"; +static const char col_gray2[] = "#353b45"; +static const char col_white[] = "#abb2bf"; +static const char *colors[][3] = { /* fg bg border */ - [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, - [SchemeSel] = { col_gray4, col_cyan, col_cyan }, + [SchemeNorm] = { col_white, col_gray1, col_gray2 }, + [SchemeSel] = { col_white, col_gray2, col_white }, }; /* tagging */ @@ -31,15 +32,14 @@ static const Rule rules[] = { */ /* class instance title tags mask isfloating monitor */ { "Gimp", NULL, NULL, 0, 1, -1 }, - { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, + /* { "Firefox", NULL, NULL, 1 << 8, 0, -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 int resizehints = 1; /* 1 means respect size hints in tiled resizals */ -static const int attachbelow = 1; /* 1 means attach after the currently active window */ -static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ +static const float mfact = 0.50; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ static const Layout layouts[] = { /* symbol arrange function */ @@ -60,10 +60,9 @@ static const Layout layouts[] = { #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } /* commands */ -static const char *dmenucmd[] = { "dmenu_run", "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +static const char *dmenucmd[] = { "dmenu_run", "-fn", dmenufont, "-nb", col_gray1, "-nf", col_white, "-sb", col_gray2, "-sf", col_white, NULL }; static const char *termcmd[] = { "st", NULL }; -#include "movestack.c" static const Key keys[] = { /* modifier key function argument */ { MODKEY, XK_p, spawn, {.v = dmenucmd } }, @@ -75,8 +74,6 @@ static const Key keys[] = { { MODKEY, XK_d, incnmaster, {.i = -1 } }, { MODKEY, XK_h, setmfact, {.f = -0.05} }, { MODKEY, XK_l, setmfact, {.f = +0.05} }, - { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } }, - { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, { MODKEY, XK_Return, zoom, {0} }, { MODKEY, XK_Tab, view, {0} }, { MODKEY|ShiftMask, XK_c, killclient, {0} }, @@ -107,8 +104,8 @@ static const Key keys[] = { /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ static const Button buttons[] = { /* click event mask button function argument */ - { ClkLtSymbol, 0, Button1, setlayout, {0} }, - { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, { ClkWinTitle, 0, Button2, zoom, {0} }, { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, { ClkClientWin, MODKEY, Button1, movemouse, {0} }, @@ -1,22 +1,25 @@ /* See LICENSE file for copyright and license details. */ /* appearance */ -static const unsigned int borderpx = 1; /* border pixel of windows */ -static const unsigned int snap = 32; /* snap pixel */ -static const int showbar = 1; /* 0 means no bar */ -static const int topbar = 1; /* 0 means bottom bar */ -static const int focusonwheel = 0; /* 0 means focus on click */ -static const int splitstatus = 1; /* 1 for split status items */ -static const char *splitdelim = ";"; /* Character used for separating status */ -static const char *fonts[] = { "monospace:size=12" }; -static const char dmenufont[] = "monospace:size=12"; -static const char col_gray1[] = "#282c34"; -static const char col_gray2[] = "#353b45"; -static const char col_white[] = "#abb2bf"; -static const char *colors[][3] = { +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const unsigned int snap = 32; /* snap pixel */ +static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ +static const unsigned int systrayonleft = 1; /* 0: systray in the right corner, >0: systray on left of status text */ +static const unsigned int systrayspacing = 2; /* systray spacing */ +static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ +static const int showsystray = 1; /* 0 means no systray */ +static const int showbar = 1; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ +static const int focusonwheel = 0; +static const char *fonts[] = { "monospace:size=12" }; +static const char dmenufont[] = "monospace:size=12"; +static const char col_gray1[] = "#282c34"; +static const char col_gray2[] = "#353b45"; +static const char col_white[] = "#abb2bf"; +static const char *colors[][3] = { /* fg bg border */ - [SchemeNorm] = { col_white, col_gray1, col_gray2 }, - [SchemeSel] = { col_white, col_gray2, col_white }, + [SchemeNorm] = { col_white, col_gray1, col_gray2 }, + [SchemeSel] = { col_white, col_gray2, col_white }, }; /* tagging */ @@ -33,11 +36,10 @@ static const Rule rules[] = { }; /* layout(s) */ -static const float mfact = 0.50; /* factor of master area size [0.05..0.95] */ -static const int nmaster = 1; /* number of clients in master area */ -static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */ -static const int attachbelow = 1; /* 1 means attach after the currently active window */ -static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ +static const float mfact = 0.50; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ static const Layout layouts[] = { /* symbol arrange function */ @@ -61,21 +63,25 @@ static const Layout layouts[] = { static const char *dmenucmd[] = { "dmenu_run", "-fn", dmenufont, "-nb", col_gray1, "-nf", col_white, "-sb", col_gray2, "-sf", col_white, NULL }; static const char *termcmd[] = { "st", NULL }; -#include "movestack.c" static const Key keys[] = { /* modifier key function argument */ { MODKEY, XK_p, spawn, {.v = dmenucmd } }, { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, { MODKEY, XK_j, focusstack, {.i = +1 } }, { MODKEY, XK_k, focusstack, {.i = -1 } }, + { 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_j, movestack, {.i = +1 } }, - { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, { MODKEY, 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_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, { MODKEY, XK_0, view, {.ui = ~0 } }, { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, { MODKEY, XK_comma, focusmon, {.i = -1 } }, @@ -98,8 +104,8 @@ static const Key keys[] = { /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ static const Button buttons[] = { /* click event mask button function argument */ - { ClkLtSymbol, 0, Button1, setlayout, {0} }, - { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, { ClkWinTitle, 0, Button2, zoom, {0} }, { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, { ClkClientWin, MODKEY, Button1, movemouse, {0} }, @@ -29,9 +29,6 @@ color. The tags of the focused window are indicated with a filled square in the top left corner. The tags which are applied to one or more windows are indicated with an empty square in the top left corner. .P -The attach below patch makes newly spawned windows attach after the currently -selected window -.P dwm draws a small border around windows to indicate the focus state. .SH OPTIONS .TP @@ -57,12 +57,27 @@ #define TAGMASK ((1 << LENGTH(tags)) - 1) #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) +#define SYSTEM_TRAY_REQUEST_DOCK 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 { SchemeNorm, SchemeSel }; /* color schemes */ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, + NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ +enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ @@ -143,13 +158,18 @@ typedef struct { int monitor; } Rule; +typedef struct Systray Systray; +struct Systray { + Window win; + Client *icons; +}; + /* function declarations */ static void applyrules(Client *c); static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); static void arrange(Monitor *m); static void arrangemon(Monitor *m); static void attach(Client *c); -static void attachBelow(Client *c); static void attachstack(Client *c); static void buttonpress(XEvent *e); static void checkotherwm(void); @@ -174,6 +194,7 @@ static void focusstack(const Arg *arg); static Atom getatomprop(Client *c, Atom prop); static int getrootptr(int *x, int *y); static long getstate(Window w); +static unsigned int getsystraywidth(); static int gettextprop(Window w, Atom atom, char *text, unsigned int size); static void grabbuttons(Client *c, int focused); static void grabkeys(void); @@ -190,13 +211,16 @@ static void pop(Client *c); 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, int 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 int sendevent(Client *c, Atom proto); +static int 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); @@ -208,6 +232,7 @@ static void seturgent(Client *c, int urg); static void showhide(Client *c); static void sigchld(int unused); static void spawn(const Arg *arg); +static Monitor *systraytomon(Monitor *m); static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *m); @@ -225,18 +250,23 @@ static int updategeom(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 updatetitle(Client *c); static void updatewindowtype(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 const char broken[] = "broken"; static char stext[256]; static int screen; @@ -257,9 +287,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { [MappingNotify] = mappingnotify, [MapRequest] = maprequest, [PropertyNotify] = propertynotify, + [ResizeRequest] = resizerequest, [UnmapNotify] = unmapnotify }; -static Atom wmatom[WMLast], netatom[NetLast]; +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; static int running = 1; static Cur *cursor[CurLast]; static Clr **scheme; @@ -416,21 +447,6 @@ attach(Client *c) c->next = c->mon->clients; c->mon->clients = c; } -void -attachBelow(Client *c) -{ - //If there is nothing on the monitor or the selected client is floating, attach as normal - if(c->mon->sel == NULL || c->mon->sel == c || c->mon->sel->isfloating) { - attach(c); - return; - } - - //Set the new client's next property to the same as the currently selected clients next - c->next = c->mon->sel->next; - //Set the currently selected clients next property to the new client - c->mon->sel->next = c; - -} void attachstack(Client *c) @@ -466,7 +482,7 @@ buttonpress(XEvent *e) arg.ui = 1 << i; } else if (ev->x < x + TEXTW(selmon->ltsymbol)) click = ClkLtSymbol; - else if (ev->x > selmon->ww - (int)TEXTW(stext)) + else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth()) click = ClkStatusText; else click = ClkWinTitle; @@ -509,6 +525,13 @@ cleanup(void) XUngrabKey(dpy, AnyKey, AnyModifier, root); while (mons) cleanupmon(mons); + + if (showsystray) { + XUnmapWindow(dpy, systray->win); + XDestroyWindow(dpy, systray->win); + free(systray); + } + for (i = 0; i < CurLast; i++) drw_cur_free(drw, cursor[i]); for (i = 0; i < LENGTH(colors); i++) @@ -540,9 +563,58 @@ cleanupmon(Monitor *mon) 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)); + if (!(c->win = cme->data.l[2])) { + free(c); + return; + } + c->mon = selmon; + c->next = systray->icons; + systray->icons = c; + if (!XGetWindowAttributes(dpy, c->win, &wa)) { + /* use sane defaults */ + wa.width = bh; + wa.height = bh; + wa.border_width = 0; + } + 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 color */ + swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; + XChangeWindowAttributes(dpy, c->win, 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); + XSync(dpy, False); + resizebarwin(selmon); + updatesystray(); + setclientstate(c, NormalState); + } + return; + } + if (!c) return; if (cme->message_type == netatom[NetWMState]) { @@ -595,7 +667,7 @@ configurenotify(XEvent *e) for (c = m->clients; c; c = c->next) if (c->isfullscreen) resizeclient(c, m->mx, m->my, m->mw, m->mh); - XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); + resizebarwin(m); } focus(NULL); arrange(NULL); @@ -695,6 +767,11 @@ destroynotify(XEvent *e) if ((c = wintoclient(ev->window))) unmanage(c, 1); + else if ((c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + resizebarwin(selmon); + updatesystray(); + } } void @@ -738,7 +815,7 @@ dirtomon(int dir) void drawbar(Monitor *m) { - int x, w, tw = 0; + int x, w, tw = 0, stw = 0; int boxs = drw->fonts->h / 9; int boxw = drw->fonts->h / 6 + 2; unsigned int i, occ = 0, urg = 0; @@ -747,10 +824,17 @@ drawbar(Monitor *m) if (!m->showbar) return; - char *mstext; - char *rstext; - int msx; + if(showsystray && m == systraytomon(m) && !systrayonleft) + stw = getsystraywidth(); + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ + drw_setscheme(drw, scheme[SchemeNorm]); + tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px extra right padding */ + drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0); + } + + resizebarwin(m); for (c = m->clients; c; c = c->next) { occ |= c->tags; if (c->isurgent) @@ -771,21 +855,18 @@ drawbar(Monitor *m) drw_setscheme(drw, scheme[SchemeNorm]); x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); - drw_setscheme(drw, scheme[SchemeNorm]); - drw_rect(drw, x, 0, m->ww - x, bh, 1, 1); - - if (m == selmon) { /* status is only drawn on selected monitor */ - rstext = strdup(stext); - if (splitstatus) { - mstext = strsep(&rstext, splitdelim); - msx = (m->ww - TEXTW(mstext) + lrpad) / 2; /* x position of middle status text */ - drw_text(drw, msx, 0, TEXTW(mstext) - lrpad, bh, 0, mstext, 0); + if ((w = m->ww - tw - stw - x) > bh) { + if (m->sel) { + drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); + if (m->sel->isfloating) + drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); + } else { + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, x, 0, w, bh, 1, 1); } - tw = TEXTW(rstext) - lrpad + 2; /* 2px right padding */ - drw_text(drw, m->ww - tw, 0, tw, bh, 0, rstext, 0); } - - drw_map(drw, m->barwin, 0, 0, m->ww, bh); + drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); } void @@ -803,8 +884,11 @@ expose(XEvent *e) Monitor *m; XExposeEvent *ev = &e->xexpose; - if (ev->count == 0 && (m = wintomon(ev->window))) + if (ev->count == 0 && (m = wintomon(ev->window))) { drawbar(m); + if (m == selmon) + updatesystray(); + } } void @@ -890,14 +974,32 @@ getatomprop(Client *c, Atom prop) unsigned char *p = NULL; Atom da, atom = None; - if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, + /* 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, 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 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; +} + int getrootptr(int *x, int *y) { @@ -1028,7 +1130,8 @@ 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); @@ -1079,18 +1182,13 @@ manage(Window w, XWindowAttributes *wa) updatewindowtype(c); updatesizehints(c); updatewmhints(c); - c->x = c->mon->mx + (c->mon->mw - WIDTH(c)) / 2; - c->y = c->mon->my + (c->mon->mh - HEIGHT(c)) / 2; XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); grabbuttons(c, 0); if (!c->isfloating) c->isfloating = c->oldstate = trans != None || c->isfixed; if (c->isfloating) XRaiseWindow(dpy, c->win); - if( attachbelow ) - attachBelow(c); - else - attach(c); + attach(c); attachstack(c); XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, (unsigned char *) &(c->win), 1); @@ -1120,6 +1218,13 @@ 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) || wa.override_redirect) return; if (!wintoclient(ev->window)) @@ -1224,6 +1329,17 @@ 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) @@ -1275,6 +1391,19 @@ 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, int interact) { if (applysizehints(c, &x, &y, &w, &h, interact)) @@ -1282,6 +1411,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) } void +resizebarwin(Monitor *m) { + unsigned int w = m->ww; + if (showsystray && m == systraytomon(m) && !systrayonleft) + 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; @@ -1297,6 +1434,19 @@ resizeclient(Client *c, int x, int y, int w, int h) } 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 resizemouse(const Arg *arg) { int ocx, ocy, nw, nh; @@ -1426,10 +1576,7 @@ sendmon(Client *c, Monitor *m) detachstack(c); c->mon = m; c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ - if( attachbelow ) - attachBelow(c); - else - attach(c); + attach(c); attachstack(c); focus(NULL); arrange(NULL); @@ -1445,26 +1592,37 @@ setclientstate(Client *c, long state) } int -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; int exists = 0; 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; } @@ -1478,7 +1636,7 @@ setfocus(Client *c) XA_WINDOW, 32, PropModeReplace, (unsigned char *) &(c->win), 1); } - sendevent(c, wmatom[WMTakeFocus]); + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); } void @@ -1567,6 +1725,10 @@ 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[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False); netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); @@ -1574,6 +1736,9 @@ setup(void) 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] = drw_cur_create(drw, XC_left_ptr); cursor[CurResize] = drw_cur_create(drw, XC_sizing); @@ -1582,6 +1747,8 @@ setup(void) scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); for (i = 0; i < LENGTH(colors); i++) scheme[i] = drw_scm_create(drw, colors[i], 3); + /* init system tray */ + updatesystray(); /* init bars */ updatebars(); updatestatus(); @@ -1710,7 +1877,18 @@ togglebar(const Arg *arg) { 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); } @@ -1830,11 +2008,18 @@ unmapnotify(XEvent *e) else unmanage(c, 0); } + else if ((c = wintosystrayicon(ev->window))) { + /* KLUDGE! sometimes icons occasionally unmap their windows, but do + * _not_ destroy them. We map those windows back */ + XMapRaised(dpy, c->win); + updatesystray(); + } } void updatebars(void) { + unsigned int w; Monitor *m; XSetWindowAttributes wa = { .override_redirect = True, @@ -1845,10 +2030,15 @@ updatebars(void) for (m = mons; m; m = m->next) { if (m->barwin) continue; - m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), + w = m->ww; + if (showsystray && m == systraytomon(m)) + 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]->cursor); + if (showsystray && m == systraytomon(m)) + XMapRaised(dpy, systray->win); XMapRaised(dpy, m->barwin); XSetClassHint(dpy, m->barwin, &ch); } @@ -1932,10 +2122,7 @@ updategeom(void) m->clients = c->next; detachstack(c); c->mon = mons; - if( attachbelow ) - attachBelow(c); - else - attach(c); + attach(c); attachstack(c); } if (m == selmon) @@ -2028,6 +2215,125 @@ updatestatus(void) if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) strcpy(stext, "dwm-"VERSION); drawbar(selmon); + updatesystray(); +} + + +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 dimensions 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; + XWindowChanges wc; + Client *i; + Monitor *m = systraytomon(NULL); + unsigned int x = m->mx + m->mw; + unsigned int sw = TEXTW(stext) - lrpad + systrayspacing; + unsigned int w = 1; + + if (!showsystray) + return; + if (systrayonleft) + x -= sw + lrpad / 2; + 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, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); + wa.event_mask = ButtonPressMask | ExposureMask; + wa.override_redirect = True; + wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; + XSelectInput(dpy, systray->win, SubstructureNotifyMask); + XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, + PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 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) { + /* make sure the background color stays the same */ + wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; + XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); + XMapRaised(dpy, i->win); + w += systrayspacing; + i->x = w; + XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); + w += i->w; + if (i->mon != m) + i->mon = m; + } + w = w ? w + systrayspacing : 1; + x -= w; + XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); + wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; + wc.stack_mode = Above; wc.sibling = m->barwin; + XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); + XMapWindow(dpy, systray->win); + XMapSubwindows(dpy, systray->win); + /* redraw background */ + XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); + XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); + XSync(dpy, False); } void @@ -2121,6 +2427,16 @@ wintoclient(Window w) return NULL; } +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; +} + Monitor * wintomon(Window w) { @@ -2174,6 +2490,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee) return -1; } +Monitor * +systraytomon(Monitor *m) { + Monitor *t; + int i, n; + if(!systraypinning) { + if(!m) + return selmon; + return m == selmon ? m : NULL; + } + for(n = 1, t = mons; t && t->next; n++, t = t->next) ; + for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; + if(systraypinningfailfirst && n < systraypinning) + return mons; + return t; +} + void zoom(const Arg *arg) { diff --git a/movestack.c b/movestack.c deleted file mode 100644 index c040462..0000000 --- a/movestack.c +++ /dev/null @@ -1,49 +0,0 @@ -void -movestack(const Arg *arg) { - Client *c = NULL, *p = NULL, *pc = NULL, *i; - - if(arg->i > 0) { - /* find the client after selmon->sel */ - for(c = selmon->sel->next; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); - if(!c) - for(c = selmon->clients; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); - - } - else { - /* find the client before selmon->sel */ - for(i = selmon->clients; i != selmon->sel; i = i->next) - if(ISVISIBLE(i) && !i->isfloating) - c = i; - if(!c) - for(; i; i = i->next) - if(ISVISIBLE(i) && !i->isfloating) - c = i; - } - /* find the client before selmon->sel and c */ - for(i = selmon->clients; i && (!p || !pc); i = i->next) { - if(i->next == selmon->sel) - p = i; - if(i->next == c) - pc = i; - } - - /* swap c and selmon->sel selmon->clients in the selmon->clients list */ - if(c && c != selmon->sel) { - Client *temp = selmon->sel->next==c?selmon->sel:selmon->sel->next; - selmon->sel->next = c->next==selmon->sel?c:c->next; - c->next = temp; - - if(p && p != c) - p->next = c; - if(pc && pc != selmon->sel) - pc->next = selmon->sel; - - if(selmon->sel == selmon->clients) - selmon->clients = c; - else if(c == selmon->clients) - selmon->clients = selmon->sel; - - arrange(selmon); - } -} - diff --git a/patches/dwm-alwayscenter-20200625-f04cac6.diff b/patches/dwm-alwayscenter-20200625-f04cac6.diff deleted file mode 100644 index 03ea9ef..0000000 --- a/patches/dwm-alwayscenter-20200625-f04cac6.diff +++ /dev/null @@ -1,12 +0,0 @@ -diff -up dwm/dwm.c dwmmod/dwm.c ---- dwm/dwm.c 2020-06-25 00:21:30.383692180 -0300 -+++ dwmmod/dwm.c 2020-06-25 00:20:35.643692330 -0300 -@@ -1057,6 +1057,8 @@ manage(Window w, XWindowAttributes *wa) - updatewindowtype(c); - updatesizehints(c); - updatewmhints(c); -+ c->x = c->mon->mx + (c->mon->mw - WIDTH(c)) / 2; -+ c->y = c->mon->my + (c->mon->mh - HEIGHT(c)) / 2; - XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); - grabbuttons(c, 0); - if (!c->isfloating) diff --git a/patches/dwm-attachbelow-6.2.diff b/patches/dwm-attachbelow-6.2.diff deleted file mode 100644 index 1562b38..0000000 --- a/patches/dwm-attachbelow-6.2.diff +++ /dev/null @@ -1,96 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 1c0b587..cb8053a 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -35,6 +35,7 @@ static const Rule rules[] = { - 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 int resizehints = 1; /* 1 means respect size hints in tiled resizals */ -+static const int attachbelow = 1; /* 1 means attach after the currently active window */ - - static const Layout layouts[] = { - /* symbol arrange function */ -diff --git a/dwm.1 b/dwm.1 -index 13b3729..fb6e76c 100644 ---- a/dwm.1 -+++ b/dwm.1 -@@ -29,6 +29,9 @@ color. The tags of the focused window are indicated with a filled square in the - top left corner. The tags which are applied to one or more windows are - indicated with an empty square in the top left corner. - .P -+The attach below patch makes newly spawned windows attach after the currently -+selected window -+.P - dwm draws a small border around windows to indicate the focus state. - .SH OPTIONS - .TP -diff --git a/dwm.c b/dwm.c -index 4465af1..bd715a2 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -147,6 +147,7 @@ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interac - static void arrange(Monitor *m); - static void arrangemon(Monitor *m); - static void attach(Client *c); -+static void attachBelow(Client *c); - static void attachstack(Client *c); - static void buttonpress(XEvent *e); - static void checkotherwm(void); -@@ -405,6 +406,21 @@ attach(Client *c) - c->next = c->mon->clients; - c->mon->clients = c; - } -+void -+attachBelow(Client *c) -+{ -+ //If there is nothing on the monitor or the selected client is floating, attach as normal -+ if(c->mon->sel == NULL || c->mon->sel == c || c->mon->sel->isfloating) { -+ attach(c); -+ return; -+ } -+ -+ //Set the new client's next property to the same as the currently selected clients next -+ c->next = c->mon->sel->next; -+ //Set the currently selected clients next property to the new client -+ c->mon->sel->next = c; -+ -+} - - void - attachstack(Client *c) -@@ -1062,7 +1078,10 @@ manage(Window w, XWindowAttributes *wa) - c->isfloating = c->oldstate = trans != None || c->isfixed; - if (c->isfloating) - XRaiseWindow(dpy, c->win); -- attach(c); -+ if( attachbelow ) -+ attachBelow(c); -+ else -+ attach(c); - attachstack(c); - XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, - (unsigned char *) &(c->win), 1); -@@ -1417,7 +1436,10 @@ sendmon(Client *c, Monitor *m) - detachstack(c); - c->mon = m; - c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ -- attach(c); -+ if( attachbelow ) -+ attachBelow(c); -+ else -+ attach(c); - attachstack(c); - focus(NULL); - arrange(NULL); -@@ -1897,7 +1919,10 @@ updategeom(void) - m->clients = c->next; - detachstack(c); - c->mon = mons; -- attach(c); -+ if( attachbelow ) -+ attachBelow(c); -+ else -+ attach(c); - attachstack(c); - } - if (m == selmon) diff --git a/patches/dwm-movestack-6.1.diff b/patches/dwm-movestack-6.1.diff deleted file mode 100644 index a6c83fa..0000000 --- a/patches/dwm-movestack-6.1.diff +++ /dev/null @@ -1,73 +0,0 @@ -diff -r 050d521d66d8 config.def.h ---- a/config.def.h Tue Aug 24 13:13:20 2010 +0100 -+++ b/config.def.h Sun Sep 05 18:43:07 2010 +0200 -@@ -57,6 +57,7 @@ - static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL }; - static const char *termcmd[] = { "st", NULL }; - -+#include "movestack.c" - static Key keys[] = { - /* modifier key function argument */ - { MODKEY, XK_p, spawn, {.v = dmenucmd } }, -@@ -68,6 +69,8 @@ - { MODKEY, XK_d, incnmaster, {.i = -1 } }, - { MODKEY, XK_h, setmfact, {.f = -0.05} }, - { MODKEY, XK_l, setmfact, {.f = +0.05} }, -+ { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } }, -+ { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, - { MODKEY, XK_Return, zoom, {0} }, - { MODKEY, XK_Tab, view, {0} }, - { MODKEY|ShiftMask, XK_c, killclient, {0} }, -diff -r 050d521d66d8 movestack.c ---- /dev/null Thu Jan 01 00:00:00 1970 +0000 -+++ b/movestack.c Sun Sep 05 18:43:07 2010 +0200 -@@ -0,0 +1,49 @@ -+void -+movestack(const Arg *arg) { -+ Client *c = NULL, *p = NULL, *pc = NULL, *i; -+ -+ if(arg->i > 0) { -+ /* find the client after selmon->sel */ -+ for(c = selmon->sel->next; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); -+ if(!c) -+ for(c = selmon->clients; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); -+ -+ } -+ else { -+ /* find the client before selmon->sel */ -+ for(i = selmon->clients; i != selmon->sel; i = i->next) -+ if(ISVISIBLE(i) && !i->isfloating) -+ c = i; -+ if(!c) -+ for(; i; i = i->next) -+ if(ISVISIBLE(i) && !i->isfloating) -+ c = i; -+ } -+ /* find the client before selmon->sel and c */ -+ for(i = selmon->clients; i && (!p || !pc); i = i->next) { -+ if(i->next == selmon->sel) -+ p = i; -+ if(i->next == c) -+ pc = i; -+ } -+ -+ /* swap c and selmon->sel selmon->clients in the selmon->clients list */ -+ if(c && c != selmon->sel) { -+ Client *temp = selmon->sel->next==c?selmon->sel:selmon->sel->next; -+ selmon->sel->next = c->next==selmon->sel?c:c->next; -+ c->next = temp; -+ -+ if(p && p != c) -+ p->next = c; -+ if(pc && pc != selmon->sel) -+ pc->next = selmon->sel; -+ -+ if(selmon->sel == selmon->clients) -+ selmon->clients = c; -+ else if(c == selmon->clients) -+ selmon->clients = selmon->sel; -+ -+ arrange(selmon); -+ } -+} -+ diff --git a/patches/dwm-pertag-6.2.diff b/patches/dwm-pertag-20200914-61bb8b2.diff index d753727..c8d7fbc 100644 --- a/patches/dwm-pertag-6.2.diff +++ b/patches/dwm-pertag-20200914-61bb8b2.diff @@ -1,5 +1,5 @@ diff --git a/dwm.c b/dwm.c -index 4465af1..6474055 100644 +index 664c527..ac8e4ec 100644 --- a/dwm.c +++ b/dwm.c @@ -111,6 +111,7 @@ typedef struct { @@ -18,7 +18,7 @@ index 4465af1..6474055 100644 }; typedef struct { -@@ -271,6 +273,15 @@ static Window root, wmcheckwin; +@@ -272,6 +274,15 @@ static Window root, wmcheckwin; /* configuration, allows nested code to access above variables */ #include "config.h" @@ -34,7 +34,7 @@ index 4465af1..6474055 100644 /* compile-time check if all tags fit into an unsigned int bit array. */ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; -@@ -631,6 +642,7 @@ Monitor * +@@ -632,6 +643,7 @@ Monitor * createmon(void) { Monitor *m; @@ -42,7 +42,7 @@ index 4465af1..6474055 100644 m = ecalloc(1, sizeof(Monitor)); m->tagset[0] = m->tagset[1] = 1; -@@ -641,6 +653,20 @@ createmon(void) +@@ -642,6 +654,20 @@ createmon(void) m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); @@ -63,7 +63,7 @@ index 4465af1..6474055 100644 return m; } -@@ -966,7 +992,7 @@ grabkeys(void) +@@ -967,7 +993,7 @@ grabkeys(void) void incnmaster(const Arg *arg) { @@ -72,7 +72,7 @@ index 4465af1..6474055 100644 arrange(selmon); } -@@ -1501,9 +1527,9 @@ void +@@ -1502,9 +1528,9 @@ void setlayout(const Arg *arg) { if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) @@ -84,16 +84,16 @@ index 4465af1..6474055 100644 strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); if (selmon->sel) arrange(selmon); -@@ -1522,7 +1548,7 @@ setmfact(const Arg *arg) +@@ -1523,7 +1549,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) + if (f < 0.05 || f > 0.95) return; - selmon->mfact = f; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; arrange(selmon); } -@@ -1699,7 +1725,7 @@ tile(Monitor *m) +@@ -1702,7 +1728,7 @@ tile(Monitor *m) void togglebar(const Arg *arg) { @@ -102,7 +102,7 @@ index 4465af1..6474055 100644 updatebarpos(selmon); XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); arrange(selmon); -@@ -1738,9 +1764,33 @@ void +@@ -1741,9 +1767,33 @@ void toggleview(const Arg *arg) { unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); @@ -136,7 +136,7 @@ index 4465af1..6474055 100644 focus(NULL); arrange(selmon); } -@@ -2035,11 +2085,37 @@ updatewmhints(Client *c) +@@ -2038,11 +2088,37 @@ updatewmhints(Client *c) void view(const Arg *arg) { diff --git a/patches/dwm-splitstatus-20201114-61bb8b2.diff b/patches/dwm-splitstatus-20201114-61bb8b2.diff deleted file mode 100644 index 0f1130c..0000000 --- a/patches/dwm-splitstatus-20201114-61bb8b2.diff +++ /dev/null @@ -1,77 +0,0 @@ -From d2efb5e19eb466f77f0860f0175b84247799bb93 Mon Sep 17 00:00:00 2001 -From: Alex Cole <ajzcole@airmail.cc> -Date: Sat, 14 Nov 2020 21:03:09 +1300 -Subject: [PATCH] splitstatus patch - ---- - config.def.h | 2 ++ - dwm.c | 31 +++++++++++++++---------------- - 2 files changed, 17 insertions(+), 16 deletions(-) - -diff --git a/config.def.h b/config.def.h -index 1c0b587..4161652 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -5,6 +5,8 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ - static const unsigned int snap = 32; /* snap pixel */ - static const int showbar = 1; /* 0 means no bar */ - static const int topbar = 1; /* 0 means bottom bar */ -+static const int splitstatus = 1; /* 1 for split status items */ -+static const char *splitdelim = ";"; /* Character used for separating status */ - static const char *fonts[] = { "monospace:size=10" }; - static const char dmenufont[] = "monospace:size=10"; - static const char col_gray1[] = "#222222"; -diff --git a/dwm.c b/dwm.c -index 664c527..e1a8085 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -701,13 +701,9 @@ drawbar(Monitor *m) - int boxw = drw->fonts->h / 6 + 2; - unsigned int i, occ = 0, urg = 0; - Client *c; -- -- /* draw status first so it can be overdrawn by tags later */ -- if (m == selmon) { /* status is only drawn on selected monitor */ -- drw_setscheme(drw, scheme[SchemeNorm]); -- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ -- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); -- } -+ char *mstext; -+ char *rstext; -+ int msx; - - for (c = m->clients; c; c = c->next) { - occ |= c->tags; -@@ -729,17 +725,20 @@ drawbar(Monitor *m) - drw_setscheme(drw, scheme[SchemeNorm]); - x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); - -- if ((w = m->ww - tw - x) > bh) { -- if (m->sel) { -- drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); -- drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); -- if (m->sel->isfloating) -- drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); -- } else { -- drw_setscheme(drw, scheme[SchemeNorm]); -- drw_rect(drw, x, 0, w, bh, 1, 1); -+ drw_setscheme(drw, scheme[SchemeNorm]); -+ drw_rect(drw, x, 0, m->ww - x, bh, 1, 1); -+ -+ if (m == selmon) { /* status is only drawn on selected monitor */ -+ rstext = strdup(stext); -+ if (splitstatus) { -+ mstext = strsep(&rstext, splitdelim); -+ msx = (m->ww - TEXTW(mstext) + lrpad) / 2; /* x position of middle status text */ -+ drw_text(drw, msx, 0, TEXTW(mstext) - lrpad, bh, 0, mstext, 0); - } -+ tw = TEXTW(rstext) - lrpad + 2; /* 2px right padding */ -+ drw_text(drw, m->ww - tw, 0, tw, bh, 0, rstext, 0); - } -+ - drw_map(drw, m->barwin, 0, 0, m->ww, bh); - } - --- -2.29.2 - diff --git a/patches/dwm-systray-6.4.diff b/patches/dwm-systray-6.4.diff new file mode 100644 index 0000000..58e4a69 --- /dev/null +++ b/patches/dwm-systray-6.4.diff @@ -0,0 +1,746 @@ +diff --git a/config.def.h b/config.def.h +index 9efa774..750529d 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -3,6 +3,11 @@ + /* appearance */ + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ ++static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ ++static const unsigned int systrayonleft = 0; /* 0: systray in the right corner, >0: systray on left of status text */ ++static const unsigned int systrayspacing = 2; /* systray spacing */ ++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ ++static const int showsystray = 1; /* 0 means no systray */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ + static const char *fonts[] = { "monospace:size=10" }; +@@ -101,8 +106,8 @@ static const Key keys[] = { + /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ + static const Button buttons[] = { + /* click event mask button function argument */ +- { ClkLtSymbol, 0, Button1, setlayout, {0} }, +- { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, ++ { ClkTagBar, MODKEY, Button1, tag, {0} }, ++ { ClkTagBar, MODKEY, Button3, toggletag, {0} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, +diff --git a/dwm.c b/dwm.c +index 03baf42..4611a03 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -57,12 +57,27 @@ + #define TAGMASK ((1 << LENGTH(tags)) - 1) + #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + ++#define SYSTEM_TRAY_REQUEST_DOCK 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 { SchemeNorm, SchemeSel }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, NetWMCheck, ++ NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ ++enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ + enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +@@ -141,6 +156,12 @@ typedef struct { + int monitor; + } Rule; + ++typedef struct Systray Systray; ++struct Systray { ++ Window win; ++ Client *icons; ++}; ++ + /* function declarations */ + static void applyrules(Client *c); + static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +@@ -172,6 +193,7 @@ static void focusstack(const Arg *arg); + static Atom getatomprop(Client *c, Atom prop); + static int getrootptr(int *x, int *y); + static long getstate(Window w); ++static unsigned int getsystraywidth(); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); + static void grabkeys(void); +@@ -189,13 +211,16 @@ static void pop(Client *c); + 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, int 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 int sendevent(Client *c, Atom proto); ++static int 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); +@@ -207,6 +232,7 @@ static void seturgent(Client *c, int urg); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static Monitor *systraytomon(Monitor *m); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *m); +@@ -224,18 +250,23 @@ static int updategeom(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 updatetitle(Client *c); + static void updatewindowtype(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 const char broken[] = "broken"; + static char stext[256]; + static int screen; +@@ -258,9 +289,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 int running = 1; + static Cur *cursor[CurLast]; + static Clr **scheme; +@@ -442,7 +474,7 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + TEXTW(selmon->ltsymbol)) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - (int)TEXTW(stext)) ++ else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth()) + click = ClkStatusText; + else + click = ClkWinTitle; +@@ -485,6 +517,13 @@ cleanup(void) + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); ++ ++ if (showsystray) { ++ XUnmapWindow(dpy, systray->win); ++ XDestroyWindow(dpy, systray->win); ++ free(systray); ++ } ++ + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < LENGTH(colors); i++) +@@ -516,9 +555,58 @@ cleanupmon(Monitor *mon) + 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)); ++ if (!(c->win = cme->data.l[2])) { ++ free(c); ++ return; ++ } ++ c->mon = selmon; ++ c->next = systray->icons; ++ systray->icons = c; ++ if (!XGetWindowAttributes(dpy, c->win, &wa)) { ++ /* use sane defaults */ ++ wa.width = bh; ++ wa.height = bh; ++ wa.border_width = 0; ++ } ++ 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 color */ ++ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++ XChangeWindowAttributes(dpy, c->win, 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); ++ XSync(dpy, False); ++ resizebarwin(selmon); ++ updatesystray(); ++ setclientstate(c, NormalState); ++ } ++ return; ++ } ++ + if (!c) + return; + if (cme->message_type == netatom[NetWMState]) { +@@ -571,7 +659,7 @@ configurenotify(XEvent *e) + for (c = m->clients; c; c = c->next) + if (c->isfullscreen) + resizeclient(c, m->mx, m->my, m->mw, m->mh); +- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ resizebarwin(m); + } + focus(NULL); + arrange(NULL); +@@ -656,6 +744,11 @@ destroynotify(XEvent *e) + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); ++ else if ((c = wintosystrayicon(ev->window))) { ++ removesystrayicon(c); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + } + + void +@@ -699,7 +792,7 @@ dirtomon(int dir) + void + drawbar(Monitor *m) + { +- int x, w, tw = 0; ++ int x, w, tw = 0, stw = 0; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0; +@@ -708,13 +801,17 @@ drawbar(Monitor *m) + if (!m->showbar) + return; + ++ if(showsystray && m == systraytomon(m) && !systrayonleft) ++ stw = getsystraywidth(); ++ + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ + drw_setscheme(drw, scheme[SchemeNorm]); +- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); ++ tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px extra right padding */ ++ drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0); + } + ++ resizebarwin(m); + for (c = m->clients; c; c = c->next) { + occ |= c->tags; + if (c->isurgent) +@@ -735,7 +832,7 @@ drawbar(Monitor *m) + drw_setscheme(drw, scheme[SchemeNorm]); + x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + +- if ((w = m->ww - tw - x) > bh) { ++ if ((w = m->ww - tw - stw - x) > bh) { + if (m->sel) { + drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); +@@ -746,7 +843,7 @@ drawbar(Monitor *m) + drw_rect(drw, x, 0, w, bh, 1, 1); + } + } +- drw_map(drw, m->barwin, 0, 0, m->ww, bh); ++ drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); + } + + void +@@ -783,8 +880,11 @@ expose(XEvent *e) + Monitor *m; + XExposeEvent *ev = &e->xexpose; + +- if (ev->count == 0 && (m = wintomon(ev->window))) ++ if (ev->count == 0 && (m = wintomon(ev->window))) { + drawbar(m); ++ if (m == selmon) ++ updatesystray(); ++ } + } + + void +@@ -870,14 +970,32 @@ getatomprop(Client *c, Atom prop) + unsigned char *p = NULL; + Atom da, atom = None; + +- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, ++ /* 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, 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 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; ++} ++ + int + getrootptr(int *x, int *y) + { +@@ -1018,7 +1136,8 @@ 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); +@@ -1105,6 +1224,13 @@ 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) || wa.override_redirect) + return; + if (!wintoclient(ev->window)) +@@ -1226,6 +1352,17 @@ 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) +@@ -1276,6 +1413,19 @@ recttomon(int x, int y, int w, int h) + return r; + } + ++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, int interact) + { +@@ -1283,6 +1433,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) + resizeclient(c, x, y, w, h); + } + ++void ++resizebarwin(Monitor *m) { ++ unsigned int w = m->ww; ++ if (showsystray && m == systraytomon(m) && !systrayonleft) ++ w -= getsystraywidth(); ++ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); ++} ++ + void + resizeclient(Client *c, int x, int y, int w, int h) + { +@@ -1298,6 +1456,19 @@ resizeclient(Client *c, int x, int y, int w, int h) + XSync(dpy, False); + } + ++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 + resizemouse(const Arg *arg) + { +@@ -1444,26 +1615,37 @@ setclientstate(Client *c, long state) + } + + int +-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; + int exists = 0; + 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; + } +@@ -1477,7 +1659,7 @@ setfocus(Client *c) + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); + } +- sendevent(c, wmatom[WMTakeFocus]); ++ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); + } + + void +@@ -1566,6 +1748,10 @@ 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[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False); + netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); + netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); + netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); +@@ -1573,6 +1759,9 @@ setup(void) + 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] = drw_cur_create(drw, XC_left_ptr); + cursor[CurResize] = drw_cur_create(drw, XC_sizing); +@@ -1581,6 +1770,8 @@ setup(void) + scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); + for (i = 0; i < LENGTH(colors); i++) + scheme[i] = drw_scm_create(drw, colors[i], 3); ++ /* init system tray */ ++ updatesystray(); + /* init bars */ + updatebars(); + updatestatus(); +@@ -1711,7 +1902,18 @@ togglebar(const Arg *arg) + { + selmon->showbar = !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); + } + +@@ -1807,11 +2009,18 @@ unmapnotify(XEvent *e) + else + unmanage(c, 0); + } ++ else if ((c = wintosystrayicon(ev->window))) { ++ /* KLUDGE! sometimes icons occasionally unmap their windows, but do ++ * _not_ destroy them. We map those windows back */ ++ XMapRaised(dpy, c->win); ++ updatesystray(); ++ } + } + + void + updatebars(void) + { ++ unsigned int w; + Monitor *m; + XSetWindowAttributes wa = { + .override_redirect = True, +@@ -1822,10 +2031,15 @@ updatebars(void) + for (m = mons; m; m = m->next) { + if (m->barwin) + continue; +- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), ++ w = m->ww; ++ if (showsystray && m == systraytomon(m)) ++ 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]->cursor); ++ if (showsystray && m == systraytomon(m)) ++ XMapRaised(dpy, systray->win); + XMapRaised(dpy, m->barwin); + XSetClassHint(dpy, m->barwin, &ch); + } +@@ -2002,6 +2216,125 @@ updatestatus(void) + if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + strcpy(stext, "dwm-"VERSION); + drawbar(selmon); ++ updatesystray(); ++} ++ ++ ++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 dimensions 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; ++ XWindowChanges wc; ++ Client *i; ++ Monitor *m = systraytomon(NULL); ++ unsigned int x = m->mx + m->mw; ++ unsigned int sw = TEXTW(stext) - lrpad + systrayspacing; ++ unsigned int w = 1; ++ ++ if (!showsystray) ++ return; ++ if (systrayonleft) ++ x -= sw + lrpad / 2; ++ 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, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); ++ wa.event_mask = ButtonPressMask | ExposureMask; ++ wa.override_redirect = True; ++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++ XSelectInput(dpy, systray->win, SubstructureNotifyMask); ++ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, ++ PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 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) { ++ /* make sure the background color stays the same */ ++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); ++ XMapRaised(dpy, i->win); ++ w += systrayspacing; ++ i->x = w; ++ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); ++ w += i->w; ++ if (i->mon != m) ++ i->mon = m; ++ } ++ w = w ? w + systrayspacing : 1; ++ x -= w; ++ XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); ++ wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; ++ wc.stack_mode = Above; wc.sibling = m->barwin; ++ XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); ++ XMapWindow(dpy, systray->win); ++ XMapSubwindows(dpy, systray->win); ++ /* redraw background */ ++ XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); ++ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); ++ XSync(dpy, False); + } + + void +@@ -2069,6 +2402,16 @@ wintoclient(Window w) + return NULL; + } + ++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; ++} ++ + Monitor * + wintomon(Window w) + { +@@ -2122,6 +2465,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee) + return -1; + } + ++Monitor * ++systraytomon(Monitor *m) { ++ Monitor *t; ++ int i, n; ++ if(!systraypinning) { ++ if(!m) ++ return selmon; ++ return m == selmon ? m : NULL; ++ } ++ for(n = 1, t = mons; t && t->next; n++, t = t->next) ; ++ for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; ++ if(systraypinningfailfirst && n < systraypinning) ++ return mons; ++ return t; ++} ++ + void + zoom(const Arg *arg) + { |
