From caa1adaf02ab4f9a326761ade5d1346149bc7c59 Mon Sep 17 00:00:00 2001 From: Sivecano Date: Sun, 26 Jan 2025 18:30:02 +0100 Subject: [PATCH] redo hot-reloading in one file --- Makefile | 19 ++- config.def.h | 5 +- dwl.c | 337 ++++++++++++++++++++++++++++++++++++++++++++------- util.c | 34 ++++++ util.h | 6 + 5 files changed, 351 insertions(+), 50 deletions(-) diff --git a/Makefile b/Makefile index 3358bae..70d3d0f 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,8 @@ install: dwl mkdir -p $(DESTDIR)$(PREFIX)/bin cp -f dwl $(DESTDIR)$(PREFIX)/bin chmod 755 $(DESTDIR)$(PREFIX)/bin/dwl + mkdir -p $(DESTDIR)$(PREFIX)/lib + install -m 744 dwl.so $(DESTDIR)$(PREFIX)/lib mkdir -p $(DESTDIR)$(MANDIR)/man1 cp -f dwl.1 $(DESTDIR)$(MANDIR)/man1 chmod 644 $(DESTDIR)$(MANDIR)/man1/dwl.1 @@ -70,9 +75,13 @@ install: dwl cp -f dwl.desktop $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop chmod 644 $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop uninstall: - rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 \ + rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(PREFIX)/lib/dwl.so $(DESTDIR)$(MANDIR)/man1/dwl.1 \ $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop .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..7e059ad 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 +#include +#include +#include +#include + #include #include #include @@ -67,6 +76,7 @@ #include #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,141 @@ 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]); + 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()); + + if (fork() == 0) + execl("/bin/env", "--", "Notify-send", "-u", "low", "failed to reload dwl", NULL); + 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; + + if (fork() == 0) + execl("/bin/env", "--", "notify-send", "-u", "low", "reloaded dwl", NULL); + +} + 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 +3464,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