From 71c8b0b7b2cf2fa79ac4c81b7756f2b230f2de7a Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Wed, 2 Apr 2003 07:46:46 +0000 Subject: [PATCH] create a generic tokenizer/sectionizer for the config file. pass off the token to functions registered for each section to parse them further. some fixes for the engine irt font shadows, and fixed a bug with rendering the iconify button when it was not in the layout --- engines/openbox/Makefile.am | 1 - engines/openbox/obengine.c | 9 ++- engines/openbox/obengine.h | 1 + engines/openbox/obtheme.c | 30 ++++---- openbox/Makefile.am | 12 ++-- openbox/config.c | 47 ++++++------- openbox/config.h | 2 - openbox/cparse.l | 124 -------------------------------- openbox/openbox.c | 11 ++- openbox/parse.c | 137 ++++++++++++++++++++++++++++++++++++ openbox/parse.h | 42 +++++++++++ openbox/parse.l | 48 +++++++++++++ openbox/parse.yacc | 98 ++++++++++++++++++++++++++ 13 files changed, 384 insertions(+), 178 deletions(-) delete mode 100644 openbox/cparse.l create mode 100644 openbox/parse.c create mode 100644 openbox/parse.h create mode 100644 openbox/parse.l create mode 100644 openbox/parse.yacc diff --git a/engines/openbox/Makefile.am b/engines/openbox/Makefile.am index 800956d9..33efbb71 100644 --- a/engines/openbox/Makefile.am +++ b/engines/openbox/Makefile.am @@ -5,7 +5,6 @@ CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) @CPPFLAGS@ \ -DENGINEDIR=\"$(enginedir)\" \ -DTHEMEDIR=\"$(themedir)\" \ -DDEFAULT_THEME=\"nyz\" \ --DDEFAULT_FONT=\"Sans-7\" \ -DG_LOG_DOMAIN=\"Openbox-Engine\" engine_LTLIBRARIES=openbox.la diff --git a/engines/openbox/obengine.c b/engines/openbox/obengine.c index b6b9638f..f98bb36c 100644 --- a/engines/openbox/obengine.c +++ b/engines/openbox/obengine.c @@ -36,6 +36,7 @@ color_rgb *ob_s_titlebut_unfocused_color; int ob_s_winfont_height; int ob_s_winfont_shadow; int ob_s_winfont_shadow_offset; +int ob_s_winfont_shadow_tint; ObFont *ob_s_winfont; /* style settings - masks */ pixmap_mask *ob_s_max_set_mask; @@ -495,7 +496,7 @@ void frame_adjust_area(ObFrame *self, gboolean moved, gboolean resized) self->icon_x = -1; self->desk_x = -1; self->shade_x = -1; - self->icon_x = -1; + self->iconify_x = -1; self->label_x = -1; self->max_x = -1; self->close_x = -1; @@ -712,10 +713,8 @@ static void layout_title(ObFrame *self) n = d = i = l = m = c = s = FALSE; - if (!config_get("titlebar.layout", Config_String, &layout)) { - layout.string = "NDSLIMC"; - config_set("titlebar.layout", Config_String, layout); - } + if (!config_get("titlebar.layout", Config_String, &layout)) + g_assert_not_reached(); /* figure out whats being shown, and the width of the label */ self->label_width = self->width - (ob_s_bevel + 1) * 2; diff --git a/engines/openbox/obengine.h b/engines/openbox/obengine.h index 4f9cb5b6..b4e46983 100644 --- a/engines/openbox/obengine.h +++ b/engines/openbox/obengine.h @@ -30,6 +30,7 @@ extern color_rgb *ob_s_titlebut_unfocused_color; extern int ob_s_winfont_height; extern int ob_s_winfont_shadow; extern int ob_s_winfont_shadow_offset; +extern int ob_s_winfont_shadow_tint; extern ObFont *ob_s_winfont; extern pixmap_mask *ob_s_max_set_mask; diff --git a/engines/openbox/obtheme.c b/engines/openbox/obtheme.c index ccd17cc0..3f45c209 100644 --- a/engines/openbox/obtheme.c +++ b/engines/openbox/obtheme.c @@ -277,7 +277,7 @@ gboolean obtheme_load() XrmDatabase db = NULL; Justify winjust; char *winjuststr; - ConfigValue theme, shadow, offset, font; + ConfigValue theme, shadow, offset, font, tint; if (config_get("theme", Config_String, &theme)) { db = loaddb(theme.string); @@ -299,21 +299,21 @@ gboolean obtheme_load() /* load the font, not from the theme file tho, its in the config */ - if (!config_get("font.shadow", Config_Bool, &shadow)) { - shadow.bool = TRUE; /* default */ - config_set("font.shadow", Config_Bool, shadow); - } + if (!config_get("font.shadow", Config_Bool, &shadow)) + g_assert_not_reached(); ob_s_winfont_shadow = shadow.bool; - if (!config_get("font.shadow.offset", Config_Integer, &offset) || - offset.integer < 0 || offset.integer >= 10) { - offset.integer = 1; /* default */ - config_set("font.shadow.offset", Config_Integer, offset); - } + if (!config_get("font.shadow.offset", Config_Integer, &offset)) + g_assert_not_reached(); ob_s_winfont_shadow_offset = offset.integer; - if (!config_get("font", Config_String, &font)) { - font.string = DEFAULT_FONT; - config_set("font", Config_String, font); - } + if (!config_get("font.shadow.tint", Config_Integer, &tint)) + g_assert_not_reached(); + /* XXX put these checks into the config system somehow!!! */ + if (tint.integer < -100) tint.integer = -100; + if (tint.integer > 100) tint.integer = 100; + config_set("font.shadow.tint", Config_Integer, tint); + ob_s_winfont_shadow_tint = tint.integer; + if (!config_get("font", Config_String, &font)) + g_assert_not_reached(); ob_s_winfont = font_open(font.string); ob_s_winfont_height = font_height(ob_s_winfont, ob_s_winfont_shadow, ob_s_winfont_shadow_offset); @@ -495,6 +495,7 @@ gboolean obtheme_load() ob_a_focused_label->texture[0].data.text.shadow = ob_s_winfont_shadow; ob_a_focused_label->texture[0].data.text.offset = ob_s_winfont_shadow_offset; + ob_a_focused_label->texture[0].data.text.tint = ob_s_winfont_shadow_tint; ob_a_focused_label->texture[0].data.text.color = ob_s_title_focused_color; ob_a_unfocused_label->texture[0].type = Text; @@ -503,6 +504,7 @@ gboolean obtheme_load() ob_a_unfocused_label->texture[0].data.text.shadow = ob_s_winfont_shadow; ob_a_unfocused_label->texture[0].data.text.offset = ob_s_winfont_shadow_offset; + ob_a_unfocused_label->texture[0].data.text.tint = ob_s_winfont_shadow_tint; ob_a_unfocused_label->texture[0].data.text.color = ob_s_title_unfocused_color; diff --git a/openbox/Makefile.am b/openbox/Makefile.am index d691cbcd..33355cb3 100644 --- a/openbox/Makefile.am +++ b/openbox/Makefile.am @@ -27,14 +27,18 @@ openbox3_LDADD=@LIBINTL@ ../render/librender.a openbox3_LDFLAGS=-export-dynamic openbox3_SOURCES=client.c event.c extensions.c focus.c frame.c openbox.c \ prop.c screen.c stacking.c xerror.c timer.c dispatch.c \ - engine.c plugin.c action.c grab.c lex.cparse.c config.c menu.c + engine.c plugin.c action.c grab.c config.c menu.c \ + y.tab.c lex.yy.c parse.c noinst_HEADERS=client.h event.h extensions.h focus.h frame.h geom.h gettext.h \ openbox.h prop.h screen.h stacking.h xerror.h dispatch.h \ - timer.h engine.h plugin.h action.h grab.h config.h menu.h + timer.h engine.h plugin.h action.h grab.h config.h menu.h parse.h -lex.cparse.c: cparse.l - $(FLEX) -Pcparse $^ +lex.yy.c: parse.l + $(FLEX) $^ + +y.tab.c: parse.yacc + $(YACC) -d $< MAINTAINERCLEANFILES= Makefile.in diff --git a/openbox/config.c b/openbox/config.c index 6a6bd901..a6056ee1 100644 --- a/openbox/config.c +++ b/openbox/config.c @@ -25,26 +25,47 @@ void config_startup() "Engine", "The name of the theming engine to be used " "to decorate windows.")); + config_def_set(config_def_new("theme", Config_String, "Theme", "The name of the theme to load with the " "chosen engine.")); + config_def_set(config_def_new("font", Config_String, "Titlebar Font", "The fontstring specifying the font to " "be used in window titlebars.")); + val.string = "Sans-7"; + config_set("font", Config_String, val); + config_def_set(config_def_new("font.shadow", Config_Bool, "Titlebar Font Shadow", "Whether or not the text in the window " "titlebars gets a drop shadow.")); + val.bool = FALSE; + config_set("font.shadow", Config_Bool, val); + config_def_set(config_def_new("font.shadow.offset", Config_Integer, "Titlebar Font Shadow Offset", "The offset of the drop shadow for text " "in the window titlebars.")); + val.integer = 1; + config_set("font.shadow.offset", Config_Integer, val); + + config_def_set(config_def_new("font.shadow.tint", Config_Integer, + "Titlebar Font Shadow Tint", + "The percentage of tint/opacity to give the " + "the shadow(from -100(white) to " + "100(black)).")); + val.integer = 25; + config_set("font.shadow.tint", Config_Integer, val); + config_def_set(config_def_new("titlebar.layout", Config_String, "Titlebar Layout", "The ordering of the elements in the " "window titlebars.")); + val.string = "NDSLIMC"; + config_set("titlebar.layout", Config_String, val); config_def_set(config_def_new("focusNew", Config_Bool, "Focus New Windows", @@ -66,32 +87,6 @@ void config_shutdown() g_datalist_clear(&config_def); } -void config_parse() -{ - FILE *file; - char *path; - gboolean load = FALSE; - - /* load the user rc */ - path = g_build_filename(g_get_home_dir(), ".openbox", "rc3", NULL); - if ((file = fopen(path, "r")) != NULL) { - cparse_go(path, file); - fclose(file); - load = TRUE; - } - g_free(path); - - if (!load) { - /* load the system wide rc */ - path = g_build_filename(RCDIR, "rc3", NULL); - if ((file = fopen(path, "r")) != NULL) { - /*cparse_go(path, file);*/ - fclose(file); - } - g_free(path); - } -} - gboolean config_set(char *name, ConfigValueType type, ConfigValue value) { ConfigDefEntry *def; diff --git a/openbox/config.h b/openbox/config.h index 9b62b8e5..3d82090b 100644 --- a/openbox/config.h +++ b/openbox/config.h @@ -54,6 +54,4 @@ gboolean config_def_add_value(ConfigDefEntry *entry, char *value); FALSE. */ gboolean config_def_set(ConfigDefEntry *entry); -void config_parse(); - #endif diff --git a/openbox/cparse.l b/openbox/cparse.l deleted file mode 100644 index 70524007..00000000 --- a/openbox/cparse.l +++ /dev/null @@ -1,124 +0,0 @@ -%{ -#include -#include "config.h" - -static char *filename; -static int lineno = 1; -static gboolean haserror = FALSE; -static gboolean comment = FALSE; -static ConfigEntry entry = { NULL, -1 }; - -static void stringvalue(); -static void numbervalue(); -static void boolvalue(); -static void identifier(); -static void newline(); -static int cparsewrap(); -%} - -number [0-9]+ -string \"[^"\n]*\" -identifier [a-zA-Z][a-zA-Z0-9_.]* -white [ \t]* -assign {white}={white} -bool ([tT][rR][uU][eE]|[fF][aA][lL][sS][eE]|[yY][eE][sS]|[nN][oO]|[oO][nN]|[oO][fF][fF]) - -%% - -^{white}# comment = TRUE; -{bool}/{white}\n boolvalue(); -{string}/{white}\n stringvalue(); -{number}/{white}\n numbervalue(); -^{identifier}/{assign} identifier(); -\n newline(); -= -[ \t] -. if (!comment) haserror = TRUE; - -%% - -static void stringvalue() -{ - if (!comment) { - if (!haserror && entry.name != NULL && (signed)entry.type < 0) { - entry.type = Config_String; - entry.value.string = g_strdup(cparsetext+1); /* drop the left quote */ - if (entry.value.string[cparseleng-2] != '"') - g_warning("improperly terminated string on line %d", - lineno); - else - entry.value.string[cparseleng-2] = '\0'; - } else - haserror = TRUE; - } -} - -static void numbervalue() -{ - if (!comment) { - if (!haserror && entry.name != NULL && (signed)entry.type < 0) { - entry.type = Config_Integer; - entry.value.integer = atoi(cparsetext); - } else - haserror = TRUE; - } -} - -static void boolvalue() -{ - if (!comment) { - if (!haserror && entry.name != NULL && (signed)entry.type < 0) { - entry.type = Config_Bool; - entry.value.bool = (!g_ascii_strcasecmp("true", cparsetext) || - !g_ascii_strcasecmp("yes", cparsetext) || - !g_ascii_strcasecmp("on", cparsetext)); - } else - haserror = TRUE; - } -} - -static void identifier() -{ - if (!comment) { - entry.name = g_strdup(cparsetext); - entry.type = -1; - } -} - -static void newline() -{ - if (!comment) { - if (!haserror && entry.name != NULL && (signed)entry.type >= 0) { - if (!config_set(entry.name, entry.type, entry.value)) - g_warning("Parser error in '%s' on line %d\n", filename, - lineno); - } else if (haserror || entry.name != NULL || (signed)entry.type >= 0) { - g_warning("Parser error in '%s' on line %d", filename, lineno); - } - g_free(entry.name); - entry.name = NULL; - if (entry.type == Config_String) - g_free(entry.value.string); - entry.type = -1; - - haserror = FALSE; - } - comment = FALSE; - ++lineno; -} - -static int cparsewrap() -{ - g_free(entry.name); - entry.name = NULL; - if (entry.type == Config_String) - g_free(entry.value.string); - return 1; -} - -void cparse_go(char *fname, FILE *file) -{ - filename = fname; - cparsein = file; - cparselex(); -} diff --git a/openbox/openbox.c b/openbox/openbox.c index 117349f2..a7357b2f 100644 --- a/openbox/openbox.c +++ b/openbox/openbox.c @@ -9,6 +9,7 @@ #include "extensions.h" #include "gettext.h" #include "config.h" +#include "parse.h" #include "grab.h" #include "engine.h" #include "plugin.h" @@ -145,7 +146,7 @@ int main(int argc, char **argv) prop_startup(); /* get atoms values for the display */ extensions_query_all(); /* find which extensions are present */ - + if (screen_annex()) { /* it will be ours! */ timer_startup(); config_startup(); @@ -153,10 +154,16 @@ int main(int argc, char **argv) font_startup(); plugin_startup(); + /* startup the parsing so plugins can register sections of the rc */ + parse_startup(); + /* load the plugins specified in the pluginrc */ plugin_loadall(); /* parse/load user options */ - config_parse(); + parse_rc(); + + /* we're done with parsing now, kill it */ + parse_shutdown(); engine_startup(); event_startup(); diff --git a/openbox/parse.c b/openbox/parse.c new file mode 100644 index 00000000..f8f0cd94 --- /dev/null +++ b/openbox/parse.c @@ -0,0 +1,137 @@ +#include "parse.h" +#include "config.h" + +static GHashTable *reg = NULL; +static ParseFunc func = NULL; + +/* parse tokens from the [openbox] section of the rc file */ +static void parse_rc_token(ParseTokenType type, union ParseToken token); + +void destkey(gpointer key) { g_free(key); } + +void parse_startup() +{ + reg = g_hash_table_new_full(g_str_hash, g_str_equal, destkey, NULL); + func = NULL; + + parse_reg_section("openbox", parse_rc_token); +} + +void parse_shutdown() +{ + g_hash_table_destroy(reg); +} + +void parse_reg_section(char *section, ParseFunc func) +{ + if (g_hash_table_lookup(reg, section) != NULL) + g_warning("duplicate request for section '%s' in the rc file", + section); + else + g_hash_table_insert(reg, g_ascii_strdown(section, -1), (void*)func); +} + +void parse_free_token(ParseTokenType type, union ParseToken token) +{ + switch (type) { + case TOKEN_STRING: + g_free(token.string); + break; + case TOKEN_IDENTIFIER: + g_free(token.identifier); + break; + case TOKEN_REAL: + case TOKEN_INTEGER: + case TOKEN_BOOL: + case TOKEN_LBRACKET: + case TOKEN_RBRACKET: + case TOKEN_LBRACE: + case TOKEN_RBRACE: + case TOKEN_EQUALS: + case TOKEN_COMMA: + case TOKEN_NEWLINE: + break; + } +} + +void parse_set_section(char *section) +{ + func = (ParseFunc)g_hash_table_lookup(reg, section); +} + +void parse_token(ParseTokenType type, union ParseToken token) +{ + if (func != NULL) + func(type, token); +} + +static void parse_rc_token(ParseTokenType type, union ParseToken token) +{ + static int got_eq = FALSE; + static ParseTokenType got_val = 0; + static char *id = NULL, *s = NULL; + static int i; + static gboolean b; + + if (id == NULL) { + if (type == TOKEN_IDENTIFIER) { + id = token.identifier; + return; + } else { + yyerror("syntax error"); + } + } else if (!got_eq) { + if (type == TOKEN_EQUALS) { + got_eq = TRUE; + return; + } else { + yyerror("syntax error"); + } + } else if (!got_val) { + if (type == TOKEN_STRING) { + s = token.string; + got_val = type; + return; + } else if (type == TOKEN_BOOL) { + b = token.bool; + got_val = type; + return; + } else if (type == TOKEN_INTEGER) { + i = token.integer; + got_val = type; + return; + } else + yyerror("syntax error"); + } else if (type != TOKEN_NEWLINE) { + yyerror("syntax error"); + } else { + ConfigValue v; + + switch (got_val) { + case TOKEN_STRING: + v.string = s; + if (!config_set(id, Config_String, v)) + yyerror("invalid value type"); + break; + case TOKEN_BOOL: + v.bool = b; + if (!config_set(id, Config_Bool, v)) + yyerror("invalid value type"); + break; + case TOKEN_INTEGER: + v.integer = i; + if (!config_set(id, Config_Integer, v)) + yyerror("invalid value type"); + break; + default: + g_assert_not_reached(); /* unhandled type got parsed */ + } + } + + g_free(id); + g_free(s); + id = s = NULL; + got_eq = FALSE; + got_val = 0; + parse_free_token(type, token); +} diff --git a/openbox/parse.h b/openbox/parse.h new file mode 100644 index 00000000..3c649db1 --- /dev/null +++ b/openbox/parse.h @@ -0,0 +1,42 @@ +#ifndef __parse_h +#define __parse_h + +#include +#include "y.tab.h" + +typedef enum { + TOKEN_REAL = REAL, + TOKEN_INTEGER = INTEGER, + TOKEN_STRING = STRING, + TOKEN_IDENTIFIER = IDENTIFIER, + TOKEN_BOOL = BOOL, + TOKEN_LBRACKET = '(', + TOKEN_RBRACKET = ')', + TOKEN_LBRACE = '{', + TOKEN_RBRACE = '}', + TOKEN_EQUALS = '=', + TOKEN_COMMA = ',', + TOKEN_NEWLINE = '\n' +} ParseTokenType; + +typedef void (*ParseFunc)(ParseTokenType type, union ParseToken token); + +void parse_startup(); +void parse_shutdown(); + +/* Parse the RC file + found in parse.yacc +*/ +void parse_rc(); + +void parse_reg_section(char *section, ParseFunc func); + + +/* Free a parsed token's allocated memory */ +void parse_free_token(ParseTokenType type, union ParseToken token); + +/* Display an error message while parsing. + found in parse.yacc */ +void yyerror(char *err); + +#endif diff --git a/openbox/parse.l b/openbox/parse.l new file mode 100644 index 00000000..c888b9f1 --- /dev/null +++ b/openbox/parse.l @@ -0,0 +1,48 @@ +%{ +#include +#include "y.tab.h" +#ifdef HAVE_STDLIB_H +# include +#endif + +extern void yyerror(char *err); + +int yylineno = 1; +%} + +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 */ { ++yylineno; } +^[ \t]*#.* /* comment */ +^[ \t]*\n /* empty lines */ { ++yylineno; } +[ \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 BOOL; + } +{identifier} { yylval.identifier = g_strdup(yytext); return IDENTIFIER; } +[{}()\[\]=,] { yylval.character = *yytext; return *yytext; } +\n { yylval.character = *yytext; ++yylineno; return *yytext; } +. { return INVALID; } + +%% + +int yywrap() { + return 1; +} diff --git a/openbox/parse.yacc b/openbox/parse.yacc new file mode 100644 index 00000000..e9b469e0 --- /dev/null +++ b/openbox/parse.yacc @@ -0,0 +1,98 @@ +%{ +#include "parse.h" +#ifdef HAVE_STDIO_H +# include +#endif + +extern int yylex(); + +extern int yylineno; +extern FILE *yyin; + +static char *path; +static union ParseToken t; + +/* in parse.c */ +void parse_token(ParseTokenType type, union ParseToken token); +void parse_set_section(char *section); +%} + +%union ParseToken { + float real; + int integer; + char *string; + char *identifier; + gboolean bool; + char character; +} + +%token REAL +%token INTEGER +%token STRING +%token IDENTIFIER +%token BOOL +%token '(' +%token ')' +%token '{' +%token '}' +%token '=' +%token ',' +%token '\n' +%token INVALID + +%% + +sections: + | sections '[' IDENTIFIER ']' { parse_set_section($3); } '\n' lines + ; + +lines: + | lines tokens '\n' { t.character = $3; parse_token(TOKEN_NEWLINE, t); } + ; + +tokens: + tokens token + | token + ; + +token: + REAL { t.real = $1; parse_token(TOKEN_REAL, t); } + | INTEGER { t.integer = $1; parse_token(TOKEN_INTEGER, t); } + | STRING { t.string = $1; parse_token(TOKEN_STRING, t); } + | IDENTIFIER { t.identifier = $1; parse_token(TOKEN_IDENTIFIER, t); } + | BOOL { t.bool = $1; parse_token(TOKEN_BOOL, t); } + | '(' { t.character = $1; parse_token(TOKEN_LBRACKET, t); } + | ')' { t.character = $1; parse_token(TOKEN_RBRACKET, t); } + | '{' { t.character = $1; parse_token(TOKEN_LBRACE, t); } + | '}' { t.character = $1; parse_token(TOKEN_RBRACE, t); } + | '=' { t.character = $1; parse_token(TOKEN_EQUALS, t); } + | ',' { t.character = $1; parse_token(TOKEN_COMMA, t); } + ; + +%% + +void yyerror(char *err) { + g_message("%s:%d: %s", path, yylineno, 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; + } + } + + yylineno = 1; + + yyparse(); + + g_free(path); +} -- 2.39.2