mirror of
https://github.com/labwc/labwc.git
synced 2026-04-10 08:21:07 -04:00
query: allow nested conditional actions
This commit is contained in:
parent
b2623ce1e3
commit
fb14ac9c0f
1 changed files with 127 additions and 87 deletions
|
|
@ -49,7 +49,8 @@ struct parser_state {
|
||||||
bool in_touch;
|
bool in_touch;
|
||||||
bool in_libinput_category;
|
bool in_libinput_category;
|
||||||
bool in_window_switcher_field;
|
bool in_window_switcher_field;
|
||||||
bool in_window_rules;
|
bool in_window_rule;
|
||||||
|
bool in_action;
|
||||||
bool in_action_query;
|
bool in_action_query;
|
||||||
bool in_action_then_branch;
|
bool in_action_then_branch;
|
||||||
bool in_action_else_branch;
|
bool in_action_else_branch;
|
||||||
|
|
@ -60,14 +61,13 @@ struct parser_state {
|
||||||
struct touch_config_entry *current_touch;
|
struct touch_config_entry *current_touch;
|
||||||
struct libinput_category *current_libinput_category;
|
struct libinput_category *current_libinput_category;
|
||||||
const char *current_mouse_context;
|
const char *current_mouse_context;
|
||||||
struct action *current_keybind_action;
|
|
||||||
struct action *current_mousebind_action;
|
|
||||||
struct region *current_region;
|
struct region *current_region;
|
||||||
struct window_switcher_field *current_field;
|
struct window_switcher_field *current_field;
|
||||||
struct window_rule *current_window_rule;
|
struct window_rule *current_window_rule;
|
||||||
struct action *current_window_rule_action;
|
|
||||||
struct view_query *current_view_query;
|
struct view_query *current_view_query;
|
||||||
struct action *current_child_action;
|
struct action *current_inline_action;
|
||||||
|
struct wl_list *current_action_siblings;
|
||||||
|
struct action *current_action;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* for backward compatibility of <mouse><scrollFactor> */
|
/* for backward compatibility of <mouse><scrollFactor> */
|
||||||
|
|
@ -279,10 +279,14 @@ fill_window_rule(char *nodename, char *content, struct parser_state *state)
|
||||||
state->current_window_rule->window_type = -1; // Window types are >= 0
|
state->current_window_rule->window_type = -1; // Window types are >= 0
|
||||||
wl_list_append(&rc.window_rules, &state->current_window_rule->link);
|
wl_list_append(&rc.window_rules, &state->current_window_rule->link);
|
||||||
wl_list_init(&state->current_window_rule->actions);
|
wl_list_init(&state->current_window_rule->actions);
|
||||||
|
state->current_action = NULL;
|
||||||
|
state->current_action_siblings = &state->current_window_rule->actions;
|
||||||
|
state->current_inline_action = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string_truncate_at_pattern(nodename, ".windowrule.windowrules");
|
string_truncate_at_pattern(nodename, ".windowrule.windowrules");
|
||||||
|
|
||||||
if (!content) {
|
if (!content) {
|
||||||
/* nop */
|
/* nop */
|
||||||
} else if (!state->current_window_rule) {
|
} else if (!state->current_window_rule) {
|
||||||
|
|
@ -328,16 +332,16 @@ fill_window_rule(char *nodename, char *content, struct parser_state *state)
|
||||||
|
|
||||||
/* Actions */
|
/* Actions */
|
||||||
} else if (!strcmp(nodename, "name.action")) {
|
} else if (!strcmp(nodename, "name.action")) {
|
||||||
state->current_window_rule_action = action_create(content);
|
state->current_inline_action = action_create(content);
|
||||||
if (state->current_window_rule_action) {
|
if (state->current_inline_action) {
|
||||||
wl_list_append(&state->current_window_rule->actions,
|
wl_list_append(&state->current_window_rule->actions,
|
||||||
&state->current_window_rule_action->link);
|
&state->current_inline_action->link);
|
||||||
}
|
}
|
||||||
} else if (!state->current_window_rule_action) {
|
} else if (!state->current_inline_action) {
|
||||||
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
||||||
"nodename: '%s' content: '%s'", nodename, content);
|
"nodename: '%s' content: '%s'", nodename, content);
|
||||||
} else {
|
} else {
|
||||||
action_arg_from_xml_node(state->current_window_rule_action, nodename, content);
|
action_arg_from_xml_node(state->current_inline_action, nodename, content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -399,15 +403,19 @@ fill_region(char *nodename, char *content, struct parser_state *state)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fill_action_query(char *nodename, char *content, struct action *action, struct parser_state *state)
|
fill_action_query(char *nodename, char *content, struct parser_state *state)
|
||||||
{
|
{
|
||||||
if (!action) {
|
if (!state->current_action) {
|
||||||
wlr_log(WLR_ERROR, "No parent action for query: %s=%s", nodename, content);
|
wlr_log(WLR_ERROR, "No parent action for query: %s=%s", nodename, content);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string_truncate_at_pattern(nodename, ".windowrule.windowrules");
|
||||||
string_truncate_at_pattern(nodename, ".keybind.keyboard");
|
string_truncate_at_pattern(nodename, ".keybind.keyboard");
|
||||||
string_truncate_at_pattern(nodename, ".mousebind.context.mouse");
|
string_truncate_at_pattern(nodename, ".mousebind.context.mouse");
|
||||||
|
string_truncate_at_pattern(nodename, ".then.action");
|
||||||
|
string_truncate_at_pattern(nodename, ".else.action");
|
||||||
|
string_truncate_at_pattern(nodename, ".none.action");
|
||||||
|
|
||||||
if (!strcasecmp(nodename, "query.action")) {
|
if (!strcasecmp(nodename, "query.action")) {
|
||||||
state->current_view_query = NULL;
|
state->current_view_query = NULL;
|
||||||
|
|
@ -420,10 +428,10 @@ fill_action_query(char *nodename, char *content, struct action *action, struct p
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!state->current_view_query) {
|
if (!state->current_view_query) {
|
||||||
struct wl_list *queries = action_get_querylist(action, "query");
|
struct wl_list *queries = action_get_querylist(state->current_action, "query");
|
||||||
if (!queries) {
|
if (!queries) {
|
||||||
action_arg_add_querylist(action, "query");
|
action_arg_add_querylist(state->current_action, "query");
|
||||||
queries = action_get_querylist(action, "query");
|
queries = action_get_querylist(state->current_action, "query");
|
||||||
}
|
}
|
||||||
state->current_view_query = view_query_create();
|
state->current_view_query = view_query_create();
|
||||||
wl_list_append(queries, &state->current_view_query->link);
|
wl_list_append(queries, &state->current_view_query->link);
|
||||||
|
|
@ -463,14 +471,9 @@ fill_action_query(char *nodename, char *content, struct action *action, struct p
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fill_child_action(char *nodename, char *content, struct action *parent,
|
fill_action(char *nodename, char *content, struct parser_state *state)
|
||||||
const char *branch_name, struct parser_state *state)
|
|
||||||
{
|
{
|
||||||
if (!parent) {
|
string_truncate_at_pattern(nodename, ".windowrule.windowrules");
|
||||||
wlr_log(WLR_ERROR, "No parent action for branch: %s=%s", nodename, content);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string_truncate_at_pattern(nodename, ".keybind.keyboard");
|
string_truncate_at_pattern(nodename, ".keybind.keyboard");
|
||||||
string_truncate_at_pattern(nodename, ".mousebind.context.mouse");
|
string_truncate_at_pattern(nodename, ".mousebind.context.mouse");
|
||||||
string_truncate_at_pattern(nodename, ".then.action");
|
string_truncate_at_pattern(nodename, ".then.action");
|
||||||
|
|
@ -478,33 +481,60 @@ fill_child_action(char *nodename, char *content, struct action *parent,
|
||||||
string_truncate_at_pattern(nodename, ".none.action");
|
string_truncate_at_pattern(nodename, ".none.action");
|
||||||
|
|
||||||
if (!strcasecmp(nodename, "action")) {
|
if (!strcasecmp(nodename, "action")) {
|
||||||
state->current_child_action = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!content) {
|
|
||||||
return;
|
return;
|
||||||
|
} else if (!strcmp(nodename, "name.action")) {
|
||||||
|
state->current_action = action_create(content);
|
||||||
|
if (state->current_action) {
|
||||||
|
wl_list_append(state->current_action_siblings,
|
||||||
|
&state->current_action->link);
|
||||||
}
|
}
|
||||||
|
} else if (!state->current_action) {
|
||||||
struct wl_list *siblings = action_get_actionlist(parent, branch_name);
|
|
||||||
if (!siblings) {
|
|
||||||
action_arg_add_actionlist(parent, branch_name);
|
|
||||||
siblings = action_get_actionlist(parent, branch_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcasecmp(nodename, "name.action")) {
|
|
||||||
if (!strcasecmp(content, "If") || !strcasecmp(content, "ForEach")) {
|
|
||||||
wlr_log(WLR_ERROR, "action '%s' cannot be a child action", content);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
state->current_child_action = action_create(content);
|
|
||||||
if (state->current_child_action) {
|
|
||||||
wl_list_append(siblings, &state->current_child_action->link);
|
|
||||||
}
|
|
||||||
} else if (!state->current_child_action) {
|
|
||||||
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
||||||
"nodename: '%s' content: '%s'", nodename, content);
|
"nodename: '%s' content: '%s'", nodename, content);
|
||||||
} else {
|
} else {
|
||||||
action_arg_from_xml_node(state->current_child_action, nodename, content);
|
action_arg_from_xml_node(state->current_action, nodename, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fill_child_action(char *nodename, char *content, struct parser_state *state,
|
||||||
|
const char *branch_name)
|
||||||
|
{
|
||||||
|
string_truncate_at_pattern(nodename, ".windowrule.windowrules");
|
||||||
|
string_truncate_at_pattern(nodename, ".keybind.keyboard");
|
||||||
|
string_truncate_at_pattern(nodename, ".mousebind.context.mouse");
|
||||||
|
string_truncate_at_pattern(nodename, ".then.action");
|
||||||
|
string_truncate_at_pattern(nodename, ".else.action");
|
||||||
|
string_truncate_at_pattern(nodename, ".none.action");
|
||||||
|
|
||||||
|
if (!state->current_action) {
|
||||||
|
wlr_log(WLR_ERROR, "No parent action for branch: %s=%s", nodename, content);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wl_list *siblings = action_get_actionlist(state->current_action, branch_name);
|
||||||
|
if (!siblings) {
|
||||||
|
action_arg_add_actionlist(state->current_action, branch_name);
|
||||||
|
siblings = action_get_actionlist(state->current_action, branch_name);
|
||||||
|
}
|
||||||
|
state->current_action_siblings = siblings;
|
||||||
|
|
||||||
|
if (!content) {
|
||||||
|
state->current_inline_action = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(nodename, "name.action")) {
|
||||||
|
state->current_inline_action = action_create(content);
|
||||||
|
if (state->current_inline_action) {
|
||||||
|
wl_list_append(state->current_action_siblings,
|
||||||
|
&state->current_inline_action->link);
|
||||||
|
}
|
||||||
|
} else if (!state->current_inline_action) {
|
||||||
|
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
||||||
|
"nodename: '%s' content: '%s'", nodename, content);
|
||||||
|
} else {
|
||||||
|
action_arg_from_xml_node(state->current_inline_action, nodename, content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -514,10 +544,10 @@ fill_keybind(char *nodename, char *content, struct parser_state *state)
|
||||||
if (!content) {
|
if (!content) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string_truncate_at_pattern(nodename, ".keybind.keyboard");
|
string_truncate_at_pattern(nodename, ".keybind.keyboard");
|
||||||
if (!strcmp(nodename, "key")) {
|
if (!strcmp(nodename, "key")) {
|
||||||
state->current_keybind = keybind_create(content);
|
state->current_keybind = keybind_create(content);
|
||||||
state->current_keybind_action = NULL;
|
|
||||||
/*
|
/*
|
||||||
* If an invalid keybind has been provided,
|
* If an invalid keybind has been provided,
|
||||||
* keybind_create() complains.
|
* keybind_create() complains.
|
||||||
|
|
@ -526,6 +556,9 @@ fill_keybind(char *nodename, char *content, struct parser_state *state)
|
||||||
wlr_log(WLR_ERROR, "Invalid keybind: %s", content);
|
wlr_log(WLR_ERROR, "Invalid keybind: %s", content);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
state->current_action = NULL;
|
||||||
|
state->current_action_siblings = &state->current_keybind->actions;
|
||||||
|
state->current_inline_action = NULL;
|
||||||
} else if (!state->current_keybind) {
|
} else if (!state->current_keybind) {
|
||||||
wlr_log(WLR_ERROR, "expect <keybind key=\"\"> element first. "
|
wlr_log(WLR_ERROR, "expect <keybind key=\"\"> element first. "
|
||||||
"nodename: '%s' content: '%s'", nodename, content);
|
"nodename: '%s' content: '%s'", nodename, content);
|
||||||
|
|
@ -536,12 +569,12 @@ fill_keybind(char *nodename, char *content, struct parser_state *state)
|
||||||
} else if (!strcasecmp(nodename, "allowWhenLocked")) {
|
} else if (!strcasecmp(nodename, "allowWhenLocked")) {
|
||||||
set_bool(content, &state->current_keybind->allow_when_locked);
|
set_bool(content, &state->current_keybind->allow_when_locked);
|
||||||
} else if (!strcmp(nodename, "name.action")) {
|
} else if (!strcmp(nodename, "name.action")) {
|
||||||
state->current_keybind_action = action_create(content);
|
state->current_inline_action = action_create(content);
|
||||||
if (state->current_keybind_action) {
|
if (state->current_inline_action) {
|
||||||
wl_list_append(&state->current_keybind->actions,
|
wl_list_append(&state->current_keybind->actions,
|
||||||
&state->current_keybind_action->link);
|
&state->current_inline_action->link);
|
||||||
}
|
}
|
||||||
} else if (!state->current_keybind_action) {
|
} else if (!state->current_inline_action) {
|
||||||
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
||||||
"nodename: '%s' content: '%s'", nodename, content);
|
"nodename: '%s' content: '%s'", nodename, content);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -550,7 +583,7 @@ fill_keybind(char *nodename, char *content, struct parser_state *state)
|
||||||
* <region>, <direction> and so on. This is common to key- and
|
* <region>, <direction> and so on. This is common to key- and
|
||||||
* mousebinds.
|
* mousebinds.
|
||||||
*/
|
*/
|
||||||
action_arg_from_xml_node(state->current_keybind_action, nodename, content);
|
action_arg_from_xml_node(state->current_inline_action, nodename, content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -574,7 +607,13 @@ fill_mousebind(char *nodename, char *content, struct parser_state *state)
|
||||||
wlr_log(WLR_INFO, "create mousebind for %s",
|
wlr_log(WLR_INFO, "create mousebind for %s",
|
||||||
state->current_mouse_context);
|
state->current_mouse_context);
|
||||||
state->current_mousebind = mousebind_create(state->current_mouse_context);
|
state->current_mousebind = mousebind_create(state->current_mouse_context);
|
||||||
state->current_mousebind_action = NULL;
|
if (!state->current_mousebind) {
|
||||||
|
wlr_log(WLR_ERROR, "Invalid mousebind: %s", content);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state->current_action = NULL;
|
||||||
|
state->current_action_siblings = &state->current_mousebind->actions;
|
||||||
|
state->current_inline_action = NULL;
|
||||||
return;
|
return;
|
||||||
} else if (!content) {
|
} else if (!content) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -596,16 +635,16 @@ fill_mousebind(char *nodename, char *content, struct parser_state *state)
|
||||||
state->current_mousebind->mouse_event =
|
state->current_mousebind->mouse_event =
|
||||||
mousebind_event_from_str(content);
|
mousebind_event_from_str(content);
|
||||||
} else if (!strcmp(nodename, "name.action")) {
|
} else if (!strcmp(nodename, "name.action")) {
|
||||||
state->current_mousebind_action = action_create(content);
|
state->current_inline_action = action_create(content);
|
||||||
if (state->current_mousebind_action) {
|
if (state->current_inline_action) {
|
||||||
wl_list_append(&state->current_mousebind->actions,
|
wl_list_append(&state->current_mousebind->actions,
|
||||||
&state->current_mousebind_action->link);
|
&state->current_inline_action->link);
|
||||||
}
|
}
|
||||||
} else if (!state->current_mousebind_action) {
|
} else if (!state->current_inline_action) {
|
||||||
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
|
||||||
"nodename: '%s' content: '%s'", nodename, content);
|
"nodename: '%s' content: '%s'", nodename, content);
|
||||||
} else {
|
} else {
|
||||||
action_arg_from_xml_node(state->current_mousebind_action, nodename, content);
|
action_arg_from_xml_node(state->current_inline_action, nodename, content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -954,40 +993,29 @@ entry(xmlNode *node, char *nodename, char *content, struct parser_state *state)
|
||||||
if (state->in_usable_area_override) {
|
if (state->in_usable_area_override) {
|
||||||
fill_usable_area_override(nodename, content, state);
|
fill_usable_area_override(nodename, content, state);
|
||||||
}
|
}
|
||||||
if (state->in_keybind) {
|
|
||||||
|
if ((state->in_keybind || state->in_mousebind ||
|
||||||
|
state->in_window_rule) && state->in_action) {
|
||||||
if (state->in_action_query) {
|
if (state->in_action_query) {
|
||||||
fill_action_query(nodename, content,
|
fill_action_query(nodename, content, state);
|
||||||
state->current_keybind_action, state);
|
|
||||||
} else if (state->in_action_then_branch) {
|
} else if (state->in_action_then_branch) {
|
||||||
fill_child_action(nodename, content,
|
fill_child_action(nodename, content, state, "then");
|
||||||
state->current_keybind_action, "then", state);
|
|
||||||
} else if (state->in_action_else_branch) {
|
} else if (state->in_action_else_branch) {
|
||||||
fill_child_action(nodename, content,
|
fill_child_action(nodename, content, state, "else");
|
||||||
state->current_keybind_action, "else", state);
|
|
||||||
} else if (state->in_action_none_branch) {
|
} else if (state->in_action_none_branch) {
|
||||||
fill_child_action(nodename, content,
|
fill_child_action(nodename, content, state, "none");
|
||||||
state->current_keybind_action, "none", state);
|
|
||||||
} else {
|
} else {
|
||||||
|
fill_action(nodename, content, state);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (state->in_keybind) {
|
||||||
fill_keybind(nodename, content, state);
|
fill_keybind(nodename, content, state);
|
||||||
}
|
return;
|
||||||
}
|
} else if (state->in_mousebind) {
|
||||||
if (state->in_mousebind) {
|
|
||||||
if (state->in_action_query) {
|
|
||||||
fill_action_query(nodename, content,
|
|
||||||
state->current_mousebind_action, state);
|
|
||||||
} else if (state->in_action_then_branch) {
|
|
||||||
fill_child_action(nodename, content,
|
|
||||||
state->current_mousebind_action, "then", state);
|
|
||||||
} else if (state->in_action_else_branch) {
|
|
||||||
fill_child_action(nodename, content,
|
|
||||||
state->current_mousebind_action, "else", state);
|
|
||||||
} else if (state->in_action_none_branch) {
|
|
||||||
fill_child_action(nodename, content,
|
|
||||||
state->current_mousebind_action, "none", state);
|
|
||||||
} else {
|
|
||||||
fill_mousebind(nodename, content, state);
|
fill_mousebind(nodename, content, state);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (state->in_touch) {
|
if (state->in_touch) {
|
||||||
fill_touch(nodename, content, state);
|
fill_touch(nodename, content, state);
|
||||||
return;
|
return;
|
||||||
|
|
@ -1004,7 +1032,7 @@ entry(xmlNode *node, char *nodename, char *content, struct parser_state *state)
|
||||||
fill_window_switcher_field(nodename, content, state);
|
fill_window_switcher_field(nodename, content, state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (state->in_window_rules) {
|
if (state->in_window_rule) {
|
||||||
fill_window_rule(nodename, content, state);
|
fill_window_rule(nodename, content, state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1352,10 +1380,22 @@ xml_tree_walk(xmlNode *node, struct parser_state *state)
|
||||||
state->in_window_switcher_field = false;
|
state->in_window_switcher_field = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcasecmp((char *)n->name, "windowRules")) {
|
if (!strcasecmp((char *)n->name, "windowRule")) {
|
||||||
state->in_window_rules = true;
|
state->in_window_rule = true;
|
||||||
traverse(n, state);
|
traverse(n, state);
|
||||||
state->in_window_rules = false;
|
state->in_window_rule = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcasecmp((char *)n->name, "action")) {
|
||||||
|
struct parser_state new_state = *state;
|
||||||
|
new_state.current_action = NULL;
|
||||||
|
new_state.current_view_query = NULL;
|
||||||
|
new_state.in_action = true;
|
||||||
|
new_state.in_action_query = false;
|
||||||
|
new_state.in_action_then_branch = false;
|
||||||
|
new_state.in_action_else_branch = false;
|
||||||
|
new_state.in_action_none_branch = false;
|
||||||
|
traverse(n, &new_state);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcasecmp((char *)n->name, "query")) {
|
if (!strcasecmp((char *)n->name, "query")) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue