#include "edit.h"
typedef struct {
- char* buf;
+ uint8_t* buf;
size_t len;
} FMap;
(fstat(fd, &sb) < 0) ||
(sb.st_size == 0))
return file;
- file.buf = (char*)mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ file.buf = (uint8_t*)mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
file.len = sb.st_size;
if (file.buf == MAP_FAILED)
die("memory mapping of file failed");
unsigned len = buf_eol(buf, pos) - bol;
return buf_byrune(buf, bol, (len > col ? col : len));
}
-
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
};
-int charset(const char* buf, size_t len) {
+int charset(const uint8_t* buf, size_t len) {
/* look for a BOM and parse it */
for (size_t i = 0; i < (sizeof(BOMS)/sizeof(BOMS[0])); i++)
- if (!strncmp(buf, BOMS[i].seq, BOMS[i].len))
+ if (!strncmp((char*)buf, BOMS[i].seq, BOMS[i].len))
return BOMS[i].type;
/* look for bytes that are invalid in utf-8 */
int type = UTF_8;
- for (size_t i = 0; type && (i < len); i++)
+ size_t i = 0;
+ for (i = 0; type && (i < len); i++)
type = Utf8Valid[(int)buf[i]];
return type;
}
UTF_32LE,
};
-int charset(const char* buf, size_t len);
+int charset(const uint8_t* buf, size_t len);
size_t utf8encode(char str[UTF_MAX], Rune rune);
bool utf8decode(Rune* rune, size_t* length, int byte);
Rune fgetrune(FILE* f);
/* Miscellaneous Functions
*****************************************************************************/
-void die(char* msg);
+void die(const char* fmt, ...);
/* Color Scheme Handling
*****************************************************************************/
TabWidth = 4, /* maximum number of spaces used to represent a tab */
ScrollLines = 1, /* number of lines to scroll by for mouse wheel scrolling */
BufSize = 8192, /* default buffer size */
+ MaxFonts = 16 /* maximum number of fonts to cache */
};
static const Color Palette[][2] = {
/* choose the font to use for xft */
#ifdef __MACH__
-#define FONTNAME "Inconsolata:pixelsize=14:antialias=true:autohint=true"
+#define FONTNAME "Monaco:size=10:antialias=true:autohint=true"
#else
-#define FONTNAME "Liberation Mono:pixelsize=14:antialias=true:autohint=true"
+#define FONTNAME "Monaco:size=10.5:antialias=true:autohint=true"
#endif
#define DEFAULT_COLORSCHEME DARK
unsigned TargetCol;
enum ColorScheme ColorBase;
-void die(char* m) {
+void die(const char* m, ...) {
(void)m;
}
--- /dev/null
+#define _GNU_SOURCE
+#include <time.h>
+#include <signal.h>
+#include <locale.h>
+#include <wchar.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <X11/Xlib.h>
+#include <X11/Xft/Xft.h>
+
+uint32_t Msg1[] = {
+ 0x5916, 0x56fd, 0x8a9e, 0x306e, 0x5b66, 0x7fd2, 0x3068, 0x6559, 0x6388
+};
+
+uint32_t Msg2[] = {
+ 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x20, 0x4c,
+ 0x65, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e,
+ 0x64, 0x20, 0x54, 0x65, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67
+};
+
+struct {
+ Display* display;
+ Visual* visual;
+ Colormap colormap;
+ unsigned depth;
+ int screen;
+ GC gc;
+ Window window;
+ Pixmap pixmap;
+ XftDraw* xft;
+ int width;
+ int height;
+ int rows;
+ int cols;
+ XIC xic;
+ XIM xim;
+} X;
+
+static void die(const char* msgfmt, ...) {
+ va_list args;
+ va_start(args, msgfmt);
+ fprintf(stderr, "Error: ");
+ vfprintf(stderr, msgfmt, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+ exit(EXIT_FAILURE);
+}
+
+static XftColor xftcolor(uint32_t c) {
+ XftColor xc;
+ xc.color.red = ((c & 0x00FF0000) >> 8);
+ xc.color.green = ((c & 0x0000FF00));
+ xc.color.blue = ((c & 0x000000FF) << 8);
+ xc.color.alpha = UINT16_MAX;
+ XftColorAllocValue(X.display, X.visual, X.colormap, &xc.color, &xc);
+ return xc;
+}
+
+static int init(void) {
+ signal(SIGPIPE, SIG_IGN); // Ignore the SIGPIPE signal
+ /* open the X display and get basic attributes */
+ if (!(X.display = XOpenDisplay(0)))
+ die("cannot open display");
+ Window root = DefaultRootWindow(X.display);
+ XWindowAttributes wa;
+ XGetWindowAttributes(X.display, root, &wa);
+ X.visual = wa.visual;
+ X.colormap = wa.colormap;
+ X.screen = DefaultScreen(X.display);
+ X.depth = DefaultDepth(X.display, X.screen);
+
+ /* create the main window */
+ X.window = XCreateSimpleWindow(X.display, root, 0, 0, 640, 480, 0, 0, WhitePixel(X.display, X.screen));
+ XSetWindowAttributes swa;
+ swa.backing_store = WhenMapped;
+ swa.bit_gravity = NorthWestGravity;
+ XChangeWindowAttributes(X.display, X.window, CWBackingStore|CWBitGravity, &swa);
+ XStoreName(X.display, X.window, "edit");
+ XSelectInput(X.display, X.window, StructureNotifyMask|ExposureMask|FocusChangeMask);
+
+ /* simulate an initial resize and map the window */
+ XConfigureEvent ce;
+ ce.type = ConfigureNotify;
+ ce.width = 640;
+ ce.height = 480;
+ XSendEvent(X.display, X.window, False, StructureNotifyMask, (XEvent *)&ce);
+ XMapWindow(X.display, X.window);
+
+ /* set input methods */
+ if((X.xim = XOpenIM(X.display, 0, 0, 0)))
+ X.xic = XCreateIC(X.xim, XNInputStyle, XIMPreeditNothing|XIMStatusNothing, XNClientWindow, X.window, XNFocusWindow, X.window, NULL);
+
+ /* initialize the graphics context */
+ XGCValues gcv;
+ gcv.foreground = WhitePixel(X.display, X.screen);
+ gcv.graphics_exposures = False;
+ X.gc = XCreateGC(X.display, X.window, GCForeground|GCGraphicsExposures, &gcv);
+
+ /* initialize pixmap and drawing context */
+ X.pixmap = XCreatePixmap(X.display, X.window, 640, 480, X.depth);
+ X.xft = XftDrawCreate(X.display, X.pixmap, X.visual, X.colormap);
+
+ return XConnectionNumber(X.display);
+}
+
+static void handle_event(XEvent* e) {
+ switch (e->type) {
+ case FocusIn: if (X.xic) XSetICFocus(X.xic); break;
+ case FocusOut: if (X.xic) XUnsetICFocus(X.xic); break;
+ case ConfigureNotify: // Resize the window
+ if (e->xconfigure.width != X.width || e->xconfigure.height != X.height) {
+ X.width = e->xconfigure.width;
+ X.height = e->xconfigure.height;
+ X.pixmap = XCreatePixmap(X.display, X.window, X.width, X.height, X.depth);
+ X.xft = XftDrawCreate(X.display, X.pixmap, X.visual, X.colormap);
+ }
+ break;
+ }
+}
+
+/*****************************************************************************/
+
+typedef uint32_t Rune;
+
+static char FontName[] = "Liberation Mono:size=14:antialias=true:autohint=true";
+
+/* globals */
+#define MaxFonts 16
+struct {
+ struct {
+ int height;
+ int width;
+ int ascent;
+ int descent;
+ XftFont* match;
+ FcFontSet* set;
+ FcPattern* pattern;
+ } base;
+ struct {
+ XftFont* font;
+ Rune unicodep;
+ } cache[MaxFonts];
+ int ncached;
+} Fonts;
+
+void font_init(void);
+void font_find(XftGlyphFontSpec* spec, Rune rune);
+int font_makespecs(XftGlyphFontSpec* specs, const Rune* runes, int len, int x, int y);
+void font_drawspecs(const XftGlyphFontSpec* specs, int len, XftColor* fg, XftColor* bg, int x, int y);
+
+void draw_runes(unsigned x, unsigned y, XftColor* fg, XftColor* bg, Rune* runes, size_t rlen);
+static void redraw(void);
+
+int main(int argc, char** argv) {
+ setlocale(LC_CTYPE, "");
+ XSetLocaleModifiers("");
+ init();
+ font_init();
+ XEvent e;
+ while (true) {
+ XPeekEvent(X.display,&e);
+ while (XPending(X.display)) {
+ XNextEvent(X.display, &e);
+ if (!XFilterEvent(&e, None))
+ handle_event(&e);
+ }
+ redraw();
+ }
+ return 0;
+}
+
+static void redraw(void) {
+ /* Allocate the colors */
+ XftColor bkgclr = xftcolor(0x002b36);
+ XftColor txtclr = xftcolor(0x839496);
+ /* draw the background colors */
+ XftDrawRect(X.xft, &bkgclr, 0, 0, X.width, X.height);
+ /* Draw text */
+ draw_runes(0, 0, &txtclr, &bkgclr, (FcChar32*)(Msg1), (sizeof(Msg1)/sizeof(Msg1[0])));
+ draw_runes(0, 1, &txtclr, &bkgclr, (FcChar32*)(Msg1), (sizeof(Msg1)/sizeof(Msg1[0])));
+ draw_runes(0, 2, &txtclr, &bkgclr, (FcChar32*)(Msg2), (sizeof(Msg2)/sizeof(Msg2[0])));
+ /* flush pixels to the screen */
+ XCopyArea(X.display, X.pixmap, X.window, X.gc, 0, 0, X.width, X.height, 0, 0);
+ XFlush(X.display);
+}
+
+/*****************************************************************************/
+
+void draw_runes(unsigned x, unsigned y, XftColor* fg, XftColor* bg, Rune* runes, size_t rlen) {
+ XftGlyphFontSpec specs[rlen];
+ size_t nspecs = font_makespecs(specs, runes, rlen, x, y);
+ font_drawspecs(specs, nspecs, fg, bg, x, y);
+}
+
+void font_init(void) {
+ /* init the library and the base font pattern */
+ if (!FcInit())
+ die("Could not init fontconfig.\n");
+ FcPattern* pattern = FcNameParse((FcChar8 *)FontName);
+ if (!pattern)
+ die("st: can't open font %s\n", FontName);
+
+ /* load the base font */
+ FcResult result;
+ FcPattern* match = XftFontMatch(X.display, X.screen, pattern, &result);
+ if (!match || !(Fonts.base.match = XftFontOpenPattern(X.display, match)))
+ die("could not load default font: %s", FontName);
+
+ /* get base font extents */
+ XGlyphInfo extents;
+ const FcChar8 ascii[] =
+ " !\"#$%&'()*+,-./0123456789:;<=>?"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
+ "`abcdefghijklmnopqrstuvwxyz{|}~";
+ XftTextExtentsUtf8(X.display, Fonts.base.match, ascii, sizeof(ascii), &extents);
+ Fonts.base.set = NULL;
+ Fonts.base.pattern = FcPatternDuplicate(pattern);
+ Fonts.base.ascent = Fonts.base.match->ascent;
+ Fonts.base.descent = Fonts.base.match->descent;
+ Fonts.base.height = Fonts.base.ascent + Fonts.base.descent;
+ Fonts.base.width = ((extents.xOff + (sizeof(ascii) - 1)) / sizeof(ascii));
+ FcPatternDestroy(pattern);
+}
+
+void font_find(XftGlyphFontSpec* spec, Rune rune) {
+ /* if the rune is in the base font, set it and return */
+ FT_UInt glyphidx = XftCharIndex(X.display, Fonts.base.match, rune);
+ if (glyphidx) {
+ puts("font: default");
+ spec->font = Fonts.base.match;
+ spec->glyph = glyphidx;
+ return;
+ }
+ /* Otherwise check the cache */
+ for (int f = 0; f < Fonts.ncached; f++) {
+ glyphidx = XftCharIndex(X.display, Fonts.cache[f].font, rune);
+ /* Fond a suitable font or found a default font */
+ if (glyphidx || (!glyphidx && Fonts.cache[f].unicodep == rune)) {
+ puts("font: match");
+ spec->font = Fonts.cache[f].font;
+ spec->glyph = glyphidx;
+ return;
+ }
+ }
+ /* if all other options fail, ask fontconfig for a suitable font */
+ FcResult fcres;
+ if (!Fonts.base.set)
+ Fonts.base.set = FcFontSort(0, Fonts.base.pattern, 1, 0, &fcres);
+ FcFontSet* fcsets[] = { Fonts.base.set };
+ FcPattern* fcpattern = FcPatternDuplicate(Fonts.base.pattern);
+ FcCharSet* fccharset = FcCharSetCreate();
+ FcCharSetAddChar(fccharset, rune);
+ FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
+ FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
+ FcConfigSubstitute(0, fcpattern, FcMatchPattern);
+ FcDefaultSubstitute(fcpattern);
+ FcPattern* fontmatch = FcFontSetMatch(0, fcsets, 1, fcpattern, &fcres);
+ /* add the font to the cache and use it */
+ if (Fonts.ncached >= MaxFonts) {
+ Fonts.ncached = MaxFonts - 1;
+ XftFontClose(X.display, Fonts.cache[Fonts.ncached].font);
+ }
+ Fonts.cache[Fonts.ncached].font = XftFontOpenPattern(X.display, fontmatch);
+ Fonts.cache[Fonts.ncached].unicodep = rune;
+ spec->glyph = XftCharIndex(X.display, Fonts.cache[Fonts.ncached].font, rune);
+ spec->font = Fonts.cache[Fonts.ncached].font;
+ Fonts.ncached++;
+ FcPatternDestroy(fcpattern);
+ FcCharSetDestroy(fccharset);
+ puts("font: fontconfig");
+}
+
+int font_makespecs(XftGlyphFontSpec* specs, const Rune* runes, int len, int x, int y) {
+ int winx = x * Fonts.base.width, winy = y * Fonts.base.height, xp, yp;
+ int numspecs = 0;
+ for (int i = 0, xp = winx, yp = winy + Fonts.base.ascent; i < len; ++i) {
+ if (!runes[i]) continue;
+ font_find(&(specs[numspecs]), runes[i]);
+ int runewidth = wcwidth(runes[i]) * Fonts.base.width;
+ specs[numspecs].x = (short)xp;
+ specs[numspecs].y = (short)yp;
+ xp += runewidth;
+ numspecs++;
+ }
+ return numspecs;
+}
+
+void font_drawspecs(const XftGlyphFontSpec* specs, int len, XftColor* fg, XftColor* bg, int x, int y) {
+ //int charlen = len; // * ((base.mode & ATTR_WIDE) ? 2 : 1);
+ //int winx = x * Fonts.base.width, winy = y * Fonts.base.height,
+ // width = charlen * Fonts.base.width;
+ //XRectangle r;
+
+ /* Render the glyphs. */
+ XftDrawGlyphFontSpec(X.xft, fg, specs, len);
+}
+
+
--- /dev/null
+/**
+ @brief Simple UTF-8 encoding and decoding routines.
+ @author Michael D. Lowis
+ @license BSD 2-clause License
+*/
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+enum {
+ UTF_MAX = 6u, /* maximum number of bytes that make up a rune */
+ RUNE_SELF = 0x80, /* byte values larger than this are *not* ascii */
+ RUNE_ERR = 0xFFFD, /* rune value representing an error */
+ RUNE_MAX = 0x10FFFF, /* Maximum decodable rune value */
+ RUNE_EOF = UINT32_MAX /* rune value representing end of file */
+};
+
+typedef uint32_t Rune;
+
+const uint8_t UTF8_SeqBits[] = { 0x00u, 0x80u, 0xC0u, 0xE0u, 0xF0u, 0xF8u, 0xFCu, 0xFEu };
+const uint8_t UTF8_SeqMask[] = { 0x00u, 0xFFu, 0x1Fu, 0x0Fu, 0x07u, 0x03u, 0x01u, 0x00u };
+const uint8_t UTF8_SeqLens[] = { 0x01u, 0x00u, 0x02u, 0x03u, 0x04u, 0x05u, 0x06u, 0x00u };
+
+static bool runevalid(Rune val) {
+ return (val <= RUNE_MAX)
+ && ((val & 0xFFFEu) != 0xFFFEu)
+ && ((val < 0xD800u) || (val > 0xDFFFu))
+ && ((val < 0xFDD0u) || (val > 0xFDEFu));
+}
+
+static size_t runelen(Rune rune) {
+ if(!runevalid(rune))
+ return 0;
+ else if(rune <= 0x7F)
+ return 1;
+ else if(rune <= 0x07FF)
+ return 2;
+ else if(rune <= 0xFFFF)
+ return 3;
+ else
+ return 4;
+}
+
+static uint8_t utfseq(uint8_t byte) {
+ for (int i = 1; i < 8; i++)
+ if ((byte & UTF8_SeqBits[i]) == UTF8_SeqBits[i-1])
+ return UTF8_SeqLens[i-1];
+ return 0;
+}
+
+size_t utf8encode(char str[UTF_MAX], Rune rune) {
+ size_t len = runelen(rune);
+ str[0] = (len == 1 ? 0x00 : UTF8_SeqBits[len])
+ | (UTF8_SeqMask[len] & (rune >> (6 * (len-1))));
+ for (size_t i = 1; i < len; i++)
+ str[i] = 0x80u | (0x3Fu & (rune >> (6 * (len-i-1))));
+ return len;
+}
+
+bool utf8decode(Rune* rune, size_t* length, int byte) {
+ /* Handle the start of a new rune */
+ if (*length == 0) {
+ /* If we were fed in an EOF as a start byte, handle it here */
+ if (byte == EOF) {
+ *rune = RUNE_EOF;
+ } else {
+ /* Otherwise, decode the first byte of the rune */
+ *length = utfseq(byte);
+ *rune = (*length == 0) ? RUNE_ERR : (byte & UTF8_SeqMask[*length]);
+ (*length)--;
+ }
+ /* Handle continuation bytes */
+ } else if ((byte & 0xC0) == 0x80) {
+ /* add bits from continuation byte to rune value
+ * cannot overflow: 6 byte sequences contain 31 bits */
+ *rune = (*rune << 6) | (byte & 0x3F); /* 10xxxxxx */
+ (*length)--;
+ /* Sanity check the final rune value before finishing */
+ if ((*length == 0) && !runevalid(*rune))
+ *rune = RUNE_ERR;
+ /* Didn't get the continuation byte we expected */
+ } else {
+ *rune = RUNE_ERR;
+ }
+ /* Tell the caller whether we finished or not */
+ return ((*length == 0) || (*rune == RUNE_ERR));
+}
+
+Rune fgetrune(FILE* f) {
+ Rune rune = 0;
+ size_t length = 0;
+ while (!utf8decode(&rune, &length, fgetc(f)));
+ return rune;
+}
+
+void fputrune(Rune rune, FILE* f) {
+ char utf[UTF_MAX] = {0};
+ utf8encode(utf, rune);
+ fprintf(f, "%s", utf);
+}
+
+void print_runes(FILE* in) {
+ if (!in) return;
+ Rune r;
+ while (RUNE_EOF != (r = fgetrune(in)))
+ printf("%#x\n", r);
+ fclose(in);
+}
+
+int main(int argc, char** argv) {
+ if (argc == 1)
+ print_runes(stdin);
+ else
+ for (int i = 1; i < argc; i++)
+ print_runes(fopen(argv[i], "rb"));
+ return 0;
+}
#include <time.h>
#include <signal.h>
#include <locale.h>
+#include <wchar.h>
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
Pixmap pixmap;
XftDraw* xft;
XftFont* font;
- unsigned fheight;
- unsigned fwidth;
- unsigned fascent;
- unsigned fdescent;
int width;
int height;
int rows;
XIM xim;
} X;
-/*****************************************************************************/
+struct {
+ struct {
+ int height;
+ int width;
+ int ascent;
+ int descent;
+ XftFont* match;
+ FcFontSet* set;
+ FcPattern* pattern;
+ } base;
+ struct {
+ XftFont* font;
+ Rune unicodep;
+ } cache[MaxFonts];
+ int ncached;
+} Fonts;
-struct XFont {
- struct XFont* next;
- XftFont* font;
- FcPattern* pattern;
-}* FontList = NULL;
-
-struct XFont* fontbyname(char* fontname) {
- struct XFont* xfont = (struct XFont*)calloc(1, sizeof(struct XFont));
- if (!(xfont->font = XftFontOpenName(X.display, X.screen, fontname)))
- die("cannot open default font");
- if (!(xfont->pattern = FcNameParse((FcChar8 *)FONTNAME)))
- die("cannot convert fontname to font pattern");
- return xfont;
-}
+/*****************************************************************************/
-struct XFont* fontbypatt(FcPattern* pattern) {
- struct XFont* xfont = (struct XFont*)calloc(1, sizeof(struct XFont));
- if (!(xfont->font = XftFontOpenPattern(X.display, pattern)))
- die("cannot get font by pattern");
- return xfont;
+void font_init(void) {
+ /* init the library and the base font pattern */
+ if (!FcInit())
+ die("Could not init fontconfig.\n");
+ FcPattern* pattern = FcNameParse((FcChar8 *)FONTNAME);
+ if (!pattern)
+ die("st: can't open font %s\n", FONTNAME);
+
+ /* load the base font */
+ FcResult result;
+ FcPattern* match = XftFontMatch(X.display, X.screen, pattern, &result);
+ if (!match || !(Fonts.base.match = XftFontOpenPattern(X.display, match)))
+ die("could not load default font: %s", FONTNAME);
+
+ /* get base font extents */
+ XGlyphInfo extents;
+ const FcChar8 ascii[] =
+ " !\"#$%&'()*+,-./0123456789:;<=>?"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
+ "`abcdefghijklmnopqrstuvwxyz{|}~";
+ XftTextExtentsUtf8(X.display, Fonts.base.match, ascii, sizeof(ascii), &extents);
+ Fonts.base.set = NULL;
+ Fonts.base.pattern = FcPatternDuplicate(pattern);
+ Fonts.base.ascent = Fonts.base.match->ascent;
+ Fonts.base.descent = Fonts.base.match->descent;
+ Fonts.base.height = Fonts.base.ascent + Fonts.base.descent;
+ Fonts.base.width = ((extents.xOff + (sizeof(ascii) - 1)) / sizeof(ascii));
+ FcPatternDestroy(pattern);
}
-struct XFont* getfont(Rune r) {
- /* check to see if the font is already loaded */
- struct XFont* xfont = FontList;
- while (xfont) {
- printf("does font have rune? %d\n", XftCharExists(X.display, xfont->font, r));
- if (XftCharExists(X.display, xfont->font, r)) {
- //puts("found font in font list");
- return xfont;
+void font_find(XftGlyphFontSpec* spec, Rune rune) {
+ /* if the rune is in the base font, set it and return */
+ FT_UInt glyphidx = XftCharIndex(X.display, Fonts.base.match, rune);
+ if (glyphidx) {
+ spec->font = Fonts.base.match;
+ spec->glyph = glyphidx;
+ return;
+ }
+ /* Otherwise check the cache */
+ for (int f = 0; f < Fonts.ncached; f++) {
+ glyphidx = XftCharIndex(X.display, Fonts.cache[f].font, rune);
+ /* Fond a suitable font or found a default font */
+ if (glyphidx || (!glyphidx && Fonts.cache[f].unicodep == rune)) {
+ spec->font = Fonts.cache[f].font;
+ spec->glyph = glyphidx;
+ return;
}
- xfont = xfont->next;
}
- /* search for a new font that has the rune */
- XftResult result;
+ /* if all other options fail, ask fontconfig for a suitable font */
+ FcResult fcres;
+ if (!Fonts.base.set)
+ Fonts.base.set = FcFontSort(0, Fonts.base.pattern, 1, 0, &fcres);
+ FcFontSet* fcsets[] = { Fonts.base.set };
+ FcPattern* fcpattern = FcPatternDuplicate(Fonts.base.pattern);
FcCharSet* fccharset = FcCharSetCreate();
- FcCharSetAddChar(fccharset, r);
- FcPattern* fcpattern = FcPatternDuplicate(FontList->pattern);
+ FcCharSetAddChar(fccharset, rune);
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
- FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
- FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
+ FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
+ FcConfigSubstitute(0, fcpattern, FcMatchPattern);
FcDefaultSubstitute(fcpattern);
- FcPattern* match = XftFontMatch(X.display, X.screen, fcpattern, &result);
- FcCharSetDestroy(fccharset);
- FcPatternDestroy(fcpattern);
- if (match) {
- //puts("found new font, adding it to the list");
- struct XFont* newfont = fontbypatt(match);
- struct XFont* lastfont = FontList;
- printf("newfont: %p, %d\n", newfont->font, XftCharExists(X.display, newfont->font, r));
- if (XftCharExists(X.display, newfont->font, r)) {
- for (; lastfont->next; lastfont = lastfont->next)
- ; /* NOP */
- lastfont->next = newfont;
- return newfont;
- } else {
- XftFontClose(X.display, newfont->font);
- free(newfont);
- }
+ FcPattern* fontmatch = FcFontSetMatch(0, fcsets, 1, fcpattern, &fcres);
+ /* add the font to the cache and use it */
+ if (Fonts.ncached >= MaxFonts) {
+ Fonts.ncached = MaxFonts - 1;
+ XftFontClose(X.display, Fonts.cache[Fonts.ncached].font);
}
- puts("failed to find a font with the given rune");
- return FontList;
+ Fonts.cache[Fonts.ncached].font = XftFontOpenPattern(X.display, fontmatch);
+ Fonts.cache[Fonts.ncached].unicodep = rune;
+ spec->glyph = XftCharIndex(X.display, Fonts.cache[Fonts.ncached].font, rune);
+ spec->font = Fonts.cache[Fonts.ncached].font;
+ Fonts.ncached++;
+ FcPatternDestroy(fcpattern);
+ FcCharSetDestroy(fccharset);
}
-void fontinit(char* fontstr)
-{
- double fontval;
- float ceilf(float);
- /* initialize fontconfig */
- if (!FcInit())
- die("Could not init fontconfig");
- /* get pattern from font name */
- FcPattern *pattern;
- if (fontstr[0] == '-') {
- pattern = XftXlfdParse(fontstr, False, False);
- } else {
- pattern = FcNameParse((FcChar8 *)fontstr);
+int font_makespecs(XftGlyphFontSpec* specs, const Rune* runes, int len, int x, int y) {
+ int winx = x * Fonts.base.width, winy = y * Fonts.base.height;
+ int numspecs = 0;
+ for (int i = 0, xp = winx, yp = winy + Fonts.base.ascent; i < len; ++i) {
+ if (!runes[i]) continue;
+ font_find(&(specs[numspecs]), runes[i]);
+ int runewidth = wcwidth(runes[i]) * Fonts.base.width;
+ specs[numspecs].x = xp;
+ specs[numspecs].y = yp;
+ xp += runewidth;
+ numspecs++;
}
- if (!pattern)
- die("failed to open default font");
- /* load the font by pattern */
- if (!(FontList = fontbypatt(pattern)))
- die("failed to load the font");
- FcPatternDestroy(pattern);
+ return numspecs;
}
-
/*****************************************************************************/
-void die(char* m) {
- fprintf(stderr, "dying, %s\n", m);
- exit(1);
+void die(const char* msgfmt, ...) {
+ va_list args;
+ va_start(args, msgfmt);
+ fprintf(stderr, "Error: ");
+ vfprintf(stderr, msgfmt, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+ exit(EXIT_FAILURE);
}
static XftColor xftcolor(enum ColorId cid) {
XMapWindow(X.display, X.window);
/* allocate font */
- //fontinit(FONTNAME);
- FontList = fontbyname(FONTNAME);
- X.fheight = FontList->font->height;
- X.fwidth = FontList->font->max_advance_width;
- X.fascent = FontList->font->ascent;
- X.fdescent = FontList->font->descent;
+ font_init();
/* set input methods */
if ((X.xim = XOpenIM(X.display, 0, 0, 0)))
if (e->type == MotionNotify) {
event.type = MouseMove;
event.button = MOUSE_NONE;
- event.x = e->xmotion.x / X.fwidth;
- event.y = e->xmotion.y / (X.fascent + X.fdescent);
+ event.x = e->xmotion.x / Fonts.base.width;
+ event.y = e->xmotion.y / (Fonts.base.ascent + Fonts.base.descent);
} else {
event.type = (e->type = ButtonPress ? MouseDown : MouseUp);
/* set the button id */
case Button5: event.button = MOUSE_WHEELDOWN; break;
default: event.button = MOUSE_NONE; break;
}
- event.x = e->xbutton.x / X.fwidth;
- event.y = e->xbutton.y / (X.fascent + X.fdescent);
+ event.x = e->xbutton.x / Fonts.base.width;
+ event.y = e->xbutton.y / (Fonts.base.ascent + Fonts.base.descent);
}
return &event;
}
X.xft = XftDrawCreate(X.display, X.pixmap, X.visual, X.colormap);
screen_setsize(
&Buffer,
- X.height / X.fheight,
- X.width / X.fwidth);
+ X.height / Fonts.base.height,
+ X.width / Fonts.base.width);
}
break;
}
}
-#include <assert.h>
-
-static void draw_string(XftDraw* xft, XftColor* clr, unsigned x, unsigned y, Rune* r, unsigned len) {
- struct XFont* curfont = NULL;
- for (unsigned i = 0, n = 0; i < len; i += n, n = 0) {
- //printf("i: %d, n: %d\n", i, n);
- Rune* str = r+i;
- struct XFont* newfont = NULL;
- curfont = getfont(str[n]);
- while (curfont == (newfont = getfont(str[n]))) {
- n++;
- }
- if (n) {
- //printf("printing: %p %u\n", curfont, n);
- //if (!curfont) curfont = FontList;
- XftDrawString32(xft, clr, (curfont ? curfont->font : FontList->font), x, y, str, n);
- }
- }
- //for (unsigned i = 0; i < len;) {
- // struct XFont* newfont = NULL;
- // Rune* curr = r+i;
- // unsigned n = 0;
- // while (curfont == (newfont = getfont(curr[n])))
- // n++;
- // if (!curfont) curfont = FontList;
- // XftDrawString32(xft, clr, curfont->font, x, y, curr, n);
- // curfont = newfont;
- // i += n;
- //}
+void draw_runes(unsigned x, unsigned y, XftColor* fg, XftColor* bg, Rune* runes, size_t rlen) {
+ (void)bg;
+ XftGlyphFontSpec specs[rlen];
+ size_t nspecs = font_makespecs(specs, runes, rlen, x, y);
+ XftDrawGlyphFontSpec(X.xft, fg, specs, nspecs);
}
static void redraw(void) {
/* draw the background colors */
XftDrawRect(X.xft, &bkgclr, 0, 0, X.width, X.height);
- XftDrawRect(X.xft, >rclr, 79 * X.fwidth, 0, X.fwidth, X.height);
- XftDrawRect(X.xft, &txtclr, 0, 0, X.width, X.fheight + X.fdescent);
+ XftDrawRect(X.xft, >rclr, 79 * Fonts.base.width, 0, Fonts.base.width, X.height);
+ XftDrawRect(X.xft, &txtclr, 0, 0, X.width, Fonts.base.height);
/* update the screen buffer and retrieve cursor coordinates */
unsigned csrx, csry;
);
for (unsigned y = 0; y < nrows; y++) {
Row* row = screen_getrow(y);
- draw_string(X.xft, (y == 0 ? &bkgclr : &txtclr), 0, (y+1) * X.fheight, row->cols, row->len);
+ draw_runes(0, y, (y == 0 ? &bkgclr : &txtclr), NULL, row->cols, row->len);
}
/* Place cursor on screen */
Rune csrrune = screen_getcell(csry,csrx);
if (Buffer.insert_mode) {
- XftDrawRect(X.xft, &csrclr, csrx * X.fwidth, csry * X.fheight + X.fdescent, 2, X.fheight);
+ XftDrawRect(X.xft, &csrclr, csrx * Fonts.base.width, csry * Fonts.base.height, 2, Fonts.base.height);
} else {
unsigned width = ('\t' == buf_get(&Buffer, CursorPos) ? (TabWidth - (csrx % TabWidth)) : 1);
- XftDrawRect(X.xft, &csrclr, csrx * X.fwidth, csry * X.fheight + X.fdescent, width * X.fwidth, X.fheight);
- draw_string(X.xft, &bkgclr, csrx * X.fwidth, (csry+1) * X.fheight, (FcChar32*)&csrrune, 1);
+ XftDrawRect(X.xft, &csrclr, csrx * Fonts.base.width, csry * Fonts.base.height, width * Fonts.base.width, Fonts.base.height);
+ draw_runes(csrx, csry, &bkgclr, NULL, (FcChar32*)&csrrune, 1);
}
/* flush pixels to the screen */