2023-08-17 18:59:29 +02:00
|
|
|
// 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>
|
2026-02-23 16:34:36 -05:00
|
|
|
#include "common/scene-helpers.h"
|
2025-08-17 16:01:50 -04:00
|
|
|
#include "config/rcxml.h"
|
2023-08-17 18:59:29 +02:00
|
|
|
#include "labwc.h"
|
2024-05-22 09:56:16 +09:00
|
|
|
#include "resize-indicator.h"
|
2024-05-29 11:06:39 +09:00
|
|
|
#include "resize-outlines.h"
|
2025-09-02 17:47:01 +09:00
|
|
|
#include "scaled-buffer/scaled-font-buffer.h"
|
2025-09-03 05:08:52 -04:00
|
|
|
#include "ssd.h"
|
2025-08-17 16:01:50 -04:00
|
|
|
#include "theme.h"
|
2023-08-17 18:59:29 +02:00
|
|
|
#include "view.h"
|
|
|
|
|
|
2025-08-08 12:42:41 +09:00
|
|
|
#define PADDING rc.theme->osd_window_switcher_classic.padding
|
|
|
|
|
|
2023-08-17 18:59:29 +02:00
|
|
|
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)
|
2025-08-08 12:42:41 +09:00
|
|
|
+ 2 * PADDING
|
2023-08-17 18:59:29 +02:00
|
|
|
+ 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,
|
2025-08-08 12:42:41 +09:00
|
|
|
theme->osd_border_width + PADDING,
|
|
|
|
|
theme->osd_border_width + PADDING);
|
2023-08-17 18:59:29 +02:00
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
|
2026-02-23 16:34:36 -05:00
|
|
|
indicator->tree = lab_wlr_scene_tree_create(view->scene_tree);
|
|
|
|
|
indicator->border = lab_wlr_scene_rect_create(
|
2023-08-17 18:59:29 +02:00
|
|
|
indicator->tree, 0, 0, rc.theme->osd_border_color);
|
2026-02-23 16:34:36 -05:00
|
|
|
indicator->background = lab_wlr_scene_rect_create(
|
2023-08-17 18:59:29 +02:00
|
|
|
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 bool
|
|
|
|
|
wants_indicator(struct view *view)
|
|
|
|
|
{
|
|
|
|
|
assert(view);
|
|
|
|
|
|
|
|
|
|
if (rc.resize_indicator == LAB_RESIZE_INDICATOR_NON_PIXEL) {
|
tree-wide: auto-replace of (struct server *)
#!/bin/bash
read -r -d '' EXPRS << EOF
s/xwayland->server/xwayland->svr/g;
s/\t*struct server \*server;\n//g;
s/\t*struct server \*server =.*?;\n//gs;
s/\t*.* = ([a-z_]*->)*server[;,]\n//g;
s/\{\n\n/\{\n/g;
s/\n\n+/\n\n/g;
s/\(\s*struct server \*server\)/(void)/g;
s/\(\s*struct server \*server,\s*/(/g;
s/,\s*struct server \*server\)/)/g;
s/,\s*struct server \*server,\s*/, /g;
s/\(\s*([a-z_]*->)*server\)/()/g;
s/\(\s*([a-z_]*->)*server,\s*/(/g;
s/,\s*([a-z_]*->)*server\)/)/g;
s/,\s*([a-z_]*->)*server,\s*/, /g;
s/([a-z_]*->)*server->/g_server./g;
s/xwayland->svr/xwayland->server/g;
EOF
find src include \( -name \*.c -o -name \*.h \) -exec \
perl -0777 -i -pe "$EXPRS" \{\} \;
2026-02-23 11:56:39 -05:00
|
|
|
if (g_server.input_mode != LAB_INPUT_STATE_RESIZE) {
|
2023-08-17 18:59:29 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2023-09-22 01:22:19 -04:00
|
|
|
struct view_size_hints hints = view_get_size_hints(view);
|
|
|
|
|
if (hints.width_inc && hints.height_inc) {
|
2023-08-17 18:59:29 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return rc.resize_indicator == LAB_RESIZE_INDICATOR_ALWAYS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
tree-wide: auto-replace of (struct server *)
#!/bin/bash
read -r -d '' EXPRS << EOF
s/xwayland->server/xwayland->svr/g;
s/\t*struct server \*server;\n//g;
s/\t*struct server \*server =.*?;\n//gs;
s/\t*.* = ([a-z_]*->)*server[;,]\n//g;
s/\{\n\n/\{\n/g;
s/\n\n+/\n\n/g;
s/\(\s*struct server \*server\)/(void)/g;
s/\(\s*struct server \*server,\s*/(/g;
s/,\s*struct server \*server\)/)/g;
s/,\s*struct server \*server,\s*/, /g;
s/\(\s*([a-z_]*->)*server\)/()/g;
s/\(\s*([a-z_]*->)*server,\s*/(/g;
s/,\s*([a-z_]*->)*server\)/)/g;
s/,\s*([a-z_]*->)*server,\s*/, /g;
s/([a-z_]*->)*server->/g_server./g;
s/xwayland->svr/xwayland->server/g;
EOF
find src include \( -name \*.c -o -name \*.h \) -exec \
perl -0777 -i -pe "$EXPRS" \{\} \;
2026-02-23 11:56:39 -05:00
|
|
|
resize_indicator_reconfigure(void)
|
2023-08-17 18:59:29 +02:00
|
|
|
{
|
|
|
|
|
struct view *view;
|
tree-wide: auto-replace of (struct server *)
#!/bin/bash
read -r -d '' EXPRS << EOF
s/xwayland->server/xwayland->svr/g;
s/\t*struct server \*server;\n//g;
s/\t*struct server \*server =.*?;\n//gs;
s/\t*.* = ([a-z_]*->)*server[;,]\n//g;
s/\{\n\n/\{\n/g;
s/\n\n+/\n\n/g;
s/\(\s*struct server \*server\)/(void)/g;
s/\(\s*struct server \*server,\s*/(/g;
s/,\s*struct server \*server\)/)/g;
s/,\s*struct server \*server,\s*/, /g;
s/\(\s*([a-z_]*->)*server\)/()/g;
s/\(\s*([a-z_]*->)*server,\s*/(/g;
s/,\s*([a-z_]*->)*server\)/)/g;
s/,\s*([a-z_]*->)*server,\s*/, /g;
s/([a-z_]*->)*server->/g_server./g;
s/xwayland->svr/xwayland->server/g;
EOF
find src include \( -name \*.c -o -name \*.h \) -exec \
perl -0777 -i -pe "$EXPRS" \{\} \;
2026-02-23 11:56:39 -05:00
|
|
|
wl_list_for_each(view, &g_server.views, link) {
|
2023-08-17 18:59:29 +02:00
|
|
|
struct resize_indicator *indicator = &view->resize_indicator;
|
|
|
|
|
if (indicator->tree) {
|
|
|
|
|
resize_indicator_reconfigure_view(indicator);
|
|
|
|
|
}
|
tree-wide: auto-replace of (struct server *)
#!/bin/bash
read -r -d '' EXPRS << EOF
s/xwayland->server/xwayland->svr/g;
s/\t*struct server \*server;\n//g;
s/\t*struct server \*server =.*?;\n//gs;
s/\t*.* = ([a-z_]*->)*server[;,]\n//g;
s/\{\n\n/\{\n/g;
s/\n\n+/\n\n/g;
s/\(\s*struct server \*server\)/(void)/g;
s/\(\s*struct server \*server,\s*/(/g;
s/,\s*struct server \*server\)/)/g;
s/,\s*struct server \*server,\s*/, /g;
s/\(\s*([a-z_]*->)*server\)/()/g;
s/\(\s*([a-z_]*->)*server,\s*/(/g;
s/,\s*([a-z_]*->)*server\)/)/g;
s/,\s*([a-z_]*->)*server,\s*/, /g;
s/([a-z_]*->)*server->/g_server./g;
s/xwayland->svr/xwayland->server/g;
EOF
find src include \( -name \*.c -o -name \*.h \) -exec \
perl -0777 -i -pe "$EXPRS" \{\} \;
2026-02-23 11:56:39 -05:00
|
|
|
if (view != g_server.grabbed_view) {
|
2023-08-17 18:59:29 +02:00
|
|
|
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
|
2025-08-08 12:42:41 +09:00
|
|
|
+ 2 * PADDING
|
2023-08-17 18:59:29 +02:00
|
|
|
+ 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);
|
tree-wide: auto-replace of (struct server *)
#!/bin/bash
read -r -d '' EXPRS << EOF
s/xwayland->server/xwayland->svr/g;
s/\t*struct server \*server;\n//g;
s/\t*struct server \*server =.*?;\n//gs;
s/\t*.* = ([a-z_]*->)*server[;,]\n//g;
s/\{\n\n/\{\n/g;
s/\n\n+/\n\n/g;
s/\(\s*struct server \*server\)/(void)/g;
s/\(\s*struct server \*server,\s*/(/g;
s/,\s*struct server \*server\)/)/g;
s/,\s*struct server \*server,\s*/, /g;
s/\(\s*([a-z_]*->)*server\)/()/g;
s/\(\s*([a-z_]*->)*server,\s*/(/g;
s/,\s*([a-z_]*->)*server\)/)/g;
s/,\s*([a-z_]*->)*server,\s*/, /g;
s/([a-z_]*->)*server->/g_server./g;
s/xwayland->svr/xwayland->server/g;
EOF
find src include \( -name \*.c -o -name \*.h \) -exec \
perl -0777 -i -pe "$EXPRS" \{\} \;
2026-02-23 11:56:39 -05:00
|
|
|
assert(view == g_server.grabbed_view);
|
2023-08-17 18:59:29 +02:00
|
|
|
|
|
|
|
|
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 */
|
|
|
|
|
|
2024-05-29 11:06:39 +09:00
|
|
|
struct wlr_box view_box;
|
|
|
|
|
if (resize_outlines_enabled(view)) {
|
|
|
|
|
view_box = view->resize_outlines.view_geo;
|
|
|
|
|
} else {
|
|
|
|
|
view_box = view->current;
|
|
|
|
|
view_box.height = view_effective_height(view, /* use_pending */ false);
|
|
|
|
|
}
|
2023-08-08 03:39:35 +02:00
|
|
|
|
tree-wide: auto-replace of (struct server *)
#!/bin/bash
read -r -d '' EXPRS << EOF
s/xwayland->server/xwayland->svr/g;
s/\t*struct server \*server;\n//g;
s/\t*struct server \*server =.*?;\n//gs;
s/\t*.* = ([a-z_]*->)*server[;,]\n//g;
s/\{\n\n/\{\n/g;
s/\n\n+/\n\n/g;
s/\(\s*struct server \*server\)/(void)/g;
s/\(\s*struct server \*server,\s*/(/g;
s/,\s*struct server \*server\)/)/g;
s/,\s*struct server \*server,\s*/, /g;
s/\(\s*([a-z_]*->)*server\)/()/g;
s/\(\s*([a-z_]*->)*server,\s*/(/g;
s/,\s*([a-z_]*->)*server\)/)/g;
s/,\s*([a-z_]*->)*server,\s*/, /g;
s/([a-z_]*->)*server->/g_server./g;
s/xwayland->svr/xwayland->server/g;
EOF
find src include \( -name \*.c -o -name \*.h \) -exec \
perl -0777 -i -pe "$EXPRS" \{\} \;
2026-02-23 11:56:39 -05:00
|
|
|
if (g_server.input_mode == LAB_INPUT_STATE_RESIZE) {
|
2023-09-22 01:22:19 -04:00
|
|
|
struct view_size_hints hints = view_get_size_hints(view);
|
2023-08-17 18:59:29 +02:00
|
|
|
snprintf(text, sizeof(text), "%d x %d",
|
2024-05-29 11:06:39 +09:00
|
|
|
MAX(0, view_box.width - hints.base_width)
|
2023-09-22 01:22:19 -04:00
|
|
|
/ MAX(1, hints.width_inc),
|
2024-05-29 11:06:39 +09:00
|
|
|
MAX(0, view_box.height - hints.base_height)
|
2023-09-22 01:22:19 -04:00
|
|
|
/ MAX(1, hints.height_inc));
|
tree-wide: auto-replace of (struct server *)
#!/bin/bash
read -r -d '' EXPRS << EOF
s/xwayland->server/xwayland->svr/g;
s/\t*struct server \*server;\n//g;
s/\t*struct server \*server =.*?;\n//gs;
s/\t*.* = ([a-z_]*->)*server[;,]\n//g;
s/\{\n\n/\{\n/g;
s/\n\n+/\n\n/g;
s/\(\s*struct server \*server\)/(void)/g;
s/\(\s*struct server \*server,\s*/(/g;
s/,\s*struct server \*server\)/)/g;
s/,\s*struct server \*server,\s*/, /g;
s/\(\s*([a-z_]*->)*server\)/()/g;
s/\(\s*([a-z_]*->)*server,\s*/(/g;
s/,\s*([a-z_]*->)*server\)/)/g;
s/,\s*([a-z_]*->)*server,\s*/, /g;
s/([a-z_]*->)*server->/g_server./g;
s/xwayland->svr/xwayland->server/g;
EOF
find src include \( -name \*.c -o -name \*.h \) -exec \
perl -0777 -i -pe "$EXPRS" \{\} \;
2026-02-23 11:56:39 -05:00
|
|
|
} else if (g_server.input_mode == LAB_INPUT_STATE_MOVE) {
|
2023-08-17 18:59:29 +02:00
|
|
|
struct border margin = ssd_get_margin(view->ssd);
|
|
|
|
|
snprintf(text, sizeof(text), "%d , %d",
|
2024-05-29 11:06:39 +09:00
|
|
|
view_box.x - margin.left,
|
|
|
|
|
view_box.y - margin.top);
|
2025-05-22 10:53:58 -04:00
|
|
|
} else {
|
2023-08-17 18:59:29 +02:00
|
|
|
wlr_log(WLR_ERROR, "Invalid input mode for indicator update %u",
|
tree-wide: auto-replace of (struct server *)
#!/bin/bash
read -r -d '' EXPRS << EOF
s/xwayland->server/xwayland->svr/g;
s/\t*struct server \*server;\n//g;
s/\t*struct server \*server =.*?;\n//gs;
s/\t*.* = ([a-z_]*->)*server[;,]\n//g;
s/\{\n\n/\{\n/g;
s/\n\n+/\n\n/g;
s/\(\s*struct server \*server\)/(void)/g;
s/\(\s*struct server \*server,\s*/(/g;
s/,\s*struct server \*server\)/)/g;
s/,\s*struct server \*server,\s*/, /g;
s/\(\s*([a-z_]*->)*server\)/()/g;
s/\(\s*([a-z_]*->)*server,\s*/(/g;
s/,\s*([a-z_]*->)*server\)/)/g;
s/,\s*([a-z_]*->)*server,\s*/, /g;
s/([a-z_]*->)*server->/g_server./g;
s/xwayland->svr/xwayland->server/g;
EOF
find src include \( -name \*.c -o -name \*.h \) -exec \
perl -0777 -i -pe "$EXPRS" \{\} \;
2026-02-23 11:56:39 -05:00
|
|
|
g_server.input_mode);
|
2023-08-17 18:59:29 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Let the indicator change width as required by the content */
|
|
|
|
|
int width = font_width(&rc.font_osd, text);
|
|
|
|
|
|
|
|
|
|
resize_indicator_set_size(indicator, width);
|
|
|
|
|
|
|
|
|
|
/* Center the indicator in the window */
|
2024-05-29 11:06:39 +09:00
|
|
|
int x = view_box.x - view->current.x + (view_box.width - indicator->width) / 2;
|
|
|
|
|
int y = view_box.y - view->current.y + (view_box.height - indicator->height) / 2;
|
|
|
|
|
wlr_scene_node_set_position(&indicator->tree->node, x, y);
|
2023-08-17 18:59:29 +02:00
|
|
|
|
|
|
|
|
scaled_font_buffer_update(indicator->text, text, width, &rc.font_osd,
|
2024-12-03 16:09:40 +09:00
|
|
|
rc.theme->osd_label_text_color, rc.theme->osd_bg_color);
|
2023-08-17 18:59:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|