aboutsummaryrefslogtreecommitdiff
path: root/src/FbTk/XFontImp.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/FbTk/XFontImp.cc')
-rw-r--r--src/FbTk/XFontImp.cc398
1 files changed, 398 insertions, 0 deletions
diff --git a/src/FbTk/XFontImp.cc b/src/FbTk/XFontImp.cc
new file mode 100644
index 0000000..66adee3
--- /dev/null
+++ b/src/FbTk/XFontImp.cc
@@ -0,0 +1,398 @@
1// XFontImp.cc for FbTk fluxbox toolkit
2// Copyright (c) 2002 Henrik Kinnunen (fluxgen@linuxmail.org)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22// $Id: XFontImp.cc,v 1.5 2002/12/09 22:12:56 fluxgen Exp $
23
24#include "XFontImp.hh"
25#include "App.hh"
26
27#include <X11/Xutil.h>
28
29#include <iostream>
30#include <new>
31#include <cstdio>
32using namespace std;
33
34namespace FbTk {
35
36XFontImp::XFontImp(const char *fontname):m_rotfont(0), m_fontstruct(0),
37 m_angle(0), m_rotate(true) {
38 if (fontname != 0)
39 load(fontname);
40}
41
42XFontImp::~XFontImp() {
43 if (m_fontstruct != 0)
44 XFreeFont(App::instance()->display(), m_fontstruct);
45 if (m_rotfont != 0)
46 freeRotFont();
47}
48
49int XFontImp::ascent() const {
50 if (m_fontstruct == 0)
51 return 0;
52 if (m_rotfont != 0)
53 return m_rotfont->max_ascent;
54
55 return m_fontstruct->ascent;
56}
57
58bool XFontImp::load(const std::string &fontname) {
59 XFontStruct *font = XLoadQueryFont(App::instance()->display(), fontname.c_str());
60 if (font == 0)
61 return false;
62 if (m_fontstruct != 0) // free old font struct, if any
63 XFreeFont(App::instance()->display(), m_fontstruct);
64
65 m_fontstruct = font; //set new font
66
67 if (m_rotfont != 0) {
68 freeRotFont(); // free old rotated font
69 rotate(m_angle); // allocate new rotated font and rotate it to old angle
70 }
71
72 return true;
73}
74
75void XFontImp::drawText(Drawable w, int screen, GC gc, const char *text, size_t len, int x, int y) const {
76 if (m_fontstruct == 0)
77 return;
78 // use roated font functions?
79 if (m_rotfont != 0 && m_rotate) {
80 drawRotText(w, screen, gc, text, len, x, y);
81 return;
82 }
83
84 Display *disp = App::instance()->display();
85 XSetFont(disp, gc, m_fontstruct->fid);
86 XDrawString(disp, w, gc, x, y, text, len);
87}
88
89unsigned int XFontImp::textWidth(const char * const text, unsigned int size) const {
90 if (text == 0)
91 return 0;
92 if (m_fontstruct == 0)
93 return 0;
94 // check rotated font?
95 if (m_rotfont != 0)
96 return rotTextWidth(text, size);
97
98 return XTextWidth(m_fontstruct, text, size);
99}
100
101unsigned int XFontImp::height() const {
102 if (m_fontstruct == 0)
103 return 0;
104
105 return m_fontstruct->ascent + m_fontstruct->descent;
106}
107
108void XFontImp::rotate(float angle) {
109 //we must have a font loaded before we rotate
110 if (m_fontstruct == 0 || m_fontstruct->per_char == 0)
111 return;
112
113 if (m_rotfont != 0)
114 freeRotFont();
115
116 // no need for rotating, use regular font
117 if (angle == 0) {
118 m_angle = 0;
119 return;
120 }
121
122 //get positive angle
123 while (angle < 0)
124 angle += 360;
125
126 m_angle = angle;
127
128 char val;
129 XImage *I1, *I2;
130 // X system default vars
131 Display *dpy = App::instance()->display();
132 Window rootwin = DefaultRootWindow(dpy);
133 int screen = DefaultScreen(dpy);
134
135 GC font_gc;
136 char text[3];
137 int ichar, i, j, index, boxlen = 60;
138 int vert_w, vert_h, vert_len, bit_w, bit_h, bit_len;
139 int min_char, max_char;
140 unsigned char *vertdata, *bitdata;
141 int ascent, descent, lbearing, rbearing;
142
143 // get nearest vertical or horizontal direction
144 int dir = (int)((angle+45.0)/90.0)%4;
145
146 if (dir == 0) // no rotation
147 return;
148
149 // create the depth 1 canvas bitmap
150 Pixmap canvas = XCreatePixmap(dpy, rootwin, boxlen, boxlen, 1);
151
152 // create graphic context for our canvas
153 font_gc = XCreateGC(dpy, canvas, 0, 0);
154
155 XSetBackground(dpy, font_gc, None);
156
157 XSetFont(dpy, font_gc, m_fontstruct->fid);
158
159 // allocate space for rotated font
160 m_rotfont = new(nothrow) XRotFontStruct;
161
162 if (m_rotfont == 0) {
163 cerr<<"RotFont: out of memory"<<endl;
164 return;
165 }
166
167 // determine which characters are defined in font
168 min_char = m_fontstruct->min_char_or_byte2;
169 max_char = m_fontstruct->max_char_or_byte2;
170
171 // we only want printable chars
172 if (min_char<32)
173 min_char = 32;
174 if (max_char>126)
175 max_char = 126;
176
177 /* some overall font data ... */
178 m_rotfont->dir = dir;
179 m_rotfont->min_char = min_char;
180 m_rotfont->max_char = max_char;
181 m_rotfont->max_ascent = m_fontstruct->max_bounds.ascent;
182 m_rotfont->max_descent = m_fontstruct->max_bounds.descent;
183 m_rotfont->height = m_rotfont->max_ascent + m_rotfont->max_descent;
184
185 // font needs rotation
186 // loop through each character
187 for (ichar = min_char; ichar <= max_char; ichar++) {
188 index = ichar - m_fontstruct->min_char_or_byte2;
189
190 // per char dimensions ...
191 ascent = m_rotfont->per_char[ichar-32].ascent = m_fontstruct->per_char[index].ascent;
192 descent = m_rotfont->per_char[ichar-32].descent = m_fontstruct->per_char[index].descent;
193 lbearing = m_rotfont->per_char[ichar-32].lbearing = m_fontstruct->per_char[index].lbearing;
194 rbearing = m_rotfont->per_char[ichar-32].rbearing = m_fontstruct->per_char[index].rbearing;
195 m_rotfont->per_char[ichar-32].width = m_fontstruct->per_char[index].width;
196
197 // some space chars have zero body, but a bitmap can't have
198 if (!ascent && !descent)
199 ascent = m_rotfont->per_char[ichar-32].ascent = 1;
200 if (!lbearing && !rbearing)
201 rbearing = m_rotfont->per_char[ichar-32].rbearing = 1;
202
203 // glyph width and height when vertical
204 vert_w = rbearing - lbearing;
205 vert_h = ascent + descent;
206
207 // width in bytes
208 vert_len = (vert_w-1)/8+1;
209
210 XSetForeground(dpy, font_gc, None);
211 XFillRectangle(dpy, canvas, font_gc, 0, 0, boxlen, boxlen);
212
213 // draw the character centre top right on canvas
214 sprintf(text, "%c", ichar);
215 XSetForeground(dpy, font_gc, 1);
216 XDrawImageString(dpy, canvas, font_gc, boxlen/2 - lbearing,
217 boxlen/2 - descent, text, 1);
218
219 // reserve memory for first XImage
220 vertdata = (unsigned char *) malloc((unsigned)(vert_len*vert_h));
221
222 /* create the XImage ... */
223 I1 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap,
224 0, (char *)vertdata, vert_w, vert_h, 8, 0);
225
226 if (I1 == None) {
227 cerr<<"RotFont: Cant create ximage."<<endl;
228 delete m_rotfont;
229 m_rotfont = 0;
230 return;
231 }
232
233 I1->byte_order = I1->bitmap_bit_order = MSBFirst;
234
235 /* extract character from canvas ... */
236 XGetSubImage(dpy, canvas, boxlen/2, boxlen/2 - vert_h,
237 vert_w, vert_h, 1, XYPixmap, I1, 0, 0);
238 I1->format = XYBitmap;
239
240 /* width, height of rotated character ... */
241 if (dir == 2) {
242 bit_w = vert_w;
243 bit_h = vert_h;
244 } else {
245 bit_w = vert_h;
246 bit_h = vert_w;
247 }
248
249 /* width in bytes ... */
250 bit_len = (bit_w-1)/8 + 1;
251
252 m_rotfont->per_char[ichar-32].glyph.bit_w = bit_w;
253 m_rotfont->per_char[ichar-32].glyph.bit_h = bit_h;
254
255 /* reserve memory for the rotated image ... */
256 bitdata = (unsigned char *)calloc((unsigned)(bit_h * bit_len), 1);
257
258 /* create the image ... */
259 I2 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0,
260 (char *)bitdata, bit_w, bit_h, 8, 0);
261
262 if (I2 == None) {
263 cerr<<"XFontImp: Cant create ximage!"<<endl;
264 delete m_rotfont;
265 m_rotfont = 0;
266 return;
267 }
268
269 I2->byte_order = I2->bitmap_bit_order = MSBFirst;
270
271 /* map vertical data to rotated character ... */
272 for (j = 0; j < bit_h; j++) {
273 for (i = 0; i < bit_w; i++) {
274 /* map bits ... */
275 if (dir == 1) {
276 val = vertdata[i*vert_len + (vert_w-j-1)/8] &
277 (128>>((vert_w-j-1)%8));
278 } else if (dir == 2) {
279 val = vertdata[(vert_h-j-1)*vert_len +
280 (vert_w-i-1)/8] & (128>>((vert_w-i-1)%8));
281 } else {
282 val = vertdata[(vert_h-i-1)*vert_len + j/8] &
283 (128>>(j%8));
284 }
285 if (val) {
286 bitdata[j*bit_len + i/8] = bitdata[j*bit_len + i/8] |
287 (128>>(i%8));
288 }
289 }
290 }
291
292 // create this character's bitmap
293 m_rotfont->per_char[ichar-32].glyph.bm =
294 XCreatePixmap(dpy, rootwin, bit_w, bit_h, 1);
295
296 // put the image into the bitmap
297 XPutImage(dpy, m_rotfont->per_char[ichar-32].glyph.bm,
298 font_gc, I2, 0, 0, 0, 0, bit_w, bit_h);
299
300 // free the image and data
301 XDestroyImage(I1);
302 XDestroyImage(I2);
303 }
304
305 /* free pixmap and GC ... */
306 XFreePixmap(dpy, canvas);
307 XFreeGC(dpy, font_gc);
308
309}
310
311void XFontImp::freeRotFont() {
312 if (m_rotfont == 0)
313 return;
314 // loop through each character and free its pixmap
315 for (int ichar = m_rotfont->min_char - 32;
316 ichar <= m_rotfont->max_char - 32; ++ichar) {
317 XFreePixmap(App::instance()->display(), m_rotfont->per_char[ichar].glyph.bm);
318 }
319
320 delete m_rotfont;
321 m_rotfont = 0;
322}
323
324void XFontImp::drawRotText(Drawable w, int screen, GC gc, const char *text, size_t len, int x, int y) const {
325
326 Display *dpy = App::instance()->display();
327 static GC my_gc = 0;
328 int xp, yp, dir, ichar;
329
330 if (text == NULL || len<1)
331 return;
332
333 dir = m_rotfont->dir;
334 if (my_gc == 0)
335 my_gc = XCreateGC(dpy, w, 0, 0);
336
337 XCopyGC(dpy, gc, GCForeground|GCBackground, my_gc);
338
339 // vertical or upside down
340
341 XSetFillStyle(dpy, my_gc, FillStippled);
342
343 // loop through each character in texting
344 for (size_t i = 0; i<len; i++) {
345 ichar = text[i]-32;
346
347 // make sure it's a printing character
348 if (ichar >= 0 && ichar<95) {
349 // suitable offset
350 if (dir == 1) {
351 xp = x-m_rotfont->per_char[ichar].ascent;
352 yp = y-m_rotfont->per_char[ichar].rbearing;
353 } else if (dir == 2) {
354 xp = x-m_rotfont->per_char[ichar].rbearing;
355 yp = y-m_rotfont->per_char[ichar].descent+1;
356 } else {
357 xp = x-m_rotfont->per_char[ichar].descent+1;
358 yp = y+m_rotfont->per_char[ichar].lbearing;
359 }
360
361 // draw the glyph
362 XSetStipple(dpy, my_gc, m_rotfont->per_char[ichar].glyph.bm);
363
364 XSetTSOrigin(dpy, my_gc, xp, yp);
365
366 XFillRectangle(dpy, w, my_gc, xp, yp,
367 m_rotfont->per_char[ichar].glyph.bit_w,
368 m_rotfont->per_char[ichar].glyph.bit_h);
369
370 // advance position
371 if (dir == 1)
372 y -= m_rotfont->per_char[ichar].width;
373 else if (dir == 2)
374 x -= m_rotfont->per_char[ichar].width;
375 else
376 y += m_rotfont->per_char[ichar].width;
377 }
378 }
379}
380
381
382unsigned int XFontImp::rotTextWidth(const char * const text, unsigned int size) const {
383
384 if (text == 0)
385 return 0;
386
387 unsigned int width = 0;
388 for (size_t i = 0; i<size; i++) {
389 int ichar = text[i] - 32;
390 // make sure it's a printing character
391 if (ichar >= 0 && ichar < 95)
392 width += m_rotfont->per_char[ichar].width;
393 }
394
395 return width;
396}
397
398};