From 7c613f6a4ca4354165e2cab987d0db1e7ce32c5a Mon Sep 17 00:00:00 2001 From: Dave Davenport Date: Fri, 20 Sep 2019 15:05:36 +0200 Subject: [PATCH] Issue893: Add support for @media in the theme format. (#1015) * [Lexer] Add support for @media. Issue: #893 * [Theme] @media limit to px. * [Theme@Media] add *{} support. * [Theme@Media] Add support for monitor-id media. * [Theme@Media] Code cleanup. * [Theme@Media] Add min/max-aspect-ratio. * [Theme@Media] Remove some debug output Fixes: #893 --- include/theme.h | 27 +++++++++ lexer/theme-lexer.l | 64 ++++++++++++++++++++-- lexer/theme-parser.y | 102 +++++++++++++++++++++++++++++++++- source/rofi.c | 3 + source/theme.c | 128 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 319 insertions(+), 5 deletions(-) diff --git a/include/theme.h b/include/theme.h index 0a7c5fc3..2196887e 100644 --- a/include/theme.h +++ b/include/theme.h @@ -32,6 +32,24 @@ #include #include "rofi-types.h" + +typedef enum { + THEME_MEDIA_TYPE_MIN_WIDTH, + THEME_MEDIA_TYPE_MAX_WIDTH, + THEME_MEDIA_TYPE_MIN_HEIGHT, + THEME_MEDIA_TYPE_MAX_HEIGHT, + THEME_MEDIA_TYPE_MON_ID, + THEME_MEDIA_TYPE_MIN_ASPECT_RATIO, + THEME_MEDIA_TYPE_MAX_ASPECT_RATIO, + THEME_MEDIA_TYPE_INVALID, +} ThemeMediaType; + + +typedef struct ThemeMedia { + ThemeMediaType type; + double value; +} ThemeMedia; + /** * ThemeWidget. */ @@ -43,6 +61,8 @@ typedef struct ThemeWidget unsigned int num_widgets; struct ThemeWidget **widgets; + ThemeMedia *media; + GHashTable *properties; struct ThemeWidget *parent; @@ -323,4 +343,11 @@ char *helper_get_theme_path ( const char *file ); * @returns full path to file. */ char * rofi_theme_parse_prepare_file ( const char *file, const char *parent_file ); + +/** + * Process conditionals. + */ +void rofi_theme_parse_process_conditionals ( void ); +void rofi_theme_parse_merge_widgets ( ThemeWidget *parent, ThemeWidget *child ); +ThemeMediaType rofi_theme_parse_media_type ( const char *type ); #endif diff --git a/lexer/theme-lexer.l b/lexer/theme-lexer.l index 4ebeff7f..50a2c4e7 100644 --- a/lexer/theme-lexer.l +++ b/lexer/theme-lexer.l @@ -239,6 +239,8 @@ C_COMMENT_OPEN "/*" INCLUDE "@import" THEME "@theme" +MEDIA "@media" + CONFIGURATION (?i:configuration) %x INCLUDE @@ -250,6 +252,8 @@ CONFIGURATION (?i:configuration) %x NAMESTR %x SECTION %x DEFAULTS +%x MEDIA +%x MEDIA_CONTENT %% %{ @@ -424,13 +428,13 @@ if ( queue == NULL ){ /* After Namestr/Classstr we want to go to state str, then to { */ {WHITESPACE}+ ; // ignore all whitespace -{WHITESPACE}+ ; // ignore all whitespace +{WHITESPACE}+ ; // ignore all whitespace
":" { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(PROPERTIES); return T_PSEP; } ";" { BEGIN(GPOINTER_TO_INT ( g_queue_pop_head ( queue ))); return T_PCLOSE;} (true|false) { yylval->bval= g_strcmp0(yytext, "true") == 0; return T_BOOLEAN;} -{PNNUMBER}\.{NUMBER}+ { yylval->fval = g_ascii_strtod(yytext, NULL); return T_DOUBLE;} -{PNNUMBER} { yylval->ival = (int)g_ascii_strtoll(yytext, NULL, 10); return T_INT;} +{PNNUMBER}\.{NUMBER}+ { yylval->fval = g_ascii_strtod(yytext, NULL); return T_DOUBLE;} +{PNNUMBER} { yylval->ival = (int)g_ascii_strtoll(yytext, NULL, 10); return T_INT;} {STRING} { yytext[yyleng-1] = '\0'; yylval->sval = g_strcompress(&yytext[1]); return T_STRING;} @{WORD} { @@ -440,7 +444,7 @@ if ( queue == NULL ){ {EM} { return T_UNIT_EM; } {CH} { return T_UNIT_CH; } -{PX} { return T_UNIT_PX; } +{PX} { return T_UNIT_PX; } {PERCENT} { return T_PERCENT; } {LS_SOLID} { return T_SOLID; } {LS_DASH} { return T_DASH; } @@ -619,6 +623,50 @@ if ( queue == NULL ){ yylloc->last_line ++; }; + +{MEDIA} { + g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); + BEGIN(MEDIA); + return T_MEDIA; +} + +{S_T_PARENT_LEFT} { + g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); + BEGIN(MEDIA_CONTENT); + return T_PARENT_LEFT; +} +{WORD} { + yylval->sval = g_strdup(yytext); + return T_STRING; +} +":" { + return T_PSEP; +} +{S_T_PARENT_RIGHT} { + int id = GPOINTER_TO_INT(g_queue_pop_head ( queue )); + BEGIN(id); + return T_PARENT_RIGHT; +} +"\{" { + g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); + BEGIN(INITIAL); + return T_BOPEN; +} + +"\}" { + g_queue_pop_head ( queue ); + BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue ))); + return T_BCLOSE; +} +{WHITESPACE}+ ; // ignore all whitespace + + +. { + yytext[yyleng-1] = '\0'; + fprintf(stderr,"found: |%s|\n", yytext); + return T_ERROR; +} + /** * If we just encounter a word, we assume it is a Widget name. * This makes include,theme, configuration a reserved keyword. @@ -630,9 +678,13 @@ if ( queue == NULL ){ return T_NAME_ELEMENT; } . { + yytext[yyleng-1] = '\0'; + fprintf(stderr,"initial found: |%s|\n", yytext); return T_ERROR; }
. { + yytext[yyleng-1] = '\0'; + fprintf(stderr,"section found: |%s|\n", yytext); return T_ERROR_SECTION; } {WORD} { @@ -646,9 +698,13 @@ if ( queue == NULL ){ } . { + yytext[yyleng-1] = '\0'; + fprintf(stderr,"prop found: |%s|\n", yytext); return T_ERROR_PROPERTY; } . { + yytext[yyleng-1] = '\0'; + fprintf(stderr,"namestr found: |%s|\n", yytext); return T_ERROR_NAMESTRING; } %% diff --git a/lexer/theme-parser.y b/lexer/theme-parser.y index 23b0a5dc..c85a5bbe 100644 --- a/lexer/theme-parser.y +++ b/lexer/theme-parser.y @@ -172,6 +172,8 @@ static ThemeColor hwb_to_rgb ( double h, double w, double b) %token T_POS_NORTH "North" %token T_POS_SOUTH "South" +%token T_MEDIA "@media" + %token T_NONE "None" %token T_BOLD "Bold" %token T_ITALIC "Italic" @@ -223,8 +225,17 @@ static ThemeColor hwb_to_rgb ( double h, double w, double b) %token T_INHERIT "Inherit" +%token T_MEDIA_WIDTH "Width" +%token T_MEDIA_HEIGHT "Height" + +%token T_MEDIA_MIN "Min" +%token T_MEDIA_MONITOR_ID "Monitor-ID" +%token T_MEDIA_MAX "Max" +%token T_MEDIA_SEP "-" + %type t_entry %type t_entry_list +%type t_media_entry_list %type t_entry_name_path %type t_entry_name_path_selectors %type t_property @@ -280,6 +291,56 @@ t_entry_list: } ; +t_media_entry_list: +t_name_prefix_optional t_entry_name_path_selectors T_BOPEN t_property_list_optional T_BCLOSE { + ThemeWidget *widget = $$ = g_slice_new0 ( ThemeWidget ); + for ( GList *liter = g_list_first ( $2); liter; liter = g_list_next ( liter ) ) { + for ( GList *iter = g_list_first ( (GList*)liter->data ); widget && iter ; iter = g_list_next ( iter ) ) { + widget = rofi_theme_find_or_create_name ( widget, iter->data ); + } + g_list_free_full ( (GList*)liter->data, g_free ); + widget->set = TRUE; + rofi_theme_widget_add_properties ( widget, $4); + } + if ( $4 ) { + g_hash_table_destroy ( $4 ); + } + g_list_free ( $2 ); +} +| T_PDEFAULTS T_BOPEN t_property_list_optional T_BCLOSE { + ThemeWidget *widget = $$ = g_slice_new0( ThemeWidget ) ; + widget = rofi_theme_find_or_create_name ( widget, "*" ); + widget->set = TRUE; + rofi_theme_widget_add_properties ( widget, $3); + if ( $3 ) { + g_hash_table_destroy ( $3 ); + } +} +| t_media_entry_list T_PDEFAULTS T_BOPEN t_property_list_optional T_BCLOSE { + ThemeWidget *widget = $$ = $1 ; + widget = rofi_theme_find_or_create_name ( widget, "*" ); + widget->set = TRUE; + rofi_theme_widget_add_properties ( widget, $4); + if ( $4 ) { + g_hash_table_destroy ( $4 ); + } +} +| t_media_entry_list t_name_prefix_optional t_entry_name_path_selectors T_BOPEN t_property_list_optional T_BCLOSE { + ThemeWidget *widget = $$ = $1 ; + for ( GList *liter = g_list_first ( $3); liter; liter = g_list_next ( liter ) ) { + for ( GList *iter = g_list_first ( (GList*)liter->data ); widget && iter ; iter = g_list_next ( iter ) ) { + widget = rofi_theme_find_or_create_name ( widget, iter->data ); + } + g_list_free_full ( (GList*)liter->data, g_free ); + widget->set = TRUE; + rofi_theme_widget_add_properties ( widget, $5); + } + if ( $5 ) { + g_hash_table_destroy ( $5 ); + } + g_list_free ( $3 ); +}; + /** * Small dummy object to make the prefix optional. */ @@ -293,7 +354,7 @@ t_name_prefix_optional t_entry_name_path_selectors T_BOPEN t_property_list_optio { for ( GList *liter = g_list_first ( $2); liter; liter = g_list_next ( liter ) ) { ThemeWidget *widget = rofi_theme; - for ( GList *iter = g_list_first ( (GList*)liter->data ); iter ; iter = g_list_next ( iter ) ) { + for ( GList *iter = g_list_first ( (GList*)liter->data ); widget && iter ; iter = g_list_next ( iter ) ) { widget = rofi_theme_find_or_create_name ( widget, iter->data ); } g_list_free_full ( (GList*)liter->data, g_free ); @@ -312,6 +373,45 @@ t_name_prefix_optional t_entry_name_path_selectors T_BOPEN t_property_list_optio g_hash_table_destroy ( $3 ); } } +| T_MEDIA T_PARENT_LEFT T_STRING T_PSEP T_INT T_PARENT_RIGHT T_BOPEN t_media_entry_list T_BCLOSE { + gchar *name = g_strdup_printf("@media ( %s: %d )",$3, $5); + ThemeWidget *widget = rofi_theme_find_or_create_name ( rofi_theme, name ); + widget->set = TRUE; + widget->media = g_malloc0(sizeof(ThemeMedia)); + widget->media->type = rofi_theme_parse_media_type ( $3 ); + widget->media->value = (double)$5; + for ( unsigned int i = 0; i < $8->num_widgets;i++) { + ThemeWidget *d = $8->widgets[i]; + rofi_theme_parse_merge_widgets(widget, d); + } + g_free ( name ); +} +| T_MEDIA T_PARENT_LEFT T_STRING T_PSEP T_DOUBLE T_PARENT_RIGHT T_BOPEN t_media_entry_list T_BCLOSE { + gchar *name = g_strdup_printf("@media ( %s: %f )",$3, $5); + ThemeWidget *widget = rofi_theme_find_or_create_name ( rofi_theme, name ); + widget->set = TRUE; + widget->media = g_malloc0(sizeof(ThemeMedia)); + widget->media->type = rofi_theme_parse_media_type ( $3 ); + widget->media->value = $5; + for ( unsigned int i = 0; i < $8->num_widgets;i++) { + ThemeWidget *d = $8->widgets[i]; + rofi_theme_parse_merge_widgets(widget, d); + } + g_free ( name ); +} +| T_MEDIA T_PARENT_LEFT T_STRING T_PSEP T_INT T_UNIT_PX T_PARENT_RIGHT T_BOPEN t_media_entry_list T_BCLOSE { + gchar *name = g_strdup_printf("@media ( %s: %d px )",$3, $5); + ThemeWidget *widget = rofi_theme_find_or_create_name ( rofi_theme, name ); + widget->set = TRUE; + widget->media = g_malloc0(sizeof(ThemeMedia)); + widget->media->type = rofi_theme_parse_media_type ( $3 ); + widget->media->value = (double)$5; + for ( unsigned int i = 0; i < $9->num_widgets;i++) { + ThemeWidget *d = $9->widgets[i]; + rofi_theme_parse_merge_widgets(widget, d); + } + g_free ( name ); +} ; t_config_property_list_optional diff --git a/source/rofi.c b/source/rofi.c index 650e788d..1bc09ebc 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -999,6 +999,9 @@ int main ( int argc, char *argv[] ) } TICK_N ( "Setup late Display" ); + rofi_theme_parse_process_conditionals (); + TICK_N ( "Theme setup" ); + // Setup signal handling sources. // SIGINT g_unix_signal_add ( SIGINT, main_loop_signal_handler_int, NULL ); diff --git a/source/theme.c b/source/theme.c index da3b726b..f0a71c32 100644 --- a/source/theme.c +++ b/source/theme.c @@ -1021,3 +1021,131 @@ char * rofi_theme_parse_prepare_file ( const char *file, const char *parent_file return filename; } + + +void rofi_theme_parse_merge_widgets ( ThemeWidget *parent, ThemeWidget *child ) +{ + g_assert ( parent != NULL ); + g_assert ( child != NULL ); + + if ( parent == rofi_theme && g_strcmp0(child->name, "*") == 0 ){ + rofi_theme_widget_add_properties ( parent, child->properties); + return; + } + + ThemeWidget *w = rofi_theme_find_or_create_name ( parent, child->name); + rofi_theme_widget_add_properties ( w, child->properties); + for ( unsigned int i =0; i < child->num_widgets; i++) { + rofi_theme_parse_merge_widgets ( w, child->widgets[i]); + } +} + +void rofi_theme_parse_process_conditionals ( void ) +{ + workarea mon; + monitor_active ( &mon ); + if ( rofi_theme == NULL ) return; + for ( unsigned int i = 0; i < rofi_theme->num_widgets; i++ ) { + ThemeWidget *widget = rofi_theme->widgets[i]; + if ( widget->media != NULL ) { + switch ( widget->media->type ) + { + case THEME_MEDIA_TYPE_MIN_WIDTH: + { + int w = widget->media->value; + if ( mon.w >= w ){ + for ( unsigned int x =0; x < widget->num_widgets; x++) { + rofi_theme_parse_merge_widgets ( rofi_theme, widget->widgets[x] ); + } + } + break; + } + case THEME_MEDIA_TYPE_MAX_WIDTH: + { + int w = widget->media->value; + if ( mon.w < w ){ + for ( unsigned int x =0; x < widget->num_widgets; x++) { + rofi_theme_parse_merge_widgets ( rofi_theme, widget->widgets[x] ); + } + } + break; + } + case THEME_MEDIA_TYPE_MIN_HEIGHT: + { + int h = widget->media->value; + if ( mon.h >= h ){ + for ( unsigned int x =0; x < widget->num_widgets; x++) { + rofi_theme_parse_merge_widgets ( rofi_theme, widget->widgets[x] ); + } + } + break; + } + case THEME_MEDIA_TYPE_MAX_HEIGHT: + { + int h = widget->media->value; + if ( mon.h < h ){ + for ( unsigned int x =0; x < widget->num_widgets; x++) { + rofi_theme_parse_merge_widgets ( rofi_theme, widget->widgets[x] ); + } + } + break; + } + case THEME_MEDIA_TYPE_MON_ID: + { + if ( mon.monitor_id == widget->media->value ){ + for ( unsigned int x =0; x < widget->num_widgets; x++) { + rofi_theme_parse_merge_widgets ( rofi_theme, widget->widgets[x] ); + } + } + break; + } + case THEME_MEDIA_TYPE_MIN_ASPECT_RATIO: + { + double r = widget->media->value; + if ( (mon.w/(double)mon.h) >= r ){ + for ( unsigned int x =0; x < widget->num_widgets; x++) { + rofi_theme_parse_merge_widgets ( rofi_theme, widget->widgets[x] ); + } + } + break; + } + case THEME_MEDIA_TYPE_MAX_ASPECT_RATIO: + { + double r = widget->media->value; + if ( (mon.w/(double)mon.h) < r ){ + for ( unsigned int x =0; x < widget->num_widgets; x++) { + rofi_theme_parse_merge_widgets ( rofi_theme, widget->widgets[x] ); + } + } + break; + } + default: + { + break; + } + } + } + } +} + + +ThemeMediaType rofi_theme_parse_media_type ( const char *type ) +{ + if ( g_strcmp0( type, "monitor-id" ) == 0 ) { + return THEME_MEDIA_TYPE_MON_ID; + } else if ( g_strcmp0 ( type, "min-width") == 0 ) { + return THEME_MEDIA_TYPE_MIN_WIDTH; + } else if ( g_strcmp0 ( type, "min-height") == 0 ) { + return THEME_MEDIA_TYPE_MIN_HEIGHT; + } else if ( g_strcmp0 ( type, "max-width") == 0 ) { + return THEME_MEDIA_TYPE_MAX_WIDTH; + } else if ( g_strcmp0 ( type, "max-height") == 0 ) { + return THEME_MEDIA_TYPE_MAX_HEIGHT; + } else if ( g_strcmp0 ( type, "min-aspect-ratio") == 0 ) { + return THEME_MEDIA_TYPE_MIN_ASPECT_RATIO; + } else if ( g_strcmp0 ( type, "max-aspect-ratio") == 0 ) { + return THEME_MEDIA_TYPE_MAX_ASPECT_RATIO; + } + return THEME_MEDIA_TYPE_INVALID; +} +