]> git.sur5r.net Git - i3/i3/blobdiff - i3-nagbar/main.c
remove superfluous ev.h include statements
[i3/i3] / i3-nagbar / main.c
index d0d7e77a248281ed2699babeb66099f692b5ba84..a38d1839ed7b08cfd90ab3fb00c492aa4db805be 100644 (file)
@@ -2,15 +2,12 @@
  * vim:ts=4:sw=4:expandtab
  *
  * i3 - an improved dynamic tiling window manager
+ * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
  *
- * © 2009-2011 Michael Stapelberg and contributors
- *
- * See file LICENSE for license information.
- *
- * i3-nagbar is a utility which displays a nag message.
+ * 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/wait.h>
 #include <xcb/xcb_aux.h>
 #include <xcb/xcb_event.h>
 
+#include "libi3.h"
 #include "i3-nagbar.h"
 
 typedef struct {
-    char *label;
+    i3String *label;
     char *action;
     int16_t x;
     uint16_t width;
@@ -41,11 +39,41 @@ static xcb_window_t win;
 static xcb_pixmap_t pixmap;
 static xcb_gcontext_t pixmap_gc;
 static xcb_rectangle_t rect = { 0, 0, 600, 20 };
-static int font_height;
-static char *prompt = "Please do not run this program.";
+static i3Font font;
+static i3String *prompt;
 static button_t *buttons;
 static int buttoncnt;
+
+/* Result of get_colorpixel() for the various colors. */
+static uint32_t color_background;        /* background of the bar */
+static uint32_t color_button_background; /* background for buttons */
+static uint32_t color_border;            /* color of the button border */
+static uint32_t color_border_bottom;     /* color of the bottom border */
+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
@@ -118,32 +146,28 @@ static void handle_button_release(xcb_connection_t *conn, xcb_button_release_eve
  *
  */
 static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
-    printf("expose!\n");
-
     /* re-draw the background */
-    xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#900000"));
+    xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){ color_background });
     xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &rect);
 
     /* restore font color */
-    uint32_t values[3];
-    values[0] = get_colorpixel(conn, "#FFFFFF");
-    values[1] = get_colorpixel(conn, "#900000");
-    xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND, values);
-    xcb_image_text_8(conn, strlen(prompt), pixmap, pixmap_gc, 4 + 4/* X */,
-                      font_height + 2 + 4 /* Y = baseline of font */, prompt);
+    set_font_colors(pixmap_gc, color_text, color_background);
+    draw_text(prompt, pixmap, pixmap_gc,
+            4 + 4, 4 + 4, rect.width - 4 - 4);
 
     /* render close button */
     int line_width = 4;
     int w = 20;
     int y = rect.width;
-    values[0] = get_colorpixel(conn, "#680a0a");
+    uint32_t values[3];
+    values[0] = color_button_background;
     values[1] = line_width;
     xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_LINE_WIDTH, values);
 
     xcb_rectangle_t close = { y - w - (2 * line_width), 0, w + (2 * line_width), rect.height };
     xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &close);
 
-    xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#d92424"));
+    xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){ color_border });
     xcb_point_t points[] = {
         { y - w - (2 * line_width), line_width / 2 },
         { y - (line_width / 2), line_width / 2 },
@@ -153,12 +177,10 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
     };
     xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, pixmap, pixmap_gc, 5, points);
 
-    values[0] = get_colorpixel(conn, "#ffffff");
-    values[1] = get_colorpixel(conn, "#680a0a");
-    values[2] = 1;
-    xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_LINE_WIDTH, values);
-    xcb_image_text_8(conn, strlen("x"), pixmap, pixmap_gc, y - w - line_width + (w / 2) - 4/* X */,
-                      font_height + 2 + 4 - 1/* Y = baseline of font */, "X");
+    values[0] = 1;
+    set_font_colors(pixmap_gc, color_text, color_button_background);
+    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;
 
     y -= 20;
@@ -167,13 +189,13 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
     line_width = 1;
     for (int c = 0; c < buttoncnt; c++) {
         /* TODO: make w = text extents of the label */
-        w = 90;
+        w = 100;
         y -= 30;
-        xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#680a0a"));
+        xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){ color_button_background });
         close = (xcb_rectangle_t){ y - w - (2 * line_width), 2, w + (2 * line_width), rect.height - 6 };
         xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &close);
 
-        xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#d92424"));
+        xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){ color_border });
         buttons[c].x = y - w - (2 * line_width);
         buttons[c].width = w;
         xcb_point_t points2[] = {
@@ -185,18 +207,18 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
         };
         xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, pixmap, pixmap_gc, 5, points2);
 
-        values[0] = get_colorpixel(conn, "#ffffff");
-        values[1] = get_colorpixel(conn, "#680a0a");
-        xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND, values);
-        xcb_image_text_8(conn, strlen(buttons[c].label), pixmap, pixmap_gc, y - w - line_width + 6/* X */,
-                          font_height + 2 + 3/* Y = baseline of font */, buttons[c].label);
+        values[0] = color_text;
+        values[1] = color_button_background;
+        set_font_colors(pixmap_gc, color_text, color_button_background);
+        draw_text(buttons[c].label, pixmap, pixmap_gc,
+                y - w - line_width + 6, 4 + 3, rect.width - y + w + line_width - 6);
 
         y -= w;
     }
 
     /* border line at the bottom */
     line_width = 2;
-    values[0] = get_colorpixel(conn, "#470909");
+    values[0] = color_border_bottom;
     values[1] = line_width;
     xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_LINE_WIDTH, values);
     xcb_point_t bottom[] = {
@@ -214,8 +236,9 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
 }
 
 int main(int argc, char *argv[]) {
-    char *pattern = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1";
+    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;
 
     static struct option long_options[] = {
         {"version", no_argument, 0, 'v'},
@@ -223,10 +246,13 @@ int main(int argc, char *argv[]) {
         {"button", required_argument, 0, 'b'},
         {"help", no_argument, 0, 'h'},
         {"message", no_argument, 0, 'm'},
+        {"type", required_argument, 0, 't'},
         {0, 0, 0, 0}
     };
 
-    char *options_string = "b:f:m:vh";
+    char *options_string = "b:f:m:t:vh";
+
+    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) {
@@ -235,21 +261,25 @@ int main(int argc, char *argv[]) {
                 return 0;
             case 'f':
                 FREE(pattern);
-                pattern = strdup(optarg);
+                pattern = sstrdup(optarg);
                 break;
             case 'm':
-                prompt = strdup(optarg);
+                i3string_free(prompt);
+                prompt = i3string_from_utf8(optarg);
+                break;
+            case 't':
+                bar_type = (strcasecmp(optarg, "warning") == 0 ? TYPE_WARNING : TYPE_ERROR);
                 break;
             case 'h':
                 printf("i3-nagbar " I3_VERSION "\n");
-                printf("i3-nagbar [-m <message>] [-b <button> <action>] [-f <font>] [-v]\n");
+                printf("i3-nagbar [-m <message>] [-b <button> <action>] [-t warning|error] [-f <font>] [-v]\n");
                 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);
@@ -260,7 +290,6 @@ int main(int argc, char *argv[]) {
     }
 
     int screens;
-    xcb_connection_t *conn;
     if ((conn = xcb_connect(NULL, &screens)) == NULL ||
         xcb_connection_has_error(conn))
         die("Cannot open display\n");
@@ -271,13 +300,51 @@ 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;
 
-    uint32_t font_id = get_font_id(conn, pattern, &font_height);
+    if (bar_type == TYPE_ERROR) {
+        /* Red theme for error messages */
+        color_button_background = get_colorpixel("#680a0a");
+        color_background = get_colorpixel("#900000");
+        color_text = get_colorpixel("#ffffff");
+        color_border = get_colorpixel("#d92424");
+        color_border_bottom = get_colorpixel("#470909");
+    } else {
+        /* Yellowish theme for warnings */
+        color_button_background = get_colorpixel("#ffc100");
+        color_background = get_colorpixel("#ffa8000");
+        color_text = get_colorpixel("#000000");
+        color_border = get_colorpixel("#ab7100");
+        color_border_bottom = get_colorpixel("#ab7100");
+    }
+
+    font = load_font(pattern, true);
+    set_font(&font);
 
     /* Open an input window */
-    win = open_input_window(conn, 500, font_height + 8 + 8 /* 8px padding */);
+    win = xcb_generate_id(conn);
+
+    xcb_create_window(
+        conn,
+        XCB_COPY_FROM_PARENT,
+        win, /* the window id */
+        root, /* parent == root */
+        50, 50, 500, font.height + 8 + 8 /* 8 px padding */, /* dimensions */
+        0, /* x11 border = 0, we draw our own */
+        XCB_WINDOW_CLASS_INPUT_OUTPUT,
+        XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */
+        XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK,
+        (uint32_t[]){
+            0, /* back pixel: black */
+            XCB_EVENT_MASK_EXPOSURE |
+            XCB_EVENT_MASK_STRUCTURE_NOTIFY |
+            XCB_EVENT_MASK_BUTTON_PRESS |
+            XCB_EVENT_MASK_BUTTON_RELEASE
+        });
+
+    /* Map the window (make it visible) */
+    xcb_map_window(conn, win);
 
     /* Setup NetWM atoms */
     #define xmacro(name) \
@@ -318,7 +385,7 @@ int main(int argc, char *argv[]) {
         uint32_t bottom_end_x;
     } __attribute__((__packed__)) strut_partial = {0,};
 
-    strut_partial.top = font_height + 6;
+    strut_partial.top = font.height + 6;
     strut_partial.top_start_x = 0;
     strut_partial.top_end_x = 800;
 
@@ -334,12 +401,9 @@ int main(int argc, char *argv[]) {
     /* Create pixmap */
     pixmap = xcb_generate_id(conn);
     pixmap_gc = xcb_generate_id(conn);
-    xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, 500, font_height + 8);
+    xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, 500, font.height + 8);
     xcb_create_gc(conn, pixmap_gc, pixmap, 0, 0);
 
-    /* Create graphics context */
-    xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FONT, font_id);
-
     /* Grab the keyboard to get all input */
     xcb_flush(conn);
 
@@ -381,9 +445,6 @@ int main(int argc, char *argv[]) {
 
                 xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, rect.width, rect.height);
                 xcb_create_gc(conn, pixmap_gc, pixmap, 0, 0);
-
-                /* Create graphics context */
-                xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FONT, font_id);
                 break;
             }
         }
@@ -391,5 +452,7 @@ int main(int argc, char *argv[]) {
         free(event);
     }
 
+    FREE(pattern);
+
     return 0;
 }