mirror of
				https://github.com/labwc/labwc.git
				synced 2025-10-29 05:40:24 -04:00 
			
		
		
		
	Support png buttons
In the theme directory add close-{active,inactive}.png instead of
close.xbm - and similarly for iconify, menu and max.
			
			
This commit is contained in:
		
							parent
							
								
									eca98a9b6e
								
							
						
					
					
						commit
						a6a03daae3
					
				
					 7 changed files with 138 additions and 11 deletions
				
			
		|  | @ -18,7 +18,8 @@ searched for in the following order: | ||||||
| Choosing a theme is done by editing the <name> key in the <theme> section of | Choosing a theme is done by editing the <name> key in the <theme> section of | ||||||
| the rc.xml configuration file (labwc-config(5)). | the rc.xml configuration file (labwc-config(5)). | ||||||
| 
 | 
 | ||||||
| A theme consists of a themerc file and optionally some xbm icons. | A theme consists of a themerc file and optionally some titlebar icons (referred | ||||||
|  | to as buttons). | ||||||
| 
 | 
 | ||||||
| Theme settings specified in themerc can be overridden by creating a | Theme settings specified in themerc can be overridden by creating a | ||||||
| 'themerc-override' file in the configuration directory, which is normally | 'themerc-override' file in the configuration directory, which is normally | ||||||
|  | @ -175,19 +176,26 @@ elements are not listed here, but are supported. | ||||||
| 
 | 
 | ||||||
| # BUTTONS | # BUTTONS | ||||||
| 
 | 
 | ||||||
| The images used for the titlebar buttons are 1-bit xbm (X Bitmaps). These are | The images used for the titlebar icons are referred to as buttons. | ||||||
| masks where 0=clear and 1=colored. The xbm image files are placed in the same | 
 | ||||||
| directory within your theme as the themerc file. Here are all the possible xbm | The image formats listed below are supported. They are listed in order of | ||||||
| files looked for: | precedence, where the first format in the list is searched for first. | ||||||
|  | 
 | ||||||
|  | - png | ||||||
|  | - xbm | ||||||
|  | 
 | ||||||
|  | By default, buttons are 1-bit xbm (X Bitmaps). These are masks where 0=clear and | ||||||
|  | 1=colored. The xbm image files are placed in the same directory as the themerc | ||||||
|  | file within a particular theme. The following xbm buttons are supported: | ||||||
| 
 | 
 | ||||||
| - max.xbm | - max.xbm | ||||||
| - iconify.xbm | - iconify.xbm | ||||||
| - close.xbm | - close.xbm | ||||||
| - menu.xbm | - menu.xbm | ||||||
| 
 | 
 | ||||||
| More will be supported later. | One advantage of xbm buttons over other formats is that they change color based | ||||||
| 
 | on the theme. Other formats use the suffices "-active" and "-inactive" to align | ||||||
| Note: menu.xbm is not part of openbox-3.6 spec | with the respective titlebar colors. For example: "close-active.png" | ||||||
| 
 | 
 | ||||||
| # DEFINITIONS | # DEFINITIONS | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										9
									
								
								include/button-png.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								include/button-png.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | ||||||
|  | /* SPDX-License-Identifier: GPL-2.0-only */ | ||||||
|  | #ifndef LABWC_BUTTON_PNG_H | ||||||
|  | #define LABWC_BUTTON_PNG_H | ||||||
|  | 
 | ||||||
|  | struct lab_data_buffer; | ||||||
|  | 
 | ||||||
|  | void png_load(const char *filename, struct lab_data_buffer **buffer); | ||||||
|  | 
 | ||||||
|  | #endif /* LABWC_BUTTON_PNG_H */ | ||||||
|  | @ -69,6 +69,7 @@ cairo = dependency('cairo') | ||||||
| pangocairo = dependency('pangocairo') | pangocairo = dependency('pangocairo') | ||||||
| input = dependency('libinput', version: '>=1.14') | input = dependency('libinput', version: '>=1.14') | ||||||
| math = cc.find_library('m') | math = cc.find_library('m') | ||||||
|  | png = dependency('libpng') | ||||||
| 
 | 
 | ||||||
| if get_option('xwayland').enabled() and not wlroots_has_xwayland | if get_option('xwayland').enabled() and not wlroots_has_xwayland | ||||||
| 	error('no wlroots Xwayland support') | 	error('no wlroots Xwayland support') | ||||||
|  | @ -103,6 +104,7 @@ labwc_deps = [ | ||||||
|   pangocairo, |   pangocairo, | ||||||
|   input, |   input, | ||||||
|   math, |   math, | ||||||
|  |   png, | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| subdir('include') | subdir('include') | ||||||
|  |  | ||||||
							
								
								
									
										91
									
								
								src/button-png.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/button-png.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,91 @@ | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-only
 | ||||||
|  | /*
 | ||||||
|  |  * Copyright (C) Johan Malm 2023 | ||||||
|  |  */ | ||||||
|  | #define _POSIX_C_SOURCE 200809L | ||||||
|  | #include <cairo.h> | ||||||
|  | #include <png.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <sys/stat.h> | ||||||
|  | #include <wlr/util/log.h> | ||||||
|  | #include "buffer.h" | ||||||
|  | #include "button-png.h" | ||||||
|  | #include "common/dir.h" | ||||||
|  | #include "labwc.h" | ||||||
|  | #include "theme.h" | ||||||
|  | 
 | ||||||
|  | /* Share with session.c:isfile() */ | ||||||
|  | static bool | ||||||
|  | file_exists(const char *path) | ||||||
|  | { | ||||||
|  | 	struct stat st; | ||||||
|  | 	return (!stat(path, &st)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Share with xbm.c:xbm_path() */ | ||||||
|  | static char * | ||||||
|  | button_path(const char *filename) | ||||||
|  | { | ||||||
|  | 	static char buffer[4096] = { 0 }; | ||||||
|  | 	snprintf(buffer, sizeof(buffer), "%s/%s", theme_dir(rc.theme_name), filename); | ||||||
|  | 	return buffer; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * cairo_image_surface_create_from_png() does not gracefully handle non-png | ||||||
|  |  * files, so we verify the header before trying to read the rest of the file. | ||||||
|  |  */ | ||||||
|  | #define PNG_BYTES_TO_CHECK (4) | ||||||
|  | static bool | ||||||
|  | ispng(const char *filename) | ||||||
|  | { | ||||||
|  | 	unsigned char header[PNG_BYTES_TO_CHECK]; | ||||||
|  | 	FILE *fp = fopen(filename, "rb"); | ||||||
|  | 	if (!fp) { | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	if (fread(header, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK) { | ||||||
|  | 		fclose(fp); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	if (png_sig_cmp(header, (png_size_t)0, PNG_BYTES_TO_CHECK)) { | ||||||
|  | 		wlr_log(WLR_ERROR, "file '%s' is not a recognised png file", filename); | ||||||
|  | 		fclose(fp); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	fclose(fp); | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #undef PNG_BYTES_TO_CHECK | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | png_load(const char *filename, struct lab_data_buffer **buffer) | ||||||
|  | { | ||||||
|  | 	if (*buffer) { | ||||||
|  | 		wlr_buffer_drop(&(*buffer)->base); | ||||||
|  | 		*buffer = NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	char *path = button_path(filename); | ||||||
|  | 	if (!file_exists(path) || !ispng(path)) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	cairo_surface_t *image = cairo_image_surface_create_from_png(path); | ||||||
|  | 	if (cairo_surface_status(image)) { | ||||||
|  | 		wlr_log(WLR_ERROR, "error reading png button '%s'", path); | ||||||
|  | 		cairo_surface_destroy(image); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	cairo_surface_flush(image); | ||||||
|  | 
 | ||||||
|  | 	double w = cairo_image_surface_get_width(image); | ||||||
|  | 	double h = cairo_image_surface_get_height(image); | ||||||
|  | 	*buffer = buffer_create_cairo((int)w, (int)h, 1.0, true); | ||||||
|  | 	cairo_t *cairo = (*buffer)->cairo; | ||||||
|  | 	cairo_set_source_surface(cairo, image, 0, 0); | ||||||
|  | 	cairo_paint_with_alpha(cairo, 1.0); | ||||||
|  | } | ||||||
|  | @ -15,6 +15,7 @@ labwc_sources = files( | ||||||
|   'node.c', |   'node.c', | ||||||
|   'osd.c', |   'osd.c', | ||||||
|   'output.c', |   'output.c', | ||||||
|  |   'button-png.c', | ||||||
|   'regions.c', |   'regions.c', | ||||||
|   'resistance.c', |   'resistance.c', | ||||||
|   'seat.c', |   'seat.c', | ||||||
|  |  | ||||||
|  | @ -53,7 +53,8 @@ ssd_titlebar_create(struct ssd *ssd) | ||||||
| 			corner_top_right = &theme->corner_top_right_inactive_normal->base; | 			corner_top_right = &theme->corner_top_right_inactive_normal->base; | ||||||
| 			menu_button_unpressed = &theme->button_menu_inactive_unpressed->base; | 			menu_button_unpressed = &theme->button_menu_inactive_unpressed->base; | ||||||
| 			iconify_button_unpressed = &theme->button_iconify_inactive_unpressed->base; | 			iconify_button_unpressed = &theme->button_iconify_inactive_unpressed->base; | ||||||
| 			maximize_button_unpressed = &theme->button_maximize_inactive_unpressed->base; | 			maximize_button_unpressed = | ||||||
|  | 				&theme->button_maximize_inactive_unpressed->base; | ||||||
| 			close_button_unpressed = &theme->button_close_inactive_unpressed->base; | 			close_button_unpressed = &theme->button_close_inactive_unpressed->base; | ||||||
| 			wlr_scene_node_set_enabled(&parent->node, false); | 			wlr_scene_node_set_enabled(&parent->node, false); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
							
								
								
									
										19
									
								
								src/theme.c
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								src/theme.c
									
										
									
									
									
								
							|  | @ -24,6 +24,7 @@ | ||||||
| #include "common/match.h" | #include "common/match.h" | ||||||
| #include "common/string-helpers.h" | #include "common/string-helpers.h" | ||||||
| #include "config/rcxml.h" | #include "config/rcxml.h" | ||||||
|  | #include "button-png.h" | ||||||
| #include "theme.h" | #include "theme.h" | ||||||
| #include "xbm/xbm.h" | #include "xbm/xbm.h" | ||||||
| #include "buffer.h" | #include "buffer.h" | ||||||
|  | @ -95,9 +96,23 @@ load_buttons(struct theme *theme) | ||||||
| 	char filename[4096] = {0}; | 	char filename[4096] = {0}; | ||||||
| 	for (size_t i = 0; i < sizeof(buttons) / sizeof(buttons[0]); ++i) { | 	for (size_t i = 0; i < sizeof(buttons) / sizeof(buttons[0]); ++i) { | ||||||
| 		struct button *b = &buttons[i]; | 		struct button *b = &buttons[i]; | ||||||
|  | 
 | ||||||
|  | 		/* Try png icon first */ | ||||||
|  | 		snprintf(filename, sizeof(filename), "%s-active.png", b->name); | ||||||
|  | 		png_load(filename, b->active.buffer); | ||||||
|  | 		snprintf(filename, sizeof(filename), "%s-inactive.png", b->name); | ||||||
|  | 		png_load(filename, b->inactive.buffer); | ||||||
|  | 
 | ||||||
|  | 		/* If there were no png buttons, use xbm */ | ||||||
| 		snprintf(filename, sizeof(filename), "%s.xbm", b->name); | 		snprintf(filename, sizeof(filename), "%s.xbm", b->name); | ||||||
| 		xbm_load_button(filename, b->active.buffer, b->fallback_button, b->active.rgba); | 		if (!*b->active.buffer) { | ||||||
| 		xbm_load_button(filename, b->inactive.buffer, b->fallback_button, b->inactive.rgba); | 			xbm_load_button(filename, b->active.buffer, | ||||||
|  | 				b->fallback_button, b->active.rgba); | ||||||
|  | 		} | ||||||
|  | 		if (!*b->inactive.buffer) { | ||||||
|  | 			xbm_load_button(filename, b->inactive.buffer, | ||||||
|  | 				b->fallback_button, b->inactive.rgba); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Johan Malm
						Johan Malm