mirror of
https://codeberg.org/dwl/dwl-patches.git
synced 2025-09-10 13:14:57 +00:00
add hot-reload patch
This commit is contained in:
parent
a727409aca
commit
d7a456e879
36
patches/hot-reload/README.md
Normal file
36
patches/hot-reload/README.md
Normal file
@ -0,0 +1,36 @@
|
||||
### Description
|
||||
Enables hot-reloading of dwl; meaning almost all logic can be changed at runtime.
|
||||
This obviously requires some black magic so for now there's a glibc 2.0 or later
|
||||
dependency to this.
|
||||
In particular this allows for every option in config.h to be changed at runtime.
|
||||
|
||||
#### Reloading
|
||||
To reload rebuild dwl.so, perhaps reinstall it and then run trigger reload function (bound to Mod+Shift+R by default).
|
||||
This currently calls `notify-send` in order to inform you of a reloading taking place.
|
||||
So in short:
|
||||
1. make changes to `config.h` or `dwl.c`
|
||||
2. run `make` to rebuild dwl.so
|
||||
3. run `sudo make install` to reinstall dwl
|
||||
|
||||
|
||||
#### Limitations
|
||||
Reloading the compositor will replace all functionality except for `main`, `setup`, `run` and the reload logic.
|
||||
Note that you're responsible yourself for reloading ressources like fonts, which may only get acquired once.
|
||||
A lot of components of dwl will also only get run on a trigger (the tiling for example).
|
||||
So not every change will be immediate.
|
||||
|
||||
#### Note
|
||||
This patches triggers `-Wpedantic` a bunch (there's no way around this, `dlsym` yields `void*` pointers to functions).
|
||||
This will show a lot of warnings but cause no errors.
|
||||
So you may want to disable this compile option in order to get readable compiler output.
|
||||
|
||||
#### How?
|
||||
Most of all dwl functionality is moved into a shared object file `dwl.so`, which can be reloaded at runtime.
|
||||
|
||||
### Download
|
||||
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/hot-reload/hot-reload-0.7.patch)
|
||||
- [main 2025-02-14](/dwl/dwl-patches/raw/branch/main/patches/hot-reload/hot-reload.patch)
|
||||
- find the repo for the patch [here](/Sivecano/dwl/src/branch/hot-reload)
|
||||
### Authors
|
||||
- [Sivecano](https://codeberg.org/Sivecano)
|
||||
- Sérécano at [dwl Discord](https://discord.gg/jJxZnrGPWN)
|
762
patches/hot-reload/hot-reload-0.7.patch
Normal file
762
patches/hot-reload/hot-reload-0.7.patch
Normal file
@ -0,0 +1,762 @@
|
||||
From 4b20c81709895564fa623e8752d6cf8e9ec0f98e Mon Sep 17 00:00:00 2001
|
||||
From: Sivecano <sivecano@gmail.com>
|
||||
Date: Sun, 26 Jan 2025 18:30:02 +0100
|
||||
Subject: [PATCH] redo hot-reloading in one file
|
||||
|
||||
---
|
||||
Makefile | 18 ++-
|
||||
config.def.h | 5 +-
|
||||
dwl.c | 335 ++++++++++++++++++++++++++++++++++++++++++++-------
|
||||
util.c | 34 ++++++
|
||||
util.h | 6 +
|
||||
5 files changed, 349 insertions(+), 49 deletions(-)
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index 3358bae..9cf200f 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -13,13 +13,16 @@ DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement \
|
||||
|
||||
# CFLAGS / LDFLAGS
|
||||
PKGS = wlroots-0.18 wayland-server xkbcommon libinput $(XLIBS)
|
||||
-DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
|
||||
+DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) -fPIC -rdynamic
|
||||
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` -lm $(LIBS)
|
||||
|
||||
-all: dwl
|
||||
+all: dwl dwl.so
|
||||
dwl: dwl.o util.o
|
||||
$(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
|
||||
-dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
|
||||
+dwl.o: dwl.c cursor-shape-v1-protocol.h \
|
||||
+ pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
|
||||
+ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
|
||||
+dwl.so: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
|
||||
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
|
||||
wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
|
||||
util.o: util.c util.h
|
||||
@@ -49,7 +52,7 @@ xdg-shell-protocol.h:
|
||||
config.h:
|
||||
cp config.def.h $@
|
||||
clean:
|
||||
- rm -f dwl *.o *-protocol.h
|
||||
+ rm -f dwl *.o *-protocol.h *.so
|
||||
|
||||
dist: clean
|
||||
mkdir -p dwl-$(VERSION)
|
||||
@@ -63,6 +66,9 @@ install: dwl
|
||||
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||
cp -f dwl $(DESTDIR)$(PREFIX)/bin
|
||||
chmod 755 $(DESTDIR)$(PREFIX)/bin/dwl
|
||||
+ mkdir -p $(DESTDIR)$(PREFIX)/lib
|
||||
+ cp -f dwl.so $(DESTDIR)$(PREFIX)/lib
|
||||
+ chmod 744 $(DESTDIR)$(PREFIX)/lib/dwl.so
|
||||
mkdir -p $(DESTDIR)$(MANDIR)/man1
|
||||
cp -f dwl.1 $(DESTDIR)$(MANDIR)/man1
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man1/dwl.1
|
||||
@@ -76,3 +82,7 @@ uninstall:
|
||||
.SUFFIXES: .c .o
|
||||
.c.o:
|
||||
$(CC) $(CPPFLAGS) $(DWLCFLAGS) -o $@ -c $<
|
||||
+
|
||||
+.SUFFIXES: .c .so
|
||||
+.c.so:
|
||||
+ $(CC) $(CPPFLAGS) $(DWLCFLAGS) -o $@ -shared -DHOT $<
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..6e3dda1 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -7,7 +7,7 @@
|
||||
static const int sloppyfocus = 1; /* focus follows mouse */
|
||||
static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */
|
||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
-static const float rootcolor[] = COLOR(0x222222ff);
|
||||
+const float rootcolor[] = COLOR(0x222222ff);
|
||||
static const float bordercolor[] = COLOR(0x444444ff);
|
||||
static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
@@ -18,7 +18,7 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca
|
||||
#define TAGCOUNT (9)
|
||||
|
||||
/* logging */
|
||||
-static int log_level = WLR_ERROR;
|
||||
+int log_level = WLR_ERROR;
|
||||
|
||||
/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */
|
||||
static const Rule rules[] = {
|
||||
@@ -127,6 +127,7 @@ static const Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_R, reload, {0} },
|
||||
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
|
||||
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
|
||||
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index def2562..6a428c5 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1,6 +1,15 @@
|
||||
/*
|
||||
* See LICENSE file for copyright and license details.
|
||||
*/
|
||||
+
|
||||
+/* stuff for hot-reload */
|
||||
+#define _GNU_SOURCE
|
||||
+#include <dlfcn.h>
|
||||
+#include <limits.h>
|
||||
+#include <unistd.h>
|
||||
+#include <libgen.h>
|
||||
+#include <errno.h>
|
||||
+
|
||||
#include <getopt.h>
|
||||
#include <libinput.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
@@ -67,6 +76,7 @@
|
||||
#include <xcb/xcb_icccm.h>
|
||||
#endif
|
||||
|
||||
+
|
||||
#include "util.h"
|
||||
|
||||
/* macros */
|
||||
@@ -77,8 +87,34 @@
|
||||
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||
#define END(A) ((A) + LENGTH(A))
|
||||
#define TAGMASK ((1u << TAGCOUNT) - 1)
|
||||
-#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L)))
|
||||
-#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0)
|
||||
+
|
||||
+#define SYM(a) dlsym(dwl_module, #a)
|
||||
+#define TSYM(T, a) ((T)SYM(a))
|
||||
+#define CSYM(T, a) *(TSYM(T*, a))
|
||||
+
|
||||
+#define LISTEN(E, L, H) do { \
|
||||
+ (L)->notify = SYM(H); \
|
||||
+ listeners = append_listener((L), listeners); \
|
||||
+ wl_signal_add((E), (L)); \
|
||||
+ } while(0)
|
||||
+
|
||||
+#define LISTEN_GLOBAL(E, L) do { \
|
||||
+ struct wl_listener* l = SYM(L); \
|
||||
+ listeners = append_listener(l, listeners); \
|
||||
+ wl_signal_add((E), l); \
|
||||
+ } while (0)
|
||||
+
|
||||
+#define LISTEN_STATIC(E, H) do { \
|
||||
+ struct wl_listener* _l = malloc(sizeof(struct wl_listener)); \
|
||||
+ _l->notify = SYM(H); \
|
||||
+ listeners = append_listener(_l, listeners); \
|
||||
+ wl_signal_add((E), _l); \
|
||||
+ } while (0)
|
||||
+
|
||||
+#define UNLISTEN(L) do { \
|
||||
+ wl_list_remove(&(L)->link); \
|
||||
+ listeners = remove_listener((L), listeners);\
|
||||
+ } while (0)
|
||||
|
||||
/* enums */
|
||||
enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
|
||||
@@ -242,6 +278,9 @@ typedef struct {
|
||||
struct wl_listener destroy;
|
||||
} SessionLock;
|
||||
|
||||
+#define static
|
||||
+
|
||||
+#ifdef HOT
|
||||
/* function declarations */
|
||||
static void applybounds(Client *c, struct wlr_box *bbox);
|
||||
static void applyrules(Client *c);
|
||||
@@ -253,7 +292,18 @@ static void axisnotify(struct wl_listener *listener, void *data);
|
||||
static void buttonpress(struct wl_listener *listener, void *data);
|
||||
static void chvt(const Arg *arg);
|
||||
static void checkidleinhibitor(struct wlr_surface *exclude);
|
||||
+
|
||||
+#undef static
|
||||
+#define static extern
|
||||
+#endif
|
||||
+
|
||||
+/* this is cold */
|
||||
static void cleanup(void);
|
||||
+
|
||||
+#undef static
|
||||
+#define static
|
||||
+#ifdef HOT
|
||||
+
|
||||
static void cleanupmon(struct wl_listener *listener, void *data);
|
||||
static void closemon(Monitor *m);
|
||||
static void commitlayersurfacenotify(struct wl_listener *listener, void *data);
|
||||
@@ -321,7 +371,18 @@ static void requestdecorationmode(struct wl_listener *listener, void *data);
|
||||
static void requeststartdrag(struct wl_listener *listener, void *data);
|
||||
static void requestmonstate(struct wl_listener *listener, void *data);
|
||||
static void resize(Client *c, struct wlr_box geo, int interact);
|
||||
+
|
||||
+#undef static
|
||||
+#define static extern
|
||||
+#endif
|
||||
+
|
||||
+/* this is cold */
|
||||
static void run(char *startup_cmd);
|
||||
+
|
||||
+#ifdef HOT
|
||||
+#undef static
|
||||
+#define static
|
||||
+
|
||||
static void setcursor(struct wl_listener *listener, void *data);
|
||||
static void setcursorshape(struct wl_listener *listener, void *data);
|
||||
static void setfloating(Client *c, int floating);
|
||||
@@ -332,7 +393,18 @@ static void setmfact(const Arg *arg);
|
||||
static void setmon(Client *c, Monitor *m, uint32_t newtags);
|
||||
static void setpsel(struct wl_listener *listener, void *data);
|
||||
static void setsel(struct wl_listener *listener, void *data);
|
||||
+
|
||||
+#undef static
|
||||
+#define static extern
|
||||
+#endif
|
||||
+
|
||||
+/* this is cold */
|
||||
static void setup(void);
|
||||
+
|
||||
+#ifdef HOT
|
||||
+#undef static
|
||||
+#define static
|
||||
+
|
||||
static void spawn(const Arg *arg);
|
||||
static void startdrag(struct wl_listener *listener, void *data);
|
||||
static void tag(const Arg *arg);
|
||||
@@ -356,6 +428,16 @@ static void xytonode(double x, double y, struct wlr_surface **psurface,
|
||||
Client **pc, LayerSurface **pl, double *nx, double *ny);
|
||||
static void zoom(const Arg *arg);
|
||||
|
||||
+#endif
|
||||
+
|
||||
+#ifdef HOT
|
||||
+ #undef static
|
||||
+ #define static extern
|
||||
+#else
|
||||
+ #undef static
|
||||
+ #define static
|
||||
+#endif
|
||||
+
|
||||
/* variables */
|
||||
static const char broken[] = "broken";
|
||||
static pid_t child_pid = -1;
|
||||
@@ -400,7 +482,9 @@ static struct wlr_scene_rect *root_bg;
|
||||
static struct wlr_session_lock_manager_v1 *session_lock_mgr;
|
||||
static struct wlr_scene_rect *locked_bg;
|
||||
static struct wlr_session_lock_v1 *cur_lock;
|
||||
+#ifdef HOT
|
||||
static struct wl_listener lock_listener = {.notify = locksession};
|
||||
+#endif
|
||||
|
||||
static struct wlr_seat *seat;
|
||||
static KeyboardGroup *kb_group;
|
||||
@@ -426,6 +510,33 @@ static struct wlr_xwayland *xwayland;
|
||||
static xcb_atom_t netatom[NetLast];
|
||||
#endif
|
||||
|
||||
+/* undoes the shadowing of static from above */
|
||||
+#undef static
|
||||
+
|
||||
+/* this is where we put global hot-reload state */
|
||||
+#ifdef HOT
|
||||
+#define COLD extern
|
||||
+#else
|
||||
+#define COLD
|
||||
+
|
||||
+static void* load(void);
|
||||
+static const char* get_module_path(void);
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
+COLD void * dwl_module = NULL;
|
||||
+COLD void * last_module = NULL;
|
||||
+COLD struct listens* listeners = NULL;
|
||||
+COLD void reload(const Arg* arg);
|
||||
+
|
||||
+#ifndef HOT
|
||||
+static char* runpath;
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
+#ifdef HOT
|
||||
+
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
|
||||
@@ -673,6 +784,8 @@ checkidleinhibitor(struct wlr_surface *exclude)
|
||||
wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited);
|
||||
}
|
||||
|
||||
+#endif
|
||||
+
|
||||
void
|
||||
cleanup(void)
|
||||
{
|
||||
@@ -687,7 +800,7 @@ cleanup(void)
|
||||
}
|
||||
wlr_xcursor_manager_destroy(cursor_mgr);
|
||||
|
||||
- destroykeyboardgroup(&kb_group->destroy, NULL);
|
||||
+ TSYM(void (*)(struct wl_listener*, void*), destroykeyboardgroup)(&kb_group->destroy, NULL);
|
||||
|
||||
/* 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 */
|
||||
@@ -699,6 +812,8 @@ cleanup(void)
|
||||
wlr_scene_node_destroy(&scene->tree.node);
|
||||
}
|
||||
|
||||
+#ifdef HOT
|
||||
+
|
||||
void
|
||||
cleanupmon(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -712,10 +827,10 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||
wlr_layer_surface_v1_destroy(l->layer_surface);
|
||||
}
|
||||
|
||||
- wl_list_remove(&m->destroy.link);
|
||||
- wl_list_remove(&m->frame.link);
|
||||
+ UNLISTEN(&m->destroy);
|
||||
+ UNLISTEN(&m->frame);
|
||||
wl_list_remove(&m->link);
|
||||
- wl_list_remove(&m->request_state.link);
|
||||
+ UNLISTEN(&m->request_state);
|
||||
m->wlr_output->data = NULL;
|
||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
||||
wlr_scene_output_destroy(m->scene_output);
|
||||
@@ -848,7 +963,7 @@ commitpopup(struct wl_listener *listener, void *data)
|
||||
box.x -= (type == LayerShell ? l->geom.x : c->geom.x);
|
||||
box.y -= (type == LayerShell ? l->geom.y : c->geom.y);
|
||||
wlr_xdg_popup_unconstrain_from_box(popup, &box);
|
||||
- wl_list_remove(&listener->link);
|
||||
+ UNLISTEN(listener);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1179,8 +1294,8 @@ destroydecoration(struct wl_listener *listener, void *data)
|
||||
Client *c = wl_container_of(listener, c, destroy_decoration);
|
||||
c->decoration = NULL;
|
||||
|
||||
- wl_list_remove(&c->destroy_decoration.link);
|
||||
- wl_list_remove(&c->set_decoration_mode.link);
|
||||
+ UNLISTEN(&c->destroy_decoration);
|
||||
+ UNLISTEN(&c->set_decoration_mode);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1205,9 +1320,9 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data)
|
||||
LayerSurface *l = wl_container_of(listener, l, destroy);
|
||||
|
||||
wl_list_remove(&l->link);
|
||||
- wl_list_remove(&l->destroy.link);
|
||||
- wl_list_remove(&l->unmap.link);
|
||||
- wl_list_remove(&l->surface_commit.link);
|
||||
+ UNLISTEN(&l->destroy);
|
||||
+ UNLISTEN(&l->unmap);
|
||||
+ UNLISTEN(&l->surface_commit);
|
||||
wlr_scene_node_destroy(&l->scene->node);
|
||||
wlr_scene_node_destroy(&l->popups->node);
|
||||
free(l);
|
||||
@@ -1226,9 +1341,9 @@ destroylock(SessionLock *lock, int unlock)
|
||||
motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
|
||||
destroy:
|
||||
- wl_list_remove(&lock->new_surface.link);
|
||||
- wl_list_remove(&lock->unlock.link);
|
||||
- wl_list_remove(&lock->destroy.link);
|
||||
+ UNLISTEN(&lock->new_surface);
|
||||
+ UNLISTEN(&lock->unlock);
|
||||
+ UNLISTEN(&lock->destroy);
|
||||
|
||||
wlr_scene_node_destroy(&lock->scene->node);
|
||||
cur_lock = NULL;
|
||||
@@ -1242,7 +1357,7 @@ destroylocksurface(struct wl_listener *listener, void *data)
|
||||
struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface;
|
||||
|
||||
m->lock_surface = NULL;
|
||||
- wl_list_remove(&m->destroy_lock_surface.link);
|
||||
+ UNLISTEN(&m->destroy_lock_surface);
|
||||
|
||||
if (lock_surface->surface != seat->keyboard_state.focused_surface)
|
||||
return;
|
||||
@@ -1262,22 +1377,22 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* Called when the xdg_toplevel is destroyed. */
|
||||
Client *c = wl_container_of(listener, c, destroy);
|
||||
- wl_list_remove(&c->destroy.link);
|
||||
- wl_list_remove(&c->set_title.link);
|
||||
- wl_list_remove(&c->fullscreen.link);
|
||||
+ UNLISTEN(&c->destroy);
|
||||
+ UNLISTEN(&c->set_title);
|
||||
+ UNLISTEN(&c->fullscreen);
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
- wl_list_remove(&c->activate.link);
|
||||
- wl_list_remove(&c->associate.link);
|
||||
- wl_list_remove(&c->configure.link);
|
||||
- wl_list_remove(&c->dissociate.link);
|
||||
- wl_list_remove(&c->set_hints.link);
|
||||
+ UNLISTEN(&c->activate);
|
||||
+ UNLISTEN(&c->associate);
|
||||
+ UNLISTEN(&c->configure);
|
||||
+ UNLISTEN(&c->dissociate);
|
||||
+ UNLISTEN(&c->set_hints);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
- wl_list_remove(&c->commit.link);
|
||||
- wl_list_remove(&c->map.link);
|
||||
- wl_list_remove(&c->unmap.link);
|
||||
+ UNLISTEN(&c->commit);
|
||||
+ UNLISTEN(&c->map);
|
||||
+ UNLISTEN(&c->unmap);
|
||||
}
|
||||
free(c);
|
||||
}
|
||||
@@ -1292,7 +1407,7 @@ destroypointerconstraint(struct wl_listener *listener, void *data)
|
||||
active_constraint = NULL;
|
||||
}
|
||||
|
||||
- wl_list_remove(&pointer_constraint->destroy.link);
|
||||
+ UNLISTEN(&pointer_constraint->destroy);
|
||||
free(pointer_constraint);
|
||||
}
|
||||
|
||||
@@ -1306,8 +1421,8 @@ destroysessionlock(struct wl_listener *listener, void *data)
|
||||
void
|
||||
destroysessionmgr(struct wl_listener *listener, void *data)
|
||||
{
|
||||
- wl_list_remove(&lock_listener.link);
|
||||
- wl_list_remove(&listener->link);
|
||||
+ UNLISTEN(&lock_listener);
|
||||
+ UNLISTEN(listener);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1315,10 +1430,10 @@ destroykeyboardgroup(struct wl_listener *listener, void *data)
|
||||
{
|
||||
KeyboardGroup *group = wl_container_of(listener, group, destroy);
|
||||
wl_event_source_remove(group->key_repeat_source);
|
||||
+ UNLISTEN(&group->key);
|
||||
+ UNLISTEN(&group->modifiers);
|
||||
+ UNLISTEN(&group->destroy);
|
||||
wlr_keyboard_group_destroy(group->wlr_group);
|
||||
- wl_list_remove(&group->key.link);
|
||||
- wl_list_remove(&group->modifiers.link);
|
||||
- wl_list_remove(&group->destroy.link);
|
||||
free(group);
|
||||
}
|
||||
|
||||
@@ -2212,6 +2327,8 @@ resize(Client *c, struct wlr_box geo, int interact)
|
||||
wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
|
||||
}
|
||||
|
||||
+#else /*HOT*/
|
||||
+
|
||||
void
|
||||
run(char *startup_cmd)
|
||||
{
|
||||
@@ -2251,11 +2368,11 @@ run(char *startup_cmd)
|
||||
if (fd_set_nonblock(STDOUT_FILENO) < 0)
|
||||
close(STDOUT_FILENO);
|
||||
|
||||
- printstatus();
|
||||
+ TSYM(void (*)(void), printstatus)();
|
||||
|
||||
/* At this point the outputs are initialized, choose initial selmon based on
|
||||
* cursor position, and set default cursor image */
|
||||
- selmon = xytomon(cursor->x, cursor->y);
|
||||
+ selmon = TSYM(Monitor* (*)(double x, double y), xytomon)(cursor->x, cursor->y);
|
||||
|
||||
/* TODO hack to get cursor to display in its initial location (100, 100)
|
||||
* instead of (0, 0) and then jumping. still may not be fully
|
||||
@@ -2271,6 +2388,9 @@ run(char *startup_cmd)
|
||||
wl_display_run(dpy);
|
||||
}
|
||||
|
||||
+#endif
|
||||
+#ifdef HOT
|
||||
+
|
||||
void
|
||||
setcursor(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -2428,17 +2548,19 @@ setsel(struct wl_listener *listener, void *data)
|
||||
wlr_seat_set_selection(seat, event->source, event->serial);
|
||||
}
|
||||
|
||||
+#else /*HOT*/
|
||||
+
|
||||
void
|
||||
setup(void)
|
||||
{
|
||||
int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
|
||||
- struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
|
||||
+ struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = SYM(handlesig)};
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
for (i = 0; i < (int)LENGTH(sig); i++)
|
||||
sigaction(sig[i], &sa, NULL);
|
||||
|
||||
- wlr_log_init(log_level, NULL);
|
||||
+ wlr_log_init(CSYM(enum wlr_log_importance, log_level), NULL);
|
||||
|
||||
/* The Wayland display is managed by libwayland. It handles accepting
|
||||
* clients from the Unix socket, manging Wayland globals, and so on. */
|
||||
@@ -2454,7 +2576,7 @@ setup(void)
|
||||
|
||||
/* Initialize the scene graph used to lay out windows */
|
||||
scene = wlr_scene_create();
|
||||
- root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, rootcolor);
|
||||
+ root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, TSYM(float*, rootcolor));
|
||||
for (i = 0; i < NUM_LAYERS; i++)
|
||||
layers[i] = wlr_scene_tree_create(&scene->tree);
|
||||
drag_icon = wlr_scene_tree_create(&scene->tree);
|
||||
@@ -2550,7 +2672,7 @@ setup(void)
|
||||
LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor);
|
||||
|
||||
session_lock_mgr = wlr_session_lock_manager_v1_create(dpy);
|
||||
- wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener);
|
||||
+ LISTEN_GLOBAL(&session_lock_mgr->events.new_lock, lock_listener);
|
||||
LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr);
|
||||
locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height,
|
||||
(float [4]){0.1f, 0.1f, 0.1f, 1.0f});
|
||||
@@ -2620,7 +2742,7 @@ setup(void)
|
||||
LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag);
|
||||
LISTEN_STATIC(&seat->events.start_drag, startdrag);
|
||||
|
||||
- kb_group = createkeyboardgroup();
|
||||
+ kb_group = TSYM(KeyboardGroup *(*)(void), createkeyboardgroup)();
|
||||
wl_list_init(&kb_group->destroy.link);
|
||||
|
||||
output_mgr = wlr_output_manager_v1_create(dpy);
|
||||
@@ -2647,6 +2769,9 @@ setup(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
+#endif
|
||||
+#ifdef HOT
|
||||
+
|
||||
void
|
||||
spawn(const Arg *arg)
|
||||
{
|
||||
@@ -3121,8 +3246,8 @@ void
|
||||
dissociatex11(struct wl_listener *listener, void *data)
|
||||
{
|
||||
Client *c = wl_container_of(listener, c, dissociate);
|
||||
- wl_list_remove(&c->map.link);
|
||||
- wl_list_remove(&c->unmap.link);
|
||||
+ UNLISTEN(&c->map);
|
||||
+ UNLISTEN(&c->unmap);
|
||||
}
|
||||
|
||||
xcb_atom_t
|
||||
@@ -3185,17 +3310,139 @@ xwaylandready(struct wl_listener *listener, void *data)
|
||||
}
|
||||
#endif
|
||||
|
||||
+#else /* HOT */
|
||||
+void*
|
||||
+load(void)
|
||||
+{
|
||||
+ const char* path = get_module_path();
|
||||
+ char load[PATH_MAX] = "/tmp/dwl.soXXXXXX";
|
||||
+ void* new;
|
||||
+
|
||||
+ if (!path) {
|
||||
+ fprintf(stderr, "cannot find dwl.so\n");
|
||||
+ }
|
||||
+
|
||||
+ do {
|
||||
+ mktemp(load);
|
||||
+ errno = 0;
|
||||
+ symlink(path, load);
|
||||
+ } while(errno == EEXIST);
|
||||
+
|
||||
+ new = dlopen(load, RTLD_NOW|RTLD_LOCAL);
|
||||
+
|
||||
+ unlink(load);
|
||||
+ if (new == NULL)
|
||||
+ fprintf(stderr, "error while loading %s: %s\n", path, dlerror());
|
||||
+ else
|
||||
+ printf("loaded: %s\n", path);
|
||||
+
|
||||
+ return new;
|
||||
+}
|
||||
+
|
||||
+const char *
|
||||
+get_module_path(void) {
|
||||
+ char home[PATH_MAX];
|
||||
+ strcpy(home, getenv("HOME"));
|
||||
+ strcat(home, "/.local/lib");
|
||||
+ const char* abspaths[] = {".", home, "/usr/share/lib", "/usr/local/lib", "/usr/local/share/lib"};
|
||||
+ const char* relpaths[] = {"", "/../lib"};
|
||||
+ char paths[LENGTH(abspaths) + LENGTH(relpaths)][PATH_MAX];
|
||||
+ static char out[PATH_MAX] = "./";
|
||||
+
|
||||
+ for (size_t i = 0; i < LENGTH(abspaths); i++)
|
||||
+ realpath(abspaths[i], paths[i]);
|
||||
+
|
||||
+ for (size_t i = 0; i < LENGTH(relpaths); i++)
|
||||
+ {
|
||||
+ char tmp[PATH_MAX];
|
||||
+ strcpy(tmp, runpath);
|
||||
+ strcat(tmp, relpaths[i]);
|
||||
+ realpath(tmp, paths[LENGTH(abspaths) + i]);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+
|
||||
+ for (size_t i = 0; i < LENGTH(paths); i++)
|
||||
+ {
|
||||
+ char tmp[PATH_MAX];
|
||||
+ printf("checking path: %s\n", paths[i]);
|
||||
+ strcpy(tmp, paths[i]);
|
||||
+ // printf("tmp: %s\n", tmp);
|
||||
+ strcat(tmp, "/dwl.so");
|
||||
+ if (access(tmp, F_OK|R_OK) == 0)
|
||||
+ {
|
||||
+ strcpy(out, tmp);
|
||||
+ return out;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+reload(const Arg* arg)
|
||||
+{
|
||||
+ char* error;
|
||||
+ void* new;
|
||||
+ size_t i = 0;
|
||||
+
|
||||
+ // deinitialize previous module
|
||||
+ if (last_module) {
|
||||
+ // dlclose(last_module);
|
||||
+ last_module = NULL;
|
||||
+ }
|
||||
+
|
||||
+ wlr_log(WLR_INFO, "reloading");
|
||||
+
|
||||
+ new = load();
|
||||
+
|
||||
+ if (new == NULL)
|
||||
+ {
|
||||
+ wlr_log(WLR_ERROR, "couldn't load new dwl module from %s", get_module_path());
|
||||
+ system("notify-send -u low \"failed to reload dwl\"");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ wlr_log(WLR_DEBUG, "---------- listens ---------");
|
||||
+ for(listens* a = listeners; a != NULL; a = a->next)
|
||||
+ {
|
||||
+ Dl_info info;
|
||||
+ void* old = a->listen->notify;
|
||||
+ dladdr(a->listen->notify, &info);
|
||||
+ a->listen->notify = dlsym(new, info.dli_sname);
|
||||
+ if ((error = dlerror()) != NULL){
|
||||
+ fprintf(stderr, "reload failure: %s", error);
|
||||
+ a->listen->notify = old;
|
||||
+ return;
|
||||
+ }
|
||||
+ wlr_log(WLR_DEBUG, "replaced listener: %s", info.dli_sname);
|
||||
+ i++;
|
||||
+ }
|
||||
+
|
||||
+ wlr_log(WLR_DEBUG, "---------- done! ---------");
|
||||
+ wlr_log(WLR_DEBUG, "replaced %zu listeners", i);
|
||||
+
|
||||
+ last_module = dwl_module;
|
||||
+ dwl_module = new;
|
||||
+
|
||||
+ system("notify-send -u low \"reloaded dwl\"");
|
||||
+
|
||||
+}
|
||||
+
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *startup_cmd = NULL;
|
||||
int c;
|
||||
|
||||
+ runpath = dirname(argv[0]);
|
||||
+ dwl_module = load();
|
||||
+
|
||||
while ((c = getopt(argc, argv, "s:hdv")) != -1) {
|
||||
if (c == 's')
|
||||
startup_cmd = optarg;
|
||||
else if (c == 'd')
|
||||
- log_level = WLR_DEBUG;
|
||||
+ CSYM(enum wlr_log_importance, log_level) = WLR_DEBUG;
|
||||
else if (c == 'v')
|
||||
die("dwl " VERSION);
|
||||
else
|
||||
@@ -3215,3 +3462,5 @@ main(int argc, char *argv[])
|
||||
usage:
|
||||
die("Usage: %s [-v] [-d] [-s startup command]", argv[0]);
|
||||
}
|
||||
+
|
||||
+#endif
|
||||
diff --git a/util.c b/util.c
|
||||
index 51130af..2000731 100644
|
||||
--- a/util.c
|
||||
+++ b/util.c
|
||||
@@ -49,3 +49,37 @@ fd_set_nonblock(int fd) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+struct listens*
|
||||
+append_listener(struct wl_listener* new, struct listens* list)
|
||||
+{
|
||||
+ struct listens* l = malloc(sizeof(struct listens));
|
||||
+ l->listen = new;
|
||||
+ l->next = list;
|
||||
+ return l;
|
||||
+}
|
||||
+
|
||||
+struct listens*
|
||||
+remove_listener(struct wl_listener* l, struct listens* ls)
|
||||
+{
|
||||
+ struct listens* out = ls;
|
||||
+ struct listens* f = NULL;
|
||||
+ for(struct listens* last = NULL; ls != NULL; ls = ls->next)
|
||||
+ {
|
||||
+ if (ls->listen == l)
|
||||
+ {
|
||||
+ if (last != NULL)
|
||||
+ last->next = ls->next;
|
||||
+ else
|
||||
+ out = ls->next;
|
||||
+
|
||||
+ f = ls;
|
||||
+ }
|
||||
+ else
|
||||
+ last = ls;
|
||||
+ }
|
||||
+
|
||||
+ free(f);
|
||||
+
|
||||
+ return out;
|
||||
+}
|
||||
diff --git a/util.h b/util.h
|
||||
index 226980d..11aab34 100644
|
||||
--- a/util.h
|
||||
+++ b/util.h
|
||||
@@ -1,5 +1,11 @@
|
||||
/* See LICENSE.dwm file for copyright and license details. */
|
||||
+typedef struct listens {
|
||||
+ struct wl_listener* listen;
|
||||
+ struct listens* next;
|
||||
+} listens;
|
||||
|
||||
void die(const char *fmt, ...);
|
||||
void *ecalloc(size_t nmemb, size_t size);
|
||||
int fd_set_nonblock(int fd);
|
||||
+struct listens* append_listener(struct wl_listener* l, struct listens* ls);
|
||||
+struct listens* remove_listener(struct wl_listener* l, struct listens* ls);
|
||||
--
|
||||
2.48.1
|
||||
|
997
patches/hot-reload/hot-reload.patch
Normal file
997
patches/hot-reload/hot-reload.patch
Normal file
@ -0,0 +1,997 @@
|
||||
From 4e0b5b310180e4328c050e4878bf8261937848d5 Mon Sep 17 00:00:00 2001
|
||||
From: Sivecano <sivecano@gmail.com>
|
||||
Date: Sun, 26 Jan 2025 18:30:02 +0100
|
||||
Subject: [PATCH] redo hot-reloading in one file
|
||||
|
||||
---
|
||||
Makefile | 18 +-
|
||||
config.def.h | 5 +-
|
||||
dwl.c | 471 +++++++++++++++++++++++++++++++++++++++------------
|
||||
util.c | 34 ++++
|
||||
util.h | 6 +
|
||||
5 files changed, 417 insertions(+), 117 deletions(-)
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index 578194f..567e9b9 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -13,13 +13,16 @@ DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \
|
||||
|
||||
# CFLAGS / LDFLAGS
|
||||
PKGS = wayland-server xkbcommon libinput $(XLIBS)
|
||||
-DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
|
||||
+DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) -fPIC -rdynamic
|
||||
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)
|
||||
|
||||
-all: dwl
|
||||
+all: dwl dwl.so
|
||||
dwl: dwl.o util.o
|
||||
$(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
|
||||
-dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
|
||||
+dwl.o: dwl.c cursor-shape-v1-protocol.h \
|
||||
+ pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
|
||||
+ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
|
||||
+dwl.so: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
|
||||
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
|
||||
wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
|
||||
util.o: util.c util.h
|
||||
@@ -49,7 +52,7 @@ xdg-shell-protocol.h:
|
||||
config.h:
|
||||
cp config.def.h $@
|
||||
clean:
|
||||
- rm -f dwl *.o *-protocol.h
|
||||
+ rm -f dwl *.o *-protocol.h *.so
|
||||
|
||||
dist: clean
|
||||
mkdir -p dwl-$(VERSION)
|
||||
@@ -64,6 +67,9 @@ install: dwl
|
||||
rm -f $(DESTDIR)$(PREFIX)/bin/dwl
|
||||
cp -f dwl $(DESTDIR)$(PREFIX)/bin
|
||||
chmod 755 $(DESTDIR)$(PREFIX)/bin/dwl
|
||||
+ mkdir -p $(DESTDIR)$(PREFIX)/lib
|
||||
+ cp -f dwl.so $(DESTDIR)$(PREFIX)/lib
|
||||
+ chmod 744 $(DESTDIR)$(PREFIX)/lib/dwl.so
|
||||
mkdir -p $(DESTDIR)$(MANDIR)/man1
|
||||
cp -f dwl.1 $(DESTDIR)$(MANDIR)/man1
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man1/dwl.1
|
||||
@@ -77,3 +83,7 @@ uninstall:
|
||||
.SUFFIXES: .c .o
|
||||
.c.o:
|
||||
$(CC) $(CPPFLAGS) $(DWLCFLAGS) -o $@ -c $<
|
||||
+
|
||||
+.SUFFIXES: .c .so
|
||||
+.c.so:
|
||||
+ $(CC) $(CPPFLAGS) $(DWLCFLAGS) -o $@ -shared -DHOT $<
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 22d2171..6e3dda1 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -7,7 +7,7 @@
|
||||
static const int sloppyfocus = 1; /* focus follows mouse */
|
||||
static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */
|
||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
-static const float rootcolor[] = COLOR(0x222222ff);
|
||||
+const float rootcolor[] = COLOR(0x222222ff);
|
||||
static const float bordercolor[] = COLOR(0x444444ff);
|
||||
static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
@@ -18,7 +18,7 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca
|
||||
#define TAGCOUNT (9)
|
||||
|
||||
/* logging */
|
||||
-static int log_level = WLR_ERROR;
|
||||
+int log_level = WLR_ERROR;
|
||||
|
||||
/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */
|
||||
static const Rule rules[] = {
|
||||
@@ -127,6 +127,7 @@ static const Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
|
||||
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_R, reload, {0} },
|
||||
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
|
||||
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
|
||||
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index ec4ca86..c852b9b 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -1,6 +1,15 @@
|
||||
/*
|
||||
* See LICENSE file for copyright and license details.
|
||||
*/
|
||||
+
|
||||
+/* stuff for hot-reload */
|
||||
+#define _GNU_SOURCE
|
||||
+#include <dlfcn.h>
|
||||
+#include <limits.h>
|
||||
+#include <unistd.h>
|
||||
+#include <libgen.h>
|
||||
+#include <errno.h>
|
||||
+
|
||||
#include <getopt.h>
|
||||
#include <libinput.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
@@ -68,6 +77,7 @@
|
||||
#include <xcb/xcb_icccm.h>
|
||||
#endif
|
||||
|
||||
+
|
||||
#include "util.h"
|
||||
|
||||
/* macros */
|
||||
@@ -78,8 +88,33 @@
|
||||
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||
#define END(A) ((A) + LENGTH(A))
|
||||
#define TAGMASK ((1u << TAGCOUNT) - 1)
|
||||
-#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L)))
|
||||
-#define LISTEN_STATIC(E, H) do { struct wl_listener *_l = ecalloc(1, sizeof(*_l)); _l->notify = (H); wl_signal_add((E), _l); } while (0)
|
||||
+#define SYM(a) dlsym(dwl_module, #a)
|
||||
+#define TSYM(T, a) ((T)SYM(a))
|
||||
+#define CSYM(T, a) *(TSYM(T*, a))
|
||||
+
|
||||
+#define LISTEN(E, L, H) do { \
|
||||
+ (L)->notify = SYM(H); \
|
||||
+ listeners = append_listener((L), listeners); \
|
||||
+ wl_signal_add((E), (L)); \
|
||||
+ } while(0)
|
||||
+
|
||||
+#define LISTEN_GLOBAL(E, L) do { \
|
||||
+ struct wl_listener* l = SYM(L); \
|
||||
+ listeners = append_listener(l, listeners); \
|
||||
+ wl_signal_add((E), l); \
|
||||
+ } while (0)
|
||||
+
|
||||
+#define LISTEN_STATIC(E, H) do { \
|
||||
+ struct wl_listener* _l = ecalloc(1, sizeof(struct wl_listener)); \
|
||||
+ _l->notify = SYM(H); \
|
||||
+ listeners = append_listener(_l, listeners); \
|
||||
+ wl_signal_add((E), _l); \
|
||||
+ } while (0)
|
||||
+
|
||||
+#define UNLISTEN(L) do { \
|
||||
+ wl_list_remove(&(L)->link); \
|
||||
+ listeners = remove_listener((L), listeners);\
|
||||
+ } while (0)
|
||||
|
||||
/* enums */
|
||||
enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
|
||||
@@ -239,6 +274,9 @@ typedef struct {
|
||||
struct wl_listener destroy;
|
||||
} SessionLock;
|
||||
|
||||
+#define static
|
||||
+
|
||||
+#ifdef HOT
|
||||
/* function declarations */
|
||||
static void applybounds(Client *c, struct wlr_box *bbox);
|
||||
static void applyrules(Client *c);
|
||||
@@ -250,7 +288,18 @@ static void axisnotify(struct wl_listener *listener, void *data);
|
||||
static void buttonpress(struct wl_listener *listener, void *data);
|
||||
static void chvt(const Arg *arg);
|
||||
static void checkidleinhibitor(struct wlr_surface *exclude);
|
||||
+
|
||||
+#undef static
|
||||
+#define static extern
|
||||
+#endif
|
||||
+
|
||||
+/* this is cold */
|
||||
static void cleanup(void);
|
||||
+
|
||||
+#undef static
|
||||
+#define static
|
||||
+#ifdef HOT
|
||||
+
|
||||
static void cleanupmon(struct wl_listener *listener, void *data);
|
||||
static void cleanuplisteners(void);
|
||||
static void closemon(Monitor *m);
|
||||
@@ -318,7 +367,18 @@ static void requestdecorationmode(struct wl_listener *listener, void *data);
|
||||
static void requeststartdrag(struct wl_listener *listener, void *data);
|
||||
static void requestmonstate(struct wl_listener *listener, void *data);
|
||||
static void resize(Client *c, struct wlr_box geo, int interact);
|
||||
+
|
||||
+#undef static
|
||||
+#define static extern
|
||||
+#endif
|
||||
+
|
||||
+/* this is cold */
|
||||
static void run(char *startup_cmd);
|
||||
+
|
||||
+#ifdef HOT
|
||||
+#undef static
|
||||
+#define static
|
||||
+
|
||||
static void setcursor(struct wl_listener *listener, void *data);
|
||||
static void setcursorshape(struct wl_listener *listener, void *data);
|
||||
static void setfloating(Client *c, int floating);
|
||||
@@ -328,7 +388,18 @@ static void setmfact(const Arg *arg);
|
||||
static void setmon(Client *c, Monitor *m, uint32_t newtags);
|
||||
static void setpsel(struct wl_listener *listener, void *data);
|
||||
static void setsel(struct wl_listener *listener, void *data);
|
||||
+
|
||||
+#undef static
|
||||
+#define static extern
|
||||
+#endif
|
||||
+
|
||||
+/* this is cold */
|
||||
static void setup(void);
|
||||
+
|
||||
+#ifdef HOT
|
||||
+#undef static
|
||||
+#define static
|
||||
+
|
||||
static void spawn(const Arg *arg);
|
||||
static void startdrag(struct wl_listener *listener, void *data);
|
||||
static void tag(const Arg *arg);
|
||||
@@ -352,6 +423,16 @@ static void xytonode(double x, double y, struct wlr_surface **psurface,
|
||||
Client **pc, LayerSurface **pl, double *nx, double *ny);
|
||||
static void zoom(const Arg *arg);
|
||||
|
||||
+#endif
|
||||
+
|
||||
+#ifdef HOT
|
||||
+ #undef static
|
||||
+ #define static extern
|
||||
+#else
|
||||
+ #undef static
|
||||
+ #define static
|
||||
+#endif
|
||||
+
|
||||
/* variables */
|
||||
static pid_t child_pid = -1;
|
||||
static int locked;
|
||||
@@ -406,6 +487,10 @@ static struct wlr_box sgeom;
|
||||
static struct wl_list mons;
|
||||
static Monitor *selmon;
|
||||
|
||||
+#ifdef HOT
|
||||
+#undef static
|
||||
+#define static
|
||||
+
|
||||
/* global event handlers */
|
||||
static struct wl_listener cursor_axis = {.notify = axisnotify};
|
||||
static struct wl_listener cursor_button = {.notify = buttonpress};
|
||||
@@ -429,6 +514,7 @@ static struct wl_listener output_mgr_test = {.notify = outputmgrtest};
|
||||
static struct wl_listener output_power_mgr_set_mode = {.notify = powermgrsetmode};
|
||||
static struct wl_listener request_activate = {.notify = urgent};
|
||||
static struct wl_listener request_cursor = {.notify = setcursor};
|
||||
+
|
||||
static struct wl_listener request_set_psel = {.notify = setpsel};
|
||||
static struct wl_listener request_set_sel = {.notify = setsel};
|
||||
static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape};
|
||||
@@ -449,6 +535,34 @@ static struct wl_listener xwayland_ready = {.notify = xwaylandready};
|
||||
static struct wlr_xwayland *xwayland;
|
||||
#endif
|
||||
|
||||
+/* undoes the shadowing of static from above */
|
||||
+#endif
|
||||
+#undef static
|
||||
+
|
||||
+/* this is where we put global hot-reload state */
|
||||
+#ifdef HOT
|
||||
+#define COLD extern
|
||||
+#else
|
||||
+#define COLD
|
||||
+
|
||||
+static void* load(void);
|
||||
+static const char* get_module_path(void);
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
+COLD void * dwl_module = NULL;
|
||||
+COLD void * last_module = NULL;
|
||||
+COLD struct listens* listeners = NULL;
|
||||
+COLD void reload(const Arg* arg);
|
||||
+
|
||||
+#ifndef HOT
|
||||
+static char* runpath;
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
+#ifdef HOT
|
||||
+
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
|
||||
@@ -692,10 +806,12 @@ checkidleinhibitor(struct wlr_surface *exclude)
|
||||
wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited);
|
||||
}
|
||||
|
||||
+#endif
|
||||
+
|
||||
void
|
||||
cleanup(void)
|
||||
{
|
||||
- cleanuplisteners();
|
||||
+ TSYM(void (*)(void), cleanuplisteners)();
|
||||
#ifdef XWAYLAND
|
||||
wlr_xwayland_destroy(xwayland);
|
||||
xwayland = NULL;
|
||||
@@ -707,7 +823,7 @@ cleanup(void)
|
||||
}
|
||||
wlr_xcursor_manager_destroy(cursor_mgr);
|
||||
|
||||
- destroykeyboardgroup(&kb_group->destroy, NULL);
|
||||
+ TSYM(void (*)(struct wl_listener*, void*), destroykeyboardgroup)(&kb_group->destroy, NULL);
|
||||
|
||||
/* 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 */
|
||||
@@ -719,6 +835,8 @@ cleanup(void)
|
||||
wlr_scene_node_destroy(&scene->tree.node);
|
||||
}
|
||||
|
||||
+#ifdef HOT
|
||||
+
|
||||
void
|
||||
cleanupmon(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -732,10 +850,10 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||
wlr_layer_surface_v1_destroy(l->layer_surface);
|
||||
}
|
||||
|
||||
- wl_list_remove(&m->destroy.link);
|
||||
- wl_list_remove(&m->frame.link);
|
||||
+ UNLISTEN(&m->destroy);
|
||||
+ UNLISTEN(&m->frame);
|
||||
wl_list_remove(&m->link);
|
||||
- wl_list_remove(&m->request_state.link);
|
||||
+ UNLISTEN(&m->request_state);
|
||||
m->wlr_output->data = NULL;
|
||||
wlr_output_layout_remove(output_layout, m->wlr_output);
|
||||
wlr_scene_output_destroy(m->scene_output);
|
||||
@@ -748,37 +866,37 @@ cleanupmon(struct wl_listener *listener, void *data)
|
||||
void
|
||||
cleanuplisteners(void)
|
||||
{
|
||||
- wl_list_remove(&cursor_axis.link);
|
||||
- wl_list_remove(&cursor_button.link);
|
||||
- wl_list_remove(&cursor_frame.link);
|
||||
- wl_list_remove(&cursor_motion.link);
|
||||
- wl_list_remove(&cursor_motion_absolute.link);
|
||||
- wl_list_remove(&gpu_reset.link);
|
||||
- wl_list_remove(&new_idle_inhibitor.link);
|
||||
- wl_list_remove(&layout_change.link);
|
||||
- wl_list_remove(&new_input_device.link);
|
||||
- wl_list_remove(&new_virtual_keyboard.link);
|
||||
- wl_list_remove(&new_virtual_pointer.link);
|
||||
- wl_list_remove(&new_pointer_constraint.link);
|
||||
- wl_list_remove(&new_output.link);
|
||||
- wl_list_remove(&new_xdg_toplevel.link);
|
||||
- wl_list_remove(&new_xdg_decoration.link);
|
||||
- wl_list_remove(&new_xdg_popup.link);
|
||||
- wl_list_remove(&new_layer_surface.link);
|
||||
- wl_list_remove(&output_mgr_apply.link);
|
||||
- wl_list_remove(&output_mgr_test.link);
|
||||
- wl_list_remove(&output_power_mgr_set_mode.link);
|
||||
- wl_list_remove(&request_activate.link);
|
||||
- wl_list_remove(&request_cursor.link);
|
||||
- wl_list_remove(&request_set_psel.link);
|
||||
- wl_list_remove(&request_set_sel.link);
|
||||
- wl_list_remove(&request_set_cursor_shape.link);
|
||||
- wl_list_remove(&request_start_drag.link);
|
||||
- wl_list_remove(&start_drag.link);
|
||||
- wl_list_remove(&new_session_lock.link);
|
||||
+ UNLISTEN(&cursor_axis);
|
||||
+ UNLISTEN(&cursor_button);
|
||||
+ UNLISTEN(&cursor_frame);
|
||||
+ UNLISTEN(&cursor_motion);
|
||||
+ UNLISTEN(&cursor_motion_absolute);
|
||||
+ UNLISTEN(&gpu_reset);
|
||||
+ UNLISTEN(&new_idle_inhibitor);
|
||||
+ UNLISTEN(&layout_change);
|
||||
+ UNLISTEN(&new_input_device);
|
||||
+ UNLISTEN(&new_virtual_keyboard);
|
||||
+ UNLISTEN(&new_virtual_pointer);
|
||||
+ UNLISTEN(&new_pointer_constraint);
|
||||
+ UNLISTEN(&new_output);
|
||||
+ UNLISTEN(&new_xdg_toplevel);
|
||||
+ UNLISTEN(&new_xdg_decoration);
|
||||
+ UNLISTEN(&new_xdg_popup);
|
||||
+ UNLISTEN(&new_layer_surface);
|
||||
+ UNLISTEN(&output_mgr_apply);
|
||||
+ UNLISTEN(&output_mgr_test);
|
||||
+ UNLISTEN(&output_power_mgr_set_mode);
|
||||
+ UNLISTEN(&request_activate);
|
||||
+ UNLISTEN(&request_cursor);
|
||||
+ UNLISTEN(&request_set_psel);
|
||||
+ UNLISTEN(&request_set_sel);
|
||||
+ UNLISTEN(&request_set_cursor_shape);
|
||||
+ UNLISTEN(&request_start_drag);
|
||||
+ UNLISTEN(&start_drag);
|
||||
+ UNLISTEN(&new_session_lock);
|
||||
#ifdef XWAYLAND
|
||||
- wl_list_remove(&new_xwayland_surface.link);
|
||||
- wl_list_remove(&xwayland_ready.link);
|
||||
+ UNLISTEN(&new_xwayland_surface);
|
||||
+ UNLISTEN(&xwayland_ready);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -905,8 +1023,7 @@ commitpopup(struct wl_listener *listener, void *data)
|
||||
box.x -= (type == LayerShell ? l->scene->node.x : c->geom.x);
|
||||
box.y -= (type == LayerShell ? l->scene->node.y : c->geom.y);
|
||||
wlr_xdg_popup_unconstrain_from_box(popup, &box);
|
||||
- wl_list_remove(&listener->link);
|
||||
- free(listener);
|
||||
+ UNLISTEN(listener);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1236,8 +1353,8 @@ destroydecoration(struct wl_listener *listener, void *data)
|
||||
{
|
||||
Client *c = wl_container_of(listener, c, destroy_decoration);
|
||||
|
||||
- wl_list_remove(&c->destroy_decoration.link);
|
||||
- wl_list_remove(&c->set_decoration_mode.link);
|
||||
+ UNLISTEN(&c->destroy_decoration);
|
||||
+ UNLISTEN(&c->set_decoration_mode);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1246,8 +1363,7 @@ destroydragicon(struct wl_listener *listener, void *data)
|
||||
/* Focus enter isn't sent during drag, so refocus the focused node. */
|
||||
focusclient(focustop(selmon), 1);
|
||||
motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
- wl_list_remove(&listener->link);
|
||||
- free(listener);
|
||||
+ UNLISTEN(listener);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1256,8 +1372,7 @@ destroyidleinhibitor(struct wl_listener *listener, void *data)
|
||||
/* `data` is the wlr_surface of the idle inhibitor being destroyed,
|
||||
* at this point the idle inhibitor is still in the list of the manager */
|
||||
checkidleinhibitor(wlr_surface_get_root_surface(data));
|
||||
- wl_list_remove(&listener->link);
|
||||
- free(listener);
|
||||
+ UNLISTEN(listener);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1266,9 +1381,9 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data)
|
||||
LayerSurface *l = wl_container_of(listener, l, destroy);
|
||||
|
||||
wl_list_remove(&l->link);
|
||||
- wl_list_remove(&l->destroy.link);
|
||||
- wl_list_remove(&l->unmap.link);
|
||||
- wl_list_remove(&l->surface_commit.link);
|
||||
+ UNLISTEN(&l->destroy);
|
||||
+ UNLISTEN(&l->unmap);
|
||||
+ UNLISTEN(&l->surface_commit);
|
||||
wlr_scene_node_destroy(&l->scene->node);
|
||||
wlr_scene_node_destroy(&l->popups->node);
|
||||
free(l);
|
||||
@@ -1287,9 +1402,9 @@ destroylock(SessionLock *lock, int unlock)
|
||||
motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
|
||||
destroy:
|
||||
- wl_list_remove(&lock->new_surface.link);
|
||||
- wl_list_remove(&lock->unlock.link);
|
||||
- wl_list_remove(&lock->destroy.link);
|
||||
+ UNLISTEN(&lock->new_surface);
|
||||
+ UNLISTEN(&lock->unlock);
|
||||
+ UNLISTEN(&lock->destroy);
|
||||
|
||||
wlr_scene_node_destroy(&lock->scene->node);
|
||||
cur_lock = NULL;
|
||||
@@ -1303,7 +1418,7 @@ destroylocksurface(struct wl_listener *listener, void *data)
|
||||
struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface;
|
||||
|
||||
m->lock_surface = NULL;
|
||||
- wl_list_remove(&m->destroy_lock_surface.link);
|
||||
+ UNLISTEN(&m->destroy_lock_surface);
|
||||
|
||||
if (lock_surface->surface != seat->keyboard_state.focused_surface)
|
||||
return;
|
||||
@@ -1323,23 +1438,23 @@ destroynotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* Called when the xdg_toplevel is destroyed. */
|
||||
Client *c = wl_container_of(listener, c, destroy);
|
||||
- wl_list_remove(&c->destroy.link);
|
||||
- wl_list_remove(&c->set_title.link);
|
||||
- wl_list_remove(&c->fullscreen.link);
|
||||
+ UNLISTEN(&c->destroy);
|
||||
+ UNLISTEN(&c->set_title);
|
||||
+ UNLISTEN(&c->fullscreen);
|
||||
#ifdef XWAYLAND
|
||||
if (c->type != XDGShell) {
|
||||
- wl_list_remove(&c->activate.link);
|
||||
- wl_list_remove(&c->associate.link);
|
||||
- wl_list_remove(&c->configure.link);
|
||||
- wl_list_remove(&c->dissociate.link);
|
||||
- wl_list_remove(&c->set_hints.link);
|
||||
+ UNLISTEN(&c->activate);
|
||||
+ UNLISTEN(&c->associate);
|
||||
+ UNLISTEN(&c->configure);
|
||||
+ UNLISTEN(&c->dissociate);
|
||||
+ UNLISTEN(&c->set_hints);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
- wl_list_remove(&c->commit.link);
|
||||
- wl_list_remove(&c->map.link);
|
||||
- wl_list_remove(&c->unmap.link);
|
||||
- wl_list_remove(&c->maximize.link);
|
||||
+ UNLISTEN(&c->commit);
|
||||
+ UNLISTEN(&c->map);
|
||||
+ UNLISTEN(&c->unmap);
|
||||
+ UNLISTEN(&c->maximize);
|
||||
}
|
||||
free(c);
|
||||
}
|
||||
@@ -1354,7 +1469,7 @@ destroypointerconstraint(struct wl_listener *listener, void *data)
|
||||
active_constraint = NULL;
|
||||
}
|
||||
|
||||
- wl_list_remove(&pointer_constraint->destroy.link);
|
||||
+ UNLISTEN(&pointer_constraint->destroy);
|
||||
free(pointer_constraint);
|
||||
}
|
||||
|
||||
@@ -1370,9 +1485,9 @@ destroykeyboardgroup(struct wl_listener *listener, void *data)
|
||||
{
|
||||
KeyboardGroup *group = wl_container_of(listener, group, destroy);
|
||||
wl_event_source_remove(group->key_repeat_source);
|
||||
- wl_list_remove(&group->key.link);
|
||||
- wl_list_remove(&group->modifiers.link);
|
||||
- wl_list_remove(&group->destroy.link);
|
||||
+ UNLISTEN(&group->key);
|
||||
+ UNLISTEN(&group->modifiers);
|
||||
+ UNLISTEN(&group->destroy);
|
||||
wlr_keyboard_group_destroy(group->wlr_group);
|
||||
free(group);
|
||||
}
|
||||
@@ -1538,8 +1653,8 @@ gpureset(struct wl_listener *listener, void *data)
|
||||
if (!(alloc = wlr_allocator_autocreate(backend, drw)))
|
||||
die("couldn't recreate allocator");
|
||||
|
||||
- wl_list_remove(&gpu_reset.link);
|
||||
- wl_signal_add(&drw->events.lost, &gpu_reset);
|
||||
+ UNLISTEN(&gpu_reset);
|
||||
+ LISTEN_GLOBAL(&drw->events.lost, gpu_reset);
|
||||
|
||||
wlr_compositor_set_renderer(compositor, drw);
|
||||
|
||||
@@ -2229,6 +2344,8 @@ resize(Client *c, struct wlr_box geo, int interact)
|
||||
wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
|
||||
}
|
||||
|
||||
+#else /*HOT*/
|
||||
+
|
||||
void
|
||||
run(char *startup_cmd)
|
||||
{
|
||||
@@ -2268,11 +2385,11 @@ run(char *startup_cmd)
|
||||
if (fd_set_nonblock(STDOUT_FILENO) < 0)
|
||||
close(STDOUT_FILENO);
|
||||
|
||||
- printstatus();
|
||||
+ TSYM(void (*)(void), printstatus)();
|
||||
|
||||
/* At this point the outputs are initialized, choose initial selmon based on
|
||||
* cursor position, and set default cursor image */
|
||||
- selmon = xytomon(cursor->x, cursor->y);
|
||||
+ selmon = TSYM(Monitor* (*)(double x, double y), xytomon)(cursor->x, cursor->y);
|
||||
|
||||
/* TODO hack to get cursor to display in its initial location (100, 100)
|
||||
* instead of (0, 0) and then jumping. still may not be fully
|
||||
@@ -2288,6 +2405,9 @@ run(char *startup_cmd)
|
||||
wl_display_run(dpy);
|
||||
}
|
||||
|
||||
+#endif
|
||||
+#ifdef HOT
|
||||
+
|
||||
void
|
||||
setcursor(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -2434,17 +2554,19 @@ setsel(struct wl_listener *listener, void *data)
|
||||
wlr_seat_set_selection(seat, event->source, event->serial);
|
||||
}
|
||||
|
||||
+#else /*HOT*/
|
||||
+
|
||||
void
|
||||
setup(void)
|
||||
{
|
||||
int drm_fd, i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
|
||||
- struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
|
||||
+ struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = SYM(handlesig)};
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
for (i = 0; i < (int)LENGTH(sig); i++)
|
||||
sigaction(sig[i], &sa, NULL);
|
||||
|
||||
- wlr_log_init(log_level, NULL);
|
||||
+ wlr_log_init(CSYM(enum wlr_log_importance, log_level), NULL);
|
||||
|
||||
/* The Wayland display is managed by libwayland. It handles accepting
|
||||
* clients from the Unix socket, manging Wayland globals, and so on. */
|
||||
@@ -2460,7 +2582,7 @@ setup(void)
|
||||
|
||||
/* Initialize the scene graph used to lay out windows */
|
||||
scene = wlr_scene_create();
|
||||
- root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, rootcolor);
|
||||
+ root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, TSYM(float*, rootcolor));
|
||||
for (i = 0; i < NUM_LAYERS; i++)
|
||||
layers[i] = wlr_scene_tree_create(&scene->tree);
|
||||
drag_icon = wlr_scene_tree_create(&scene->tree);
|
||||
@@ -2472,7 +2594,7 @@ setup(void)
|
||||
* supports for shared memory, this configures that for clients. */
|
||||
if (!(drw = wlr_renderer_autocreate(backend)))
|
||||
die("couldn't create renderer");
|
||||
- wl_signal_add(&drw->events.lost, &gpu_reset);
|
||||
+ LISTEN_GLOBAL(&drw->events.lost, gpu_reset);
|
||||
|
||||
/* Create shm, drm and linux_dmabuf interfaces by ourselves.
|
||||
* The simplest way is call:
|
||||
@@ -2519,24 +2641,24 @@ setup(void)
|
||||
|
||||
/* Initializes the interface used to implement urgency hints */
|
||||
activation = wlr_xdg_activation_v1_create(dpy);
|
||||
- wl_signal_add(&activation->events.request_activate, &request_activate);
|
||||
+ LISTEN_GLOBAL(&activation->events.request_activate, request_activate);
|
||||
|
||||
wlr_scene_set_gamma_control_manager_v1(scene, wlr_gamma_control_manager_v1_create(dpy));
|
||||
|
||||
power_mgr = wlr_output_power_manager_v1_create(dpy);
|
||||
- wl_signal_add(&power_mgr->events.set_mode, &output_power_mgr_set_mode);
|
||||
+ LISTEN_GLOBAL(&power_mgr->events.set_mode, output_power_mgr_set_mode);
|
||||
|
||||
/* Creates an output layout, which a wlroots utility for working with an
|
||||
* arrangement of screens in a physical layout. */
|
||||
output_layout = wlr_output_layout_create(dpy);
|
||||
- wl_signal_add(&output_layout->events.change, &layout_change);
|
||||
+ LISTEN_GLOBAL(&output_layout->events.change, layout_change);
|
||||
|
||||
wlr_xdg_output_manager_v1_create(dpy, output_layout);
|
||||
|
||||
/* Configure a listener to be notified when new outputs are available on the
|
||||
* backend. */
|
||||
wl_list_init(&mons);
|
||||
- wl_signal_add(&backend->events.new_output, &new_output);
|
||||
+ LISTEN_GLOBAL(&backend->events.new_output, new_output);
|
||||
|
||||
/* Set up our client lists, the xdg-shell and the layer-shell. The xdg-shell is a
|
||||
* Wayland protocol which is used for application windows. For more
|
||||
@@ -2548,19 +2670,19 @@ setup(void)
|
||||
wl_list_init(&fstack);
|
||||
|
||||
xdg_shell = wlr_xdg_shell_create(dpy, 6);
|
||||
- wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel);
|
||||
- wl_signal_add(&xdg_shell->events.new_popup, &new_xdg_popup);
|
||||
+ LISTEN_GLOBAL(&xdg_shell->events.new_toplevel, new_xdg_toplevel);
|
||||
+ LISTEN_GLOBAL(&xdg_shell->events.new_popup, new_xdg_popup);
|
||||
|
||||
layer_shell = wlr_layer_shell_v1_create(dpy, 3);
|
||||
- wl_signal_add(&layer_shell->events.new_surface, &new_layer_surface);
|
||||
+ LISTEN_GLOBAL(&layer_shell->events.new_surface, new_layer_surface);
|
||||
|
||||
idle_notifier = wlr_idle_notifier_v1_create(dpy);
|
||||
|
||||
idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy);
|
||||
- wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &new_idle_inhibitor);
|
||||
+ LISTEN_GLOBAL(&idle_inhibit_mgr->events.new_inhibitor, new_idle_inhibitor);
|
||||
|
||||
session_lock_mgr = wlr_session_lock_manager_v1_create(dpy);
|
||||
- wl_signal_add(&session_lock_mgr->events.new_lock, &new_session_lock);
|
||||
+ LISTEN_GLOBAL(&session_lock_mgr->events.new_lock, new_session_lock);
|
||||
locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height,
|
||||
(float [4]){0.1f, 0.1f, 0.1f, 1.0f});
|
||||
wlr_scene_node_set_enabled(&locked_bg->node, 0);
|
||||
@@ -2570,10 +2692,10 @@ setup(void)
|
||||
wlr_server_decoration_manager_create(dpy),
|
||||
WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
|
||||
xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy);
|
||||
- wl_signal_add(&xdg_decoration_mgr->events.new_toplevel_decoration, &new_xdg_decoration);
|
||||
+ LISTEN_GLOBAL(&xdg_decoration_mgr->events.new_toplevel_decoration, new_xdg_decoration);
|
||||
|
||||
pointer_constraints = wlr_pointer_constraints_v1_create(dpy);
|
||||
- wl_signal_add(&pointer_constraints->events.new_constraint, &new_pointer_constraint);
|
||||
+ LISTEN_GLOBAL(&pointer_constraints->events.new_constraint, new_pointer_constraint);
|
||||
|
||||
relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy);
|
||||
|
||||
@@ -2601,14 +2723,14 @@ setup(void)
|
||||
*
|
||||
* And more comments are sprinkled throughout the notify functions above.
|
||||
*/
|
||||
- wl_signal_add(&cursor->events.motion, &cursor_motion);
|
||||
- wl_signal_add(&cursor->events.motion_absolute, &cursor_motion_absolute);
|
||||
- wl_signal_add(&cursor->events.button, &cursor_button);
|
||||
- wl_signal_add(&cursor->events.axis, &cursor_axis);
|
||||
- wl_signal_add(&cursor->events.frame, &cursor_frame);
|
||||
+ LISTEN_GLOBAL(&cursor->events.motion, cursor_motion);
|
||||
+ LISTEN_GLOBAL(&cursor->events.motion_absolute, cursor_motion_absolute);
|
||||
+ LISTEN_GLOBAL(&cursor->events.button, cursor_button);
|
||||
+ LISTEN_GLOBAL(&cursor->events.axis, cursor_axis);
|
||||
+ LISTEN_GLOBAL(&cursor->events.frame, cursor_frame);
|
||||
|
||||
cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1);
|
||||
- wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape);
|
||||
+ LISTEN_GLOBAL(&cursor_shape_mgr->events.request_set_shape, request_set_cursor_shape);
|
||||
|
||||
/*
|
||||
* Configures a seat, which is a single "seat" at which a user sits and
|
||||
@@ -2616,27 +2738,27 @@ setup(void)
|
||||
* pointer, touch, and drawing tablet device. We also rig up a listener to
|
||||
* let us know when new input devices are available on the backend.
|
||||
*/
|
||||
- wl_signal_add(&backend->events.new_input, &new_input_device);
|
||||
+ LISTEN_GLOBAL(&backend->events.new_input, new_input_device);
|
||||
virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);
|
||||
- wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard,
|
||||
- &new_virtual_keyboard);
|
||||
+ LISTEN_GLOBAL(&virtual_keyboard_mgr->events.new_virtual_keyboard,
|
||||
+ new_virtual_keyboard);
|
||||
virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy);
|
||||
- wl_signal_add(&virtual_pointer_mgr->events.new_virtual_pointer,
|
||||
- &new_virtual_pointer);
|
||||
+ LISTEN_GLOBAL(&virtual_pointer_mgr->events.new_virtual_pointer,
|
||||
+ new_virtual_pointer);
|
||||
|
||||
seat = wlr_seat_create(dpy, "seat0");
|
||||
- wl_signal_add(&seat->events.request_set_cursor, &request_cursor);
|
||||
- wl_signal_add(&seat->events.request_set_selection, &request_set_sel);
|
||||
- wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel);
|
||||
- wl_signal_add(&seat->events.request_start_drag, &request_start_drag);
|
||||
- wl_signal_add(&seat->events.start_drag, &start_drag);
|
||||
+ LISTEN_GLOBAL(&seat->events.request_set_cursor, request_cursor);
|
||||
+ LISTEN_GLOBAL(&seat->events.request_set_selection, request_set_sel);
|
||||
+ LISTEN_GLOBAL(&seat->events.request_set_primary_selection, request_set_psel);
|
||||
+ LISTEN_GLOBAL(&seat->events.request_start_drag, request_start_drag);
|
||||
+ LISTEN_GLOBAL(&seat->events.start_drag, start_drag);
|
||||
|
||||
- kb_group = createkeyboardgroup();
|
||||
+ kb_group = TSYM(KeyboardGroup *(*)(void), createkeyboardgroup)();
|
||||
wl_list_init(&kb_group->destroy.link);
|
||||
|
||||
output_mgr = wlr_output_manager_v1_create(dpy);
|
||||
- wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);
|
||||
- wl_signal_add(&output_mgr->events.test, &output_mgr_test);
|
||||
+ LISTEN_GLOBAL(&output_mgr->events.apply, output_mgr_apply);
|
||||
+ LISTEN_GLOBAL(&output_mgr->events.test, output_mgr_test);
|
||||
|
||||
/* 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
|
||||
@@ -2648,8 +2770,8 @@ setup(void)
|
||||
* It will be started when the first X client is started.
|
||||
*/
|
||||
if ((xwayland = wlr_xwayland_create(dpy, compositor, 1))) {
|
||||
- wl_signal_add(&xwayland->events.ready, &xwayland_ready);
|
||||
- wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface);
|
||||
+ LISTEN_GLOBAL(&xwayland->events.ready, xwayland_ready);
|
||||
+ LISTEN_GLOBAL(&xwayland->events.new_surface, new_xwayland_surface);
|
||||
|
||||
setenv("DISPLAY", xwayland->display_name, 1);
|
||||
} else {
|
||||
@@ -2658,6 +2780,9 @@ setup(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
+#endif
|
||||
+#ifdef HOT
|
||||
+
|
||||
void
|
||||
spawn(const Arg *arg)
|
||||
{
|
||||
@@ -3139,8 +3264,8 @@ void
|
||||
dissociatex11(struct wl_listener *listener, void *data)
|
||||
{
|
||||
Client *c = wl_container_of(listener, c, dissociate);
|
||||
- wl_list_remove(&c->map.link);
|
||||
- wl_list_remove(&c->unmap.link);
|
||||
+ UNLISTEN(&c->map);
|
||||
+ UNLISTEN(&c->unmap);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -3175,17 +3300,139 @@ xwaylandready(struct wl_listener *listener, void *data)
|
||||
}
|
||||
#endif
|
||||
|
||||
+#else /* HOT */
|
||||
+void*
|
||||
+load(void)
|
||||
+{
|
||||
+ const char* path = get_module_path();
|
||||
+ char load[PATH_MAX] = "/tmp/dwl.soXXXXXX";
|
||||
+ void* new;
|
||||
+
|
||||
+ if (!path) {
|
||||
+ fprintf(stderr, "cannot find dwl.so\n");
|
||||
+ }
|
||||
+
|
||||
+ do {
|
||||
+ mktemp(load);
|
||||
+ errno = 0;
|
||||
+ symlink(path, load);
|
||||
+ } while(errno == EEXIST);
|
||||
+
|
||||
+ new = dlopen(load, RTLD_NOW|RTLD_LOCAL);
|
||||
+
|
||||
+ unlink(load);
|
||||
+ if (new == NULL)
|
||||
+ fprintf(stderr, "error while loading %s: %s\n", path, dlerror());
|
||||
+ else
|
||||
+ printf("loaded: %s\n", path);
|
||||
+
|
||||
+ return new;
|
||||
+}
|
||||
+
|
||||
+const char *
|
||||
+get_module_path(void) {
|
||||
+ char home[PATH_MAX];
|
||||
+ strcpy(home, getenv("HOME"));
|
||||
+ strcat(home, "/.local/lib");
|
||||
+ const char* abspaths[] = {".", home, "/usr/share/lib", "/usr/local/lib", "/usr/local/share/lib"};
|
||||
+ const char* relpaths[] = {"", "/../lib"};
|
||||
+ char paths[LENGTH(abspaths) + LENGTH(relpaths)][PATH_MAX];
|
||||
+ static char out[PATH_MAX] = "./";
|
||||
+
|
||||
+ for (size_t i = 0; i < LENGTH(abspaths); i++)
|
||||
+ realpath(abspaths[i], paths[i]);
|
||||
+
|
||||
+ for (size_t i = 0; i < LENGTH(relpaths); i++)
|
||||
+ {
|
||||
+ char tmp[PATH_MAX];
|
||||
+ strcpy(tmp, runpath);
|
||||
+ strcat(tmp, relpaths[i]);
|
||||
+ realpath(tmp, paths[LENGTH(abspaths) + i]);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+
|
||||
+ for (size_t i = 0; i < LENGTH(paths); i++)
|
||||
+ {
|
||||
+ char tmp[PATH_MAX];
|
||||
+ printf("checking path: %s\n", paths[i]);
|
||||
+ strcpy(tmp, paths[i]);
|
||||
+ // printf("tmp: %s\n", tmp);
|
||||
+ strcat(tmp, "/dwl.so");
|
||||
+ if (access(tmp, F_OK|R_OK) == 0)
|
||||
+ {
|
||||
+ strcpy(out, tmp);
|
||||
+ return out;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+reload(const Arg* arg)
|
||||
+{
|
||||
+ char* error;
|
||||
+ void* new;
|
||||
+ size_t i = 0;
|
||||
+
|
||||
+ // deinitialize previous module
|
||||
+ if (last_module) {
|
||||
+ // dlclose(last_module);
|
||||
+ last_module = NULL;
|
||||
+ }
|
||||
+
|
||||
+ wlr_log(WLR_INFO, "reloading");
|
||||
+
|
||||
+ new = load();
|
||||
+
|
||||
+ if (new == NULL)
|
||||
+ {
|
||||
+ wlr_log(WLR_ERROR, "couldn't load new dwl module from %s", get_module_path());
|
||||
+ system("notify-send -u low \"failed to reload dwl\"");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ wlr_log(WLR_DEBUG, "---------- listens ---------");
|
||||
+ for(listens* a = listeners; a != NULL; a = a->next)
|
||||
+ {
|
||||
+ Dl_info info;
|
||||
+ void* old = a->listen->notify;
|
||||
+ dladdr(a->listen->notify, &info);
|
||||
+ a->listen->notify = dlsym(new, info.dli_sname);
|
||||
+ if ((error = dlerror()) != NULL){
|
||||
+ fprintf(stderr, "reload failure: %s", error);
|
||||
+ a->listen->notify = old;
|
||||
+ return;
|
||||
+ }
|
||||
+ wlr_log(WLR_DEBUG, "replaced listener: %s", info.dli_sname);
|
||||
+ i++;
|
||||
+ }
|
||||
+
|
||||
+ wlr_log(WLR_DEBUG, "---------- done! ---------");
|
||||
+ wlr_log(WLR_DEBUG, "replaced %zu listeners", i);
|
||||
+
|
||||
+ last_module = dwl_module;
|
||||
+ dwl_module = new;
|
||||
+
|
||||
+ system("notify-send -u low \"reloaded dwl\"");
|
||||
+
|
||||
+}
|
||||
+
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *startup_cmd = NULL;
|
||||
int c;
|
||||
|
||||
+ runpath = dirname(argv[0]);
|
||||
+ dwl_module = load();
|
||||
+
|
||||
while ((c = getopt(argc, argv, "s:hdv")) != -1) {
|
||||
if (c == 's')
|
||||
startup_cmd = optarg;
|
||||
else if (c == 'd')
|
||||
- log_level = WLR_DEBUG;
|
||||
+ CSYM(enum wlr_log_importance, log_level) = WLR_DEBUG;
|
||||
else if (c == 'v')
|
||||
die("dwl " VERSION);
|
||||
else
|
||||
@@ -3205,3 +3452,5 @@ main(int argc, char *argv[])
|
||||
usage:
|
||||
die("Usage: %s [-v] [-d] [-s startup command]", argv[0]);
|
||||
}
|
||||
+
|
||||
+#endif
|
||||
diff --git a/util.c b/util.c
|
||||
index b925987..8fb9b77 100644
|
||||
--- a/util.c
|
||||
+++ b/util.c
|
||||
@@ -49,3 +49,37 @@ fd_set_nonblock(int fd) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+struct listens*
|
||||
+append_listener(struct wl_listener* new, struct listens* list)
|
||||
+{
|
||||
+ struct listens* l = malloc(sizeof(struct listens));
|
||||
+ l->listen = new;
|
||||
+ l->next = list;
|
||||
+ return l;
|
||||
+}
|
||||
+
|
||||
+struct listens*
|
||||
+remove_listener(struct wl_listener* l, struct listens* ls)
|
||||
+{
|
||||
+ struct listens* out = ls;
|
||||
+ struct listens* f = NULL;
|
||||
+ for(struct listens* last = NULL; ls != NULL; ls = ls->next)
|
||||
+ {
|
||||
+ if (ls->listen == l)
|
||||
+ {
|
||||
+ if (last != NULL)
|
||||
+ last->next = ls->next;
|
||||
+ else
|
||||
+ out = ls->next;
|
||||
+
|
||||
+ f = ls;
|
||||
+ }
|
||||
+ else
|
||||
+ last = ls;
|
||||
+ }
|
||||
+
|
||||
+ free(f);
|
||||
+
|
||||
+ return out;
|
||||
+}
|
||||
diff --git a/util.h b/util.h
|
||||
index 226980d..11aab34 100644
|
||||
--- a/util.h
|
||||
+++ b/util.h
|
||||
@@ -1,5 +1,11 @@
|
||||
/* See LICENSE.dwm file for copyright and license details. */
|
||||
+typedef struct listens {
|
||||
+ struct wl_listener* listen;
|
||||
+ struct listens* next;
|
||||
+} listens;
|
||||
|
||||
void die(const char *fmt, ...);
|
||||
void *ecalloc(size_t nmemb, size_t size);
|
||||
int fd_set_nonblock(int fd);
|
||||
+struct listens* append_listener(struct wl_listener* l, struct listens* ls);
|
||||
+struct listens* remove_listener(struct wl_listener* l, struct listens* ls);
|
||||
--
|
||||
2.48.1
|
||||
|
Loading…
x
Reference in New Issue
Block a user