mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-23 00:38:10 +02:00
Allow specifying a right_margin that is not rendered for the CSD title
Can void double rendering if I ever decide to add button to the titlebar
This commit is contained in:
2
glfw/glfw3.h
vendored
2
glfw/glfw3.h
vendored
@@ -1683,7 +1683,7 @@ typedef void (* GLFWjoystickfun)(int,int);
|
|||||||
|
|
||||||
typedef void (* GLFWuserdatafun)(unsigned long long, void*);
|
typedef void (* GLFWuserdatafun)(unsigned long long, void*);
|
||||||
typedef void (* GLFWtickcallback)(void*);
|
typedef void (* GLFWtickcallback)(void*);
|
||||||
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);
|
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);
|
||||||
|
|
||||||
/*! @brief Video mode type.
|
/*! @brief Video mode type.
|
||||||
*
|
*
|
||||||
|
|||||||
2
glfw/wl_client_side_decorations.c
vendored
2
glfw/wl_client_side_decorations.c
vendored
@@ -55,7 +55,7 @@ render_title_bar(_GLFWwindow *window, bool to_front_buffer) {
|
|||||||
uint8_t *output = to_front_buffer ? decs.top.buffer.data.front : decs.top.buffer.data.back;
|
uint8_t *output = to_front_buffer ? decs.top.buffer.data.front : decs.top.buffer.data.back;
|
||||||
if (window->wl.title && window->wl.title[0] && _glfw.callbacks.draw_text) {
|
if (window->wl.title && window->wl.title[0] && _glfw.callbacks.draw_text) {
|
||||||
uint32_t fg_color = is_focused ? 0xff444444 : 0xff888888;
|
uint32_t fg_color = is_focused ? 0xff444444 : 0xff888888;
|
||||||
if (_glfw.callbacks.draw_text((GLFWwindow*)window, window->wl.title, fg_color, bg_color, output, decs.top.buffer.width, decs.top.buffer.height, 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, 0, 0, 0)) return;
|
||||||
}
|
}
|
||||||
for (uint32_t *px = (uint32_t*)output, *end = (uint32_t*)(output + decs.top.buffer.size_in_bytes); px < end; px++) {
|
for (uint32_t *px = (uint32_t*)output, *end = (uint32_t*)(output + decs.top.buffer.size_in_bytes); px < end; px++) {
|
||||||
*px = bg_color;
|
*px = bg_color;
|
||||||
|
|||||||
@@ -98,19 +98,6 @@ get_load_flags(int hinting, int hintstyle, int base) {
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned int
|
|
||||||
width_for_char(Face *face, char_type ch) {
|
|
||||||
unsigned int ans = 0;
|
|
||||||
int glyph_index = FT_Get_Char_Index(face->freetype, ch);
|
|
||||||
if (glyph_index) {
|
|
||||||
int error = FT_Load_Glyph(face->freetype, glyph_index, get_load_flags(face->hinting, face->hintstyle, FT_LOAD_DEFAULT));
|
|
||||||
if (!error) {
|
|
||||||
ans = (unsigned int)ceilf((float)face->freetype->glyph->metrics.horiAdvance / 64.f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ans;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
load_font(FontConfigFace *info, Face *ans) {
|
load_font(FontConfigFace *info, Face *ans) {
|
||||||
ans->freetype = native_face_from_path(info->path, info->index);
|
ans->freetype = native_face_from_path(info->path, info->index);
|
||||||
@@ -159,7 +146,7 @@ set_pixel_size(RenderCtx *ctx, Face *face, FT_UInt sz, bool get_metrics UNUSED)
|
|||||||
typedef struct RenderState {
|
typedef struct RenderState {
|
||||||
uint32_t pending_in_buffer, fg, bg;
|
uint32_t pending_in_buffer, fg, bg;
|
||||||
pixel *output;
|
pixel *output;
|
||||||
size_t output_width, output_height;
|
size_t output_width, output_height, stride;
|
||||||
Face *current_face;
|
Face *current_face;
|
||||||
float x, y;
|
float x, y;
|
||||||
int y_offset;
|
int y_offset;
|
||||||
@@ -207,7 +194,7 @@ alpha_blend_premult(pixel over, pixel under) {
|
|||||||
static void
|
static void
|
||||||
render_color_bitmap(ProcessedBitmap *src, RenderState *rs) {
|
render_color_bitmap(ProcessedBitmap *src, RenderState *rs) {
|
||||||
for (size_t sr = rs->src.top, dr = rs->dest.top; sr < rs->src.bottom && dr < rs->dest.bottom; sr++, dr++) {
|
for (size_t sr = rs->src.top, dr = rs->dest.top; sr < rs->src.bottom && dr < rs->dest.bottom; sr++, dr++) {
|
||||||
pixel *dest_row = rs->output + rs->output_width * dr;
|
pixel *dest_row = rs->output + rs->stride * dr;
|
||||||
uint8_t *src_px = src->buf + src->stride * sr + 4 * rs->src.left;
|
uint8_t *src_px = src->buf + src->stride * sr + 4 * rs->src.left;
|
||||||
for (size_t sc = rs->src.left, dc = rs->dest.left; sc < rs->src.right && dc < rs->dest.right; sc++, dc++, src_px += 4) {
|
for (size_t sc = rs->src.left, dc = rs->dest.left; sc < rs->src.right && dc < rs->dest.right; sc++, dc++, src_px += 4) {
|
||||||
pixel fg = premult_pixel(ARGB(src_px[3], src_px[2], src_px[1], src_px[0]), src_px[3]);
|
pixel fg = premult_pixel(ARGB(src_px[3], src_px[2], src_px[1], src_px[0]), src_px[3]);
|
||||||
@@ -219,7 +206,7 @@ render_color_bitmap(ProcessedBitmap *src, RenderState *rs) {
|
|||||||
static void
|
static void
|
||||||
render_gray_bitmap(ProcessedBitmap *src, RenderState *rs) {
|
render_gray_bitmap(ProcessedBitmap *src, RenderState *rs) {
|
||||||
for (size_t sr = rs->src.top, dr = rs->dest.top; sr < rs->src.bottom && dr < rs->dest.bottom; sr++, dr++) {
|
for (size_t sr = rs->src.top, dr = rs->dest.top; sr < rs->src.bottom && dr < rs->dest.bottom; sr++, dr++) {
|
||||||
pixel *dest_row = rs->output + rs->output_width * dr;
|
pixel *dest_row = rs->output + rs->stride * dr;
|
||||||
uint8_t *src_row = src->buf + src->stride * sr;
|
uint8_t *src_row = src->buf + src->stride * sr;
|
||||||
for (size_t sc = rs->src.left, dc = rs->dest.left; sc < rs->src.right && dc < rs->dest.right; sc++, dc++) {
|
for (size_t sc = rs->src.left, dc = rs->dest.left; sc < rs->src.right && dc < rs->dest.right; sc++, dc++) {
|
||||||
pixel fg = premult_pixel(rs->fg, src_row[sc]);
|
pixel fg = premult_pixel(rs->fg, src_row[sc]);
|
||||||
@@ -439,12 +426,16 @@ process_codepoint(RenderCtx *ctx, RenderState *rs, char_type codep, char_type ne
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
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) {
|
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) {
|
||||||
RenderCtx *ctx = (RenderCtx*)ctx_;
|
RenderCtx *ctx = (RenderCtx*)ctx_;
|
||||||
if (!ctx->created) return false;
|
if (!ctx->created) return false;
|
||||||
|
size_t output_width = right_margin <= width ? width - right_margin : 0;
|
||||||
bool has_text = text && text[0];
|
bool has_text = text && text[0];
|
||||||
pixel pbg = premult_pixel(bg, ((bg >> 24) & 0xff));
|
pixel pbg = premult_pixel(bg, ((bg >> 24) & 0xff));
|
||||||
for (pixel *px = (pixel*)output_buf, *end = ((pixel*)output_buf) + width * height; px < end; px++) *px = pbg;
|
for (size_t y = 0; y < height; y++) {
|
||||||
|
pixel *px = (pixel*)(output_buf + 4 * y * width);
|
||||||
|
for (size_t x = (size_t)x_offset; x < output_width; x++) px[x] = pbg;
|
||||||
|
}
|
||||||
if (!has_text) return true;
|
if (!has_text) return true;
|
||||||
hb_buffer_clear_contents(hb_buffer);
|
hb_buffer_clear_contents(hb_buffer);
|
||||||
if (!hb_buffer_pre_allocate(hb_buffer, 512)) { PyErr_NoMemory(); return false; }
|
if (!hb_buffer_pre_allocate(hb_buffer, 512)) { PyErr_NoMemory(); return false; }
|
||||||
@@ -457,7 +448,8 @@ render_single_line(FreeTypeRenderCtx ctx_, const char *text, unsigned sz_px, pix
|
|||||||
set_pixel_size(ctx, &main_face, sz_px, true);
|
set_pixel_size(ctx, &main_face, sz_px, true);
|
||||||
unsigned text_height = font_units_to_pixels_y(main_face.freetype, main_face.freetype->height);
|
unsigned text_height = font_units_to_pixels_y(main_face.freetype, main_face.freetype->height);
|
||||||
RenderState rs = {
|
RenderState rs = {
|
||||||
.current_face = &main_face, .fg = fg, .bg = bg, .output_width = width, .output_height = height,
|
.current_face = &main_face, .fg = fg, .bg = bg,
|
||||||
|
.output_width = output_width, .output_height = height, .stride = width,
|
||||||
.output = (pixel*)output_buf, .x = x_offset, .y = y_offset, .sz_px = sz_px
|
.output = (pixel*)output_buf, .x = x_offset, .y = y_offset, .sz_px = sz_px
|
||||||
};
|
};
|
||||||
if (text_height < height) rs.y_offset = (height - text_height) / 2;
|
if (text_height < height) rs.y_offset = (height - text_height) / 2;
|
||||||
@@ -504,18 +496,18 @@ render_line(PyObject *self UNUSED, PyObject *args, PyObject *kw) {
|
|||||||
// use for testing as below
|
// use for testing as below
|
||||||
// kitty +runpy "from kitty.fast_data_types import *; open('/tmp/test.rgba', 'wb').write(freetype_render_line())" && convert -size 800x60 -depth 8 /tmp/test.rgba /tmp/test.png && icat /tmp/test.png
|
// kitty +runpy "from kitty.fast_data_types import *; open('/tmp/test.rgba', 'wb').write(freetype_render_line())" && convert -size 800x60 -depth 8 /tmp/test.rgba /tmp/test.png && icat /tmp/test.png
|
||||||
const char *text = "Test 猫 H🐱🚀b rendering with ellipsis for cut off text", *family = NULL;
|
const char *text = "Test 猫 H🐱🚀b rendering with ellipsis for cut off text", *family = NULL;
|
||||||
unsigned int width = 800, height = 60;
|
unsigned int width = 800, height = 60, right_margin = 0;
|
||||||
int bold = 0, italic = 0;
|
int bold = 0, italic = 0;
|
||||||
unsigned long fg = 0, bg = 0xfffefefe;
|
unsigned long fg = 0, bg = 0xfffefefe;
|
||||||
float x_offset = 0, y_offset = 0;
|
float x_offset = 0, y_offset = 0;
|
||||||
static const char* kwlist[] = {"text", "width", "height", "font_family", "bold", "italic", "fg", "bg", "x_offset", "y_offset", NULL};
|
static const char* kwlist[] = {"text", "width", "height", "font_family", "bold", "italic", "fg", "bg", "x_offset", "y_offset", "right_margin", NULL};
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "|sIIzppkkff", (char**)kwlist, &text, &width, &height, &family, &bold, &italic, &fg, &bg, &x_offset, &y_offset)) return NULL;
|
if (!PyArg_ParseTupleAndKeywords(args, kw, "|sIIzppkkffI", (char**)kwlist, &text, &width, &height, &family, &bold, &italic, &fg, &bg, &x_offset, &y_offset, &right_margin)) return NULL;
|
||||||
PyObject *ans = PyBytes_FromStringAndSize(NULL, width * height * 4);
|
PyObject *ans = PyBytes_FromStringAndSize(NULL, width * height * 4);
|
||||||
if (!ans) return NULL;
|
if (!ans) return NULL;
|
||||||
uint8_t *buffer = (u_int8_t*) PyBytes_AS_STRING(ans);
|
uint8_t *buffer = (u_int8_t*) PyBytes_AS_STRING(ans);
|
||||||
RenderCtx *ctx = (RenderCtx*)create_freetype_render_context(family, bold, italic);
|
RenderCtx *ctx = (RenderCtx*)create_freetype_render_context(family, bold, italic);
|
||||||
if (!ctx) return NULL;
|
if (!ctx) return NULL;
|
||||||
if (!render_single_line((FreeTypeRenderCtx)ctx, text, 3 * height / 4, 0, 0xffffffff, buffer, width, height, x_offset, y_offset)) {
|
if (!render_single_line((FreeTypeRenderCtx)ctx, text, 3 * height / 4, 0, 0xffffffff, buffer, width, height, x_offset, y_offset, right_margin)) {
|
||||||
Py_CLEAR(ans);
|
Py_CLEAR(ans);
|
||||||
if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError, "Unknown error while rendering text");
|
if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError, "Unknown error while rendering text");
|
||||||
ans = NULL;
|
ans = NULL;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ typedef struct {bool created;} *FreeTypeRenderCtx;
|
|||||||
|
|
||||||
FreeTypeRenderCtx create_freetype_render_context(const char *family, bool bold, bool italic);
|
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);
|
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);
|
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);
|
||||||
void release_freetype_render_context(FreeTypeRenderCtx ctx);
|
void release_freetype_render_context(FreeTypeRenderCtx ctx);
|
||||||
|
|
||||||
typedef struct FontConfigFace {
|
typedef struct FontConfigFace {
|
||||||
|
|||||||
2
kitty/glfw-wrapper.h
generated
2
kitty/glfw-wrapper.h
generated
@@ -1421,7 +1421,7 @@ typedef void (* GLFWjoystickfun)(int,int);
|
|||||||
|
|
||||||
typedef void (* GLFWuserdatafun)(unsigned long long, void*);
|
typedef void (* GLFWuserdatafun)(unsigned long long, void*);
|
||||||
typedef void (* GLFWtickcallback)(void*);
|
typedef void (* GLFWtickcallback)(void*);
|
||||||
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);
|
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);
|
||||||
|
|
||||||
/*! @brief Video mode type.
|
/*! @brief Video mode type.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -398,7 +398,7 @@ apple_file_open_callback(const char* filepath) {
|
|||||||
static FreeTypeRenderCtx csd_title_render_ctx = NULL;
|
static FreeTypeRenderCtx csd_title_render_ctx = NULL;
|
||||||
|
|
||||||
static bool
|
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) {
|
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) {
|
||||||
if (!set_callback_window(window)) return false;
|
if (!set_callback_window(window)) return false;
|
||||||
if (!csd_title_render_ctx) {
|
if (!csd_title_render_ctx) {
|
||||||
csd_title_render_ctx = create_freetype_render_context(NULL, true, false);
|
csd_title_render_ctx = create_freetype_render_context(NULL, true, false);
|
||||||
@@ -413,7 +413,7 @@ draw_text_callback(GLFWwindow *window, const char *text, uint32_t fg, uint32_t b
|
|||||||
px_sz = MIN(px_sz, 3 * height / 4);
|
px_sz = MIN(px_sz, 3 * height / 4);
|
||||||
static char title[2048];
|
static char title[2048];
|
||||||
snprintf(title, sizeof(title), "🐱 %s", text);
|
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);
|
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 (!ok && PyErr_Occurred()) PyErr_Print();
|
if (!ok && PyErr_Occurred()) PyErr_Print();
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user