mirror of
https://github.com/labwc/labwc.git
synced 2025-11-03 09:01:51 -05:00
refactor <mouse> xml parsing to match rest of xml parsing
This commit is contained in:
parent
92891b4dfa
commit
10a685a0e4
2 changed files with 124 additions and 217 deletions
|
|
@ -81,7 +81,9 @@ mousebind_create(const char* context_str, const char* mouse_button_str,
|
|||
m->button = button;
|
||||
m->mouse_action = action_mouse_did;
|
||||
m->action = strdup(action); /* TODO: replace with strndup? */
|
||||
m->command = strdup(command);
|
||||
if(command && !strcasecmp(action, "Execute")) {
|
||||
m->command = strdup(command);
|
||||
}
|
||||
|
||||
return m;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,10 +21,12 @@
|
|||
#include "config/rcxml.h"
|
||||
|
||||
static bool in_keybind = false;
|
||||
static bool in_mousebind = false;
|
||||
static bool is_attribute = false;
|
||||
static struct keybind *current_keybind;
|
||||
static const char* current_mouse_context = "";
|
||||
|
||||
|
||||
enum font_place {
|
||||
FONT_PLACE_UNKNOWN = 0,
|
||||
FONT_PLACE_ACTIVEWINDOW,
|
||||
|
|
@ -32,6 +34,27 @@ enum font_place {
|
|||
/* TODO: Add all places based on Openbox's rc.xml */
|
||||
};
|
||||
|
||||
/*
|
||||
* unchecked mousebind params. we fill these out one at a time, then pass them
|
||||
* all to mousebind_create() once we are ready
|
||||
*/
|
||||
static const char* current_mouse_button = "";
|
||||
static const char* current_action_mouse_did= "";
|
||||
struct mouse_action {
|
||||
const char* action;
|
||||
const char* command;
|
||||
};
|
||||
/*
|
||||
* A given mousebind can have multiple actions associated with it.
|
||||
* This array is a list of the actions for the currently-being-parsed mousebind
|
||||
*
|
||||
* TODO: make it a linked list?
|
||||
*/
|
||||
#define MAX_MOUSE_ACTIONS 32
|
||||
static struct mouse_action mouse_actions[MAX_MOUSE_ACTIONS] = {{0}};
|
||||
static int num_mouse_actions = 0;
|
||||
|
||||
|
||||
static void load_default_key_bindings(void);
|
||||
|
||||
static void
|
||||
|
|
@ -63,6 +86,75 @@ fill_keybind(char *nodename, char *content)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_new_mousebinds(void)
|
||||
{
|
||||
for(int i = 0; i < num_mouse_actions; i++) {
|
||||
struct mousebind* m = mousebind_create(current_mouse_context,
|
||||
current_mouse_button,
|
||||
current_action_mouse_did,
|
||||
mouse_actions[i].action,
|
||||
mouse_actions[i].command);
|
||||
if(m != NULL) {
|
||||
wl_list_insert(&rc.mousebinds, &m->link);
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "failed to create mousebind\n"
|
||||
" context: (%s)\n"
|
||||
" button: (%s)\n"
|
||||
" mouse action (%s)\n"
|
||||
" action (%s)\n"
|
||||
" command: (%s)\n",
|
||||
current_mouse_context,
|
||||
current_mouse_button,
|
||||
current_action_mouse_did,
|
||||
mouse_actions[i].action,
|
||||
mouse_actions[i].command);
|
||||
}
|
||||
}
|
||||
|
||||
num_mouse_actions = 0;
|
||||
memset(mouse_actions, 0, sizeof(struct mouse_action) * MAX_MOUSE_ACTIONS);
|
||||
}
|
||||
|
||||
static void
|
||||
fill_mousebind(char* nodename, char* content)
|
||||
{
|
||||
/*
|
||||
* Example of what we're parsing:
|
||||
*
|
||||
* <mousebind button="Left" action="DoubleClick">
|
||||
* <action name="ToggleMaximize"/>
|
||||
* </mousebind>
|
||||
*/
|
||||
if(!content) {
|
||||
return;
|
||||
}
|
||||
|
||||
string_truncate_at_pattern(nodename, ".mousebind.context.mouse");
|
||||
|
||||
if(is_attribute && !strcmp(nodename, "button")) {
|
||||
current_mouse_button = content;
|
||||
} else if(!strcmp(nodename, "action")) {
|
||||
/*
|
||||
* checking for is_attribute fails even though we are looking for the
|
||||
* attribute of mousebind named action. initial thoughts were to check
|
||||
* for is_attribute to distinguish the attribute of mousebind named
|
||||
* action from the child of mousebind named action. since the child of
|
||||
* mousebind named action doesn't have any content, I don't think we
|
||||
* need to make this distinction since we already filtered out nodes that
|
||||
* don't have content
|
||||
*/
|
||||
current_action_mouse_did = content;
|
||||
} else if(is_attribute && !strcmp(nodename, "name.action")) {
|
||||
if(num_mouse_actions < MAX_MOUSE_ACTIONS) {
|
||||
num_mouse_actions++;
|
||||
mouse_actions[num_mouse_actions-1].action = content;
|
||||
}
|
||||
} else if(!strcmp(nodename, "command.action")) {
|
||||
mouse_actions[num_mouse_actions-1].command = content;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
get_bool(const char *s)
|
||||
{
|
||||
|
|
@ -169,6 +261,10 @@ entry(xmlNode *node, char *nodename, char *content)
|
|||
fill_keybind(nodename, content);
|
||||
}
|
||||
|
||||
if (in_mousebind) {
|
||||
fill_mousebind(nodename, content);
|
||||
}
|
||||
|
||||
if (is_attribute && !strcmp(nodename, "place.font.theme")) {
|
||||
font_place = enum_font_place(content);
|
||||
}
|
||||
|
|
@ -194,6 +290,26 @@ entry(xmlNode *node, char *nodename, char *content)
|
|||
} else if (!strcasecmp(nodename, "RaiseOnFocus.focus")) {
|
||||
rc.focus_follow_mouse = true;
|
||||
rc.raise_on_focus = get_bool(content);
|
||||
} else if(!strcasecmp(nodename, "doubleClickTime.mouse")) {
|
||||
long doubleclick_time_parsed = strtol(content, NULL, 10);
|
||||
|
||||
/*
|
||||
* There are 2 possible sources for a bad doubleclicktime value:
|
||||
* - user gave a value of 0 (which doesn't make sense)
|
||||
* - user gave a negative value (which doesn't make sense)
|
||||
* - user gave a value which strtol couldn't parse
|
||||
*
|
||||
* since strtol() returns 0 on error, all we have to do is check
|
||||
* for to see if strtol() returned 0 or less to handle the error
|
||||
* cases. in case of error, we just choose not to override the
|
||||
* default value and everything should be fine
|
||||
*/
|
||||
bool valid_doubleclick_time = doubleclick_time_parsed > 0;
|
||||
if(valid_doubleclick_time) {
|
||||
rc.doubleclick_time = doubleclick_time_parsed;
|
||||
}
|
||||
} else if(is_attribute && !strcasecmp(nodename, "name.context.mouse")) {
|
||||
current_mouse_context = content;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -226,220 +342,6 @@ traverse(xmlNode *n)
|
|||
xml_tree_walk(n->children);
|
||||
}
|
||||
|
||||
static bool
|
||||
is_ignorable_node(const xmlNode* n)
|
||||
{
|
||||
if(n->type == XML_COMMENT_NODE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(n->type == XML_TEXT_NODE) {
|
||||
for(const char* s = (const char*)n->content; s && (*s != '\0'); s++) {
|
||||
if(!isspace(*s)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
traverse_mousebind_action(xmlNode* node, const char* button_str, const char* mouse_action)
|
||||
{
|
||||
/*
|
||||
* Right now, all we have implemented is:
|
||||
*
|
||||
* <action name="ToggleMaximize"/> ] -- only supported attribute is "name"
|
||||
*
|
||||
* <action name="Execute>
|
||||
* <command>command text here</command> ] -- if name is execute, we support a child node of name command
|
||||
* </action>
|
||||
*/
|
||||
const char* action_to_do = "";
|
||||
const char* command = "";
|
||||
for(xmlAttr* attr = node->properties; attr; attr = attr->next) {
|
||||
if(strcasecmp((const char*)attr->name, "name") == 0) {
|
||||
action_to_do = (const char*)attr->children->content;
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "hit unexpected attr (%s) in mousebind action\n", (const char*) attr->name);
|
||||
}
|
||||
}
|
||||
|
||||
if(strcasecmp((const char*)action_to_do, "Execute") == 0) {
|
||||
for(xmlNode* n = node->children; n && n->name; n = n->next) {
|
||||
if(strcasecmp((const char*)n->name, "command") == 0) {
|
||||
for(xmlNode* t = n->children; t; t = t->next) {
|
||||
if( (t->type == XML_TEXT_NODE) ) {
|
||||
command = (const char*)t->content;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct mousebind* mousebind = mousebind_create(current_mouse_context,
|
||||
button_str,
|
||||
mouse_action,
|
||||
action_to_do,
|
||||
command);
|
||||
if(mousebind != NULL) {
|
||||
wl_list_insert(&rc.mousebinds, &mousebind->link);
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "failed to create mousebind:\n"
|
||||
" context: (%s)\n"
|
||||
" button: (%s)\n"
|
||||
" mouse action: (%s)\n"
|
||||
" action: (%s)\n"
|
||||
" command: (%s)\n",
|
||||
current_mouse_context,
|
||||
button_str,
|
||||
mouse_action,
|
||||
action_to_do,
|
||||
command);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
traverse_mousebind(xmlNode* node)
|
||||
{
|
||||
/*
|
||||
* Right now, all we have implemented is:
|
||||
*
|
||||
* this node
|
||||
* | this node's only supported attributes are "button" and "action"
|
||||
* | | |
|
||||
* v v v
|
||||
* <mousebind button="Left" action="DoubleClick>
|
||||
* <action name="ToggleMaximize"/> -|
|
||||
* <action name="Execute> | -- This node's only supported children are actions
|
||||
* <command>command text here</command> |
|
||||
* </action> -|
|
||||
* </context>
|
||||
*/
|
||||
const char* button_str = "";
|
||||
const char* action_mouse_did_str = "";
|
||||
for(xmlAttr* attr = node->properties; attr; attr = attr->next) {
|
||||
if(strcasecmp((const char*)attr->name, "button") == 0) {
|
||||
button_str = (const char*)attr->children->content;
|
||||
} else if(strcasecmp((const char*)attr->name, "action") == 0) {
|
||||
action_mouse_did_str = (const char*)attr->children->content;
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "hit unexpected attr (%s) in mousebind\n", (const char*)attr->name);
|
||||
}
|
||||
}
|
||||
|
||||
for(xmlNode* n = node->children; n && n->name; n = n->next) {
|
||||
if(strcasecmp((const char*)n->name, "action") == 0) {
|
||||
traverse_mousebind_action(n, button_str, action_mouse_did_str);
|
||||
} else if(is_ignorable_node(n)) {
|
||||
continue;
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "hit unexpected node (%s) in mousebind\n", (const char*) n->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
traverse_context(xmlNode* node)
|
||||
{
|
||||
/*
|
||||
* Right now, all we have implemented is:
|
||||
*
|
||||
* this node
|
||||
* | this node's only supported attribute is "name"
|
||||
* | |
|
||||
* v v
|
||||
* <context name="TitleBar">
|
||||
* <mousebind....> -|
|
||||
* ... | -- This node's only supported child is mousebind
|
||||
* </mousebind> -|
|
||||
* </context>
|
||||
*/
|
||||
for(xmlAttr* attr = node->properties; attr; attr = attr->next) {
|
||||
if(strcasecmp((const char*)attr->name, "name") == 0) {
|
||||
current_mouse_context = (const char*)attr->children->content;
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "hit unexpected attr (%s) in context\n", (const char*)attr->name);
|
||||
}
|
||||
}
|
||||
|
||||
for(xmlNode* n = node->children; n && n->name; n = n->next) {
|
||||
if(strcasecmp((const char*)n->name, "mousebind") == 0) {
|
||||
traverse_mousebind(n);
|
||||
} else if(is_ignorable_node(n)) {
|
||||
continue;
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "hit unexpected node (%s) in context\n", (const char*)n->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
traverse_doubleclick_time(xmlNode* node)
|
||||
{
|
||||
/*
|
||||
* this node
|
||||
* |
|
||||
* |
|
||||
* v
|
||||
* <doubleClickTime>200</doubleClickTime>
|
||||
*/
|
||||
for(xmlNode* n = node->children; n && n->name; n = n->next) {
|
||||
if(n->type == XML_TEXT_NODE) {
|
||||
long doubleclick_time_parsed = strtol((const char*)n->content, NULL, 10);
|
||||
|
||||
/*
|
||||
* There are 2 possible sources for a bad doubleclicktime value:
|
||||
* - user gave a value of 0 (which doesn't make sense)
|
||||
* - user gave a negative value (which doesn't make sense)
|
||||
* - user gave a value which strtol couldn't parse
|
||||
*
|
||||
* since strtol() returns 0 on error, all we have to do is check
|
||||
* for to see if strtol() returned 0 or less to handle the error
|
||||
* cases. in case of error, we just choose not to override the
|
||||
* default value and everything should be fine
|
||||
*/
|
||||
bool valid_doubleclick_time = doubleclick_time_parsed > 0;
|
||||
if(valid_doubleclick_time) {
|
||||
rc.doubleclick_time = doubleclick_time_parsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
traverse_mouse(xmlNode* node)
|
||||
{
|
||||
/*
|
||||
* Right now, all we have implemented is:
|
||||
*
|
||||
* this node
|
||||
* |
|
||||
* |
|
||||
* v
|
||||
* <mouse>
|
||||
* <doubleClickTime>200</doubleClickTime> ]
|
||||
* <context name="TitleBar"> -|
|
||||
* <mousebind....> |
|
||||
* ... | -- This node's only supported children
|
||||
* </mousebind> | are doubleClickTime and context
|
||||
* </context> -|
|
||||
* </mouse>
|
||||
*/
|
||||
for(xmlNode* n = node->children; n && n->name; n = n->next) {
|
||||
if(strcasecmp((const char*)n->name, "context") == 0) {
|
||||
traverse_context(n);
|
||||
} else if(strcasecmp((const char*)n->name, "doubleClickTime") == 0) {
|
||||
traverse_doubleclick_time(n);
|
||||
} else if(is_ignorable_node(n)) {
|
||||
continue;
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "hit unexpected node (%s) in mouse\n", (const char*)n->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xml_tree_walk(xmlNode *node)
|
||||
{
|
||||
|
|
@ -453,8 +355,11 @@ xml_tree_walk(xmlNode *node)
|
|||
in_keybind = false;
|
||||
continue;
|
||||
}
|
||||
if(!strcasecmp((char *)n->name, "mouse")) {
|
||||
traverse_mouse(n);
|
||||
if(!strcasecmp((char *)n->name, "mousebind")) {
|
||||
in_mousebind = true;
|
||||
traverse(n);
|
||||
in_mousebind = false;
|
||||
add_new_mousebinds();
|
||||
continue;
|
||||
}
|
||||
traverse(n);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue