X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=i3-nagbar%2Fmain.c;h=6ca80ba5babfaf6f80bde744c954caca2a765bdf;hb=32e2180b56a82ed7373e4af8fc5cbf5977f3de5b;hp=1dbd77369b28a184a07ccd7973f1e0443dc57e06;hpb=6f8b2845863e9071d7d630b270729d46423c1eb5;p=i3%2Fi3 diff --git a/i3-nagbar/main.c b/i3-nagbar/main.c index 1dbd7736..6ca80ba5 100644 --- a/i3-nagbar/main.c +++ b/i3-nagbar/main.c @@ -2,15 +2,15 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) * * i3-nagbar is a utility which displays a nag message, for example in the case * when the user has an error in his configuration file. * */ -#include #include #include +#include #include #include #include @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -29,8 +30,10 @@ #include "libi3.h" #include "i3-nagbar.h" +static char *argv0 = NULL; + typedef struct { - char *label; + i3String *label; char *action; int16_t x; uint16_t width; @@ -41,7 +44,7 @@ static xcb_pixmap_t pixmap; static xcb_gcontext_t pixmap_gc; static xcb_rectangle_t rect = { 0, 0, 600, 20 }; static i3Font font; -static char *prompt; +static i3String *prompt; static button_t *buttons; static int buttoncnt; @@ -54,6 +57,27 @@ static uint32_t color_text; /* color of the text */ xcb_window_t root; xcb_connection_t *conn; +xcb_screen_t *root_screen; + +/* + * Having verboselog() and errorlog() is necessary when using libi3. + * + */ +void verboselog(char *fmt, ...) { + va_list args; + + va_start(args, fmt); + vfprintf(stdout, fmt, args); + va_end(args); +} + +void errorlog(char *fmt, ...) { + va_list args; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} /* * Starts the given application by passing it through a shell. We use double fork @@ -115,7 +139,42 @@ static void handle_button_release(xcb_connection_t *conn, xcb_button_release_eve button_t *button = get_button_at(event->event_x, event->event_y); if (!button) return; - start_application(button->action); + + /* We need to create a custom script containing our actual command + * since not every terminal emulator which is contained in + * i3-sensible-terminal supports -e with multiple arguments (and not + * all of them support -e with one quoted argument either). + * + * NB: The paths need to be unique, that is, don’t assume users close + * their nagbars at any point in time (and they still need to work). + * */ + char *script_path = get_process_filename("nagbar-cmd"); + + int fd = open(script_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (fd == -1) { + warn("Could not create temporary script to store the nagbar command"); + return; + } + FILE *script = fdopen(fd, "w"); + if (script == NULL) { + warn("Could not fdopen() temporary script to store the nagbar command"); + return; + } + fprintf(script, "#!/bin/sh\nrm %s\n%s", script_path, button->action); + /* Also closes fd */ + fclose(script); + + char *terminal_cmd; + sasprintf(&terminal_cmd, "i3-sensible-terminal -e %s", argv0); + printf("argv0 = %s\n", argv0); + printf("terminal_cmd = %s\n", terminal_cmd); + + setenv("_I3_NAGBAR_CMD", script_path, 1); + start_application(terminal_cmd); + unsetenv("_I3_NAGBAR_CMD"); + + free(terminal_cmd); + free(script_path); /* TODO: unset flag, re-render */ } @@ -132,7 +191,7 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { /* restore font color */ set_font_colors(pixmap_gc, color_text, color_background); - draw_text(prompt, strlen(prompt), false, pixmap, pixmap_gc, + draw_text(prompt, pixmap, pixmap_gc, 4 + 4, 4 + 4, rect.width - 4 - 4); /* render close button */ @@ -159,7 +218,7 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { values[0] = 1; set_font_colors(pixmap_gc, color_text, color_button_background); - draw_text("X", 1, false, pixmap, pixmap_gc, y - w - line_width + w / 2 - 4, + draw_text_ascii("X", pixmap, pixmap_gc, y - w - line_width + w / 2 - 4, 4 + 4 - 1, rect.width - y + w + line_width - w / 2 + 4); y -= w; @@ -190,7 +249,7 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { values[0] = color_text; values[1] = color_button_background; set_font_colors(pixmap_gc, color_text, color_button_background); - draw_text(buttons[c].label, strlen(buttons[c].label), false, pixmap, pixmap_gc, + draw_text(buttons[c].label, pixmap, pixmap_gc, y - w - line_width + 6, 4 + 3, rect.width - y + w + line_width - 6); y -= w; @@ -216,7 +275,30 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { } int main(int argc, char *argv[]) { - char *pattern = strdup("-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1"); + /* The following lines are a horrible kludge. Because terminal emulators + * have different ways of interpreting the -e command line argument (some + * need -e "less /etc/fstab", others need -e less /etc/fstab), we need to + * write commands to a script and then just run that script. However, since + * on some machines, $XDG_RUNTIME_DIR and $TMPDIR are mounted with noexec, + * we cannot directly execute the script either. + * + * Therefore, we run i3-nagbar instead and pass the path to the script in + * the environment variable $_I3_NAGBAR_CMD. i3-nagbar then execs /bin/sh + * with that path in order to run that script. + * + * From a security point of view, i3-nagbar is just an alias to /bin/sh in + * certain circumstances. This should not open any new security issues, I + * hope. */ + char *cmd = NULL; + if ((cmd = getenv("_I3_NAGBAR_CMD")) != NULL) { + unsetenv("_I3_NAGBAR_CMD"); + execl("/bin/sh", "/bin/sh", cmd, NULL); + err(EXIT_FAILURE, "execv(/bin/sh, /bin/sh, %s)", cmd); + } + + argv0 = argv[0]; + + char *pattern = sstrdup("-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1"); int o, option_index = 0; enum { TYPE_ERROR = 0, TYPE_WARNING = 1 } bar_type = TYPE_ERROR; @@ -225,14 +307,14 @@ int main(int argc, char *argv[]) { {"font", required_argument, 0, 'f'}, {"button", required_argument, 0, 'b'}, {"help", no_argument, 0, 'h'}, - {"message", no_argument, 0, 'm'}, + {"message", required_argument, 0, 'm'}, {"type", required_argument, 0, 't'}, {0, 0, 0, 0} }; char *options_string = "b:f:m:t:vh"; - prompt = strdup("Please do not run this program."); + prompt = i3string_from_utf8("Please do not run this program."); while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) { switch (o) { @@ -241,11 +323,11 @@ int main(int argc, char *argv[]) { return 0; case 'f': FREE(pattern); - pattern = strdup(optarg); + pattern = sstrdup(optarg); break; case 'm': - FREE(prompt); - prompt = strdup(optarg); + i3string_free(prompt); + prompt = i3string_from_utf8(optarg); break; case 't': bar_type = (strcasecmp(optarg, "warning") == 0 ? TYPE_WARNING : TYPE_ERROR); @@ -256,10 +338,10 @@ int main(int argc, char *argv[]) { return 0; case 'b': buttons = realloc(buttons, sizeof(button_t) * (buttoncnt + 1)); - buttons[buttoncnt].label = optarg; + buttons[buttoncnt].label = i3string_from_utf8(optarg); buttons[buttoncnt].action = argv[optind]; printf("button with label *%s* and action *%s*\n", - buttons[buttoncnt].label, + i3string_as_utf8(buttons[buttoncnt].label), buttons[buttoncnt].action); buttoncnt++; printf("now %d buttons\n", buttoncnt); @@ -280,7 +362,7 @@ int main(int argc, char *argv[]) { #include "atoms.xmacro" #undef xmacro - xcb_screen_t *root_screen = xcb_aux_get_screen(conn, screens); + root_screen = xcb_aux_get_screen(conn, screens); root = root_screen->root; if (bar_type == TYPE_ERROR) { @@ -432,5 +514,7 @@ int main(int argc, char *argv[]) { free(event); } + FREE(pattern); + return 0; }