#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <time.h>
#include <getopt.h>
static guint second_timer;
static char old_text[16];
static GtkWidget *win, *hbox1, *vbox1, *timebox, *namebox, *togglebutton1;
+static PangoFontDescription *timebox_font;
+static bool autoresize_timebox_font = false;
+static int timebox_font_size;
static time_t alarm_time;
static char *run_notify;
static char *default_name = "Tea";
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]=='%')
- {
- i++;
- g_string_append_c(expanded_cmd, '%');
- }
- else
- if (cmd[i]=='%' && cmd[i+1]=='n')
- {
- i++;
- const gchar *name = gtk_entry_get_text(GTK_ENTRY(namebox));
- g_string_append(expanded_cmd, name);
- }
- else
- g_string_append_c(expanded_cmd, cmd[i]);
- }
-
GError *err = NULL;
gint argc;
gchar ** argv = NULL;
int pid;
- g_shell_parse_argv(expanded_cmd->str, &argc, &argv, &err);
- g_string_free(expanded_cmd, 1);
+ g_shell_parse_argv(cmd, &argc, &argv, &err);
+ GString ** expanded_argv = malloc(sizeof(expanded_argv[0])*argc);
+ if (!expanded_argv)
+ return 0;
+ gchar ** expanded_argv_gchar = malloc(sizeof(expanded_argv_gchar[0])*(argc+1));
if (err)
{
- fprintf(stderr, "teatimer: Unable to run command: %s\n", err->message);
+ fprintf(stderr, "teatimer: Unable to parse 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);
+ if(!expanded_argv_gchar) return 0;
+ for (int i=0; i<argc; i++)
+ {
+ expanded_argv[i] = g_string_new("");
+ for (int j=0; argv[i][j]; j++)
+ {
+ if (argv[i][j]=='%' && argv[i][j+1]=='%')
+ {
+ j++;
+ g_string_append_c(expanded_argv[i], '%');
+ }
+ else
+ if (argv[i][j]=='%' && argv[i][j+1]=='n')
+ {
+ j++;
+ const gchar * name = gtk_entry_get_text(GTK_ENTRY(namebox));
+ g_string_append(expanded_argv[i], name);
+ }
+ else
+ g_string_append_c(expanded_argv[i], argv[i][j]);
+ }
+ expanded_argv_gchar[i] = expanded_argv[i]->str;
+ }
+ expanded_argv_gchar[argc]=NULL;
+ g_spawn_async(NULL, expanded_argv_gchar, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &pid, &err);
g_strfreev(argv);
+ for (int i=0; i<argc; i++)
+ g_string_free(expanded_argv[i], 1);
if (err)
{
fprintf(stderr, "teatimer: Unable to run command: %s\n", err->message);
quit();
}
+static void
+set_timebox_font_size(int new_size)
+{
+ if (new_size == timebox_font_size)
+ return;
+ timebox_font_size = new_size;
+
+ pango_font_description_set_size(timebox_font, timebox_font_size*PANGO_SCALE);
+ gtk_widget_modify_font(timebox, timebox_font);
+}
+
+static void
+on_window_resized(GtkWidget *widget UNUSED, GdkRectangle *rect, gpointer user_data UNUSED)
+{
+ int window_width = rect->width;
+ int window_height = rect->height;
+
+ if (autoresize_timebox_font)
+ {
+ // Binary search for optimal font size
+ int beg = 12, end = 1024;
+ while (beg < end)
+ {
+ int mid = (beg + end) / 2;
+ pango_font_description_set_size(timebox_font, mid*PANGO_SCALE);
+ PangoFontMetrics *metric = pango_context_get_metrics(gtk_widget_get_pango_context(timebox), timebox_font, NULL);
+ int width = pango_font_metrics_get_approximate_digit_width(metric) * 8.3 / PANGO_SCALE;
+ int height = pango_font_metrics_get_height(metric) / PANGO_SCALE;
+ if (width > window_width - 50 || height > window_height - 45)
+ end = mid;
+ else
+ beg = mid + 1;
+ }
+
+ set_timebox_font_size(beg);
+ }
+}
+
static void
open_window(void)
{
gtk_widget_show(timebox);
gtk_box_pack_start(GTK_BOX(vbox1), timebox, TRUE, TRUE, 0);
gtk_entry_set_text(GTK_ENTRY(timebox), "00:00");
+ timebox_font = pango_font_description_from_string("Monospace");
+ set_timebox_font_size(12);
togglebutton1 = gtk_toggle_button_new_with_label("Run");
gtk_widget_show(togglebutton1);
gtk_box_pack_start(GTK_BOX(hbox1), togglebutton1, FALSE, FALSE, 0);
gtk_signal_connect(GTK_OBJECT(win), "remove", GTK_SIGNAL_FUNC(on_window_remove), NULL);
+ gtk_signal_connect(GTK_OBJECT(win), "size-allocate", GTK_SIGNAL_FUNC(on_window_resized), NULL);
gtk_signal_connect(GTK_OBJECT(namebox), "key_press_event", GTK_SIGNAL_FUNC(on_box_key), NULL);
gtk_signal_connect(GTK_OBJECT(timebox), "key_press_event", GTK_SIGNAL_FUNC(on_box_key), NULL);
gtk_signal_connect(GTK_OBJECT(togglebutton1), "toggled", GTK_SIGNAL_FUNC(on_togglebutton1_toggled), NULL);
gtk_widget_show(win);
}
-static const char short_opts[] = "r:n:k:";
+static const char short_opts[] = "r:n:k:a";
static const struct option long_opts[] = {
{ "run", required_argument, NULL, 'r' },
{ "kill", required_argument, NULL, 'k' },
{ "timer-name", required_argument, NULL, 'n' },
+ { "auto-resize", no_argument, NULL, 'a' },
{ NULL, 0, NULL, 0 },
};
\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\
+-a, --auto-resize\tAutomatically resize font to fit the box\n\
");
exit(1);
}
case 'n':
default_name = optarg;
break;
+ case 'a':
+ autoresize_timebox_font = true;
+ break;
default:
usage();
}