Execp: force update after custom command execution (issue #586)
This commit is contained in:
parent
a09e1a0e45
commit
da51d37322
6 changed files with 100 additions and 57 deletions
|
@ -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,18 +513,30 @@ 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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
85
src/tint.c
85
src/tint.c
|
@ -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,49 +398,40 @@ 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()
|
||||||
{
|
{
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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); \
|
||||||
|
|
Loading…
Reference in a new issue