Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/filemanager/boxes.c
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,16 @@ task_cb (WButton *button, int action)
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */

/* Re-read the currently configured skin from disk and redraw. Used to hot-reload
the skin file when it changes on disk (see the skin_watch_* functions in main.c). */
void
mc_skin_reload (void)
{
skin_apply (NULL);
}

/* --------------------------------------------------------------------------------------------- */

void
about_box (void)
{
Expand Down
1 change: 1 addition & 0 deletions src/filemanager/boxes.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

/*** declarations of public functions ************************************************************/

void mc_skin_reload (void);
void about_box (void);
void configure_box (void);
void appearance_box (void);
Expand Down
85 changes: 85 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#include <config.h>

#include <errno.h>
#include <locale.h>
#include <pwd.h> // for username in xterm title
#include <stdio.h>
Expand All @@ -40,6 +41,9 @@
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h> // getsid()
#ifdef __linux__
#include <sys/inotify.h> // skin hot-reload watch
#endif

#include "lib/global.h"

Expand All @@ -60,6 +64,7 @@
#include "filemanager/ext.h" // flush_extension_file()
#include "filemanager/command.h" // cmdline
#include "filemanager/panel.h" // panalized_panel
#include "filemanager/boxes.h" // mc_skin_reload()

#ifdef USE_INTERNAL_EDIT
#include "editor/edit.h" // edit_arg_free()
Expand Down Expand Up @@ -90,10 +95,82 @@

/*** file scope variables ************************************************************************/

#ifdef __linux__
// Hot-reload: watch the active skin file and re-apply it on change.
static int skin_watch_fd = -1;
#endif

/* --------------------------------------------------------------------------------------------- */
/*** file scope functions ************************************************************************/
/* --------------------------------------------------------------------------------------------- */

#ifdef __linux__

/* Arm the watch on whatever skin file is currently loaded. Only called once,
at startup: our write pattern (in-place truncate+write, not rename) never
invalidates the watch descriptor, so there is nothing to re-arm on reload.
(Calling inotify_rm_watch() from the event callback would itself raise
IN_IGNORED on the same fd, which the next select() sees immediately --
an infinite self-triggering loop.) */
static void
skin_watch_arm (void)
{
if (mc_skin__default.config == NULL || mc_skin__default.config->ini_path == NULL)
return;

inotify_add_watch (skin_watch_fd, mc_skin__default.config->ini_path,
IN_MODIFY | IN_CLOSE_WRITE);
}

/* --------------------------------------------------------------------------------------------- */

static int
skin_watch_callback (int fd, void *info)
{
char buf[4096] __attribute__ ((aligned (__alignof__ (struct inotify_event))));

(void) info;

// Drain all pending events before acting; a plain "w" rewrite of the skin
// file typically raises both IN_MODIFY and IN_CLOSE_WRITE for one save.
while (read (fd, buf, sizeof (buf)) > 0)
;

mc_skin_reload ();

return 0;
}

/* --------------------------------------------------------------------------------------------- */

static void
skin_watch_init (void)
{
skin_watch_fd = inotify_init1 (IN_NONBLOCK | IN_CLOEXEC);
if (skin_watch_fd < 0)
return;

skin_watch_arm ();
add_select_channel (skin_watch_fd, skin_watch_callback, NULL);
}

/* --------------------------------------------------------------------------------------------- */

static void
skin_watch_deinit (void)
{
if (skin_watch_fd < 0)
return;

delete_select_channel (skin_watch_fd);
close (skin_watch_fd);
skin_watch_fd = -1;
}

#endif // __linux__

/* --------------------------------------------------------------------------------------------- */

/** POSIX version. The only version we support. */
static void
OS_Setup (void)
Expand Down Expand Up @@ -372,6 +449,10 @@ main (int argc, char *argv[])

mc_error_message (&mcerror, NULL);

#ifdef __linux__
skin_watch_init ();
#endif

#ifdef ENABLE_SUBSHELL
// Done here to ensure that the subshell doesn't
// inherit the file descriptors opened below, etc
Expand Down Expand Up @@ -450,6 +531,10 @@ main (int argc, char *argv[])

flush_extension_file (); // does only free memory

#ifdef __linux__
skin_watch_deinit ();
#endif

mc_skin_deinit ();
tty_colors_done ();

Expand Down