]> git.sur5r.net Git - i3/i3/blobdiff - i3-nagbar/main.c
Merge branch 'fix-nagbar'
[i3/i3] / i3-nagbar / main.c
index 1dbd77369b28a184a07ccd7973f1e0443dc57e06..6ca80ba5babfaf6f80bde744c954caca2a765bdf 100644 (file)
@@ -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 <ev.h>
 #include <stdio.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/wait.h>
 #include <stdlib.h>
 #include <stdbool.h>
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <getopt.h>
 #include <limits.h>
+#include <fcntl.h>
 
 #include <xcb/xcb.h>
 #include <xcb/xcb_aux.h>
 #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;
 }