mirror of
https://github.com/labwc/labwc.git
synced 2025-11-05 13:29:58 -05:00
First implemenation of <mouse> in rc.xml
Can successfully parse the following XML and and implement the action:
<mouse>
<context name="TitleBar">
<mousebind button="Left" action="DoubleClick">
<action name="ToggleMaximize"/>
</mousebind>
</context>
</mouse>
The XML parsing code for this looks A LOT different than the already
existing XML parsing code. It may have to be reworked
This commit is contained in:
parent
75564d6b8d
commit
dfdb4e4b0e
6 changed files with 335 additions and 1 deletions
|
|
@ -2,4 +2,5 @@ labwc_sources += files(
|
|||
'rcxml.c',
|
||||
'keybind.c',
|
||||
'session.c',
|
||||
'mousebind.c',
|
||||
)
|
||||
|
|
|
|||
90
src/config/mousebind.c
Normal file
90
src/config/mousebind.c
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "config/mousebind.h"
|
||||
#include "config/rcxml.h"
|
||||
#include <wlr/util/log.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static enum mouse_context
|
||||
context_from_str(const char* str)
|
||||
{
|
||||
if(str == NULL) {
|
||||
return MOUSE_CONTEXT_NONE;
|
||||
}
|
||||
else if(strcasecmp(str, "Titlebar") == 0) {
|
||||
return MOUSE_CONTEXT_TITLEBAR;
|
||||
} else {
|
||||
return MOUSE_CONTEXT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static enum mouse_button
|
||||
mouse_button_from_str(const char* str)
|
||||
{
|
||||
if(str == NULL) {
|
||||
return MOUSE_BUTTON_NONE;
|
||||
}
|
||||
else if(strcasecmp(str, "Left") == 0) {
|
||||
return MOUSE_BUTTON_LEFT;
|
||||
} else if(strcasecmp(str, "Right") == 0) {
|
||||
return MOUSE_BUTTON_RIGHT;
|
||||
} else if(strcasecmp(str, "Middle") == 0) {
|
||||
return MOUSE_BUTTON_MIDDLE;
|
||||
} else {
|
||||
return MOUSE_BUTTON_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static enum action_mouse_did
|
||||
action_mouse_did_from_str(const char* str)
|
||||
{
|
||||
if(str == NULL) {
|
||||
return MOUSE_ACTION_NONE;
|
||||
}
|
||||
else if(strcasecmp(str, "doubleclick") == 0) {
|
||||
return MOUSE_ACTION_DOUBLECLICK;
|
||||
} else {
|
||||
return MOUSE_ACTION_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
struct mousebind*
|
||||
mousebind_create(const char* context_str, const char* mouse_button_str,
|
||||
const char* action_mouse_did_str, const char* action,
|
||||
const char* command)
|
||||
{
|
||||
struct mousebind* m = calloc(1, sizeof(struct mousebind));
|
||||
|
||||
enum mouse_context context = context_from_str(context_str);
|
||||
enum mouse_button button = mouse_button_from_str(mouse_button_str);
|
||||
enum action_mouse_did action_mouse_did = action_mouse_did_from_str(action_mouse_did_str);
|
||||
|
||||
if(context == MOUSE_CONTEXT_NONE) {
|
||||
wlr_log(WLR_ERROR, "unknown mouse context (%s)", context_str);
|
||||
goto CREATE_ERROR;
|
||||
}
|
||||
if(button == MOUSE_BUTTON_NONE) {
|
||||
wlr_log(WLR_ERROR, "unknown button (%s)", mouse_button_str);
|
||||
goto CREATE_ERROR;
|
||||
}
|
||||
if(action_mouse_did == MOUSE_ACTION_NONE) {
|
||||
wlr_log(WLR_ERROR, "unknown mouse action (%s)", action_mouse_did_str);
|
||||
goto CREATE_ERROR;
|
||||
}
|
||||
if(action == NULL) {
|
||||
wlr_log(WLR_ERROR, "action is NULL\n");
|
||||
goto CREATE_ERROR;
|
||||
}
|
||||
|
||||
m->context = context;
|
||||
m->button = button;
|
||||
m->mouse_action = action_mouse_did;
|
||||
m->action = strdup(action); /* TODO: replace with strndup? */
|
||||
m->command = strdup(command);
|
||||
|
||||
return m;
|
||||
|
||||
CREATE_ERROR:
|
||||
free(m);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -16,11 +16,13 @@
|
|||
#include "common/string-helpers.h"
|
||||
#include "common/zfree.h"
|
||||
#include "config/keybind.h"
|
||||
#include "config/mousebind.h"
|
||||
#include "config/rcxml.h"
|
||||
|
||||
static bool in_keybind = false;
|
||||
static bool is_attribute = false;
|
||||
static struct keybind *current_keybind;
|
||||
static const char* current_mouse_context = "";
|
||||
|
||||
enum font_place {
|
||||
FONT_PLACE_UNKNOWN = 0,
|
||||
|
|
@ -223,6 +225,184 @@ 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_mouse(xmlNode* node)
|
||||
{
|
||||
/*
|
||||
* Right now, all we have implemented is:
|
||||
*
|
||||
* this node
|
||||
* |
|
||||
* |
|
||||
* v
|
||||
* <mouse>
|
||||
* <context name="TitleBar"> -|
|
||||
* <mousebind....> |
|
||||
* ... | -- This node's only supported child is context
|
||||
* </mousebind> |
|
||||
* </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(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)
|
||||
{
|
||||
|
|
@ -235,6 +415,10 @@ xml_tree_walk(xmlNode *node)
|
|||
traverse(n);
|
||||
in_keybind = false;
|
||||
continue;
|
||||
}
|
||||
if(!strcasecmp((char *)n->name, "mouse")) {
|
||||
traverse_mouse(n);
|
||||
continue;
|
||||
}
|
||||
traverse(n);
|
||||
}
|
||||
|
|
@ -265,6 +449,7 @@ rcxml_init()
|
|||
has_run = true;
|
||||
LIBXML_TEST_VERSION
|
||||
wl_list_init(&rc.keybinds);
|
||||
wl_list_init(&rc.mousebinds);
|
||||
rc.xdg_shell_server_side_deco = true;
|
||||
rc.corner_radius = 8;
|
||||
rc.font_size_activewindow = 10;
|
||||
|
|
@ -400,4 +585,12 @@ rcxml_finish(void)
|
|||
zfree(k->keysyms);
|
||||
zfree(k);
|
||||
}
|
||||
|
||||
struct mousebind *m, *m_tmp;
|
||||
wl_list_for_each_safe(m, m_tmp, &rc.mousebinds, link) {
|
||||
wl_list_remove(&m->link);
|
||||
zfree(m->command);
|
||||
zfree(m->action);
|
||||
zfree(m);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue