#include "cfg.h" #if defined(G) && defined(HAVE_FREETYPE) #include "links.h" #include #if defined(__CYGWIN__) #ifdef HAVE_PTHREADS #define BACKGROUND_FONT_INIT #endif #include #include static void set_font_path(void) { unsigned char *path = stracpy(cast_uchar "/cygdrive/c/Windows/Fonts"); #if defined(HAVE_CYGWIN_CONV_PATH) unsigned char win32_path[MAX_PATH]; if (SHGetFolderPathA(NULL, CSIDL_FONTS, NULL, 0, cast_char win32_path) == S_OK) { mem_free(path); path = stracpy(win32_path); translate_win32_to_unix(&path); } #endif FcConfigAppFontAddDir(NULL, path); mem_free(path); } #else #define set_font_path() do { } while (0) #endif static void *do_initialize_fontconfig(void *ptr) { if (!FcInit()) fatal_exit("FcInit returned an error"); set_font_path(); return NULL; } static unsigned fontconfig_initialized = 0; #ifdef BACKGROUND_FONT_INIT #include static pthread_t font_thread; void wait_for_fontconfig(void) { if (!fontconfig_initialized) { int r; if ((r = pthread_join(font_thread, NULL))) fatal_exit("pthread_join failed: %s", strerror(r)); fontconfig_initialized = 1; } } void fontconfig_init(void) { int r; if ((r = pthread_create(&font_thread, NULL, do_initialize_fontconfig, NULL))) fatal_exit("Could not start thread: %s", strerror(r)); } #else void wait_for_fontconfig(void) { if (!fontconfig_initialized) { do_initialize_fontconfig(NULL); fontconfig_initialized = 1; } } void fontconfig_init(void) { } #endif LIBC_CALLBACK static int compare_fonts(const void *f1_, const void *f2_) { struct list_of_fonts *f1 = (struct list_of_fonts *)f1_; struct list_of_fonts *f2 = (struct list_of_fonts *)f2_; int c = strcmp(cast_const_char f1->name, cast_const_char f2->name); if (c) return c; return strcmp(cast_const_char f1->file, cast_const_char f2->file); } void fontconfig_list_fonts(struct list_of_fonts **fonts, int *n_fonts, int monospaced) { int i, j; FcPattern *pat; FcValue val; FcObjectSet *os; FcFontSet *fs; wait_for_fontconfig(); *fonts = DUMMY; *n_fonts = 0; pat = FcPatternCreate(); if (!pat) { error("FcPatternCreate failed"); return; } if (monospaced) { val.type = FcTypeInteger; val.u.i = FC_MONO; if (!FcPatternAdd(pat, FC_SPACING, val, FcFalse)) error("FcPatternAdd FC_SPACING failed"); } val.type = FcTypeBool; val.u.b = FcTrue; if (!FcPatternAdd(pat, FC_SCALABLE, val, FcFalse)) error("FcPatterAdd FC_SCALABLE failed"); os = FcObjectSetBuild(FC_FILE, FC_INDEX, FC_FAMILY, FC_STYLE, #ifdef FC_FULLNAME FC_FULLNAME, #endif (char *)NULL); if (!os) { error("FcObjectSetBuild failed"); goto free_pattern_ret; } fs = FcFontList(0, pat, os); if (!fs) { error("FcFontList failed"); goto free_object_set_ret; } if ((unsigned)fs->nfont > MAXINT / sizeof(struct list_of_fonts) - 1) overalloc(); *fonts = mem_alloc((fs->nfont + 1) * sizeof(struct list_of_fonts)); for (i = 0; i < fs->nfont; i++) { FcResult res; unsigned char *value; int index; unsigned char *file, *name; int file_l, name_l; FcPattern *font = fs->fonts[i]; file = init_str(), file_l = 0; name = init_str(), name_l = 0; res = FcPatternGetString(font, FC_FILE, 0, &value); if (res != FcResultMatch) { cont: mem_free(file); mem_free(name); continue; } add_to_str(&file, &file_l, value); res = FcPatternGetInteger(font, FC_INDEX, 0, &index); if (res == FcResultMatch && index) { add_to_str(&file, &file_l, cast_uchar " @"); add_num_to_str(&file, &file_l, index); } if (file_l >= MAX_STR_LEN) goto cont; #ifdef FC_FULLNAME res = FcPatternGetString(font, FC_FULLNAME, 0, &value); if (res == FcResultMatch) { add_to_str(&name, &name_l, value); } else #endif { unsigned char *family, *style; res = FcPatternGetString(font, FC_FAMILY, 0, &family); if (res != FcResultMatch) goto cont; res = FcPatternGetString(font, FC_STYLE, 0, &style); if (res != FcResultMatch) goto cont; add_to_str(&name, &name_l, family); add_chr_to_str(&name, &name_l, ' '); add_to_str(&name, &name_l, style); } (*fonts)[*n_fonts].file = file; (*fonts)[*n_fonts].name = name; (*n_fonts)++; /*FcPatternPrint(font);*/ } if (*n_fonts) qsort(*fonts, *n_fonts, sizeof(struct list_of_fonts), (int (*)(const void *, const void *))compare_fonts); for (i = 1, j = 1; i < *n_fonts; i++) { if (strcmp(cast_const_char (*fonts)[j - 1].name, cast_const_char (*fonts)[i].name)) { (*fonts)[j++] = (*fonts)[i]; } else { mem_free((*fonts)[i].name); mem_free((*fonts)[i].file); } } *n_fonts = j; (*fonts)[j].file = NULL; (*fonts)[j].name = NULL; /*{ for (i = 0; i < *n_fonts; i++) { fprintf(stderr, "%d: '%s' '%s'\n", i, (*fonts)[i].file, (*fonts)[i].name); } }*/ FcFontSetDestroy(fs); free_object_set_ret: FcObjectSetDestroy(os); free_pattern_ret: FcPatternDestroy(pat); } void fontconfig_free_fonts(struct list_of_fonts *fonts) { int i; for (i = 0; fonts[i].file; i++) { mem_free(fonts[i].file); mem_free(fonts[i].name); } mem_free(fonts); } void add_fontconfig_version(unsigned char **s, int *l) { int fc_version; #ifdef HAVE_FT_LIBRARY_VERSION fc_version = FcGetVersion(); #else fc_version = FC_VERSION; #endif add_to_str(s, l, cast_uchar "FontConfig "); add_num_to_str(s, l, fc_version / 10000); add_chr_to_str(s, l, '.'); add_num_to_str(s, l, fc_version / 100 % 100); add_chr_to_str(s, l, '.'); add_num_to_str(s, l, fc_version % 100); } #endif