Merge pull request #1697 from Airblader/feature-1695
Extend mouse commands on i3bar
This commit is contained in:
commit
696d844ffa
|
@ -1209,23 +1209,41 @@ Available modifiers are Mod1-Mod5, Shift, Control (see +xmodmap(1)+).
|
||||||
=== Mouse button commands
|
=== Mouse button commands
|
||||||
|
|
||||||
Specifies a command to run when a button was pressed on i3bar to override the
|
Specifies a command to run when a button was pressed on i3bar to override the
|
||||||
default behavior. Currently only the mouse wheel buttons are supported. This is
|
default behavior. This is useful, e.g., for disabling the scroll wheel action
|
||||||
useful for disabling the scroll wheel action or running scripts that implement
|
or running scripts that implement custom behavior for these buttons.
|
||||||
custom behavior for these buttons.
|
|
||||||
|
A button is always named +button<n>+, where 1 to 5 are default buttons as follows and higher
|
||||||
|
numbers can be special buttons on devices offering more buttons:
|
||||||
|
|
||||||
|
button1::
|
||||||
|
Left mouse button.
|
||||||
|
button2::
|
||||||
|
Middle mouse button.
|
||||||
|
button3::
|
||||||
|
Right mouse button.
|
||||||
|
button4::
|
||||||
|
Scroll wheel up.
|
||||||
|
button5::
|
||||||
|
Scroll wheel down.
|
||||||
|
|
||||||
|
Please note that the old +wheel_up_cmd+ and +wheel_down_cmd+ commands are deprecated
|
||||||
|
and will be removed in a future release. We strongly recommend using the more general
|
||||||
|
+bindsym+ with +button4+ and +button5+ instead.
|
||||||
|
|
||||||
*Syntax*:
|
*Syntax*:
|
||||||
---------------------
|
----------------------------
|
||||||
wheel_up_cmd <command>
|
bindsym button<n> <command>
|
||||||
wheel_down_cmd <command>
|
----------------------------
|
||||||
---------------------
|
|
||||||
|
|
||||||
*Example*:
|
*Example*:
|
||||||
---------------------
|
---------------------------------------------------------
|
||||||
bar {
|
bar {
|
||||||
wheel_up_cmd nop
|
# disable clicking on workspace buttons
|
||||||
wheel_down_cmd exec ~/.i3/scripts/custom_wheel_down
|
bindsym button1 nop
|
||||||
|
# execute custom script when scrolling downwards
|
||||||
|
bindsym button5 exec ~/.i3/scripts/custom_wheel_down
|
||||||
}
|
}
|
||||||
---------------------
|
---------------------------------------------------------
|
||||||
|
|
||||||
=== Bar ID
|
=== Bar ID
|
||||||
|
|
||||||
|
|
|
@ -22,10 +22,16 @@ typedef enum { M_DOCK = 0,
|
||||||
M_HIDE = 1,
|
M_HIDE = 1,
|
||||||
M_INVISIBLE = 2 } bar_display_mode_t;
|
M_INVISIBLE = 2 } bar_display_mode_t;
|
||||||
|
|
||||||
|
typedef struct binding_t {
|
||||||
|
int input_code;
|
||||||
|
char *command;
|
||||||
|
|
||||||
|
TAILQ_ENTRY(binding_t) bindings;
|
||||||
|
} binding_t;
|
||||||
|
|
||||||
typedef struct config_t {
|
typedef struct config_t {
|
||||||
int modifier;
|
int modifier;
|
||||||
char *wheel_up_cmd;
|
TAILQ_HEAD(bindings_head, binding_t) bindings;
|
||||||
char *wheel_down_cmd;
|
|
||||||
position_t position;
|
position_t position;
|
||||||
int verbose;
|
int verbose;
|
||||||
struct xcb_color_strings_t colors;
|
struct xcb_color_strings_t colors;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
static char *cur_key;
|
static char *cur_key;
|
||||||
|
static bool parsing_bindings;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse a key.
|
* Parse a key.
|
||||||
|
@ -34,6 +35,14 @@ static int config_map_key_cb(void *params_, const unsigned char *keyVal, size_t
|
||||||
strncpy(cur_key, (const char *)keyVal, keyLen);
|
strncpy(cur_key, (const char *)keyVal, keyLen);
|
||||||
cur_key[keyLen] = '\0';
|
cur_key[keyLen] = '\0';
|
||||||
|
|
||||||
|
if (strcmp(cur_key, "bindings") == 0)
|
||||||
|
parsing_bindings = true;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int config_end_array_cb(void *params_) {
|
||||||
|
parsing_bindings = false;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +72,27 @@ static int config_string_cb(void *params_, const unsigned char *val, size_t _len
|
||||||
if (!strcmp(cur_key, "id") || !strcmp(cur_key, "socket_path"))
|
if (!strcmp(cur_key, "id") || !strcmp(cur_key, "socket_path"))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
if (parsing_bindings) {
|
||||||
|
if (strcmp(cur_key, "command") == 0) {
|
||||||
|
binding_t *binding = TAILQ_LAST(&(config.bindings), bindings_head);
|
||||||
|
if (binding == NULL) {
|
||||||
|
ELOG("There is no binding to put the current command onto. This is a bug in i3.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binding->command != NULL) {
|
||||||
|
ELOG("The binding for input_code = %d already has a command. This is a bug in i3.\n", binding->input_code);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sasprintf(&(binding->command), "%.*s", len, val);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ELOG("Unknown key \"%s\" while parsing bar bindings.\n", cur_key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp(cur_key, "mode")) {
|
if (!strcmp(cur_key, "mode")) {
|
||||||
DLOG("mode = %.*s, len = %d\n", len, val, len);
|
DLOG("mode = %.*s, len = %d\n", len, val, len);
|
||||||
config.hide_on_modifier = (len == 4 && !strncmp((const char *)val, "dock", strlen("dock")) ? M_DOCK
|
config.hide_on_modifier = (len == 4 && !strncmp((const char *)val, "dock", strlen("dock")) ? M_DOCK
|
||||||
|
@ -112,17 +142,25 @@ static int config_string_cb(void *params_, const unsigned char *val, size_t _len
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This key was sent in <= 4.10.2. We keep it around to avoid breakage for
|
||||||
|
* users updating from that version and restarting i3bar before i3. */
|
||||||
if (!strcmp(cur_key, "wheel_up_cmd")) {
|
if (!strcmp(cur_key, "wheel_up_cmd")) {
|
||||||
DLOG("wheel_up_cmd = %.*s\n", len, val);
|
DLOG("wheel_up_cmd = %.*s\n", len, val);
|
||||||
FREE(config.wheel_up_cmd);
|
binding_t *binding = scalloc(sizeof(binding_t));
|
||||||
sasprintf(&config.wheel_up_cmd, "%.*s", len, val);
|
binding->input_code = 4;
|
||||||
|
sasprintf(&(binding->command), "%.*s", len, val);
|
||||||
|
TAILQ_INSERT_TAIL(&(config.bindings), binding, bindings);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This key was sent in <= 4.10.2. We keep it around to avoid breakage for
|
||||||
|
* users updating from that version and restarting i3bar before i3. */
|
||||||
if (!strcmp(cur_key, "wheel_down_cmd")) {
|
if (!strcmp(cur_key, "wheel_down_cmd")) {
|
||||||
DLOG("wheel_down_cmd = %.*s\n", len, val);
|
DLOG("wheel_down_cmd = %.*s\n", len, val);
|
||||||
FREE(config.wheel_down_cmd);
|
binding_t *binding = scalloc(sizeof(binding_t));
|
||||||
sasprintf(&config.wheel_down_cmd, "%.*s", len, val);
|
binding->input_code = 5;
|
||||||
|
sasprintf(&(binding->command), "%.*s", len, val);
|
||||||
|
TAILQ_INSERT_TAIL(&(config.bindings), binding, bindings);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,11 +270,34 @@ static int config_boolean_cb(void *params_, int val) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse an integer value
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int config_integer_cb(void *params_, long long val) {
|
||||||
|
if (parsing_bindings) {
|
||||||
|
if (strcmp(cur_key, "input_code") == 0) {
|
||||||
|
binding_t *binding = scalloc(sizeof(binding_t));
|
||||||
|
binding->input_code = val;
|
||||||
|
TAILQ_INSERT_TAIL(&(config.bindings), binding, bindings);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ELOG("Unknown key \"%s\" while parsing bar bindings.\n", cur_key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* A datastructure to pass all these callbacks to yajl */
|
/* A datastructure to pass all these callbacks to yajl */
|
||||||
static yajl_callbacks outputs_callbacks = {
|
static yajl_callbacks outputs_callbacks = {
|
||||||
.yajl_null = config_null_cb,
|
.yajl_null = config_null_cb,
|
||||||
.yajl_boolean = config_boolean_cb,
|
.yajl_boolean = config_boolean_cb,
|
||||||
|
.yajl_integer = config_integer_cb,
|
||||||
.yajl_string = config_string_cb,
|
.yajl_string = config_string_cb,
|
||||||
|
.yajl_end_array = config_end_array_cb,
|
||||||
.yajl_map_key = config_map_key_cb,
|
.yajl_map_key = config_map_key_cb,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -249,6 +310,8 @@ void parse_config_json(char *json) {
|
||||||
yajl_status state;
|
yajl_status state;
|
||||||
handle = yajl_alloc(&outputs_callbacks, NULL, NULL);
|
handle = yajl_alloc(&outputs_callbacks, NULL, NULL);
|
||||||
|
|
||||||
|
TAILQ_INIT(&(config.bindings));
|
||||||
|
|
||||||
state = yajl_parse(handle, (const unsigned char *)json, strlen(json));
|
state = yajl_parse(handle, (const unsigned char *)json, strlen(json));
|
||||||
|
|
||||||
/* FIXME: Proper error handling for JSON parsing */
|
/* FIXME: Proper error handling for JSON parsing */
|
||||||
|
|
|
@ -468,20 +468,23 @@ void handle_button(xcb_button_press_event_t *event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If a custom command was specified for this mouse button, it overrides
|
||||||
|
* the default behavior. */
|
||||||
|
binding_t *binding;
|
||||||
|
TAILQ_FOREACH(binding, &(config.bindings), bindings) {
|
||||||
|
if (binding->input_code != event->detail)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, binding->command);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (event->detail) {
|
switch (event->detail) {
|
||||||
case 4:
|
case 4:
|
||||||
/* Mouse wheel up. We select the previous ws, if any.
|
/* Mouse wheel up. We select the previous ws, if any.
|
||||||
* If there is no more workspace, don’t even send the workspace
|
* If there is no more workspace, don’t even send the workspace
|
||||||
* command, otherwise (with workspace auto_back_and_forth) we’d end
|
* command, otherwise (with workspace auto_back_and_forth) we’d end
|
||||||
* up on the wrong workspace. */
|
* up on the wrong workspace. */
|
||||||
|
|
||||||
/* If `wheel_up_cmd [COMMAND]` was specified, it should override
|
|
||||||
* the default behavior */
|
|
||||||
if (config.wheel_up_cmd) {
|
|
||||||
i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, config.wheel_up_cmd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cur_ws == TAILQ_FIRST(walk->workspaces))
|
if (cur_ws == TAILQ_FIRST(walk->workspaces))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -492,14 +495,6 @@ void handle_button(xcb_button_press_event_t *event) {
|
||||||
* If there is no more workspace, don’t even send the workspace
|
* If there is no more workspace, don’t even send the workspace
|
||||||
* command, otherwise (with workspace auto_back_and_forth) we’d end
|
* command, otherwise (with workspace auto_back_and_forth) we’d end
|
||||||
* up on the wrong workspace. */
|
* up on the wrong workspace. */
|
||||||
|
|
||||||
/* if `wheel_down_cmd [COMMAND]` was specified, it should override
|
|
||||||
* the default behavior */
|
|
||||||
if (config.wheel_down_cmd) {
|
|
||||||
i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, config.wheel_down_cmd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cur_ws == TAILQ_LAST(walk->workspaces, ws_head))
|
if (cur_ws == TAILQ_LAST(walk->workspaces, ws_head))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -281,13 +281,7 @@ struct Barconfig {
|
||||||
M_MOD5 = 7
|
M_MOD5 = 7
|
||||||
} modifier;
|
} modifier;
|
||||||
|
|
||||||
/** Command that should be run when mouse wheel up button is pressed over
|
TAILQ_HEAD(bar_bindings_head, Barbinding) bar_bindings;
|
||||||
* i3bar to override the default behavior. */
|
|
||||||
char *wheel_up_cmd;
|
|
||||||
|
|
||||||
/** Command that should be run when mouse wheel down button is pressed over
|
|
||||||
* i3bar to override the default behavior. */
|
|
||||||
char *wheel_down_cmd;
|
|
||||||
|
|
||||||
/** Bar position (bottom by default). */
|
/** Bar position (bottom by default). */
|
||||||
enum { P_BOTTOM = 0,
|
enum { P_BOTTOM = 0,
|
||||||
|
@ -353,6 +347,21 @@ struct Barconfig {
|
||||||
TAILQ_ENTRY(Barconfig) configs;
|
TAILQ_ENTRY(Barconfig) configs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a mouse command to be executed instead of the default behavior when
|
||||||
|
* clicking on the non-statusline part of i3bar.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct Barbinding {
|
||||||
|
/** The button to be used (e.g., 1 for "button1"). */
|
||||||
|
int input_code;
|
||||||
|
|
||||||
|
/** The command which is to be executed for this button. */
|
||||||
|
char *command;
|
||||||
|
|
||||||
|
TAILQ_ENTRY(Barbinding) bindings;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the configuration file to use (either the one specified by
|
* Finds the configuration file to use (either the one specified by
|
||||||
* override_configpath), the user’s one or the system default) and calls
|
* override_configpath), the user’s one or the system default) and calls
|
||||||
|
|
|
@ -80,6 +80,7 @@ CFGFUN(bar_verbose, const char *verbose);
|
||||||
CFGFUN(bar_modifier, const char *modifier);
|
CFGFUN(bar_modifier, const char *modifier);
|
||||||
CFGFUN(bar_wheel_up_cmd, const char *command);
|
CFGFUN(bar_wheel_up_cmd, const char *command);
|
||||||
CFGFUN(bar_wheel_down_cmd, const char *command);
|
CFGFUN(bar_wheel_down_cmd, const char *command);
|
||||||
|
CFGFUN(bar_bindsym, const char *button, const char *command);
|
||||||
CFGFUN(bar_position, const char *position);
|
CFGFUN(bar_position, const char *position);
|
||||||
CFGFUN(bar_i3bar_command, const char *i3bar_command);
|
CFGFUN(bar_i3bar_command, const char *i3bar_command);
|
||||||
CFGFUN(bar_color, const char *colorclass, const char *border, const char *background, const char *text);
|
CFGFUN(bar_color, const char *colorclass, const char *border, const char *background, const char *text);
|
||||||
|
@ -90,4 +91,5 @@ CFGFUN(bar_status_command, const char *command);
|
||||||
CFGFUN(bar_binding_mode_indicator, const char *value);
|
CFGFUN(bar_binding_mode_indicator, const char *value);
|
||||||
CFGFUN(bar_workspace_buttons, const char *value);
|
CFGFUN(bar_workspace_buttons, const char *value);
|
||||||
CFGFUN(bar_strip_workspace_numbers, const char *value);
|
CFGFUN(bar_strip_workspace_numbers, const char *value);
|
||||||
|
CFGFUN(bar_start);
|
||||||
CFGFUN(bar_finish);
|
CFGFUN(bar_finish);
|
||||||
|
|
|
@ -393,7 +393,7 @@ state BARBRACE:
|
||||||
end
|
end
|
||||||
->
|
->
|
||||||
'{'
|
'{'
|
||||||
-> BAR
|
-> call cfg_bar_start(); BAR
|
||||||
|
|
||||||
state BAR:
|
state BAR:
|
||||||
end ->
|
end ->
|
||||||
|
@ -409,6 +409,7 @@ state BAR:
|
||||||
'modifier' -> BAR_MODIFIER
|
'modifier' -> BAR_MODIFIER
|
||||||
'wheel_up_cmd' -> BAR_WHEEL_UP_CMD
|
'wheel_up_cmd' -> BAR_WHEEL_UP_CMD
|
||||||
'wheel_down_cmd' -> BAR_WHEEL_DOWN_CMD
|
'wheel_down_cmd' -> BAR_WHEEL_DOWN_CMD
|
||||||
|
'bindsym' -> BAR_BINDSYM
|
||||||
'position' -> BAR_POSITION
|
'position' -> BAR_POSITION
|
||||||
'output' -> BAR_OUTPUT
|
'output' -> BAR_OUTPUT
|
||||||
'tray_output' -> BAR_TRAY_OUTPUT
|
'tray_output' -> BAR_TRAY_OUTPUT
|
||||||
|
@ -463,6 +464,14 @@ state BAR_WHEEL_DOWN_CMD:
|
||||||
command = string
|
command = string
|
||||||
-> call cfg_bar_wheel_down_cmd($command); BAR
|
-> call cfg_bar_wheel_down_cmd($command); BAR
|
||||||
|
|
||||||
|
state BAR_BINDSYM:
|
||||||
|
button = word
|
||||||
|
-> BAR_BINDSYM_COMMAND
|
||||||
|
|
||||||
|
state BAR_BINDSYM_COMMAND:
|
||||||
|
command = string
|
||||||
|
-> call cfg_bar_bindsym($button, $command); BAR
|
||||||
|
|
||||||
state BAR_POSITION:
|
state BAR_POSITION:
|
||||||
position = 'top', 'bottom'
|
position = 'top', 'bottom'
|
||||||
-> call cfg_bar_position($position); BAR
|
-> call cfg_bar_position($position); BAR
|
||||||
|
|
|
@ -530,14 +530,44 @@ CFGFUN(bar_modifier, const char *modifier) {
|
||||||
current_bar.modifier = M_SHIFT;
|
current_bar.modifier = M_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bar_configure_binding(const char *button, const char *command) {
|
||||||
|
if (strncasecmp(button, "button", strlen("button")) != 0) {
|
||||||
|
ELOG("Bindings for a bar can only be mouse bindings, not \"%s\", ignoring.\n", button);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int input_code = atoi(button + strlen("button"));
|
||||||
|
if (input_code < 1) {
|
||||||
|
ELOG("Button \"%s\" does not seem to be in format 'buttonX'.\n", button);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Barbinding *current;
|
||||||
|
TAILQ_FOREACH(current, &(current_bar.bar_bindings), bindings) {
|
||||||
|
if (current->input_code == input_code) {
|
||||||
|
ELOG("command for button %s was already specified, ignoring.\n", button);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Barbinding *new_binding = scalloc(sizeof(struct Barbinding));
|
||||||
|
new_binding->input_code = input_code;
|
||||||
|
new_binding->command = sstrdup(command);
|
||||||
|
TAILQ_INSERT_TAIL(&(current_bar.bar_bindings), new_binding, bindings);
|
||||||
|
}
|
||||||
|
|
||||||
CFGFUN(bar_wheel_up_cmd, const char *command) {
|
CFGFUN(bar_wheel_up_cmd, const char *command) {
|
||||||
FREE(current_bar.wheel_up_cmd);
|
ELOG("'wheel_up_cmd' is deprecated. Please us 'bindsym button4 %s' instead.\n", command);
|
||||||
current_bar.wheel_up_cmd = sstrdup(command);
|
bar_configure_binding("button4", command);
|
||||||
}
|
}
|
||||||
|
|
||||||
CFGFUN(bar_wheel_down_cmd, const char *command) {
|
CFGFUN(bar_wheel_down_cmd, const char *command) {
|
||||||
FREE(current_bar.wheel_down_cmd);
|
ELOG("'wheel_down_cmd' is deprecated. Please us 'bindsym button5 %s' instead.\n", command);
|
||||||
current_bar.wheel_down_cmd = sstrdup(command);
|
bar_configure_binding("button5", command);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFGFUN(bar_bindsym, const char *button, const char *command) {
|
||||||
|
bar_configure_binding(button, command);
|
||||||
}
|
}
|
||||||
|
|
||||||
CFGFUN(bar_position, const char *position) {
|
CFGFUN(bar_position, const char *position) {
|
||||||
|
@ -611,6 +641,10 @@ CFGFUN(bar_strip_workspace_numbers, const char *value) {
|
||||||
current_bar.strip_workspace_numbers = eval_boolstr(value);
|
current_bar.strip_workspace_numbers = eval_boolstr(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFGFUN(bar_start) {
|
||||||
|
TAILQ_INIT(&(current_bar.bar_bindings));
|
||||||
|
}
|
||||||
|
|
||||||
CFGFUN(bar_finish) {
|
CFGFUN(bar_finish) {
|
||||||
DLOG("\t new bar configuration finished, saving.\n");
|
DLOG("\t new bar configuration finished, saving.\n");
|
||||||
/* Generate a unique ID for this bar if not already configured */
|
/* Generate a unique ID for this bar if not already configured */
|
||||||
|
|
32
src/ipc.c
32
src/ipc.c
|
@ -469,6 +469,28 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
|
||||||
y(map_close);
|
y(map_close);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dump_bar_bindings(yajl_gen gen, Barconfig *config) {
|
||||||
|
if (TAILQ_EMPTY(&(config->bar_bindings)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ystr("bindings");
|
||||||
|
y(array_open);
|
||||||
|
|
||||||
|
struct Barbinding *current;
|
||||||
|
TAILQ_FOREACH(current, &(config->bar_bindings), bindings) {
|
||||||
|
y(map_open);
|
||||||
|
|
||||||
|
ystr("input_code");
|
||||||
|
y(integer, current->input_code);
|
||||||
|
ystr("command");
|
||||||
|
ystr(current->command);
|
||||||
|
|
||||||
|
y(map_close);
|
||||||
|
}
|
||||||
|
|
||||||
|
y(array_close);
|
||||||
|
}
|
||||||
|
|
||||||
static void dump_bar_config(yajl_gen gen, Barconfig *config) {
|
static void dump_bar_config(yajl_gen gen, Barconfig *config) {
|
||||||
y(map_open);
|
y(map_open);
|
||||||
|
|
||||||
|
@ -549,15 +571,7 @@ static void dump_bar_config(yajl_gen gen, Barconfig *config) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->wheel_up_cmd) {
|
dump_bar_bindings(gen, config);
|
||||||
ystr("wheel_up_cmd");
|
|
||||||
ystr(config->wheel_up_cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config->wheel_down_cmd) {
|
|
||||||
ystr("wheel_down_cmd");
|
|
||||||
ystr(config->wheel_down_cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
ystr("position");
|
ystr("position");
|
||||||
if (config->position == P_BOTTOM)
|
if (config->position == P_BOTTOM)
|
||||||
|
|
|
@ -688,8 +688,9 @@ bar {
|
||||||
EOT
|
EOT
|
||||||
|
|
||||||
$expected = <<'EOT';
|
$expected = <<'EOT';
|
||||||
|
cfg_bar_start()
|
||||||
cfg_bar_output(LVDS-1)
|
cfg_bar_output(LVDS-1)
|
||||||
ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'i3bar_command', 'status_command', 'socket_path', 'mode', 'hidden_state', 'id', 'modifier', 'wheel_up_cmd', 'wheel_down_cmd', 'position', 'output', 'tray_output', 'font', 'separator_symbol', 'binding_mode_indicator', 'workspace_buttons', 'strip_workspace_numbers', 'verbose', 'colors', '}'
|
ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'i3bar_command', 'status_command', 'socket_path', 'mode', 'hidden_state', 'id', 'modifier', 'wheel_up_cmd', 'wheel_down_cmd', 'bindsym', 'position', 'output', 'tray_output', 'font', 'separator_symbol', 'binding_mode_indicator', 'workspace_buttons', 'strip_workspace_numbers', 'verbose', 'colors', '}'
|
||||||
ERROR: CONFIG: (in file <stdin>)
|
ERROR: CONFIG: (in file <stdin>)
|
||||||
ERROR: CONFIG: Line 1: bar {
|
ERROR: CONFIG: Line 1: bar {
|
||||||
ERROR: CONFIG: Line 2: output LVDS-1
|
ERROR: CONFIG: Line 2: output LVDS-1
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
#!perl
|
||||||
|
# vim:ts=4:sw=4:expandtab
|
||||||
|
#
|
||||||
|
# Please read the following documents before working on tests:
|
||||||
|
# • http://build.i3wm.org/docs/testsuite.html
|
||||||
|
# (or docs/testsuite)
|
||||||
|
#
|
||||||
|
# • http://build.i3wm.org/docs/lib-i3test.html
|
||||||
|
# (alternatively: perldoc ./testcases/lib/i3test.pm)
|
||||||
|
#
|
||||||
|
# • http://build.i3wm.org/docs/ipc.html
|
||||||
|
# (or docs/ipc)
|
||||||
|
#
|
||||||
|
# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
|
||||||
|
# (unless you are already familiar with Perl)
|
||||||
|
#
|
||||||
|
# Ensures that mouse bindings on the i3bar work correctly.
|
||||||
|
# Ticket: #1695
|
||||||
|
use i3test i3_autostart => 0;
|
||||||
|
|
||||||
|
my ($cv, $timer);
|
||||||
|
sub reset_test {
|
||||||
|
$cv = AE::cv;
|
||||||
|
$timer = AE::timer(1, 0, sub { $cv->send(0); });
|
||||||
|
}
|
||||||
|
|
||||||
|
my $config = <<EOT;
|
||||||
|
# i3 config file (v4)
|
||||||
|
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||||
|
focus_follows_mouse no
|
||||||
|
|
||||||
|
bar {
|
||||||
|
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||||
|
position top
|
||||||
|
|
||||||
|
bindsym button1 focus left
|
||||||
|
bindsym button2 focus right
|
||||||
|
bindsym button3 focus left
|
||||||
|
bindsym button4 focus right
|
||||||
|
bindsym button5 focus left
|
||||||
|
}
|
||||||
|
EOT
|
||||||
|
|
||||||
|
SKIP: {
|
||||||
|
qx(command -v xdotool 2> /dev/null);
|
||||||
|
skip 'xdotool is required for this test', 1 if $?;
|
||||||
|
|
||||||
|
my $pid = launch_with_config($config);
|
||||||
|
my $i3 = i3(get_socket_path());
|
||||||
|
$i3->connect()->recv;
|
||||||
|
my $ws = fresh_workspace;
|
||||||
|
|
||||||
|
reset_test;
|
||||||
|
$i3->subscribe({
|
||||||
|
window => sub {
|
||||||
|
my ($event) = @_;
|
||||||
|
if ($event->{change} eq 'focus') {
|
||||||
|
$cv->send($event->{container});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})->recv;
|
||||||
|
|
||||||
|
my $left = open_window;
|
||||||
|
my $right = open_window;
|
||||||
|
sync_with_i3;
|
||||||
|
my $con = $cv->recv;
|
||||||
|
is($con->{window}, $right->{id}, 'focus is initially on the right container');
|
||||||
|
reset_test;
|
||||||
|
|
||||||
|
qx(xdotool mousemove 3 3 click 1);
|
||||||
|
sync_with_i3;
|
||||||
|
$con = $cv->recv;
|
||||||
|
is($con->{window}, $left->{id}, 'button 1 moves focus left');
|
||||||
|
reset_test;
|
||||||
|
|
||||||
|
qx(xdotool mousemove 3 3 click 2);
|
||||||
|
sync_with_i3;
|
||||||
|
$con = $cv->recv;
|
||||||
|
is($con->{window}, $right->{id}, 'button 2 moves focus right');
|
||||||
|
reset_test;
|
||||||
|
|
||||||
|
qx(xdotool mousemove 3 3 click 3);
|
||||||
|
sync_with_i3;
|
||||||
|
$con = $cv->recv;
|
||||||
|
is($con->{window}, $left->{id}, 'button 3 moves focus left');
|
||||||
|
reset_test;
|
||||||
|
|
||||||
|
qx(xdotool mousemove 3 3 click 4);
|
||||||
|
sync_with_i3;
|
||||||
|
$con = $cv->recv;
|
||||||
|
is($con->{window}, $right->{id}, 'button 4 moves focus right');
|
||||||
|
reset_test;
|
||||||
|
|
||||||
|
qx(xdotool mousemove 3 3 click 5);
|
||||||
|
sync_with_i3;
|
||||||
|
$con = $cv->recv;
|
||||||
|
is($con->{window}, $left->{id}, 'button 5 moves focus left');
|
||||||
|
reset_test;
|
||||||
|
|
||||||
|
exit_gracefully($pid);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
done_testing;
|
Loading…
Reference in New Issue