Execp: force update after custom command execution (issue #586)

This commit is contained in:
o9000 2016-08-08 12:04:31 +02:00
parent a09e1a0e45
commit da51d37322
6 changed files with 100 additions and 57 deletions

View file

@ -32,12 +32,11 @@ Execp *create_execp()
Execp *execp = calloc(1, sizeof(Execp)); Execp *execp = calloc(1, sizeof(Execp));
execp->backend = calloc(1, sizeof(ExecpBackend)); execp->backend = calloc(1, sizeof(ExecpBackend));
execp->backend->child_pipe = -1; execp->backend->child_pipe = -1;
execp->backend->cmd_pids = g_tree_new(cmp_ptr);
execp->backend->interval = 30; execp->backend->interval = 30;
execp->backend->cache_icon = TRUE; execp->backend->cache_icon = TRUE;
execp->backend->centered = TRUE; execp->backend->centered = TRUE;
execp->backend->font_color.alpha = 0.5; execp->backend->font_color.alpha = 0.5;
return execp; return execp;
} }
@ -83,6 +82,10 @@ void destroy_execp(void *obj)
close(execp->backend->child_pipe); close(execp->backend->child_pipe);
execp->backend->child_pipe = -1; 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; execp->backend->bg = NULL;
pango_font_description_free(execp->backend->font_desc); pango_font_description_free(execp->backend->font_desc);
@ -467,6 +470,18 @@ void execp_dump_geometry(void *obj, int indent)
execp->backend->text); 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) void execp_action(void *obj, int button, int x, int y)
{ {
Execp *execp = obj; Execp *execp = obj;
@ -498,20 +513,32 @@ void execp_action(void *obj, int button, int x, int y)
execp->area.width, execp->area.width,
execp->area.height, execp->area.height,
command); 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); g_free(full_cmd);
} else { } else {
if (execp->backend->child_pipe > 0) { execp_force_update(execp);
// 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_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) void execp_timer_callback(void *arg)
{ {
Execp *execp = arg; Execp *execp = arg;

View file

@ -70,6 +70,7 @@ typedef struct ExecpBackend {
// List of Execp which are frontends for this backend, one for each panel // List of Execp which are frontends for this backend, one for each panel
GList *instances; GList *instances;
GTree *cmd_pids;
} ExecpBackend; } ExecpBackend;
typedef struct ExecpFrontend { typedef struct ExecpFrontend {
@ -130,6 +131,8 @@ gboolean resize_execp(void *obj);
// Called on mouse click event. // Called on mouse click event.
void execp_action(void *obj, int button, int x, int y); 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. // Called to check if new output from the command can be read.
// No command might be running. // No command might be running.
// Returns 1 if the output has been updated and a redraw is needed. // Returns 1 if the output has been updated and a redraw is needed.

View file

@ -140,6 +140,11 @@ void cleanup_server()
XFreeGC(server.display, server.gc); XFreeGC(server.display, server.gc);
server.gc = NULL; server.gc = NULL;
server.disable_transparency = FALSE; 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) void send_event32(Window win, Atom at, long data1, long data2, long data3)

View file

@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**************************************************************************/ **************************************************************************/
#include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
@ -376,8 +377,8 @@ void init(int argc, char *argv[])
debug_geometry = getenv("DEBUG_GEOMETRY") != NULL; debug_geometry = getenv("DEBUG_GEOMETRY") != NULL;
} }
static int sn_pipe_valid = 0; static int sigchild_pipe_valid = FALSE;
static int sn_pipe[2]; static int sigchild_pipe[2];
#ifdef HAVE_SN #ifdef HAVE_SN
static int error_trap_depth = 0; static int error_trap_depth = 0;
@ -397,50 +398,41 @@ static void error_trap_pop(SnDisplay *display, Display *xdisplay)
XSync(xdisplay, False); /* get all errors out of the queue */ XSync(xdisplay, False); /* get all errors out of the queue */
--error_trap_depth; --error_trap_depth;
} }
#endif // HAVE_SN
static void sigchld_handler(int sig) static void sigchld_handler(int sig)
{ {
if (!startup_notifications) if (!sigchild_pipe_valid)
return; return;
if (!sn_pipe_valid) int savedErrno = errno;
return; ssize_t unused = write(sigchild_pipe[1], "x", 1);
ssize_t wur = write(sn_pipe[1], "x", 1); (void)unused;
(void)wur; fsync(sigchild_pipe[1]);
fsync(sn_pipe[1]); errno = savedErrno;
} }
static void sigchld_handler_async() static void sigchld_handler_async()
{ {
if (!startup_notifications)
return;
// Wait for all dead processes // Wait for all dead processes
pid_t pid; pid_t pid;
while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { int status;
SnLauncherContext *ctx; while ((pid = waitpid(-1, &status, WNOHANG)) != -1) {
ctx = (SnLauncherContext *)g_tree_lookup(server.pids, GINT_TO_POINTER(pid)); #ifdef HAVE_SN
SnLauncherContext *ctx = (SnLauncherContext *)g_tree_lookup(server.pids, GINT_TO_POINTER(pid));
if (ctx) { if (ctx) {
g_tree_remove(server.pids, GINT_TO_POINTER(pid)); g_tree_remove(server.pids, GINT_TO_POINTER(pid));
sn_launcher_context_complete(ctx); sn_launcher_context_complete(ctx);
sn_launcher_context_unref(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() void init_X11_pre_config()
{ {
server.display = XOpenDisplay(NULL); server.display = XOpenDisplay(NULL);
@ -475,25 +467,32 @@ void init_X11_post_config()
{ {
server_init_visual(); server_init_visual();
gboolean need_sigchld = FALSE;
#ifdef HAVE_SN #ifdef HAVE_SN
// Initialize startup-notification // Initialize startup-notification
if (startup_notifications) { if (startup_notifications) {
server.sn_display = sn_display_new(server.display, error_trap_push, error_trap_pop); server.sn_display = sn_display_new(server.display, error_trap_push, error_trap_pop);
server.pids = g_tree_new(cmp_ptr); 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 // Setup a handler for child termination
if (pipe(sn_pipe) != 0) { if (pipe(sigchild_pipe) != 0) {
fprintf(stderr, "Creating pipe failed.\n"); fprintf(stderr, "Creating pipe failed.\n");
} else { } else {
fcntl(sn_pipe[0], F_SETFL, O_NONBLOCK | fcntl(sn_pipe[0], F_GETFL)); fcntl(sigchild_pipe[0], F_SETFL, O_NONBLOCK | fcntl(sigchild_pipe[0], F_GETFL));
fcntl(sn_pipe[1], F_SETFL, O_NONBLOCK | fcntl(sn_pipe[1], F_GETFL)); fcntl(sigchild_pipe[1], F_SETFL, O_NONBLOCK | fcntl(sigchild_pipe[1], F_GETFL));
sn_pipe_valid = 1; sigchild_pipe_valid = 1;
struct sigaction act = {.sa_handler = sigchld_handler, .sa_flags = SA_RESTART}; struct sigaction act = {.sa_handler = sigchld_handler, .sa_flags = SA_RESTART};
if (sigaction(SIGCHLD, &act, 0)) { if (sigaction(SIGCHLD, &act, 0)) {
perror("sigaction"); perror("sigaction");
} }
} }
} }
#endif // HAVE_SN
imlib_context_set_display(server.display); imlib_context_set_display(server.display);
imlib_context_set_visual(server.visual); imlib_context_set_visual(server.visual);
@ -543,15 +542,11 @@ void cleanup()
XCloseDisplay(server.display); XCloseDisplay(server.display);
server.display = NULL; server.display = NULL;
#ifdef HAVE_SN if (sigchild_pipe_valid) {
if (startup_notifications) { sigchild_pipe_valid = FALSE;
if (sn_pipe_valid) { close(sigchild_pipe[1]);
sn_pipe_valid = 0; close(sigchild_pipe[0]);
close(sn_pipe[1]);
close(sn_pipe[0]);
}
} }
#endif
uevent_cleanup(); uevent_cleanup();
} }
@ -1641,9 +1636,9 @@ start:
FD_ZERO(&fdset); FD_ZERO(&fdset);
FD_SET(x11_fd, &fdset); FD_SET(x11_fd, &fdset);
int maxfd = x11_fd; int maxfd = x11_fd;
if (sn_pipe_valid) { if (sigchild_pipe_valid) {
FD_SET(sn_pipe[0], &fdset); FD_SET(sigchild_pipe[0], &fdset);
maxfd = maxfd < sn_pipe[0] ? sn_pipe[0] : maxfd; maxfd = maxfd < sigchild_pipe[0] ? sigchild_pipe[0] : maxfd;
} }
for (GList *l = panel_config.execp_list; l; l = l->next) { for (GList *l = panel_config.execp_list; l; l = l->next) {
Execp *execp = (Execp *)l->data; Execp *execp = (Execp *)l->data;
@ -1664,9 +1659,9 @@ start:
if (XPending(server.display) > 0 || select(maxfd + 1, &fdset, 0, 0, select_timeout) >= 0) { if (XPending(server.display) > 0 || select(maxfd + 1, &fdset, 0, 0, select_timeout) >= 0) {
uevent_handler(); uevent_handler();
if (sn_pipe_valid) { if (sigchild_pipe_valid) {
char buffer[1]; char buffer[1];
while (read(sn_pipe[0], buffer, sizeof(buffer)) > 0) { while (read(sigchild_pipe[0], buffer, sizeof(buffer)) > 0) {
sigchld_handler_async(); sigchld_handler_async();
} }
} }

View file

@ -673,3 +673,13 @@ GSList *slist_remove_duplicates(GSList *list, GCompareFunc eq, GDestroyNotify fr
return new_list; return new_list;
} }
gint cmp_ptr(gconstpointer a, gconstpointer b)
{
if (a < b)
return -1;
else if (a == b)
return 0;
else
return 1;
}

View file

@ -120,6 +120,9 @@ GSList *load_locations_from_env(GSList *locations, const char *var, ...);
GSList *slist_remove_duplicates(GSList *list, GCompareFunc eq, GDestroyNotify fr); 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) \ #define free_and_null(p) \
{ \ { \
free(p); \ free(p); \