From: Michael Stapelberg Date: Sun, 1 May 2011 11:56:35 +0000 (+0200) Subject: wizard: actually write the output config X-Git-Tag: tree-pr3~59 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=43ec3ddbafe93c7562929de280fd4e2bb97dfa1b;p=i3%2Fi3 wizard: actually write the output config --- diff --git a/i3-config-wizard/cfgparse.l b/i3-config-wizard/cfgparse.l index d94abe2a..772b8470 100644 --- a/i3-config-wizard/cfgparse.l +++ b/i3-config-wizard/cfgparse.l @@ -78,6 +78,7 @@ Mod3 { yylval.number = (1 << 5); return MODIFIER; } Mod4 { yylval.number = (1 << 6); return MODIFIER; } Mod5 { yylval.number = (1 << 7); return MODIFIER; } Mode_switch { yylval.number = (1 << 8); return MODIFIER; } +$mod { yylval.number = (1 << 9); return TOKMODVAR; } control { return TOKCONTROL; } ctrl { return TOKCONTROL; } shift { return TOKSHIFT; } diff --git a/i3-config-wizard/cfgparse.y b/i3-config-wizard/cfgparse.y index 85e57bfb..f2e4a054 100644 --- a/i3-config-wizard/cfgparse.y +++ b/i3-config-wizard/cfgparse.y @@ -89,6 +89,10 @@ static char *modifier_to_string(int modifiers) { return strdup("Mod1"); else if (modifiers == ((1 << 3) | (1 << 0))) return strdup("Mod1+shift"); + else if (modifiers == (1 << 9)) + return strdup("$mod"); + else if (modifiers == ((1 << 9) | (1 << 0))) + return strdup("$mod+shift"); else return strdup("UNKNOWN"); } @@ -105,6 +109,7 @@ static char *modifier_to_string(int modifiers) { %token NUMBER "" %token STR "" %token TOKBINDCODE +%token TOKMODVAR "$mod" %token MODIFIER "" %token TOKCONTROL "control" %token TOKSHIFT "shift" @@ -148,6 +153,7 @@ binding_modifiers: binding_modifier: MODIFIER { $$ = $1; } + | TOKMODVAR { $$ = $1; } | TOKCONTROL { $$ = (1 << 2); } | TOKSHIFT { $$ = (1 << 0); } ; diff --git a/i3-config-wizard/ipc.c b/i3-config-wizard/ipc.c new file mode 100644 index 00000000..597a86ef --- /dev/null +++ b/i3-config-wizard/ipc.c @@ -0,0 +1,68 @@ +/* + * vim:ts=8:expandtab + * + * i3 - an improved dynamic tiling window manager + * + * © 2009 Michael Stapelberg and contributors + * + * See file LICENSE for license information. + * + */ +#include +#include +#include +#include +#include +#include +#include + +/* + * Formats a message (payload) of the given size and type and sends it to i3 via + * the given socket file descriptor. + * + */ +void ipc_send_message(int sockfd, uint32_t message_size, + uint32_t message_type, uint8_t *payload) { + int buffer_size = strlen("i3-ipc") + sizeof(uint32_t) + sizeof(uint32_t) + message_size; + char msg[buffer_size]; + char *walk = msg; + + strcpy(walk, "i3-ipc"); + walk += strlen("i3-ipc"); + memcpy(walk, &message_size, sizeof(uint32_t)); + walk += sizeof(uint32_t); + memcpy(walk, &message_type, sizeof(uint32_t)); + walk += sizeof(uint32_t); + memcpy(walk, payload, message_size); + + int sent_bytes = 0; + int bytes_to_go = buffer_size; + while (sent_bytes < bytes_to_go) { + int n = write(sockfd, msg + sent_bytes, bytes_to_go); + if (n == -1) + err(EXIT_FAILURE, "write() failed"); + + sent_bytes += n; + bytes_to_go -= n; + } +} + +/* + * Connects to the i3 IPC socket and returns the file descriptor for the + * socket. die()s if anything goes wrong. + * + */ +int connect_ipc(char *socket_path) { + int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (sockfd == -1) + err(EXIT_FAILURE, "Could not create socket"); + + struct sockaddr_un addr; + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_LOCAL; + strcpy(addr.sun_path, socket_path); + if (connect(sockfd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_un)) < 0) + err(EXIT_FAILURE, "Could not connect to i3"); + + return sockfd; +} diff --git a/i3-config-wizard/ipc.h b/i3-config-wizard/ipc.h new file mode 100644 index 00000000..c40c909d --- /dev/null +++ b/i3-config-wizard/ipc.h @@ -0,0 +1,9 @@ +#ifndef _IPC_H +#define _IPC_H + +void ipc_send_message(int sockfd, uint32_t message_size, + uint32_t message_type, uint8_t *payload); + +int connect_ipc(char *socket_path); + +#endif diff --git a/i3-config-wizard/main.c b/i3-config-wizard/main.c index b546f607..a4dd070c 100644 --- a/i3-config-wizard/main.c +++ b/i3-config-wizard/main.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ while (0) #include "xcb.h" +#include "ipc.h" enum { STEP_WELCOME, STEP_GENERATE } current_step = STEP_WELCOME; enum { MOD_ALT, MOD_SUPER } modifier = MOD_SUPER; @@ -52,7 +54,6 @@ static xcb_connection_t *conn; static uint32_t font_id; static uint32_t font_bold_id; static char *socket_path; -static int sockfd; static int font_height; static int font_bold_height; static xcb_window_t win; @@ -62,6 +63,7 @@ static xcb_key_symbols_t *symbols; xcb_window_t root; Display *dpy; +char *rewrite_binding(const char *bindingline); static void finish(); /* @@ -205,36 +207,82 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press return 1; } +/* + * Creates the config file and tells i3 to reload. + * + */ static void finish() { - printf("finishing the wizard\n"); + printf("creating \"%s\"...\n", config_path); -#if 0 - dpy = XOpenDisplay(NULL); + if (!(dpy = XOpenDisplay(NULL))) + errx(1, "Could not connect to X11"); FILE *kc_config = fopen("../i3.config.kc", "r"); + if (kc_config == NULL) + err(1, "Could not open input file \"%s\"", "../i3.config.kc"); + + FILE *ks_config = fopen(config_path, "w"); + if (ks_config == NULL) + err(1, "Could not open output config file \"%s\"", config_path); + char *line = NULL; size_t len = 0; ssize_t read; + bool head_of_file = true; + + /* write a header about auto-generation to the output file */ + fputs("# This file has been auto-generated by i3-config-wizard(1).\n", ks_config); + fputs("# It will not be overwritten, so edit it as you like.\n", ks_config); + fputs("#\n", ks_config); + fputs("# Should you change your keyboard layout somewhen, delete\n", ks_config); + fputs("# this file and re-run i3-config-wizard(1).\n", ks_config); + fputs("#\n", ks_config); + fputs("# See http://i3wm.org/docs/userguide.html\n", ks_config); + while ((read = getline(&line, &len, kc_config)) != -1) { - /* See if that line is interesting by skipping leading whitespaces, - * then checking for 'bindcode' */ + /* skip the warning block at the beginning of the input file */ + if (head_of_file && + strncmp("# WARNING", line, strlen("# WARNING")) == 0) + continue; + + head_of_file = false; + + /* Skip leading whitespace */ char *walk = line; while (isspace(*walk) && walk < (line + len)) walk++; - if (strncmp(walk, "bindcode", strlen("bindcode")) != 0) + + /* Set the modifier the user chose */ + if (strncmp(walk, "set $mod ", strlen("set $mod ")) == 0) { + if (modifier == MOD_ALT) + fputs("set $mod Mod1\n", ks_config); + else fputs("set $mod Mod4\n", ks_config); + continue; + } + + /* Check for 'bindcode'. If it’s not a bindcode line, we + * just copy it to the output file */ + if (strncmp(walk, "bindcode", strlen("bindcode")) != 0) { + fputs(line, ks_config); continue; + } char *result = rewrite_binding(walk); - printf("in: %s", walk); - printf("out: %s", result); + fputs(result, ks_config); free(result); - } + /* sync to do our best in order to have the file really stored on disk */ + fflush(ks_config); + fsync(fileno(ks_config)); + free(line); fclose(kc_config); + fclose(ks_config); - exit(0); -#endif + /* tell i3 to reload the config file */ + int sockfd = connect_ipc(socket_path); + ipc_send_message(sockfd, strlen("reload"), 0, (uint8_t*)"reload"); + close(sockfd); exit(0); }