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");
}
%token <number>NUMBER "<number>"
%token <string>STR "<string>"
%token TOKBINDCODE
+%token TOKMODVAR "$mod"
%token MODIFIER "<modifier>"
%token TOKCONTROL "control"
%token TOKSHIFT "shift"
binding_modifier:
MODIFIER { $<number>$ = $<number>1; }
+ | TOKMODVAR { $<number>$ = $<number>1; }
| TOKCONTROL { $<number>$ = (1 << 2); }
| TOKSHIFT { $<number>$ = (1 << 0); }
;
--- /dev/null
+/*
+ * vim:ts=8:expandtab
+ *
+ * i3 - an improved dynamic tiling window manager
+ *
+ * © 2009 Michael Stapelberg and contributors
+ *
+ * See file LICENSE for license information.
+ *
+ */
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <err.h>
+
+/*
+ * 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;
+}
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
+#include <ctype.h>
#include <errno.h>
#include <err.h>
#include <stdint.h>
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;
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;
xcb_window_t root;
Display *dpy;
+char *rewrite_binding(const char *bindingline);
static void finish();
/*
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);
}