many progresses
This commit is contained in:
parent
29f551626e
commit
c8f383329d
|
@ -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(¤t_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(¤t_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(¤t_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(¤t_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(¤t_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(¤t_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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
131
src/click.c
131
src/click.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
273
src/commands.c
273
src/commands.c
|
@ -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;
|
||||||
|
}
|
||||||
|
|
15
src/config.c
15
src/config.c
|
@ -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);
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
SCM guile_split(SCM direction);
|
58
src/main.c
58
src/main.c
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue