]> git.sur5r.net Git - i3/i3/blobdiff - i3-config-wizard/main.c
Use the DPI setting within the i3-config-wizard and i3-nagbar (#2585)
[i3/i3] / i3-config-wizard / main.c
index 5a855c40cb76832978b794a4acbb3e2fe05af3f9..9e851c06f3f1b73e0ca7f6453b93e62034f0e320 100644 (file)
@@ -2,12 +2,14 @@
  * vim:ts=4:sw=4:expandtab
  *
  * i3 - an improved dynamic tiling window manager
- * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
+ * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
  *
  * i3-config-wizard: Program to convert configs using keycodes to configs using
  *                   keysyms.
  *
  */
+#include <config.h>
+
 #if defined(__FreeBSD__)
 #include <sys/param.h>
 #endif
 #include "xcb.h"
 #include "libi3.h"
 
+#define row_y(row) \
+    (((row)-1) * font.height + logical_px(4))
+#define window_height() \
+    (row_y(15) + font.height)
+
 enum { STEP_WELCOME,
        STEP_GENERATE } current_step = STEP_WELCOME;
 enum { MOD_Mod1,
@@ -80,6 +87,7 @@ xcb_screen_t *root_screen;
 static xcb_get_modifier_mapping_reply_t *modmap_reply;
 static i3Font font;
 static i3Font bold_font;
+static int char_width;
 static char *socket_path;
 static xcb_window_t win;
 static xcb_pixmap_t pixmap;
@@ -386,7 +394,7 @@ static char *rewrite_binding(const char *input) {
                     }
                 }
                 if (walk != beginning) {
-                    char *str = scalloc(walk - beginning + 1);
+                    char *str = scalloc(walk - beginning + 1, 1);
                     /* We copy manually to handle escaping of characters. */
                     int inpos, outpos;
                     for (inpos = 0, outpos = 0;
@@ -455,45 +463,13 @@ void errorlog(char *fmt, ...) {
 void debuglog(char *fmt, ...) {
 }
 
-/*
- * This function resolves ~ in pathnames.
- * It may resolve wildcards in the first part of the path, but if no match
- * or multiple matches are found, it just returns a copy of path as given.
- *
- */
-static char *resolve_tilde(const char *path) {
-    static glob_t globbuf;
-    char *head, *tail, *result;
-
-    tail = strchr(path, '/');
-    head = strndup(path, tail ? (size_t)(tail - path) : strlen(path));
-
-    int res = glob(head, GLOB_TILDE, NULL, &globbuf);
-    free(head);
-    /* no match, or many wildcard matches are bad */
-    if (res == GLOB_NOMATCH || globbuf.gl_pathc != 1)
-        result = strdup(path);
-    else if (res != 0) {
-        err(1, "glob() failed");
-    } else {
-        head = globbuf.gl_pathv[0];
-        result = calloc(1, strlen(head) + (tail ? strlen(tail) : 0) + 1);
-        strncpy(result, head, strlen(head));
-        if (tail)
-            strncat(result, tail, strlen(tail));
-    }
-    globfree(&globbuf);
-
-    return result;
-}
-
 /*
  * Handles expose events, that is, draws the window contents.
  *
  */
 static int handle_expose() {
     /* re-draw the background */
-    xcb_rectangle_t border = {0, 0, 300, (15 * font.height) + 8};
+    xcb_rectangle_t border = {0, 0, logical_px(300), window_height()};
     xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){get_colorpixel("#000000")});
     xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &border);
 
@@ -501,62 +477,68 @@ static int handle_expose() {
 
 #define txt(x, row, text)                    \
     draw_text_ascii(text, pixmap, pixmap_gc, \
-                    x, (row - 1) * font.height + 4, 300 - x * 2)
+                    x, row_y(row), logical_px(500) - x * 2)
 
     if (current_step == STEP_WELCOME) {
         /* restore font color */
-        set_font_colors(pixmap_gc, get_colorpixel("#FFFFFF"), get_colorpixel("#000000"));
+        set_font_colors(pixmap_gc, draw_util_hex_to_color("#FFFFFF"), draw_util_hex_to_color("#000000"));
+
+        txt(logical_px(10), 2, "You have not configured i3 yet.");
+        txt(logical_px(10), 3, "Do you want me to generate a config at");
+
+        char *msg;
+        sasprintf(&msg, "%s?", config_path);
+        txt(logical_px(10), 4, msg);
+        free(msg);
 
-        txt(10, 2, "You have not configured i3 yet.");
-        txt(10, 3, "Do you want me to generate ~/.i3/config?");
-        txt(85, 5, "Yes, generate ~/.i3/config");
-        txt(85, 7, "No, I will use the defaults");
+        txt(logical_px(85), 6, "Yes, generate the config");
+        txt(logical_px(85), 8, "No, I will use the defaults");
 
         /* green */
-        set_font_colors(pixmap_gc, get_colorpixel("#00FF00"), get_colorpixel("#000000"));
-        txt(25, 5, "<Enter>");
+        set_font_colors(pixmap_gc, draw_util_hex_to_color("#00FF00"), draw_util_hex_to_color("#000000"));
+        txt(logical_px(25), 6, "<Enter>");
 
         /* red */
-        set_font_colors(pixmap_gc, get_colorpixel("#FF0000"), get_colorpixel("#000000"));
-        txt(31, 7, "<ESC>");
+        set_font_colors(pixmap_gc, draw_util_hex_to_color("#FF0000"), draw_util_hex_to_color("#000000"));
+        txt(logical_px(31), 8, "<ESC>");
     }
 
     if (current_step == STEP_GENERATE) {
-        set_font_colors(pixmap_gc, get_colorpixel("#FFFFFF"), get_colorpixel("#000000"));
+        set_font_colors(pixmap_gc, draw_util_hex_to_color("#FFFFFF"), draw_util_hex_to_color("#000000"));
 
-        txt(10, 2, "Please choose either:");
-        txt(85, 4, "Win as default modifier");
-        txt(85, 5, "Alt as default modifier");
-        txt(10, 7, "Afterwards, press");
-        txt(85, 9, "to write ~/.i3/config");
-        txt(85, 10, "to abort");
+        txt(logical_px(10), 2, "Please choose either:");
+        txt(logical_px(85), 4, "Win as default modifier");
+        txt(logical_px(85), 5, "Alt as default modifier");
+        txt(logical_px(10), 7, "Afterwards, press");
+        txt(logical_px(85), 9, "to write the config");
+        txt(logical_px(85), 10, "to abort");
 
         /* the not-selected modifier */
         if (modifier == MOD_Mod4)
-            txt(31, 5, "<Alt>");
+            txt(logical_px(31), 5, "<Alt>");
         else
-            txt(31, 4, "<Win>");
+            txt(logical_px(31), 4, "<Win>");
 
         /* the selected modifier */
         set_font(&bold_font);
-        set_font_colors(pixmap_gc, get_colorpixel("#FFFFFF"), get_colorpixel("#000000"));
+        set_font_colors(pixmap_gc, draw_util_hex_to_color("#FFFFFF"), draw_util_hex_to_color("#000000"));
         if (modifier == MOD_Mod4)
-            txt(10, 4, "-> <Win>");
+            txt(logical_px(10), 4, "-> <Win>");
         else
-            txt(10, 5, "-> <Alt>");
+            txt(logical_px(10), 5, "-> <Alt>");
 
         /* green */
         set_font(&font);
-        set_font_colors(pixmap_gc, get_colorpixel("#00FF00"), get_colorpixel("#000000"));
-        txt(25, 9, "<Enter>");
+        set_font_colors(pixmap_gc, draw_util_hex_to_color("#00FF00"), draw_util_hex_to_color("#000000"));
+        txt(logical_px(25), 9, "<Enter>");
 
         /* red */
-        set_font_colors(pixmap_gc, get_colorpixel("#FF0000"), get_colorpixel("#000000"));
-        txt(31, 10, "<ESC>");
+        set_font_colors(pixmap_gc, draw_util_hex_to_color("#FF0000"), draw_util_hex_to_color("#000000"));
+        txt(logical_px(31), 10, "<ESC>");
     }
 
     /* Copy the contents of the pixmap to the real window */
-    xcb_copy_area(conn, pixmap, win, pixmap_gc, 0, 0, 0, 0, /* */ 500, 500);
+    xcb_copy_area(conn, pixmap, win, pixmap_gc, 0, 0, 0, 0, logical_px(500), logical_px(500));
     xcb_flush(conn);
 
     return 1;
@@ -592,6 +574,12 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press
             finish();
     }
 
+    /* Swap between modifiers when up or down is pressed. */
+    if (sym == XK_Up || sym == XK_Down) {
+        modifier = (modifier == MOD_Mod1) ? MOD_Mod4 : MOD_Mod1;
+        handle_expose();
+    }
+
     /* cancel any time */
     if (sym == XK_Escape)
         exit(0);
@@ -637,14 +625,16 @@ static void handle_button_press(xcb_button_press_event_t *event) {
     if (current_step != STEP_GENERATE)
         return;
 
-    if (event->event_x >= 32 && event->event_x <= 68 &&
-        event->event_y >= 45 && event->event_y <= 54) {
+    if (event->event_x < logical_px(32) ||
+        event->event_x > (logical_px(32) + char_width * 5))
+        return;
+
+    if (event->event_y >= row_y(4) && event->event_y <= (row_y(4) + font.height)) {
         modifier = MOD_Mod4;
         handle_expose();
     }
 
-    if (event->event_x >= 32 && event->event_x <= 68 &&
-        event->event_y >= 56 && event->event_y <= 70) {
+    if (event->event_y >= row_y(5) && event->event_y <= (row_y(5) + font.height)) {
         modifier = MOD_Mod1;
         handle_expose();
     }
@@ -758,10 +748,10 @@ static void finish() {
 }
 
 int main(int argc, char *argv[]) {
-    config_path = resolve_tilde("~/.i3/config");
+    char *xdg_config_home;
     socket_path = getenv("I3SOCK");
-    char *pattern = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1";
-    char *patternbold = "-misc-fixed-bold-r-normal--13-120-75-75-C-70-iso10646-1";
+    char *pattern = "pango:monospace 8";
+    char *patternbold = "pango:monospace bold 8";
     int o, option_index = 0;
 
     static struct option long_options[] = {
@@ -780,7 +770,7 @@ int main(int argc, char *argv[]) {
         switch (o) {
             case 's':
                 FREE(socket_path);
-                socket_path = strdup(optarg);
+                socket_path = sstrdup(optarg);
                 break;
             case 'v':
                 printf("i3-config-wizard " I3_VERSION "\n");
@@ -792,20 +782,29 @@ int main(int argc, char *argv[]) {
         }
     }
 
-    /* Check if the destination config file does not exist but the path is
-     * writable. If not, exit now, this program is not useful in that case. */
-    struct stat stbuf;
-    if (stat(config_path, &stbuf) == 0) {
-        printf("The config file \"%s\" already exists. Exiting.\n", config_path);
+    char *path = get_config_path(NULL, false);
+    if (path != NULL) {
+        printf("The config file \"%s\" already exists. Exiting.\n", path);
+        free(path);
         return 0;
     }
 
-    /* Create ~/.i3 if it does not yet exist */
-    char *config_dir = resolve_tilde("~/.i3");
+    /* Always write to $XDG_CONFIG_HOME/i3/config by default. */
+    if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL)
+        xdg_config_home = "~/.config";
+
+    xdg_config_home = resolve_tilde(xdg_config_home);
+    sasprintf(&config_path, "%s/i3/config", xdg_config_home);
+
+    /* Create $XDG_CONFIG_HOME/i3 if it does not yet exist */
+    char *config_dir;
+    struct stat stbuf;
+    sasprintf(&config_dir, "%s/i3", xdg_config_home);
     if (stat(config_dir, &stbuf) != 0)
-        if (mkdir(config_dir, 0755) == -1)
-            err(1, "mkdir(%s) failed", config_dir);
+        if (mkdirp(config_dir, DEFAULT_DIR_MODE) != 0)
+            err(EXIT_FAILURE, "mkdirp(%s) failed", config_dir);
     free(config_dir);
+    free(xdg_config_home);
 
     int fd;
     if ((fd = open(config_path, O_CREAT | O_RDWR, 0644)) == -1) {
@@ -855,18 +854,23 @@ int main(int argc, char *argv[]) {
 
     xcb_numlock_mask = get_mod_mask_for(XCB_NUM_LOCK, symbols, modmap_reply);
 
+    init_dpi();
     font = load_font(pattern, true);
     bold_font = load_font(patternbold, true);
 
+    /* Determine character width in the default font. */
+    set_font(&font);
+    char_width = predict_text_width(i3string_from_utf8("a"));
+
     /* Open an input window */
     win = xcb_generate_id(conn);
     xcb_create_window(
         conn,
         XCB_COPY_FROM_PARENT,
-        win,                /* the window id */
-        root,               /* parent == root */
-        490, 297, 300, 205, /* dimensions */
-        0,                  /* X11 border = 0, we draw our own */
+        win,                                                                /* the window id */
+        root,                                                               /* parent == root */
+        logical_px(490), logical_px(297), logical_px(300), window_height(), /* 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,
@@ -914,7 +918,7 @@ 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, 500);
+    xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, logical_px(500), logical_px(500));
     xcb_create_gc(conn, pixmap_gc, pixmap, 0, 0);
 
     /* Grab the keyboard to get all input */