1
0
mirror of https://github.com/tiyn/dwm.git synced 2025-04-20 08:17:45 +02:00

Compare commits

..

No commits in common. "037b9cf74d8ea7af61dad0b56c04f11b5901c143" and "3547e19c2c0a381f8a0b807269ccff89a2c4f65a" have entirely different histories.

6 changed files with 33 additions and 1166 deletions

View File

@ -14,15 +14,14 @@ This repository is set up according to the
The list below shows the currently applied patches to the master branch. The list below shows the currently applied patches to the master branch.
- dwm-actualfullscreen-20191112-cb3f58a.diff (enables true fullscreen) - dwm-actualfullscreen-20191112-cb3f58a.diff (enables true fullscreen)
- dwm-alttagsdecoration-2020010304-cb3f58a.diff (enables different icons for tags with windows) - dwm-bottomstack-20160719-56a31dc.diff (adds bottomstack and
- dwm-bottomstack-20160719-56a31dc.diff (adds bottomstack and bottomstackhorizontal layout) bottomstackhorizontal layout)
- dwm-center-6.1.diff (adds ability to center floating windows at launch) - dwm-center-6.1.diff (adds ability to center floating windows at launch)
- dwm-deck-6.0.diff (adds deck layout) - dwm-deck-6.0.diff (adds deck layout)
- dwm-noborder-6.2.diff (removes border if there is only one window) - dwm-noborder-6.2.diff (removes border if there is only one window)
- dwm-pertag-20170513-ceac8c9.diff (allows having a layout/mwfact/barpos/nmaster per tag) - dwm-pertag-20170513-ceac8c9.diff (allows having a layout/mwfact/barpos/nmaster
- dwm-statusallmons-6.2.diff (display statusbar on every monitors) per tag)
- dwm-statuscmd-6.2.diff (enables dwmblocks compatibility) - dwm-statuscmd-6.2.diff (enables dwmblocks compatibility)
- dwm-systray-6.2.diff (adds systray to statusbar)
## Hotkeys ## Hotkeys

View File

@ -6,10 +6,6 @@
/* appearance */ /* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */ static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */ 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 showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */ static const int topbar = 1; /* 0 means bottom bar */
static const char *fonts[] = { "monospace:size=10" }; static const char *fonts[] = { "monospace:size=10" };

View File

@ -6,10 +6,6 @@
/* appearance */ /* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */ static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */ 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 showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */ static const int topbar = 1; /* 0 means bottom bar */
static const char *fonts[] = { "monospace:size=10" }; static const char *fonts[] = { "monospace:size=10" };
@ -128,3 +124,4 @@ static Button buttons[] = {
{ ClkTagBar, MODKEY, Button1, tag, {0} }, { ClkTagBar, MODKEY, Button1, tag, {0} },
{ ClkTagBar, MODKEY, Button3, toggletag, {0} }, { ClkTagBar, MODKEY, Button3, toggletag, {0} },
}; };

View File

@ -1,25 +0,0 @@
diff -up a/dwm.c b/dwm.c
--- a/dwm.c 2020-07-09 16:49:10.023585649 +0200
+++ b/dwm.c 2020-07-09 16:49:43.497542191 +0200
@@ -702,7 +702,7 @@ drawbar(Monitor *m)
Client *c;
/* draw status first so it can be overdrawn by tags later */
- if (m == selmon) { /* status is only drawn on selected monitor */
+ if (m == selmon || 1) { /* 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);
@@ -1987,9 +1987,11 @@ updatesizehints(Client *c)
void
updatestatus(void)
{
+ Monitor* m;
if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
strcpy(stext, "dwm-"VERSION);
- drawbar(selmon);
+ for(m = mons; m; m = m->next)
+ drawbar(m);
}
void

View File

@ -1,746 +0,0 @@
From 4001ccae7b1a41bdcb247b0cf095a51af7b68c28 Mon Sep 17 00:00:00 2001
From: Igor Gevka <igor.gevka@gmail.com>
Date: Sun, 16 Feb 2020 15:03:10 -0800
Subject: [PATCH] [PATCH] Implements a system tray for dwm.
Original author: Jan Christoph Ebersbach <jceb@e-jc.de>, inspired by http://code.google.com/p/dwm-plus
URL: http://dwm.suckless.org/patches/systray
dwm 6.2 port by Igor Gevka <igor.gevka@gmail.com>
---
config.def.h | 4 +
dwm.c | 404 +++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 382 insertions(+), 26 deletions(-)
diff --git a/config.def.h b/config.def.h
index 1c0b587..2d824d1 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/dwm.c b/dwm.c
index 4465af1..3e361fa 100644
--- a/dwm.c
+++ b/dwm.c
@@ -57,12 +57,30 @@
#define TAGMASK ((1 << LENGTH(tags)) - 1)
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
+#define SYSTEM_TRAY_REQUEST_DOCK 0
+
+/* XEMBED messages */
+#define XEMBED_EMBEDDED_NOTIFY 0
+#define XEMBED_WINDOW_ACTIVATE 1
+#define XEMBED_FOCUS_IN 4
+#define XEMBED_MODALITY_ON 10
+
+#define XEMBED_MAPPED (1 << 0)
+#define XEMBED_WINDOW_ACTIVATE 1
+#define XEMBED_WINDOW_DEACTIVATE 2
+
+#define VERSION_MAJOR 0
+#define VERSION_MINOR 0
+#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
+
/* enums */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
enum { SchemeNorm, SchemeSel }; /* color schemes */
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
+ NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
+enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
@@ -141,6 +159,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);
@@ -169,8 +193,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);
@@ -188,13 +214,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);
@@ -206,6 +235,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 *);
@@ -223,18 +253,23 @@ static int updategeom(void);
static void updatenumlockmask(void);
static void updatesizehints(Client *c);
static void updatestatus(void);
+static void updatesystray(void);
+static void updatesystrayicongeom(Client *i, int w, int h);
+static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
static void updatetitle(Client *c);
static void updatewindowtype(Client *c);
static void updatewmhints(Client *c);
static void view(const Arg *arg);
static Client *wintoclient(Window w);
static Monitor *wintomon(Window w);
+static Client *wintosystrayicon(Window w);
static int xerror(Display *dpy, XErrorEvent *ee);
static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);
/* variables */
+static Systray *systray = NULL;
static const char broken[] = "broken";
static char stext[256];
static int screen;
@@ -257,9 +292,10 @@ static void (*handler[LASTEvent]) (XEvent *) = {
[MapRequest] = maprequest,
[MotionNotify] = motionnotify,
[PropertyNotify] = propertynotify,
+ [ResizeRequest] = resizerequest,
[UnmapNotify] = unmapnotify
};
-static Atom wmatom[WMLast], netatom[NetLast];
+static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
static int running = 1;
static Cur *cursor[CurLast];
static Clr **scheme;
@@ -439,7 +475,7 @@ buttonpress(XEvent *e)
arg.ui = 1 << i;
} else if (ev->x < x + blw)
click = ClkLtSymbol;
- else if (ev->x > selmon->ww - TEXTW(stext))
+ else if (ev->x > selmon->ww - TEXTW(stext) - getsystraywidth())
click = ClkStatusText;
else
click = ClkWinTitle;
@@ -482,6 +518,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++)
@@ -512,9 +553,57 @@ cleanupmon(Monitor *mon)
void
clientmessage(XEvent *e)
{
+ XWindowAttributes wa;
+ XSetWindowAttributes swa;
XClientMessageEvent *cme = &e->xclient;
Client *c = wintoclient(cme->window);
+ if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
+ /* add systray icons */
+ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
+ if (!(c = (Client *)calloc(1, sizeof(Client))))
+ die("fatal: could not malloc() %u bytes\n", sizeof(Client));
+ if (!(c->win = cme->data.l[2])) {
+ free(c);
+ return;
+ }
+ c->mon = selmon;
+ c->next = systray->icons;
+ systray->icons = c;
+ if (!XGetWindowAttributes(dpy, c->win, &wa)) {
+ /* use sane defaults */
+ wa.width = bh;
+ wa.height = bh;
+ wa.border_width = 0;
+ }
+ c->x = c->oldx = c->y = c->oldy = 0;
+ c->w = c->oldw = wa.width;
+ c->h = c->oldh = wa.height;
+ c->oldbw = wa.border_width;
+ c->bw = 0;
+ c->isfloating = True;
+ /* reuse tags field as mapped status */
+ c->tags = 1;
+ updatesizehints(c);
+ updatesystrayicongeom(c, wa.width, wa.height);
+ XAddToSaveSet(dpy, c->win);
+ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
+ XReparentWindow(dpy, c->win, systray->win, 0, 0);
+ /* use parents background color */
+ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
+ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
+ /* FIXME not sure if I have to send these events, too */
+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
+ XSync(dpy, False);
+ resizebarwin(selmon);
+ updatesystray();
+ setclientstate(c, NormalState);
+ }
+ return;
+ }
if (!c)
return;
if (cme->message_type == netatom[NetWMState]) {
@@ -567,7 +656,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);
@@ -652,6 +741,11 @@ destroynotify(XEvent *e)
if ((c = wintoclient(ev->window)))
unmanage(c, 1);
+ else if ((c = wintosystrayicon(ev->window))) {
+ removesystrayicon(c);
+ resizebarwin(selmon);
+ updatesystray();
+ }
}
void
@@ -695,19 +789,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);
+ sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */
+ 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)
@@ -728,7 +826,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);
@@ -739,7 +837,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
@@ -776,8 +874,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 +963,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 +1007,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)
{
@@ -1003,7 +1121,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);
@@ -1091,6 +1209,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;
@@ -1215,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)
@@ -1265,6 +1399,20 @@ recttomon(int x, int y, int w, int h)
return r;
}
+void
+removesystrayicon(Client *i)
+{
+ Client **ii;
+
+ if (!showsystray || !i)
+ return;
+ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
+ if (ii)
+ *ii = i->next;
+ free(i);
+}
+
+
void
resize(Client *c, int x, int y, int w, int h, int interact)
{
@@ -1272,6 +1420,14 @@ resize(Client *c, int x, int y, int w, int h, int interact)
resizeclient(c, x, y, w, h);
}
+void
+resizebarwin(Monitor *m) {
+ unsigned int w = m->ww;
+ if (showsystray && m == systraytomon(m))
+ w -= getsystraywidth();
+ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh);
+}
+
void
resizeclient(Client *c, int x, int y, int w, int h)
{
@@ -1344,6 +1500,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)
{
@@ -1433,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;
}
@@ -1466,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
@@ -1555,6 +1734,10 @@ setup(void)
wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
+ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
+ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
+ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
+ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
@@ -1562,6 +1745,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);
@@ -1570,6 +1756,8 @@ setup(void)
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
for (i = 0; i < LENGTH(colors); i++)
scheme[i] = drw_scm_create(drw, colors[i], 3);
+ /* init system tray */
+ updatesystray();
/* init bars */
updatebars();
updatestatus();
@@ -1701,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);
}
@@ -1796,11 +1995,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,
@@ -1811,10 +2017,15 @@ updatebars(void)
for (m = mons; m; m = m->next) {
if (m->barwin)
continue;
- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
+ w = m->ww;
+ if (showsystray && m == systraytomon(m))
+ w -= getsystraywidth();
+ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen),
CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
+ if (showsystray && m == systraytomon(m))
+ XMapRaised(dpy, systray->win);
XMapRaised(dpy, m->barwin);
XSetClassHint(dpy, m->barwin, &ch);
}
@@ -1990,6 +2201,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 dimensions if they don't want to */
+ if (i->h > bh) {
+ if (i->w == i->h)
+ i->w = bh;
+ else
+ i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
+ i->h = bh;
+ }
+ }
+}
+
+void
+updatesystrayiconstate(Client *i, XPropertyEvent *ev)
+{
+ long flags;
+ int code = 0;
+
+ if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
+ !(flags = getatomprop(i, xatom[XembedInfo])))
+ return;
+
+ if (flags & XEMBED_MAPPED && !i->tags) {
+ i->tags = 1;
+ code = XEMBED_WINDOW_ACTIVATE;
+ XMapRaised(dpy, i->win);
+ setclientstate(i, NormalState);
+ }
+ else if (!(flags & XEMBED_MAPPED) && i->tags) {
+ i->tags = 0;
+ code = XEMBED_WINDOW_DEACTIVATE;
+ XUnmapWindow(dpy, i->win);
+ setclientstate(i, WithdrawnState);
+ }
+ else
+ return;
+ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
+ systray->win, XEMBED_EMBEDDED_VERSION);
+}
+
+void
+updatesystray(void)
+{
+ XSetWindowAttributes wa;
+ XWindowChanges wc;
+ Client *i;
+ Monitor *m = systraytomon(NULL);
+ unsigned int x = m->mx + m->mw;
+ unsigned int 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
@@ -2057,6 +2383,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)
{
@@ -2110,6 +2446,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.17.1

410
dwm.c
View File

@ -57,30 +57,12 @@
#define TAGMASK ((1 << LENGTH(tags)) - 1) #define TAGMASK ((1 << LENGTH(tags)) - 1)
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
#define SYSTEM_TRAY_REQUEST_DOCK 0
/* XEMBED messages */
#define XEMBED_EMBEDDED_NOTIFY 0
#define XEMBED_WINDOW_ACTIVATE 1
#define XEMBED_FOCUS_IN 4
#define XEMBED_MODALITY_ON 10
#define XEMBED_MAPPED (1 << 0)
#define XEMBED_WINDOW_ACTIVATE 1
#define XEMBED_WINDOW_DEACTIVATE 2
#define VERSION_MAJOR 0
#define VERSION_MINOR 0
#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
/* enums */ /* enums */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
enum { SchemeNorm, SchemeSel }; /* color schemes */ enum { SchemeNorm, SchemeSel }; /* color schemes */
enum { NetSupported, NetWMName, NetWMState, NetWMCheck, enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz,
NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMFullscreen, NetActiveWindow, NetWMWindowType,
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
@ -162,12 +144,6 @@ typedef struct {
int monitor; int monitor;
} Rule; } Rule;
typedef struct Systray Systray;
struct Systray {
Window win;
Client *icons;
};
/* function declarations */ /* function declarations */
static void applyrules(Client *c); static void applyrules(Client *c);
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
@ -199,10 +175,8 @@ static void focusin(XEvent *e);
static void focusmon(const Arg *arg); static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg); static void focusstack(const Arg *arg);
static int getdwmblockspid(); static int getdwmblockspid();
static Atom getatomprop(Client *c, Atom prop);
static int getrootptr(int *x, int *y); static int getrootptr(int *x, int *y);
static long getstate(Window w); static long getstate(Window w);
static unsigned int getsystraywidth();
static int gettextprop(Window w, Atom atom, char *text, unsigned int size); static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
static void grabbuttons(Client *c, int focused); static void grabbuttons(Client *c, int focused);
static void grabkeys(void); static void grabkeys(void);
@ -220,16 +194,13 @@ static void pop(Client *);
static void propertynotify(XEvent *e); static void propertynotify(XEvent *e);
static void quit(const Arg *arg); static void quit(const Arg *arg);
static Monitor *recttomon(int x, int y, int w, int h); 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 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 resizeclient(Client *c, int x, int y, int w, int h);
static void resizemouse(const Arg *arg); static void resizemouse(const Arg *arg);
static void resizerequest(XEvent *e);
static void restack(Monitor *m); static void restack(Monitor *m);
static void run(void); static void run(void);
static void scan(void); static void scan(void);
static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); static int sendevent(Client *c, Atom proto);
static void sendmon(Client *c, Monitor *m); static void sendmon(Client *c, Monitor *m);
static void setclientstate(Client *c, long state); static void setclientstate(Client *c, long state);
static void setfocus(Client *c); static void setfocus(Client *c);
@ -242,7 +213,6 @@ static void showhide(Client *c);
static void sigchld(int unused); static void sigchld(int unused);
static void sigdwmblocks(const Arg *arg); static void sigdwmblocks(const Arg *arg);
static void spawn(const Arg *arg); static void spawn(const Arg *arg);
static Monitor *systraytomon(Monitor *m);
static void tag(const Arg *arg); static void tag(const Arg *arg);
static void tagmon(const Arg *arg); static void tagmon(const Arg *arg);
static void tile(Monitor *); static void tile(Monitor *);
@ -261,16 +231,12 @@ static int updategeom(void);
static void updatenumlockmask(void); static void updatenumlockmask(void);
static void updatesizehints(Client *c); static void updatesizehints(Client *c);
static void updatestatus(void); static void updatestatus(void);
static void updatesystray(void);
static void updatesystrayicongeom(Client *i, int w, int h);
static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
static void updatetitle(Client *c); static void updatetitle(Client *c);
static void updatewindowtype(Client *c); static void updatewindowtype(Client *c);
static void updatewmhints(Client *c); static void updatewmhints(Client *c);
static void view(const Arg *arg); static void view(const Arg *arg);
static Client *wintoclient(Window w); static Client *wintoclient(Window w);
static Monitor *wintomon(Window w); static Monitor *wintomon(Window w);
static Client *wintosystrayicon(Window w);
static int xerror(Display *dpy, XErrorEvent *ee); static int xerror(Display *dpy, XErrorEvent *ee);
static int xerrordummy(Display *dpy, XErrorEvent *ee); static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee); static int xerrorstart(Display *dpy, XErrorEvent *ee);
@ -279,7 +245,6 @@ static void bstack(Monitor *m);
static void bstackhoriz(Monitor *m); static void bstackhoriz(Monitor *m);
/* variables */ /* variables */
static Systray *systray = NULL;
static const char broken[] = "broken"; static const char broken[] = "broken";
static char stext[256]; static char stext[256];
static char rawstext[256]; static char rawstext[256];
@ -305,10 +270,9 @@ static void (*handler[LASTEvent]) (XEvent *) = {
[MapRequest] = maprequest, [MapRequest] = maprequest,
[MotionNotify] = motionnotify, [MotionNotify] = motionnotify,
[PropertyNotify] = propertynotify, [PropertyNotify] = propertynotify,
[ResizeRequest] = resizerequest,
[UnmapNotify] = unmapnotify [UnmapNotify] = unmapnotify
}; };
static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; static Atom wmatom[WMLast], netatom[NetLast];
static int running = 1; static int running = 1;
static Cur *cursor[CurLast]; static Cur *cursor[CurLast];
static Clr **scheme; static Clr **scheme;
@ -502,7 +466,7 @@ buttonpress(XEvent *e)
arg.ui = 1 << i; arg.ui = 1 << i;
} else if (ev->x < x + blw) } else if (ev->x < x + blw)
click = ClkLtSymbol; click = ClkLtSymbol;
else if (ev->x > (x = selmon->ww - TEXTW(stext) + lrpad) - getsystraywidth()) { else if (ev->x > (x = selmon->ww - TEXTW(stext) + lrpad)) {
click = ClkStatusText; click = ClkStatusText;
char *text = rawstext; char *text = rawstext;
@ -562,11 +526,6 @@ cleanup(void)
XUngrabKey(dpy, AnyKey, AnyModifier, root); XUngrabKey(dpy, AnyKey, AnyModifier, root);
while (mons) while (mons)
cleanupmon(mons); cleanupmon(mons);
if (showsystray) {
XUnmapWindow(dpy, systray->win);
XDestroyWindow(dpy, systray->win);
free(systray);
}
for (i = 0; i < CurLast; i++) for (i = 0; i < CurLast; i++)
drw_cur_free(drw, cursor[i]); drw_cur_free(drw, cursor[i]);
for (i = 0; i < LENGTH(colors); i++) for (i = 0; i < LENGTH(colors); i++)
@ -597,57 +556,9 @@ cleanupmon(Monitor *mon)
void void
clientmessage(XEvent *e) clientmessage(XEvent *e)
{ {
XWindowAttributes wa;
XSetWindowAttributes swa;
XClientMessageEvent *cme = &e->xclient; XClientMessageEvent *cme = &e->xclient;
Client *c = wintoclient(cme->window); Client *c = wintoclient(cme->window);
if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
/* add systray icons */
if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
if (!(c = (Client *)calloc(1, sizeof(Client))))
die("fatal: could not malloc() %u bytes\n", sizeof(Client));
if (!(c->win = cme->data.l[2])) {
free(c);
return;
}
c->mon = selmon;
c->next = systray->icons;
systray->icons = c;
if (!XGetWindowAttributes(dpy, c->win, &wa)) {
/* use sane defaults */
wa.width = bh;
wa.height = bh;
wa.border_width = 0;
}
c->x = c->oldx = c->y = c->oldy = 0;
c->w = c->oldw = wa.width;
c->h = c->oldh = wa.height;
c->oldbw = wa.border_width;
c->bw = 0;
c->isfloating = True;
/* reuse tags field as mapped status */
c->tags = 1;
updatesizehints(c);
updatesystrayicongeom(c, wa.width, wa.height);
XAddToSaveSet(dpy, c->win);
XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
XReparentWindow(dpy, c->win, systray->win, 0, 0);
/* use parents background color */
swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
/* FIXME not sure if I have to send these events, too */
sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
XSync(dpy, False);
resizebarwin(selmon);
updatesystray();
setclientstate(c, NormalState);
}
return;
}
if (!c) if (!c)
return; return;
if (cme->message_type == netatom[NetWMState]) { if (cme->message_type == netatom[NetWMState]) {
@ -700,7 +611,7 @@ configurenotify(XEvent *e)
for (c = m->clients; c; c = c->next) for (c = m->clients; c; c = c->next)
if (c->isfullscreen) if (c->isfullscreen)
resizeclient(c, m->mx, m->my, m->mw, m->mh); resizeclient(c, m->mx, m->my, m->mw, m->mh);
resizebarwin(m); XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
} }
focus(NULL); focus(NULL);
arrange(NULL); arrange(NULL);
@ -813,11 +724,6 @@ destroynotify(XEvent *e)
if ((c = wintoclient(ev->window))) if ((c = wintoclient(ev->window)))
unmanage(c, 1); unmanage(c, 1);
else if ((c = wintosystrayicon(ev->window))) {
removesystrayicon(c);
resizebarwin(selmon);
updatesystray();
}
} }
void void
@ -886,24 +792,20 @@ dirtomon(int dir)
void void
drawbar(Monitor *m) drawbar(Monitor *m)
{ {
int x, w, sw = 0, stw = 0; int x, w, sw = 0;
int boxs = drw->fonts->h / 9; int boxs = drw->fonts->h / 9;
int boxw = drw->fonts->h / 6 + 2; int boxw = drw->fonts->h / 6 + 2;
unsigned int i, occ = 0, urg = 0; unsigned int i, occ = 0, urg = 0;
const char *tagtext; const char *tagtext;
Client *c; Client *c;
if(showsystray && m == systraytomon(m))
stw = getsystraywidth();
/* draw status first so it can be overdrawn by tags later */ /* draw status first so it can be overdrawn by tags later */
if (m == selmon || 1) { /* status is only drawn on selected monitor */ if (m == selmon) { /* status is only drawn on selected monitor */
drw_setscheme(drw, scheme[SchemeNorm]); drw_setscheme(drw, scheme[SchemeNorm]);
sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0);
} }
resizebarwin(m);
for (c = m->clients; c; c = c->next) { for (c = m->clients; c; c = c->next) {
occ |= c->tags; occ |= c->tags;
if (c->isurgent) if (c->isurgent)
@ -921,7 +823,7 @@ drawbar(Monitor *m)
drw_setscheme(drw, scheme[SchemeNorm]); drw_setscheme(drw, scheme[SchemeNorm]);
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
if ((w = m->ww - sw - stw - x) > bh) { if ((w = m->ww - sw - x) > bh) {
if (m->sel) { if (m->sel) {
drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
@ -932,7 +834,7 @@ drawbar(Monitor *m)
drw_rect(drw, x, 0, w, bh, 1, 1); drw_rect(drw, x, 0, w, bh, 1, 1);
} }
} }
drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); drw_map(drw, m->barwin, 0, 0, m->ww, bh);
} }
void void
@ -969,11 +871,8 @@ expose(XEvent *e)
Monitor *m; Monitor *m;
XExposeEvent *ev = &e->xexpose; XExposeEvent *ev = &e->xexpose;
if (ev->count == 0 && (m = wintomon(ev->window))) { if (ev->count == 0 && (m = wintomon(ev->window)))
drawbar(m); drawbar(m);
if (m == selmon)
updatesystray();
}
} }
void void
@ -1058,17 +957,10 @@ getatomprop(Client *c, Atom prop)
unsigned long dl; unsigned long dl;
unsigned char *p = NULL; unsigned char *p = NULL;
Atom da, atom = None; 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, req, if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
&da, &di, &dl, &dl, &p) == Success && p) { &da, &di, &dl, &dl, &p) == Success && p) {
atom = *(Atom *)p; atom = *(Atom *)p;
if (da == xatom[XembedInfo] && dl == 2)
atom = ((Atom *)p)[1];
XFree(p); XFree(p);
} }
return atom; return atom;
@ -1114,16 +1006,6 @@ getstate(Window w)
return result; 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 int
gettextprop(Window w, Atom atom, char *text, unsigned int size) gettextprop(Window w, Atom atom, char *text, unsigned int size)
{ {
@ -1228,7 +1110,7 @@ killclient(const Arg *arg)
{ {
if (!selmon->sel) if (!selmon->sel)
return; return;
if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { if (!sendevent(selmon->sel, wmatom[WMDelete])) {
XGrabServer(dpy); XGrabServer(dpy);
XSetErrorHandler(xerrordummy); XSetErrorHandler(xerrordummy);
XSetCloseDownMode(dpy, DestroyAll); XSetCloseDownMode(dpy, DestroyAll);
@ -1321,12 +1203,6 @@ maprequest(XEvent *e)
{ {
static XWindowAttributes wa; static XWindowAttributes wa;
XMapRequestEvent *ev = &e->xmaprequest; 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)) if (!XGetWindowAttributes(dpy, ev->window, &wa))
return; return;
@ -1451,16 +1327,6 @@ propertynotify(XEvent *e)
Window trans; Window trans;
XPropertyEvent *ev = &e->xproperty; 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)) if ((ev->window == root) && (ev->atom == XA_WM_NAME))
updatestatus(); updatestatus();
else if (ev->state == PropertyDelete) else if (ev->state == PropertyDelete)
@ -1511,20 +1377,6 @@ recttomon(int x, int y, int w, int h)
return r; return r;
} }
void
removesystrayicon(Client *i)
{
Client **ii;
if (!showsystray || !i)
return;
for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
if (ii)
*ii = i->next;
free(i);
}
void void
resize(Client *c, int x, int y, int w, int h, int interact) resize(Client *c, int x, int y, int w, int h, int interact)
{ {
@ -1532,14 +1384,6 @@ resize(Client *c, int x, int y, int w, int h, int interact)
resizeclient(c, x, y, w, h); resizeclient(c, x, y, w, h);
} }
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 void
resizeclient(Client *c, int x, int y, int w, int h) resizeclient(Client *c, int x, int y, int w, int h)
{ {
@ -1619,19 +1463,6 @@ 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 void
restack(Monitor *m) restack(Monitor *m)
{ {
@ -1721,36 +1552,26 @@ setclientstate(Client *c, long state)
} }
int int
sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) sendevent(Client *c, Atom proto)
{ {
int n; int n;
Atom *protocols, mt; Atom *protocols;
int exists = 0; int exists = 0;
XEvent ev; XEvent ev;
if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
mt = wmatom[WMProtocols]; while (!exists && n--)
if (XGetWMProtocols(dpy, w, &protocols, &n)) { exists = protocols[n] == proto;
while (!exists && n--) XFree(protocols);
exists = protocols[n] == proto;
XFree(protocols);
}
}
else {
exists = True;
mt = proto;
} }
if (exists) { if (exists) {
ev.type = ClientMessage; ev.type = ClientMessage;
ev.xclient.window = w; ev.xclient.window = c->win;
ev.xclient.message_type = mt; ev.xclient.message_type = wmatom[WMProtocols];
ev.xclient.format = 32; ev.xclient.format = 32;
ev.xclient.data.l[0] = d0; ev.xclient.data.l[0] = proto;
ev.xclient.data.l[1] = d1; ev.xclient.data.l[1] = CurrentTime;
ev.xclient.data.l[2] = d2; XSendEvent(dpy, c->win, False, NoEventMask, &ev);
ev.xclient.data.l[3] = d3;
ev.xclient.data.l[4] = d4;
XSendEvent(dpy, w, False, mask, &ev);
} }
return exists; return exists;
} }
@ -1764,7 +1585,7 @@ setfocus(Client *c)
XA_WINDOW, 32, PropModeReplace, XA_WINDOW, 32, PropModeReplace,
(unsigned char *) &(c->win), 1); (unsigned char *) &(c->win), 1);
} }
sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); sendevent(c, wmatom[WMTakeFocus]);
} }
void void
@ -1853,10 +1674,6 @@ setup(void)
wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", 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[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
@ -1864,9 +1681,6 @@ setup(void)
netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", 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 */ /* init cursors */
cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
cursor[CurResize] = drw_cur_create(drw, XC_sizing); cursor[CurResize] = drw_cur_create(drw, XC_sizing);
@ -1875,8 +1689,6 @@ setup(void)
scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
for (i = 0; i < LENGTH(colors); i++) for (i = 0; i < LENGTH(colors); i++)
scheme[i] = drw_scm_create(drw, colors[i], 3); scheme[i] = drw_scm_create(drw, colors[i], 3);
/* init system tray */
updatesystray();
/* init bars */ /* init bars */
updatebars(); updatebars();
updatestatus(); updatestatus();
@ -2025,18 +1837,7 @@ togglebar(const Arg *arg)
{ {
selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
updatebarpos(selmon); updatebarpos(selmon);
resizebarwin(selmon); XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
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); arrange(selmon);
} }
@ -2162,18 +1963,11 @@ unmapnotify(XEvent *e)
else else
unmanage(c, 0); 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 void
updatebars(void) updatebars(void)
{ {
unsigned int w;
Monitor *m; Monitor *m;
XSetWindowAttributes wa = { XSetWindowAttributes wa = {
.override_redirect = True, .override_redirect = True,
@ -2184,15 +1978,10 @@ updatebars(void)
for (m = mons; m; m = m->next) { for (m = mons; m; m = m->next) {
if (m->barwin) if (m->barwin)
continue; continue;
w = m->ww; m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
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), CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
if (showsystray && m == systraytomon(m))
XMapRaised(dpy, systray->win);
XMapRaised(dpy, m->barwin); XMapRaised(dpy, m->barwin);
XSetClassHint(dpy, m->barwin, &ch); XSetClassHint(dpy, m->barwin, &ch);
} }
@ -2365,128 +2154,11 @@ updatesizehints(Client *c)
void void
updatestatus(void) updatestatus(void)
{ {
Monitor* m;
if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext)))
strcpy(stext, "dwm-"VERSION); strcpy(stext, "dwm-"VERSION);
else else
copyvalidchars(stext, rawstext); copyvalidchars(stext, rawstext);
for(m = mons; m; m = m->next) drawbar(selmon);
drawbar(m);
updatesystray();
}
void
updatesystrayicongeom(Client *i, int w, int h)
{
if (i) {
i->h = bh;
if (w == h)
i->w = bh;
else if (h == bh)
i->w = w;
else
i->w = (int) ((float)bh * ((float)w / (float)h));
applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
/* force icons into the systray dimensions if they don't want to */
if (i->h > bh) {
if (i->w == i->h)
i->w = bh;
else
i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
i->h = bh;
}
}
}
void
updatesystrayiconstate(Client *i, XPropertyEvent *ev)
{
long flags;
int code = 0;
if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
!(flags = getatomprop(i, xatom[XembedInfo])))
return;
if (flags & XEMBED_MAPPED && !i->tags) {
i->tags = 1;
code = XEMBED_WINDOW_ACTIVATE;
XMapRaised(dpy, i->win);
setclientstate(i, NormalState);
}
else if (!(flags & XEMBED_MAPPED) && i->tags) {
i->tags = 0;
code = XEMBED_WINDOW_DEACTIVATE;
XUnmapWindow(dpy, i->win);
setclientstate(i, WithdrawnState);
}
else
return;
sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
systray->win, XEMBED_EMBEDDED_VERSION);
}
void
updatesystray(void)
{
XSetWindowAttributes wa;
XWindowChanges wc;
Client *i;
Monitor *m = systraytomon(NULL);
unsigned int x = m->mx + m->mw;
unsigned int 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 void
@ -2580,16 +2252,6 @@ wintoclient(Window w)
return NULL; 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 * Monitor *
wintomon(Window w) wintomon(Window w)
{ {
@ -2643,22 +2305,6 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
return -1; 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 void
zoom(const Arg *arg) zoom(const Arg *arg)
{ {