many progresses

This commit is contained in:
nixo 2020-05-10 17:20:32 +02:00
parent 29f551626e
commit c8f383329d
10 changed files with 305 additions and 355 deletions

View File

@ -610,35 +610,19 @@ static void GENERATED_call(const int call_identifier, struct CommandResultIR *re
break; break;
case 76: case 76:
result->next_state = INITIAL; result->next_state = INITIAL;
#ifndef TEST_PARSER
cmd_focus_direction(&current_match, result, get_string("direction"));
#else
fprintf(stderr, "cmd_focus_direction(%s)\n", get_string("direction")); fprintf(stderr, "cmd_focus_direction(%s)\n", get_string("direction"));
#endif
break; break;
case 77: case 77:
result->next_state = INITIAL; result->next_state = INITIAL;
#ifndef TEST_PARSER
cmd_focus_direction(&current_match, result, get_string("direction"));
#else
fprintf(stderr, "cmd_focus_direction(%s)\n", get_string("direction")); fprintf(stderr, "cmd_focus_direction(%s)\n", get_string("direction"));
#endif
break; break;
case 78: case 78:
result->next_state = INITIAL; result->next_state = INITIAL;
#ifndef TEST_PARSER
cmd_focus_direction(&current_match, result, get_string("direction"));
#else
fprintf(stderr, "cmd_focus_direction(%s)\n", get_string("direction")); fprintf(stderr, "cmd_focus_direction(%s)\n", get_string("direction"));
#endif
break; break;
case 79: case 79:
result->next_state = INITIAL; result->next_state = INITIAL;
#ifndef TEST_PARSER
cmd_focus_direction(&current_match, result, get_string("direction"));
#else
fprintf(stderr, "cmd_focus_direction(%s)\n", get_string("direction")); fprintf(stderr, "cmd_focus_direction(%s)\n", get_string("direction"));
#endif
break; break;
case 80: case 80:
result->next_state = INITIAL; result->next_state = INITIAL;
@ -762,19 +746,9 @@ static void GENERATED_call(const int call_identifier, struct CommandResultIR *re
break; break;
case 95: case 95:
result->next_state = INITIAL; result->next_state = INITIAL;
#ifndef TEST_PARSER
cmd_nop(&current_match, result, get_string("comment"));
#else
fprintf(stderr, "cmd_nop(%s)\n", get_string("comment"));
#endif
break; break;
case 96: case 96:
result->next_state = INITIAL; result->next_state = INITIAL;
#ifndef TEST_PARSER
cmd_nop(&current_match, result, NULL);
#else
fprintf(stderr, "cmd_nop(NULL)\n");
#endif
break; break;
default: default:
printf("BUG in the parser. state = %d\n", call_identifier); printf("BUG in the parser. state = %d\n", call_identifier);

View File

@ -13,6 +13,8 @@
#include "commands_parser.h" #include "commands_parser.h"
#include "libguile.h"
/** The beginning of the prototype for every cmd_ function. */ /** The beginning of the prototype for every cmd_ function. */
#define I3_CMD Match *current_match, struct CommandResultIR *cmd_output #define I3_CMD Match *current_match, struct CommandResultIR *cmd_output
@ -80,12 +82,6 @@ void cmd_resize(I3_CMD, const char *way, const char *direction, long resize_px,
*/ */
void cmd_border(I3_CMD, const char *border_style_str, long border_width); void cmd_border(I3_CMD, const char *border_style_str, long border_width);
/**
* Implementation of 'nop <comment>'.
*
*/
void cmd_nop(I3_CMD, const char *comment);
/** /**
* Implementation of 'append_layout <path>'. * Implementation of 'append_layout <path>'.
* *
@ -164,12 +160,6 @@ void cmd_move_workspace_to_output(I3_CMD, const char *name);
*/ */
void cmd_split(I3_CMD, const char *direction); void cmd_split(I3_CMD, const char *direction);
/**
* Implementation of 'kill [window|client]'.
*
*/
void cmd_kill(I3_CMD, const char *kill_mode_str);
/** /**
* Implementation of 'exec [--no-startup-id] <command>'. * Implementation of 'exec [--no-startup-id] <command>'.
* *
@ -180,7 +170,7 @@ void cmd_exec(I3_CMD, const char *nosn, const char *command);
* Implementation of 'focus left|right|up|down'. * Implementation of 'focus left|right|up|down'.
* *
*/ */
void cmd_focus_direction(I3_CMD, const char *direction); SCM guile_focus_direction(SCM direction);
/** /**
* Implementation of 'focus next|prev sibling' * Implementation of 'focus next|prev sibling'
@ -337,3 +327,6 @@ void cmd_shmlog(I3_CMD, const char *argument);
* *
*/ */
void cmd_debuglog(I3_CMD, const char *argument); void cmd_debuglog(I3_CMD, const char *argument);
SCM guile_kill(SCM kill_mode);

View File

@ -39,7 +39,6 @@ CFGFUN(criteria_init, int _state);
CFGFUN(criteria_add, const char *ctype, const char *cvalue); CFGFUN(criteria_add, const char *ctype, const char *cvalue);
CFGFUN(criteria_pop_state); CFGFUN(criteria_pop_state);
CFGFUN(font, const char *font);
CFGFUN(exec, const char *exectype, const char *no_startup_id, const char *command); CFGFUN(exec, const char *exectype, const char *no_startup_id, const char *command);
CFGFUN(for_window, const char *command); CFGFUN(for_window, const char *command);
CFGFUN(floating_minimum_size, const long width, const long height); CFGFUN(floating_minimum_size, const long width, const long height);

View File

@ -40,11 +40,10 @@ struct ConfigResultIR *parse_config(const char *input, struct context *context);
void start_config_error_nagbar(const char *configpath, bool has_errors); void start_config_error_nagbar(const char *configpath, bool has_errors);
/** /**
* Parses the given file by first replacing the variables, then calling * Parses the given scheme file.
* parse_config and launching i3-nagbar if use_nagbar is true.
* *
* The return value is a boolean indicating whether there were errors during * The return value is a boolean indicating whether there were errors during
* parsing. * parsing.
* *
*/ */
bool parse_file(const char *f, bool use_nagbar); bool parse_file(const char *f);

View File

@ -11,6 +11,8 @@
#include <time.h> #include <time.h>
#include "guile-objects.h"
typedef enum { CLICK_BORDER = 0, typedef enum { CLICK_BORDER = 0,
CLICK_DECORATION = 1, CLICK_DECORATION = 1,
CLICK_INSIDE = 2 } click_destination_t; CLICK_INSIDE = 2 } click_destination_t;
@ -299,74 +301,83 @@ done:
* *
*/ */
void handle_button_press(xcb_button_press_event_t *event) { void handle_button_press(xcb_button_press_event_t *event) {
Con *con; Con *con;
DLOG("Button %d (state %d) %s on window 0x%08x (child 0x%08x) at (%d, %d) (root %d, %d)\n", DLOG("Button %d (state %d) %s on window 0x%08x (child 0x%08x) at (%d, %d) (root %d, %d)\n",
event->detail, event->state, (event->response_type == XCB_BUTTON_PRESS ? "press" : "release"), event->detail, event->state, (event->response_type == XCB_BUTTON_PRESS ? "press" : "release"),
event->event, event->child, event->event_x, event->event_y, event->root_x, event->event, event->child, event->event_x, event->event_y, event->root_x,
event->root_y); event->root_y);
last_timestamp = event->time; last_timestamp = event->time;
const uint32_t mod = (config.floating_modifier & 0xFFFF); // Click hook
const bool mod_pressed = (mod != 0 && (event->state & mod) == mod); SCM hook = scm_variable_ref(scm_c_lookup("button-press-hook"));
DLOG("floating_mod = %d, detail = %d\n", mod_pressed, event->detail); if (scm_is_true(hook)) {
if ((con = con_by_window_id(event->event))) { scm_call_6(hook,
route_click(con, event, mod_pressed, CLICK_INSIDE); scm_from_int(event->root_x), scm_from_int(event->root_y),
return; scm_from_int(event->event_x), scm_from_int(event->event_y),
scm_from_int(event->state), scm_from_int(event->same_screen));
}
const uint32_t mod = (config.floating_modifier & 0xFFFF);
const bool mod_pressed = (mod != 0 && (event->state & mod) == mod);
DLOG("floating_mod = %d, detail = %d\n", mod_pressed, event->detail);
if ((con = con_by_window_id(event->event))) {
route_click(con, event, mod_pressed, CLICK_INSIDE);
return;
}
if (!(con = con_by_frame_id(event->event))) {
/* Run bindings on the root window as well, see #2097. We only run it
* if --whole-window was set as that's the equivalent for a normal
* window. */
if (event->event == root) {
Binding *bind = get_binding_from_xcb_event((xcb_generic_event_t *)event);
if (bind != NULL && bind->whole_window) {
CommandResult *result = run_binding(bind, NULL);
command_result_free(result);
}
} }
if (!(con = con_by_frame_id(event->event))) { /* If the root window is clicked, find the relevant output from the
/* Run bindings on the root window as well, see #2097. We only run it * click coordinates and focus the output's active workspace. */
* if --whole-window was set as that's the equivalent for a normal if (event->event == root && event->response_type == XCB_BUTTON_PRESS) {
* window. */ Con *output, *ws;
if (event->event == root) { TAILQ_FOREACH (output, &(croot->nodes_head), nodes) {
Binding *bind = get_binding_from_xcb_event((xcb_generic_event_t *)event); if (con_is_internal(output) ||
if (bind != NULL && bind->whole_window) { !rect_contains(output->rect, event->event_x, event->event_y))
CommandResult *result = run_binding(bind, NULL); continue;
command_result_free(result);
}
}
/* If the root window is clicked, find the relevant output from the ws = TAILQ_FIRST(&(output_get_content(output)->focus_head));
* click coordinates and focus the output's active workspace. */ if (ws != con_get_workspace(focused)) {
if (event->event == root && event->response_type == XCB_BUTTON_PRESS) { workspace_show(ws);
Con *output, *ws; tree_render();
TAILQ_FOREACH (output, &(croot->nodes_head), nodes) { }
if (con_is_internal(output) || return;
!rect_contains(output->rect, event->event_x, event->event_y)) }
continue; return;
ws = TAILQ_FIRST(&(output_get_content(output)->focus_head));
if (ws != con_get_workspace(focused)) {
workspace_show(ws);
tree_render();
}
return;
}
return;
}
ELOG("Clicked into unknown window?!\n");
xcb_allow_events(conn, XCB_ALLOW_REPLAY_POINTER, event->time);
xcb_flush(conn);
return;
} }
/* Check if the click was on the decoration of a child */ ELOG("Clicked into unknown window?!\n");
Con *child; xcb_allow_events(conn, XCB_ALLOW_REPLAY_POINTER, event->time);
TAILQ_FOREACH_REVERSE (child, &(con->nodes_head), nodes_head, nodes) { xcb_flush(conn);
if (!rect_contains(child->deco_rect, event->event_x, event->event_y)) return;
continue; }
route_click(child, event, mod_pressed, CLICK_DECORATION); /* Check if the click was on the decoration of a child */
return; Con *child;
} TAILQ_FOREACH_REVERSE (child, &(con->nodes_head), nodes_head, nodes) {
if (!rect_contains(child->deco_rect, event->event_x, event->event_y))
continue;
if (event->child != XCB_NONE) { route_click(child, event, mod_pressed, CLICK_DECORATION);
DLOG("event->child not XCB_NONE, so this is an event which originated from a click into the application, but the application did not handle it.\n"); return;
route_click(con, event, mod_pressed, CLICK_INSIDE); }
return;
}
route_click(con, event, mod_pressed, CLICK_BORDER); if (event->child != XCB_NONE) {
DLOG("event->child not XCB_NONE, so this is an event which originated from a click into the application, but the application did not handle it.\n");
route_click(con, event, mod_pressed, CLICK_INSIDE);
return;
}
route_click(con, event, mod_pressed, CLICK_BORDER);
} }

View File

@ -757,17 +757,6 @@ void cmd_border(I3_CMD, const char *border_style_str, long border_width) {
ysuccess(true); ysuccess(true);
} }
/*
* Implementation of 'nop <comment>'.
*
*/
void cmd_nop(I3_CMD, const char *comment) {
LOG("-------------------------------------------------\n");
LOG(" NOP: %.4000s\n", comment);
LOG("-------------------------------------------------\n");
ysuccess(true);
}
/* /*
* Implementation of 'append_layout <path>'. * Implementation of 'append_layout <path>'.
* *
@ -1165,67 +1154,6 @@ void cmd_split(I3_CMD, const char *direction) {
ysuccess(true); ysuccess(true);
} }
/*
* Implementation of 'kill [window|client]'.
*
*/
void cmd_kill(I3_CMD, const char *kill_mode_str) {
if (kill_mode_str == NULL)
kill_mode_str = "window";
DLOG("kill_mode=%s\n", kill_mode_str);
int kill_mode;
if (strcmp(kill_mode_str, "window") == 0)
kill_mode = KILL_WINDOW;
else if (strcmp(kill_mode_str, "client") == 0)
kill_mode = KILL_CLIENT;
else {
yerror("BUG: called with kill_mode=%s", kill_mode_str);
return;
}
HANDLE_EMPTY_MATCH;
owindow *current;
TAILQ_FOREACH (current, &owindows, owindows) {
con_close(current->con, kill_mode);
}
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
ysuccess(true);
}
/*
* Implementation of 'exec [--no-startup-id] <command>'.
*
*/
void cmd_exec(I3_CMD, const char *nosn, const char *command) {
bool no_startup_id = (nosn != NULL);
HANDLE_EMPTY_MATCH;
int count = 0;
owindow *current;
TAILQ_FOREACH (current, &owindows, owindows) {
count++;
}
if (count > 1) {
LOG("WARNING: Your criteria for the exec command match %d containers, "
"so the command will execute this many times.\n",
count);
}
TAILQ_FOREACH (current, &owindows, owindows) {
DLOG("should execute %s, no_startup_id = %d\n", command, no_startup_id);
start_application(command, no_startup_id);
}
ysuccess(true);
}
#define CMD_FOCUS_WARN_CHILDREN \ #define CMD_FOCUS_WARN_CHILDREN \
do { \ do { \
int count = 0; \ int count = 0; \
@ -1241,44 +1169,6 @@ void cmd_exec(I3_CMD, const char *nosn, const char *command) {
} \ } \
} while (0) } while (0)
/*
* Implementation of 'focus left|right|up|down|next|prev'.
*
*/
void cmd_focus_direction(I3_CMD, const char *direction_str) {
HANDLE_EMPTY_MATCH;
CMD_FOCUS_WARN_CHILDREN;
direction_t direction;
position_t position;
bool auto_direction = true;
if (strcmp(direction_str, "prev") == 0) {
position = BEFORE;
} else if (strcmp(direction_str, "next") == 0) {
position = AFTER;
} else {
auto_direction = false;
direction = parse_direction(direction_str);
}
owindow *current;
TAILQ_FOREACH (current, &owindows, owindows) {
Con *ws = con_get_workspace(current->con);
if (!ws || con_is_internal(ws)) {
continue;
}
if (auto_direction) {
orientation_t o = con_orientation(current->con->parent);
direction = direction_from_orientation_position(o, position);
}
tree_next(current->con, direction);
}
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
ysuccess(true);
}
/* /*
* Implementation of 'focus next|prev sibling' * Implementation of 'focus next|prev sibling'
* *
@ -2211,3 +2101,166 @@ void cmd_debuglog(I3_CMD, const char *argument) {
// XXX: default reply for now, make this a better reply // XXX: default reply for now, make this a better reply
ysuccess(true); ysuccess(true);
} }
static struct CommandResultIR subcommand_output;
SCM guile_kill(SCM g_direction) {
Con * con;
owindow * ow;
while (!TAILQ_EMPTY(&owindows)) {
ow = TAILQ_FIRST(&owindows);
TAILQ_REMOVE(&owindows, ow, owindows);
free(ow);
}
TAILQ_INIT(&owindows);
/* copy all_cons */
TAILQ_FOREACH (con, &all_cons, all_cons) {
ow = smalloc(sizeof(owindow));
ow->con = con;
TAILQ_INSERT_TAIL(&owindows, ow, owindows);
}
while (!TAILQ_EMPTY(&owindows)) {
ow = TAILQ_FIRST(&owindows);
TAILQ_REMOVE(&owindows, ow, owindows);
free(ow);
}
ow = smalloc(sizeof(owindow));
ow->con = focused;
TAILQ_INIT(&owindows);
TAILQ_INSERT_TAIL(&owindows, ow, owindows);
owindow *current;
const char * kill_mode_str = "window";
// TODO: DEFATULT TO WINDOW
int kill_mode;
if (strcmp(kill_mode_str, "window") == 0)
kill_mode = KILL_WINDOW;
else if (strcmp(kill_mode_str, "client") == 0)
kill_mode = KILL_CLIENT;
else {
//yerror("BUG: called with kill_mode=%s", kill_mode_str);
return SCM_BOOL_F;
}
TAILQ_FOREACH (current, &owindows, owindows) {
con_close(current->con, kill_mode);
}
tree_render();
return SCM_BOOL_T;
}
// WORKING!!
SCM guile_split(SCM g_direction) {
char * direction = scm_to_locale_string(g_direction);
Con * con;
owindow * ow;
while (!TAILQ_EMPTY(&owindows)) {
ow = TAILQ_FIRST(&owindows);
TAILQ_REMOVE(&owindows, ow, owindows);
free(ow);
}
TAILQ_INIT(&owindows);
/* copy all_cons */
TAILQ_FOREACH (con, &all_cons, all_cons) {
ow = smalloc(sizeof(owindow));
ow->con = con;
TAILQ_INSERT_TAIL(&owindows, ow, owindows);
}
while (!TAILQ_EMPTY(&owindows)) {
ow = TAILQ_FIRST(&owindows);
TAILQ_REMOVE(&owindows, ow, owindows);
free(ow);
}
ow = smalloc(sizeof(owindow));
ow->con = focused;
TAILQ_INIT(&owindows);
TAILQ_INSERT_TAIL(&owindows, ow, owindows);
owindow *current;
LOG("splitting in direction %c\n", direction[0]);
TAILQ_FOREACH (current, &owindows, owindows) {
if (con_is_docked(current->con)) {
ELOG("Cannot split a docked container, skipping.\n");
continue;
}
DLOG("matching: %p / %s\n", current->con, current->con->name);
if (direction[0] == 't') {
layout_t current_layout;
if (current->con->type == CT_WORKSPACE) {
current_layout = current->con->layout;
} else {
current_layout = current->con->parent->layout;
}
/* toggling split orientation */
if (current_layout == L_SPLITH) {
tree_split(current->con, VERT);
} else {
tree_split(current->con, HORIZ);
}
} else {
tree_split(current->con, (direction[0] == 'v' ? VERT : HORIZ));
}
}
tree_render();
return SCM_BOOL_T;
}
/*
* Implementation of 'focus left|right|up|down|next|prev'.
*
*/
SCM guile_focus_direction(SCM g_direction) {
char * direction_str = scm_to_locale_string(g_direction);
Con * con;
owindow * ow;
while (!TAILQ_EMPTY(&owindows)) {
ow = TAILQ_FIRST(&owindows);
TAILQ_REMOVE(&owindows, ow, owindows);
free(ow);
}
int count = 0;
owindow *current;
TAILQ_FOREACH (current, &owindows, owindows) {
count++;
}
if (count > 1) {
LOG("WARNING: Your criteria for the focus command matches %d containers, "
"while only exactly one container can be focused at a time.\n",
count);
}
direction_t direction;
position_t position;
bool auto_direction = true;
if (strcmp(direction_str, "prev") == 0) {
position = BEFORE;
} else if (strcmp(direction_str, "next") == 0) {
position = AFTER;
} else {
auto_direction = false;
direction = parse_direction(direction_str);
}
TAILQ_FOREACH (current, &owindows, owindows) {
Con *ws = con_get_workspace(current->con);
if (!ws || con_is_internal(ws)) {
continue;
}
if (auto_direction) {
orientation_t o = con_orientation(current->con->parent);
direction = direction_from_orientation_position(o, position);
}
tree_next(current->con, direction);
}
tree_render();
return SCM_BOOL_T;
}

View File

@ -223,19 +223,16 @@ bool load_configuration(const char *override_configpath, config_load_t load_type
current_configpath = get_config_path(override_configpath, true); current_configpath = get_config_path(override_configpath, true);
if (current_configpath == NULL) { if (current_configpath == NULL) {
die("Unable to find the configuration file (looked at " die("Unable to find the configuration file (looked at "
"$XDG_CONFIG_HOME/i3/config, ~/.i3/config, $XDG_CONFIG_DIRS/i3/config " "$XDG_CONFIG_HOME/i3/config.scm, ~/.i3/config.scm, $XDG_CONFIG_DIRS/i3/config.scm "
"and " SYSCONFDIR "/i3/config)"); "and " SYSCONFDIR "/i3/config.scm)");
} }
LOG("Parsing configfile %s\n", current_configpath); LOG("Parsing configfile %s\n", current_configpath);
const bool result = parse_file(current_configpath, load_type != C_VALIDATE); const bool result = parse_file(current_configpath);
config.font = load_font("fixed", true); config.font = load_font
(scm_to_locale_string(scm_variable_ref(scm_c_lookup("font"))), false);
set_font(&config.font); set_font(&config.font);
/* /\* i3Font font = load_font(scm_to_locale_string(scm_variable_ref(scm_c_lookup("font"))), false); *\/ */
/* i3Font font = load_font("pango:monospace 20", false); */
/* set_font(&font); */
if (load_type == C_RELOAD) { if (load_type == C_RELOAD) {
translate_keysyms(); translate_keysyms();
grab_all_keys(conn); grab_all_keys(conn);

View File

@ -564,72 +564,6 @@ struct ConfigResultIR *parse_config(const char *input, struct context *context)
return &command_output; return &command_output;
} }
/*
* Goes through each line of buf (separated by \n) and checks for statements /
* commands which only occur in i3 v4 configuration files. If it finds any, it
* returns version 4, otherwise it returns version 3.
*
*/
static int detect_version(char *buf) {
char *walk = buf;
char *line = buf;
while (*walk != '\0') {
if (*walk != '\n') {
walk++;
continue;
}
/* check for some v4-only statements */
if (strncasecmp(line, "bindcode", strlen("bindcode")) == 0 ||
strncasecmp(line, "force_focus_wrapping", strlen("force_focus_wrapping")) == 0 ||
strncasecmp(line, "# i3 config file (v4)", strlen("# i3 config file (v4)")) == 0 ||
strncasecmp(line, "workspace_layout", strlen("workspace_layout")) == 0) {
LOG("deciding for version 4 due to this line: %.*s\n", (int)(walk - line), line);
return 4;
}
/* if this is a bind statement, we can check the command */
if (strncasecmp(line, "bind", strlen("bind")) == 0) {
char *bind = strchr(line, ' ');
if (bind == NULL)
goto next;
while ((*bind == ' ' || *bind == '\t') && *bind != '\0')
bind++;
if (*bind == '\0')
goto next;
if ((bind = strchr(bind, ' ')) == NULL)
goto next;
while ((*bind == ' ' || *bind == '\t') && *bind != '\0')
bind++;
if (*bind == '\0')
goto next;
if (strncasecmp(bind, "layout", strlen("layout")) == 0 ||
strncasecmp(bind, "floating", strlen("floating")) == 0 ||
strncasecmp(bind, "workspace", strlen("workspace")) == 0 ||
strncasecmp(bind, "focus left", strlen("focus left")) == 0 ||
strncasecmp(bind, "focus right", strlen("focus right")) == 0 ||
strncasecmp(bind, "focus up", strlen("focus up")) == 0 ||
strncasecmp(bind, "focus down", strlen("focus down")) == 0 ||
strncasecmp(bind, "border normal", strlen("border normal")) == 0 ||
strncasecmp(bind, "border 1pixel", strlen("border 1pixel")) == 0 ||
strncasecmp(bind, "border pixel", strlen("border pixel")) == 0 ||
strncasecmp(bind, "border borderless", strlen("border borderless")) == 0 ||
strncasecmp(bind, "--no-startup-id", strlen("--no-startup-id")) == 0 ||
strncasecmp(bind, "bar", strlen("bar")) == 0) {
LOG("deciding for version 4 due to this line: %.*s\n", (int)(walk - line), line);
return 4;
}
}
next:
/* advance to the next line */
walk++;
line = walk;
}
return 3;
}
/** /**
* Launch nagbar to indicate errors in the configuration file. * Launch nagbar to indicate errors in the configuration file.
*/ */
@ -658,74 +592,12 @@ void start_config_error_nagbar(const char *configpath, bool has_errors) {
free(pageraction); free(pageraction);
} }
/*
* Inserts or updates a variable assignment depending on whether it already exists.
*
*/
static void upsert_variable(struct variables_head *variables, char *key, char *value) {
struct Variable *current;
SLIST_FOREACH (current, variables, variables) {
if (strcmp(current->key, key) != 0) {
continue;
}
DLOG("Updated variable: %s = %s -> %s\n", key, current->value, value);
FREE(current->value);
current->value = sstrdup(value);
return;
}
DLOG("Defined new variable: %s = %s\n", key, value);
struct Variable *new = scalloc(1, sizeof(struct Variable));
struct Variable *test = NULL, *loc = NULL;
new->key = sstrdup(key);
new->value = sstrdup(value);
/* ensure that the correct variable is matched in case of one being
* the prefix of another */
SLIST_FOREACH (test, variables, variables) {
if (strlen(new->key) >= strlen(test->key))
break;
loc = test;
}
if (loc == NULL) {
SLIST_INSERT_HEAD(variables, new, variables);
} else {
SLIST_INSERT_AFTER(loc, new, variables);
}
}
static char *get_resource(char *name) {
if (conn == NULL) {
return NULL;
}
/* Load the resource database lazily. */
if (database == NULL) {
database = xcb_xrm_database_from_default(conn);
if (database == NULL) {
ELOG("Failed to open the resource database.\n");
/* Load an empty database so we don't keep trying to load the
* default database over and over again. */
database = xcb_xrm_database_from_string("");
return NULL;
}
}
char *resource;
xcb_xrm_resource_get_string(database, name, NULL, &resource);
return resource;
}
/* /*
* Parses the given file by first replacing the variables, then calling * Parses the given file by first replacing the variables, then calling
* parse_config and possibly launching i3-nagbar. * parse_config and possibly launching i3-nagbar.
* *
*/ */
bool parse_file(const char *f, bool use_nagbar) { bool parse_file(const char *f) {
if (database != NULL) { if (database != NULL) {
xcb_xrm_database_free(database); xcb_xrm_database_free(database);
/* Explicitly set the database to NULL again in case the config gets reloaded. */ /* Explicitly set the database to NULL again in case the config gets reloaded. */

2
src/guile-objects.h Normal file
View File

@ -0,0 +1,2 @@
SCM guile_split(SCM direction);

View File

@ -26,6 +26,7 @@
#include <unistd.h> #include <unistd.h>
#include <libguile.h> #include <libguile.h>
#include "guile-objects.h"
#ifdef I3_ASAN_ENABLED #ifdef I3_ASAN_ENABLED
#include <sanitizer/lsan_interface.h> #include <sanitizer/lsan_interface.h>
@ -264,6 +265,8 @@ void set_defaults(void){
scm_c_define("font", scm_from_locale_string("fixed")); scm_c_define("font", scm_from_locale_string("fixed"));
} }
void define_objects(void) { }
SCM guile_binding(SCM g_bindtype, SCM g_modifiers, SCM g_key, SCM g_release, SCM guile_binding(SCM g_bindtype, SCM g_modifiers, SCM g_key, SCM g_release,
SCM g_border, SCM g_whole_window, SCM g_exclude_titlebar, SCM g_border, SCM g_whole_window, SCM g_exclude_titlebar,
SCM g_command) { SCM g_command) {
@ -276,14 +279,64 @@ SCM guile_binding(SCM g_bindtype, SCM g_modifiers, SCM g_key, SCM g_release,
const char * exclude_titlebar = scm_to_locale_string (g_exclude_titlebar); const char * exclude_titlebar = scm_to_locale_string (g_exclude_titlebar);
// procedure // procedure
configure_binding(bindtype, modifiers, key, release, border, whole_window, exclude_titlebar, g_command, DEFAULT_BINDING_MODE, false); configure_binding(bindtype, modifiers, key, release, border, whole_window, exclude_titlebar, g_command, DEFAULT_BINDING_MODE, false);
return scm_from_bool(true); return SCM_BOOL_T;
} }
SCM guile_change_workspace(SCM g_which) {
const char * which = scm_to_locale_string(g_which);
if (con_get_fullscreen_con(croot, CF_GLOBAL)) {
return scm_list_2(SCM_BOOL_F,
scm_from_locale_string("Cannot switch workspace while in global fullscreen"));
}
// TODO: We don't need to parse anything!
long parsed_num = ws_name_to_number(which);
if (parsed_num == -1) {
/* scm_simple_format */
/* (SCM_BOOL_F, */
/* "Could not parse initial part of ~A as a number.", */
/* scm_list_1(which)) */
return scm_list_2(SCM_BOOL_F, scm_from_locale_string("NaN"));
}
Con *workspace = get_existing_workspace_by_num(parsed_num);
if (!workspace) {
workspace_show_by_name(which);
tree_render();
return scm_list_2
(SCM_BOOL_T,
scm_simple_format(SCM_BOOL_F,
scm_from_locale_string("There is no workspace with number ~S, creating a new one.\n"),
scm_list_1(scm_from_int(parsed_num))));
}
workspace_show(workspace);
tree_render();
return SCM_BOOL_T;
}
// Force display update when a variable is changed
// (eg. fonts)
SCM guile_refresh() {
config.font = load_font
(scm_to_locale_string(scm_variable_ref(scm_c_lookup("font"))), false);
set_font(&config.font);
tree_render();
return SCM_BOOL_T;
}
static void* static void*
register_functions (void* data) { register_functions (void* data) {
set_defaults(); set_defaults();
define_objects();
scm_c_define_gsubr ("set-binding", 8, 0, 0, &guile_binding); scm_c_define_gsubr ("set-binding", 8, 0, 0, &guile_binding);
scm_c_define_gsubr ("change-workspace", 1, 0, 0, &guile_change_workspace);
scm_c_define_gsubr ("refresh", 0, 0, 0, &guile_refresh);
scm_c_define_gsubr ("kill", 0, 0, 0, &guile_kill);
scm_c_define_gsubr ("split", 1, 0, 0, &guile_split);
scm_c_define_gsubr ("focus-direction", 1, 0, 0, &guile_focus_direction);
return NULL; return NULL;
} }
@ -525,7 +578,6 @@ int main(int argc, char *argv[]) {
FREE(payload); FREE(payload);
uint32_t reply_length; uint32_t reply_length;
uint32_t reply_type;
uint8_t *reply; uint8_t *reply;
int ret; int ret;
if ((ret = ipc_recv_message(sockfd, &reply_length, &reply)) != 0) { if ((ret = ipc_recv_message(sockfd, &reply_length, &reply)) != 0) {
@ -533,8 +585,6 @@ int main(int argc, char *argv[]) {
err(EXIT_FAILURE, "IPC: read()"); err(EXIT_FAILURE, "IPC: read()");
return 1; return 1;
} }
if (reply_type != I3_IPC_REPLY_TYPE_COMMAND)
errx(EXIT_FAILURE, "IPC: received reply of type %d but expected %d (COMMAND)", reply_type, I3_IPC_REPLY_TYPE_COMMAND);
printf("%.*s\n", reply_length, reply); printf("%.*s\n", reply_length, reply);
FREE(reply); FREE(reply);
return 0; return 0;