From 2433e0499e4607d39a3f511449f9466886055914 Mon Sep 17 00:00:00 2001 From: Bakkeby Date: Mon, 10 Jan 2022 14:06:10 +0100 Subject: [PATCH 1/2] Bar Modules - splits the bar functionality into individual segments that can be re-arranged --- config.def.h | 20 +++ dwm.c | 393 ++++++++++++++++++++++++++++++++----------- patch/bar_ltsymbol.c | 17 ++ patch/bar_ltsymbol.h | 3 + patch/bar_status.c | 19 +++ patch/bar_status.h | 3 + patch/bar_tags.c | 55 ++++++ patch/bar_tags.h | 3 + patch/bar_wintitle.c | 31 ++++ patch/bar_wintitle.h | 3 + patch/include.c | 5 + patch/include.h | 5 + 12 files changed, 458 insertions(+), 99 deletions(-) create mode 100644 patch/bar_ltsymbol.c create mode 100644 patch/bar_ltsymbol.h create mode 100644 patch/bar_status.c create mode 100644 patch/bar_status.h create mode 100644 patch/bar_tags.c create mode 100644 patch/bar_tags.h create mode 100644 patch/bar_wintitle.c create mode 100644 patch/bar_wintitle.h create mode 100644 patch/include.c create mode 100644 patch/include.h diff --git a/config.def.h b/config.def.h index a2ac963..f870c41 100644 --- a/config.def.h +++ b/config.def.h @@ -31,6 +31,26 @@ static const Rule rules[] = { { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, }; +/* Bar rules allow you to configure what is shown where on the bar, as well as + * introducing your own bar modules. + * + * monitor: + * -1 show on all monitors + * 0 show on monitor 0 + * 'A' show on active monitor (i.e. focused / selected) (or just -1 for active?) + * bar - bar index, 0 is default, 1 is extrabar + * alignment - how the module is aligned compared to other modules + * widthfunc, drawfunc, clickfunc - providing bar module width, draw and click functions + * name - does nothing, intended for visual clue and for logging / debugging + */ +static const BarRule barrules[] = { + /* monitor bar alignment widthfunc drawfunc clickfunc name */ + { -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" }, + { -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" }, + { 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" }, + { -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" }, +}; + /* layout(s) */ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ static const int nmaster = 1; /* number of clients in master area */ diff --git a/dwm.c b/dwm.c index a96f33c..86763d8 100644 --- a/dwm.c +++ b/dwm.c @@ -45,6 +45,7 @@ #include "util.h" /* macros */ +#define BARRULES 20 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ @@ -66,6 +67,19 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +enum { + BAR_ALIGN_LEFT, + BAR_ALIGN_CENTER, + BAR_ALIGN_RIGHT, + BAR_ALIGN_LEFT_LEFT, + BAR_ALIGN_LEFT_RIGHT, + BAR_ALIGN_LEFT_CENTER, + BAR_ALIGN_NONE, + BAR_ALIGN_RIGHT_LEFT, + BAR_ALIGN_RIGHT_RIGHT, + BAR_ALIGN_RIGHT_CENTER, + BAR_ALIGN_LAST +}; /* bar alignment */ typedef union { int i; @@ -74,6 +88,46 @@ typedef union { const void *v; } Arg; +typedef struct Monitor Monitor; +typedef struct Bar Bar; +struct Bar { + Window win; + Monitor *mon; + Bar *next; + int idx; + int topbar; + int bx, by, bw, bh; /* bar geometry */ + int w[BARRULES]; // module width + int x[BARRULES]; // module position +}; + +typedef struct { + int max_width; +} BarWidthArg; + +typedef struct { + int x; + int w; +} BarDrawArg; + +typedef struct { + int rel_x; + int rel_y; + int rel_w; + int rel_h; +} BarClickArg; + +typedef struct { + int monitor; + int bar; + int alignment; // see bar alignment enum + int (*widthfunc)(Bar *bar, BarWidthArg *a); + int (*drawfunc)(Bar *bar, BarDrawArg *a); + int (*clickfunc)(Bar *bar, Arg *arg, BarClickArg *a); + char *name; // for debugging + int x, w; // position, width for internal use +} BarRule; + typedef struct { unsigned int click; unsigned int mask; @@ -82,7 +136,6 @@ typedef struct { const Arg arg; } Button; -typedef struct Monitor Monitor; typedef struct Client Client; struct Client { char name[256]; @@ -116,19 +169,17 @@ struct Monitor { float mfact; int nmaster; int num; - int by; /* bar geometry */ int mx, my, mw, mh; /* screen size */ int wx, wy, ww, wh; /* window area */ unsigned int seltags; unsigned int sellt; unsigned int tagset[2]; int showbar; - int topbar; Client *clients; Client *sel; Client *stack; Monitor *next; - Window barwin; + Bar *bar; const Layout *lt[2]; }; @@ -163,6 +214,7 @@ static void detachstack(Client *c); static Monitor *dirtomon(int dir); static void drawbar(Monitor *m); static void drawbars(void); +static void drawbarwin(Bar *bar); static void enternotify(XEvent *e); static void expose(XEvent *e); static void focus(Client *c); @@ -235,12 +287,13 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee); static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); +#include "patch/include.h" /* variables */ static const char broken[] = "broken"; static char stext[256]; static int screen; static int sw, sh; /* X display screen geometry width, height */ -static int bh, blw = 0; /* bar geometry */ +static int bh; /* bar geometry */ static int lrpad; /* sum of left and right padding for text */ static int (*xerrorxlib)(Display *, XErrorEvent *); static unsigned int numlockmask = 0; @@ -272,6 +325,8 @@ static Window root, wmcheckwin; /* configuration, allows nested code to access above variables */ #include "config.h" +#include "patch/include.c" + /* compile-time check if all tags fit into an unsigned int bit array. */ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; @@ -417,43 +472,61 @@ attachstack(Client *c) void buttonpress(XEvent *e) { - unsigned int i, x, click; + int click, i, r, mi; Arg arg = {0}; Client *c; Monitor *m; + Bar *bar; XButtonPressedEvent *ev = &e->xbutton; + const BarRule *br; + BarClickArg carg = { 0, 0, 0, 0 }; click = ClkRootWin; /* focus monitor if necessary */ - if ((m = wintomon(ev->window)) && m != selmon) { + if ((m = wintomon(ev->window)) && m != selmon + ) { unfocus(selmon->sel, 1); selmon = m; focus(NULL); } - if (ev->window == selmon->barwin) { - i = x = 0; - do - x += TEXTW(tags[i]); - while (ev->x >= x && ++i < LENGTH(tags)); - if (i < LENGTH(tags)) { - click = ClkTagBar; - arg.ui = 1 << i; - } else if (ev->x < x + blw) - click = ClkLtSymbol; - else if (ev->x > selmon->ww - (int)TEXTW(stext)) - click = ClkStatusText; - else - click = ClkWinTitle; - } else if ((c = wintoclient(ev->window))) { + + for (mi = 0, m = mons; m && m != selmon; m = m->next, mi++); // get the monitor index + for (bar = selmon->bar; bar; bar = bar->next) { + if (ev->window == bar->win) { + for (r = 0; r < LENGTH(barrules); r++) { + br = &barrules[r]; + if (br->bar != bar->idx || (br->monitor == 'A' && m != selmon) || br->clickfunc == NULL) + continue; + if (br->monitor != 'A' && br->monitor != -1 && br->monitor != mi) + continue; + if (bar->x[r] <= ev->x && ev->x <= bar->x[r] + bar->w[r]) { + carg.rel_x = ev->x - bar->x[r]; + carg.rel_y = ev->y; + carg.rel_w = bar->w[r]; + carg.rel_h = bar->bh; + click = br->clickfunc(bar, &arg, &carg); + if (click < 0) + return; + break; + } + } + break; + } + } + + if (click == ClkRootWin && (c = wintoclient(ev->window))) { focus(c); restack(selmon); XAllowEvents(dpy, ReplayPointer, CurrentTime); click = ClkClientWin; } - for (i = 0; i < LENGTH(buttons); i++) + + for (i = 0; i < LENGTH(buttons); i++) { if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button - && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) { buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); + } + } } void @@ -498,6 +571,7 @@ void cleanupmon(Monitor *mon) { Monitor *m; + Bar *bar; if (mon == mons) mons = mons->next; @@ -505,8 +579,12 @@ cleanupmon(Monitor *mon) for (m = mons; m && m->next != mon; m = m->next); m->next = mon->next; } - XUnmapWindow(dpy, mon->barwin); - XDestroyWindow(dpy, mon->barwin); + for (bar = mon->bar; bar; bar = mon->bar) { + XUnmapWindow(dpy, bar->win); + XDestroyWindow(dpy, bar->win); + mon->bar = bar->next; + free(bar); + } free(mon); } @@ -552,6 +630,7 @@ void configurenotify(XEvent *e) { Monitor *m; + Bar *bar; Client *c; XConfigureEvent *ev = &e->xconfigure; int dirty; @@ -568,7 +647,8 @@ 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); + for (bar = m->bar; bar; bar = bar->next) + XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); } focus(NULL); arrange(NULL); @@ -631,17 +711,40 @@ configurerequest(XEvent *e) Monitor * createmon(void) { - Monitor *m; + Monitor *m, *mon; + int i, n, mi, max_bars = 2, istopbar = topbar; + + const BarRule *br; + Bar *bar; m = ecalloc(1, sizeof(Monitor)); m->tagset[0] = m->tagset[1] = 1; m->mfact = mfact; m->nmaster = nmaster; m->showbar = showbar; - m->topbar = topbar; + + for (mi = 0, mon = mons; mon; mon = mon->next, mi++); // monitor index m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + + /* Derive the number of bars for this monitor based on bar rules */ + for (n = -1, i = 0; i < LENGTH(barrules); i++) { + br = &barrules[i]; + if (br->monitor == 'A' || br->monitor == -1 || br->monitor == mi) + n = MAX(br->bar, n); + } + + for (i = 0; i <= n && i < max_bars; i++) { + bar = ecalloc(1, sizeof(Bar)); + bar->mon = m; + bar->idx = i; + bar->next = m->bar; + bar->topbar = istopbar; + m->bar = bar; + istopbar = !istopbar; + } + return m; } @@ -696,65 +799,117 @@ dirtomon(int dir) void drawbar(Monitor *m) { - int x, w, tw = 0; - int boxs = drw->fonts->h / 9; - int boxw = drw->fonts->h / 6 + 2; - unsigned int i, occ = 0, urg = 0; - Client *c; - - if (!m->showbar) - return; - - /* 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]); - tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ - drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); - } - - for (c = m->clients; c; c = c->next) { - occ |= c->tags; - if (c->isurgent) - urg |= c->tags; - } - x = 0; - for (i = 0; i < LENGTH(tags); i++) { - w = TEXTW(tags[i]); - drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); - drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); - if (occ & 1 << i) - drw_rect(drw, x + boxs, boxs, boxw, boxw, - m == selmon && selmon->sel && selmon->sel->tags & 1 << i, - urg & 1 << i); - x += w; - } - w = blw = TEXTW(m->ltsymbol); - drw_setscheme(drw, scheme[SchemeNorm]); - x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); - - if ((w = m->ww - tw - 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); - if (m->sel->isfloating) - drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); - } else { - drw_setscheme(drw, scheme[SchemeNorm]); - drw_rect(drw, x, 0, w, bh, 1, 1); - } - } - drw_map(drw, m->barwin, 0, 0, m->ww, bh); + Bar *bar; + for (bar = m->bar; bar; bar = bar->next) + drawbarwin(bar); } void drawbars(void) { Monitor *m; - for (m = mons; m; m = m->next) drawbar(m); } +void +drawbarwin(Bar *bar) +{ + if (!bar->win) + return; + Monitor *mon; + int r, w, mi; + int rx, lx, rw, lw; // bar size, split between left and right if a center module is added + const BarRule *br; + BarWidthArg warg = { 0 }; + BarDrawArg darg = { 0, 0 }; + + for (mi = 0, mon = mons; mon && mon != bar->mon; mon = mon->next, mi++); // get the monitor index + rw = lw = bar->bw; + rx = lx = 0; + + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, lx, 0, lw, bh, 1, 1); + for (r = 0; r < LENGTH(barrules); r++) { + br = &barrules[r]; + if (br->bar != bar->idx || br->drawfunc == NULL || (br->monitor == 'A' && bar->mon != selmon)) + continue; + if (br->monitor != 'A' && br->monitor != -1 && br->monitor != mi) + continue; + drw_setscheme(drw, scheme[SchemeNorm]); + warg.max_width = (br->alignment < BAR_ALIGN_RIGHT_LEFT ? lw : rw); + w = br->widthfunc(bar, &warg); + w = MIN(warg.max_width, w); + + if (lw <= 0) { // if left is exhausted then switch to right side, and vice versa + lw = rw; + lx = rx; + } else if (rw <= 0) { + rw = lw; + rx = lx; + } + + switch(br->alignment) { + default: + case BAR_ALIGN_NONE: + case BAR_ALIGN_LEFT_LEFT: + case BAR_ALIGN_LEFT: + bar->x[r] = lx; + if (lx == rx) { + rx += w; + rw -= w; + } + lx += w; + lw -= w; + break; + case BAR_ALIGN_LEFT_RIGHT: + case BAR_ALIGN_RIGHT: + bar->x[r] = lx + lw - w; + if (lx == rx) + rw -= w; + lw -= w; + break; + case BAR_ALIGN_LEFT_CENTER: + case BAR_ALIGN_CENTER: + bar->x[r] = lx + lw / 2 - w / 2; + if (lx == rx) { + rw = rx + rw - bar->x[r] - w; + rx = bar->x[r] + w; + } + lw = bar->x[r] - lx; + break; + case BAR_ALIGN_RIGHT_LEFT: + bar->x[r] = rx; + if (lx == rx) { + lx += w; + lw -= w; + } + rx += w; + rw -= w; + break; + case BAR_ALIGN_RIGHT_RIGHT: + bar->x[r] = rx + rw - w; + if (lx == rx) + lw -= w; + rw -= w; + break; + case BAR_ALIGN_RIGHT_CENTER: + bar->x[r] = rx + rw / 2 - w / 2; + if (lx == rx) { + lw = lx + lw - bar->x[r] + w; + lx = bar->x[r] + w; + } + rw = bar->x[r] - rx; + break; + } + bar->w[r] = w; + darg.x = bar->x[r]; + darg.w = bar->w[r]; + br->drawfunc(bar, &darg); + } + drw_map(drw, bar->win, 0, 0, bar->bw, bar->bh); +} + void enternotify(XEvent *e) { @@ -1049,7 +1204,7 @@ manage(Window w, XWindowAttributes *wa) c->y = c->mon->my + c->mon->mh - HEIGHT(c); c->x = MAX(c->x, c->mon->mx); /* only fix client y-offset, if the client center might cover the bar */ - c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) + c->y = MAX(c->y, ((c->mon->bar->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); c->bw = borderpx; @@ -1236,7 +1391,8 @@ propertynotify(XEvent *e) break; case XA_WM_HINTS: updatewmhints(c); - drawbars(); + if (c->isurgent) + drawbars(); break; } if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { @@ -1362,7 +1518,7 @@ restack(Monitor *m) XRaiseWindow(dpy, m->sel->win); if (m->lt[m->sellt]->arrange) { wc.stack_mode = Below; - wc.sibling = m->barwin; + wc.sibling = m->bar->win; for (c = m->stack; c; c = c->snext) if (!c->isfloating && ISVISIBLE(c)) { XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); @@ -1705,9 +1861,11 @@ tile(Monitor *m) void togglebar(const Arg *arg) { + Bar *bar; selmon->showbar = !selmon->showbar; updatebarpos(selmon); - XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + for (bar = selmon->bar; bar; bar = bar->next) + XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); arrange(selmon); } @@ -1807,22 +1965,37 @@ unmapnotify(XEvent *e) void updatebars(void) { + Bar *bar; Monitor *m; XSetWindowAttributes wa = { .override_redirect = True, + #if BAR_ALPHA_PATCH + .background_pixel = 0, + .border_pixel = 0, + .colormap = cmap, + #else .background_pixmap = ParentRelative, + #endif // BAR_ALPHA_PATCH .event_mask = ButtonPressMask|ExposureMask }; XClassHint ch = {"dwm", "dwm"}; 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), - CopyFromParent, DefaultVisual(dpy, screen), - CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); - XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); - XMapRaised(dpy, m->barwin); - XSetClassHint(dpy, m->barwin, &ch); + for (bar = m->bar; bar; bar = bar->next) { + if (!bar->win) { + #if BAR_ALPHA_PATCH + bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, depth, + InputOutput, visual, + CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa); + #else + bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + #endif // BAR_ALPHA_PATCH + XDefineCursor(dpy, bar->win, cursor[CurNormal]->cursor); + XMapRaised(dpy, bar->win); + XSetClassHint(dpy, bar->win, &ch); + } + } } } @@ -1831,12 +2004,30 @@ updatebarpos(Monitor *m) { m->wy = m->my; m->wh = m->mh; - if (m->showbar) { - m->wh -= bh; - m->by = m->topbar ? m->wy : m->wy + m->wh; - m->wy = m->topbar ? m->wy + bh : m->wy; - } else - m->by = -bh; + int num_bars; + Bar *bar; + int y_pad = 0; + int x_pad = 0; + + for (bar = m->bar; bar; bar = bar->next) { + bar->bx = m->mx + x_pad; + bar->bw = m->ww - 2 * x_pad; + bar->bh = bh; + } + + if (!m->showbar) { + for (bar = m->bar; bar; bar = bar->next) + bar->by = -bh - y_pad; + return; + } + + for (num_bars = 0, bar = m->bar; bar; bar = bar->next, num_bars++) + if (bar->topbar) + m->wy = m->my + bh + y_pad; + m->wh = m->wh - y_pad * num_bars - bh * num_bars; + + for (bar = m->bar; bar; bar = bar->next) + bar->by = (bar->topbar ? m->wy - bh : m->wy + m->wh); } void @@ -1993,9 +2184,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 @@ -2069,12 +2262,14 @@ wintomon(Window w) int x, y; Client *c; Monitor *m; + Bar *bar; if (w == root && getrootptr(&x, &y)) return recttomon(x, y, 1, 1); for (m = mons; m; m = m->next) - if (w == m->barwin) - return m; + for (bar = m->bar; bar; bar = bar->next) + if (w == bar->win) + return m; if ((c = wintoclient(w))) return c->mon; return selmon; diff --git a/patch/bar_ltsymbol.c b/patch/bar_ltsymbol.c new file mode 100644 index 0000000..6676a2a --- /dev/null +++ b/patch/bar_ltsymbol.c @@ -0,0 +1,17 @@ +int +width_ltsymbol(Bar *bar, BarWidthArg *a) +{ + return TEXTW(bar->mon->ltsymbol); +} + +int +draw_ltsymbol(Bar *bar, BarDrawArg *a) +{ + return drw_text(drw, a->x, 0, a->w, bh, lrpad / 2, bar->mon->ltsymbol, 0); +} + +int +click_ltsymbol(Bar *bar, Arg *arg, BarClickArg *a) +{ + return ClkLtSymbol; +} diff --git a/patch/bar_ltsymbol.h b/patch/bar_ltsymbol.h new file mode 100644 index 0000000..d9c79bf --- /dev/null +++ b/patch/bar_ltsymbol.h @@ -0,0 +1,3 @@ +static int width_ltsymbol(Bar *bar, BarWidthArg *a); +static int draw_ltsymbol(Bar *bar, BarDrawArg *a); +static int click_ltsymbol(Bar *bar, Arg *arg, BarClickArg *a); diff --git a/patch/bar_status.c b/patch/bar_status.c new file mode 100644 index 0000000..7d27282 --- /dev/null +++ b/patch/bar_status.c @@ -0,0 +1,19 @@ +int +width_status(Bar *bar, BarWidthArg *a) +{ + return TEXTW(stext); +} + + +int +draw_status(Bar *bar, BarDrawArg *a) +{ + return drw_text(drw, a->x, 0, a->w, bh, lrpad / 2, stext, 0); +} + + +int +click_status(Bar *bar, Arg *arg, BarClickArg *a) +{ + return ClkStatusText; +} diff --git a/patch/bar_status.h b/patch/bar_status.h new file mode 100644 index 0000000..b02a4b8 --- /dev/null +++ b/patch/bar_status.h @@ -0,0 +1,3 @@ +static int width_status(Bar *bar, BarWidthArg *a); +static int draw_status(Bar *bar, BarDrawArg *a); +static int click_status(Bar *bar, Arg *arg, BarClickArg *a); diff --git a/patch/bar_tags.c b/patch/bar_tags.c new file mode 100644 index 0000000..680e1fe --- /dev/null +++ b/patch/bar_tags.c @@ -0,0 +1,55 @@ +int +width_tags(Bar *bar, BarWidthArg *a) +{ + int w, i; + + for (w = 0, i = 0; i < LENGTH(tags); i++) { + w += TEXTW(tags[i]); + } + return w; +} + +int +draw_tags(Bar *bar, BarDrawArg *a) +{ + int invert; + int w, x = a->x; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0; + Client *c; + Monitor *m = bar->mon; + + for (c = m->clients; c; c = c->next) { + occ |= c->tags; + if (c->isurgent) + urg |= c->tags; + } + + for (i = 0; i < LENGTH(tags); i++) { + invert = urg & 1 << i; + w = TEXTW(tags[i]); + drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], invert); + if (occ & 1 << i) + drw_rect(drw, x + boxs, boxs, boxw, boxw, + m == selmon && selmon->sel && selmon->sel->tags & 1 << i, invert); + x += w; + } + + return x; +} + +int +click_tags(Bar *bar, Arg *arg, BarClickArg *a) +{ + int i = 0, x = lrpad / 2; + + do { + x += TEXTW(tags[i]); + } while (a->rel_x >= x && ++i < LENGTH(tags)); + if (i < LENGTH(tags)) { + arg->ui = 1 << i; + } + return ClkTagBar; +} diff --git a/patch/bar_tags.h b/patch/bar_tags.h new file mode 100644 index 0000000..7ac04d8 --- /dev/null +++ b/patch/bar_tags.h @@ -0,0 +1,3 @@ +static int width_tags(Bar *bar, BarWidthArg *a); +static int draw_tags(Bar *bar, BarDrawArg *a); +static int click_tags(Bar *bar, Arg *arg, BarClickArg *a); diff --git a/patch/bar_wintitle.c b/patch/bar_wintitle.c new file mode 100644 index 0000000..3c11b75 --- /dev/null +++ b/patch/bar_wintitle.c @@ -0,0 +1,31 @@ +int +width_wintitle(Bar *bar, BarWidthArg *a) +{ + return a->max_width; +} + +int +draw_wintitle(Bar *bar, BarDrawArg *a) +{ + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + int x = a->x, w = a->w; + Monitor *m = bar->mon; + + if (m->sel) { + drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); + if (m->sel->isfloating) + drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); + } else { + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, x, 0, w, bh, 1, 1); + } + return x + w; +} + +int +click_wintitle(Bar *bar, Arg *arg, BarClickArg *a) +{ + return ClkWinTitle; +} diff --git a/patch/bar_wintitle.h b/patch/bar_wintitle.h new file mode 100644 index 0000000..266404c --- /dev/null +++ b/patch/bar_wintitle.h @@ -0,0 +1,3 @@ +static int width_wintitle(Bar *bar, BarWidthArg *a); +static int draw_wintitle(Bar *bar, BarDrawArg *a); +static int click_wintitle(Bar *bar, Arg *arg, BarClickArg *a); diff --git a/patch/include.c b/patch/include.c new file mode 100644 index 0000000..d422f56 --- /dev/null +++ b/patch/include.c @@ -0,0 +1,5 @@ +/* Bar functionality */ +#include "bar_ltsymbol.c" +#include "bar_status.c" +#include "bar_tags.c" +#include "bar_wintitle.c" \ No newline at end of file diff --git a/patch/include.h b/patch/include.h new file mode 100644 index 0000000..5f9a3fe --- /dev/null +++ b/patch/include.h @@ -0,0 +1,5 @@ +/* Bar functionality */ +#include "bar_ltsymbol.h" +#include "bar_status.h" +#include "bar_tags.h" +#include "bar_wintitle.h" \ No newline at end of file -- 2.19.1 From a44a11168d6823a5b725242dfb5480b5be2f4b91 Mon Sep 17 00:00:00 2001 From: Bakkeby Date: Mon, 10 Jan 2022 14:11:51 +0100 Subject: [PATCH 2/2] Adding systray module --- config.def.h | 3 + dwm.c | 131 ++++++++++++++++++++++++++---- patch/bar_systray.c | 190 ++++++++++++++++++++++++++++++++++++++++++++ patch/bar_systray.h | 40 ++++++++++ patch/include.c | 3 +- patch/include.h | 3 +- 6 files changed, 353 insertions(+), 17 deletions(-) create mode 100644 patch/bar_systray.c create mode 100644 patch/bar_systray.h diff --git a/config.def.h b/config.def.h index f870c41..a22f507 100644 --- a/config.def.h +++ b/config.def.h @@ -5,6 +5,8 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ static const unsigned int snap = 32; /* snap pixel */ static const int showbar = 1; /* 0 means no bar */ static const int topbar = 1; /* 0 means bottom bar */ +static const unsigned int systrayspacing = 2; /* systray spacing */ +static const int showsystray = 1; /* 0 means no systray */ static const char *fonts[] = { "monospace:size=10" }; static const char dmenufont[] = "monospace:size=10"; static const char col_gray1[] = "#222222"; @@ -47,6 +49,7 @@ static const BarRule barrules[] = { /* monitor bar alignment widthfunc drawfunc clickfunc name */ { -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" }, { -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" }, + { 'A', 0, BAR_ALIGN_RIGHT, width_systray, draw_systray, click_systray, "systray" }, { 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" }, { -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" }, }; diff --git a/dwm.c b/dwm.c index 86763d8..6875b06 100644 --- a/dwm.c +++ b/dwm.c @@ -63,6 +63,8 @@ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ enum { SchemeNorm, SchemeSel }; /* color schemes */ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, + NetSystemTrayVisual, NetWMWindowTypeDock, NetSystemTrayOrientationHorz, NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, @@ -247,7 +249,7 @@ static void resizemouse(const Arg *arg); 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); @@ -311,9 +313,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; @@ -556,6 +559,15 @@ cleanup(void) XUngrabKey(dpy, AnyKey, AnyModifier, root); while (mons) cleanupmon(mons); + if (showsystray && systray) { + while (systray->icons) + removesystrayicon(systray->icons); + if (systray->win) { + 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++) @@ -591,9 +603,48 @@ cleanupmon(Monitor *mon) void clientmessage(XEvent *e) { + XWindowAttributes wa; + XSetWindowAttributes swa; XClientMessageEvent *cme = &e->xclient; Client *c = wintoclient(cme->window); + if (showsystray && systray && 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; + XGetWindowAttributes(dpy, c->win, &wa); + 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); + XSync(dpy, False); + setclientstate(c, NormalState); + } + return; + } + if (!c) return; if (cme->message_type == netatom[NetWMState]) { @@ -756,6 +807,10 @@ destroynotify(XEvent *e) if ((c = wintoclient(ev->window))) unmanage(c, 1); + else if (showsystray && (c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + drawbarwin(systray->bar); + } } void @@ -1022,9 +1077,15 @@ getatomprop(Client *c, Atom prop) unsigned char *p = NULL; Atom da, atom = None; - if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, + Atom req = XA_ATOM; + if (prop == xatom[XembedInfo]) + req = xatom[XembedInfo]; + + 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; @@ -1162,7 +1223,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); @@ -1248,9 +1309,15 @@ mappingnotify(XEvent *e) void maprequest(XEvent *e) { + Client *i; static XWindowAttributes wa; XMapRequestEvent *ev = &e->xmaprequest; + if (showsystray && systray && (i = wintosystrayicon(ev->window))) { + sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); + drawbarwin(systray->bar); + } + if (!XGetWindowAttributes(dpy, ev->window, &wa)) return; if (wa.override_redirect) @@ -1374,6 +1441,16 @@ propertynotify(XEvent *e) Window trans; XPropertyEvent *ev = &e->xproperty; + if (showsystray && (c = wintosystrayicon(ev->window))) { + if (ev->atom == XA_WM_NORMAL_HINTS) { + updatesizehints(c); + updatesystrayicongeom(c, c->w, c->h); + } + else + updatesystrayiconstate(c, ev); + drawbarwin(systray->bar); + } + if ((ev->window == root) && (ev->atom == XA_WM_NAME)) updatestatus(); else if (ev->state == PropertyDelete) @@ -1593,26 +1670,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 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; } @@ -1626,7 +1713,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 @@ -1715,6 +1802,15 @@ 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[NetSystemTrayVisual] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_VISUAL", False); + netatom[NetWMWindowTypeDock] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); + xatom[Manager] = XInternAtom(dpy, "MANAGER", False); + xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); + xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", 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); @@ -1959,6 +2055,11 @@ unmapnotify(XEvent *e) setclientstate(c, WithdrawnState); else unmanage(c, 0); + } else if (showsystray && (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); + drawbarwin(systray->bar); } } diff --git a/patch/bar_systray.c b/patch/bar_systray.c new file mode 100644 index 0000000..3ae2e56 --- /dev/null +++ b/patch/bar_systray.c @@ -0,0 +1,190 @@ +static Systray *systray = NULL; +static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ; + +int +width_systray(Bar *bar, BarWidthArg *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, BarDrawArg *a) +{ + if (!showsystray) { + if (systray) + XMoveWindow(dpy, systray->win, -500, bar->by); + return a->x; + } + + XSetWindowAttributes wa; + 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; + #if BAR_ALPHA_PATCH + wa.background_pixel = 0; + wa.colormap = cmap; + systray->win = XCreateWindow(dpy, root, bar->bx + a->x + lrpad / 2, bar->by, MAX(a->w + 40, 1), bar->bh, 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, MIN(a->w, 1), bar->bh, 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 a->x; + } + } + + systray->bar = bar; + + 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 : -bar->by), MAX(w, 1), bar->bh); + return a->x + a->w; +} + +int +click_systray(Bar *bar, Arg *arg, BarClickArg *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 (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; + } + if (i->w > 2*bh) + i->w = bh; + } +} + +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; +} diff --git a/patch/bar_systray.h b/patch/bar_systray.h new file mode 100644 index 0000000..5123a73 --- /dev/null +++ b/patch/bar_systray.h @@ -0,0 +1,40 @@ +#define SYSTEM_TRAY_REQUEST_DOCK 0 +#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 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 { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ + +typedef struct Systray Systray; +struct Systray { + Window win; + Client *icons; + Bar *bar; +}; + +/* bar integration */ +static int width_systray(Bar *bar, BarWidthArg *a); +static int draw_systray(Bar *bar, BarDrawArg *a); +static int click_systray(Bar *bar, Arg *arg, BarClickArg *a); + +/* function declarations */ +static Atom getatomprop(Client *c, Atom prop); +static void removesystrayicon(Client *i); +static void resizerequest(XEvent *e); +static void updatesystrayicongeom(Client *i, int w, int h); +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); +static Client *wintosystrayicon(Window w); + diff --git a/patch/include.c b/patch/include.c index d422f56..c82b392 100644 --- a/patch/include.c +++ b/patch/include.c @@ -2,4 +2,5 @@ #include "bar_ltsymbol.c" #include "bar_status.c" #include "bar_tags.c" -#include "bar_wintitle.c" \ No newline at end of file +#include "bar_wintitle.c" +#include "bar_systray.c" \ No newline at end of file diff --git a/patch/include.h b/patch/include.h index 5f9a3fe..c01916a 100644 --- a/patch/include.h +++ b/patch/include.h @@ -2,4 +2,5 @@ #include "bar_ltsymbol.h" #include "bar_status.h" #include "bar_tags.h" -#include "bar_wintitle.h" \ No newline at end of file +#include "bar_wintitle.h" +#include "bar_systray.h" \ No newline at end of file -- 2.19.1