Implement rendering of window control buttons in CSD

They still need to be wired up
This commit is contained in:
Kovid Goyal
2024-04-06 08:23:07 +05:30
parent 416d52bdac
commit 4f6faddbab
9 changed files with 93 additions and 20 deletions

2
glfw/glfw3.h vendored
View File

@@ -1785,7 +1785,7 @@ typedef void (* GLFWjoystickfun)(int,int);
typedef void (* GLFWuserdatafun)(unsigned long long, void*);
typedef void (* GLFWtickcallback)(void*);
typedef void (* GLFWactivationcallback)(GLFWwindow *window, const char *token, void *data);
typedef bool (* GLFWdrawtextfun)(GLFWwindow *window, const char *text, uint32_t fg, uint32_t bg, uint8_t *output_buf, size_t width, size_t height, float x_offset, float y_offset, size_t right_margin);
typedef bool (* GLFWdrawtextfun)(GLFWwindow *window, const char *text, uint32_t fg, uint32_t bg, uint8_t *output_buf, size_t width, size_t height, float x_offset, float y_offset, size_t right_margin, bool is_single_glyph);
typedef char* (* GLFWcurrentselectionfun)(void);
typedef bool (* GLFWhascurrentselectionfun)(void);
typedef void (* GLFWclipboarddatafreefun)(void* data);

View File

@@ -164,9 +164,10 @@ create_shadow_tile(_GLFWwindow *window) {
static void
render_title_bar(_GLFWwindow *window, bool to_front_buffer) {
const bool is_focused = window->id == _glfw.focusedWindowId;
uint32_t light_fg = is_focused ? 0xff444444 : 0xff888888, light_bg = is_focused ? 0xffdddad6 : 0xffeeeeee;
uint32_t dark_fg = is_focused ? 0xffffffff : 0xffcccccc, dark_bg = is_focused ? 0xff303030 : 0xff242424;
uint32_t bg_color = light_bg, fg_color = light_fg;
const uint32_t light_fg = is_focused ? 0xff444444 : 0xff888888, light_bg = is_focused ? 0xffdddad6 : 0xffeeeeee;
const uint32_t dark_fg = is_focused ? 0xffffffff : 0xffcccccc, dark_bg = is_focused ? 0xff303030 : 0xff242424;
static const uint32_t hover_dark_bg = 0xff444444, hover_light_bg = 0xffcccccc;
uint32_t bg_color = light_bg, fg_color = light_fg, hover_bg = hover_light_bg;
GLFWColorScheme appearance = glfwGetCurrentSystemColorTheme();
if (decs.use_custom_titlebar_color || appearance == GLFW_COLOR_SCHEME_NO_PREFERENCE) {
bg_color = 0xff000000 | (decs.titlebar_color & 0xffffff);
@@ -174,7 +175,7 @@ render_title_bar(_GLFWwindow *window, bool to_front_buffer) {
double green = ((bg_color >> 8) & 0xFF) / 255.0;
double blue = (bg_color & 0xFF) / 255.0;
double luma = 0.2126 * red + 0.7152 * green + 0.0722 * blue;
if (luma < 0.5) fg_color = dark_fg;
if (luma < 0.5) { fg_color = dark_fg; hover_bg = hover_dark_bg; }
if (!decs.use_custom_titlebar_color) bg_color = luma < 0.5 ? dark_bg : light_bg;
} else if (appearance == GLFW_COLOR_SCHEME_DARK) { bg_color = dark_bg; fg_color = dark_fg; }
uint8_t *output = to_front_buffer ? decs.top.buffer.data.front : decs.top.buffer.data.back;
@@ -198,12 +199,30 @@ render_title_bar(_GLFWwindow *window, bool to_front_buffer) {
}
// render text part
int button_size = (int)roundf(decs.metrics.visible_titlebar_height * decs.for_window_state.fscale);
int num_buttons = 1;
if (window->wl.wm_capabilities.maximize) num_buttons++;
if (window->wl.wm_capabilities.minimize) num_buttons++;
output += decs.top.buffer.stride * margin;
if (window->wl.title && window->wl.title[0] && _glfw.callbacks.draw_text) {
if (_glfw.callbacks.draw_text((GLFWwindow*)window, window->wl.title, fg_color, bg_color, output, decs.top.buffer.width, decs.top.buffer.height - margin, 0, 0, 0)) return;
if (_glfw.callbacks.draw_text((GLFWwindow*)window, window->wl.title, fg_color, bg_color, output, decs.top.buffer.width, decs.top.buffer.height - margin, 0, 0, num_buttons * button_size, false)) goto render_buttons;
}
// rendering of text failed, blank the buffer
for (uint32_t *px = (uint32_t*)output, *end = (uint32_t*)(output + decs.top.buffer.size_in_bytes); px < end; px++) *px = bg_color;
render_buttons:
decs.maximize.width = 0; decs.minimize.width = 0; decs.close.width = 0;
if (!button_size) return;
int left = decs.top.buffer.width - num_buttons * button_size;
#define draw(which, text, hover_bg) { \
_glfw.callbacks.draw_text((GLFWwindow*)window, text, fg_color, decs.which.hovered ? hover_bg : bg_color, output, decs.top.buffer.width, \
decs.top.buffer.height - margin, /*x=*/left, /*y=*/0, /*right_margin=*/decs.top.buffer.width - left - button_size, true); \
decs.which.left = left; decs.which.width = button_size; left += button_size; \
}
if (window->wl.wm_capabilities.minimize) draw(minimize, "🗕", hover_bg);
if (window->wl.wm_capabilities.maximize) draw(maximize, "🗖", hover_bg);
draw(close, "🗙", 0xffff0000);
#undef draw
}
static void

6
glfw/wl_init.c vendored
View File

@@ -675,8 +675,10 @@ static void registryHandleGlobal(void* data UNUSED,
}
else if (is(xdg_wm_base))
{
_glfw.wl.wmBase =
wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
#ifdef XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION
version = min(XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION, version);
#endif
_glfw.wl.wmBase = wl_registry_bind(registry, name, &xdg_wm_base_interface, version);
xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL);
}
else if (is(zxdg_decoration_manager_v1))

10
glfw/wl_platform.h vendored
View File

@@ -166,6 +166,7 @@ typedef struct _GLFWwindowWayland
struct xdg_surface* surface;
struct xdg_toplevel* toplevel;
struct zxdg_toplevel_decoration_v1* decoration;
struct { int width, height; } top_level_bounds;
} xdg;
struct wp_fractional_scale_v1 *wp_fractional_scale_v1;
struct wp_viewport *wp_viewport;
@@ -224,6 +225,10 @@ typedef struct _GLFWwindowWayland
int32_t x, y, width, height;
} geometry;
struct {
bool hovered;
int width, left;
} minimize, maximize, close;
struct {
uint32_t *data;
size_t for_decoration_size, stride, segments, corner_size;
@@ -244,6 +249,11 @@ typedef struct _GLFWwindowWayland
int32_t width, height;
} user_requested_content_size;
struct {
bool minimize, maximize, fullscreen, window_menu;
} wm_capabilities;
bool maximize_on_first_show;
// counters for ignoring axis events following axis_discrete events in the
// same frame along the same axis

37
glfw/wl_window.c vendored
View File

@@ -696,9 +696,42 @@ static void xdgToplevelHandleClose(void* data,
_glfwInputWindowCloseRequest(window);
}
#if defined(XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION)
static void
xdg_toplevel_wm_capabilities(void *data, struct xdg_toplevel *xdg_toplevel UNUSED, struct wl_array *caps) {
_GLFWwindow *window = data;
#define c (window->wl.wm_capabilities)
memset(&c, 0, sizeof(c));
enum xdg_toplevel_wm_capabilities *cap;
wl_array_for_each(cap, caps) {
switch (*cap) {
case XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE: c.maximize = true; break;
case XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE: c.minimize = true; break;
case XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU: c.window_menu = true; break;
case XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN: c.fullscreen = true; break;
}
}
debug("Compositor top-level capabilities: maximize=%d minimize=%d window_menu=%d fullscreen=%d\n",
c.maximize, c.minimize, c.window_menu, c.fullscreen);
#undef c
}
#endif
static void
xdg_toplevel_configure_bounds(void *data, struct xdg_toplevel *xdg_toplevel UNUSED, int32_t width, int32_t height) {
_GLFWwindow *window = data;
window->wl.xdg.top_level_bounds.width = width;
window->wl.xdg.top_level_bounds.height = height;
}
static const struct xdg_toplevel_listener xdgToplevelListener = {
xdgToplevelHandleConfigure,
xdgToplevelHandleClose
.configure = xdgToplevelHandleConfigure,
.close = xdgToplevelHandleClose,
#ifdef XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION
.configure_bounds = xdg_toplevel_configure_bounds,
.wm_capabilities = xdg_toplevel_wm_capabilities,
#endif
};
static void