Add window resize indicator

This commit is contained in:
Consolatis 2023-08-17 18:59:29 +02:00
parent c8321e3264
commit 58b33fb0c9
12 changed files with 296 additions and 0 deletions

View file

@ -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="">*

View file

@ -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>

View file

@ -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;

View 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 */

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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 */

View file

@ -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();
}

View file

@ -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
View 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);
}

View file

@ -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