When changing colour scheme during runtime using xrdb the systray and icons would keep the original colours. To work around that the systray icon windows need to be redrawn after changing the background pixel value. Just calling XClearWindow for each systray window results in the systray icons disappearing, they do not automatically redraw. The solution is apparently to send an Expose event to each window which should in principle trigger a redraw from the application side. One way to achieve this is to move the window out of the drawable area. When the window is then brought back into view the X server will send the Expose event for the window. The "easiest" way to do this is to move the entire systray window out of view as part of the xrdb call. It is possible to do this in the draw_systray function itself, but we probably do not want to do this every single time the bar is drawn and it may also cause some noticeable flickering. This issue is isolated to using the systray without the alpha patch.
209 lines
5.5 KiB
C
209 lines
5.5 KiB
C
static Systray *systray = NULL;
|
|
static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ;
|
|
|
|
int
|
|
width_systray(Bar *bar, BarArg *a)
|
|
{
|
|
unsigned int w = 0;
|
|
Client *i;
|
|
if (!systray)
|
|
return 1;
|
|
if (showsystray) {
|
|
for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next);
|
|
if (!w)
|
|
XMoveWindow(dpy, systray->win, -systray->h, bar->by);
|
|
}
|
|
return w ? w + lrpad - systrayspacing : 0;
|
|
}
|
|
|
|
int
|
|
draw_systray(Bar *bar, BarArg *a)
|
|
{
|
|
if (!showsystray)
|
|
return 0;
|
|
|
|
XSetWindowAttributes wa;
|
|
XWindowChanges wc;
|
|
Client *i;
|
|
unsigned int w;
|
|
|
|
if (!systray) {
|
|
/* init systray */
|
|
if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
|
|
die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
|
|
|
|
wa.override_redirect = True;
|
|
wa.event_mask = ButtonPressMask|ExposureMask;
|
|
wa.border_pixel = 0;
|
|
systray->h = MIN(a->h, drw->fonts->h);
|
|
#if BAR_ALPHA_PATCH
|
|
wa.background_pixel = 0;
|
|
wa.colormap = cmap;
|
|
systray->win = XCreateWindow(dpy, root, bar->bx + a->x + lrpad / 2, -systray->h, MAX(a->w + 40, 1), systray->h, 0, depth,
|
|
InputOutput, visual,
|
|
CWOverrideRedirect|CWBorderPixel|CWBackPixel|CWColormap|CWEventMask, &wa); // CWBackPixmap
|
|
#else
|
|
wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
|
systray->win = XCreateSimpleWindow(dpy, root, bar->bx + a->x + lrpad / 2, -systray->h, MIN(a->w, 1), systray->h, 0, 0, scheme[SchemeNorm][ColBg].pixel);
|
|
XChangeWindowAttributes(dpy, systray->win, CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWEventMask, &wa);
|
|
#endif // BAR_ALPHA_PATCH
|
|
|
|
XSelectInput(dpy, systray->win, SubstructureNotifyMask);
|
|
XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
|
|
PropModeReplace, (unsigned char *)&systrayorientation, 1);
|
|
#if BAR_ALPHA_PATCH
|
|
XChangeProperty(dpy, systray->win, netatom[NetSystemTrayVisual], XA_VISUALID, 32,
|
|
PropModeReplace, (unsigned char *)&visual->visualid, 1);
|
|
#endif // BAR_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 0;
|
|
}
|
|
}
|
|
|
|
systray->bar = bar;
|
|
|
|
wc.stack_mode = Above;
|
|
wc.sibling = bar->win;
|
|
XConfigureWindow(dpy, systray->win, CWSibling|CWStackMode, &wc);
|
|
|
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
|
for (w = 0, i = systray->icons; i; i = i->next) {
|
|
#if BAR_ALPHA_PATCH
|
|
wa.background_pixel = 0;
|
|
#else
|
|
wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
|
#endif // BAR_ALPHA_PATCH
|
|
XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
|
|
XMapRaised(dpy, i->win);
|
|
i->x = w;
|
|
XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
|
|
w += i->w;
|
|
if (i->next)
|
|
w += systrayspacing;
|
|
if (i->mon != bar->mon)
|
|
i->mon = bar->mon;
|
|
}
|
|
|
|
#if !BAR_ALPHA_PATCH
|
|
wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
|
XChangeWindowAttributes(dpy, systray->win, CWBackPixel, &wa);
|
|
XClearWindow(dpy, systray->win);
|
|
#endif // BAR_ALPHA_PATCH
|
|
|
|
XMoveResizeWindow(dpy, systray->win, bar->bx + a->x + lrpad / 2, (w ? bar->by + a->y + (a->h - systray->h) / 2: -systray->h), MAX(w, 1), systray->h);
|
|
return w;
|
|
}
|
|
|
|
int
|
|
click_systray(Bar *bar, Arg *arg, BarArg *a)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
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;
|
|
XReparentWindow(dpy, i->win, root, 0, 0);
|
|
free(i);
|
|
drawbarwin(systray->bar);
|
|
}
|
|
|
|
void
|
|
resizerequest(XEvent *e)
|
|
{
|
|
XResizeRequestEvent *ev = &e->xresizerequest;
|
|
Client *i;
|
|
|
|
if ((i = wintosystrayicon(ev->window))) {
|
|
updatesystrayicongeom(i, ev->width, ev->height);
|
|
drawbarwin(systray->bar);
|
|
}
|
|
}
|
|
|
|
void
|
|
updatesystrayicongeom(Client *i, int w, int h)
|
|
{
|
|
if (!systray)
|
|
return;
|
|
|
|
int icon_height = systray->h;
|
|
if (i) {
|
|
i->h = icon_height;
|
|
if (w == h)
|
|
i->w = icon_height;
|
|
else if (h == icon_height)
|
|
i->w = w;
|
|
else
|
|
i->w = (int) ((float)icon_height * ((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 > icon_height) {
|
|
if (i->w == i->h)
|
|
i->w = icon_height;
|
|
else
|
|
i->w = (int) ((float)icon_height * ((float)i->w / (float)i->h));
|
|
i->h = icon_height;
|
|
}
|
|
if (i->w > 2 * icon_height)
|
|
i->w = icon_height;
|
|
}
|
|
}
|
|
|
|
void
|
|
updatesystrayiconstate(Client *i, XPropertyEvent *ev)
|
|
{
|
|
long flags;
|
|
int code = 0;
|
|
|
|
if (!showsystray || !systray || !i || ev->atom != xatom[XembedInfo] ||
|
|
!(flags = getatomprop(i, xatom[XembedInfo], 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 *
|
|
wintosystrayicon(Window w)
|
|
{
|
|
if (!systray)
|
|
return NULL;
|
|
Client *i = NULL;
|
|
if (!showsystray || !w)
|
|
return i;
|
|
for (i = systray->icons; i && i->win != w; i = i->next);
|
|
return i;
|
|
}
|
|
|