/* * wmfs2 by Martin Duquesnoy { for(i = 2011; i < 2111; ++i) ©(i); } * For license, see COPYING. */ #include "wmfs.h" #include "systray.h" #include "ewmh.h" #include "infobar.h" #define SYSTRAY_SPACING (2) void systray_acquire(void) { Window w = 0; XSetWindowAttributes wattr = { .event_mask = ButtonPressMask | ExposureMask, .override_redirect = true, .background_pixmap = ParentRelative, .background_pixel = W->systray.infobar->theme->bars.bg, }; if(!(W->flags & WMFS_SYSTRAY) || W->systray.win) return; if(XGetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s]) != None) { warnx("Can't initialize system tray: owned by another process."); return; } SLIST_INIT(&W->systray.head); /* Init systray window */ w = XCreateSimpleWindow(W->dpy, W->systray.barwin->win, 0, 0, W->systray.barwin->geo.h, W->systray.barwin->geo.h, 0, 0, 0); XChangeWindowAttributes(W->dpy, w, CWEventMask | CWOverrideRedirect | CWBackPixel, &wattr); XSelectInput(W->dpy, w, KeyPressMask | ButtonPressMask); XMapRaised(W->dpy, w); XSetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s], w, CurrentTime); if(XGetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s]) != w) { warnl("System tray: can't get systray manager"); systray_freeicons(); return; } ewmh_send_message(W->root, W->root, "MANAGER", CurrentTime, W->net_atom[net_system_tray_s], w, 0, 0); XSync(W->dpy, false); W->systray.win = w; } void systray_add(Window win) { struct _systray *s; if(!(W->flags & WMFS_SYSTRAY)) return; s = xcalloc(1, sizeof(struct _systray)); s->win = win; s->geo.h = W->systray.barwin->geo.h; s->geo.w = W->systray.barwin->geo.h + SYSTRAY_SPACING; ewmh_set_wm_state(s->win, NormalState); XSelectInput(W->dpy, s->win, StructureNotifyMask | PropertyChangeMask| EnterWindowMask | FocusChangeMask); XReparentWindow(W->dpy, s->win, W->systray.win, 0, 0); ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0, W->systray.win, 0); SLIST_INSERT_HEAD(&W->systray.head, s, next); W->systray.redim = true; } void systray_del(struct _systray *s) { if(!(W->flags & WMFS_SYSTRAY)) return; SLIST_REMOVE(&W->systray.head, s, _systray, next); free(s); W->systray.redim = true; } void systray_state(struct _systray *s) { long flags; int code = 0; if(!(W->flags & WMFS_SYSTRAY) || !(flags = ewmh_get_xembed_state(s->win))) return; if(flags & XEMBED_MAPPED) { code = XEMBED_WINDOW_ACTIVATE; XMapRaised(W->dpy, s->win); ewmh_set_wm_state(s->win, NormalState); } else { code = XEMBED_WINDOW_DEACTIVATE; XUnmapWindow(W->dpy, s->win); ewmh_set_wm_state(s->win, WithdrawnState); } ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime, code, 0, 0, 0); } void systray_freeicons(void) { struct _systray *i; if(!(W->flags & WMFS_SYSTRAY)) return; while(!SLIST_EMPTY(&W->systray.head)) { i = SLIST_FIRST(&W->systray.head); SLIST_REMOVE_HEAD(&W->systray.head, next); XUnmapWindow(W->dpy, i->win); XReparentWindow(W->dpy, i->win, W->root, 0, 0); free(i); } XSetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s], None, CurrentTime); W->systray.barwin->geo.w = 0; infobar_elem_reinit(W->systray.infobar); XSync(W->dpy, false); } struct _systray* systray_find(Window win) { struct _systray *i; if(!(W->flags & WMFS_SYSTRAY)) return NULL; SLIST_FOREACH(i, &W->systray.head, next) if(i->win == win) return i; return NULL; } int systray_get_width(void) { int w = 1; struct _systray *i; SLIST_FOREACH(i, &W->systray.head, next) w += i->geo.w + SYSTRAY_SPACING; return w; } void systray_update(void) { int x = 1; struct _systray *i; if(!(W->flags & WMFS_SYSTRAY)) return; if(W->systray.redim) { W->systray.redim = false; infobar_elem_reinit(W->systray.infobar); } SLIST_FOREACH(i, &W->systray.head, next) { XMapWindow(W->dpy, i->win); XMoveResizeWindow(W->dpy, i->win, (i->geo.x = x), 0, i->geo.w, i->geo.h); x += i->geo.w + SYSTRAY_SPACING; } }