--- /dev/null
+*.o
+obtheme
+obtheme.lex.*
+obtheme.tab.*
--- /dev/null
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+#include "obtheme.h"
+
+struct obthemedata themedata;
+
+int main(int argc, char **argv)
+{
+ int err;
+ struct theme *thm;
+ Rect br;
+ Strut bstrut;
+
+ themedata.themes = g_hash_table_new(g_str_hash, g_str_equal);
+ themedata.materials = g_hash_table_new(g_str_hash, g_str_equal);
+ err = obtheme_parse(&themedata, argv[1]);
+ if (err) {
+ printf("Fix the script\n");
+ exit(1);
+ }
+ printf("err = %d\n", err);
+
+// g_hash_table_foreach(themedata.materials, material_print, NULL);
+
+// g_hash_table_foreach(themedata.themes, theme_print, NULL);
+
+ thm = g_hash_table_lookup(themedata.themes, "awesome");
+ obtheme_decorate_window(thm, "regular_window");
+ obtheme_calc_bound(thm, "regular_window", &br, &bstrut);
+ printf("bounding rectangle: (%d %d) - (%d %d)\n", br.x, br.y, br.x + br.width, br.y + br.height);
+
+ return 0;
+}
--- /dev/null
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+#include "obtheme.h"
+#include "geom.h"
+
+static double variable_lookup(struct variable *in)
+{
+ if (strcmp("client", in->base) == 0) {
+ if (strcmp("width", in->member) == 0) {
+ return 640;
+ } else
+ return 480;
+ }
+ if (strcmp("font", in->base) == 0) {
+ return 15.0;
+ }
+ return 0.0;
+}
+
+static double expression_eval(struct expression *in)
+{
+ switch (in->op) {
+ case OB_THEME_INV:
+ return - expression_eval(in->a);
+ break;
+ case OB_THEME_MUL:
+ return expression_eval(in->a) * expression_eval(in->b);
+ break;
+ case OB_THEME_DIV:
+ return expression_eval(in->a) / expression_eval(in->b);
+ break;
+ case OB_THEME_ADD:
+ return expression_eval(in->a) + expression_eval(in->b);
+ break;
+ case OB_THEME_SUB:
+ return expression_eval(in->a) - expression_eval(in->b);
+ break;
+ case OB_THEME_EQL:
+ if (in->v.base == NULL) {
+ return in->v.number;
+ } else return variable_lookup(&in->v);
+ break;
+ default:
+ assert(!!!"OH NOES!!!");
+ }
+ return 0;
+}
+
+static void decor_print(gpointer data, gpointer user_data)
+{
+ struct decor *decor = data;
+ printf(" decor id %s\n", decor->name);
+printf(" anchor.x = %f\n", expression_eval(&decor->space.anchor.x));
+ if (decor->texture.present) {
+ if (decor->texture.internal)
+ printf(" texture internal: %s\n", decor->texture.name);
+ else
+ printf(" texture file: %s\n", decor->texture.name);
+ }
+// printf(" anchor (%d %d %d)\n", decor->space.anchor.x, decor->space.anchor.y, decor->space.anchor.z);
+// printf(" up (%d %d %d)\n", decor->space.up.x, decor->space.up.y, decor->space.up.z);
+ if (decor->children)
+ g_slist_foreach(decor->children, decor_print, NULL);
+}
+
+static void style_print(gpointer key, gpointer value, gpointer user_data)
+{
+ char *stylename = key;
+ struct style *style = value;
+
+ printf(" style %s\n", stylename);
+ g_slist_foreach(style->tree, decor_print, NULL);
+}
+
+static void theme_print(gpointer key, gpointer value, gpointer user_data)
+{
+ char *name = key;
+ struct theme *thm = value;
+ printf("name = %s\n", name);
+ g_hash_table_foreach(thm->styles, style_print, NULL);
+}
+
+static void material_print(gpointer key, gpointer value, gpointer user_data)
+{
+ char *name = key;
+ struct material *mat = value;
+ printf("name = %s\n", name);
+ printf(" opacity = %f\n", mat->opacity);
+}
+
+static void decor_render(gpointer data, gpointer user_data)
+{
+ struct decor *decor = data;
+ struct box *box = &decor->geometry.box;
+ struct vector *a = &decor->space.anchor;
+ double x, y;
+
+ printf("%s:", decor->name);
+ x = expression_eval(&a->x);
+ y = expression_eval(&a->y);
+ printf("rectangle(%f %f) - (%f %f)\n", x + expression_eval(&box->start.x), y + expression_eval(&box->start.y),
+ x + expression_eval(&box->end.x), y + expression_eval(&box->end.y));
+ if (decor->children)
+ g_slist_foreach(decor->children, decor_render, NULL);
+}
+
+struct boundstuff {
+ Rect r;
+ Strut s;
+};
+
+static void decor_bound(gpointer data, gpointer user_data)
+{
+ struct boundstuff *bs = user_data;
+ struct decor *decor = data;
+ struct box *box = &decor->geometry.box;
+ struct vector *a = &decor->space.anchor;
+ Rect newrect, temprect;
+ double x1, y1, x2, y2;
+
+ x1 = expression_eval(&a->x);
+ y1 = expression_eval(&a->y);
+ x2 = x1;
+ y2 = y1;
+ x1 += expression_eval(&box->start.x);
+ y1 += expression_eval(&box->start.y);
+ x2 += expression_eval(&box->end.x);
+ y2 += expression_eval(&box->end.y);
+ RECT_SET(temprect, x1, y1, x2-x1, y2-y2);
+ RECT_ADD(newrect, temprect, bs->r);
+ bs->r = newrect;
+
+ if (decor->children)
+ g_slist_foreach(decor->children, decor_bound, bs);
+}
+
+void obtheme_calc_bound(struct theme *thm, char *name, Rect *r, Strut *s)
+{
+ struct style *sty;
+ struct boundstuff bs;
+
+ RECT_SET(bs.r, 0, 0 ,0 ,0);
+ sty = g_hash_table_lookup(thm->styles, name);
+ assert(sty);
+ g_slist_foreach(sty->tree, decor_bound, &bs);
+ *r = bs.r;
+}
+
+void obtheme_decorate_window(struct theme *thm, char *name)
+{
+ struct style *sty;
+ sty = g_hash_table_lookup(thm->styles, name);
+ g_slist_foreach(sty->tree, decor_render, NULL);
+}
--- /dev/null
+#ifndef __THEME_PARSE_H__
+#define __THEME_PARSE_H__
+
+#include <glib.h>
+#include "frame.h"
+#include "misc.h"
+
+#undef YY_DECL
+#define YY_DECL int obthemelex(YYSTYPE *yylval, struct parser_control *pc)
+
+#define YYDEBUG 1
+#define YYLEX_PARAM pc
+
+#define MAX_INCLUDE_DEPTH 32
+#define LINE pc->currline[pc->include_stack_ptr]
+
+extern int themedebug;
+
+struct boundrect {
+ double x1, y1, x2, y2;
+};
+
+typedef enum {
+ OB_THEME_INV,
+ OB_THEME_ADD,
+ OB_THEME_SUB,
+ OB_THEME_MUL,
+ OB_THEME_DIV,
+ OB_THEME_EQL
+} ObThemeOp;
+
+struct variable {
+ char *base;
+ char *member;
+ double number;
+};
+
+struct expression {
+ ObThemeOp op;
+ struct expression *a;
+ struct expression *b;
+ struct variable v;
+};
+
+struct material {
+ float opacity;
+};
+
+struct style {
+ char *name;
+ GSList *tree;
+};
+
+struct obthemedata {
+ GHashTable *themes;
+ GHashTable *materials;
+};
+
+struct theme {
+ char *name;
+ GHashTable *styles;
+};
+
+struct vector {
+ struct expression x;
+ struct expression y;
+ struct expression z;
+};
+
+struct space {
+ struct vector anchor;
+ struct vector up;
+};
+
+struct texture {
+ gboolean present;
+ gboolean internal;
+ char *name;
+};
+
+struct box {
+ struct vector start;
+ struct vector end;
+};
+
+struct geometry {
+ struct box box;
+};
+
+struct decor {
+ char *name;
+ GSList *children;
+ struct space space;
+ ObDirection cursor;
+ ObFrameContext context;
+ struct texture texture;
+ struct material *material;
+ struct geometry geometry;
+};
+
+struct parser_control {
+ struct yy_buffer_state *include_stack[MAX_INCLUDE_DEPTH];
+ int currline[MAX_INCLUDE_DEPTH];
+ char currfile[MAX_INCLUDE_DEPTH][501];
+ int include_stack_ptr;
+ char error_buf[4096];
+ struct obthemedata *target;
+};
+
+void obthemeerror(struct parser_control *pc, char *s);
+int obtheme_parse(struct obthemedata *td, const char *filename);
+struct parser_control *parser_init(struct obthemedata *td);
+int obthemeparse(struct parser_control *);
+void parser_finish(struct parser_control *);
+void obtheme_calc_bound(struct theme *thm, char *name, Rect *r, Strut *s);
+void obtheme_decorate_window(struct theme *thm, char *name);
+
+#endif /* __THEME_PARSE_H__ */
--- /dev/null
+%{
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "frame.h"
+#include "misc.h"
+#include "render.h"
+#include "obtheme.h"
+#include "obtheme.tab.h"
+
+int yylex(YYSTYPE *yylval, struct parser_control *pc);
+
+void obthemeerror(struct parser_control *pc, char *s)
+{
+ printf("Parse error in file %s on line %d\n%s"
+ , pc->currfile[pc->include_stack_ptr]
+ , pc->currline[pc->include_stack_ptr] + 1
+ , pc->error_buf);
+}
+
+extern int parserparse(void *);
+
+int yywrap(void)
+{
+ return 1;
+}
+
+int obtheme_parse(struct obthemedata *td, const char *filename)
+{
+ FILE *input;
+ int ret;
+ struct parser_control *pc;
+//illdebug = 1;
+ pc = parser_init(td);
+ input = fopen(filename, "r");
+ if (!input)
+ return 2;
+ yyin = input;
+ yyrestart(input);
+ BEGIN 0;
+ pc->include_stack_ptr = 0;
+ pc->currline[pc->include_stack_ptr] = 0;
+ strncpy(pc->currfile[pc->include_stack_ptr], filename, 500);
+ ret = obthemeparse(pc);
+ if (ret != 0) {
+ //XXX I THINK I NEED TO CLOSE ALL INCLUDE FILES HERE
+ //probably also fclose input and call parser_finish?
+ return ret;
+ }
+ fclose(input);
+ parser_finish(pc);
+ return ret;
+}
+
+%}
+%x comment
+%x incl
+%%
+
+include BEGIN(incl);
+<incl>[ \t]* /* eat the whitespace */
+<incl>[^ \t\n]+ { /* got the include file name */
+ char *incfile;
+ if ( pc->include_stack_ptr >= MAX_INCLUDE_DEPTH) {
+ fprintf( stderr, "Includes nested too deeply" );
+ exit(1);
+ }
+
+ pc->include_stack[pc->include_stack_ptr++] = YY_CURRENT_BUFFER;
+ incfile = malloc(strlen(yytext) + strlen("include/")+ 1);
+ strcpy(incfile, "include/");
+ strcat(incfile, yytext);
+ yyin = fopen( incfile, "r" );
+ free(incfile);
+ strncpy(pc->currfile[pc->include_stack_ptr], yytext, 500);
+ pc->currline[pc->include_stack_ptr] = 0;
+ if ( ! yyin ) {
+ printf("Could not find include file %s (%s)\n", yytext, incfile);
+ exit(1);
+ }
+ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+
+ BEGIN(INITIAL);
+ }
+
+<<EOF>> {
+ if ( --(pc->include_stack_ptr) < 0 )
+ {
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yyterminate();
+ }
+
+ else
+ {
+ yy_delete_buffer( YY_CURRENT_BUFFER );
+ fclose(yyin);
+ yy_switch_to_buffer(
+ pc->include_stack[pc->include_stack_ptr] );
+ }
+ }
+
+
+"//"+[^\n]* ;
+"/*" BEGIN(comment);
+<comment>[^*\n]* ;
+<comment>"*"+[^*/\n]* ;
+<comment>"*"+"/" BEGIN(INITIAL);
+<comment>\n LINE++;
+
+theme return THEME;
+frame return FRAME;
+decor return DECOR;
+space return SPACE;
+geometry return GEOMETRY;
+material return MATERIAL;
+gradient return GRADIENT;
+context return CONTEXT;
+cursor return CURSOR;
+style return STYLE;
+up return UP;
+anchor return ANCHOR;
+opacity return OPACITY;
+shapeof return SHAPEOF;
+texture return TEXTURE;
+image return IMAGE;
+to return TO;
+box return BOX;
+NORTH return NORTH;
+NORTHEAST return NORTHEAST;
+EAST return EAST;
+SOUTHEAST return SOUTHEAST;
+SOUTH return SOUTH;
+SOUTHWEST return SOUTHWEST;
+WEST return WEST;
+NORTHWEST return NORTHWEST;
+NONE return NONE;
+UNCHANGED return UNCHANGED;
+
+0x[0-9A-Z]+ yylval->integer = strtol(yytext, (char **)NULL, 16); return NUMBER;
+[0-9]+ yylval->integer = atoi(yytext); return NUMBER;
+[a-zA-Z_][a-zA-Z0-9_]* yylval->string = g_strdup(yytext); return ID;
+\".*\" {
+ yylval->string = g_strdup(yytext+1);
+ yylval->string[strlen(yylval->string)-1] = 0;
+ return STRING;
+ }
+\`[^`]*\` {
+ yylval->string = g_strdup(yytext+1);
+ yylval->string[strlen(yylval->string)-1] = 0;
+ return STRING;
+ }
+
+\$[a-zA-Z_][a-zA-Z0-9_]* yylval->string = g_strdup(yytext+1); return ID;
+\$[0-9]* yylval->integer = strtol(yytext + 1, (char **)NULL, 16); return SUBST;
+\@ return AT;
+: return COLON;
+; return SEMICOLON;
+"+" return PLUS;
+"-" return MINUS;
+"}" return RCB;
+"{" return LCB;
+")" return RB;
+"(" return LB;
+"<-" return LEFT_ARROW;
+"->" return RIGHT_ARROW;
+"<->" return DOUBLE_ARROW;
+"." return DOT;
+"*" return STAR;
+"/" return SLASH;
+"," return COMMA;
+\n LINE++; /* zap EOL */
+[ \t]+ ; /* and whitespace */
+. return 0;
+%%
--- /dev/null
+%pure-parser
+%name-prefix "obtheme"
+%parse-param {struct parser_control *pc}
+%{
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <unistd.h>
+#include "frame.h"
+#include "misc.h"
+#include "render.h"
+#include "obtheme.h"
+#include "obtheme.tab.h"
+
+YY_DECL;
+
+struct context_table_item {
+ char *name;
+ ObFrameContext val;
+};
+
+/* some of these contexts don't make any sense for a theme... */
+static struct context_table_item contexts[OB_FRAME_NUM_CONTEXTS] = {
+ {"none", OB_FRAME_CONTEXT_NONE},
+ {"desktop", OB_FRAME_CONTEXT_DESKTOP},
+ {"root", OB_FRAME_CONTEXT_ROOT},
+ {"client", OB_FRAME_CONTEXT_CLIENT},
+ {"titlebar", OB_FRAME_CONTEXT_TITLEBAR},
+ {"frame", OB_FRAME_CONTEXT_FRAME},
+ {"blcorner", OB_FRAME_CONTEXT_BLCORNER},
+ {"brcorner", OB_FRAME_CONTEXT_BRCORNER},
+ {"tlcorner", OB_FRAME_CONTEXT_TLCORNER},
+ {"trcorner", OB_FRAME_CONTEXT_TRCORNER},
+ {"top", OB_FRAME_CONTEXT_TOP},
+ {"bottom", OB_FRAME_CONTEXT_BOTTOM},
+ {"left", OB_FRAME_CONTEXT_LEFT},
+ {"right", OB_FRAME_CONTEXT_RIGHT},
+ {"maximize", OB_FRAME_CONTEXT_MAXIMIZE},
+ {"alldesktops", OB_FRAME_CONTEXT_ALLDESKTOPS},
+ {"shade", OB_FRAME_CONTEXT_SHADE},
+ {"iconify", OB_FRAME_CONTEXT_ICONIFY},
+ {"icon", OB_FRAME_CONTEXT_ICON},
+ {"close", OB_FRAME_CONTEXT_CLOSE},
+ {"moveresize", OB_FRAME_CONTEXT_MOVE_RESIZE}
+};
+
+static ObFrameContext context_from_string(char *str)
+{
+ int i;
+ for (i = 0; i < OB_FRAME_NUM_CONTEXTS; i++)
+ if (strcmp(contexts[i].name, str) == 1)
+ return contexts[i].val;
+ return -1;
+}
+
+struct gradient_table_item {
+ char *name;
+ RrSurfaceColorType val;
+};
+
+struct gradient_table_item gradients[RR_SURFACE_NUM_TYPES] = {
+ {"none", RR_SURFACE_NONE},
+ {"parentrel", RR_SURFACE_PARENTREL},
+ {"solid", RR_SURFACE_SOLID},
+ {"split", RR_SURFACE_SPLIT_VERTICAL},
+ {"horizontal", RR_SURFACE_HORIZONTAL},
+ {"vertical", RR_SURFACE_VERTICAL},
+ {"diagonal", RR_SURFACE_DIAGONAL},
+ {"cross_diagonal", RR_SURFACE_CROSS_DIAGONAL},
+ {"pyramid", RR_SURFACE_PYRAMID},
+ {"mirror_horizontal", RR_SURFACE_MIRROR_HORIZONTAL},
+};
+
+static RrSurfaceColorType gradient_from_string(char *str)
+{
+ int i;
+
+ for (i = 0; i < RR_SURFACE_NUM_TYPES; i++)
+ if (strcmp(gradients[i].name, str) == 1)
+ return gradients[i].val;
+
+ return -1;
+}
+
+struct parser_control *parser_init(struct obthemedata *otd)
+{
+ struct parser_control *out;
+ out = calloc(1, sizeof(struct parser_control));
+ out->include_stack_ptr = 0;
+ out->target = otd;
+ return out;
+}
+
+void parser_finish(struct parser_control *c)
+{
+ free(c);
+}
+
+struct expression *exdup(struct expression in)
+{
+ struct expression *out;
+ out = malloc(sizeof(struct expression));
+ *out = in;
+ return out;
+}
+
+%}
+%start theme_objects
+
+%union {
+ int integer;
+ float realnum;
+ char *string;
+ struct decor decor;
+ struct space space;
+ struct theme theme;
+ struct material material;
+ struct style style;
+ GSList *list;
+ GHashTable *hash;
+ struct vector vector;
+ ObCursor dir;
+ ObFrameContext context;
+ RrSurfaceColorType gradient;
+ struct expression expr;
+ struct variable var;
+ struct texture tex;
+ struct material *matptr;
+ struct box box;
+ struct geometry geometry;
+}
+
+%token NORTH NORTHEAST EAST SOUTHEAST SOUTH SOUTHWEST
+%token WEST NORTHWEST NONE UNCHANGED
+%token LCB RCB LB RB TO
+%token LEFT_ARROW RIGHT_ARROW DOUBLE_ARROW
+%token SEMICOLON AT COLON DEFAULT NOT
+%token PLUS MINUS STAR SLASH COMMA BOX
+%token <string> STRING ID
+%token <integer> NUMBER SUBST BULK BIG LITTLE
+%token THEME FRAME SPACE GEOMETRY MATERIAL GRADIENT
+%token CONTEXT CURSOR UP ANCHOR STYLE TEXTURE OPACITY
+%token SHAPEOF DECOR DOT IMAGE
+%type <decor> decor
+%type <decor> decoritems styleitem
+%type <space> space
+%type <style> style styleitems
+%type <hash> styles
+%type <material> material_props
+%type <realnum> opacity
+%type <space> spaceconstraints
+%type <vector> up anchor
+%type <dir> cursor
+%type <context> context
+%type <gradient> gradient
+%type <expr> expression
+%type <var> variable
+%type <tex> texture image texitems
+%type <matptr> material_use
+%type <box> box
+%type <geometry> geometry geometry_item
+%left PLUS MINUS
+%left STAR SLASH
+%left LB
+%%
+
+theme_object : material_decl
+ | theme
+ ;
+
+theme_objects : /* empty */
+ | theme_objects theme_object
+ ;
+
+theme : THEME ID LCB styles RCB {
+ struct theme *out;
+ out = malloc(sizeof(struct theme));
+ out->name = $2;
+ out->styles = $4;
+ g_hash_table_insert(pc->target->themes, $2, out);
+ }
+ ;
+
+opacity : OPACITY LB NUMBER RB { $$ = $3; }
+ ;
+
+material_props : /* empty */ { memset(&$$, 0, sizeof($$)); }
+ | material_props opacity { $$ = $1; $$.opacity = $2;}
+ | material_props gradient
+ ;
+
+material_decl : MATERIAL ID LCB material_props RCB {
+ struct material *out;
+ out = malloc(sizeof(struct material));
+ *out = $4;
+ g_hash_table_insert(pc->target->materials, $2, out);
+ }
+ ;
+
+anchor : ANCHOR LB expression COMMA expression COMMA expression RB {
+ $$.x = $3;
+ $$.y = $5;
+ $$.z = $7;
+ }
+ ;
+
+up : UP LB expression COMMA expression COMMA expression RB {
+ $$.x = $3;
+ $$.y = $5;
+ $$.z = $7;
+ }
+ ;
+
+spaceconstraints: /* empty */ { memset(&$$, 0, sizeof($$));
+ $$.anchor.x.op = OB_THEME_EQL;
+ $$.anchor.x.v.number = 0;
+ $$.anchor.y.op = OB_THEME_EQL;
+ $$.anchor.y.v.number = 0;
+ $$.anchor.z.op = OB_THEME_EQL;
+ $$.anchor.z.v.number = 0;
+ $$.up.x.op = OB_THEME_EQL;
+ $$.up.x.v.number = 0;
+ $$.up.y.op = OB_THEME_EQL;
+ $$.up.y.v.number = 1;
+ $$.up.z.op = OB_THEME_EQL;
+ $$.up.z.v.number = 0;
+ }
+ | spaceconstraints anchor { $1.anchor = $2; $$ = $1; }
+ | spaceconstraints up { $1.up = $2; $$ = $1; }
+ ;
+
+space : SPACE LCB spaceconstraints RCB {
+ $$ = $3;
+ }
+ ;
+
+shape : SHAPEOF LB ID RB
+ ;
+
+box : BOX LB expression COMMA expression COMMA expression RB TO
+ LB expression COMMA expression COMMA expression RB {
+ $$.start.x = $3;
+ $$.start.y = $5;
+ $$.start.z = $7;
+ $$.end.x = $11;
+ $$.end.y = $13;
+ $$.end.z = $15;
+ }
+ ;
+
+geometry_item : /* empty */
+ | shape
+ | box { $$.box = $1; }
+ ;
+
+geometry : GEOMETRY LCB geometry_item RCB {
+ $$ = $3;
+ }
+ ;
+
+material_use : MATERIAL LB ID RB {
+ $$ = g_hash_table_lookup(pc->target->materials, $3);
+ if ($$ == NULL) {
+ snprintf(pc->error_buf, 4000, "No definition for material '%s'\n", $3);
+ obthemeerror(pc, pc->error_buf);
+ return 1;
+ }
+ }
+ ;
+
+styleitem : decor
+ ;
+
+styleitems : /* empty */ { $$.tree = NULL; $$.name = NULL; }
+ | styleitems styleitem {
+ struct decor *out = malloc(sizeof(struct decor));
+ *out = $2;
+ $1.tree = g_slist_prepend($1.tree, out);
+ $$ = $1;
+ }
+ ;
+
+styles : /* empty */ { $$ = g_hash_table_new(g_str_hash, g_str_equal); }
+ | styles style {
+ struct style *out = malloc(sizeof(struct style));
+ *out = $2;
+ $$ = $1;
+ g_hash_table_insert($1, out->name, out);
+ }
+ ;
+
+style : STYLE ID LCB styleitems RCB {
+ $$ = $4;
+ $$.name = $2;
+ }
+ ;
+
+decoritems : /* empty */ {
+ memset(&$$, 0, sizeof($$));
+// $$.space.up.y = -1; XXX need a sane default!
+ $$.cursor = OB_CURSOR_NONE;
+ $$.space.anchor.x.op = OB_THEME_EQL;
+ $$.space.anchor.x.v.number = 1;
+ $$.space.anchor.y.op = OB_THEME_EQL;
+ $$.space.anchor.y.v.number = 1;
+ $$.space.anchor.z.op = OB_THEME_EQL;
+ $$.space.anchor.z.v.number = 1;
+ $$.space.up.x.op = OB_THEME_EQL;
+ $$.space.up.x.v.number = 1;
+ $$.space.up.y.op = OB_THEME_EQL;
+ $$.space.up.y.v.number = 1;
+ $$.space.up.z.op = OB_THEME_EQL;
+ $$.space.up.z.v.number = 1;
+ $$.texture.present = 0;
+ $$.material = NULL;
+ }
+ | decoritems decor {
+ struct decor *out = malloc(sizeof(struct decor));
+ *out = $2;
+ $$ = $1;
+ $$.children = g_slist_append($1.children, out);
+ }
+ | decoritems space { $1.space = $2; $$ = $1; }
+ | decoritems material_use { $1.material = $2; $$ = $1; }
+ | decoritems geometry { $1.geometry = $2; $$ = $1;}
+ | decoritems texture { $1.texture = $2; $$ = $1; } //XXX multitexture?
+ | decoritems context { $1.context = $2; $$ = $1; }
+ | decoritems cursor { $1.cursor = $2; $$ = $1; }
+ ;
+
+ ;
+
+decor : DECOR ID LCB decoritems RCB {
+ $$ = $4;
+ $$.name = $2;
+ }
+ ;
+
+image : IMAGE LB STRING RB {
+ $$.present = 1;
+ $$.internal = 0;
+ $$.name = $3;
+ }
+ | IMAGE LB ID RB {
+ $$.present = 1;
+ $$.internal = 1;
+ $$.name = $3;
+ }
+ ;
+
+texitems : image { $$ = $1; }
+ ;
+
+texture : TEXTURE LCB texitems RCB { $$ = $3; }
+ ;
+
+context : CONTEXT LB ID RB {
+ ObFrameContext frc;
+ frc = context_from_string($3);
+ if (frc == -1) {
+ snprintf(pc->error_buf, 4000, "Illegal context '%s'\n", $3);
+ obthemeerror(pc, pc->error_buf);
+ return 1;
+ }
+ }
+ ;
+
+cursor : CURSOR LB NORTH RB { $$ = OB_CURSOR_NORTH; }
+ | CURSOR LB NORTHEAST RB { $$ = OB_CURSOR_NORTHEAST; }
+ | CURSOR LB EAST RB { $$ = OB_CURSOR_EAST; }
+ | CURSOR LB SOUTHEAST RB { $$ = OB_CURSOR_SOUTHEAST; }
+ | CURSOR LB SOUTH RB { $$ = OB_CURSOR_SOUTH; }
+ | CURSOR LB SOUTHWEST RB { $$ = OB_CURSOR_SOUTHWEST; }
+ | CURSOR LB WEST RB { $$ = OB_CURSOR_WEST; }
+ | CURSOR LB NORTHWEST RB { $$ = OB_CURSOR_NORTHWEST; }
+// | CURSOR LB NONE RB { $$ = OB_CURSOR_NORTHEAST; }
+ | CURSOR LB UNCHANGED RB { $$ = OB_CURSOR_NONE; }
+ ;
+gradient : GRADIENT LB ID RB {
+ $$ = gradient_from_string($3);
+ if ($$ == -1) {
+ snprintf(pc->error_buf, 4000, "No gradient named '%s'\n", $3);
+ obthemeerror(pc, pc->error_buf);
+ return 1;
+ }
+ }
+ ;
+
+variable : ID DOT ID { $$.base = $1; $$.member = $3; }
+ | ID { $$.base = $1; $$.member = NULL; }
+ | NUMBER { $$.base = NULL; $$.number = $1; }
+ ;
+
+expression : MINUS expression {
+ $$.op = OB_THEME_INV;
+ $$.a = exdup($2);
+ }
+ | expression STAR expression {
+ $$.op = OB_THEME_MUL;
+ $$.a = exdup($1);
+ $$.b = exdup($3);
+ }
+ | expression SLASH expression {
+ $$.op = OB_THEME_DIV;
+ $$.a = exdup($1);
+ $$.b = exdup($3);
+ }
+ | expression PLUS expression {
+ $$.op = OB_THEME_ADD;
+ $$.a = exdup($1);
+ $$.b = exdup($3);
+ }
+ | expression MINUS expression {
+ $$.op = OB_THEME_SUB;
+ $$.a = exdup($1);
+ $$.b = exdup($3);
+ }
+ | variable {
+ $$.op = OB_THEME_EQL;
+ $$.v = $1;
+ }
+ | LB expression RB { $$ = $2; }
+ ;
+
+%%
--- /dev/null
+//#include materials.obtheme
+
+//version(1)
+
+material flat {
+ opacity(1)
+}
+
+material grad {
+ opacity(1)
+ gradient(split)
+}
+
+material none {
+}
+
+theme awesome {
+ style regular_window {
+ decor clientwindow {
+ space {
+ anchor(0, 0, 0)
+ up(0, 1, 0)
+ }
+ geometry {
+// shapeof(client)
+ box (0, 0, 0) to (client.width, client.height, 0)
+ }
+ material(flat)
+ texture {
+ image(client)
+ }
+
+ decor titlebar {
+ context(titlebar)
+ space {
+ anchor(0, -font.height + 5, 0)
+ }
+ geometry {
+ box (0, 0, 0) to (client.width, font.height + 5, 0)
+ }
+ material(flat)
+
+ decor title {
+ geometry {
+ box (client.width / 4, font.height + 5, 0) to (3*client.width / 4, font.height + 5, 0)
+// text(client.title)
+// justify(center)
+ }
+ }
+ decor minbutton {
+ space {
+ anchor(client.width - 20, -10, 0)
+ }
+ geometry {
+ box (0, 0, 0) to (10, 10, 0)
+ }
+ material(none)
+ context(minimize)
+ }
+ decor maxbutton {
+ space {
+ anchor(client.width - 40, -10, 0)
+ }
+ geometry {
+ box (0, 0, 0) to (10, 10, 0)
+ }
+ material(none)
+ context(maximize)
+ }
+ }
+ decor handle {
+ geometry {
+ box (0, 0, 0) to (client.width, 10, 0)
+ }
+ space {
+ anchor(0, client.height, 0)
+ up(0, 1, 0)
+ }
+ decor leftgrip {
+ space {
+ anchor(0, client.height, 0)
+ up(0, 1, 0)
+ }
+ geometry {
+ box (0, 0, 0) to (30, 10, 0)
+ }
+ context(blcorner)
+ cursor(SOUTHWEST)
+ }
+ decor rightgrip {
+ space {
+ anchor(client.width - 30, client.height, 0)
+ up(0, 1, 0)
+ }
+ geometry {
+ box (0, 0, 0) to (30, 10, 0)
+ }
+ context(brcorner)
+ cursor(SOUTHEAST)
+ }
+ context(bottom)
+ cursor(SOUTH)
+ }
+ }
+ }
+}