diff --git a/glfw/glfw3.h b/glfw/glfw3.h index db74dced0..189139be4 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -1683,7 +1683,7 @@ typedef void (* GLFWjoystickfun)(int,int); typedef void (* GLFWuserdatafun)(unsigned long long, void*); typedef void (* GLFWtickcallback)(void*); -typedef void (* GLFWdrawtextfun)(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); /*! @brief Video mode type. * diff --git a/glfw/wl_client_side_decorations.c b/glfw/wl_client_side_decorations.c index 9996fd3d4..bc3e115fb 100644 --- a/glfw/wl_client_side_decorations.c +++ b/glfw/wl_client_side_decorations.c @@ -50,6 +50,9 @@ alloc_buffer_pair(_GLFWWaylandBufferPair *pair, struct wl_shm_pool *pool, uint8_ static void 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; + if (window->wl.title && window->wl.title[0] && _glfw.callbacks.draw_text) { + if (_glfw.callbacks.draw_text((GLFWwindow*)window, window->wl.title, 0, bg_color, output, decs.top.buffer.width, decs.top.buffer.height, 10, 0)) return; + } for (uint32_t *px = (uint32_t*)output, *end = (uint32_t*)(output + decs.top.buffer.size_in_bytes); px < end; px++) { *px = bg_color; } diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 934bb900e..1750e476d 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -817,7 +817,10 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) { - if (window->wl.title) free(window->wl.title); + if (window->wl.title) { + if (title && strcmp(title, window->wl.title) == 0) return; + free(window->wl.title); + } else if (!title) return; // Wayland cannot handle requests larger than ~8200 bytes. Sending // one causes an abort(). Since titles this large are meaningless anyway // ensure they do not happen. diff --git a/kitty/freetype_render_ui_text.c b/kitty/freetype_render_ui_text.c index 9ec2cbf3b..22e7615c3 100644 --- a/kitty/freetype_render_ui_text.c +++ b/kitty/freetype_render_ui_text.c @@ -99,7 +99,7 @@ load_font(FontConfigFace *info, Face *ans) { static bool ensure_state(void) { - if (main_face.freetype && main_face.hb) return false; + if (main_face.freetype && main_face.hb) return true; if (!information_for_font_family(main_face_family.name, main_face_family.bold, main_face_family.italic, &main_face_information)) return false; if (!load_font(&main_face_information, &main_face)) return false; hb_buffer = hb_buffer_create(); @@ -147,6 +147,7 @@ typedef struct RenderState { Face *current_face; float x, y; Region src, dest; + unsigned sz_px; } RenderState; static void @@ -227,7 +228,7 @@ render_run(RenderState *rs) { } FT_Face face = rs->current_face->freetype; bool has_color = FT_HAS_COLOR(face); - FT_UInt pixel_size = 3 * rs->output_height / 4; + FT_UInt pixel_size = rs->sz_px; set_pixel_size(rs->current_face, pixel_size, has_color); hb_shape(rs->current_face->hb, hb_buffer, NULL, 0); unsigned int len = hb_buffer_get_length(hb_buffer); @@ -327,7 +328,7 @@ process_codepoint(RenderState *rs, char_type codep, char_type next_codep) { } bool -render_single_line(const char *text, pixel fg, pixel bg, uint8_t *output_buf, size_t width, size_t height, float x_offset, float y_offset) { +render_single_line(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) { if (!ensure_state()) return false; bool has_text = text && text[0]; pixel pbg = premult_pixel(bg, ((bg >> 24) & 0xff)); @@ -343,7 +344,7 @@ render_single_line(const char *text, pixel fg, pixel bg, uint8_t *output_buf, si text_len = decode_utf8_string(text, text_len, unicode); RenderState rs = { .current_face = &main_face, .fg = fg, .bg = bg, .output_width = width, .output_height = height, - .output = (pixel*)output_buf, .x = x_offset, .y = y_offset + .output = (pixel*)output_buf, .x = x_offset, .y = y_offset, .sz_px = sz_px }; for (size_t i = 0; i < text_len && rs.x < rs.output_width; i++) { @@ -376,7 +377,7 @@ render_line(PyObject *self UNUSED, PyObject *args, PyObject *kw) { PyObject *ans = PyBytes_FromStringAndSize(NULL, width * height * 4); if (!ans) return NULL; uint8_t *buffer = (u_int8_t*) PyBytes_AS_STRING(ans); - if (!render_single_line(text, 0, 0xffffffff, buffer, width, height, x_offset, y_offset)) { + if (!render_single_line(text, 3 * height / 4, 0, 0xffffffff, buffer, width, height, x_offset, y_offset)) { Py_CLEAR(ans); if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError, "Unknown error while rendering text"); ans = NULL; diff --git a/kitty/freetype_render_ui_text.h b/kitty/freetype_render_ui_text.h index 8054b957f..adac89f2b 100644 --- a/kitty/freetype_render_ui_text.h +++ b/kitty/freetype_render_ui_text.h @@ -9,7 +9,7 @@ #include "data-types.h" #include -bool render_single_line(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); +bool render_single_line(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); typedef struct FontConfigFace { char *path; diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index cf4ffaffd..d7bc5b586 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -1421,7 +1421,7 @@ typedef void (* GLFWjoystickfun)(int,int); typedef void (* GLFWuserdatafun)(unsigned long long, void*); typedef void (* GLFWtickcallback)(void*); -typedef void (* GLFWdrawtextfun)(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); /*! @brief Video mode type. * diff --git a/kitty/glfw.c b/kitty/glfw.c index 6e8b87a1f..29e8d7063 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -10,6 +10,9 @@ #include "charsets.h" #include #include "glfw-wrapper.h" +#ifndef __APPLE__ +#include "freetype_render_ui_text.h" +#endif extern bool cocoa_make_window_resizable(void *w, bool); extern void cocoa_focus_window(void *w); extern long cocoa_window_number(void *w); @@ -381,12 +384,25 @@ application_close_requested_callback(int flags) { } } +static inline void get_window_dpi(GLFWwindow *w, double *x, double *y); + #ifdef __APPLE__ static bool apple_file_open_callback(const char* filepath) { set_cocoa_pending_action(OPEN_FILE, filepath); return true; } +#else + +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) { + if (!set_callback_window(window)) return false; + double xdpi, ydpi; + get_window_dpi(window, &xdpi, &ydpi); + unsigned px_sz = (unsigned)(global_state.callback_os_window->font_sz_in_pts * ydpi / 72.); + px_sz = MIN(px_sz, 3 * height / 4); + return render_single_line(text, px_sz, fg, bg, output_buf, width, height, x_offset, y_offset); +} #endif // }}} @@ -855,6 +871,8 @@ glfw_init(PyObject UNUSED *self, PyObject *args) { if (ans == Py_True) { #ifdef __APPLE__ glfwSetCocoaFileOpenCallback(apple_file_open_callback); +#else + glfwSetDrawTextFunction(draw_text_callback); #endif OSWindow w = {0}; set_os_window_dpi(&w);