Implement rendering of window control buttons in CSD
They still need to be wired up
This commit is contained in:
parent
416d52bdac
commit
4f6faddbab
9 changed files with 93 additions and 20 deletions
2
glfw/glfw3.h
vendored
2
glfw/glfw3.h
vendored
|
|
@ -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);
|
||||
|
|
|
|||
29
glfw/wl_client_side_decorations.c
vendored
29
glfw/wl_client_side_decorations.c
vendored
|
|
@ -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
6
glfw/wl_init.c
vendored
|
|
@ -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
10
glfw/wl_platform.h
vendored
|
|
@ -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
37
glfw/wl_window.c
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -148,11 +148,12 @@ typedef struct RenderState {
|
|||
pixel *output;
|
||||
size_t output_width, output_height, stride;
|
||||
Face *current_face;
|
||||
float x, y;
|
||||
float x, y, start_pos_for_current_run;
|
||||
int y_offset;
|
||||
Region src, dest;
|
||||
unsigned sz_px;
|
||||
bool truncated;
|
||||
bool horizontally_center;
|
||||
} RenderState;
|
||||
|
||||
static void
|
||||
|
|
@ -162,6 +163,10 @@ setup_regions(ProcessedBitmap *bm, RenderState *rs, int baseline) {
|
|||
int xoff = (int)(rs->x + bm->bitmap_left);
|
||||
if (xoff < 0) rs->src.left += -xoff;
|
||||
else rs->dest.left = xoff;
|
||||
if (rs->horizontally_center) {
|
||||
int run_width = (int)(rs->output_width - rs->start_pos_for_current_run);
|
||||
rs->dest.left = (int)rs->start_pos_for_current_run + (run_width > (int)bm->width ? (run_width - bm->width)/2 : 0);
|
||||
}
|
||||
int yoff = (int)(rs->y + bm->bitmap_top);
|
||||
if ((yoff > 0 && yoff > baseline)) {
|
||||
rs->dest.top = 0;
|
||||
|
|
@ -325,6 +330,7 @@ render_run(RenderCtx *ctx, RenderState *rs) {
|
|||
rs->truncated = true;
|
||||
}
|
||||
|
||||
rs->start_pos_for_current_run = rs->x;
|
||||
for (unsigned int i = 0; i < limit; i++) {
|
||||
rs->x += (float)positions[i].x_offset / 64.0f;
|
||||
rs->y += (float)positions[i].y_offset / 64.0f;
|
||||
|
|
@ -427,7 +433,7 @@ process_codepoint(RenderCtx *ctx, RenderState *rs, char_type codep, char_type ne
|
|||
}
|
||||
|
||||
bool
|
||||
render_single_line(FreeTypeRenderCtx ctx_, const char *text, unsigned sz_px, pixel fg, pixel bg, uint8_t *output_buf, size_t width, size_t height, float x_offset, float y_offset, size_t right_margin) {
|
||||
render_single_line(FreeTypeRenderCtx ctx_, const char *text, unsigned sz_px, pixel fg, pixel bg, uint8_t *output_buf, size_t width, size_t height, float x_offset, float y_offset, size_t right_margin, bool horizontally_center_runs) {
|
||||
RenderCtx *ctx = (RenderCtx*)ctx_;
|
||||
if (!ctx->created) return false;
|
||||
size_t output_width = right_margin <= width ? width - right_margin : 0;
|
||||
|
|
@ -449,7 +455,7 @@ render_single_line(FreeTypeRenderCtx ctx_, const char *text, unsigned sz_px, pix
|
|||
set_pixel_size(ctx, &main_face, sz_px, true);
|
||||
unsigned text_height = font_units_to_pixels_y(main_face.freetype, main_face.freetype->height);
|
||||
RenderState rs = {
|
||||
.current_face = &main_face, .fg = fg, .bg = bg,
|
||||
.current_face = &main_face, .fg = fg, .bg = bg, .horizontally_center = horizontally_center_runs,
|
||||
.output_width = output_width, .output_height = height, .stride = width,
|
||||
.output = (pixel*)output_buf, .x = x_offset, .y = y_offset, .sz_px = sz_px
|
||||
};
|
||||
|
|
@ -584,7 +590,7 @@ render_line(PyObject *self UNUSED, PyObject *args, PyObject *kw) {
|
|||
uint8_t *buffer = (uint8_t*) PyBytes_AS_STRING(ans);
|
||||
RenderCtx *ctx = (RenderCtx*)create_freetype_render_context(family, bold, italic);
|
||||
if (!ctx) return NULL;
|
||||
if (!render_single_line((FreeTypeRenderCtx)ctx, text, 3 * height / 4, 0, 0xffffffff, buffer, width, height, x_offset, y_offset, right_margin)) {
|
||||
if (!render_single_line((FreeTypeRenderCtx)ctx, text, 3 * height / 4, 0, 0xffffffff, buffer, width, height, x_offset, y_offset, right_margin, false)) {
|
||||
Py_CLEAR(ans);
|
||||
if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError, "Unknown error while rendering text");
|
||||
ans = NULL;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ typedef struct {bool created;} *FreeTypeRenderCtx;
|
|||
|
||||
FreeTypeRenderCtx create_freetype_render_context(const char *family, bool bold, bool italic);
|
||||
void set_main_face_family(FreeTypeRenderCtx ctx, const char *family, bool bold, bool italic);
|
||||
bool render_single_line(FreeTypeRenderCtx ctx, const char *text, unsigned sz_px, 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 render_single_line(FreeTypeRenderCtx ctx, const char *text, unsigned sz_px, 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 horizontally_center_runs);
|
||||
uint8_t* render_single_ascii_char_as_mask(FreeTypeRenderCtx ctx_, const char ch, size_t *result_width, size_t *result_height);
|
||||
void release_freetype_render_context(FreeTypeRenderCtx ctx);
|
||||
|
||||
|
|
|
|||
2
kitty/glfw-wrapper.h
generated
2
kitty/glfw-wrapper.h
generated
|
|
@ -1523,7 +1523,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);
|
||||
|
|
|
|||
11
kitty/glfw.c
11
kitty/glfw.c
|
|
@ -663,7 +663,7 @@ ensure_csd_title_render_ctx(void) {
|
|||
}
|
||||
|
||||
static bool
|
||||
draw_text_callback(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) {
|
||||
draw_text_callback(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) {
|
||||
if (!set_callback_window(window)) return false;
|
||||
if (!ensure_csd_title_render_ctx()) return false;
|
||||
double xdpi, ydpi;
|
||||
|
|
@ -671,8 +671,11 @@ draw_text_callback(GLFWwindow *window, const char *text, uint32_t fg, uint32_t b
|
|||
unsigned px_sz = (unsigned)(global_state.callback_os_window->fonts_data->font_sz_in_pts * ydpi / 72.);
|
||||
px_sz = MIN(px_sz, 3 * height / 4);
|
||||
static char title[2048];
|
||||
snprintf(title, sizeof(title), " ❭ %s", text);
|
||||
bool ok = render_single_line(csd_title_render_ctx, title, px_sz, fg, bg, output_buf, width, height, x_offset, y_offset, right_margin);
|
||||
if (!is_single_glyph) {
|
||||
snprintf(title, sizeof(title), " ❭ %s", text);
|
||||
text = title;
|
||||
}
|
||||
bool ok = render_single_line(csd_title_render_ctx, text, px_sz, fg, bg, output_buf, width, height, x_offset, y_offset, right_margin, is_single_glyph);
|
||||
if (!ok && PyErr_Occurred()) PyErr_Print();
|
||||
return ok;
|
||||
}
|
||||
|
|
@ -685,7 +688,7 @@ draw_window_title(OSWindow *window, const char *text, color_type fg, color_type
|
|||
unsigned px_sz = (unsigned)(window->fonts_data->font_sz_in_pts * window->fonts_data->logical_dpi_y / 72.);
|
||||
px_sz = MIN(px_sz, 3 * height / 4);
|
||||
#define RGB2BGR(x) (x & 0xFF000000) | ((x & 0xFF0000) >> 16) | (x & 0x00FF00) | ((x & 0x0000FF) << 16)
|
||||
bool ok = render_single_line(csd_title_render_ctx, buf, px_sz, RGB2BGR(fg), RGB2BGR(bg), output_buf, width, height, 0, 0, 0);
|
||||
bool ok = render_single_line(csd_title_render_ctx, buf, px_sz, RGB2BGR(fg), RGB2BGR(bg), output_buf, width, height, 0, 0, 0, false);
|
||||
#undef RGB2BGR
|
||||
if (!ok && PyErr_Occurred()) PyErr_Print();
|
||||
return ok;
|
||||
|
|
|
|||
Loading…
Reference in a new issue