diff options
author | Joshua Yun <joshua@joshuayun.com> | 2025-03-12 01:28:59 -0500 |
---|---|---|
committer | Joshua Yun <joshua@joshuayun.com> | 2025-03-12 01:28:59 -0500 |
commit | 3dc4dcc4ca0dee958a56f43e8a635a6d961e7ccc (patch) | |
tree | a8c5c08ada9f149d5cd0839b0dfd83d4630aa4eb /dwl.c | |
parent | df6d37936bac129d1fd7098cdd37f0cf44f1d4f5 (diff) | |
download | dwl-3dc4dcc4ca0dee958a56f43e8a635a6d961e7ccc.tar.gz |
Systray patch
Diffstat (limited to 'dwl.c')
-rw-r--r-- | dwl.c | 109 |
1 files changed, 103 insertions, 6 deletions
@@ -1,6 +1,7 @@ /* * See LICENSE file for copyright and license details. */ +#include <dbus/dbus.h> #include <getopt.h> #include <libinput.h> #include <linux/input-event-codes.h> @@ -72,6 +73,9 @@ #include "util.h" #include "drwl.h" +#include "dbus.h" +#include "systray/tray.h" +#include "systray/watcher.h" /* macros */ #define MAX(A, B) ((A) > (B) ? (A) : (B)) @@ -86,9 +90,11 @@ #define TEXTW(mon, text) (drwl_font_getwidth(mon->drw, text) + mon->lrpad) /* enums */ +enum { SchemeNorm, SchemeSel, SchemeUrg }; /* color schemes */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11 }; /* client types */ enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ +enum {ClkTagBar, ClkLtSymbol, ClkStatus, ClkTitle, ClkClient, ClkRoot, ClkTray }; /* clicks */ typedef union { int i; @@ -213,6 +219,7 @@ struct Monitor { int real_width, real_height; /* non-scaled */ float scale; } b; /* bar area */ + Tray *tray; struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface.link */ const Layout *lt[2]; @@ -370,6 +377,9 @@ static void togglefloating(const Arg *arg); static void togglefullscreen(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); +static void trayactivate(const Arg *arg); +static void traymenu(const Arg *arg); +static void traynotify(void *data); static void unlocksession(struct wl_listener *listener, void *data); static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); static void unmapnotify(struct wl_listener *listener, void *data); @@ -472,6 +482,10 @@ static struct wl_listener new_session_lock = {.notify = locksession}; static char stext[256]; static struct wl_event_source *status_event_source; +static DBusConnection *bus_conn; +static struct wl_event_source *bus_source; +static Watcher watcher; + static const struct wlr_buffer_impl buffer_impl = { .destroy = bufdestroy, .begin_data_ptr_access = bufdatabegin, @@ -738,8 +752,8 @@ bufrelease(struct wl_listener *listener, void *data) void buttonpress(struct wl_listener *listener, void *data) { - unsigned int i = 0, x = 0; - double cx; + unsigned int i = 0, x = 0, ti = 0; + double cx, tx = 0; unsigned int click; struct wlr_pointer_button_event *event = data; struct wlr_keyboard *keyboard; @@ -749,6 +763,7 @@ buttonpress(struct wl_listener *listener, void *data) Arg arg = {0}; Client *c; const Button *b; + int traywidth; wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); @@ -767,17 +782,29 @@ buttonpress(struct wl_listener *listener, void *data) if (!c && !exclusive_focus && (node = wlr_scene_node_at(&layers[LyrBottom]->node, cursor->x, cursor->y, NULL, NULL)) && (buffer = wlr_scene_buffer_from_node(node)) && buffer == selmon->scene_buffer) { + cx = (cursor->x - selmon->m.x) * selmon->wlr_output->scale; + traywidth = tray_get_width(selmon->tray); + do x += TEXTW(selmon, tags[i]); while (cx >= x && ++i < LENGTH(tags)); + if (i < LENGTH(tags)) { click = ClkTagBar; arg.ui = 1 << i; } else if (cx < x + TEXTW(selmon, selmon->ltsymbol)) click = ClkLtSymbol; - else if (cx > selmon->b.width - (TEXTW(selmon, stext) - selmon->lrpad + 2)) { + else if (cx > selmon->b.width - (TEXTW(selmon, stext) - selmon->lrpad + 2) && cx < selmon->b.width - traywidth) { click = ClkStatus; + } else if (cx > selmon->b.width - (TEXTW(selmon, stext) - selmon->lrpad + 2)) { + unsigned int tray_n_items = watcher_get_n_items(&watcher); + tx = selmon->b.width - traywidth; + do + tx += tray_n_items ? (int)(traywidth / tray_n_items) : 0; + while (cx >= tx && ++ti < tray_n_items); + click = ClkTray; + arg.ui = ti; } else click = ClkTitle; } @@ -791,7 +818,12 @@ buttonpress(struct wl_listener *listener, void *data) mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; for (b = buttons; b < END(buttons); b++) { if (CLEANMASK(mods) == CLEANMASK(b->mod) && event->button == b->button && click == b->click && b->func) { - b->func(click == ClkTagBar && b->arg.i == 0 ? &arg : &b->arg); + if (click == ClkTagBar && b->arg.i == 0) + b->func(&arg); + else if (click == ClkTray && b->arg.i == 0) + b->func(&arg); + else + b->func(&b->arg); return; } } @@ -858,6 +890,12 @@ cleanup(void) destroykeyboardgroup(&kb_group->destroy, NULL); + if (showbar && showsystray) { + watcher_stop(&watcher); + stopbus(bus_conn, bus_source); + dbus_connection_unref(bus_conn); + } + /* If it's not destroyed manually it will cause a use-after-free of wlr_seat. * Destroy it until it's fixed in the wlroots side */ wlr_backend_destroy(backend); @@ -886,6 +924,9 @@ cleanupmon(struct wl_listener *listener, void *data) for (i = 0; i < LENGTH(m->pool); i++) wlr_buffer_drop(&m->pool[i]->base); + if (showsystray) + destroytray(m->tray); + drwl_setimage(m->drw, NULL); drwl_destroy(m->drw); @@ -1561,6 +1602,7 @@ dirtomon(enum wlr_direction dir) void drawbar(Monitor *m) { + int traywidth = 0; int x, w, tw = 0; int boxs = m->drw->font->height / 9; int boxw = m->drw->font->height / 6 + 2; @@ -1573,11 +1615,13 @@ drawbar(Monitor *m) if (!(buf = bufmon(m))) return; + traywidth = tray_get_width(m->tray); + /* draw status first so it can be overdrawn by tags later */ if (m == selmon) { /* status is only drawn on selected monitor */ drwl_setscheme(m->drw, colors[SchemeNorm]); tw = TEXTW(m, stext) - m->lrpad + 2; /* 2px right padding */ - drwl_text(m->drw, m->b.width - tw, 0, tw, m->b.height, 0, stext, 0); + drwl_text(m->drw, m->b.width - (tw + traywidth), 0, tw, m->b.height, 0, stext, 0); } wl_list_for_each(c, &clients, link) { @@ -1603,7 +1647,7 @@ drawbar(Monitor *m) drwl_setscheme(m->drw, colors[SchemeNorm]); x = drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, m->ltsymbol, 0); - if ((w = m->b.width - tw - x) > m->b.height) { + if ((w = m->b.width - (tw + x + traywidth)) > m->b.height) { if (c) { drwl_setscheme(m->drw, colors[m == selmon ? SchemeSel : SchemeNorm]); drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, client_get_title(c), 0); @@ -1615,6 +1659,15 @@ drawbar(Monitor *m) } } + if (traywidth > 0) { + pixman_image_composite32(PIXMAN_OP_SRC, + m->tray->image, NULL, m->drw->image, + 0, 0, + 0, 0, + m->b.width - traywidth, 0, + traywidth, m->b.height); + } + wlr_scene_buffer_set_dest_size(m->scene_buffer, m->b.real_width, m->b.real_height); wlr_scene_node_set_position(&m->scene_buffer->node, m->m.x, @@ -1624,6 +1677,26 @@ drawbar(Monitor *m) } void +traynotify(void *data) +{ + Monitor *m = data; + + drawbar(m); +} + +void +trayactivate(const Arg *arg) +{ + tray_leftclicked(selmon->tray, arg->ui); +} + +void +traymenu(const Arg *arg) +{ + tray_rightclicked(selmon->tray, arg->ui, dmenucmd); +} + +void drawbars(void) { Monitor *m = NULL; @@ -2831,6 +2904,17 @@ setup(void) status_event_source = wl_event_loop_add_fd(wl_display_get_event_loop(dpy), STDIN_FILENO, WL_EVENT_READABLE, statusin, NULL); + if (showbar && showsystray) { + bus_conn = dbus_bus_get(DBUS_BUS_SESSION, NULL); + if (!bus_conn) + die("Failed to connect to bus"); + bus_source = startbus(bus_conn, event_loop); + if (!bus_source) + die("Failed to start listening to bus events"); + if (watcher_start(&watcher, bus_conn, event_loop) < 0) + die("Failed to start tray watcher"); + } + /* Make sure XWayland clients don't connect to the parent X server, * e.g when running in the x11 backend or the wayland backend and the * compositor has Xwayland support */ @@ -3173,6 +3257,7 @@ updatebar(Monitor *m) size_t i; int rw, rh; char fontattrs[12]; + Tray *tray; wlr_output_transformed_resolution(m->wlr_output, &rw, &rh); m->b.width = rw; @@ -3198,6 +3283,18 @@ updatebar(Monitor *m) m->lrpad = m->drw->font->height; m->b.height = m->drw->font->height + 2; m->b.real_height = (int)((float)m->b.height / m->wlr_output->scale); + + if (showsystray) { + if (m->tray) + destroytray(m->tray); + tray = createtray(m, + m->b.height, systrayspacing, colors[SchemeNorm], fonts, fontattrs, + &traynotify, &watcher); + if (!tray) + die("Couldn't create tray for monitor"); + m->tray = tray; + wl_list_insert(&watcher.trays, &tray->link); + } } void |