You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
5.3 KiB
198 lines
5.3 KiB
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); |
|
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, bar->by + a->y + (a->h - systray->h) / 2, 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, bar->by + a->y + (a->h - systray->h) / 2, 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; |
|
} |
|
|
|
XMoveResizeWindow(dpy, systray->win, bar->bx + a->x + lrpad / 2, (w ? bar->by + a->y + (a->h - systray->h) / 2: -bar->by - a->y), 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; |
|
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]))) |
|
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; |
|
} |
|
|
|
|