250 lines
5.4 KiB
C
250 lines
5.4 KiB
C
#include "cfg.h"
|
|
|
|
#if defined(G) && defined(HAVE_FREETYPE)
|
|
|
|
#include "links.h"
|
|
|
|
#include <fontconfig/fontconfig.h>
|
|
|
|
#if defined(__CYGWIN__)
|
|
#ifdef HAVE_PTHREADS
|
|
#define BACKGROUND_FONT_INIT
|
|
#endif
|
|
#include <windows.h>
|
|
#include <w32api/shlobj.h>
|
|
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 <pthread.h>
|
|
|
|
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
|