diff --git a/README.md b/README.md index c5e6492..7cddb47 100644 --- a/README.md +++ b/README.md @@ -190,3 +190,16 @@ See the [Configuration] document for information on the options. ## Running Run [`wayfire`][Manual] from a TTY, or via a Wayland-compatible login manager. + + +## 0.11.0-r78 (Hedron Sprint 3) + +The launcher selects the optional Hedron-owned seed for new accounts, preserving +existing configs and the Wayfire fallback. Versioned launcher/desktop/helper +inputs leave older ebuilds unchanged. Compatibility helpers prefer Hedron and +fall back to legacy implementations. Login says Hedronfire; DesktopNames=Wayfire +stays. No dependency on the shell is introduced. + +`wayfire/exit` schedules shutdown of this compositor after its response, with +core/exit's inhibited-output guard. Config monitoring follows atomically +replaced symlink targets again. diff --git a/plugins/ipc/ipc.cpp b/plugins/ipc/ipc.cpp index fd4f63f..3c12577 100644 --- a/plugins/ipc/ipc.cpp +++ b/plugins/ipc/ipc.cpp @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include #include #include @@ -406,6 +409,8 @@ class ipc_plugin_t : public wf::plugin_interface_t { private: shared_data::ref_ptr_t server; + shared_data::ref_ptr_t methods; + wl_event_source* exit_idle = nullptr; public: void init() override @@ -429,6 +434,29 @@ class ipc_plugin_t : public wf::plugin_interface_t setenv("WAYFIRE_SOCKET", socket.c_str(), 1); server->init(socket); + // Graceful logout is scoped to this IPC server's compositor. Defer + // shutdown until the response is sent; preserve core/exit's lock guard. + methods->register_method("wayfire/exit", [this] (const wf::json_t&) + { + auto output = wf::get_core().seat->get_active_output(); + if (!output || output->is_inhibited()) return ipc::json_error("Session is inhibited"); + if (!exit_idle) exit_idle = wl_event_loop_add_idle(wl_display_get_event_loop(wf::get_core().display), + [] (void* data) + { + auto self = static_cast(data); + self->exit_idle = nullptr; + auto output = wf::get_core().seat->get_active_output(); + if (output && !output->is_inhibited()) wf::get_core().shutdown(); + }, this); + return exit_idle ? ipc::json_ok() : ipc::json_error("Cannot schedule logout"); + }); + } + + void fini() override + { + methods->unregister_method("wayfire/exit"); + if (exit_idle) wl_event_source_remove(exit_idle); + exit_idle = nullptr; } bool is_unloadable() override diff --git a/src/default-config-backend.cpp b/src/default-config-backend.cpp index fb5b287..4b89ddf 100644 --- a/src/default-config-backend.cpp +++ b/src/default-config-backend.cpp @@ -23,7 +23,7 @@ static int wd_cfg_dir, wd_cfg_file; static void add_watch(int fd) { wd_cfg_dir = inotify_add_watch(fd, config_dir.c_str(), IN_CREATE | IN_MOVED_TO); - wd_cfg_file = inotify_add_watch(fd, config_file.c_str(), IN_CLOSE_WRITE); + wd_cfg_file = inotify_add_watch(fd, config_file.c_str(), IN_CLOSE_WRITE | IN_DELETE_SELF | IN_MOVE_SELF); } static const char *CONFIG_FILE_ENV = "WAYFIRE_CONFIG_FILE"; @@ -189,7 +189,17 @@ static int handle_config_updated(int fd, uint32_t mask, void *data) // We reload in two cases: // // 1. The config file itself was modified, or... - should_reload |= event->wd == wd_cfg_file; + if (event->wd == wd_cfg_file) + { + should_reload = true; + // Atomic saves may replace a symlink's target in a different + // directory. Follow the configured path again after replacement. + if (event->mask & (IN_DELETE_SELF | IN_MOVE_SELF)) + { + if (!(event->mask & IN_DELETE_SELF)) inotify_rm_watch(fd, wd_cfg_file); + wd_cfg_file = inotify_add_watch(fd, config_file.c_str(), IN_CLOSE_WRITE | IN_DELETE_SELF | IN_MOVE_SELF); + } + } // 2. The config file was moved nto or created inside the parent directory. if (event->len > 0) { @@ -200,7 +210,7 @@ static int handle_config_updated(int fd, uint32_t mask, void *data) { inotify_rm_watch(fd, wd_cfg_file); wd_cfg_file = - inotify_add_watch(fd, (config_dir + "/" + cfg_file_basename).c_str(), IN_CLOSE_WRITE); + inotify_add_watch(fd, (config_dir + "/" + cfg_file_basename).c_str(), IN_CLOSE_WRITE | IN_DELETE_SELF | IN_MOVE_SELF); } should_reload |= name_matches;