Hi Jan Cristoph, Sorry for the extreme delay, it's been six months since the last email and I read this only yesterday reviewing my inbox but here it is. There are other things that I patched but nothing extraordinary its just a basic setup.
Again, I'm really sorry. >From b44eb5b5adb57eb1d33b8df09c73c28c436fc26e Mon Sep 17 00:00:00 2001 From: Joel Santos <[email protected]> Date: Thu, 27 Oct 2016 07:46:46 -0300 Subject: [PATCH 1/2] =?UTF-8?q?Aplica=C3=A7=C3=A3o=20do=20patch=20de=20sys?= =?UTF-8?q?tray.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + config.def.h | 4 + config.h | 119 ++++++++++++++++++ dwm.c | 395 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 496 insertions(+), 24 deletions(-) create mode 100644 .gitignore create mode 100644 config.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..095e840 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +dwm diff --git a/config.def.h b/config.def.h index fd77a07..d21488f 100644 --- a/config.def.h +++ b/config.def.h @@ -3,6 +3,10 @@ /* 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 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" }; diff --git a/config.h b/config.h new file mode 100644 index 0000000..5730245 --- /dev/null +++ b/config.h @@ -0,0 +1,119 @@ +/* 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 unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ +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[] = { "Noto Mono:size=8:antialias=true" }; +static const char dmenufont[] = "Noto Mono:size=8:antialias=true"; +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[SchemeLast][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, +}; + +/* tagging */ +static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, 1, -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 = 0; /* 1 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 Mod1Mask +#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 } } + +/* commands */ +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +static const char *termcmd[] = { "xfce4-terminal", NULL }; + +static 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, 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 } }, + { 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} }, +}; + +/* 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/dwm.c b/dwm.c index 421bf27..21dda9e 100644 --- a/dwm.c +++ b/dwm.c @@ -58,12 +58,30 @@ #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) #define ColBorder 2 +#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, SchemeLast }; /* color schemes */ enum { NetSupported, NetWMName, NetWMState, + 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 */ @@ -142,6 +160,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); @@ -171,8 +195,10 @@ static void focus(Client *c); static void focusin(XEvent *e); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); +static Atom getatomprop(Client *c, Atom prop); static 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 +216,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, 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 +236,7 @@ static void setup(void); 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 *); @@ -224,18 +254,23 @@ static void updateclientlist(void); static void updatenumlockmask(void); static void updatesizehints(Client *c); static void updatestatus(void); +static void updatesystray(void); +static void updatesystrayicongeom(Client *i, int w, int h); +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); static void updatewindowtype(Client *c); static void updatetitle(Client *c); static void updatewmhints(Client *c); static void view(const Arg *arg); static Client *wintoclient(Window w); static Monitor *wintomon(Window w); +static Client *wintosystrayicon(Window w); static int xerror(Display *dpy, XErrorEvent *ee); static int xerrordummy(Display *dpy, XErrorEvent *ee); static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); /* variables */ +static Systray *systray = NULL; static const char broken[] = "broken"; static char stext[256]; static int screen; @@ -258,9 +293,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 Scm scheme[SchemeLast]; @@ -481,6 +517,11 @@ 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 < SchemeLast; i++) @@ -523,9 +564,52 @@ 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)); + if (!(c->win = cme->data.l[2])) { + free(c); + return; + } + 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 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]) { @@ -580,7 +664,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); @@ -665,6 +749,11 @@ destroynotify(XEvent *e) if ((c = wintoclient(ev->window))) unmanage(c, 1); + else if ((c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + resizebarwin(selmon); + updatesystray(); + } } void @@ -708,19 +797,23 @@ dirtomon(int dir) void drawbar(Monitor *m) { - int x, w, sw = 0; + int x, w, sw = 0, stw = 0; int boxs = drw->fonts->h / 9; int boxw = drw->fonts->h / 6 + 2; unsigned int i, occ = 0, urg = 0; Client *c; + if(showsystray && m == systraytomon(m)) + 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]); sw = TEXTW(stext) - lrpad / 2; /* no right padding so status text hugs the corner */ - drw_text(drw, m->ww - sw, 0, sw, bh, lrpad / 2 - 2, stext, 0); + drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); } + resizebarwin(m); for (c = m->clients; c; c = c->next) { occ |= c->tags; if (c->isurgent) @@ -741,7 +834,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 - sw - x) > bh) { + if ((w = m->ww - sw - 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); @@ -752,7 +845,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 @@ -789,8 +882,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 @@ -877,10 +973,17 @@ getatomprop(Client *c, Atom prop) unsigned long dl; unsigned char *p = NULL; Atom da, atom = None; + /* FIXME getatomprop should return the number of items and a pointer to + * the stored data instead of this workaround */ + Atom req = XA_ATOM; + if (prop == xatom[XembedInfo]) + req = xatom[XembedInfo]; - if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, + if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, &da, &di, &dl, &dl, &p) == Success && p) { atom = *(Atom *)p; + if (da == xatom[XembedInfo] && dl == 2) + atom = ((Atom *)p)[1]; XFree(p); } return atom; @@ -914,6 +1017,16 @@ 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; +} + int gettextprop(Window w, Atom atom, char *text, unsigned int size) { @@ -1020,7 +1133,7 @@ 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); @@ -1108,6 +1221,12 @@ 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; @@ -1235,6 +1354,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) @@ -1286,6 +1415,20 @@ 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)) @@ -1293,6 +1436,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)) + 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; @@ -1365,6 +1516,19 @@ 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; @@ -1453,26 +1617,36 @@ 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; } @@ -1486,7 +1660,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 @@ -1572,12 +1746,19 @@ 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[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); + xatom[Manager] = XInternAtom(dpy, "MANAGER", False); + xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); + xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); /* init cursors */ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); cursor[CurResize] = drw_cur_create(drw, XC_sizing); @@ -1585,6 +1766,8 @@ setup(void) /* init appearance */ scheme[SchemeNorm] = drw_scm_create(drw, colors[SchemeNorm], 3); scheme[SchemeSel] = drw_scm_create(drw, colors[SchemeSel], 3); + /* init system tray */ + updatesystray(); /* init bars */ updatebars(); updatestatus(); @@ -1693,7 +1876,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); } @@ -1789,11 +1983,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, @@ -1803,10 +2004,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); } } @@ -1994,6 +2200,121 @@ 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 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; + XWindowChanges wc; + Client *i; + Monitor *m = systraytomon(NULL); + unsigned int x = m->mx + m->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, 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 @@ -2052,6 +2373,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) { @@ -2105,6 +2436,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) { -- 2.7.4 >From f0b12bd52f497732ee52323c23d8077407b86ff7 Mon Sep 17 00:00:00 2001 From: Joel Santos <[email protected]> Date: Sun, 18 Dec 2016 10:48:37 -0300 Subject: [PATCH 2/2] =?UTF-8?q?Altera=C3=A7=C3=A3o=20da=20configura=C3=A7?= =?UTF-8?q?=C3=A3o.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.h | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/config.h b/config.h index 5730245..566da89 100644 --- a/config.h +++ b/config.h @@ -9,8 +9,8 @@ static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display 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[] = { "Noto Mono:size=8:antialias=true" }; -static const char dmenufont[] = "Noto Mono:size=8:antialias=true"; +static const char *fonts[] = { "Source Sans Pro:size=9:antialias=true" }; +static const char dmenufont[] = "Source Sans Pro:size=9:antialias=true"; static const char col_gray1[] = "#222222"; static const char col_gray2[] = "#444444"; static const char col_gray3[] = "#bbbbbb"; @@ -42,9 +42,9 @@ static const int resizehints = 0; /* 1 means respect size hints in tiled resi static const Layout layouts[] = { /* symbol arrange function */ - { "[]=", tile }, /* first entry is default */ - { "><>", NULL }, /* no layout function means floating behavior */ - { "[M]", monocle }, + { "#", tile }, /* first entry is default */ + { "@", NULL }, /* no layout function means floating behavior */ + { "M", monocle }, }; /* key definitions */ @@ -62,11 +62,21 @@ static const Layout layouts[] = { static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; static const char *termcmd[] = { "xfce4-terminal", NULL }; +static const char *mutecmd[] = {"amixer","-D","pulse","sset","Master","toggle",NULL}; +static const char *lowervolcmd[] = {"amixer","-D","pulse","sset","Master","3%-",NULL}; +static const char *raisevolcmd[] = {"amixer","-D","pulse","sset","Master","3%+",NULL}; +static const char *lowerlightcmd[] = {"xbacklight","-dec","10",NULL}; +static const char *raiselightcmd[] = {"xbacklight","-inc","10",NULL}; +static const char *lockcmd[] = {"slock",NULL}; +static const char *mediaplay[] = {"playerctl","play-pause",NULL}; +static const char *medianext[] = {"playerctl","next",NULL}; +static const char *mediaprev[] = {"playerctl","previous",NULL}; static Key keys[] = { /* modifier key function argument */ { MODKEY, XK_p, spawn, {.v = dmenucmd } }, { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY|ShiftMask, XK_l, spawn, {.v = lockcmd } }, { MODKEY, XK_b, togglebar, {0} }, { MODKEY, XK_j, focusstack, {.i = +1 } }, { MODKEY, XK_k, focusstack, {.i = -1 } }, @@ -88,6 +98,14 @@ static Key keys[] = { { MODKEY, XK_period, focusmon, {.i = +1 } }, { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + { 0, 0x1008ff14,spawn, {.v = mediaplay } }, + { 0, 0x1008ff17,spawn, {.v = medianext } }, + { 0, 0x1008ff16,spawn, {.v = mediaprev } }, + { 0, 0x1008ff12,spawn, {.v = mutecmd } }, + { 0, 0x1008ff11,spawn, {.v = lowervolcmd } }, + { 0, 0x1008ff13,spawn, {.v = raisevolcmd } }, + { 0, 0x1008ff03,spawn, {.v = lowerlightcmd } }, + { 0, 0x1008ff02,spawn, {.v = raiselightcmd } }, TAGKEYS( XK_1, 0) TAGKEYS( XK_2, 1) TAGKEYS( XK_3, 2) -- 2.7.4 Muito obrigado. Joel 2016-12-26 6:18 GMT-03:00 Jan Christoph Ebersbach <[email protected]>: > @Eon, I'd be happy to integrate parts of the patch into the systray > patch. Would you mind posting your version as a proper patch file in > the wiki or in this list? > > On Fri 23-12-2016 17:21 +0900, Eon S. Jeon wrote: > >> This patch is a merge b/w systray and alpha. >> >> Additional changes are: >> - create systray-> win with apropriate visual and attributes >> - utilize _NET_SYSTEM_TRAY_VISUAL to let tray icon alpha-aware >> --- >> config.def.h | 14 +- >> config.mk | 2 +- >> drw.c | 59 +++++++-- >> drw.h | 3 + >> dwm.c | 409 >> +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- >> 5 files changed, 446 insertions(+), 41 deletions(-) >> >> diff --git a/config.def.h b/config.def.h >> index ba9a240..498b5bb 100644 >> --- a/config.def.h >> +++ b/config.def.h >> @@ -3,15 +3,19 @@ >> /* 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 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" }; >> 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 col_gray1[] = "#222222A#dd"; >> +static const char col_gray2[] = "#444444A#ff"; >> +static const char col_gray3[] = "#bbbbbbA#ff"; >> +static const char col_gray4[] = "#eeeeeeA#ff"; >> +static const char col_cyan[] = "#005577A#dd"; >> static const char *colors[][3] = { >> /* fg bg border */ >> [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, >> diff --git a/config.mk b/config.mk >> index 80dc936..2c62e89 100644 >> --- a/config.mk >> +++ b/config.mk >> @@ -22,7 +22,7 @@ FREETYPEINC = /usr/include/freetype2 >> >> # includes and libs >> INCS = -I${X11INC} -I${FREETYPEINC} >> -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} >> +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender >> >> # flags >> CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 >> -DVERSION="${VERSION}\" ${XINERAMAFLAGS} >> diff --git a/drw.c b/drw.c >> index 319eb6b..833e8d1 100644 >> --- a/drw.c >> +++ b/drw.c >> @@ -60,6 +60,39 @@ utf8decode(const char *c, long *u, size_t clen) >> return len; >> } >> >> +static void >> +drw_initvisual(Drw *drw, Display *dpy, int screen, Window root) >> +{ >> + XVisualInfo *infos; >> + XRenderPictFormat *fmt; >> + int nitems; >> + int i; >> + >> + XVisualInfo tpl = { >> + .screen = screen, >> + .depth = 32, >> + .class = TrueColor >> + }; >> + long masks = VisualScreenMask | VisualDepthMask | VisualClassMask; >> + >> + infos = XGetVisualInfo(dpy, masks, &tpl, &nitems); >> + for(i = 0; i < nitems; i ++) { >> + fmt = XRenderFindVisualFormat(dpy, infos[i].visual); >> + if (fmt-> type == PictTypeDirect && fmt->direct.alphaMask) >> + goto found; >> + } >> + >> + drw-> visual = DefaultVisual(dpy, screen); >> + drw-> depth = DefaultDepth(dpy, screen); >> + drw-> cmap = DefaultColormap(dpy, screen); >> + return; >> + >> +found: >> + drw-> visual = infos[i].visual; >> + drw-> depth = infos[i].depth; >> + drw-> cmap = XCreateColormap(dpy, root, drw->visual, AllocNone); >> +} >> + >> Drw * >> drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned >> int h) >> { >> @@ -70,8 +103,9 @@ drw_create(Display *dpy, int screen, Window root, >> unsigned int w, unsigned int h >> drw-> root = root; >> drw-> w = w; >> drw-> h = h; >> - drw-> drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, >> screen)); >> - drw-> gc = XCreateGC(dpy, root, 0, NULL); >> + drw_initvisual(drw, dpy, screen, root); >> + drw-> drawable = XCreatePixmap(dpy, root, w, h, drw->depth); >> + drw-> gc = XCreateGC(dpy, drw->drawable, 0, NULL); >> XSetLineAttributes(dpy, drw-> gc, 1, LineSolid, CapButt, JoinMiter); >> >> return drw; >> @@ -87,7 +121,7 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h) >> drw-> h = h; >> if (drw-> drawable) >> XFreePixmap(drw-> dpy, drw->drawable); >> - drw-> drawable = XCreatePixmap(drw->dpy, drw->root, w, h, >> DefaultDepth(drw->dpy, drw->screen)); >> + drw-> drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth); >> } >> >> void >> @@ -182,13 +216,24 @@ drw_fontset_free(Fnt *font) >> void >> drw_clr_create(Drw *drw, XftColor *dest, const char *clrname) >> { >> + unsigned long alpha; >> + size_t i; >> + >> if (!drw || !dest || !clrname) >> return; >> >> - if (!XftColorAllocName(drw-> dpy, DefaultVisual(drw->dpy, drw->screen), >> - DefaultColormap(drw-> dpy, drw->screen), >> + if (!XftColorAllocName(drw-> dpy, drw->visual, drw->cmap, >> clrname, dest)) >> die("error, cannot allocate color '%s'", clrname); >> + >> + i = strlen(clrname) + 1; >> + if (clrname[i] == 'A' && clrname[i+1] == '#') { >> + alpha = strtoul(&clrname[i+2], NULL, 16); >> + printf("alpha : %lun", alpha); >> + dest-> pixel &= 0x00ffffffUL; >> + dest-> pixel |= alpha << 24; >> + dest-> color.alpha = alpha << 8; >> + } >> } >> >> /* Wrapper to create color schemes. The caller has to call free(3) on the >> @@ -260,9 +305,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, >> unsigned int h, unsigned int lp >> } else { >> XSetForeground(drw-> dpy, drw->gc, drw->scheme[invert ? ColFg >> : ColBg].pixel); >> XFillRectangle(drw-> dpy, drw->drawable, drw->gc, x, y, w, h); >> - d = XftDrawCreate(drw-> dpy, drw->drawable, >> - DefaultVisual(drw-> dpy, drw->screen), >> - DefaultColormap(drw-> dpy, drw->screen)); >> + d = XftDrawCreate(drw-> dpy, drw->drawable, drw->visual, >> drw->cmap); >> x += lpad; >> w -= lpad; >> } >> diff --git a/drw.h b/drw.h >> index ff4355b..b3b13aa 100644 >> --- a/drw.h >> +++ b/drw.h >> @@ -20,6 +20,9 @@ typedef struct { >> Display *dpy; >> int screen; >> Window root; >> + Visual *visual; >> + unsigned int depth; >> + Colormap cmap; >> Drawable drawable; >> GC gc; >> Scm scheme; >> diff --git a/dwm.c b/dwm.c >> index d27cb67..2fb2f5b 100644 >> --- a/dwm.c >> +++ b/dwm.c >> @@ -58,12 +58,30 @@ >> #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) >> #define ColBorder 2 >> >> +#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, NetSystemTrayVisual, >> 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 */ >> @@ -142,6 +160,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); >> @@ -170,8 +194,10 @@ static void focus(Client *c); >> static void focusin(XEvent *e); >> static void focusmon(const Arg *arg); >> static void focusstack(const Arg *arg); >> +static Atom getatomprop(Client *c, Atom prop); >> static 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 +215,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, 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 +236,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 *); >> @@ -224,18 +254,23 @@ static void updateclientlist(void); >> static void updatenumlockmask(void); >> static void updatesizehints(Client *c); >> static void updatestatus(void); >> +static void updatesystray(void); >> +static void updatesystrayicongeom(Client *i, int w, int h); >> +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); >> static void updatewindowtype(Client *c); >> static void updatetitle(Client *c); >> static void updatewmhints(Client *c); >> static void view(const Arg *arg); >> static Client *wintoclient(Window w); >> static Monitor *wintomon(Window w); >> +static Client *wintosystrayicon(Window w); >> static int xerror(Display *dpy, XErrorEvent *ee); >> static int xerrordummy(Display *dpy, XErrorEvent *ee); >> static int xerrorstart(Display *dpy, XErrorEvent *ee); >> static void zoom(const Arg *arg); >> >> /* variables */ >> +static Systray *systray = NULL; >> static const char broken[] = "broken"; >> static char stext[256]; >> static int screen; >> @@ -258,9 +293,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 Scm *scheme; >> @@ -481,6 +517,11 @@ 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++) >> @@ -511,9 +552,52 @@ 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 bytesn", >> sizeof(Client)); >> + if (!(c-> win = cme->data.l[2])) { >> + free(c); >> + return; >> + } >> + 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 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]) { >> @@ -565,7 +649,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); >> @@ -650,6 +734,11 @@ destroynotify(XEvent *e) >> >> if ((c = wintoclient(ev-> window))) >> unmanage(c, 1); >> + else if ((c = wintosystrayicon(ev-> window))) { >> + removesystrayicon(c); >> + resizebarwin(selmon); >> + updatesystray(); >> + } >> } >> >> void >> @@ -693,19 +782,23 @@ dirtomon(int dir) >> void >> drawbar(Monitor *m) >> { >> - int x, w, sw = 0; >> + int x, w, sw = 0, stw = 0; >> int boxs = drw-> fonts->h / 9; >> int boxw = drw-> fonts->h / 6 + 2; >> unsigned int i, occ = 0, urg = 0; >> Client *c; >> >> + if(showsystray && m == systraytomon(m)) >> + 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]); >> sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ >> - drw_text(drw, m-> ww - sw, 0, sw, bh, 0, stext, 0); >> + drw_text(drw, m-> ww - sw - stw, 0, sw, bh, 0, stext, 0); >> } >> >> + resizebarwin(m); >> for (c = m-> clients; c; c = c->next) { >> occ |= c-> tags; >> if (c-> isurgent) >> @@ -726,7 +819,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 - sw - x) > bh) { >> + if ((w = m-> ww - sw - 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); >> @@ -737,7 +830,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 >> @@ -774,8 +867,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 >> @@ -862,10 +958,17 @@ getatomprop(Client *c, Atom prop) >> unsigned long dl; >> unsigned char *p = NULL; >> Atom da, atom = None; >> + /* FIXME getatomprop should return the number of items and a pointer to >> + * the stored data instead of this workaround */ >> + Atom req = XA_ATOM; >> + if (prop == xatom[XembedInfo]) >> + req = xatom[XembedInfo]; >> >> - if (XGetWindowProperty(dpy, c-> win, prop, 0L, sizeof atom, False, >> XA_ATOM, >> + if (XGetWindowProperty(dpy, c-> win, prop, 0L, sizeof atom, False, req, >> &da, &di, &dl, &dl, &p) == Success && p) { >> atom = *(Atom *)p; >> + if (da == xatom[XembedInfo] && dl == 2) >> + atom = ((Atom *)p)[1]; >> XFree(p); >> } >> return atom; >> @@ -899,6 +1002,16 @@ 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; >> +} >> + >> int >> gettextprop(Window w, Atom atom, char *text, unsigned int size) >> { >> @@ -1005,7 +1118,7 @@ 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); >> @@ -1093,6 +1206,12 @@ 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; >> @@ -1220,6 +1339,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) >> @@ -1271,6 +1400,20 @@ 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)) >> @@ -1278,6 +1421,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)) >> + 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; >> @@ -1350,6 +1501,19 @@ 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; >> @@ -1438,26 +1602,36 @@ 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; >> } >> @@ -1471,7 +1645,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 >> @@ -1560,6 +1734,11 @@ 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[NetSystemTrayVisual] = XInternAtom(dpy, >> "_NET_SYSTEM_TRAY_VISUAL", 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); >> @@ -1567,6 +1746,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); >> @@ -1575,6 +1757,8 @@ setup(void) >> scheme = ecalloc(LENGTH(colors), sizeof(Scm)); >> for (i = 0; i < LENGTH(colors); i++) >> scheme[i] = drw_scm_create(drw, colors[i], 3); >> + /* init system tray */ >> + updatesystray(); >> /* init bars */ >> updatebars(); >> updatestatus(); >> @@ -1705,7 +1889,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); >> } >> >> @@ -1801,24 +1996,38 @@ 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, >> - .background_pixmap = ParentRelative, >> + .background_pixel = 0, >> + .border_pixel = 0, >> + .colormap = drw-> cmap, >> .event_mask = ButtonPressMask|ExposureMask >> }; >> for (m = mons; m; m = m-> next) { >> if (m-> barwin) >> continue; >> - m-> barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, >> 0, DefaultDepth(dpy, screen), >> - CopyFromParent, DefaultVisual(dpy, >> screen), >> - >> CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); >> + w = m-> ww; >> + if (showsystray && m == systraytomon(m)) >> + w -= getsystraywidth(); >> + m-> barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, >> drw->depth, >> + CopyFromParent, drw-> visual, >> + >> CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa); >> XDefineCursor(dpy, m-> barwin, cursor[CurNormal]->cursor); >> + if (showsystray && m == systraytomon(m)) >> + XMapRaised(dpy, systray-> win); >> XMapRaised(dpy, m-> barwin); >> } >> } >> @@ -2006,6 +2215,126 @@ 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 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; >> + XWindowChanges wc; >> + Client *i; >> + Monitor *m = systraytomon(NULL); >> + unsigned int x = m-> mx + m->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 bytesn", >> sizeof(Systray)); >> + wa.event_mask = ButtonPressMask | ExposureMask; >> + wa.override_redirect = True; >> + wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; >> + wa.border_pixel = 0; >> + wa.colormap = drw-> cmap; >> + systray-> win = XCreateWindow(dpy, root, x, m->by, w, bh, 0, >> drw->depth, >> + InputOutput, drw-> visual, >> + >> CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa); >> + XSelectInput(dpy, systray-> win, SubstructureNotifyMask); >> + XChangeProperty(dpy, systray-> win, >> netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, >> + PropModeReplace, (unsigned char >> *)&netatom[NetSystemTrayOrientationHorz], 1); >> + XChangeProperty(dpy, systray-> win, >> netatom[NetSystemTrayVisual], XA_VISUALID, 32, >> + PropModeReplace, (unsigned char *)&drw-> >> visual->visualid, 1); >> + 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 >> @@ -2064,6 +2393,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) >> { >> @@ -2117,6 +2456,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) >> { > > -- > Jan Christoph Ebersbach > I didn’t want some petty, inferior brand of righteousness that comes > from keeping a list of rules when I could get the robust kind that comes > from trusting Christ - God’s righteousness. Phil 3:9 > > -- > window manager Improved 2 (wmii) - Google Groups > http://groups.google.com/group/wmii > --- > You received this message because you are subscribed to a topic in the Google > Groups "window manager Improved 2 (wmii)" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/wmii/-Lf0fBphJk8/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > [email protected]. > For more options, visit https://groups.google.com/d/optout.
From b44eb5b5adb57eb1d33b8df09c73c28c436fc26e Mon Sep 17 00:00:00 2001 From: Joel Santos <[email protected]> Date: Thu, 27 Oct 2016 07:46:46 -0300 Subject: [PATCH 1/2] =?UTF-8?q?Aplica=C3=A7=C3=A3o=20do=20patch=20de=20sys?= =?UTF-8?q?tray.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + config.def.h | 4 + config.h | 119 ++++++++++++++++++ dwm.c | 395 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 496 insertions(+), 24 deletions(-) create mode 100644 .gitignore create mode 100644 config.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..095e840 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +dwm diff --git a/config.def.h b/config.def.h index fd77a07..d21488f 100644 --- a/config.def.h +++ b/config.def.h @@ -3,6 +3,10 @@ /* 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 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" }; diff --git a/config.h b/config.h new file mode 100644 index 0000000..5730245 --- /dev/null +++ b/config.h @@ -0,0 +1,119 @@ +/* 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 unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ +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[] = { "Noto Mono:size=8:antialias=true" }; +static const char dmenufont[] = "Noto Mono:size=8:antialias=true"; +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[SchemeLast][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, +}; + +/* tagging */ +static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, 1, -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 = 0; /* 1 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 Mod1Mask +#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 } } + +/* commands */ +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +static const char *termcmd[] = { "xfce4-terminal", NULL }; + +static 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, 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 } }, + { 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} }, +}; + +/* 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/dwm.c b/dwm.c index 421bf27..21dda9e 100644 --- a/dwm.c +++ b/dwm.c @@ -58,12 +58,30 @@ #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) #define ColBorder 2 +#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, SchemeLast }; /* color schemes */ enum { NetSupported, NetWMName, NetWMState, + 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 */ @@ -142,6 +160,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); @@ -171,8 +195,10 @@ static void focus(Client *c); static void focusin(XEvent *e); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); +static Atom getatomprop(Client *c, Atom prop); static 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 +216,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, 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 +236,7 @@ static void setup(void); 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 *); @@ -224,18 +254,23 @@ static void updateclientlist(void); static void updatenumlockmask(void); static void updatesizehints(Client *c); static void updatestatus(void); +static void updatesystray(void); +static void updatesystrayicongeom(Client *i, int w, int h); +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); static void updatewindowtype(Client *c); static void updatetitle(Client *c); static void updatewmhints(Client *c); static void view(const Arg *arg); static Client *wintoclient(Window w); static Monitor *wintomon(Window w); +static Client *wintosystrayicon(Window w); static int xerror(Display *dpy, XErrorEvent *ee); static int xerrordummy(Display *dpy, XErrorEvent *ee); static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); /* variables */ +static Systray *systray = NULL; static const char broken[] = "broken"; static char stext[256]; static int screen; @@ -258,9 +293,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 Scm scheme[SchemeLast]; @@ -481,6 +517,11 @@ 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 < SchemeLast; i++) @@ -523,9 +564,52 @@ 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)); + if (!(c->win = cme->data.l[2])) { + free(c); + return; + } + 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 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]) { @@ -580,7 +664,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); @@ -665,6 +749,11 @@ destroynotify(XEvent *e) if ((c = wintoclient(ev->window))) unmanage(c, 1); + else if ((c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + resizebarwin(selmon); + updatesystray(); + } } void @@ -708,19 +797,23 @@ dirtomon(int dir) void drawbar(Monitor *m) { - int x, w, sw = 0; + int x, w, sw = 0, stw = 0; int boxs = drw->fonts->h / 9; int boxw = drw->fonts->h / 6 + 2; unsigned int i, occ = 0, urg = 0; Client *c; + if(showsystray && m == systraytomon(m)) + 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]); sw = TEXTW(stext) - lrpad / 2; /* no right padding so status text hugs the corner */ - drw_text(drw, m->ww - sw, 0, sw, bh, lrpad / 2 - 2, stext, 0); + drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); } + resizebarwin(m); for (c = m->clients; c; c = c->next) { occ |= c->tags; if (c->isurgent) @@ -741,7 +834,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 - sw - x) > bh) { + if ((w = m->ww - sw - 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); @@ -752,7 +845,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 @@ -789,8 +882,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 @@ -877,10 +973,17 @@ getatomprop(Client *c, Atom prop) unsigned long dl; unsigned char *p = NULL; Atom da, atom = None; + /* FIXME getatomprop should return the number of items and a pointer to + * the stored data instead of this workaround */ + Atom req = XA_ATOM; + if (prop == xatom[XembedInfo]) + req = xatom[XembedInfo]; - if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, + if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, &da, &di, &dl, &dl, &p) == Success && p) { atom = *(Atom *)p; + if (da == xatom[XembedInfo] && dl == 2) + atom = ((Atom *)p)[1]; XFree(p); } return atom; @@ -914,6 +1017,16 @@ 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; +} + int gettextprop(Window w, Atom atom, char *text, unsigned int size) { @@ -1020,7 +1133,7 @@ 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); @@ -1108,6 +1221,12 @@ 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; @@ -1235,6 +1354,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) @@ -1286,6 +1415,20 @@ 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)) @@ -1293,6 +1436,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)) + 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; @@ -1365,6 +1516,19 @@ 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; @@ -1453,26 +1617,36 @@ 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; } @@ -1486,7 +1660,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 @@ -1572,12 +1746,19 @@ 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[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); + xatom[Manager] = XInternAtom(dpy, "MANAGER", False); + xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); + xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); /* init cursors */ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); cursor[CurResize] = drw_cur_create(drw, XC_sizing); @@ -1585,6 +1766,8 @@ setup(void) /* init appearance */ scheme[SchemeNorm] = drw_scm_create(drw, colors[SchemeNorm], 3); scheme[SchemeSel] = drw_scm_create(drw, colors[SchemeSel], 3); + /* init system tray */ + updatesystray(); /* init bars */ updatebars(); updatestatus(); @@ -1693,7 +1876,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); } @@ -1789,11 +1983,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, @@ -1803,10 +2004,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); } } @@ -1994,6 +2200,121 @@ 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 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; + XWindowChanges wc; + Client *i; + Monitor *m = systraytomon(NULL); + unsigned int x = m->mx + m->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, 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 @@ -2052,6 +2373,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) { @@ -2105,6 +2436,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) { -- 2.7.4 From f0b12bd52f497732ee52323c23d8077407b86ff7 Mon Sep 17 00:00:00 2001 From: Joel Santos <[email protected]> Date: Sun, 18 Dec 2016 10:48:37 -0300 Subject: [PATCH 2/2] =?UTF-8?q?Altera=C3=A7=C3=A3o=20da=20configura=C3=A7?= =?UTF-8?q?=C3=A3o.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.h | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/config.h b/config.h index 5730245..566da89 100644 --- a/config.h +++ b/config.h @@ -9,8 +9,8 @@ static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display 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[] = { "Noto Mono:size=8:antialias=true" }; -static const char dmenufont[] = "Noto Mono:size=8:antialias=true"; +static const char *fonts[] = { "Source Sans Pro:size=9:antialias=true" }; +static const char dmenufont[] = "Source Sans Pro:size=9:antialias=true"; static const char col_gray1[] = "#222222"; static const char col_gray2[] = "#444444"; static const char col_gray3[] = "#bbbbbb"; @@ -42,9 +42,9 @@ static const int resizehints = 0; /* 1 means respect size hints in tiled resi static const Layout layouts[] = { /* symbol arrange function */ - { "[]=", tile }, /* first entry is default */ - { "><>", NULL }, /* no layout function means floating behavior */ - { "[M]", monocle }, + { "#", tile }, /* first entry is default */ + { "@", NULL }, /* no layout function means floating behavior */ + { "M", monocle }, }; /* key definitions */ @@ -62,11 +62,21 @@ static const Layout layouts[] = { static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; static const char *termcmd[] = { "xfce4-terminal", NULL }; +static const char *mutecmd[] = {"amixer","-D","pulse","sset","Master","toggle",NULL}; +static const char *lowervolcmd[] = {"amixer","-D","pulse","sset","Master","3%-",NULL}; +static const char *raisevolcmd[] = {"amixer","-D","pulse","sset","Master","3%+",NULL}; +static const char *lowerlightcmd[] = {"xbacklight","-dec","10",NULL}; +static const char *raiselightcmd[] = {"xbacklight","-inc","10",NULL}; +static const char *lockcmd[] = {"slock",NULL}; +static const char *mediaplay[] = {"playerctl","play-pause",NULL}; +static const char *medianext[] = {"playerctl","next",NULL}; +static const char *mediaprev[] = {"playerctl","previous",NULL}; static Key keys[] = { /* modifier key function argument */ { MODKEY, XK_p, spawn, {.v = dmenucmd } }, { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY|ShiftMask, XK_l, spawn, {.v = lockcmd } }, { MODKEY, XK_b, togglebar, {0} }, { MODKEY, XK_j, focusstack, {.i = +1 } }, { MODKEY, XK_k, focusstack, {.i = -1 } }, @@ -88,6 +98,14 @@ static Key keys[] = { { MODKEY, XK_period, focusmon, {.i = +1 } }, { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + { 0, 0x1008ff14,spawn, {.v = mediaplay } }, + { 0, 0x1008ff17,spawn, {.v = medianext } }, + { 0, 0x1008ff16,spawn, {.v = mediaprev } }, + { 0, 0x1008ff12,spawn, {.v = mutecmd } }, + { 0, 0x1008ff11,spawn, {.v = lowervolcmd } }, + { 0, 0x1008ff13,spawn, {.v = raisevolcmd } }, + { 0, 0x1008ff03,spawn, {.v = lowerlightcmd } }, + { 0, 0x1008ff02,spawn, {.v = raiselightcmd } }, TAGKEYS( XK_1, 0) TAGKEYS( XK_2, 1) TAGKEYS( XK_3, 2) -- 2.7.4
