From ddc9326ef242828230a8745009b99ac6a054a6bd Mon Sep 17 00:00:00 2001 From: Dave Davenport Date: Tue, 15 Jun 2021 17:18:34 +0200 Subject: [PATCH] [Widget] Add scaling option to background-image. --- doc/rofi-theme.5 | 13 +++++++++- doc/rofi-theme.5.markdown | 9 ++++++- include/rofi-icon-fetcher.h | 1 + include/rofi-types.h | 11 ++++++++ lexer/theme-lexer.l | 8 ++++++ lexer/theme-parser.y | 16 ++++++++++++ source/rofi-icon-fetcher.c | 50 +++++++++++++++++++++++++++++++------ source/theme.c | 23 +++++++++++++++-- 8 files changed, 120 insertions(+), 11 deletions(-) diff --git a/doc/rofi-theme.5 b/doc/rofi-theme.5 index c089fdfe..646328fb 100644 --- a/doc/rofi-theme.5 +++ b/doc/rofi-theme.5 @@ -366,6 +366,8 @@ dynamic: false; .IP \(bu 2 Format: url("path to image"); .IP \(bu 2 +Format: url("path to image", scale); +.IP \(bu 2 Format: linear\-gradient(stop color,stop1, color, stop2 color, ...); .IP \(bu 2 Format: linear\-gradient(to direction, stop color,stop1, color, stop2 color, ...); @@ -375,7 +377,16 @@ Format: linear\-gradient(angle, stop color,stop1, color, stop2 color, ...); Angle in deg,rad,grad (as used in color). .PP -Where the path is a string, and stop color is of type color. +Where the \fB\fCpath\fR is a string, and \fB\fCstop\fR color is of type color. +The \fB\fCscale\fR property can be: +.IP \(bu 2 +none +.IP \(bu 2 +both +.IP \(bu 2 +width +.IP \(bu 2 +height .SH Color .PP diff --git a/doc/rofi-theme.5.markdown b/doc/rofi-theme.5.markdown index 336f4cc5..19cb5134 100644 --- a/doc/rofi-theme.5.markdown +++ b/doc/rofi-theme.5.markdown @@ -255,13 +255,20 @@ dynamic: false; **rofi** support a very limited set of image formats. * Format: url("path to image"); +* Format: url("path to image", scale); * Format: linear-gradient(stop color,stop1, color, stop2 color, ...); * Format: linear-gradient(to direction, stop color,stop1, color, stop2 color, ...); where direction is: top,left,right,bottom. * Format: linear-gradient(angle, stop color,stop1, color, stop2 color, ...); Angle in deg,rad,grad (as used in color). -Where the path is a string, and stop color is of type color. +Where the `path` is a string, and `stop` color is of type color. +The `scale` property can be: + +* none +* both +* width +* height ## Color diff --git a/include/rofi-icon-fetcher.h b/include/rofi-icon-fetcher.h index fed9c588..958f0a67 100644 --- a/include/rofi-icon-fetcher.h +++ b/include/rofi-icon-fetcher.h @@ -35,6 +35,7 @@ void rofi_icon_fetcher_destroy ( void ); * @returns the uid identifying the request. */ uint32_t rofi_icon_fetcher_query ( const char *name, const int size ); +uint32_t rofi_icon_fetcher_query_advanced ( const char *name, const int wsize, const int hsize ); /** * @param uid The unique id representing the matching request. diff --git a/include/rofi-types.h b/include/rofi-types.h index 7e0794d3..4117a1b3 100644 --- a/include/rofi-types.h +++ b/include/rofi-types.h @@ -188,11 +188,22 @@ typedef enum ROFI_DIRECTION_ANGLE, } RofiDirection; +typedef enum +{ + ROFI_SCALE_BOTH, + ROFI_SCALE_HEIGHT, + ROFI_SCALE_WIDTH, + ROFI_SCALE_NONE, +} RofiScaleType; + typedef struct { RofiImageType type; char *url; + RofiScaleType scaling; + int wsize; + int hsize; RofiDirection dir; double angle; diff --git a/lexer/theme-lexer.l b/lexer/theme-lexer.l index 394afa98..149b84b8 100644 --- a/lexer/theme-lexer.l +++ b/lexer/theme-lexer.l @@ -242,6 +242,11 @@ HSL (?i:hsl[a]?) /* Image type */ URL (?i:url?) LINEAR_GRADIENT (?i:linear-gradient?) +WIDTH (?i:width?) +HEIGHT (?i:height?) +BOTH (?i:both?) + + TO (?i:to?) RIGHT (?i:right?) @@ -564,6 +569,9 @@ if ( queue == NULL ){ } {URL} { return T_URL; } {LINEAR_GRADIENT} { return T_LINEAR_GRADIENT; } +{WIDTH} { return T_WIDTH; } +{HEIGHT} { return T_HEIGHT; } +{BOTH} { return T_BOTH; } {TO} { return T_TO; } {LEFT} { return T_LEFT; } diff --git a/lexer/theme-parser.y b/lexer/theme-parser.y index a7031161..729101d9 100644 --- a/lexer/theme-parser.y +++ b/lexer/theme-parser.y @@ -210,6 +210,9 @@ static ThemeColor hwb_to_rgb ( double h, double w, double b) %token T_COL_CMYK "cmyk colorscheme" %token T_URL "an URL" +%token T_WIDTH "an WIDTH" +%token T_HEIGHT "an HEIGHT" +%token T_BOTH "an BOTH" %token T_TO "an TO" %token T_LEFT "an LEFT" %token T_RIGHT "an RIGHT" @@ -217,6 +220,7 @@ static ThemeColor hwb_to_rgb ( double h, double w, double b) %token T_BOTTOM "an BOTTOM" %type t_property_direction +%type t_property_scale_type %token T_LINEAR_GRADIENT "a linear gradient" %token T_PARENT_LEFT "Parent left ('(')" @@ -561,6 +565,12 @@ t_property_element $$->value.image.type = ROFI_IMAGE_URL; $$->value.image.url = $3; } +| T_URL T_PARENT_LEFT T_STRING T_COMMA t_property_scale_type T_PARENT_RIGHT { + $$ = rofi_theme_property_create ( P_IMAGE ); + $$->value.image.type = ROFI_IMAGE_URL; + $$->value.image.url = $3; + $$->value.image.scaling = $5; +} | T_LINEAR_GRADIENT T_PARENT_LEFT t_color_list T_PARENT_RIGHT { $$ = rofi_theme_property_create ( P_IMAGE ); $$->value.image.type = ROFI_IMAGE_LINEAR_GRADIENT; @@ -589,6 +599,12 @@ t_property_direction | T_TOP { $$ = ROFI_DIRECTION_TOP; } | T_BOTTOM { $$ = ROFI_DIRECTION_BOTTOM; } ; +t_property_scale_type +: T_BOTH { $$ = ROFI_SCALE_BOTH; } +| T_WIDTH { $$ = ROFI_SCALE_WIDTH; } +| T_HEIGHT { $$ = ROFI_SCALE_HEIGHT; } +| T_NONE { $$ = ROFI_SCALE_NONE; } +; t_color_list : t_property_color { diff --git a/source/rofi-icon-fetcher.c b/source/rofi-icon-fetcher.c index 12e912a1..6a09d22a 100644 --- a/source/rofi-icon-fetcher.c +++ b/source/rofi-icon-fetcher.c @@ -77,7 +77,8 @@ typedef struct unsigned int *acount; uint32_t uid; - int size; + int wsize; + int hsize; cairo_surface_t *surface; IconFetcherNameEntry *entry; @@ -301,13 +302,13 @@ static void rofi_icon_fetcher_worker ( thread_state *sdata, G_GNUC_UNUSED gpoint icon_path = sentry->entry->name; } else { - icon_path = icon_path_ = nk_xdg_theme_get_icon ( rofi_icon_fetcher_data->xdg_context, themes, NULL, sentry->entry->name, sentry->size, 1, TRUE ); + icon_path = icon_path_ = nk_xdg_theme_get_icon ( rofi_icon_fetcher_data->xdg_context, themes, NULL, sentry->entry->name, MIN(sentry->wsize,sentry->hsize), 1, TRUE ); if ( icon_path_ == NULL ) { - g_debug ( "failed to get icon %s(%d): n/a", sentry->entry->name, sentry->size ); + g_debug ( "failed to get icon %s(%dx%d): n/a", sentry->entry->name, sentry->wsize, sentry->hsize ); return; } else{ - g_debug ( "found icon %s(%d): %s", sentry->entry->name, sentry->size, icon_path ); + g_debug ( "found icon %s(%dx%d): %s", sentry->entry->name, sentry->wsize, sentry->hsize, icon_path ); } } cairo_surface_t *icon_surf = NULL; @@ -318,7 +319,7 @@ static void rofi_icon_fetcher_worker ( thread_state *sdata, G_GNUC_UNUSED gpoint } GError *error = NULL; - GdkPixbuf *pb = gdk_pixbuf_new_from_file_at_scale ( icon_path, sentry->size, sentry->size, TRUE, &error ); + GdkPixbuf *pb = gdk_pixbuf_new_from_file_at_scale ( icon_path, sentry->wsize, sentry->hsize, TRUE, &error ); if ( error != NULL ) { g_warning ( "Failed to load image: %s", error->message ); g_error_free ( error ); @@ -336,6 +337,40 @@ static void rofi_icon_fetcher_worker ( thread_state *sdata, G_GNUC_UNUSED gpoint rofi_view_reload (); } +uint32_t rofi_icon_fetcher_query_advanced ( const char *name, const int wsize, const int hsize ) +{ + g_debug ( "Query: %s(%dx%d)", name, wsize, hsize ); + IconFetcherNameEntry *entry = g_hash_table_lookup ( rofi_icon_fetcher_data->icon_cache, name ); + if ( entry == NULL ) { + entry = g_new0 ( IconFetcherNameEntry, 1 ); + entry->name = g_strdup ( name ); + g_hash_table_insert ( rofi_icon_fetcher_data->icon_cache, entry->name, entry ); + } + IconFetcherEntry *sentry; + for ( GList *iter = g_list_first ( entry->sizes ); iter; iter = g_list_next ( iter ) ) { + sentry = iter->data; + if ( sentry->wsize == wsize && sentry->hsize == hsize ) { + return sentry->uid; + } + } + + // Not found. + sentry = g_new0 ( IconFetcherEntry, 1 ); + sentry->uid = ++( rofi_icon_fetcher_data->last_uid ); + sentry->wsize = wsize; + sentry->hsize = hsize; + sentry->entry = entry; + sentry->surface = NULL; + + entry->sizes = g_list_prepend ( entry->sizes, sentry ); + g_hash_table_insert ( rofi_icon_fetcher_data->icon_cache_uid, GINT_TO_POINTER ( sentry->uid ), sentry ); + + // Push into fetching queue. + sentry->state.callback = rofi_icon_fetcher_worker; + g_thread_pool_push ( tpool, sentry, NULL ); + + return sentry->uid; +} uint32_t rofi_icon_fetcher_query ( const char *name, const int size ) { g_debug ( "Query: %s(%d)", name, size ); @@ -348,7 +383,7 @@ uint32_t rofi_icon_fetcher_query ( const char *name, const int size ) IconFetcherEntry *sentry; for ( GList *iter = g_list_first ( entry->sizes ); iter; iter = g_list_next ( iter ) ) { sentry = iter->data; - if ( sentry->size == size ) { + if ( sentry->wsize == size && sentry->hsize == size ) { return sentry->uid; } } @@ -356,7 +391,8 @@ uint32_t rofi_icon_fetcher_query ( const char *name, const int size ) // Not found. sentry = g_new0 ( IconFetcherEntry, 1 ); sentry->uid = ++( rofi_icon_fetcher_data->last_uid ); - sentry->size = size; + sentry->wsize = size; + sentry->hsize = size; sentry->entry = entry; sentry->surface = NULL; diff --git a/source/theme.c b/source/theme.c index fa8ac220..cd6546af 100644 --- a/source/theme.c +++ b/source/theme.c @@ -996,8 +996,27 @@ gboolean rofi_theme_get_image ( const widget *widget, const char *property, cair return FALSE; } if ( p->value.image.type == ROFI_IMAGE_URL ) { - if ( p->value.image.surface_id == 0 ) { - p->value.image.surface_id = rofi_icon_fetcher_query ( p->value.image.url, -1 ); + int wsize = -1; + int hsize = -1; + switch ( p->value.image.scaling ) { + case ROFI_SCALE_BOTH: + wsize = widget->w; + hsize = widget->h; + break; + case ROFI_SCALE_WIDTH: + wsize = widget->w; + break; + case ROFI_SCALE_HEIGHT: + hsize = widget->h; + break; + case ROFI_SCALE_NONE: + default: + break; + } + if ( p->value.image.surface_id == 0 || p->value.image.wsize != wsize || p->value.image.hsize != hsize) { + p->value.image.surface_id = rofi_icon_fetcher_query_advanced ( p->value.image.url, wsize, hsize ); + p->value.image.wsize = wsize; + p->value.image.hsize = hsize; } cairo_surface_t *img = rofi_icon_fetcher_get ( p->value.image.surface_id );