From be0677cf498aa885a6203fcd0c21c315ad1face3 Mon Sep 17 00:00:00 2001 From: Dave Davenport Date: Mon, 12 Dec 2016 21:14:57 +0100 Subject: [PATCH] Update theme to new format. - @class state { } - #name state { } --- include/theme.h | 2 +- include/widgets/textbox.h | 2 +- lexer/theme-lexer.l | 27 ++++++++----- lexer/theme-parser.y | 43 ++++++++++++++++---- script/rofi-convert-theme.sh | 76 ++++++++++++++++++++++++++++++++++++ source/theme.c | 7 +++- source/view.c | 6 +-- source/widgets/scrollbar.c | 4 +- source/widgets/separator.c | 2 +- source/widgets/textbox.c | 26 ++++++------ 10 files changed, 154 insertions(+), 41 deletions(-) create mode 100755 script/rofi-convert-theme.sh diff --git a/include/theme.h b/include/theme.h index 17853177..ba0581ab 100644 --- a/include/theme.h +++ b/include/theme.h @@ -66,5 +66,5 @@ int rofi_theme_get_integer ( const char *name, const char *property, int def ); int rofi_theme_get_boolean ( const char *name, const char *property, int def ); char *rofi_theme_get_string ( const char *name, const char *property, char *def ); double rofi_theme_get_double ( const char *name, const char *property, double def ); -void rofi_theme_get_color ( const char *name, const char *property, cairo_t *d); +void rofi_theme_get_color ( const char *wclass, const char *name, const char *state, const char *property, cairo_t *d); #endif diff --git a/include/widgets/textbox.h b/include/widgets/textbox.h index 446a39a6..d86dde0a 100644 --- a/include/widgets/textbox.h +++ b/include/widgets/textbox.h @@ -40,7 +40,7 @@ typedef struct int blink; guint blink_timeout; // - char *theme_name ; + const char *theme_name ; } textbox; /** diff --git a/lexer/theme-lexer.l b/lexer/theme-lexer.l index 7f82e759..a540c229 100644 --- a/lexer/theme-lexer.l +++ b/lexer/theme-lexer.l @@ -17,7 +17,11 @@ yylloc->first_line = yylloc->last_line; yylloc->first_column = yylloc->last_column;\ } %} - +WHITESPACE [ \t] +WORD [_\-a-zA-Z0-9]+ +STRING [ \t_\-a-zA-Z0-9]+ +HEX [0-9a-fA-F] +NUMBER [0-9] %% %{ @@ -58,19 +62,22 @@ YY_LLOC_START } YY_LLOC_START } + "\{" { return BOPEN;} "\}" { return BCLOSE;} ":" { return PSEP; } ";" { return PCLOSE;} "." { return NSEP; } -[ \t] ; // ignore all whitespace -[0-9]+\.[0-9]+ { yylval->fval = g_ascii_strtod(yytext, NULL); return T_DOUBLE;} -[0-9]+ { yylval->ival = (int)g_ascii_strtoll(yytext, NULL, 10); return T_INT;} +"#" { return NAME_PREFIX;} (true|false) { yylval->bval= g_strcmp0(yytext, "true") == 0; return T_BOOLEAN;} -[_\-a-zA-Z0-9]+ { yylval->sval = g_strdup(yytext); return N_STRING;} -\"[_\-a-zA-Z0-9 \t]+\" { yytext[yyleng-1] = '\0'; yylval->sval = g_strdup(&yytext[1]); return T_STRING;} +{NUMBER}+ { yylval->ival = (int)g_ascii_strtoll(yytext, NULL, 10); return T_INT;} +{NUMBER}+\.{NUMBER}+ { yylval->fval = g_ascii_strtod(yytext, NULL); return T_DOUBLE;} +@{WORD} { yylval->sval = g_strdup(yytext); return CLASS_NAME; } +{WORD} { yylval->sval = g_strdup(yytext); return N_STRING;} +{WHITESPACE} ; // ignore all whitespace +\"{STRING}\" { yytext[yyleng-1] = '\0'; yylval->sval = g_strdup(&yytext[1]); return T_STRING;} -#[0-9A-Fa-f]{8} { +#{HEX}{8} { union { unsigned int val; struct { unsigned char b,g,r,a;};} val; val.val = (unsigned int)strtoull ( &yytext[1], NULL, 16); yylval->colorval.alpha = val.a/255.0; @@ -79,7 +86,7 @@ YY_LLOC_START yylval->colorval.blue = val.b/255.0; return T_COLOR; } -#[0-9A-Fa-f]{6} { +#{HEX}{6} { union { unsigned int val; struct { unsigned char b,g,r,a;};} val; val.val = (unsigned int)g_ascii_strtoull ( &yytext[1], NULL, 16); yylval->colorval.alpha = 1.0; @@ -88,7 +95,7 @@ YY_LLOC_START yylval->colorval.blue = val.b/255.0; return T_COLOR; } -rgba\([0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[01](\.[0-9]+)?\) { +rgba\({NUMBER}{1,3},{NUMBER}{1,3},{NUMBER}{1,3},[01](\.{NUMBER}+)?\) { char *endptr = &yytext[5]; yylval->colorval.red = g_ascii_strtoull ( endptr, &endptr, 10); yylval->colorval.green= g_ascii_strtoull ( endptr+1, &endptr, 10); @@ -96,7 +103,7 @@ rgba\([0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[01](\.[0-9]+)?\) { yylval->colorval.alpha= g_ascii_strtod ( endptr+1, NULL); return T_COLOR; } -rgb\([0-9]{1,3},[0-9]{1,3},[0-9]{1,3}\) { +rgb\({NUMBER}{1,3},{NUMBER}{1,3},{NUMBER}{1,3}\) { char *endptr = &yytext[4]; yylval->colorval.red = g_ascii_strtoull ( endptr, &endptr, 10); yylval->colorval.green = g_ascii_strtoull ( endptr+1, &endptr, 10); diff --git a/lexer/theme-parser.y b/lexer/theme-parser.y index 2ad71627..aa82cdcf 100644 --- a/lexer/theme-parser.y +++ b/lexer/theme-parser.y @@ -38,18 +38,22 @@ int yylex (YYSTYPE *, YYLTYPE *); %token N_STRING %token T_BOOLEAN %token T_COLOR +%token CLASS_NAME %token BOPEN "bracket open"; %token BCLOSE "bracket close"; %token PSEP "property separator"; %token PCLOSE "property close"; %token NSEP "Name separator"; +%token CLASS_PREFIX "Class prefix"; +%token NAME_PREFIX "Name prefix"; %type entry %type pvalue %type entries %type start %type name_path +%type state_path %type property %type property_list %type optional_properties @@ -76,20 +80,38 @@ entries: ; entry: - name_path BOPEN optional_properties BCLOSE +CLASS_NAME state_path BOPEN optional_properties BCLOSE { - Widget *widget = rofi_theme;//rofi_theme_find_or_create_class ( rofi_theme , $1 ); - for ( GList *iter = g_list_first ( $1 ); iter ; iter = g_list_next ( iter ) ) { + Widget *widget = rofi_theme_find_or_create_class ( rofi_theme , $1 ); + for ( GList *iter = g_list_first ( $2 ); iter ; iter = g_list_next ( iter ) ) { widget = rofi_theme_find_or_create_class ( widget, iter->data ); } - g_list_foreach ( $1, (GFunc)g_free , NULL ); - g_list_free ( $1 ); + g_list_foreach ( $2, (GFunc)g_free , NULL ); + g_list_free ( $2 ); if ( widget->properties != NULL ) { fprintf(stderr, "Properties already set on this widget.\n"); exit ( EXIT_FAILURE ); } - widget->properties = $3; - + widget->properties = $4; +} +| NAME_PREFIX name_path state_path BOPEN optional_properties BCLOSE +{ + Widget *widget = rofi_theme; + for ( GList *iter = g_list_first ( $2 ); iter ; iter = g_list_next ( iter ) ) { + widget = rofi_theme_find_or_create_class ( widget, iter->data ); + } + g_list_foreach ( $2, (GFunc)g_free , NULL ); + g_list_free ( $2 ); + for ( GList *iter = g_list_first ( $3 ); iter ; iter = g_list_next ( iter ) ) { + widget = rofi_theme_find_or_create_class ( widget, iter->data ); + } + g_list_foreach ( $3, (GFunc)g_free , NULL ); + g_list_free ( $3 ); + if ( widget->properties != NULL ) { + fprintf(stderr, "Properties already set on this widget.\n"); + exit ( EXIT_FAILURE ); + } + widget->properties = $5; }; /** @@ -141,13 +163,18 @@ property pvalue: N_STRING { $$ = $1; } - name_path: %empty { $$ = NULL; } | N_STRING { $$ = g_list_append ( NULL, $1 );} | name_path NSEP N_STRING { $$ = g_list_append ( $1, $3);} ; +state_path: + %empty { $$ = NULL; } +| N_STRING { $$ = g_list_append ( NULL, $1 );} +| state_path NSEP N_STRING { $$ = g_list_append ( $1, $3);} +; + %% diff --git a/script/rofi-convert-theme.sh b/script/rofi-convert-theme.sh new file mode 100755 index 00000000..7ec801d0 --- /dev/null +++ b/script/rofi-convert-theme.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +# +# This code is released in public domain by Dave Davenport +# This converts from old style theme (< 1.4) to new style theme (>= 1.4) +# +function update_color () +{ + var=${1} + var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters + var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters + if [[ ${var} =~ argb:[0-9a-fA-F]{6,8} ]] + then + echo "#${var:5}" + else + echo ${var} + fi +} + +function parse_window_color () +{ + OLDIFS=${IFS} + IFS="," + entries=( ${1} ) + echo "@window {" + echo " background: $( update_color ${entries[0]});" + echo " foreground: $( update_color ${entries[1]});" + echo "}" + if [ -n "${entries[2]}" ] + then + echo "@separator {" + echo " foreground: $( update_color ${entries[2]});" + echo "}" + echo "@scrollbar {" + echo " foreground: $( update_color ${entries[2]});" + echo "}" + fi + IFS=${OLDIFS} +} + +function parse_color () +{ + state=$1 + OLDIFS=${IFS} + IFS="," + entries=( ${2} ) + echo "@textbox normal.${state} { " + echo " background: $( update_color ${entries[0]});" + echo " foreground: $( update_color ${entries[1]});" + echo "}" + echo "@textbox selected.${state} { " + echo " background: $( update_color ${entries[3]});" + echo " foreground: $( update_color ${entries[4]});" + echo "}" + echo "@textbox alternate.${state} { " + echo " background: $( update_color ${entries[2]});" + echo " foreground: $( update_color ${entries[1]});" + echo "}" + IFS=${OLDIFS} +} + +while read LINE +do + if [[ ${LINE} =~ ^rofi\.color-normal: ]] + then + parse_color "normal" "${LINE:18}" + elif [[ ${LINE} =~ ^rofi\.color-urgent: ]] + then + parse_color "urgent" "${LINE:18}" + elif [[ ${LINE} =~ ^rofi\.color-active: ]] + then + parse_color "active" "${LINE:18}" + elif [[ ${LINE} =~ ^rofi\.color-window: ]] + then + parse_window_color "${LINE:18}" + fi +done diff --git a/source/theme.c b/source/theme.c index b098120e..5f99d4b0 100644 --- a/source/theme.c +++ b/source/theme.c @@ -221,12 +221,17 @@ double rofi_theme_get_double ( const char *name, const char *property, double d } return def; } -void rofi_theme_get_color ( const char *name, const char *property, cairo_t *d) +void rofi_theme_get_color ( const char *wclass, const char *name, const char *state, const char *property, cairo_t *d) { if ( rofi_theme == NULL ) { return ; } Widget *widget = rofi_theme_find ( rofi_theme, name ); + if ( widget == rofi_theme ){ + // Fall back to class + widget = rofi_theme_find ( widget, wclass); + } + widget = rofi_theme_find ( widget, state ); Property *p = rofi_theme_find_property ( widget, P_COLOR, property ); if ( p ){ cairo_set_source_rgba ( d, diff --git a/source/view.c b/source/view.c index 9569dc8f..416e4e24 100644 --- a/source/view.c +++ b/source/view.c @@ -781,18 +781,18 @@ void rofi_view_update ( RofiViewState *state ) cairo_paint ( d ); cairo_set_operator ( d, CAIRO_OPERATOR_OVER ); color_background ( d ); - rofi_theme_get_color ( "window" , "background", d ); + rofi_theme_get_color ( "@window" , "window" , NULL, "background", d ); cairo_paint ( d ); } else { // Paint the background. color_background ( d ); - rofi_theme_get_color ( "window" , "background", d ); + rofi_theme_get_color ( "@window", "window" , NULL, "background", d ); cairo_paint ( d ); } TICK_N ( "Background" ); color_border ( d ); - rofi_theme_get_color ( "window" , "foreground", d ); + rofi_theme_get_color ( "@window", "window" , NULL, "foreground", d ); int bw = rofi_theme_get_integer ( "window", "border-width" , config.menu_bw); if ( bw > 0 ) { diff --git a/source/widgets/scrollbar.c b/source/widgets/scrollbar.c index 4caf77c1..5df9d14a 100644 --- a/source/widgets/scrollbar.c +++ b/source/widgets/scrollbar.c @@ -29,6 +29,8 @@ #include "x11-helper.h" #include "settings.h" +#include "theme.h" + static void scrollbar_draw ( widget *, cairo_t * ); static void scrollbar_free ( widget * ); static gboolean scrollbar_motion_notify ( widget *wid, xcb_motion_notify_event_t *xme ); @@ -109,7 +111,7 @@ static void scrollbar_draw ( widget *wid, cairo_t *draw ) height = MAX ( 2, height ); // Cap length; color_separator ( draw ); - rofi_theme_get_color ( sb->widget.name, "foreground", draw ); + rofi_theme_get_color ( "@scrollbar", sb->widget.name, NULL, "foreground", draw ); cairo_rectangle ( draw, sb->widget.x, sb->widget.y + y, sb->widget.w, height ); cairo_fill ( draw ); diff --git a/source/widgets/separator.c b/source/widgets/separator.c index 0ff69554..46a65c1a 100644 --- a/source/widgets/separator.c +++ b/source/widgets/separator.c @@ -129,7 +129,7 @@ static void separator_draw ( widget *wid, cairo_t *draw ) return; } color_separator ( draw ); - rofi_theme_get_color ( wid->name, "foreground", draw ); + rofi_theme_get_color ( "@separator", wid->name, NULL, "foreground", draw ); if ( sep->line_style == S_LINE_DASH ) { const double dashes[1] = { 4 }; cairo_set_dash ( draw, dashes, 1, 0.0 ); diff --git a/source/widgets/textbox.c b/source/widgets/textbox.c index ad66999f..7e78f579 100644 --- a/source/widgets/textbox.c +++ b/source/widgets/textbox.c @@ -143,45 +143,42 @@ textbox* textbox_create ( const char *name, TextboxFlags flags, short x, short y return tb; } +const char const *const theme_prop_names[][3] = { + {"normal.normal", "selected.normal", "alternate.normal"}, + {"urgent.normal", "selected.urgent", "alternate.urgent"}, + {"active.normal", "selected.active", "alternate.active"}, +}; + void textbox_font ( textbox *tb, TextBoxFontType tbft ) { TextBoxFontType t = tbft & STATE_MASK; if ( tb == NULL ) { return; } - char *state = "normal"; - // ACTIVE has priority over URGENT if both set. if ( t == ( URGENT | ACTIVE ) ) { t = ACTIVE; } - if ( t == URGENT ) { - state = "urgent"; - } else if ( t == ACTIVE ){ - state = "active"; - } - char *mode = "normal"; RowColor *color = &( colors[t] ); switch ( ( tbft & FMOD_MASK ) ) { case HIGHLIGHT: tb->color_bg = color->hlbg; tb->color_fg = color->hlfg; - mode = "selected"; + tb->theme_name = theme_prop_names[t][1]; break; case ALT: tb->color_bg = color->bgalt; tb->color_fg = color->fg; - mode = "alternate"; + tb->theme_name = theme_prop_names[t][2]; break; default: tb->color_bg = color->bg; tb->color_fg = color->fg; + tb->theme_name = theme_prop_names[t][0]; break; } if ( tb->tbft != tbft || tb->theme_name == NULL ) { - g_free ( tb->theme_name); - tb->theme_name = g_strjoin ("." , tb->widget.name, mode, state, NULL ); tb->update = TRUE; widget_queue_redraw ( WIDGET ( tb ) ); } @@ -301,7 +298,6 @@ static void textbox_free ( widget *wid ) g_source_remove ( tb->blink_timeout ); tb->blink_timeout = 0; } - g_free(tb->theme_name ); g_free ( tb->text ); if ( tb->layout != NULL ) { @@ -374,12 +370,12 @@ static void texbox_update ( textbox *tb ) // Set ARGB Color col = tb->color_bg; cairo_set_source_rgba ( tb->main_draw, col.red, col.green, col.blue, col.alpha ); - rofi_theme_get_color ( tb->theme_name, "background", tb->main_draw); + rofi_theme_get_color ( "@textbox", tb->widget.name, tb->theme_name, "background", tb->main_draw); cairo_paint ( tb->main_draw ); col = tb->color_fg; cairo_set_source_rgba ( tb->main_draw, col.red, col.green, col.blue, col.alpha ); - rofi_theme_get_color ( tb->theme_name, "foreground", tb->main_draw); + rofi_theme_get_color ( "@textbox",tb->widget.name, tb->theme_name, "foreground", tb->main_draw); // draw the cursor if ( tb->flags & TB_EDITABLE && tb->blink ) { cairo_rectangle ( tb->main_draw, x + cursor_x, y, cursor_width, font_height );