]> mj.ucw.cz Git - teatimer.git/commitdiff
Add an option to kill the program we ran
authorMartin Mares <mj@ucw.cz>
Fri, 21 Jan 2022 20:51:01 +0000 (21:51 +0100)
committerMartin Mares <mj@ucw.cz>
Fri, 21 Jan 2022 20:51:17 +0000 (21:51 +0100)
Patch by Jiri Kalvoda, cleaned up by me.

NEWS
teatimer.c

diff --git a/NEWS b/NEWS
index aa6f5c592bb07dccc0e33350f6d6ead9217a7796..3246e65101dfa4e044340a93330d92cbb4eb1b59 100644 (file)
--- 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)
 
index df94fe2444e8d5428f420e213b9aab86917691df..78e72ff59142336eb954a6ec33f698be1b37fd74 100644 (file)
@@ -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=<cmd>\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=<int>\tKill run program by a given signal when the timer is stopped\n\
 -n, --timer-name=<str>\tFill name box with <str>\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;