1
// XFontImp.cc for FbTk fluxbox toolkit
2
// Copyright (c) 2002 - 2005 Henrik Kinnunen (fluxgen at fluxbox dot org)
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:
11
// The above copyright notice and this permission notice shall be included in
12
// all copies or substantial portions of the Software.
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.
22
// $Id: XFontImp.cc 3864 2005-01-24 18:02:34Z mathias $
24
#include "XFontImp.hh"
26
#include "GContext.hh"
27
#include "FbPixmap.hh"
30
#include <X11/Xutil.h>
43
XFontImp::XFontImp(const char *fontname):m_rotfont(0), m_fontstruct(0),
44
m_angle(0), m_rotate(true) {
49
XFontImp::~XFontImp() {
50
if (m_fontstruct != 0)
51
XFreeFont(App::instance()->display(), m_fontstruct);
56
int XFontImp::ascent() const {
57
if (m_fontstruct == 0)
60
return m_rotfont->max_ascent;
62
return m_fontstruct->ascent;
65
bool XFontImp::load(const std::string &fontname) {
66
XFontStruct *font = XLoadQueryFont(App::instance()->display(), fontname.c_str());
69
if (m_fontstruct != 0) // free old font struct, if any
70
XFreeFont(App::instance()->display(), m_fontstruct);
72
m_fontstruct = font; //set new font
75
freeRotFont(); // free old rotated font
76
rotate(m_angle); // allocate new rotated font and rotate it to old angle
82
void XFontImp::drawText(const FbDrawable &w, int screen, GC gc, const char *text, size_t len, int x, int y) const {
83
if (m_fontstruct == 0)
85
// use roated font functions?
86
if (m_rotfont != 0 && m_rotate) {
87
drawRotText(w.drawable(), screen, gc, text, len, x, y);
91
XSetFont(w.display(), gc, m_fontstruct->fid);
92
XDrawString(w.display(), w.drawable(), gc, x, y, text, len);
95
unsigned int XFontImp::textWidth(const char * const text, unsigned int size) const {
96
if (text == 0 || m_fontstruct == 0)
99
// check rotated font?
101
return rotTextWidth(text, size);
103
return XTextWidth(m_fontstruct, text, size);
106
unsigned int XFontImp::height() const {
107
if (m_fontstruct == 0)
110
return m_fontstruct->ascent + m_fontstruct->descent;
113
void XFontImp::rotate(float angle) {
114
//we must have a font loaded before we rotate
115
if (m_fontstruct == 0 || m_fontstruct->per_char == 0)
121
// no need for rotating, use regular font
135
// X system default vars
136
Display *dpy = App::instance()->display();
137
Window rootwin = DefaultRootWindow(dpy);
138
int screen = DefaultScreen(dpy);
141
int ichar, i, j, index, boxlen = 60;
142
int vert_w, vert_h, vert_len, bit_w, bit_h, bit_len;
143
int min_char, max_char;
144
unsigned char *vertdata, *bitdata;
145
int ascent, descent, lbearing, rbearing;
147
// get nearest vertical or horizontal direction
148
int dir = (int)((angle+45.0)/90.0)%4;
150
if (dir == 0) // no rotation
153
// create the depth 1 canvas bitmap
154
FbTk::FbPixmap canvas(rootwin, boxlen, boxlen, 1);
156
// create graphic context for our canvas
157
FbTk::GContext font_gc(canvas);
158
font_gc.setBackground(None);
159
font_gc.setFont(m_fontstruct->fid);
161
// allocate space for rotated font
162
m_rotfont = new(nothrow) XRotFontStruct;
164
if (m_rotfont == 0) {
165
cerr<<"RotFont: "<<_FBTKTEXT(Error, OutOfMemory, "Out of memory", "Something couldn't allocate memory")<<endl;
169
// determine which characters are defined in font
170
min_char = m_fontstruct->min_char_or_byte2;
171
max_char = m_fontstruct->max_char_or_byte2;
173
// we only want printable chars
179
/* some overall font data ... */
180
m_rotfont->dir = dir;
181
m_rotfont->min_char = min_char;
182
m_rotfont->max_char = max_char;
183
m_rotfont->max_ascent = m_fontstruct->max_bounds.ascent;
184
m_rotfont->max_descent = m_fontstruct->max_bounds.descent;
185
m_rotfont->height = m_rotfont->max_ascent + m_rotfont->max_descent;
187
// font needs rotation
188
// loop through each character
189
for (ichar = min_char; ichar <= max_char; ichar++) {
190
index = ichar - m_fontstruct->min_char_or_byte2;
192
// per char dimensions ...
193
ascent = m_rotfont->per_char[ichar-32].ascent = m_fontstruct->per_char[index].ascent;
194
descent = m_rotfont->per_char[ichar-32].descent = m_fontstruct->per_char[index].descent;
195
lbearing = m_rotfont->per_char[ichar-32].lbearing = m_fontstruct->per_char[index].lbearing;
196
rbearing = m_rotfont->per_char[ichar-32].rbearing = m_fontstruct->per_char[index].rbearing;
197
m_rotfont->per_char[ichar-32].width = m_fontstruct->per_char[index].width;
199
// some space chars have zero body, but a bitmap can't have
200
if (!ascent && !descent)
201
ascent = m_rotfont->per_char[ichar-32].ascent = 1;
202
if (!lbearing && !rbearing)
203
rbearing = m_rotfont->per_char[ichar-32].rbearing = 1;
205
// glyph width and height when vertical
206
vert_w = rbearing - lbearing;
207
vert_h = ascent + descent;
210
vert_len = (vert_w-1)/8+1;
212
font_gc.setForeground(None);
213
canvas.fillRectangle(font_gc.gc(),
216
// draw the character centre top right on canvas
217
sprintf(text, "%c", ichar);
218
font_gc.setForeground(1);
219
XDrawImageString(dpy, canvas.drawable(), font_gc.gc(),
221
boxlen/2 - descent, text, 1);
223
// reserve memory for first XImage
224
vertdata = new unsigned char[vert_len * vert_h];
226
XImage *I1 = XCreateImage(dpy, DefaultVisual(dpy, screen),
229
vert_w, vert_h, 8, 0);
232
cerr<<"RotFont: "<<_FBTKTEXT(Error, CreateXImage, "Cant create XImage", "XCreateImage failed for some reason")<<"."<<endl;
238
I1->byte_order = I1->bitmap_bit_order = MSBFirst;
240
// extract character from canvas
241
XGetSubImage(dpy, canvas.drawable(),
242
boxlen/2, boxlen/2 - vert_h,
243
vert_w, vert_h, 1, XYPixmap, I1, 0, 0);
245
I1->format = XYBitmap;
247
// width, height of rotated character
257
bit_len = (bit_w-1)/8 + 1;
259
m_rotfont->per_char[ichar-32].glyph.bit_w = bit_w;
260
m_rotfont->per_char[ichar-32].glyph.bit_h = bit_h;
262
// reserve memory for the rotated image
263
bitdata = (unsigned char *)calloc((unsigned)(bit_h * bit_len), 1);
266
XImage *I2 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0,
267
(char *)bitdata, bit_w, bit_h, 8, 0);
270
cerr<<"XFontImp: "<<_FBTKTEXT(Error, CreateXImage, "Cant create XImage", "XCreateImage failed for some reason")<<"."<<endl;
276
I2->byte_order = I2->bitmap_bit_order = MSBFirst;
278
// map vertical data to rotated character
279
for (j = 0; j < bit_h; j++) {
280
for (i = 0; i < bit_w; i++) {
283
val = vertdata[i*vert_len + (vert_w-j-1)/8] &
284
(128>>((vert_w-j-1)%8));
285
} else if (dir == 2) {
286
val = vertdata[(vert_h-j-1)*vert_len +
287
(vert_w-i-1)/8] & (128>>((vert_w-i-1)%8));
289
val = vertdata[(vert_h-i-1)*vert_len + j/8] &
293
bitdata[j*bit_len + i/8] = bitdata[j*bit_len + i/8] |
299
// create this character's bitmap
300
m_rotfont->per_char[ichar-32].glyph.bm =
301
XCreatePixmap(dpy, rootwin, bit_w, bit_h, 1);
303
// put the image into the bitmap
304
XPutImage(dpy, m_rotfont->per_char[ichar-32].glyph.bm,
305
font_gc.gc(), I2, 0, 0, 0, 0, bit_w, bit_h);
307
// free the image and data
314
void XFontImp::freeRotFont() {
317
// loop through each character and free its pixmap
318
for (int ichar = m_rotfont->min_char - 32;
319
ichar <= m_rotfont->max_char - 32; ++ichar) {
320
XFreePixmap(App::instance()->display(), m_rotfont->per_char[ichar].glyph.bm);
327
void XFontImp::drawRotText(Drawable w, int screen, GC gc, const char *text, size_t len, int x, int y) const {
329
Display *dpy = App::instance()->display();
331
int xp, yp, dir, ichar;
333
if (text == NULL || len<1)
336
dir = m_rotfont->dir;
338
my_gc = XCreateGC(dpy, w, 0, 0);
340
XCopyGC(dpy, gc, GCForeground|GCBackground, my_gc);
342
// vertical or upside down
344
XSetFillStyle(dpy, my_gc, FillStippled);
346
// loop through each character in texting
347
for (size_t i = 0; i<len; i++) {
350
// make sure it's a printing character
351
if (ichar >= 0 && ichar<95) {
354
xp = x-m_rotfont->per_char[ichar].ascent;
355
yp = y-m_rotfont->per_char[ichar].rbearing;
356
} else if (dir == 2) {
357
xp = x-m_rotfont->per_char[ichar].rbearing;
358
yp = y-m_rotfont->per_char[ichar].descent+1;
360
xp = x-m_rotfont->per_char[ichar].descent+1;
361
yp = y+m_rotfont->per_char[ichar].lbearing;
365
XSetStipple(dpy, my_gc, m_rotfont->per_char[ichar].glyph.bm);
367
XSetTSOrigin(dpy, my_gc, xp, yp);
369
XFillRectangle(dpy, w, my_gc, xp, yp,
370
m_rotfont->per_char[ichar].glyph.bit_w,
371
m_rotfont->per_char[ichar].glyph.bit_h);
375
y -= m_rotfont->per_char[ichar].width;
377
x -= m_rotfont->per_char[ichar].width;
379
y += m_rotfont->per_char[ichar].width;
385
unsigned int XFontImp::rotTextWidth(const char * const text, unsigned int size) const {
390
unsigned int width = 0;
391
for (size_t i = 0; i<size; i++) {
392
int ichar = text[i] - 32;
393
// make sure it's a printing character
394
if (ichar >= 0 && ichar < 95)
395
width += m_rotfont->per_char[ichar].width;