SXB57HHWBQQIOEUXK65JKGXX4ZNSGXU55XHSEXU2YZSTFH3PYZRQC
DPRID5UEAF6C2TPMTRPE2CQBGPQWXBRBIUOMABSJ7AICLMHYZPVAC
TRGHSV7WZDJK4N2GYF54ZPP3SQKRN3L3XAPZ2NCAZU4SVMBCD2YQC
SUD4YYZJGWJTQUBNBSYIPYSO22NCRI6MYTIUVNGTY5TD7FWKZ5UQC
CGFALGMDL4Y5V4G7RY2ISQAWZTDXTE4CVDJL3EWSMGTE5CXGVWTQC
GLMJBCVZQV44EBKNLIBESMJGWIG2QEU4F4L5KJ7IO4ALSM6LX4KQC
N3SL4BMZY4QLRU6GRFT33T6TQKSBKXD5GYEFCHAXUJBH7XQPBBIAC
7EL6M5JX7NETLCKWGFWXU3ADIHQ2EKPCFHDMMDNFF5Y7WXHYG3ZAC
TINMCJXVMLM3X5UM677SJNA6UGI3XCNMZ4ZOLQPBSRAOOY2USOSQC
7RLLU52RCOT2MQY4CPZTCDIA3FXETNPAISE5F2I7CI7TZW2SZVHAC
PRKNMJFY3IHIRZH2QSJKLEAXQOONJITGHAZ4HOJTC35V2PPR2POAC
HFIKAPN3TBMDVBDG7SZLX4ZJMSFFDGINTO6C2SKO5IVYUILGCQEQC
7B74AT3BXYB7PVW4F6SGQNPMHOU5TEV5TZ54CG6VSQI46XSEKWXQC
GGAF2M67EYKDSJFLXEZ6TJ3FC2LDKTDD2TFBM3YRQDWI6ON3FV6AC
ERBETXYU7NGSWW5LHQ3NSJA2N27JNMDDYMZ74B6IVQTEQMLRP6PAC
R2ACAAQNXWMD77ITUPIXPHB6ZQH4PCXNFEK5L64HEXU3ETFZAHDAC
AMKI4S66JRI3L5BH2A2BTQZKGJW2OFKUMOPSXT5EHP6LHLACLDEAC
ZTOYJ4G4UQ665FKUH376KJOOO5GXHI62SWVXNZS7X6F2Y4GG2FSQC
YCC55JJHQR3BEO3ZTP6NVDKTFU4NNNJP2SW755QMMUAIEBMXXIRAC
CN4FS77B6FLSEDGAQ4R5YGHS56TNW7IGUR7RK4HKCLDX2627VBKAC
JTZBFGPCDJDJWECXH2LLXY3SUAQNCP45HLJQKG3V7XGTPLD634WAC
7XCGFU3GX4TQXZBOU7GFAQ62EEOTVRNWFYQGI3XULFPSUKDZ2EYAC
D425ND7AT3F7QJ3CCSESMVDOC3J5C5P32M5SJDBHECZJXLHNQ2FAC
QKVRBSFOOQUQMZ3P7CMPA7QCVQW5TXAKWH6NDL3K7Q3Z4GMXOVPQC
WMNBUD2PGH4XJP7UJNQXULQ475EIQUPEDPZOVU4AT2ALU3FHKFEQC
HIFS24I32X4DPDLGVEK47AC3N2TRDUANPWFOZ5C52K4AGSITZLHAC
6XZIQSMIVP2GZ5S3UCKEVNDSLTHSQEVSXLV4UIFF3G3SRCGJPXYAC
6US7XFRJWUNIUZHKTODZDU3DX6WO5K3J2G3ECIQYSVBDII3DXGWAC
S7RXJJZG4IEIVLPHEWFT5M2T3SRRO5US5SYBPXSYSWJJLXAKNNPAC
4WVZ2LAGAIQ2EROHNA4T5PWQEEIPJRTA3CBHGAO55NACCUGLKEZQC
E7UO6NRGXFDMBU3BSJYRDNOA3Y7VHD7NWPHI5PHCPHQF6ZNOPZLQC
CRDMPMNSQ5IALD7Y5TVHZE6KFFTWFPP33DWMBVRPDHP7HD2SLTPAC
4QUF4MKRSB5LYYS5FSYTCDSIEMYIERI2BQZLRGJ3GIGVYCPJVEPAC
UXGT6OW6ENH6SWLVRF3JVS3WGTXPTKZPVOESJAGUSSLZT2WRASBAC
QAPSVUOF7DV6R2PSLKLZUKC5TMB62ZYOUZ2NA6CHFOU6PSTJULWAC
RKY73PZWOR4BJ7HARRPKL6X5VBP2UOMYUWHPNO5G5754XML75ZHQC
YQQETCXBXPPLXBU3UPUIIKB3JZCHRFSW7PPP2DR436WVIXNXFUHAC
7HUMD4TAMWWBQDOZYCMWQXR66G3IU5WU3IVKTPCSMETSB6VREWTAC
XXOC2AY53ZWML6TVPKX6BHGKZJNRET4IWRSTCVMJQJZMK3MFD3TQC
PYI6X6HN7VRPTRIMCETLC7MOERACNHLMUJ3F5OMLLMFGTFT5F2IQC
CENV55CAVVS7AIEOACYGIHLOJBGBX7GGSYJRU6GZ2XEMKYNUWGLQC
KTZQPN4Y5YMJV72M54WVFCA6ZL6MIEMARZRIJBWQV5FY3A6S7OGAC
RLFTJX3XEX5I2N5JDVBBYRN4INKH7MQGKC5SNJ4QFR243TRYKDXQC
EQRGODLKSVSPFSUZU7BV5ER72U4QS4ATSBKV544XXQVKKTOSC7EAC
34TOMU43GSVTGKBSPBPRFLQYCJZ35HV2BNHKUAJ6CPE4XZLADCLQC
AW7XCEBTLPKA5YP4T5P5SXX47QVPYETDFBSLV6KMJZNKN7BLO2EQC
DVIBBDIRHCREHHOHZNQ2L3JJTW6GRSUGBHDJD2OKUBHWIBJ5WJUQC
HGITBD7RZVPMWWPLFXDXW53LO5MWD4RVS77ZBFLORUIJMJ35IVDQC
N54JKDQTHG2GSXAXR6PGMVVEKAHLKENNDSQ2IUGKQUDHGA72J4XQC
HQ7H76DZBXQOQEYAB7WD76B5R6KSY65ANHC5XTLDDMPJ7KPYCOAAC
DI2TRANVC5E5BKZAW2LTC355YI7O3VI32XB3PGBHU4V4X75325EQC
CFECX3NOTBCQGTC7ZJOF2IAEJF55SZPHZJN57OZLPMZT24ERFIXQC
ZEKBZDRVZJFHG75HZQVVQHO4G7RIY5OZTSI5G3BWIF566BRQBXHAC
CD2JEM3MH5BXN7ADZAWLJFTRZG7PMDCKISDNJEO472PIBEJHBH2AC
3ZTG6CX4LPFTAV4AKALPCMGUCEA3XDE3O4LVTCBAQJDTBYO5ABCAC
WWZVYE7LMUCWGQVPLJQQBD3ZNLJHGMMQJTLXXOAEXA7ETSXIHCQAC
HONIZT6S2TNUT5XHRNWAJELT244HYO2WXYGRINBT6OONLTQ52JOQC
V27TVOIQEKBQ5YYJUV4F762WEDPB2XYPWDYZRCAR5B65F3NDFTKAC
HSAZJTBIAQFXHRMPSE6VZXIJFJTHG2LWAIPKIOER2NKCEMFHQMOQC
YDFL47ANP2XUUHFLKSWQNG6FTRQAOYQMRE5DPGEDFKDHKZEEMLCQC
WMN7AWGSUJORMCEMVPKDN22OK5WXUMLOKOG55RGBVPUIPSADXFZAC
struct listens* append_listener(struct wl_listener* l, struct listens* ls);
struct listens* remove_listener(struct wl_listener* l, struct listens* ls);
}
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;
#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)
#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;
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 /* 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\"");
}
#endif
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 \
.SUFFIXES: .c .so
.c.so:
$(CC) $(CPPFLAGS) $(DWLCFLAGS) -o $@ -shared -DHOT $<