mirror of
				https://github.com/swaywm/sway.git
				synced 2025-10-29 05:40:18 -04:00 
			
		
		
		
	swaybar: do not retry search for tray icons
In case a tray icon cannot be found or does not have a desirable size, swaybar retries the search again and again, which increases load on disk and CPU. This commit solves it by storing target_size for each icon, so that swaybar does not search for an icon of some size if it already tried to. Fixes #3789.
This commit is contained in:
		
							parent
							
								
									a5b6f40937
								
							
						
					
					
						commit
						fa0abaf7cf
					
				
					 3 changed files with 62 additions and 52 deletions
				
			
		|  | @ -20,6 +20,7 @@ struct swaybar_sni { | ||||||
| 	cairo_surface_t *icon; | 	cairo_surface_t *icon; | ||||||
| 	int min_size; | 	int min_size; | ||||||
| 	int max_size; | 	int max_size; | ||||||
|  | 	int target_size; | ||||||
| 
 | 
 | ||||||
| 	// dbus properties
 | 	// dbus properties
 | ||||||
| 	char *watcher_id; | 	char *watcher_id; | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| #define _POSIX_C_SOURCE 200809L | #define _POSIX_C_SOURCE 200809L | ||||||
| #include <arpa/inet.h> | #include <arpa/inet.h> | ||||||
| #include <cairo.h> | #include <cairo.h> | ||||||
|  | #include <limits.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  | @ -27,7 +28,7 @@ static bool sni_ready(struct swaybar_sni *sni) { | ||||||
| 
 | 
 | ||||||
| static void set_sni_dirty(struct swaybar_sni *sni) { | static void set_sni_dirty(struct swaybar_sni *sni) { | ||||||
| 	if (sni_ready(sni)) { | 	if (sni_ready(sni)) { | ||||||
| 		sni->min_size = sni->max_size = 0; // invalidate previous icon
 | 		sni->target_size = sni->min_size = sni->max_size = 0; // invalidate previous icon
 | ||||||
| 		set_bar_dirty(sni->tray->bar); | 		set_bar_dirty(sni->tray->bar); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -401,69 +402,75 @@ static enum hotspot_event_handling icon_hotspot_callback( | ||||||
| 	return HOTSPOT_PROCESS; | 	return HOTSPOT_PROCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void reload_sni(struct swaybar_sni *sni, char *icon_theme, | ||||||
|  | 		int target_size) { | ||||||
|  | 	char *icon_name = sni->status[0] == 'N' ? | ||||||
|  | 		sni->attention_icon_name : sni->icon_name; | ||||||
|  | 	if (icon_name) { | ||||||
|  | 		list_t *icon_search_paths = create_list(); | ||||||
|  | 		list_cat(icon_search_paths, sni->tray->basedirs); | ||||||
|  | 		if (sni->icon_theme_path) { | ||||||
|  | 			list_add(icon_search_paths, sni->icon_theme_path); | ||||||
|  | 		} | ||||||
|  | 		char *icon_path = find_icon(sni->tray->themes, icon_search_paths, | ||||||
|  | 				icon_name, target_size, icon_theme, | ||||||
|  | 				&sni->min_size, &sni->max_size); | ||||||
|  | 		list_free(icon_search_paths); | ||||||
|  | 		if (!icon_path && sni->icon_theme_path) { | ||||||
|  | 			icon_path = find_icon_in_dir(icon_name, sni->icon_theme_path, | ||||||
|  | 					&sni->min_size, &sni->max_size); | ||||||
|  | 		} | ||||||
|  | 		if (icon_path) { | ||||||
|  | 			cairo_surface_destroy(sni->icon); | ||||||
|  | 			sni->icon = load_background_image(icon_path); | ||||||
|  | 			free(icon_path); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	list_t *pixmaps = sni->status[0] == 'N' ? | ||||||
|  | 		sni->attention_icon_pixmap : sni->icon_pixmap; | ||||||
|  | 	if (pixmaps) { | ||||||
|  | 		struct swaybar_pixmap *pixmap = NULL; | ||||||
|  | 		int min_error = INT_MAX; | ||||||
|  | 		for (int i = 0; i < pixmaps->length; ++i) { | ||||||
|  | 			struct swaybar_pixmap *p = pixmaps->items[i]; | ||||||
|  | 			int e = abs(target_size - pixmap->size); | ||||||
|  | 			if (e < min_error) { | ||||||
|  | 				pixmap = p; | ||||||
|  | 				min_error = e; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		cairo_surface_destroy(sni->icon); | ||||||
|  | 		sni->icon = cairo_image_surface_create_for_data(pixmap->pixels, | ||||||
|  | 				CAIRO_FORMAT_ARGB32, pixmap->size, pixmap->size, | ||||||
|  | 				cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pixmap->size)); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x, | uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x, | ||||||
| 		struct swaybar_sni *sni) { | 		struct swaybar_sni *sni) { | ||||||
| 	uint32_t height = output->height * output->scale; | 	uint32_t height = output->height * output->scale; | ||||||
| 	int padding = output->bar->config->tray_padding; | 	int padding = output->bar->config->tray_padding; | ||||||
| 	int ideal_size = height - 2*padding; | 	int target_size = height - 2*padding; | ||||||
| 	if ((ideal_size < sni->min_size || ideal_size > sni->max_size) && sni_ready(sni)) { | 	if (target_size != sni->target_size && sni_ready(sni)) { | ||||||
| 		bool icon_found = false; | 		// check if another icon should be loaded
 | ||||||
| 		char *icon_name = sni->status[0] == 'N' ? | 		if (target_size < sni->min_size || target_size > sni->max_size) { | ||||||
| 			sni->attention_icon_name : sni->icon_name; | 			reload_sni(sni, output->bar->config->icon_theme, target_size); | ||||||
| 		if (icon_name) { |  | ||||||
| 			list_t *icon_search_paths = create_list(); |  | ||||||
| 			list_cat(icon_search_paths, sni->tray->basedirs); |  | ||||||
| 			if (sni->icon_theme_path) { |  | ||||||
| 				list_add(icon_search_paths, sni->icon_theme_path); |  | ||||||
| 			} |  | ||||||
| 			char *icon_path = find_icon(sni->tray->themes, icon_search_paths, |  | ||||||
| 					icon_name, ideal_size, output->bar->config->icon_theme, |  | ||||||
| 					&sni->min_size, &sni->max_size); |  | ||||||
| 			list_free(icon_search_paths); |  | ||||||
| 			if (!icon_path && sni->icon_theme_path) { |  | ||||||
| 				icon_path = find_icon_in_dir(icon_name, sni->icon_theme_path, |  | ||||||
| 						&sni->min_size, &sni->max_size); |  | ||||||
| 			} |  | ||||||
| 			if (icon_path) { |  | ||||||
| 				cairo_surface_destroy(sni->icon); |  | ||||||
| 				sni->icon = load_background_image(icon_path); |  | ||||||
| 				free(icon_path); |  | ||||||
| 				icon_found = true; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		if (!icon_found) { |  | ||||||
| 			list_t *pixmaps = sni->status[0] == 'N' ? |  | ||||||
| 				sni->attention_icon_pixmap : sni->icon_pixmap; |  | ||||||
| 			if (pixmaps) { |  | ||||||
| 				int idx = -1; |  | ||||||
| 				unsigned smallest_error = -1; // UINT_MAX
 |  | ||||||
| 				for (int i = 0; i < pixmaps->length; ++i) { |  | ||||||
| 					struct swaybar_pixmap *pixmap = pixmaps->items[i]; |  | ||||||
| 					unsigned error = (ideal_size - pixmap->size) * |  | ||||||
| 						(ideal_size < pixmap->size ? -1 : 1); |  | ||||||
| 					if (error < smallest_error) { |  | ||||||
| 						smallest_error = error; |  | ||||||
| 						idx = i; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				struct swaybar_pixmap *pixmap = pixmaps->items[idx]; |  | ||||||
| 				cairo_surface_destroy(sni->icon); |  | ||||||
| 				sni->icon = cairo_image_surface_create_for_data(pixmap->pixels, |  | ||||||
| 						CAIRO_FORMAT_ARGB32, pixmap->size, pixmap->size, |  | ||||||
| 						cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pixmap->size)); |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		sni->target_size = target_size; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	int icon_size; | 	int icon_size; | ||||||
| 	cairo_surface_t *icon; | 	cairo_surface_t *icon; | ||||||
| 	if (sni->icon) { | 	if (sni->icon) { | ||||||
| 		int actual_size = cairo_image_surface_get_height(sni->icon); | 		int actual_size = cairo_image_surface_get_height(sni->icon); | ||||||
| 		icon_size = actual_size < ideal_size ? | 		icon_size = actual_size < target_size ? | ||||||
| 			actual_size*(ideal_size/actual_size) : ideal_size; | 			actual_size*(target_size/actual_size) : target_size; | ||||||
| 		icon = cairo_image_surface_scale(sni->icon, icon_size, icon_size); | 		icon = cairo_image_surface_scale(sni->icon, icon_size, icon_size); | ||||||
| 	} else { // draw a :(
 | 	} else { // draw a :(
 | ||||||
| 		icon_size = ideal_size*0.8; | 		icon_size = target_size*0.8; | ||||||
| 		icon = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, icon_size, icon_size); | 		icon = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, icon_size, icon_size); | ||||||
| 		cairo_t *cairo_icon = cairo_create(icon); | 		cairo_t *cairo_icon = cairo_create(icon); | ||||||
| 		cairo_set_source_u32(cairo_icon, 0xFF0000FF); | 		cairo_set_source_u32(cairo_icon, 0xFF0000FF); | ||||||
|  |  | ||||||
|  | @ -124,7 +124,9 @@ uint32_t render_tray(cairo_t *cairo, struct swaybar_output *output, double *x) { | ||||||
| 	struct swaybar_tray *tray = output->bar->tray; | 	struct swaybar_tray *tray = output->bar->tray; | ||||||
| 	for (int i = 0; i < tray->items->length; ++i) { | 	for (int i = 0; i < tray->items->length; ++i) { | ||||||
| 		uint32_t h = render_sni(cairo, output, x, tray->items->items[i]); | 		uint32_t h = render_sni(cairo, output, x, tray->items->items[i]); | ||||||
| 		max_height = h > max_height ? h : max_height; | 		if (h > max_height) { | ||||||
|  | 			max_height = h; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return max_height; | 	return max_height; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Konstantin Pospelov
						Konstantin Pospelov