diff --git a/kitty/data-types.c b/kitty/data-types.c index 890f86ba1..ed0e9f0a6 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -216,6 +216,7 @@ extern bool init_cocoa(PyObject *module); extern bool init_macos_process_info(PyObject *module); #else extern bool init_freetype_library(PyObject*); +extern bool init_freetype_render_ui_text(PyObject*); #endif @@ -253,6 +254,7 @@ PyInit_fast_data_types(void) { if (!init_freetype_library(m)) return NULL; if (!init_fontconfig_library(m)) return NULL; if (!init_desktop(m)) return NULL; + if (!init_freetype_render_ui_text(m)) return NULL; #endif if (!init_fonts(m)) return NULL; diff --git a/kitty/fontconfig.c b/kitty/fontconfig.c index 71ef72137..7bfacf1ac 100644 --- a/kitty/fontconfig.c +++ b/kitty/fontconfig.c @@ -168,6 +168,31 @@ end: if (charset != NULL) FcCharSetDestroy(charset); } +const char* +file_path_for_font(const char *family, bool bold, bool italic) { + const char *ans = NULL; + FcPattern *match = NULL; + FcPattern *pat = FcPatternCreate(); + if (pat == NULL) { PyErr_NoMemory(); return NULL; } + if (family && strlen(family) > 0) AP(FcPatternAddString, FC_FAMILY, (const FcChar8*)family, "family"); + if (bold) { AP(FcPatternAddInteger, FC_WEIGHT, FC_WEIGHT_BOLD, "weight"); } + if (italic) { AP(FcPatternAddInteger, FC_SLANT, FC_SLANT_ITALIC, "slant"); } + FcResult result; + FcConfigSubstitute(NULL, pat, FcMatchPattern); + FcDefaultSubstitute(pat); + match = FcFontMatch(NULL, pat, &result); + if (match == NULL) { PyErr_SetString(PyExc_KeyError, "FcFontMatch() failed"); goto end; } + FcChar8 *out; + if (FcPatternGetString(pat, FC_FILE, 0, &out) != FcResultMatch) { PyErr_SetString(PyExc_ValueError, "No path found in fontconfig result"); goto end; } + ans = strdup((char*)out); + if (!ans) { PyErr_NoMemory(); goto end; } +end: + if (match != NULL) FcPatternDestroy(match); + if (pat != NULL) FcPatternDestroy(pat); + return ans; +} + + static PyObject* fc_match(PyObject UNUSED *self, PyObject *args) { char *family = NULL; diff --git a/kitty/fonts.h b/kitty/fonts.h index 7a9cb6f21..a4524670e 100644 --- a/kitty/fonts.h +++ b/kitty/fonts.h @@ -50,3 +50,8 @@ right_shift_canvas(pixel *canvas, size_t width, size_t height, size_t amt) { zero_at_ptr_count(src, amt); } } + + +#ifndef __APPLE__ +const char* file_path_for_font(const char *family, bool bold, bool italic); +#endif diff --git a/kitty/freetype_render_ui_text.c b/kitty/freetype_render_ui_text.c new file mode 100644 index 000000000..d2599290d --- /dev/null +++ b/kitty/freetype_render_ui_text.c @@ -0,0 +1,31 @@ +/* + * freetype_render_ui_text.c + * Copyright (C) 2021 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ + +#include "data-types.h" +#include "fonts.h" + +static PyObject* +path_for_font(PyObject *self UNUSED, PyObject *args) { + const char *family = NULL; int bold = 0, italic = 0; + if (!PyArg_ParseTuple(args, "|zpp", &family, &bold, &italic)) return NULL; + const char *ans = file_path_for_font(family, bold, italic); + if (!ans) return NULL; + return PyUnicode_FromString(ans); +} + +static PyMethodDef module_methods[] = { + METHODB(path_for_font, METH_VARARGS), + + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + + +bool +init_freetype_render_ui_text(PyObject *module) { + if (PyModule_AddFunctions(module, module_methods) != 0) return false; + return true; +} diff --git a/setup.py b/setup.py index b202fc62d..5ddc721f9 100755 --- a/setup.py +++ b/setup.py @@ -669,7 +669,11 @@ def compile_c_extension( def find_c_files() -> Tuple[List[str], List[str]]: ans, headers = [], [] d = 'kitty' - exclude = {'fontconfig.c', 'freetype.c', 'desktop.c'} if is_macos else {'core_text.m', 'cocoa_window.m', 'macos_process_info.c'} + exclude = { + 'fontconfig.c', 'freetype.c', 'desktop.c', 'freetype_render_ui_text.c' + } if is_macos else { + 'core_text.m', 'cocoa_window.m', 'macos_process_info.c' + } for x in sorted(os.listdir(d)): ext = os.path.splitext(x)[1] if ext in ('.c', '.m') and os.path.basename(x) not in exclude: