diff --git a/configure.ac b/configure.ac index 811de5de..21fc5219 100644 --- a/configure.ac +++ b/configure.ac @@ -53,6 +53,10 @@ PKG_CHECK_MODULES(XFT, [xft]) AC_SUBST(XFT_CFLAGS) AC_SUBST(XFT_LIBS) +PKG_CHECK_MODULES(XML, [libxml-2.0]) +AC_SUBST(XML_CFLAGS) +AC_SUBST(XML_LIBS) + PKG_CHECK_MODULES(LIBSN, [libstartup-notification-1.0], [ AC_DEFINE(USE_LIBSN) diff --git a/data/rc3 b/data/rc3 index 26affba4..a159e65e 100644 --- a/data/rc3 +++ b/data/rc3 @@ -1,191 +1,296 @@ -[resistance] + -# amount of resistance to provide at edges -#strength=10 + -# resistance against other windows -#windows=true + -[placement] + + 10 + yes + -# place windows where they were last -#remember = yes + + yes + -[focus] + + yes + no + yes + yes + yes + -# focus new windows when they appear -#focusNew = yes + + operation + -# does focus follow the mouse pointer when it enters a window -#followMouse = no + + 4 + + one + two + three + four + + -# when no windows are left with focus, focus the last window on the desktop -# to previously have focus -#focusLast = yes + + yes + yes + -# a special case of focusLast that applies when switching between desktops; if -# set, the previously focused window on the desktop is focused when switching -#focusLastOnDesktop = yes + + topleft + top + vertical + 0 + 0 + no + 300 + -# shows a helpful dialog while cycling focus -#cyclingDialog = yes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -[desktops] + + 3 + 200 -# The number of virtual desktops to use -#number = 4 + + + + + + + + + + + + + + + + + + client-menu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + client-menu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + client-menu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + root + + + -# A list of names for the desktops -names = ("one" "two" "three" "four") - -[moveresize] - -# When true windows are moved opaquely, when false just an outline is shown -# while they are moved -#opaque_move = yes - -# When true windows are resized opaquely, when false just an outline is shown -# while they are resized -#opaque_resize = yes - -[theme] - -# the theme to display -#theme = "operation" - -[dock] -# The position on the screen to place the dock. Options are: -# TopLeft, Top, TopRight, Right, BottomRight, Bottom, BottomLeft, Left -# - the appropriate corner/edge of the screen -# Floating - uses the floatingX and floatingY options to position itself -#position = "TopLeft" - -# When position is "Floating", this specifies the x-coordinate to place the -# the dock at. -#floatingX = 0 - -# When position is "Floating", this specifies the y-coordinate to place the -# the dock at. -#floatingY = 0 - -# The stacking layer that the dock will be in. Options are: -# Top - above all normal windows, same layer as panels -# Normal - can be above and below normal windows -# Bottom - below all normal windows -#stacking = "Top" - -# When true, the dock will grow horizontally when dock apps are added to it, -# otherwise it will grow vertically. -#horizontal = no - -# When true, the dock will hide itself while the pointer is not over it, and -# will show itself when the pointer is. -#autoHide = no - -# The number of milliseconds to wait before hiding the dock when the pointer -# leaves it, if the autoHide option is on. -#hideTimeout = 3000 - -[keyboard] - -#kbind (Key [Key...]) Action [Parameter] - -kbind (F12) execute "xterm" - -kbind (A-Left) PreviousDesktopWrap -kbind (A-Right) NextDesktopWrap - -kbind (A-1) Desktop 1 -kbind (A-2) Desktop 2 -kbind (A-3) Desktop 3 -kbind (A-4) Desktop 4 - -kbind (C-A-1) SendToDesktop 1 -kbind (C-A-2) SendToDesktop 2 -kbind (C-A-3) SendToDesktop 3 -kbind (C-A-4) SendToDesktop 4 - -kbind (C-S-x x) ToggleMaximizeFull -kbind (C-S-x Up) ToggleMaximizeVert -kbind (C-S-x Right) ToggleMaximizeHorz - -kbind (C-A-Left) MoveRelativeHorz -3 -kbind (C-A-Right) MoveRelativeHorz 3 -kbind (C-A-Up) MoveRelativeVert -3 -kbind (C-A-Down) MoveRelativeVert 3 - -kbind (A-F4) Close - -kbind (W-D) ToggleDecorations - -kbind (A-Tab) NextWindow -kbind (S-A-Tab) PreviousWindow - -[mouse] - -# the distance a drag must go before it is recognized -#dragThreshold = 3 - -# the amount of time in milliseconds in which two clicks must occur to cause a -# doubleclick event -#doubleClickTime = 200 - -#mbind Context Event Button Action [Parameter] - -mbind Titlebar Drag Left Move -mbind Handle Drag Left Move -mbind Frame Drag A-Left Move - -mbind BLCorner Drag Left Resize -mbind BRCorner Drag Left Resize -mbind Frame Drag A-Middle Resize - -mbind Titlebar Click Left Raise -mbind Titlebar Press Middle Lower -mbind Handle Click Left Raise -mbind Handle Press Middle Lower -mbind Frame Click A-Left Raise -mbind Frame Click A-Middle Lower - -mbind Titlebar Press Left Focus -mbind Handle Press Left Focus -mbind BLCorner Press Left Focus -mbind BRCorner Press Left Focus -mbind Maximize Press Left Focus -mbind Maximize Press Middle Focus -mbind Maximize Press Right Focus -mbind Iconify Press Left Focus -mbind Icon Press Left Focus -mbind Close Press Left Focus -mbind AllDesktops Press Left Focus -mbind Shade Press Left Focus -mbind Client Press Left FocusRaise -mbind Client Press Middle Focus -mbind Client Press Right Focus -mbind Frame Press A-Left Focus - -mbind Titlebar DoubleClick Left ToggleShade -mbind Titlebar Click Up Shade -mbind Titlebar Click Down UnShade - -mbind Maximize Click Left ToggleMaximizeFull -mbind Maximize Click Middle ToggleMaximizeVert -mbind Maximize Click Right ToggleMaximizeHorz -mbind Iconify Click Left Iconify -mbind Icon DoubleClick Left Close -mbind Close Click Left Close -mbind Close Click Middle Kill -mbind AllDesktops Click Left ToggleOmnipresent -mbind Shade Click Left ToggleShade - -mbind Root Click Up NextDesktopWrap -mbind Root Click Down PreviousDesktopWrap -mbind Root Click A-Up NextDesktopWrap -mbind Root Click A-Down PreviousDesktopWrap -mbind Frame Click A-Up NextDesktopWrap -mbind Frame Click A-Down PreviousDesktopWrap -mbind Frame Click C-A-Up SendToNextDesktopWrap -mbind Frame Click C-A-Down SendToPreviousDesktopWrap - -mbind Root Click Right ShowMenu "root" -mbind Frame Click Right ShowMenu "client-menu" + diff --git a/openbox/Makefile.am b/openbox/Makefile.am index 4c83005f..ecb72969 100644 --- a/openbox/Makefile.am +++ b/openbox/Makefile.am @@ -6,7 +6,7 @@ binary=openbox3 url=http://icculus.org/openbox CPPFLAGS=$(X_CFLAGS) $(XFT_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) \ - $(LIBSN_CFLAGS) $(GL_CFLAGS) @CPPFLAGS@ \ + $(LIBSN_CFLAGS) $(GL_CFLAGS) $(XML_CFLAGS) @CPPFLAGS@ \ -DLOCALEDIR=\"$(localedir)\" \ -DRCDIR=\"$(rcdir)\" \ -DPLUGINDIR=\"$(plugindir)\" \ @@ -16,38 +16,25 @@ CPPFLAGS=$(X_CFLAGS) $(XFT_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) \ INCLUDES=-I.. LIBS=$(X_LIBS) $(XFT_LIBS) $(XINERAMA_LIBS) $(XKB_LIBS) $(XRANDR_LIBS) \ $(VIDMODE_LIBS) $(XSHAPE_LIBS) $(GLIB_LIBS) $(GMODULE_LIBS) \ - $(LIBSN_LIBS) @LIBS@ @LIBINTL@ + $(LIBSN_LIBS) $(XML_LIBS) @LIBS@ @LIBINTL@ bin_PROGRAMS=$(binary) openbox3_LDADD=-lobrender -L../render openbox3_LDFLAGS=-export-dynamic -openbox3_SOURCES=parse.tab.c parse.lex.c action.c client.c config.c \ +openbox3_SOURCES=action.c client.c config.c parse.c \ extensions.c focus.c frame.c grab.c menu.c menu_render.c \ - openbox.c framerender.c parse.c plugin.c prop.c screen.c \ + openbox.c framerender.c plugin.c prop.c screen.c \ stacking.c dispatch.c event.c group.c timer.c xerror.c \ moveresize.c startup.c popup.c dock.c window.c noinst_HEADERS=action.h client.h config.h dispatch.h event.h extensions.h \ focus.h frame.h framerender.h geom.h gettext.h grab.h group.h \ - menu.h openbox.h parse.h parse.tab.h plugin.h prop.h screen.h \ + menu.h openbox.h plugin.h prop.h screen.h \ stacking.h timer.h xerror.h moveresize.h startup.h popup.h \ - dock.h window.h - -# kill the implicit .c.y rule -%.c: %.y - @ - -%.lex.c: %.l - $(FLEX) -o$@ $< - -%.tab.c: %.y - $(BISON) -d -o $@ $< + dock.h window.h parse.h MAINTAINERCLEANFILES=Makefile.in -clean-local: - $(RM) parse.lex.c parse.tab.c parse.tab.h - distclean-local: $(RM) *\~ *.orig *.rej .\#* diff --git a/openbox/config.c b/openbox/config.c index e751f32b..c3fa786c 100644 --- a/openbox/config.c +++ b/openbox/config.c @@ -23,182 +23,114 @@ gboolean config_dock_horz; gboolean config_dock_hide; guint config_dock_hide_timeout; -static void parse_focus(char *name, ParseToken *value) +static void parse_focus(xmlDocPtr doc, xmlNodePtr node, void *d) { - if (!g_ascii_strcasecmp(name, "focusnew")) { - if (value->type != TOKEN_BOOL) - yyerror("invalid value"); - else { - config_focus_new = value->data.bool; - } - } else if (!g_ascii_strcasecmp(name, "followmouse")) { - if (value->type != TOKEN_BOOL) - yyerror("invalid value"); - else { - config_focus_follow = value->data.bool; - } - } else if (!g_ascii_strcasecmp(name, "focuslast")) { - if (value->type != TOKEN_BOOL) - yyerror("invalid value"); - else { - config_focus_last = value->data.bool; - } - } else if (!g_ascii_strcasecmp(name, "focuslastondesktop")) { - if (value->type != TOKEN_BOOL) - yyerror("invalid value"); - else { - config_focus_last_on_desktop = value->data.bool; - } - } else if (!g_ascii_strcasecmp(name, "cyclingdialog")) { - if (value->type != TOKEN_BOOL) - yyerror("invalid value"); - else { - config_focus_popup = value->data.bool; - } - } else - yyerror("invalid option"); - parse_free_token(value); + xmlNodePtr n; + + if ((n = parse_find_node("focusNew", node))) + config_focus_new = parse_bool(doc, n); + if ((n = parse_find_node("followMouse", node))) + config_focus_follow = parse_bool(doc, n); + if ((n = parse_find_node("focusLast", node))) + config_focus_last = parse_bool(doc, n); + if ((n = parse_find_node("focusLastOnDesktop", node))) + config_focus_last_on_desktop = parse_bool(doc, n); + if ((n = parse_find_node("cyclingDialog", node))) + config_focus_popup = parse_bool(doc, n); } -static void parse_theme(char *name, ParseToken *value) +static void parse_theme(xmlDocPtr doc, xmlNodePtr node, void *d) { - if (!g_ascii_strcasecmp(name, "theme")) { - if (value->type != TOKEN_STRING) - yyerror("invalid value"); - else { - g_free(config_theme); - config_theme = g_strdup(value->data.string); - } - } else - yyerror("invalid option"); - parse_free_token(value); + xmlNodePtr n; + + if ((n = parse_find_node("theme", node))) { + g_free(config_theme); + config_theme = parse_string(doc, n); + } } -static void parse_desktops(char *name, ParseToken *value) +static void parse_desktops(xmlDocPtr doc, xmlNodePtr node, void *d) { - GList *it; + xmlNodePtr n; - if (!g_ascii_strcasecmp(name, "number")) { - if (value->type != TOKEN_INTEGER) - yyerror("invalid value"); - else { - config_desktops_num = value->data.integer; + if ((n = parse_find_node("number", node))) + config_desktops_num = parse_int(doc, n); + if ((n = parse_find_node("names", node))) { + GSList *it; + xmlNodePtr nname; + + for (it = config_desktops_names; it; it = it->next) + g_free(it->data); + g_slist_free(config_desktops_names); + config_desktops_names = NULL; + + nname = parse_find_node("name", n->xmlChildrenNode); + while (nname) { + config_desktops_names = g_slist_append(config_desktops_names, + parse_string(doc, nname)); + nname = parse_find_node("name", nname->next); } - } else if (!g_ascii_strcasecmp(name, "names")) { - if (value->type == TOKEN_LIST) { - for (it = value->data.list; it; it = it->next) - if (((ParseToken*)it->data)->type != TOKEN_STRING) break; - if (it == NULL) { - /* build a string list */ - g_free(config_desktops_names); - for (it = value->data.list; it; it = it->next) - config_desktops_names = - g_slist_append(config_desktops_names, - g_strdup - (((ParseToken*)it->data)->data.string)); - } else { - yyerror("invalid string in names list"); - } - } else { - yyerror("syntax error (expected list of strings)"); - } - } else - yyerror("invalid option"); - parse_free_token(value); + } } -static void parse_moveresize(char *name, ParseToken *value) +static void parse_moveresize(xmlDocPtr doc, xmlNodePtr node, void *d) { - if (!g_ascii_strcasecmp(name, "opaque_move")) { - if (value->type != TOKEN_BOOL) - yyerror("invalid value"); - else { - config_opaque_move = value->data.integer; - } - } else if (!g_ascii_strcasecmp(name, "opaque_resize")) { - if (value->type != TOKEN_BOOL) - yyerror("invalid value"); - else { - config_opaque_resize = value->data.integer; - } - } else - yyerror("invalid option"); - parse_free_token(value); + xmlNodePtr n; + + if ((n = parse_find_node("opaqueMove", node))) + config_opaque_move = parse_bool(doc, n); + if ((n = parse_find_node("opaqueResize", node))) + config_opaque_resize = parse_bool(doc, n); } -static void parse_dock(char *name, ParseToken *value) +static void parse_dock(xmlDocPtr doc, xmlNodePtr node, void *d) { - if (!g_ascii_strcasecmp(name, "stacking")) { - if (value->type != TOKEN_STRING) - yyerror("invalid value"); - else { - if (!g_ascii_strcasecmp(value->data.string, "bottom")) - config_dock_layer = Layer_Below; - else if (!g_ascii_strcasecmp(value->data.string, "normal")) - config_dock_layer = Layer_Normal; - else if (!g_ascii_strcasecmp(value->data.string, "top")) - config_dock_layer = Layer_Top; - else - yyerror("invalid layer"); - } - } else if (!g_ascii_strcasecmp(name, "position")) { - if (value->type != TOKEN_STRING) - yyerror("invalid value"); - else { - if (!g_ascii_strcasecmp(value->data.string, "topleft")) - config_dock_pos = DockPos_TopLeft; - else if (!g_ascii_strcasecmp(value->data.string, "top")) - config_dock_pos = DockPos_Top; - else if (!g_ascii_strcasecmp(value->data.string, "topright")) - config_dock_pos = DockPos_TopRight; - else if (!g_ascii_strcasecmp(value->data.string, "right")) - config_dock_pos = DockPos_Right; - else if (!g_ascii_strcasecmp(value->data.string, "bottomright")) - config_dock_pos = DockPos_BottomRight; - else if (!g_ascii_strcasecmp(value->data.string, "bottom")) - config_dock_pos = DockPos_Bottom; - else if (!g_ascii_strcasecmp(value->data.string, "bottomleft")) - config_dock_pos = DockPos_BottomLeft; - else if (!g_ascii_strcasecmp(value->data.string, "left")) - config_dock_pos = DockPos_Left; - else if (!g_ascii_strcasecmp(value->data.string, "floating")) - config_dock_pos = DockPos_Floating; - else - yyerror("invalid position"); - } - } else if (!g_ascii_strcasecmp(name, "floatingx")) { - if (value->type != TOKEN_INTEGER) - yyerror("invalid value"); - else { - config_dock_x = value->data.integer; - } - } else if (!g_ascii_strcasecmp(name, "floatingy")) { - if (value->type != TOKEN_INTEGER) - yyerror("invalid value"); - else { - config_dock_y = value->data.integer; - } - } else if (!g_ascii_strcasecmp(name, "horizontal")) { - if (value->type != TOKEN_BOOL) - yyerror("invalid value"); - else { - config_dock_horz = value->data.bool; - } - } else if (!g_ascii_strcasecmp(name, "autohide")) { - if (value->type != TOKEN_BOOL) - yyerror("invalid value"); - else { - config_dock_hide = value->data.bool; - } - } else if (!g_ascii_strcasecmp(name, "hidetimeout")) { - if (value->type != TOKEN_INTEGER) - yyerror("invalid value"); - else { - config_dock_hide_timeout = value->data.integer; - } - } else - yyerror("invalid option"); - parse_free_token(value); + xmlNodePtr n; + + if ((n = parse_find_node("position", node))) { + if (parse_contains("TopLeft", doc, n)) + config_dock_pos = DockPos_TopLeft; + else if (parse_contains("Top", doc, n)) + config_dock_pos = DockPos_Top; + else if (parse_contains("TopRight", doc, n)) + config_dock_pos = DockPos_TopRight; + else if (parse_contains("Right", doc, n)) + config_dock_pos = DockPos_Right; + else if (parse_contains("BottomRight", doc, n)) + config_dock_pos = DockPos_BottomRight; + else if (parse_contains("Bottom", doc, n)) + config_dock_pos = DockPos_Bottom; + else if (parse_contains("BottomLeft", doc, n)) + config_dock_pos = DockPos_BottomLeft; + else if (parse_contains("Left", doc, n)) + config_dock_pos = DockPos_Left; + else if (parse_contains("Floating", doc, n)) + config_dock_pos = DockPos_Floating; + } + if (config_dock_pos == DockPos_Floating) { + if ((n = parse_find_node("floatingX", node))) + config_dock_x = parse_int(doc, n); + if ((n = parse_find_node("floatingY", node))) + config_dock_y = parse_int(doc, n); + } + if ((n = parse_find_node("stacking", node))) { + if (parse_contains("top", doc, n)) + config_dock_layer = Layer_Top; + else if (parse_contains("normal", doc, n)) + config_dock_layer = Layer_Normal; + else if (parse_contains("bottom", doc, n)) + config_dock_layer = Layer_Below; + } + if ((n = parse_find_node("direction", node))) { + if (parse_contains("horizontal", doc, n)) + config_dock_horz = TRUE; + else if (parse_contains("vertical", doc, n)) + config_dock_horz = FALSE; + } + if ((n = parse_find_node("autoHide", node))) + config_dock_hide = parse_bool(doc, n); + if ((n = parse_find_node("hideTimeout", node))) + config_dock_hide_timeout = parse_int(doc, n); } void config_startup() @@ -209,21 +141,21 @@ void config_startup() config_focus_last_on_desktop = TRUE; config_focus_popup = TRUE; - parse_reg_section("focus", NULL, parse_focus); + parse_register("focus", parse_focus, NULL); config_theme = NULL; - parse_reg_section("theme", NULL, parse_theme); + parse_register("theme", parse_theme, NULL); config_desktops_num = 4; config_desktops_names = NULL; - parse_reg_section("desktops", NULL, parse_desktops); + parse_register("desktops", parse_desktops, NULL); config_opaque_move = TRUE; config_opaque_resize = TRUE; - parse_reg_section("moveresize", NULL, parse_moveresize); + parse_register("moveresize", parse_moveresize, NULL); config_dock_layer = Layer_Top; config_dock_pos = DockPos_TopRight; @@ -233,7 +165,7 @@ void config_startup() config_dock_hide = FALSE; config_dock_hide_timeout = 3000; - parse_reg_section("dock", NULL, parse_dock); + parse_register("dock", parse_dock, NULL); } void config_shutdown() diff --git a/openbox/openbox.c b/openbox/openbox.c index 3b2a9991..2b4dddce 100644 --- a/openbox/openbox.c +++ b/openbox/openbox.c @@ -180,7 +180,7 @@ int main(int argc, char **argv) /* set up the kernel config shit */ config_startup(); /* parse/load user options */ - parse_rc(); + parse_config(); /* we're done with parsing now, kill it */ parse_shutdown(); diff --git a/openbox/parse.c b/openbox/parse.c index ffb72c03..8f9c82fb 100644 --- a/openbox/parse.c +++ b/openbox/parse.c @@ -1,86 +1,243 @@ #include "parse.h" +#include -static GHashTable *reg = NULL; +struct Callback { + char *tag; + ParseCallback func; + void *data; +}; -struct Functions { - ParseFunc f; - AssignParseFunc af; -} *funcs; +static GHashTable *callbacks; +static xmlDocPtr doc_config = NULL; -void destshit(gpointer shit) { g_free(shit); } +static void destfunc(struct Callback *c) +{ + g_free(c->tag); + g_free(c); +} void parse_startup() { - reg = g_hash_table_new_full(g_str_hash, g_str_equal, destshit, destshit); - funcs = NULL; + callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, + (GDestroyNotify)destfunc); } void parse_shutdown() { - g_hash_table_destroy(reg); + xmlFree(doc_config); + doc_config = NULL; + + g_hash_table_destroy(callbacks); } -void parse_reg_section(char *section, ParseFunc func, AssignParseFunc afunc) +void parse_register(const char *tag, ParseCallback func, void *data) { - struct Functions *f = g_new(struct Functions, 1); - f->f = func; - f->af = afunc; - g_hash_table_insert(reg, g_ascii_strdown(section, -1), f); + struct Callback *c; + + if ((c = g_hash_table_lookup(callbacks, tag))) { + g_warning("tag '%s' already registered", tag); + return; + } + + c = g_new(struct Callback, 1); + c->tag = g_strdup(tag); + c->func = func; + c->data = data; + g_hash_table_insert(callbacks, c->tag, c); } -void parse_free_token(ParseToken *token) +void parse_config() { - GList *it; + char *path; + xmlNodePtr node = NULL; - switch (token->type) { - case TOKEN_STRING: - g_free(token->data.string); - break; - case TOKEN_IDENTIFIER: - g_free(token->data.identifier); - break; - case TOKEN_LIST: - for (it = token->data.list; it; it = it->next) { - parse_free_token(it->data); - g_free(it->data); + xmlLineNumbersDefault(1); + + path = g_build_filename(g_get_home_dir(), ".openbox", "rc3", NULL); + if ((doc_config = xmlParseFile(path))) { + node = xmlDocGetRootElement(doc_config); + if (!node) { + xmlFreeDoc(doc_config); + doc_config = NULL; + g_warning("%s is an empty document", path); + } else { + if (xmlStrcasecmp(node->name, (const xmlChar*)"openbox_config")) { + xmlFreeDoc(doc_config); + doc_config = NULL; + g_warning("document %s is of wrong type. root node is " + "not 'openbox_config'", path); + } } - g_list_free(token->data.list); - break; - case TOKEN_REAL: - case TOKEN_INTEGER: - case TOKEN_BOOL: - case TOKEN_LBRACE: - case TOKEN_RBRACE: - case TOKEN_COMMA: - case TOKEN_NEWLINE: - break; + } + g_free(path); + if (!doc_config) { + path = g_build_filename(RCDIR, "rc3", NULL); + if ((doc_config = xmlParseFile(path))) { + node = xmlDocGetRootElement(doc_config); + if (!node) { + xmlFreeDoc(doc_config); + doc_config = NULL; + g_warning("%s is an empty document", path); + } else { + if (xmlStrcasecmp(node->name, + (const xmlChar*)"openbox_config")) { + xmlFreeDoc(doc_config); + doc_config = NULL; + g_warning("document %s is of wrong type. root node is " + "not 'openbox_config'", path); + } + } + } + g_free(path); + } + if (!doc_config) { + g_message("unable to find a valid config file, using defaults"); + } else { + parse_tree(doc_config, node->xmlChildrenNode, NULL); } } -void parse_set_section(char *section) +void parse_tree(xmlDocPtr doc, xmlNodePtr node, void *nothing) { - char *sec; - sec = g_ascii_strdown(section, -1); - funcs = g_hash_table_lookup(reg, sec); - g_free(sec); -} + while (node) { + struct Callback *c = g_hash_table_lookup(callbacks, node->name); -void parse_token(ParseToken *token) -{ - if (funcs) { - if (funcs->f) - funcs->f(token); - else if (token->type != TOKEN_NEWLINE) - yyerror("syntax error"); + if (c) + c->func(doc, node->xmlChildrenNode, c->data); + + node = node->next; } } -void parse_assign(char *name, ParseToken *value) +char *parse_string(xmlDocPtr doc, xmlNodePtr node) { - if (funcs) { - if (funcs->af) - funcs->af(name, value); - else - yyerror("syntax error"); - } + xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE); + char *s = g_strdup((char*)c); + xmlFree(c); + return s; +} + +int parse_int(xmlDocPtr doc, xmlNodePtr node) +{ + xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE); + int i = atoi((char*)c); + xmlFree(c); + return i; +} + +gboolean parse_bool(xmlDocPtr doc, xmlNodePtr node) +{ + xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE); + gboolean b = FALSE; + if (!xmlStrcasecmp(c, (const xmlChar*) "true")) + b = TRUE; + else if (!xmlStrcasecmp(c, (const xmlChar*) "yes")) + b = TRUE; + else if (!xmlStrcasecmp(c, (const xmlChar*) "on")) + b = TRUE; + xmlFree(c); + return b; +} + +gboolean parse_contains(const char *val, xmlDocPtr doc, xmlNodePtr node) +{ + xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE); + gboolean r; + r = !xmlStrcasecmp(c, (const xmlChar*) val); + xmlFree(c); + return r; +} + +xmlNodePtr parse_find_node(const char *tag, xmlNodePtr node) +{ + while (node) { + if (!xmlStrcasecmp(node->name, (const xmlChar*) tag)) + return node; + node = node->next; + } + return NULL; +} + +gboolean parse_attr_int(const char *name, xmlNodePtr node, int *value) +{ + xmlChar *c = xmlGetProp(node, (const xmlChar*) name); + gboolean r = FALSE; + if (c) { + *value = atoi((char*)c); + r = TRUE; + } + xmlFree(c); + return r; +} + +gboolean parse_attr_string(const char *name, xmlNodePtr node, char **value) +{ + xmlChar *c = xmlGetProp(node, (const xmlChar*) name); + gboolean r = FALSE; + if (c) { + *value = g_strdup((char*)c); + r = TRUE; + } + xmlFree(c); + return r; +} + +Action *parse_action(xmlDocPtr doc, xmlNodePtr node) +{ + char *actname; + Action *act = NULL; + xmlNodePtr n; + + if (parse_attr_string("name", node, &actname)) { + if ((act = action_from_string(actname))) { + if (act->func == action_execute || act->func == action_restart) { + if ((n = parse_find_node("execute", node->xmlChildrenNode))) + act->data.execute.path = parse_string(doc, n); + } else if (act->func == action_showmenu) { + if ((n = parse_find_node("menu", node->xmlChildrenNode))) + act->data.showmenu.name = parse_string(doc, n); + } else if (act->func == action_desktop) { + if ((n = parse_find_node("desktop", node->xmlChildrenNode))) + act->data.desktop.desk = parse_int(doc, n); + if (act->data.desktop.desk > 0) act->data.desktop.desk--; + } else if (act->func == action_send_to_desktop) { + if ((n = parse_find_node("desktop", node->xmlChildrenNode))) + act->data.sendto.desk = parse_int(doc, n); + if (act->data.sendto.desk > 0) act->data.sendto.desk--; + } else if (act->func == action_move_relative_horz || + act->func == action_move_relative_vert || + act->func == action_resize_relative_horz || + act->func == action_resize_relative_vert) { + if ((n = parse_find_node("delta", node->xmlChildrenNode))) + act->data.relative.delta = parse_int(doc, n); + } else if (act->func == action_desktop_right || + act->func == action_desktop_left || + act->func == action_desktop_up || + act->func == action_desktop_down) { + if ((n = parse_find_node("wrap", node->xmlChildrenNode))) { + g_message("WRAP %d", parse_bool(doc, n)); + act->data.desktopdir.wrap = parse_bool(doc, n); + } + } else if (act->func == action_send_to_desktop_right || + act->func == action_send_to_desktop_left || + act->func == action_send_to_desktop_up || + act->func == action_send_to_desktop_down) { + if ((n = parse_find_node("wrap", node->xmlChildrenNode))) + act->data.sendtodir.wrap = parse_bool(doc, n); + if ((n = parse_find_node("follow", node->xmlChildrenNode))) + act->data.sendtodir.follow = parse_bool(doc, n); + } + } + } + return act; +} + +gboolean parse_attr_contains(const char *val, xmlNodePtr node, + const char *name) +{ + xmlChar *c = xmlGetProp(node, (const xmlChar*) name); + gboolean r; + r = !xmlStrcasecmp(c, (const xmlChar*) val); + xmlFree(c); + return r; } diff --git a/openbox/parse.h b/openbox/parse.h index abd5bb2d..199e8104 100644 --- a/openbox/parse.h +++ b/openbox/parse.h @@ -1,48 +1,38 @@ #ifndef __parse_h #define __parse_h +#include "action.h" + +#include #include -#ifndef NO_TAB_H -#include "parse.tab.h" -#endif -typedef enum { - TOKEN_REAL = REAL, - TOKEN_INTEGER = INTEGER, - TOKEN_STRING = STRING, - TOKEN_IDENTIFIER = IDENTIFIER, - TOKEN_BOOL = BOOLEAN, - TOKEN_LIST, - TOKEN_LBRACE = '{', - TOKEN_RBRACE = '}', - TOKEN_COMMA = ',', - TOKEN_NEWLINE = '\n' -} ParseTokenType; - -typedef struct { - ParseTokenType type; - union ParseTokenData data; -} ParseToken; - -typedef void (*ParseFunc)(ParseToken *token); -typedef void (*AssignParseFunc)(char *name, ParseToken *value); +typedef void (*ParseCallback)(xmlDocPtr doc, xmlNodePtr node, void *data); void parse_startup(); void parse_shutdown(); -/* Parse the RC file - found in parse.yacc -*/ -void parse_rc(); +void parse_register(const char *tag, ParseCallback func, void *data); -void parse_reg_section(char *section, ParseFunc func, AssignParseFunc afunc); +void parse_config(); + +void parse_tree(xmlDocPtr doc, xmlNodePtr node, void *nothing); -/* Free a parsed token's allocated memory */ -void parse_free_token(ParseToken *token); +/* helpers */ -/* Display an error message while parsing. - found in parse.yacc */ -void yyerror(char *err); +xmlNodePtr parse_find_node(const char *tag, xmlNodePtr node); + +char *parse_string(xmlDocPtr doc, xmlNodePtr node); +int parse_int(xmlDocPtr doc, xmlNodePtr node); +gboolean parse_bool(xmlDocPtr doc, xmlNodePtr node); + +gboolean parse_contains(const char *val, xmlDocPtr doc, xmlNodePtr node); +gboolean parse_attr_contains(const char *val, xmlNodePtr node, + const char *name); + +gboolean parse_attr_string(const char *name, xmlNodePtr node, char **value); +gboolean parse_attr_int(const char *name, xmlNodePtr node, int *value); + +Action *parse_action(xmlDocPtr doc, xmlNodePtr node); #endif diff --git a/openbox/parse.l b/openbox/parse.l deleted file mode 100644 index a7cd6c63..00000000 --- a/openbox/parse.l +++ /dev/null @@ -1,45 +0,0 @@ -%{ -#include "parse.h" -#ifdef HAVE_STDLIB_H -# include -#endif - -extern int lineno; -%} - -real [-0-9][0-9]*\.[0-9]+ -integer [-0-9][0-9]* -string \"[^"\n]*\" -identifier [a-zA-Z][-.a-zA-Z0-9_]* -bool ([tT][rR][uU][eE]|[fF][aA][lL][sS][eE]|[yY][eE][sS]|[nN][oO]|[oO][nN]|[oO][fF][fF]) - -%% - -^[ \t]*#.*\n /* comment */ { ++lineno; } -^[ \t]*#.* /* comment */ -^[ \t]*\n /* empty lines */ { ++lineno; } -[ \t] /* whitespace */ -{real} { yylval.real = atof(yytext); return REAL; } -{integer} { yylval.integer = atoi(yytext); return INTEGER; } -{string} { yylval.string = g_strdup(yytext+1); /* drop the left quote */ - if (yylval.string[yyleng-2] != '"') - yyerror("improperly terminated string on line %d"); - else - yylval.string[yyleng-2] = '\0'; - return STRING; - } -{bool} { yylval.bool = (!g_ascii_strcasecmp("true", yytext) || - !g_ascii_strcasecmp("yes", yytext) || - !g_ascii_strcasecmp("on", yytext)); - return BOOLEAN; - } -{identifier} { yylval.identifier = g_strdup(yytext); return IDENTIFIER; } -[{}()\[\]=,] { yylval.character = *yytext; return *yytext; } -\n { yylval.character = *yytext; return *yytext; } -. { return INVALID; } - -%% - -int yywrap() { - return 1; -} diff --git a/openbox/parse.y b/openbox/parse.y deleted file mode 100644 index 7e92efd6..00000000 --- a/openbox/parse.y +++ /dev/null @@ -1,146 +0,0 @@ -%{ -#include -#ifdef HAVE_STDIO_H -# include -#endif - -%} - -%union ParseTokenData { - float real; - int integer; - char *string; - char *identifier; - gboolean bool; - char character; - GList *list; -} - -%{ -#define NO_TAB_H -#include "parse.h" -#undef NO_TAB_H - -extern int yylex(); -extern int yyparse(); -void yyerror(char *err); - -extern int lineno; -extern FILE *yyin; - -static char *path; -static ParseToken t; - -/* in parse.c */ -void parse_token(ParseToken *token); -void parse_assign(char *name, ParseToken *token); -void parse_set_section(char *section); -%} - -%token REAL -%token INTEGER -%token STRING -%token IDENTIFIER -%token BOOLEAN -%token '(' -%token ')' -%token '{' -%token '}' -%token '=' -%token ',' -%token '\n' -%token INVALID - -%type list -%type listtokens - -%% - -sections: - | sections '[' IDENTIFIER ']' { parse_set_section($3); } '\n' - { ++lineno; } lines - ; - -lines: - | lines tokens { t.type='\n'; t.data.character='\n'; parse_token(&t); } '\n' - { ++lineno; } - | lines IDENTIFIER '=' listtoken { parse_assign($2, &t); } '\n' - { ++lineno; } - ; - -tokens: - tokens token { parse_token(&t); } - | token { parse_token(&t); } - ; - -token: - REAL { t.type = TOKEN_REAL; t.data.real = $1; } - | INTEGER { t.type = TOKEN_INTEGER; t.data.integer = $1; } - | STRING { t.type = TOKEN_STRING; t.data.string = $1; } - | IDENTIFIER { t.type = TOKEN_IDENTIFIER; t.data.identifier = $1; } - | BOOLEAN { t.type = TOKEN_BOOL; t.data.bool = $1; } - | list { t.type = TOKEN_LIST; t.data.list = $1; } - | '{' { t.type = $1; t.data.character = $1; } - | '}' { t.type = $1; t.data.character = $1; } - | ',' { t.type = $1; t.data.character = $1; } - ; - -list: - '(' listtokens ')' { $$ = $2; } - ; - -listtokens: - listtokens listtoken { ParseToken *nt = g_new(ParseToken, 1); - nt->type = t.type; - nt->data = t.data; - $$ = g_list_append($1, nt); - } - | listtoken { ParseToken *nt = g_new(ParseToken, 1); - nt->type = t.type; - nt->data = t.data; - $$ = g_list_append(NULL, nt); - } - ; - -listtoken: - REAL { t.type = TOKEN_REAL; t.data.real = $1; } - | INTEGER { t.type = TOKEN_INTEGER; t.data.integer = $1; } - | STRING { t.type = TOKEN_STRING; t.data.string = $1; } - | IDENTIFIER { t.type = TOKEN_IDENTIFIER; t.data.identifier = $1; } - | BOOLEAN { t.type = TOKEN_BOOL; t.data.bool = $1; } - | list { t.type = TOKEN_LIST; t.data.list = $1; } - | '{' { t.type = $1; t.data.character = $1; } - | '}' { t.type = $1; t.data.character = $1; } - | ',' { t.type = $1; t.data.character = $1; } - ; - - -%% - -int lineno; - -void yyerror(char *err) { - g_message("%s:%d: %s", path, lineno, err); -} - -void parse_rc() -{ - /* try the user's rc */ - path = g_build_filename(g_get_home_dir(), ".openbox", "rc3", NULL); - if ((yyin = fopen(path, "r")) == NULL) { - g_free(path); - /* try the system wide rc */ - path = g_build_filename(RCDIR, "rc3", NULL); - if ((yyin = fopen(path, "r")) == NULL) { - g_warning("No rc2 file found!"); - g_free(path); - return; - } - } - - lineno = 1; - - yyparse(); - - g_free(path); -} diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 4796307a..b23259d6 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -2,7 +2,8 @@ plugindir=$(libdir)/openbox/plugins SUBDIRS = keyboard mouse placement menu -CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) @CPPFLAGS@ \ +CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) \ + $(XML_CFLAGS) @CPPFLAGS@ \ -DPLUGINDIR=\"$(plugindir)\" INCLUDES=-I.. diff --git a/plugins/keyboard/Makefile.am b/plugins/keyboard/Makefile.am index ffcd104b..4b1e850a 100644 --- a/plugins/keyboard/Makefile.am +++ b/plugins/keyboard/Makefile.am @@ -1,6 +1,7 @@ plugindir=$(libdir)/openbox/plugins -CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) @CPPFLAGS@ \ +CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) \ + $(XML_CFLAGS) @CPPFLAGS@ \ -DG_LOG_DOMAIN=\"Plugin-Keyboard\" INCLUDES=-I../.. @@ -8,7 +9,7 @@ INCLUDES=-I../.. plugin_LTLIBRARIES=keyboard.la keyboard_la_LDFLAGS=-module -avoid-version -keyboard_la_SOURCES=keyboard.c keyparse.c translate.c tree.c +keyboard_la_SOURCES=keyboard.c translate.c tree.c noinst_HEADERS=keyboard.h keyparse.h translate.h tree.h diff --git a/plugins/keyboard/keyboard.c b/plugins/keyboard/keyboard.c index 5991606a..d1d93241 100644 --- a/plugins/keyboard/keyboard.c +++ b/plugins/keyboard/keyboard.c @@ -4,17 +4,74 @@ #include "kernel/event.h" #include "kernel/grab.h" #include "kernel/action.h" +#include "kernel/prop.h" #include "kernel/parse.h" #include "kernel/timer.h" #include "tree.h" #include "keyboard.h" -#include "keyparse.h" #include "translate.h" #include +/* + + + + 3 + + + +*/ + +static void parse_key(xmlDocPtr doc, xmlNodePtr node, GList *keylist) +{ + char *key; + Action *action; + xmlNodePtr n, nact; + GList *it; + + n = parse_find_node("keybind", node); + while (n) { + if (parse_attr_string("key", n, &key)) { + keylist = g_list_append(keylist, key); + + parse_key(doc, n->xmlChildrenNode, keylist); + + it = g_list_last(keylist); + g_free(it->data); + keylist = g_list_delete_link(keylist, it); + } + n = parse_find_node("keybind", n->next); + } + if (keylist) { + nact = parse_find_node("action", node); + while (nact) { + if ((action = parse_action(doc, nact))) { + /* validate that its okay for a key binding */ + if (action->func == action_moveresize && + action->data.moveresize.corner != + prop_atoms.net_wm_moveresize_move_keyboard && + action->data.moveresize.corner != + prop_atoms.net_wm_moveresize_size_keyboard) { + action_free(action); + action = NULL; + } + + if (action) + kbind(keylist, action); + } + nact = parse_find_node("action", nact->next); + } + } +} + +static void parse_xml(xmlDocPtr doc, xmlNodePtr node, void *d) +{ + parse_key(doc, node, NULL); +} + void plugin_setup_config() { - parse_reg_section("keyboard", keyparse, NULL); + parse_register("keyboard", parse_xml, NULL); } KeyBindingTree *firstnode = NULL; @@ -160,6 +217,7 @@ static void event(ObEvent *e, void *foo) act->data.cycle.cancel = FALSE; } + act->data.any.c = focus_client; act->func(&act->data); if (act->func == action_cycle_windows && diff --git a/plugins/mouse/Makefile.am b/plugins/mouse/Makefile.am index e4c897d5..3d4d6b9e 100644 --- a/plugins/mouse/Makefile.am +++ b/plugins/mouse/Makefile.am @@ -1,6 +1,7 @@ plugindir=$(libdir)/openbox/plugins -CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) @CPPFLAGS@ \ +CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) \ + $(XML_CFLAGS) @CPPFLAGS@ \ -DG_LOG_DOMAIN=\"Plugin-Mouse\" INCLUDES=-I../.. @@ -8,9 +9,9 @@ INCLUDES=-I../.. plugin_LTLIBRARIES=mouse.la mouse_la_LDFLAGS=-module -avoid-version -mouse_la_SOURCES=mouse.c mouseparse.c translate.c +mouse_la_SOURCES=mouse.c translate.c -noinst_HEADERS=mouse.h mouseparse.h translate.h +noinst_HEADERS=mouse.h translate.h MAINTAINERCLEANFILES=Makefile.in diff --git a/plugins/mouse/mouse.c b/plugins/mouse/mouse.c index e39720cb..0bfe602c 100644 --- a/plugins/mouse/mouse.c +++ b/plugins/mouse/mouse.c @@ -9,38 +9,97 @@ #include "kernel/frame.h" #include "translate.h" #include "mouse.h" -#include "mouseparse.h" #include static int threshold; static int dclicktime; -static void parse_assign(char *name, ParseToken *value) +/* + + + + + + + +*/ + +static void parse_xml(xmlDocPtr doc, xmlNodePtr node, void *d) { - if (!g_ascii_strcasecmp(name, "dragthreshold")) { - if (value->type != TOKEN_INTEGER) - yyerror("invalid value"); - else { - if (value->data.integer >= 0) - threshold = value->data.integer; + xmlNodePtr n, nbut, nact; + char *buttonstr; + char *contextstr; + MouseAction mact; + Action *action; + + if ((n = parse_find_node("dragThreshold", node))) + threshold = parse_int(doc, n); + if ((n = parse_find_node("doubleClickTime", node))) + dclicktime = parse_int(doc, n); + + n = parse_find_node("context", node); + while (n) { + if (!parse_attr_string("name", n, &contextstr)) + goto next_n; + nbut = parse_find_node("mousebind", n->xmlChildrenNode); + while (nbut) { + if (!parse_attr_string("button", nbut, &buttonstr)) + goto next_nbut; + if (parse_attr_contains("press", nbut, "action")) + mact = MouseAction_Press; + else if (parse_attr_contains("release", nbut, "action")) + mact = MouseAction_Release; + else if (parse_attr_contains("click", nbut, "action")) + mact = MouseAction_Click; + else if (parse_attr_contains("doubleclick", nbut,"action")) + mact = MouseAction_DClick; + else if (parse_attr_contains("drag", nbut, "action")) + mact = MouseAction_Motion; + else + goto next_nbut; + nact = parse_find_node("action", nbut->xmlChildrenNode); + while (nact) { + if ((action = parse_action(doc, nact))) { + /* validate that its okay for a mouse binding*/ + if (mact == MouseAction_Motion) { + if (action->func != action_moveresize || + action->data.moveresize.corner == + prop_atoms.net_wm_moveresize_move_keyboard || + action->data.moveresize.corner == + prop_atoms.net_wm_moveresize_size_keyboard) { + action_free(action); + action = NULL; + } + } else { + if (action->func == action_moveresize && + action->data.moveresize.corner != + prop_atoms.net_wm_moveresize_move_keyboard && + action->data.moveresize.corner != + prop_atoms.net_wm_moveresize_size_keyboard) { + action_free(action); + action = NULL; + } + } + if (action) + mbind(buttonstr, contextstr, mact, action); + } + nact = parse_find_node("action", nact->next); + } + g_free(buttonstr); + next_nbut: + nbut = parse_find_node("mousebind", nbut->next); } - } else if (!g_ascii_strcasecmp(name, "doubleclicktime")) { - if (value->type != TOKEN_INTEGER) - yyerror("invalid value"); - else { - if (value->data.integer >= 0) - dclicktime = value->data.integer; - } - } else - yyerror("invalid option"); - parse_free_token(value); + g_free(contextstr); + next_n: + n = parse_find_node("context", n->next); + } } void plugin_setup_config() { threshold = 3; dclicktime = 200; - parse_reg_section("mouse", mouseparse, parse_assign); + parse_register("mouse", parse_xml, NULL); } /* Array of GSList*s of PointerBinding*s. */ @@ -240,11 +299,11 @@ static void event(ObEvent *e, void *foo) e->data.x.e->xbutton.window); if (e->data.x.e->xbutton.button == button) { /* clicks are only valid if its released over the window */ - int junk; + int junk1, junk2; Window wjunk; guint ujunk, b, w, h; XGetGeometry(ob_display, e->data.x.e->xbutton.window, - &wjunk, &junk, &junk, &w, &h, &b, &ujunk); + &wjunk, &junk1, &junk2, &w, &h, &b, &ujunk); if (e->data.x.e->xbutton.x >= (signed)-b && e->data.x.e->xbutton.y >= (signed)-b && e->data.x.e->xbutton.x < (signed)(w+b) && diff --git a/plugins/placement/Makefile.am b/plugins/placement/Makefile.am index 6b328008..762f5af8 100644 --- a/plugins/placement/Makefile.am +++ b/plugins/placement/Makefile.am @@ -1,6 +1,7 @@ plugindir=$(libdir)/openbox/plugins -CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) @CPPFLAGS@ \ +CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) $(LIBSN_CFLAGS) $(GL_CFLAGS) \ + $(XML_CFLAGS) @CPPFLAGS@ \ -DG_LOG_DOMAIN=\"Plugin-Placement\" INCLUDES=-I../.. diff --git a/plugins/placement/history.c b/plugins/placement/history.c index ea3d60df..9d932b9e 100644 --- a/plugins/placement/history.c +++ b/plugins/placement/history.c @@ -3,41 +3,47 @@ #include "kernel/frame.h" #include "kernel/client.h" #include "kernel/screen.h" +#include "kernel/parse.h" +#include "history.h" #include #include #ifdef HAVE_STDLIB_H # include #endif +#define PLACED (1 << 0) + +#define HAVE_POSITION (1 << 1) +#define HAVE_SIZE (1 << 2) +#define HAVE_DESKTOP (1 << 3) + struct HistoryItem { char *name; char *class; char *role; - int x; - int y; - gboolean placed; + + int flags; + + int x, y; + int w, h; + guint desk; }; -static GSList *history = NULL; +static GSList *history_list = NULL; static char *history_path = NULL; -static struct HistoryItem *find_history(Client *c) +static struct HistoryItem *history_find(const char *name, const char *class, + const char *role) { GSList *it; struct HistoryItem *hi = NULL; /* find the client */ - for (it = history; it != NULL; it = it->next) { + for (it = history_list; it != NULL; it = it->next) { hi = it->data; - g_assert(hi->name != NULL); - g_assert(hi->class != NULL); - g_assert(hi->role != NULL); - g_assert(c->name != NULL); - g_assert(c->class != NULL); - g_assert(c->role != NULL); - if (!strcmp(hi->name, c->name) && - !strcmp(hi->class, c->class) && - !strcmp(hi->role, c->role)) + if (!g_utf8_collate(hi->name, name) && + !g_utf8_collate(hi->class, class) && + !g_utf8_collate(hi->role, role)) return hi; } return NULL; @@ -46,57 +52,65 @@ static struct HistoryItem *find_history(Client *c) gboolean place_history(Client *c) { struct HistoryItem *hi; - int x, y; + int x, y, w, h; - hi = find_history(c); + hi = history_find(c->name, c->class, c->role); - if (hi != NULL && !hi->placed) { - hi->placed = TRUE; + if (hi && !(hi->flags & PLACED)) { + hi->flags |= PLACED; if (ob_state != State_Starting) { - x = hi->x; - y = hi->y; - - frame_frame_gravity(c->frame, &x, &y); /* get where the client - should be */ - client_configure(c, Corner_TopLeft, x, y, - c->area.width, c->area.height, - TRUE, TRUE); + if (hi->flags & HAVE_POSITION || + hi->flags & HAVE_SIZE) { + if (hi->flags & HAVE_POSITION) { + x = hi->x; + y = hi->y; + /* get where the client should be */ + frame_frame_gravity(c->frame, &x, &y); + } else { + x = c->area.x; + y = c->area.y; + } + if (hi->flags & HAVE_SIZE) { + w = hi->w * c->size_inc.width; + h = hi->h * c->size_inc.height; + } else { + w = c->area.width; + h = c->area.height; + } + client_configure(c, Corner_TopLeft, x, y, w, h, + TRUE, TRUE); + } + if (hi->flags & HAVE_DESKTOP) { + client_set_desktop(c, hi->desk, FALSE); + } } - return TRUE; + return hi->flags & HAVE_POSITION; } return FALSE; } -static void strip_tabs(char *s) -{ - while (*s != '\0') { - if (*s == '\t') - *s = ' '; - ++s; - } -} - static void set_history(Client *c) { struct HistoryItem *hi; - hi = find_history(c); + hi = history_find(c->name, c->class, c->role); if (hi == NULL) { hi = g_new(struct HistoryItem, 1); - history = g_slist_append(history, hi); + history_list = g_slist_append(history_list, hi); hi->name = g_strdup(c->name); - strip_tabs(hi->name); hi->class = g_strdup(c->class); - strip_tabs(hi->class); hi->role = g_strdup(c->role); - strip_tabs(hi->role); + hi->flags = HAVE_POSITION; } - hi->x = c->frame->area.x; - hi->y = c->frame->area.y; - hi->placed = FALSE; + if (hi->flags & HAVE_POSITION) { + hi->x = c->frame->area.x; + hi->y = c->frame->area.y; + } + + hi->flags &= ~PLACED; } static void event(ObEvent *e, void *foo) @@ -106,104 +120,140 @@ static void event(ObEvent *e, void *foo) set_history(e->data.c.client); } +/* + + + 0 + 0 + 300 + 200 + 1 + + +*/ + static void save_history() { - GError *err = NULL; - GIOChannel *io; - GString *buf; + xmlDocPtr doc; + xmlNodePtr root, node; + char *s; GSList *it; - struct HistoryItem *hi; - gsize ret; - io = g_io_channel_new_file(history_path, "w", &err); - if (io != NULL) { - for (it = history; it != NULL; it = it->next) { - hi = it->data; - buf = g_string_sized_new(0); - buf=g_string_append(buf, hi->name); - g_string_append_c(buf, '\t'); - buf=g_string_append(buf, hi->class); - g_string_append_c(buf, '\t'); - buf=g_string_append(buf, hi->role); - g_string_append_c(buf, '\t'); - g_string_append_printf(buf, "%d", hi->x); - buf=g_string_append_c(buf, '\t'); - g_string_append_printf(buf, "%d", hi->y); - buf=g_string_append_c(buf, '\n'); - if (g_io_channel_write_chars(io, buf->str, buf->len, &ret, &err) != - G_IO_STATUS_NORMAL) - break; - g_string_free(buf, TRUE); + doc = xmlNewDoc(NULL); + root = xmlNewNode(NULL, (const xmlChar*) "openbox_history"); + xmlDocSetRootElement(doc, root); + + for (it = history_list; it; it = g_slist_next(it)) { + struct HistoryItem *hi = it->data; + g_message("adding %s", hi->name); + node = xmlNewChild(root, NULL, (const xmlChar*) "entry", NULL); + xmlNewProp(node, (const xmlChar*) "name", (const xmlChar*) hi->name); + xmlNewProp(node, (const xmlChar*) "class", (const xmlChar*) hi->class); + xmlNewProp(node, (const xmlChar*) "role", (const xmlChar*) hi->role); + if (hi->flags & HAVE_POSITION) { + s = g_strdup_printf("%d", hi->x); + xmlNewTextChild(node, NULL, + (const xmlChar*) "x", (const xmlChar*) s); + g_free(s); + s = g_strdup_printf("%d", hi->y); + xmlNewTextChild(node, NULL, + (const xmlChar*) "y", (const xmlChar*) s); + g_free(s); + } + if (hi->flags & HAVE_SIZE) { + s = g_strdup_printf("%d", hi->w); + xmlNewTextChild(node, NULL, + (const xmlChar*) "width", (const xmlChar*) s); + g_free(s); + s = g_strdup_printf("%d", hi->h); + xmlNewTextChild(node, NULL, + (const xmlChar*) "height", (const xmlChar*) s); + g_free(s); + } + if (hi->flags & HAVE_DESKTOP) { + s = g_strdup_printf("%d", hi->desk < 0 ? hi->desk : hi->desk + 1); + xmlNewTextChild(node, NULL, + (const xmlChar*) "desktop", (const xmlChar*) s); + g_free(s); } - g_io_channel_unref(io); } + + xmlIndentTreeOutput = 1; + xmlSaveFormatFile(history_path, doc, 1); + + xmlFree(doc); } static void load_history() { - GError *err = NULL; - GIOChannel *io; - char *buf = NULL; - char *b, *c; - struct HistoryItem *hi = NULL; + xmlDocPtr doc; + xmlNodePtr node, n; + char *name; + char *class; + char *role; + struct HistoryItem *hi; - io = g_io_channel_new_file(history_path, "r", &err); - if (io != NULL) { - while (g_io_channel_read_line(io, &buf, NULL, NULL, &err) == - G_IO_STATUS_NORMAL) { - hi = g_new0(struct HistoryItem, 1); + if (!(doc = xmlParseFile(history_path))) + return; + if (!(node = xmlDocGetRootElement(doc))) { + xmlFreeDoc(doc); + doc = NULL; + return; + } + if (xmlStrcasecmp(node->name, (const xmlChar*)"openbox_history")) { + xmlFreeDoc(doc); + doc = NULL; + return; + } - b = buf; - if ((c = strchr(b, '\t')) == NULL) break; - *c = '\0'; - hi->name = g_strdup(b); + node = parse_find_node("entry", node->xmlChildrenNode); + while (node) { + name = class = role = NULL; + if (parse_attr_string("name", node, &name) && + parse_attr_string("class", node, &class) && + parse_attr_string("role", node, &role)) { - b = c + 1; - if ((c = strchr(b, '\t')) == NULL) break; - *c = '\0'; - hi->class = g_strdup(b); + hi = history_find(name, class, role); + if (!hi) { + hi = g_new(struct HistoryItem, 1); + hi->name = g_strdup(name); + hi->class = g_strdup(class); + hi->role = g_strdup(role); + hi->flags = 0; + } + if ((n = parse_find_node("x", node->xmlChildrenNode))) { + hi->x = parse_int(doc, n); + if ((n = parse_find_node("y", node->xmlChildrenNode))) { + hi->y = parse_int(doc, n); + hi->flags |= HAVE_POSITION; + } + } + if ((n = parse_find_node("width", node->xmlChildrenNode))) { + hi->w = parse_int(doc, n); + if ((n = parse_find_node("height", node->xmlChildrenNode))) { + hi->h = parse_int(doc, n); + hi->flags |= HAVE_SIZE; + } + } + if ((n = parse_find_node("desktop", node->xmlChildrenNode))) { + hi->desk = parse_int(doc, n); + if (hi->desk > 0) --hi->desk; + hi->flags |= HAVE_DESKTOP; + } - b = c + 1; - if ((c = strchr(b, '\t')) == NULL) break; - *c = '\0'; - hi->role = g_strdup(b); - - b = c + 1; - if ((c = strchr(b, '\t')) == NULL) break; - *c = '\0'; - hi->x = atoi(b); - - b = c + 1; - if ((c = strchr(b, '\n')) == NULL) break; - *c = '\0'; - hi->y = atoi(b); - - hi->placed = FALSE; - - g_free(buf); - buf = NULL; - - history = g_slist_append(history, hi); - hi = NULL; + history_list = g_slist_append(history_list, hi); } - g_io_channel_unref(io); + g_free(name); g_free(class); g_free(role); + node = parse_find_node("entry", node->next); } - - g_free(buf); - - if (hi != NULL) { - g_free(hi->name); - g_free(hi->class); - g_free(hi->role); - } - g_free(hi); + xmlFree(doc); } void history_startup() { char *path; - history = NULL; + history_list = NULL; path = g_build_filename(g_get_home_dir(), ".openbox", "history", NULL); history_path = g_strdup_printf("%s.%d", path, ob_screen); @@ -219,9 +269,14 @@ void history_shutdown() GSList *it; save_history(); /* save to the historydb file */ - for (it = history; it != NULL; it = it->next) - g_free(it->data); - g_slist_free(history); + for (it = history_list; it != NULL; it = it->next) { + struct HistoryItem *hi = it->data; + g_free(hi->name); + g_free(hi->class); + g_free(hi->role); + g_free(hi); + } + g_slist_free(history_list); dispatch_register(0, (EventHandler)event, NULL); diff --git a/plugins/placement/history.h b/plugins/placement/history.h index 48a29c3e..38571769 100644 --- a/plugins/placement/history.h +++ b/plugins/placement/history.h @@ -1,7 +1,7 @@ #ifndef __plugin_placement_history_h #define __plugin_placement_history_h -#include "../../kernel/client.h" +#include "kernel/client.h" #include void history_startup(); diff --git a/plugins/placement/placement.c b/plugins/placement/placement.c index 23ffbb5d..dd818970 100644 --- a/plugins/placement/placement.c +++ b/plugins/placement/placement.c @@ -9,23 +9,19 @@ static gboolean history; -static void parse_assign(char *name, ParseToken *value) +static void parse_xml(xmlDocPtr doc, xmlNodePtr node, void *d) { - if (!g_ascii_strcasecmp(name, "remember")) { - if (value->type != TOKEN_BOOL) - yyerror("invalid value"); - else - history = value->data.bool; - } else - yyerror("invalid option"); - parse_free_token(value); + xmlNodePtr n; + + if ((n = parse_find_node("remember", node))) + history = parse_bool(doc, n); } void plugin_setup_config() { history = TRUE; - parse_reg_section("placement", NULL, parse_assign); + parse_register("placement", parse_xml, NULL); } static void place_random(Client *c) diff --git a/plugins/resistance.c b/plugins/resistance.c index bafd362c..ee6f6e1e 100644 --- a/plugins/resistance.c +++ b/plugins/resistance.c @@ -9,23 +9,14 @@ static int resistance; static gboolean resist_windows; -static void parse_assign(char *name, ParseToken *value) +static void parse_xml(xmlDocPtr doc, xmlNodePtr node, void *d) { - if (!g_ascii_strcasecmp(name, "strength")) { - if (value->type != TOKEN_INTEGER) - yyerror("invalid value"); - else { - if (value->data.integer >= 0) - resistance = value->data.integer; - } - } else if (!g_ascii_strcasecmp(name, "windows")) { - if (value->type != TOKEN_BOOL) - yyerror("invalid value"); - else - resist_windows = value->data.bool; - } else - yyerror("invalid option"); - parse_free_token(value); + xmlNodePtr n; + + if ((n = parse_find_node("strength", node))) + resistance = parse_int(doc, n); + if ((n = parse_find_node("windows", node))) + resist_windows = parse_bool(doc, n); } void plugin_setup_config() @@ -33,7 +24,7 @@ void plugin_setup_config() resistance = 10; resist_windows = TRUE; - parse_reg_section("resistance", NULL, parse_assign); + parse_register("resistance", parse_xml, NULL); } static void resist_move(Client *c, int *x, int *y)