2019-09-05 20:10:00 +00:00
|
|
|
|
|
|
|
static Systray *systray = NULL;
|
|
|
|
static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ;
|
|
|
|
|
|
|
|
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 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
resizerequest(XEvent *e)
|
|
|
|
{
|
|
|
|
XResizeRequestEvent *ev = &e->xresizerequest;
|
|
|
|
Client *i;
|
|
|
|
|
|
|
|
if ((i = wintosystrayicon(ev->window))) {
|
|
|
|
updatesystrayicongeom(i, ev->width, ev->height);
|
|
|
|
updatesystray();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Monitor *
|
2019-09-10 22:51:37 +00:00
|
|
|
systraytomon(Monitor *m)
|
|
|
|
{
|
2019-09-05 20:10:00 +00:00
|
|
|
Monitor *t;
|
|
|
|
int i, n;
|
2019-09-10 22:51:37 +00:00
|
|
|
if (!systraypinning) {
|
|
|
|
if (!m)
|
2019-09-05 20:10:00 +00:00
|
|
|
return selmon;
|
|
|
|
return m == selmon ? m : NULL;
|
|
|
|
}
|
2019-09-10 22:51:37 +00:00
|
|
|
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)
|
2019-09-05 20:10:00 +00:00
|
|
|
return mons;
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
updatesystray(void)
|
|
|
|
{
|
|
|
|
XSetWindowAttributes wa;
|
|
|
|
XWindowChanges wc;
|
|
|
|
Client *i;
|
|
|
|
Monitor *m = systraytomon(NULL);
|
|
|
|
unsigned int x = m->mx + m->mw;
|
2020-02-09 14:17:05 +00:00
|
|
|
unsigned int w = 1, xpad = 0, ypad = 0;
|
|
|
|
#if BARPADDING_PATCH
|
|
|
|
xpad = sp;
|
|
|
|
ypad = vp;
|
|
|
|
#endif // BARPADDING_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
|
|
|
|
if (!showsystray)
|
|
|
|
return;
|
|
|
|
if (!systray) {
|
|
|
|
/* init systray */
|
|
|
|
if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
|
|
|
|
die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
|
|
|
|
|
|
|
|
#if ALPHA_PATCH
|
|
|
|
XSetWindowAttributes wa = {
|
|
|
|
.override_redirect = True,
|
|
|
|
.background_pixel = scheme[SchemeNorm][ColBg].pixel,
|
|
|
|
.border_pixel = 0,
|
|
|
|
.colormap = cmap,
|
|
|
|
.event_mask = ButtonPressMask|ExposureMask
|
|
|
|
};
|
2020-02-09 14:17:05 +00:00
|
|
|
systray->win = XCreateWindow(dpy, root, x - xpad, m->by + ypad, w, bh, 0, depth,
|
2019-09-05 20:10:00 +00:00
|
|
|
InputOutput, visual,
|
|
|
|
CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
|
|
|
|
#else
|
2020-02-09 14:17:05 +00:00
|
|
|
systray->win = XCreateSimpleWindow(dpy, root, x - xpad, m->by + ypad, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel);
|
2019-09-05 20:10:00 +00:00
|
|
|
#endif // ALPHA_PATCH
|
|
|
|
XSelectInput(dpy, systray->win, SubstructureNotifyMask);
|
|
|
|
XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
|
|
|
|
PropModeReplace, (unsigned char *)&systrayorientation, 1);
|
|
|
|
#if ALPHA_PATCH
|
|
|
|
XChangeProperty(dpy, systray->win, netatom[NetSystemTrayVisual], XA_VISUALID, 32,
|
|
|
|
PropModeReplace, (unsigned char *)&visual->visualid, 1);
|
|
|
|
#endif // ALPHA_PATCH
|
|
|
|
XChangeProperty(dpy, systray->win, netatom[NetWMWindowType], XA_ATOM, 32,
|
|
|
|
PropModeReplace, (unsigned char *)&netatom[NetWMWindowTypeDock], 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;
|
2020-02-09 14:17:05 +00:00
|
|
|
XMoveResizeWindow(dpy, systray->win, x - xpad, m->by + ypad, w, bh);
|
|
|
|
wc.x = x - xpad;
|
|
|
|
wc.y = m->by + ypad;
|
2020-02-09 12:04:28 +00:00
|
|
|
wc.width = w;
|
|
|
|
wc.height = bh;
|
2019-09-05 20:10:00 +00:00
|
|
|
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
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
Client *
|
2019-09-10 22:51:37 +00:00
|
|
|
wintosystrayicon(Window w)
|
|
|
|
{
|
2019-09-05 20:10:00 +00:00
|
|
|
Client *i = NULL;
|
|
|
|
|
|
|
|
if (!showsystray || !w)
|
|
|
|
return i;
|
|
|
|
for (i = systray->icons; i && i->win != w; i = i->next);
|
|
|
|
return i;
|
|
|
|
}
|