all repos — tint2 @ da51d3732292a19fbc17e50e920b49adb9443d60

fork of the tint2 desktop panel for my custom setup - only minimized windows across all desktops for the taskbar

Execp: force update after custom command execution (issue #586)
o9000 mrovi9000@gmail.com
commit

da51d3732292a19fbc17e50e920b49adb9443d60

parent

a09e1a0e45d67d64b99406fd834b98d46cbd7db0

M src/execplugin/execplugin.csrc/execplugin/execplugin.c

@@ -32,12 +32,11 @@ {

Execp *execp = calloc(1, sizeof(Execp)); execp->backend = calloc(1, sizeof(ExecpBackend)); execp->backend->child_pipe = -1; - + execp->backend->cmd_pids = g_tree_new(cmp_ptr); execp->backend->interval = 30; execp->backend->cache_icon = TRUE; execp->backend->centered = TRUE; execp->backend->font_color.alpha = 0.5; - return execp; }

@@ -82,6 +81,10 @@ }

if (execp->backend->child_pipe >= 0) { close(execp->backend->child_pipe); execp->backend->child_pipe = -1; + } + if (execp->backend->cmd_pids) { + g_tree_destroy(execp->backend->cmd_pids); + execp->backend->cmd_pids = NULL; } execp->backend->bg = NULL;

@@ -467,6 +470,18 @@ execp->backend->centered ? "center" : "left",

execp->backend->text); } +void execp_force_update(Execp *execp) +{ + if (execp->backend->child_pipe > 0) { + // Command currently running, nothing to do + } else { + if (execp->backend->timer) + stop_timeout(execp->backend->timer); + // Run command right away + execp->backend->timer = add_timeout(10, 0, execp_timer_callback, execp, &execp->backend->timer); + } +} + void execp_action(void *obj, int button, int x, int y) { Execp *execp = obj;

@@ -498,18 +513,30 @@ y,

execp->area.width, execp->area.height, command); - tint_exec(full_cmd); + pid_t pid = fork(); + if (pid < 0) { + fprintf(stderr, "Could not fork\n"); + } else if (pid == 0) { + // Child process + // Allow children to exist after parent destruction + setsid(); + // Run the command + execl("/bin/sh", "/bin/sh", "-c", full_cmd, NULL); + fprintf(stderr, "Failed to execlp %s\n", full_cmd); + exit(1); + } + // Parent process + g_tree_insert(execp->backend->cmd_pids, GINT_TO_POINTER(pid), GINT_TO_POINTER(1)); g_free(full_cmd); } else { - if (execp->backend->child_pipe > 0) { - // Command currently running, nothing to do - } else { - if (execp->backend->timer) - stop_timeout(execp->backend->timer); - // Run command right away - execp->backend->timer = add_timeout(10, 0, execp_timer_callback, execp, &execp->backend->timer); - } + execp_force_update(execp); } +} + +void execp_cmd_completed(Execp *execp, pid_t pid) +{ + g_tree_remove(execp->backend->cmd_pids, GINT_TO_POINTER(pid)); + execp_force_update(execp); } void execp_timer_callback(void *arg)
M src/execplugin/execplugin.hsrc/execplugin/execplugin.h

@@ -70,6 +70,7 @@ time_t last_update_duration;

// List of Execp which are frontends for this backend, one for each panel GList *instances; + GTree *cmd_pids; } ExecpBackend; typedef struct ExecpFrontend {

@@ -129,6 +130,8 @@ gboolean resize_execp(void *obj);

// Called on mouse click event. void execp_action(void *obj, int button, int x, int y); + +void execp_cmd_completed(Execp *obj, pid_t pid); // Called to check if new output from the command can be read. // No command might be running.
M src/server.csrc/server.c

@@ -140,6 +140,11 @@ if (server.gc)

XFreeGC(server.display, server.gc); server.gc = NULL; server.disable_transparency = FALSE; +#ifdef HAVE_SN + if (server.pids) + g_tree_destroy(server.pids); + server.pids = NULL; +#endif } void send_event32(Window win, Atom at, long data1, long data2, long data3)
M src/tint.csrc/tint.c

@@ -18,6 +18,7 @@ * along with this program; if not, write to the Free Software

* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **************************************************************************/ +#include <errno.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h>

@@ -376,8 +377,8 @@

debug_geometry = getenv("DEBUG_GEOMETRY") != NULL; } -static int sn_pipe_valid = 0; -static int sn_pipe[2]; +static int sigchild_pipe_valid = FALSE; +static int sigchild_pipe[2]; #ifdef HAVE_SN static int error_trap_depth = 0;

@@ -397,50 +398,41 @@

XSync(xdisplay, False); /* get all errors out of the queue */ --error_trap_depth; } +#endif // HAVE_SN static void sigchld_handler(int sig) { - if (!startup_notifications) + if (!sigchild_pipe_valid) return; - if (!sn_pipe_valid) - return; - ssize_t wur = write(sn_pipe[1], "x", 1); - (void)wur; - fsync(sn_pipe[1]); + int savedErrno = errno; + ssize_t unused = write(sigchild_pipe[1], "x", 1); + (void)unused; + fsync(sigchild_pipe[1]); + errno = savedErrno; } static void sigchld_handler_async() { - if (!startup_notifications) - return; // Wait for all dead processes pid_t pid; - while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { - SnLauncherContext *ctx; - ctx = (SnLauncherContext *)g_tree_lookup(server.pids, GINT_TO_POINTER(pid)); + int status; + while ((pid = waitpid(-1, &status, WNOHANG)) != -1) { +#ifdef HAVE_SN + SnLauncherContext *ctx = (SnLauncherContext *)g_tree_lookup(server.pids, GINT_TO_POINTER(pid)); if (ctx) { g_tree_remove(server.pids, GINT_TO_POINTER(pid)); sn_launcher_context_complete(ctx); sn_launcher_context_unref(ctx); } +#endif + for (GList *l = panel_config.execp_list; l; l = l->next) { + Execp *execp = (Execp *)l->data; + if (g_tree_lookup(execp->backend->cmd_pids, GINT_TO_POINTER(pid))) + execp_cmd_completed(execp, pid); + } } } -static gint cmp_ptr(gconstpointer a, gconstpointer b) -{ - if (a < b) - return -1; - else if (a == b) - return 0; - else - return 1; -} -#else -static void sigchld_handler_async() -{ -} -#endif // HAVE_SN - void init_X11_pre_config() { server.display = XOpenDisplay(NULL);

@@ -475,25 +467,32 @@ void init_X11_post_config()

{ server_init_visual(); + gboolean need_sigchld = FALSE; #ifdef HAVE_SN // Initialize startup-notification if (startup_notifications) { server.sn_display = sn_display_new(server.display, error_trap_push, error_trap_pop); server.pids = g_tree_new(cmp_ptr); + need_sigchld = TRUE; + } +#endif // HAVE_SN + if (panel_config.execp_list) + need_sigchld = TRUE; + + if (need_sigchld) { // Setup a handler for child termination - if (pipe(sn_pipe) != 0) { + if (pipe(sigchild_pipe) != 0) { fprintf(stderr, "Creating pipe failed.\n"); } else { - fcntl(sn_pipe[0], F_SETFL, O_NONBLOCK | fcntl(sn_pipe[0], F_GETFL)); - fcntl(sn_pipe[1], F_SETFL, O_NONBLOCK | fcntl(sn_pipe[1], F_GETFL)); - sn_pipe_valid = 1; + fcntl(sigchild_pipe[0], F_SETFL, O_NONBLOCK | fcntl(sigchild_pipe[0], F_GETFL)); + fcntl(sigchild_pipe[1], F_SETFL, O_NONBLOCK | fcntl(sigchild_pipe[1], F_GETFL)); + sigchild_pipe_valid = 1; struct sigaction act = {.sa_handler = sigchld_handler, .sa_flags = SA_RESTART}; if (sigaction(SIGCHLD, &act, 0)) { perror("sigaction"); } } } -#endif // HAVE_SN imlib_context_set_display(server.display); imlib_context_set_visual(server.visual);

@@ -543,15 +542,11 @@ if (server.display)

XCloseDisplay(server.display); server.display = NULL; -#ifdef HAVE_SN - if (startup_notifications) { - if (sn_pipe_valid) { - sn_pipe_valid = 0; - close(sn_pipe[1]); - close(sn_pipe[0]); - } + if (sigchild_pipe_valid) { + sigchild_pipe_valid = FALSE; + close(sigchild_pipe[1]); + close(sigchild_pipe[0]); } -#endif uevent_cleanup(); }

@@ -1641,9 +1636,9 @@ fd_set fdset;

FD_ZERO(&fdset); FD_SET(x11_fd, &fdset); int maxfd = x11_fd; - if (sn_pipe_valid) { - FD_SET(sn_pipe[0], &fdset); - maxfd = maxfd < sn_pipe[0] ? sn_pipe[0] : maxfd; + if (sigchild_pipe_valid) { + FD_SET(sigchild_pipe[0], &fdset); + maxfd = maxfd < sigchild_pipe[0] ? sigchild_pipe[0] : maxfd; } for (GList *l = panel_config.execp_list; l; l = l->next) { Execp *execp = (Execp *)l->data;

@@ -1664,9 +1659,9 @@ // Wait for X Event or a Timer

if (XPending(server.display) > 0 || select(maxfd + 1, &fdset, 0, 0, select_timeout) >= 0) { uevent_handler(); - if (sn_pipe_valid) { + if (sigchild_pipe_valid) { char buffer[1]; - while (read(sn_pipe[0], buffer, sizeof(buffer)) > 0) { + while (read(sigchild_pipe[0], buffer, sizeof(buffer)) > 0) { sigchld_handler_async(); } }
M src/util/common.csrc/util/common.c

@@ -673,3 +673,13 @@ g_slist_free_full(list, fr);

return new_list; } + +gint cmp_ptr(gconstpointer a, gconstpointer b) +{ + if (a < b) + return -1; + else if (a == b) + return 0; + else + return 1; +}
M src/util/common.hsrc/util/common.h

@@ -120,6 +120,9 @@ GSList *load_locations_from_env(GSList *locations, const char *var, ...);

GSList *slist_remove_duplicates(GSList *list, GCompareFunc eq, GDestroyNotify fr); +// A trivial pointer comparator. +gint cmp_ptr(gconstpointer a, gconstpointer b); + #define free_and_null(p) \ { \ free(p); \