mirror of
				https://github.com/labwc/labwc.git
				synced 2025-10-29 05:40:24 -04:00 
			
		
		
		
	Add window resize indicator
This commit is contained in:
		
							parent
							
								
									c8321e3264
								
							
						
					
					
						commit
						58b33fb0c9
					
				
					 12 changed files with 296 additions and 0 deletions
				
			
		|  | @ -249,6 +249,22 @@ Therefore, where multiple objects of the same kind are required (for example | |||
| 	Specify the number of pixels to reserve at the edges of an output. | ||||
| 	New, maximized and tiled windows will not be placed in these areas. | ||||
| 
 | ||||
| ## RESIZE | ||||
| 
 | ||||
| *<resize><popupShow>* [Never|Always|Nonpixel] | ||||
| 	Show a small indicator on top of the window when resizing or moving. | ||||
| 	When the application sets size-hints (usually X11 terminal emulators), | ||||
| 	the indicator will show the dimensions divided by size hints instead. | ||||
| 	In the case of terminal emulators this usually means columns x rows. | ||||
| 
 | ||||
| 	The different values mean: | ||||
| 	- *Never* Do not render the indicator | ||||
| 	- *Always* Render the indicator while moving and resizing windows | ||||
| 	- *Nonpixel* Only render the indicator during resize for windows using | ||||
| 	  size-hints | ||||
| 
 | ||||
| 	Default is Never. | ||||
| 
 | ||||
| ## KEYBOARD | ||||
| 
 | ||||
| *<keyboard><keybind key="">* | ||||
|  |  | |||
|  | @ -52,6 +52,9 @@ | |||
|     <screenEdgeStrength>20</screenEdgeStrength> | ||||
|   </resistance> | ||||
| 
 | ||||
|   <!-- Show a simple resize and move indicator --> | ||||
|   <resize popupShow="Never" /> | ||||
| 
 | ||||
|   <focus> | ||||
|     <followMouse>no</followMouse> | ||||
|     <followMouseRequiresMovement>yes</followMouseRequiresMovement> | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ | |||
| #include "common/buf.h" | ||||
| #include "common/font.h" | ||||
| #include "config/libinput.h" | ||||
| #include "resize_indicator.h" | ||||
| #include "theme.h" | ||||
| 
 | ||||
| enum window_switcher_field_content { | ||||
|  | @ -78,6 +79,8 @@ struct rcxml { | |||
| 	int snap_edge_range; | ||||
| 	bool snap_top_maximize; | ||||
| 
 | ||||
| 	enum resize_indicator_mode resize_indicator; | ||||
| 
 | ||||
| 	struct { | ||||
| 		int popuptime; | ||||
| 		int min_nr_workspaces; | ||||
|  |  | |||
							
								
								
									
										19
									
								
								include/resize_indicator.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								include/resize_indicator.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | |||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
| #ifndef LABWC_RESIZE_INDICATOR_H | ||||
| #define LABWC_RESIZE_INDICATOR_H | ||||
| 
 | ||||
| struct server; | ||||
| struct view; | ||||
| 
 | ||||
| enum resize_indicator_mode { | ||||
| 	LAB_RESIZE_INDICATOR_NEVER = 0, | ||||
| 	LAB_RESIZE_INDICATOR_ALWAYS, | ||||
| 	LAB_RESIZE_INDICATOR_NON_PIXEL | ||||
| }; | ||||
| 
 | ||||
| void resize_indicator_reconfigure(struct server *server); | ||||
| void resize_indicator_show(struct view *view); | ||||
| void resize_indicator_update(struct view *view); | ||||
| void resize_indicator_hide(struct view *view); | ||||
| 
 | ||||
| #endif /* LABWC_RESIZE_INDICATOR_H */ | ||||
|  | @ -128,6 +128,13 @@ struct view { | |||
| 	struct wl_event_source *pending_configure_timeout; | ||||
| 
 | ||||
| 	struct ssd *ssd; | ||||
| 	struct resize_indicator { | ||||
| 		int width, height; | ||||
| 		struct wlr_scene_tree *tree; | ||||
| 		struct wlr_scene_rect *border; | ||||
| 		struct wlr_scene_rect *background; | ||||
| 		struct scaled_font_buffer *text; | ||||
| 	} resize_indicator; | ||||
| 
 | ||||
| 	struct foreign_toplevel { | ||||
| 		struct wlr_foreign_toplevel_handle_v1 *handle; | ||||
|  |  | |||
|  | @ -51,6 +51,7 @@ font_extents(struct font *font, const char *string) | |||
| 	pango_extents_to_pixels(&rect, NULL); | ||||
| 
 | ||||
| 	/* we put a 2 px edge on each side - because Openbox does it :) */ | ||||
| 	/* TODO: remove the 4 pixel addition and always do the padding by the caller */ | ||||
| 	rect.width += 4; | ||||
| 
 | ||||
| 	cairo_destroy(c); | ||||
|  |  | |||
|  | @ -657,6 +657,16 @@ entry(xmlNode *node, char *nodename, char *content) | |||
| 		rc.workspace_config.popuptime = atoi(content); | ||||
| 	} else if (!strcasecmp(nodename, "number.desktops")) { | ||||
| 		rc.workspace_config.min_nr_workspaces = MAX(1, atoi(content)); | ||||
| 	} else if (!strcasecmp(nodename, "popupShow.resize")) { | ||||
| 		if (!strcasecmp(content, "Always")) { | ||||
| 			rc.resize_indicator = LAB_RESIZE_INDICATOR_ALWAYS; | ||||
| 		} else if (!strcasecmp(content, "Never")) { | ||||
| 			rc.resize_indicator = LAB_RESIZE_INDICATOR_NEVER; | ||||
| 		} else if (!strcasecmp(content, "Nonpixel")) { | ||||
| 			rc.resize_indicator = LAB_RESIZE_INDICATOR_NON_PIXEL; | ||||
| 		} else { | ||||
| 			wlr_log(WLR_ERROR, "Invalid value for <resize popupShow />"); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -806,6 +816,8 @@ rcxml_init(void) | |||
| 	rc.window_switcher.preview = true; | ||||
| 	rc.window_switcher.outlines = true; | ||||
| 
 | ||||
| 	rc.resize_indicator = LAB_RESIZE_INDICATOR_NEVER; | ||||
| 
 | ||||
| 	rc.workspace_config.popuptime = INT_MIN; | ||||
| 	rc.workspace_config.min_nr_workspaces = 1; | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| // SPDX-License-Identifier: GPL-2.0-only
 | ||||
| #include "labwc.h" | ||||
| #include "regions.h" | ||||
| #include "resize_indicator.h" | ||||
| #include "view.h" | ||||
| 
 | ||||
| static int | ||||
|  | @ -96,6 +97,9 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges) | |||
| 	server->grab_y = seat->cursor->y; | ||||
| 	server->grab_box = geometry; | ||||
| 	server->resize_edges = edges; | ||||
| 	if (rc.resize_indicator) { | ||||
| 		resize_indicator_show(view); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Returns true if view was snapped to any edge */ | ||||
|  | @ -172,6 +176,7 @@ interactive_finish(struct view *view) | |||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		resize_indicator_hide(view); | ||||
| 
 | ||||
| 		view->server->input_mode = LAB_INPUT_STATE_PASSTHROUGH; | ||||
| 		view->server->grabbed_view = NULL; | ||||
|  | @ -190,6 +195,7 @@ void | |||
| interactive_cancel(struct view *view) | ||||
| { | ||||
| 	if (view->server->grabbed_view == view) { | ||||
| 		resize_indicator_hide(view); | ||||
| 		view->server->input_mode = LAB_INPUT_STATE_PASSTHROUGH; | ||||
| 		view->server->grabbed_view = NULL; | ||||
| 		/* Update focus/cursor image */ | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ | |||
| #include "layers.h" | ||||
| #include "menu/menu.h" | ||||
| #include "regions.h" | ||||
| #include "resize_indicator.h" | ||||
| #include "theme.h" | ||||
| #include "view.h" | ||||
| #include "workspaces.h" | ||||
|  | @ -54,6 +55,7 @@ reload_config_and_theme(void) | |||
| 	menu_reconfigure(g_server); | ||||
| 	seat_reconfigure(g_server); | ||||
| 	regions_reconfigure(g_server); | ||||
| 	resize_indicator_reconfigure(g_server); | ||||
| 	kde_server_decoration_update_default(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| labwc_sources += files( | ||||
|   'resize_indicator.c', | ||||
|   'ssd.c', | ||||
|   'ssd_part.c', | ||||
|   'ssd_titlebar.c', | ||||
|  |  | |||
							
								
								
									
										222
									
								
								src/ssd/resize_indicator.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								src/ssd/resize_indicator.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,222 @@ | |||
| // SPDX-License-Identifier: GPL-2.0-only
 | ||||
| #include <assert.h> | ||||
| #include <wlr/types/wlr_scene.h> | ||||
| #include <wlr/util/box.h> | ||||
| #include <wlr/util/log.h> | ||||
| #include "common/scaled_font_buffer.h" | ||||
| #include "labwc.h" | ||||
| #include "resize_indicator.h" | ||||
| #include "view.h" | ||||
| 
 | ||||
| static void | ||||
| resize_indicator_reconfigure_view(struct resize_indicator *indicator) | ||||
| { | ||||
| 	assert(indicator->tree); | ||||
| 
 | ||||
| 	struct theme *theme = rc.theme; | ||||
| 	indicator->height = font_height(&rc.font_osd) | ||||
| 		+ 2 * theme->osd_window_switcher_padding | ||||
| 		+ 2 * theme->osd_border_width; | ||||
| 
 | ||||
| 	/* Static positions */ | ||||
| 	wlr_scene_node_set_position(&indicator->background->node, | ||||
| 		theme->osd_border_width, theme->osd_border_width); | ||||
| 
 | ||||
| 	wlr_scene_node_set_position(&indicator->text->scene_buffer->node, | ||||
| 		theme->osd_border_width + theme->osd_window_switcher_padding, | ||||
| 		theme->osd_border_width + theme->osd_window_switcher_padding); | ||||
| 
 | ||||
| 	/* Colors */ | ||||
| 	wlr_scene_rect_set_color(indicator->border, theme->osd_border_color); | ||||
| 	wlr_scene_rect_set_color(indicator->background, theme->osd_bg_color); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| resize_indicator_init(struct view *view) | ||||
| { | ||||
| 	assert(view); | ||||
| 	struct resize_indicator *indicator = &view->resize_indicator; | ||||
| 	assert(!indicator->tree); | ||||
| 
 | ||||
| 	indicator->tree = wlr_scene_tree_create(view->scene_tree); | ||||
| 	indicator->border = wlr_scene_rect_create( | ||||
| 		indicator->tree, 0, 0, rc.theme->osd_border_color); | ||||
| 	indicator->background = wlr_scene_rect_create( | ||||
| 		indicator->tree, 0, 0, rc.theme->osd_bg_color); | ||||
| 	indicator->text = scaled_font_buffer_create(indicator->tree); | ||||
| 
 | ||||
| 	wlr_scene_node_set_enabled(&indicator->tree->node, false); | ||||
| 	resize_indicator_reconfigure_view(indicator); | ||||
| } | ||||
| 
 | ||||
| static struct wlr_box | ||||
| get_size_hints(struct view *view) | ||||
| { | ||||
| 	assert(view); | ||||
| 
 | ||||
| 	struct wlr_box hints = { 0 }; | ||||
| 	if (view->impl->fill_size_hints) { | ||||
| 		view->impl->fill_size_hints(view, &hints); | ||||
| 	} | ||||
| 	return hints; | ||||
| } | ||||
| 
 | ||||
| static bool | ||||
| wants_indicator(struct view *view) | ||||
| { | ||||
| 	assert(view); | ||||
| 
 | ||||
| 	if (rc.resize_indicator == LAB_RESIZE_INDICATOR_NON_PIXEL) { | ||||
| 		if (view->server->input_mode != LAB_INPUT_STATE_RESIZE) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		struct wlr_box size_hints = get_size_hints(view); | ||||
| 		if (size_hints.width && size_hints.height) { | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| 	return rc.resize_indicator == LAB_RESIZE_INDICATOR_ALWAYS; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| resize_indicator_reconfigure(struct server *server) | ||||
| { | ||||
| 	struct view *view; | ||||
| 	wl_list_for_each(view, &server->views, link) { | ||||
| 		struct resize_indicator *indicator = &view->resize_indicator; | ||||
| 		if (indicator->tree) { | ||||
| 			resize_indicator_reconfigure_view(indicator); | ||||
| 		} | ||||
| 		if (view != server->grabbed_view) { | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		/* This view is currently in an interactive move/resize operation */ | ||||
| 		if (indicator->tree && indicator->tree->node.enabled) { | ||||
| 			/* Indicator was active while reloading the config */ | ||||
| 			if (wants_indicator(view)) { | ||||
| 				/* Apply new font setting */ | ||||
| 				resize_indicator_update(view); | ||||
| 			} else { | ||||
| 				/* Indicator was disabled in config */ | ||||
| 				resize_indicator_hide(view); | ||||
| 			} | ||||
| 		} else if (wants_indicator(view)) { | ||||
| 			/* Indicator not yet active */ | ||||
| 			resize_indicator_show(view); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| resize_indicator_set_size(struct resize_indicator *indicator, int width) | ||||
| { | ||||
| 	assert(indicator->tree); | ||||
| 
 | ||||
| 	/* We are not using a width-cache-early-out here to allow for theme changes */ | ||||
| 	indicator->width = width | ||||
| 		+ 2 * rc.theme->osd_window_switcher_padding | ||||
| 		+ 2 * rc.theme->osd_border_width; | ||||
| 
 | ||||
| 	wlr_scene_rect_set_size(indicator->border, indicator->width, indicator->height); | ||||
| 	wlr_scene_rect_set_size(indicator->background, | ||||
| 		indicator->width - 2 * rc.theme->osd_border_width, | ||||
| 		indicator->height - 2 * rc.theme->osd_border_width); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| resize_indicator_show(struct view *view) | ||||
| { | ||||
| 	assert(view); | ||||
| 
 | ||||
| 	if (!wants_indicator(view)) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	struct resize_indicator *indicator = &view->resize_indicator; | ||||
| 	if (!indicator->tree) { | ||||
| 		/* Lazy initialize */ | ||||
| 		resize_indicator_init(view); | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_scene_node_raise_to_top(&indicator->tree->node); | ||||
| 	wlr_scene_node_set_enabled(&indicator->tree->node, true); | ||||
| 	resize_indicator_update(view); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| resize_indicator_update(struct view *view) | ||||
| { | ||||
| 	assert(view); | ||||
| 	assert(view == view->server->grabbed_view); | ||||
| 
 | ||||
| 	if (!wants_indicator(view)) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	struct resize_indicator *indicator = &view->resize_indicator; | ||||
| 	if (!indicator->tree) { | ||||
| 		/*
 | ||||
| 		 * Future-proofs this routine: | ||||
| 		 * | ||||
| 		 * This can only happen when either src/interactive.c | ||||
| 		 * stops calling resize_indicator_show(), there is a | ||||
| 		 * bug in this file or resize_indicator_reconfigure() | ||||
| 		 * gets changed. | ||||
| 		 */ | ||||
| 		wlr_log(WLR_INFO, "Warning: resize_indicator has to use a fallback path"); | ||||
| 		resize_indicator_show(view); | ||||
| 	} | ||||
| 
 | ||||
| 	char text[32]; /* 12345 x 12345 would be 13 chars + 1 null byte */ | ||||
| 
 | ||||
| 	switch (view->server->input_mode) { | ||||
| 	case LAB_INPUT_STATE_RESIZE: | ||||
| 		; /* works around "a label can only be part of a statement" */ | ||||
| 		struct wlr_box size_hints = get_size_hints(view); | ||||
| 		snprintf(text, sizeof(text), "%d x %d", | ||||
| 			view->current.width / MAX(1, size_hints.width), | ||||
| 			view->current.height / MAX(1, size_hints.height)); | ||||
| 		break; | ||||
| 	case LAB_INPUT_STATE_MOVE: | ||||
| 		; /* works around "a label can only be part of a statement" */ | ||||
| 		struct border margin = ssd_get_margin(view->ssd); | ||||
| 		snprintf(text, sizeof(text), "%d , %d", | ||||
| 			view->current.x - margin.left, | ||||
| 			view->current.y - margin.top); | ||||
| 		break; | ||||
| 	default: | ||||
| 		wlr_log(WLR_ERROR, "Invalid input mode for indicator update %u", | ||||
| 			view->server->input_mode); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Let the indicator change width as required by the content */ | ||||
| 	int width = font_width(&rc.font_osd, text); | ||||
| 
 | ||||
| 	/* font_extents() adds 4 pixels to the calculated width */ | ||||
| 	width -= 4; | ||||
| 
 | ||||
| 	resize_indicator_set_size(indicator, width); | ||||
| 
 | ||||
| 	/* Center the indicator in the window */ | ||||
| 	wlr_scene_node_set_position(&indicator->tree->node, | ||||
| 		(view->current.width - indicator->width) / 2, | ||||
| 		(view->current.height - indicator->height) / 2); | ||||
| 
 | ||||
| 	scaled_font_buffer_update(indicator->text, text, width, &rc.font_osd, | ||||
| 		rc.theme->osd_label_text_color, NULL /* const char *arrow */); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| resize_indicator_hide(struct view *view) | ||||
| { | ||||
| 	assert(view); | ||||
| 
 | ||||
| 	struct resize_indicator *indicator = &view->resize_indicator; | ||||
| 	if (!indicator->tree) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_scene_node_set_enabled(&indicator->tree->node, false); | ||||
| } | ||||
|  | @ -7,6 +7,7 @@ | |||
| #include "labwc.h" | ||||
| #include "menu/menu.h" | ||||
| #include "regions.h" | ||||
| #include "resize_indicator.h" | ||||
| #include "ssd.h" | ||||
| #include "view.h" | ||||
| #include "window-rules.h" | ||||
|  | @ -182,6 +183,9 @@ view_moved(struct view *view) | |||
| 	if (view->toplevel.handle) { | ||||
| 		foreign_toplevel_update_outputs(view); | ||||
| 	} | ||||
| 	if (rc.resize_indicator && view->server->grabbed_view == view) { | ||||
| 		resize_indicator_update(view); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Consolatis
						Consolatis