mirror of
https://codeberg.org/dwl/dwl-patches.git
synced 2025-09-07 11:44:51 +00:00
Add systray patch
This commit is contained in:
parent
67cf08d27f
commit
acf7519636
31
patches/bar-systray/README.md
Normal file
31
patches/bar-systray/README.md
Normal file
@ -0,0 +1,31 @@
|
||||
### Description
|
||||
Add a system tray next to the [bar](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/bar). Heed the warning, this is far from suckless ^^
|
||||
|
||||

|
||||
|
||||
### Dependencies
|
||||
- GTK4
|
||||
- [bar.patch](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/bar) as mentioned.
|
||||
- [gtk4-layer-shell](https://github.com/wmww/gtk4-layer-shell)
|
||||
- [statusnotifier-systray-gtk4](https://codeberg.org/janetski/statusnotifier-systray-gtk4) built as a static library.
|
||||
|
||||
### Applying the patch
|
||||
The patch applies on top of the bar patch. That needs to be applied first.
|
||||
|
||||
The patch creates subdirectories `lib` and `include`. After patching, but before `make`, install
|
||||
`libstatusnotifier-systray-gtk4.a` and `snsystray.h` from statusnotifier-systray-gtk4 in the
|
||||
directories. One possible way to do that:
|
||||
|
||||
1. Clone [https://codeberg.org/janetski/statusnotifier-systray-gtk4](https://codeberg.org/janetski/statusnotifier-systray-gtk4). Can clone to any location.
|
||||
2. From statusnotifier-systray-gtk4 root:
|
||||
1. `$ meson setup --default-library=static --prefix=/ -Dgir=false -Dvala=false -Ddocs=false build`
|
||||
2. `$ meson compile -C build`
|
||||
3. `$ DESTDIR=$DWLDIR meson install -C build`, where $DWLDIR is the path to dwl root.
|
||||
3. Finally, from dwl root, run `make`.
|
||||
|
||||
### Download
|
||||
- [git branch](https://codeberg.org/janetski/dwl/src/branch/0.7-systray)
|
||||
- [0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/bar-systray/bar-systray-0.7.patch)
|
||||
|
||||
### Authors
|
||||
- [janetski](https://codeberg.org/janetski) ([.vetu](https://discordapp.com/users/355488216469471242) on discord)
|
398
patches/bar-systray/bar-systray-0.7.patch
Normal file
398
patches/bar-systray/bar-systray-0.7.patch
Normal file
@ -0,0 +1,398 @@
|
||||
From 47ccbbe022e0639b5eb5ccedc805a91c19d74033 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Janne=20Vetel=C3=A4inen?= <janne.vetelainen@elisanet.fi>
|
||||
Date: Fri, 9 Aug 2024 16:25:35 +0300
|
||||
Subject: [PATCH 1/1] Add a system tray next to the sewn's bar
|
||||
|
||||
---
|
||||
Makefile | 8 +-
|
||||
config.def.h | 2 +
|
||||
dwl.c | 223 ++++++++++++++++++++++++++++++++++++++++++++-
|
||||
include/.gitignore | 1 +
|
||||
lib/.gitignore | 1 +
|
||||
5 files changed, 226 insertions(+), 9 deletions(-)
|
||||
create mode 100644 include/.gitignore
|
||||
create mode 100644 lib/.gitignore
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index 9bc67db..853b04c 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -7,14 +7,14 @@ include config.mk
|
||||
DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L \
|
||||
-DVERSION=\"$(VERSION)\" $(XWAYLAND)
|
||||
DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement \
|
||||
- -Wno-unused-parameter -Wshadow -Wunused-macros -Werror=strict-prototypes \
|
||||
+ -Wno-unused-parameter -Wshadow -Wunused-macros \
|
||||
-Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types \
|
||||
-Wfloat-conversion
|
||||
|
||||
# CFLAGS / LDFLAGS
|
||||
-PKGS = wlroots-0.18 wayland-server xkbcommon libinput pixman-1 fcft $(XLIBS)
|
||||
-DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
|
||||
-LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` -lm $(LIBS)
|
||||
+PKGS = wlroots-0.18 wayland-server xkbcommon libinput pixman-1 fcft $(XLIBS) gtk4 gtk4-layer-shell-0
|
||||
+DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) -Iinclude
|
||||
+LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` -lm $(LIBS) -Llib -lstatusnotifier-systray-gtk4
|
||||
|
||||
all: dwl
|
||||
dwl: dwl.o util.o
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 5d1dc2b..bb9366f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -11,6 +11,8 @@ static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
static const char *fonts[] = {"monospace:size=10"};
|
||||
static const float rootcolor[] = COLOR(0x000000ff);
|
||||
+static const int trayspacing = 4; /* Spacing between icons in system tray */
|
||||
+static const int traymargins = 4; /* System tray inner margins */
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
|
||||
static uint32_t colors[][3] = {
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 9a6ff48..a8f332a 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -72,9 +72,22 @@
|
||||
#include "util.h"
|
||||
#include "drwl.h"
|
||||
|
||||
+#include <snsystray.h>
|
||||
+#include <gdk/gdk.h>
|
||||
+#include <gio/gio.h>
|
||||
+#include <glib-object.h>
|
||||
+#include <glib.h>
|
||||
+#include <gtk/gtk.h>
|
||||
+#include <gtk4-layer-shell.h>
|
||||
+#include <pthread.h>
|
||||
+
|
||||
/* macros */
|
||||
+#ifndef MAX
|
||||
#define MAX(A, B) ((A) > (B) ? (A) : (B))
|
||||
+#endif /* MAX */
|
||||
+#ifndef MIN
|
||||
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
||||
+#endif /* MIN */
|
||||
#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
|
||||
#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
|
||||
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||
@@ -318,6 +331,15 @@ static void focusstack(const Arg *arg);
|
||||
static Client *focustop(Monitor *m);
|
||||
static void fullscreennotify(struct wl_listener *listener, void *data);
|
||||
static void gpureset(struct wl_listener *listener, void *data);
|
||||
+static void gtkactivate(GtkApplication *app, void *data);
|
||||
+static void gtkclosewindows(void *data, void *udata);
|
||||
+static void gtkhandletogglebarmsg(void *data);
|
||||
+static void gtkhandlewidthnotify(SnSystray *systray, GParamSpec *pspec, void *data);
|
||||
+static void* gtkinit(void *data);
|
||||
+static void gtkspawnstray(Monitor *m, GtkApplication *app);
|
||||
+static void gtkterminate(void *data);
|
||||
+static void gtktoggletray(void *data, void *udata);
|
||||
+static GdkMonitor* gtkwlrtogdkmon(Monitor *wlrmon);
|
||||
static void handlesig(int signo);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void inputdevice(struct wl_listener *listener, void *data);
|
||||
@@ -374,7 +396,7 @@ 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);
|
||||
static void updatemons(struct wl_listener *listener, void *data);
|
||||
-static void updatebar(Monitor *m);
|
||||
+static void updatebar(Monitor *m, int traywidth);
|
||||
static void updatetitle(struct wl_listener *listener, void *data);
|
||||
static void urgent(struct wl_listener *listener, void *data);
|
||||
static void view(const Arg *arg);
|
||||
@@ -388,6 +410,8 @@ static void zoom(const Arg *arg);
|
||||
/* variables */
|
||||
static const char broken[] = "broken";
|
||||
static pid_t child_pid = -1;
|
||||
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
+static pthread_t gtkthread; /* Gtk functions are only allowed to be called from this thread */
|
||||
static int locked;
|
||||
static void *exclusive_focus;
|
||||
static struct wl_display *dpy;
|
||||
@@ -1139,7 +1163,7 @@ createmon(struct wl_listener *listener, void *data)
|
||||
|
||||
m->scene_buffer = wlr_scene_buffer_create(layers[LyrBottom], NULL);
|
||||
m->scene_buffer->point_accepts_input = bar_accepts_input;
|
||||
- updatebar(m);
|
||||
+ updatebar(m, 0);
|
||||
|
||||
wl_list_insert(&mons, &m->link);
|
||||
drawbars();
|
||||
@@ -1469,6 +1493,8 @@ drawbar(Monitor *m)
|
||||
if (!m->scene_buffer->node.enabled)
|
||||
return;
|
||||
|
||||
+ pthread_mutex_lock(&mutex);
|
||||
+
|
||||
stride = drwl_stride(m->b.width);
|
||||
size = stride * m->b.height;
|
||||
|
||||
@@ -1527,6 +1553,8 @@ drawbar(Monitor *m)
|
||||
m->m.y + (topbar ? 0 : m->m.height - m->b.real_height));
|
||||
wlr_scene_buffer_set_buffer(m->scene_buffer, &buf->base);
|
||||
wlr_buffer_drop(&buf->base);
|
||||
+
|
||||
+ pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1671,6 +1699,174 @@ fullscreennotify(struct wl_listener *listener, void *data)
|
||||
setfullscreen(c, client_wants_fullscreen(c));
|
||||
}
|
||||
|
||||
+void
|
||||
+gtkactivate(GtkApplication *app, void *data)
|
||||
+{
|
||||
+ GdkDisplay *display;
|
||||
+ GtkCssProvider *cssp;
|
||||
+ char csss[64];
|
||||
+ Monitor *m;
|
||||
+ uint32_t bgcolor;
|
||||
+
|
||||
+ bgcolor = colors[SchemeNorm][1] >> 8;
|
||||
+ display = gdk_display_get_default();
|
||||
+ cssp = gtk_css_provider_new();
|
||||
+ sprintf(csss, "window{background-color:#%06x;}", bgcolor);
|
||||
+ gtk_css_provider_load_from_string(cssp, csss);
|
||||
+ gtk_style_context_add_provider_for_display(display,
|
||||
+ GTK_STYLE_PROVIDER(cssp),
|
||||
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
+
|
||||
+ wl_list_for_each(m, &mons, link)
|
||||
+ gtkspawnstray(m, app);
|
||||
+
|
||||
+ g_object_unref(cssp);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+gtkclosewindows(void *data, void *udata)
|
||||
+{
|
||||
+ GtkWindow *window = GTK_WINDOW(data);
|
||||
+
|
||||
+ gtk_window_close(window);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+gtkhandletogglebarmsg(void *data)
|
||||
+{
|
||||
+ GtkApplication *app;
|
||||
+ GList *windows;
|
||||
+
|
||||
+ app = GTK_APPLICATION(g_application_get_default());
|
||||
+ windows = gtk_application_get_windows(app);
|
||||
+ g_list_foreach(windows, gtktoggletray, data);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+gtkhandlewidthnotify(SnSystray *systray, GParamSpec *pspec, void *data)
|
||||
+{
|
||||
+ Monitor *m = (Monitor *)data;
|
||||
+ int traywidth;
|
||||
+
|
||||
+ traywidth = sn_systray_get_width(systray);
|
||||
+
|
||||
+ updatebar(m, traywidth);
|
||||
+ drawbar(m);
|
||||
+}
|
||||
+
|
||||
+void*
|
||||
+gtkinit(void *data)
|
||||
+{
|
||||
+ GtkApplication *app = gtk_application_new("org.dwl.systray",
|
||||
+ G_APPLICATION_NON_UNIQUE);
|
||||
+ g_signal_connect(app, "activate", G_CALLBACK(gtkactivate), NULL);
|
||||
+ g_application_run(G_APPLICATION(app), 0, NULL);
|
||||
+
|
||||
+ g_object_unref(app);
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+gtkspawnstray(Monitor *m, GtkApplication *app)
|
||||
+{
|
||||
+ GdkMonitor *gdkmon;
|
||||
+ GtkWindow *window;
|
||||
+ SnSystray *systray;
|
||||
+ const char *conn;
|
||||
+ gboolean anchors[4];
|
||||
+ int iconsize, tray_init_width, tray_height;
|
||||
+
|
||||
+ gdkmon = gtkwlrtogdkmon(m);
|
||||
+ if (gdkmon == NULL)
|
||||
+ die("Failed to get gdkmon");
|
||||
+
|
||||
+ conn = gdk_monitor_get_connector(gdkmon);
|
||||
+ iconsize = m->b.real_height - 2 * traymargins;
|
||||
+ tray_height = m->b.real_height;
|
||||
+ tray_init_width = m->b.real_height;
|
||||
+
|
||||
+ if (topbar) {
|
||||
+ anchors[GTK_LAYER_SHELL_EDGE_LEFT] = false;
|
||||
+ anchors[GTK_LAYER_SHELL_EDGE_RIGHT] = true;
|
||||
+ anchors[GTK_LAYER_SHELL_EDGE_TOP] = true;
|
||||
+ anchors[GTK_LAYER_SHELL_EDGE_BOTTOM] = false;
|
||||
+ } else {
|
||||
+ anchors[GTK_LAYER_SHELL_EDGE_LEFT] = false;
|
||||
+ anchors[GTK_LAYER_SHELL_EDGE_RIGHT] = true;
|
||||
+ anchors[GTK_LAYER_SHELL_EDGE_TOP] = false;
|
||||
+ anchors[GTK_LAYER_SHELL_EDGE_BOTTOM] = true;
|
||||
+ }
|
||||
+
|
||||
+ systray = sn_systray_new(iconsize,
|
||||
+ traymargins,
|
||||
+ trayspacing,
|
||||
+ conn);
|
||||
+ window = GTK_WINDOW(gtk_window_new());
|
||||
+
|
||||
+ gtk_window_set_default_size(window, tray_init_width, tray_height);
|
||||
+ gtk_window_set_child(window, GTK_WIDGET(systray));
|
||||
+ gtk_window_set_application(window, app);
|
||||
+ gtk_layer_init_for_window(window);
|
||||
+ gtk_layer_set_layer(window, GTK_LAYER_SHELL_LAYER_BOTTOM);
|
||||
+ gtk_layer_set_exclusive_zone(window, -1);
|
||||
+ gtk_layer_set_monitor(window, gdkmon);
|
||||
+
|
||||
+ for (int j = 0; j < GTK_LAYER_SHELL_EDGE_ENTRY_NUMBER; j++) {
|
||||
+ gtk_layer_set_anchor(window, j, anchors[j]);
|
||||
+ }
|
||||
+
|
||||
+ updatebar(m, tray_init_width);
|
||||
+ g_signal_connect(systray, "notify::curwidth", G_CALLBACK(gtkhandlewidthnotify), m);
|
||||
+ gtk_window_present(window);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+gtkterminate(void *data)
|
||||
+{
|
||||
+ GtkApplication *app;
|
||||
+ GList *windows;
|
||||
+
|
||||
+ app = GTK_APPLICATION(g_application_get_default());
|
||||
+ windows = gtk_application_get_windows(app);
|
||||
+ g_list_foreach(windows, gtkclosewindows, NULL);
|
||||
+}
|
||||
+
|
||||
+GdkMonitor*
|
||||
+gtkwlrtogdkmon(Monitor *wlrmon)
|
||||
+{
|
||||
+ GdkMonitor *gdkmon = NULL;
|
||||
+
|
||||
+ GListModel *gdkmons;
|
||||
+ GdkDisplay *display;
|
||||
+ const char *gdkname;
|
||||
+ const char *wlrname;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ wlrname = wlrmon->wlr_output->name;
|
||||
+ display = gdk_display_get_default();
|
||||
+ gdkmons = gdk_display_get_monitors(display);
|
||||
+
|
||||
+ for (i = 0; i < g_list_model_get_n_items(gdkmons); i++) {
|
||||
+ GdkMonitor *mon = g_list_model_get_item(gdkmons, i);
|
||||
+ gdkname = gdk_monitor_get_connector(mon);
|
||||
+ if (strcmp(wlrname, gdkname) == 0)
|
||||
+ gdkmon = mon;
|
||||
+ }
|
||||
+
|
||||
+ return gdkmon;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+gtktoggletray(void *data, void *udata)
|
||||
+{
|
||||
+ GtkWidget *widget = GTK_WIDGET(data);
|
||||
+ int *pbarvisible = (int *)udata;
|
||||
+ int barvisible = GPOINTER_TO_INT(pbarvisible);
|
||||
+
|
||||
+ gtk_widget_set_visible(widget, barvisible);
|
||||
+}
|
||||
+
|
||||
void
|
||||
gpureset(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -2254,6 +2450,8 @@ powermgrsetmode(struct wl_listener *listener, void *data)
|
||||
void
|
||||
quit(const Arg *arg)
|
||||
{
|
||||
+ g_idle_add_once(gtkterminate, NULL);
|
||||
+ pthread_join(gtkthread, NULL);
|
||||
wl_display_terminate(dpy);
|
||||
}
|
||||
|
||||
@@ -2797,6 +2995,9 @@ setup(void)
|
||||
fprintf(stderr, "failed to setup XWayland X server, continuing without it\n");
|
||||
}
|
||||
#endif
|
||||
+
|
||||
+ // Gtk functions are only allowed to be called from this thread.
|
||||
+ pthread_create(>kthread, NULL, >kinit, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2904,9 +3105,21 @@ tile(Monitor *m)
|
||||
void
|
||||
togglebar(const Arg *arg)
|
||||
{
|
||||
+ int barvisible;
|
||||
+ int *pbarvisible;
|
||||
+
|
||||
wlr_scene_node_set_enabled(&selmon->scene_buffer->node,
|
||||
!selmon->scene_buffer->node.enabled);
|
||||
arrangelayers(selmon);
|
||||
+
|
||||
+ // Notify gtkthread
|
||||
+ if (selmon->scene_buffer->node.enabled)
|
||||
+ barvisible = 1;
|
||||
+ else
|
||||
+ barvisible = 0;
|
||||
+
|
||||
+ pbarvisible = GINT_TO_POINTER(barvisible);
|
||||
+ g_idle_add_once(gtkhandletogglebarmsg, pbarvisible);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -3101,7 +3314,7 @@ updatemons(struct wl_listener *listener, void *data)
|
||||
if (stext[0] == '\0')
|
||||
strncpy(stext, "dwl-"VERSION, sizeof(stext));
|
||||
wl_list_for_each(m, &mons, link) {
|
||||
- updatebar(m);
|
||||
+ updatebar(m, 0);
|
||||
drawbar(m);
|
||||
}
|
||||
|
||||
@@ -3116,14 +3329,14 @@ updatemons(struct wl_listener *listener, void *data)
|
||||
}
|
||||
|
||||
void
|
||||
-updatebar(Monitor *m)
|
||||
+updatebar(Monitor *m, int traywidth)
|
||||
{
|
||||
int rw, rh;
|
||||
char fontattrs[12];
|
||||
|
||||
wlr_output_transformed_resolution(m->wlr_output, &rw, &rh);
|
||||
m->b.width = rw;
|
||||
- m->b.real_width = (int)((float)m->b.width / m->wlr_output->scale);
|
||||
+ m->b.real_width = (int)((float)m->b.width / m->wlr_output->scale) - traywidth;
|
||||
|
||||
wlr_scene_node_set_enabled(&m->scene_buffer->node, m->wlr_output->enabled ? showbar : 0);
|
||||
|
||||
diff --git a/include/.gitignore b/include/.gitignore
|
||||
new file mode 100644
|
||||
index 0000000..424c745
|
||||
--- /dev/null
|
||||
+++ b/include/.gitignore
|
||||
@@ -0,0 +1 @@
|
||||
+*.h
|
||||
diff --git a/lib/.gitignore b/lib/.gitignore
|
||||
new file mode 100644
|
||||
index 0000000..10301e2
|
||||
--- /dev/null
|
||||
+++ b/lib/.gitignore
|
||||
@@ -0,0 +1 @@
|
||||
+*.a
|
||||
--
|
||||
2.46.0
|
||||
|
BIN
patches/bar-systray/systray.png
Normal file
BIN
patches/bar-systray/systray.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
Loading…
x
Reference in New Issue
Block a user