1 module gui.font;
2 
3 import x11.X;
4 import x11.Xlib;
5 import x11.Xutil;
6 import std.c.stdlib;
7 import std..string;
8 import std.algorithm;
9 
10 import cboxapp;
11 import types;
12 
13 /**
14  * Font object to encapsulate the X font.
15  */
16 struct Fnt 
17 {
18     int ascent; /// Ascent of the font
19     int descent;/// Descent of the font
20     uint h; /// Height of the font. This equates to ascent + descent.
21     XFontSet set; // Font set to use
22     XFontStruct *xfont; /// The X font we're covering.
23     Display* dpy;
24 
25     /**
26      * Ctor. Creates a Fnt object wrapping the specified font for a given display.
27      * Params:
28      *  dpy=        X display
29      *  fontname=   Name of the font to wrap (X font name)
30      * Example:
31      * ---
32      * auto f = Fnt(display, "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*");
33      * ---
34      */
35     this(Display *dpy, in string fontname) 
36     {
37         if(AppDisplay.instance().dpy is null) {
38             exit(EXIT_FAILURE);
39         }
40 
41         this.dpy = dpy;
42         char *def;
43         char **missing;
44         int n;
45 
46         this.set = XCreateFontSet(AppDisplay.instance().dpy, cast(char*)fontname.toStringz, &missing, &n, &def);
47 
48         if(missing) {
49             while(n--) {
50                 //lout("drw: missing fontset: %s", missing[n].fromStringz);
51             }
52             XFreeStringList(missing);
53         }
54 
55         if(this.set) {
56             XFontStruct **xfonts;
57             char **font_names;
58             XExtentsOfFontSet(this.set);
59             n = XFontsOfFontSet(this.set, &xfonts, &font_names);
60             while(n--) {
61                 this.ascent = max(this.ascent, (*xfonts).ascent);
62                 this.descent = max(this.descent,(*xfonts).descent);
63                 xfonts++;
64             }
65         }
66 
67         else {
68             this.xfont = XLoadQueryFont(AppDisplay.instance().dpy, cast(char*)(fontname.toStringz));
69             if(this.xfont is null) {
70                 this.xfont = XLoadQueryFont(AppDisplay.instance().dpy, cast(char*)("fixed".toStringz));
71                 if(this.xfont is null) {
72                     //lout("error, cannot load font: %s", fontname);
73                     exit(EXIT_FAILURE);
74                 }
75             }
76             this.ascent = this.xfont.ascent;
77             this.descent = this.xfont.descent;
78         }
79 
80         this.h = this.ascent + this.descent;
81     }
82 
83     /**
84      * Destroy the X resources for this font.
85      */
86     private void destroy(Display* dpy) 
87     {
88         if(this.set) {
89             XFreeFontSet(dpy, this.set);
90         }
91         else if(this.xfont) {
92             XFreeFont(dpy, this.xfont);
93         }
94         this.set = null;
95         this.xfont = null;
96     }
97 
98     /**
99      * Free the given font object associated with a display. This will release
100      * the GC allocated memory.
101      * Params:
102      *  fnt=        Pointer to the font to destroy.
103      *  dpy=        Display associated with the font to destroy
104      * Example:
105      * ---
106      * auto f = Fnt(display, "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*");
107      *
108      * Fnt.free(f)
109      * ---
110      */
111     static void free(Display* dpy, Fnt* fnt) 
112     {
113         fnt.destroy(AppDisplay.instance().dpy);
114         DGC.free(fnt);
115     }
116 
117     /**
118      * Get the font extents for a given string.
119      * Params:
120      *  text=   Text to get the extents
121      *  tex=    Extents struct to fill in with the font information
122      */
123     void getexts(in string text, Extnts *tex) 
124     {
125         XRectangle r;
126 
127         if(text.length == 0) {
128             return;
129         }
130         if(this.set) {
131             XmbTextExtents(this.set, cast(char*)text.ptr, cast(int)text.length, null, &r);
132             tex.w = r.width;
133             tex.h = r.height;
134         }
135         else {
136             tex.h = this.ascent + this.descent;
137             tex.w = XTextWidth(this.xfont, cast(char*)text.ptr, cast(int)text.length);
138         }
139     }
140 
141     /**
142      * Get the rendered width of a string for the wrapped font.
143      * Params:
144      *  text=       Text to get the width for
145      * Returns:
146      *  Width of the text for the wrapped font.
147      */
148     uint getexts_width(in string text) 
149     {
150         Extnts tex;
151 
152         this.getexts(text, &tex);
153         return tex.w;
154     }
155 }