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.cc396
1 files changed, 396 insertions, 0 deletions
diff --git a/src/FbTk/XFontImp.cc b/src/FbTk/XFontImp.cc
new file mode 100644
index 0000000..e253aa6
--- /dev/null
+++ b/src/FbTk/XFontImp.cc
@@ -0,0 +1,396 @@
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.6 2003/09/11 20:00:09 fluxgen Exp $
23
24#include "XFontImp.hh"
25#include "App.hh"
26#include "GContext.hh"
27#include "FbPixmap.hh"
28
29#include <X11/Xutil.h>
30
31#include <iostream>
32#include <new>
33#include <cstdio>
34using namespace std;
35
36namespace FbTk {
37
38XFontImp::XFontImp(const char *fontname):m_rotfont(0), m_fontstruct(0),
39 m_angle(0), m_rotate(true) {
40 if (fontname != 0)
41 load(fontname);
42}
43
44XFontImp::~XFontImp() {
45 if (m_fontstruct != 0)
46 XFreeFont(App::instance()->display(), m_fontstruct);
47 if (m_rotfont != 0)
48 freeRotFont();
49}
50
51int XFontImp::ascent() const {
52 if (m_fontstruct == 0)
53 return 0;
54 if (m_rotfont != 0)
55 return m_rotfont->max_ascent;
56
57 return m_fontstruct->ascent;
58}
59
60bool XFontImp::load(const std::string &fontname) {
61 XFontStruct *font = XLoadQueryFont(App::instance()->display(), fontname.c_str());
62 if (font == 0)
63 return false;
64 if (m_fontstruct != 0) // free old font struct, if any
65 XFreeFont(App::instance()->display(), m_fontstruct);
66
67 m_fontstruct = font; //set new font
68
69 if (m_rotfont != 0) {
70 freeRotFont(); // free old rotated font
71 rotate(m_angle); // allocate new rotated font and rotate it to old angle
72 }
73
74 return true;
75}
76
77void XFontImp::drawText(Drawable w, int screen, GC gc, const char *text, size_t len, int x, int y) const {
78 if (m_fontstruct == 0)
79 return;
80 // use roated font functions?
81 if (m_rotfont != 0 && m_rotate) {
82 drawRotText(w, screen, gc, text, len, x, y);
83 return;
84 }
85
86 Display *disp = App::instance()->display();
87 XSetFont(disp, gc, m_fontstruct->fid);
88 XDrawString(disp, w, gc, x, y, text, len);
89}
90
91unsigned int XFontImp::textWidth(const char * const text, unsigned int size) const {
92 if (text == 0)
93 return 0;
94 if (m_fontstruct == 0)
95 return 0;
96 // check rotated font?
97 if (m_rotfont != 0)
98 return rotTextWidth(text, size);
99
100 return XTextWidth(m_fontstruct, text, size);
101}
102
103unsigned int XFontImp::height() const {
104 if (m_fontstruct == 0)
105 return 0;
106
107 return m_fontstruct->ascent + m_fontstruct->descent;
108}
109
110void XFontImp::rotate(float angle) {
111 //we must have a font loaded before we rotate
112 if (m_fontstruct == 0 || m_fontstruct->per_char == 0)
113 return;
114
115 if (m_rotfont != 0)
116 freeRotFont();
117
118 // no need for rotating, use regular font
119 if (angle == 0) {
120 m_angle = 0;
121 return;
122 }
123
124 //get positive angle
125 while (angle < 0)
126 angle += 360;
127
128 m_angle = angle;
129
130 // X system default vars
131 Display *dpy = App::instance()->display();
132 Window rootwin = DefaultRootWindow(dpy);
133 int screen = DefaultScreen(dpy);
134
135 char text[3];
136 int ichar, i, j, index, boxlen = 60;
137 int vert_w, vert_h, vert_len, bit_w, bit_h, bit_len;
138 int min_char, max_char;
139 unsigned char *vertdata, *bitdata;
140 int ascent, descent, lbearing, rbearing;
141
142 // get nearest vertical or horizontal direction
143 int dir = (int)((angle+45.0)/90.0)%4;
144
145 if (dir == 0) // no rotation
146 return;
147
148 // create the depth 1 canvas bitmap
149 FbTk::FbPixmap canvas(rootwin, boxlen, boxlen, 1);
150
151 // create graphic context for our canvas
152 FbTk::GContext font_gc(canvas);
153 font_gc.setBackground(None);
154 font_gc.setFont(m_fontstruct->fid);
155
156 // allocate space for rotated font
157 m_rotfont = new(nothrow) XRotFontStruct;
158
159 if (m_rotfont == 0) {
160 cerr<<"RotFont: out of memory"<<endl;
161 return;
162 }
163
164 // determine which characters are defined in font
165 min_char = m_fontstruct->min_char_or_byte2;
166 max_char = m_fontstruct->max_char_or_byte2;
167
168 // we only want printable chars
169 if (min_char<32)
170 min_char = 32;
171 if (max_char>126)
172 max_char = 126;
173
174 /* some overall font data ... */
175 m_rotfont->dir = dir;
176 m_rotfont->min_char = min_char;
177 m_rotfont->max_char = max_char;
178 m_rotfont->max_ascent = m_fontstruct->max_bounds.ascent;
179 m_rotfont->max_descent = m_fontstruct->max_bounds.descent;
180 m_rotfont->height = m_rotfont->max_ascent + m_rotfont->max_descent;
181
182 // font needs rotation
183 // loop through each character
184 for (ichar = min_char; ichar <= max_char; ichar++) {
185 index = ichar - m_fontstruct->min_char_or_byte2;
186
187 // per char dimensions ...
188 ascent = m_rotfont->per_char[ichar-32].ascent = m_fontstruct->per_char[index].ascent;
189 descent = m_rotfont->per_char[ichar-32].descent = m_fontstruct->per_char[index].descent;
190 lbearing = m_rotfont->per_char[ichar-32].lbearing = m_fontstruct->per_char[index].lbearing;
191 rbearing = m_rotfont->per_char[ichar-32].rbearing = m_fontstruct->per_char[index].rbearing;
192 m_rotfont->per_char[ichar-32].width = m_fontstruct->per_char[index].width;
193
194 // some space chars have zero body, but a bitmap can't have
195 if (!ascent && !descent)
196 ascent = m_rotfont->per_char[ichar-32].ascent = 1;
197 if (!lbearing && !rbearing)
198 rbearing = m_rotfont->per_char[ichar-32].rbearing = 1;
199
200 // glyph width and height when vertical
201 vert_w = rbearing - lbearing;
202 vert_h = ascent + descent;
203
204 // width in bytes
205 vert_len = (vert_w-1)/8+1;
206
207 font_gc.setForeground(None);
208 canvas.fillRectangle(font_gc.gc(),
209 0, 0,
210 boxlen, boxlen);
211 // draw the character centre top right on canvas
212 sprintf(text, "%c", ichar);
213 font_gc.setForeground(1);
214 XDrawImageString(dpy, canvas.drawable(), font_gc.gc(),
215 boxlen/2 - lbearing,
216 boxlen/2 - descent, text, 1);
217
218 // reserve memory for first XImage
219 vertdata = new unsigned char[vert_len * vert_h];
220
221 XImage *I1 = XCreateImage(dpy, DefaultVisual(dpy, screen),
222 1, XYBitmap,
223 0, (char *)vertdata,
224 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.drawable(),
237 boxlen/2, boxlen/2 - vert_h,
238 vert_w, vert_h, 1, XYPixmap, I1, 0, 0);
239
240 I1->format = XYBitmap;
241
242 // width, height of rotated character
243 if (dir == 2) {
244 bit_w = vert_w;
245 bit_h = vert_h;
246 } else {
247 bit_w = vert_h;
248 bit_h = vert_w;
249 }
250
251 // width in bytes
252 bit_len = (bit_w-1)/8 + 1;
253
254 m_rotfont->per_char[ichar-32].glyph.bit_w = bit_w;
255 m_rotfont->per_char[ichar-32].glyph.bit_h = bit_h;
256
257 // reserve memory for the rotated image
258 bitdata = (unsigned char *)calloc((unsigned)(bit_h * bit_len), 1);
259
260 // create the image
261 XImage *I2 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0,
262 (char *)bitdata, bit_w, bit_h, 8, 0);
263
264 if (I2 == None) {
265 cerr<<"XFontImp: Cant create ximage!"<<endl;
266 delete m_rotfont;
267 m_rotfont = 0;
268 return;
269 }
270
271 I2->byte_order = I2->bitmap_bit_order = MSBFirst;
272
273 // map vertical data to rotated character
274 for (j = 0; j < bit_h; j++) {
275 for (i = 0; i < bit_w; i++) {
276 char val = 0;
277 if (dir == 1) {
278 val = vertdata[i*vert_len + (vert_w-j-1)/8] &
279 (128>>((vert_w-j-1)%8));
280 } else if (dir == 2) {
281 val = vertdata[(vert_h-j-1)*vert_len +
282 (vert_w-i-1)/8] & (128>>((vert_w-i-1)%8));
283 } else {
284 val = vertdata[(vert_h-i-1)*vert_len + j/8] &
285 (128>>(j%8));
286 }
287 if (val) {
288 bitdata[j*bit_len + i/8] = bitdata[j*bit_len + i/8] |
289 (128>>(i%8));
290 }
291 }
292 }
293
294 // create this character's bitmap
295 m_rotfont->per_char[ichar-32].glyph.bm =
296 XCreatePixmap(dpy, rootwin, bit_w, bit_h, 1);
297
298 // put the image into the bitmap
299 XPutImage(dpy, m_rotfont->per_char[ichar-32].glyph.bm,
300 font_gc.gc(), I2, 0, 0, 0, 0, bit_w, bit_h);
301
302 // free the image and data
303 XDestroyImage(I1);
304 XDestroyImage(I2);
305 }
306
307}
308
309void XFontImp::freeRotFont() {
310 if (m_rotfont == 0)
311 return;
312 // loop through each character and free its pixmap
313 for (int ichar = m_rotfont->min_char - 32;
314 ichar <= m_rotfont->max_char - 32; ++ichar) {
315 XFreePixmap(App::instance()->display(), m_rotfont->per_char[ichar].glyph.bm);
316 }
317
318 delete m_rotfont;
319 m_rotfont = 0;
320}
321
322void XFontImp::drawRotText(Drawable w, int screen, GC gc, const char *text, size_t len, int x, int y) const {
323
324 Display *dpy = App::instance()->display();
325 static GC my_gc = 0;
326 int xp, yp, dir, ichar;
327
328 if (text == NULL || len<1)
329 return;
330
331 dir = m_rotfont->dir;
332 if (my_gc == 0)
333 my_gc = XCreateGC(dpy, w, 0, 0);
334
335 XCopyGC(dpy, gc, GCForeground|GCBackground, my_gc);
336
337 // vertical or upside down
338
339 XSetFillStyle(dpy, my_gc, FillStippled);
340
341 // loop through each character in texting
342 for (size_t i = 0; i<len; i++) {
343 ichar = text[i]-32;
344
345 // make sure it's a printing character
346 if (ichar >= 0 && ichar<95) {
347 // suitable offset
348 if (dir == 1) {
349 xp = x-m_rotfont->per_char[ichar].ascent;
350 yp = y-m_rotfont->per_char[ichar].rbearing;
351 } else if (dir == 2) {
352 xp = x-m_rotfont->per_char[ichar].rbearing;
353 yp = y-m_rotfont->per_char[ichar].descent+1;
354 } else {
355 xp = x-m_rotfont->per_char[ichar].descent+1;
356 yp = y+m_rotfont->per_char[ichar].lbearing;
357 }
358
359 // draw the glyph
360 XSetStipple(dpy, my_gc, m_rotfont->per_char[ichar].glyph.bm);
361
362 XSetTSOrigin(dpy, my_gc, xp, yp);
363
364 XFillRectangle(dpy, w, my_gc, xp, yp,
365 m_rotfont->per_char[ichar].glyph.bit_w,
366 m_rotfont->per_char[ichar].glyph.bit_h);
367
368 // advance position
369 if (dir == 1)
370 y -= m_rotfont->per_char[ichar].width;
371 else if (dir == 2)
372 x -= m_rotfont->per_char[ichar].width;
373 else
374 y += m_rotfont->per_char[ichar].width;
375 }
376 }
377}
378
379
380unsigned int XFontImp::rotTextWidth(const char * const text, unsigned int size) const {
381
382 if (text == 0)
383 return 0;
384
385 unsigned int width = 0;
386 for (size_t i = 0; i<size; i++) {
387 int ichar = text[i] - 32;
388 // make sure it's a printing character
389 if (ichar >= 0 && ichar < 95)
390 width += m_rotfont->per_char[ichar].width;
391 }
392
393 return width;
394}
395
396};