From: Martin Mares Date: Fri, 21 Jan 2022 20:51:01 +0000 (+0100) Subject: Add an option to kill the program we ran X-Git-Tag: v1.4~1 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;ds=sidebyside;h=7a016a787864a3291a5c9ff0b42cbb179459a4fc;p=teatimer.git Add an option to kill the program we ran Patch by Jiri Kalvoda, cleaned up by me. --- diff --git a/NEWS b/NEWS index aa6f5c5..3246e65 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ Version 1.4 (2021-07-13) o Added name box. You can specify which tea you make. + o Added kill feature. You can kill the notification program after + you remove tea bag from water. Version 1.3 (2013-10-07) diff --git a/teatimer.c b/teatimer.c index df94fe2..78e72ff 100644 --- a/teatimer.c +++ b/teatimer.c @@ -22,14 +22,41 @@ static guint second_timer; static char old_text[16]; static GtkWidget *win, *hbox1, *vbox1, *timebox, *namebox, *togglebutton1; static time_t alarm_time; -static char *run_cmd; +static char *run_notify; static char *default_name = "Tea"; static int expired; +static int notify_pid = 0; +static gint notify_watch = 0; +static int kill_notify_by = 0; static void +kill_notify(void) +{ + if (kill_notify_by && notify_pid) + { + kill(notify_pid, kill_notify_by); + notify_pid = 0; + } + if (notify_watch) + { + g_source_remove(notify_watch); + notify_watch = 0; + } +} + +static void +quit(void) +{ + kill_notify(); + gtk_main_quit(); +} + +static int // return pid of new process or 0 if failed expand_and_exec(char *cmd) { GString *expanded_cmd = g_string_new(""); + if (!expanded_cmd) + return 0; for (int i=0; cmd[i]; i++) { if (cmd[i]=='%' && cmd[i+1]=='%') @@ -49,23 +76,47 @@ expand_and_exec(char *cmd) } GError *err = NULL; - g_spawn_command_line_async(expanded_cmd->str, &err); + gint argc; + gchar ** argv = NULL; + int pid; + + g_shell_parse_argv(expanded_cmd->str, &argc, &argv, &err); g_string_free(expanded_cmd, 1); if (err) { fprintf(stderr, "teatimer: Unable to run command: %s\n", err->message); g_error_free(err); + return 0; + } + g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &pid, &err); + g_strfreev(argv); + if (err) + { + fprintf(stderr, "teatimer: Unable to run command: %s\n", err->message); + g_error_free(err); + return 0; } + return pid; +} + +static void +notify_exit(GPid pid, gint status UNUSED, gpointer data UNUSED) +{ + if (notify_pid == pid) + notify_pid = 0; } static void it_tolls_for_thee(void) { - if (run_cmd) + if (run_notify) { if (!expired) { - expand_and_exec(run_cmd); + if(notify_watch) + g_source_remove(notify_watch); + notify_pid = expand_and_exec(run_notify); + notify_watch = g_child_watch_add(notify_pid, notify_exit, NULL); expired = 1; } } @@ -106,7 +157,7 @@ on_box_key(GtkWidget *widget UNUSED, GdkEventKey *ev, gpointer user_data UNUSED) if (!strcmp(ev->string, "\r")) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(togglebutton1), !GTK_TOGGLE_BUTTON(togglebutton1)->active); else if (!strcmp(ev->string, "\033")) - gtk_main_quit(); + quit(); return FALSE; } @@ -166,6 +217,7 @@ on_togglebutton1_toggled(GtkToggleButton *togglebutton, gpointer user_data UNUSE gtk_timeout_remove(second_timer); second_timer = 0; } + kill_notify(); gtk_entry_set_text(GTK_ENTRY(timebox), old_text); gtk_entry_set_editable(GTK_ENTRY(timebox), 1); gtk_widget_grab_focus(timebox); @@ -175,7 +227,7 @@ on_togglebutton1_toggled(GtkToggleButton *togglebutton, gpointer user_data UNUSE static void on_window_remove(GtkContainer *container UNUSED, GtkWidget *widget UNUSED, gpointer user_data UNUSED) { - gtk_main_quit(); + quit(); } static void @@ -222,10 +274,11 @@ open_window(void) gtk_widget_show(win); } -static const char short_opts[] = "r:n:"; +static const char short_opts[] = "r:n:k:"; static const struct option long_opts[] = { { "run", required_argument, NULL, 'r' }, + { "kill", required_argument, NULL, 'k' }, { "timer-name", required_argument, NULL, 'n' }, { NULL, 0, NULL, 0 }, }; @@ -238,23 +291,39 @@ Options:\n\ -r, --run=\t\tRun a given program when the tea is ready\n\ \t\t\t\t%%d will be expanded to timer name\n\ \t\t\t\t%%%% will be expanded to %%\n\ +-k, --kill=\tKill run program by a given signal when the timer is stopped\n\ -n, --timer-name=\tFill name box with \n\ "); exit(1); } +void sig_handler(int signo) +{ + if (signo == SIGINT || signo == SIGTERM) + { + kill_notify(); + exit(0); + } +} + int main(int argc, char **argv) { gtk_set_locale(); gtk_init(&argc, &argv); + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + int opt; while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) >= 0) switch (opt) { case 'r': - run_cmd = optarg; + run_notify = optarg; + break; + case 'k': + kill_notify_by = atoi(optarg); break; case 'n': default_name = optarg;