update hot-reload README with a more comprehensive explanation of how to integrate it with other patches.

This commit is contained in:
Sivecano 2025-05-30 02:43:50 +02:00
parent 83b68bee53
commit 50c6a46c35

View File

@ -19,7 +19,8 @@ Note that you're responsible yourself for reloading ressources like fonts, which
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.
Furthermore, any patch adding more global state to dwl cannot currently be reloaded properly since
we keep state in the cold part.
we keep state in the cold part. These patches will still work and their functionality will (hopefully) be
reloadable but you will need to restart the compositor once.
#### Notes
##### reduce compile errors
@ -30,9 +31,71 @@ So you may want to disable this compile option in order to get readable compiler
This does depend on you having a notification daemon like `dunst` or `mako` running as well as
having `notify-send` installed in order for the compositor to inform you of the reload.
#### How?
Most of all dwl functionality is moved into a shared object file `dwl.so`, which can be reloaded at runtime.
#### How do I make this work with other patches?
Most patches should already put everything in more or less the correct place but if they don't, then here is
where you learn how to fix it.
The concept itself is quite simple. We compile dwl.c twice once normally and once with the `HOT` macro defined.
The first run will yield the executable and the second will yield a shared object file to be reloaded at runtime.
From the cold part there are some newly available macros:
> symbol names are written as-is, never as string literals
* `TSYM(T, s)` dynamically loads the symbol `s` with type `T` from the shared object file use this if you need to call functions in the cold part (i.e. the `setup` function).
* `CSYM(T, v)` dynamically accesses the value of the symbol `v` of type `T` from the shared object. Use this to query values from config.h for example.
* `LISTEN_GLOBAL(E, L)` is similar to the `LISTEN` macro. `E` is an event and `L` the name of a global
listener. Current implementation is a bit messy and I may fix it if someone bothers me about it.
* `UNLISTEN(L)` takes a listener and unregisteres it. This is important for reloading.
When adding new code there are some considerations to be made. Since dwl decorates all symbols with `static` by default, we cannot access them as-is.
C's macro system is a bit too powerful though and we use this to our advantage. We will repeatedly define and
undefine a macro called `static` in order to replace the `static` keyword inside some sections.
This allows us to do less refactoring and preserve a lot of the original patch compatability since we're only
strategically adding lines.
As a general guide:
* global state should be global for the cold part and `extern` in the cold part meaning it should be inside a block like this:
```C
#ifdef HOT
#define static extern
#else
#define static
#endif
... // your global variables go here
#undef static
```
* function declarations should be visible in the hot part but not included in the cold part meaning they should be enclosed like this:
```C
#ifdef HOT
#define static
... // your function declarations go here
#undef static
#endif
```
* static data like the event handler structs in the current `main` branch are a bit more difficult but we will let them reside inside the hot part.
Thus, we enclose them the same way we do functions:
```C
#ifdef HOT
#define static
... // your struct wl_listener event handlers go here
#undef static
#endif
```
* function definitions should go in the hot part, so they need to be inside a big block like this:
```C
#ifdef HOT
... // function definitions here
#endif
* enfore use of the `LISTEN_GLOBAL` and `UNLISTEN` macros (I know this sucks but what can I do, I need to get
access to the callbacks somehow). So you want
* `wl_list_remove(listener.link)` to become `UNLISTEN(listener)` and
* `wl_signal_add(event, global_listener)` to become `LISTEN_GLOBAL(event, global)listener`.
* Make sure that any patch you're using also uses static everywhere.
Note that you do not have to create additional such feature blocks most of the time (there's a huge
`#ifdef HOT`-delimited codeblock at the bottom of dwl.c where all the function definitions go for example).
If you have any troubles, feel free to reach out.
### Download
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/hot-reload/hot-reload-0.7.patch)
- [main 2025-05-30](/dwl/dwl-patches/raw/branch/main/patches/hot-reload/hot-reload.patch)