aboutsummaryrefslogtreecommitdiff
path: root/src/DrawUtil.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/DrawUtil.cc')
-rw-r--r--src/DrawUtil.cc467
1 files changed, 467 insertions, 0 deletions
diff --git a/src/DrawUtil.cc b/src/DrawUtil.cc
new file mode 100644
index 0000000..a276e48
--- /dev/null
+++ b/src/DrawUtil.cc
@@ -0,0 +1,467 @@
1// DrawUtil.cc for fluxbox
2// Copyright (c) 2001-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: DrawUtil.cc,v 1.4 2002/01/09 14:11:20 fluxgen Exp $
23
24#ifdef HAVE_CONFIG_H
25# include "config.h"
26#endif //HAVE_CONFIG_H
27
28#include "DrawUtil.hh"
29#include "StringUtil.hh"
30#include "i18n.hh"
31
32#include <cstdlib>
33#include <cassert>
34#include <cstdio>
35#include <iostream>
36#include <X11/Xutil.h>
37
38using namespace std;
39
40// ----------------------------------------------------------------------
41// xvertext, Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma)
42// ----------------------------------------------------------------------
43
44//------- XRotLoadFont -------------------
45// Load the rotated version of a given font
46//----------------------------------------
47DrawUtil::XRotFontStruct *DrawUtil::XRotLoadFont(Display *dpy, char *fontname, float angle) {
48 char val;
49 XImage *I1, *I2;
50 Pixmap canvas;
51 Window root;
52 int screen;
53 GC font_gc;
54 char text[3];/*, errstr[300];*/
55 XFontStruct *fontstruct;
56 XRotFontStruct *rotfont;
57 int ichar, i, j, index, boxlen = 60, dir;
58 int vert_w, vert_h, vert_len, bit_w, bit_h, bit_len;
59 int min_char, max_char;
60 unsigned char *vertdata, *bitdata;
61 int ascent, descent, lbearing, rbearing;
62 int on = 1, off = 0;
63
64 /* make angle positive ... */
65 if (angle < 0) do angle += 360; while (angle < 0);
66
67 /* get nearest vertical or horizontal direction ... */
68 dir = (int)((angle+45.)/90.)%4;
69
70 /* useful macros ... */
71 screen = DefaultScreen(dpy);
72 root = DefaultRootWindow(dpy);
73
74 /* create the depth 1 canvas bitmap ... */
75 canvas = XCreatePixmap(dpy, root, boxlen, boxlen, 1);
76
77 /* create a GC ... */
78 font_gc = XCreateGC(dpy, canvas, 0, 0);
79 XSetBackground(dpy, font_gc, off);
80
81 /* load the font ... */
82 fontstruct = XLoadQueryFont(dpy, fontname);
83 if (fontstruct == NULL) {
84 cerr<<"Fluxbox::DrawUtil: No font"<<endl;
85 return 0;
86 }
87
88 XSetFont(dpy, font_gc, fontstruct->fid);
89
90 /* allocate space for rotated font ... */
91 rotfont = (XRotFontStruct *)malloc((unsigned)sizeof(XRotFontStruct));
92
93 if (rotfont == 0) {
94 cerr<<"Fluxbox::DrawUtil: out of memory"<<endl;
95 return 0;
96 }
97
98 /* determine which characters are defined in font ... */
99 min_char = fontstruct->min_char_or_byte2;
100 max_char = fontstruct->max_char_or_byte2;
101
102 /* we only want printing characters ... */
103 if (min_char<32) min_char = 32;
104 if (max_char>126) max_char = 126;
105
106 /* some overall font data ... */
107 rotfont->name = StringUtil::strdup(fontname);
108 rotfont->dir = dir;
109 rotfont->min_char = min_char;
110 rotfont->max_char = max_char;
111 rotfont->max_ascent = fontstruct->max_bounds.ascent;
112 rotfont->max_descent = fontstruct->max_bounds.descent;
113 rotfont->height = rotfont->max_ascent+rotfont->max_descent;
114
115 /* remember xfontstruct for `normal' text ... */
116 if (dir == 0)
117 rotfont->xfontstruct = fontstruct;
118 else {
119 /* font needs rotation ... */
120 /* loop through each character ... */
121 for (ichar = min_char; ichar <= max_char; ichar++) {
122 index = ichar-fontstruct->min_char_or_byte2;
123
124 /* per char dimensions ... */
125 ascent = rotfont->per_char[ichar-32].ascent =
126 fontstruct->per_char[index].ascent;
127 descent = rotfont->per_char[ichar-32].descent =
128 fontstruct->per_char[index].descent;
129 lbearing = rotfont->per_char[ichar-32].lbearing =
130 fontstruct->per_char[index].lbearing;
131 rbearing = rotfont->per_char[ichar-32].rbearing =
132 fontstruct->per_char[index].rbearing;
133 rotfont->per_char[ichar-32].width =
134 fontstruct->per_char[index].width;
135
136 /* some space chars have zero body, but a bitmap can't have ... */
137 if (!ascent && !descent)
138 ascent = rotfont->per_char[ichar-32].ascent = 1;
139 if (!lbearing && !rbearing)
140 rbearing = rotfont->per_char[ichar-32].rbearing = 1;
141
142 /* glyph width and height when vertical ... */
143 vert_w = rbearing-lbearing;
144 vert_h = ascent+descent;
145
146 /* width in bytes ... */
147 vert_len = (vert_w-1)/8+1;
148
149 XSetForeground(dpy, font_gc, off);
150 XFillRectangle(dpy, canvas, font_gc, 0, 0, boxlen, boxlen);
151
152 /* draw the character centre top right on canvas ... */
153 sprintf(text, "%c", ichar);
154 XSetForeground(dpy, font_gc, on);
155 XDrawImageString(dpy, canvas, font_gc, boxlen/2 - lbearing,
156 boxlen/2 - descent, text, 1);
157
158 /* reserve memory for first XImage ... */
159 vertdata = (unsigned char *) malloc((unsigned)(vert_len*vert_h));
160
161 /* create the XImage ... */
162 I1 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap,
163 0, (char *)vertdata, vert_w, vert_h, 8, 0);
164
165 if (I1 == NULL) {
166 cerr<<"Fluxbox::DrawUtil: Cant create ximage."<<endl;
167 return NULL;
168 }
169
170 I1->byte_order = I1->bitmap_bit_order = MSBFirst;
171
172 /* extract character from canvas ... */
173 XGetSubImage(dpy, canvas, boxlen/2, boxlen/2-vert_h,
174 vert_w, vert_h, 1, XYPixmap, I1, 0, 0);
175 I1->format = XYBitmap;
176
177 /* width, height of rotated character ... */
178 if (dir == 2) {
179 bit_w = vert_w;
180 bit_h = vert_h;
181 } else {
182 bit_w = vert_h;
183 bit_h = vert_w;
184 }
185
186 /* width in bytes ... */
187 bit_len = (bit_w-1)/8 + 1;
188
189 rotfont->per_char[ichar-32].glyph.bit_w = bit_w;
190 rotfont->per_char[ichar-32].glyph.bit_h = bit_h;
191
192 /* reserve memory for the rotated image ... */
193 bitdata = (unsigned char *)calloc((unsigned)(bit_h*bit_len), 1);
194
195 /* create the image ... */
196 I2 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0,
197 (char *)bitdata, bit_w, bit_h, 8, 0);
198
199 if (I2 == NULL) {
200 cerr<<"Font::DrawUtil: Cant create ximage!"<<endl;
201 return 0;
202 }
203
204 I2->byte_order = I2->bitmap_bit_order = MSBFirst;
205
206 /* map vertical data to rotated character ... */
207 for (j = 0; j < bit_h; j++) {
208 for (i = 0; i < bit_w; i++) {
209 /* map bits ... */
210 if (dir == 1) {
211 val = vertdata[i*vert_len + (vert_w-j-1)/8] &
212 (128>>((vert_w-j-1)%8));
213 } else if (dir == 2) {
214 val = vertdata[(vert_h-j-1)*vert_len +
215 (vert_w-i-1)/8] & (128>>((vert_w-i-1)%8));
216 } else {
217 val = vertdata[(vert_h-i-1)*vert_len + j/8] &
218 (128>>(j%8));
219 }
220 if (val) {
221 bitdata[j*bit_len + i/8] = bitdata[j*bit_len + i/8] |
222 (128>>(i%8));
223 }
224 }
225 }
226
227 /* create this character's bitmap ... */
228 rotfont->per_char[ichar-32].glyph.bm =
229 XCreatePixmap(dpy, root, bit_w, bit_h, 1);
230
231 /* put the image into the bitmap ... */
232 XPutImage(dpy, rotfont->per_char[ichar-32].glyph.bm,
233 font_gc, I2, 0, 0, 0, 0, bit_w, bit_h);
234
235 /* free the image and data ... */
236 XDestroyImage(I1);
237 XDestroyImage(I2);
238 /* free((char *)bitdata); -- XDestroyImage does this
239 free((char *)vertdata);*/
240 }
241 XFreeFont(dpy, fontstruct);
242 }
243
244 /* free pixmap and GC ... */
245 XFreePixmap(dpy, canvas);
246 XFreeGC(dpy, font_gc);
247
248 return rotfont;
249}
250
251//------- XRotUnloadFont -----------------
252// Free the resources associated with a
253// rotated font
254//----------------------------------------
255void DrawUtil::XRotUnloadFont(Display *dpy, XRotFontStruct *rotfont)
256{
257 int ichar;
258
259 if (rotfont->dir == 0)
260 XFreeFont(dpy, rotfont->xfontstruct);
261 else {
262 /* loop through each character, freeing its pixmap ... */
263 for (ichar = rotfont->min_char-32; ichar <= rotfont->max_char-32;
264 ichar++)
265 XFreePixmap(dpy, rotfont->per_char[ichar].glyph.bm);
266 }
267
268 free((char *)rotfont->name);
269 free((char *)rotfont);
270}
271
272//------- XRotTextWidth ------------------
273// Returns the width of a rotated string
274//----------------------------------------
275unsigned int DrawUtil::XRotTextWidth(XRotFontStruct *rotfont, char *str, int len)
276{
277 int i, width = 0, ichar;
278
279 if (str == NULL)
280 return 0;
281
282 if (rotfont->dir == 0)
283 width = XTextWidth(rotfont->xfontstruct, str, strlen(str));
284 else {
285 for (i = 0; i<len; i++) {
286 ichar = str[i]-32;
287
288 /* make sure it's a printing character ... */
289 if (ichar >= 0 && ichar<95)
290 width += rotfont->per_char[ichar].width;
291 }
292 }
293 return width;
294}
295
296
297//------- XRotDrawString -----------------
298// A front end to XRotDrawString : mimics XDrawString
299//----------------------------------------
300void DrawUtil::XRotDrawString(Display *dpy, XRotFontStruct *rotfont, Drawable drawable,
301 GC gc, int x, int y, char *str, int len)
302{
303 static GC my_gc = 0;
304 int i, xp, yp, dir, ichar;
305
306 if (str == NULL || len<1)
307 return;
308
309 dir = rotfont->dir;
310 if (my_gc == 0)
311 my_gc = XCreateGC(dpy, drawable, 0, 0);
312
313 XCopyGC(dpy, gc, GCForeground|GCBackground, my_gc);
314
315 /* a horizontal string is easy ... */
316 if (dir == 0) {
317 XSetFillStyle(dpy, my_gc, FillSolid);
318 XSetFont(dpy, my_gc, rotfont->xfontstruct->fid);
319 XDrawString(dpy, drawable, my_gc, x, y, str, len);
320 return;
321 }
322
323 /* vertical or upside down ... */
324
325 XSetFillStyle(dpy, my_gc, FillStippled);
326
327 /* loop through each character in string ... */
328 for (i = 0; i<len; i++) {
329 ichar = str[i]-32;
330
331 /* make sure it's a printing character ... */
332 if (ichar >= 0 && ichar<95) {
333 /* suitable offset ... */
334 if (dir == 1) {
335 xp = x-rotfont->per_char[ichar].ascent;
336 yp = y-rotfont->per_char[ichar].rbearing;
337 } else if (dir == 2) {
338 xp = x-rotfont->per_char[ichar].rbearing;
339 yp = y-rotfont->per_char[ichar].descent+1;
340 } else {
341 xp = x-rotfont->per_char[ichar].descent+1;
342 yp = y+rotfont->per_char[ichar].lbearing;
343 }
344
345 /* draw the glyph ... */
346 XSetStipple(dpy, my_gc, rotfont->per_char[ichar].glyph.bm);
347
348 XSetTSOrigin(dpy, my_gc, xp, yp);
349
350 XFillRectangle(dpy, drawable, my_gc, xp, yp,
351 rotfont->per_char[ichar].glyph.bit_w,
352 rotfont->per_char[ichar].glyph.bit_h);
353
354 /* advance position ... */
355 if (dir == 1)
356 y -= rotfont->per_char[ichar].width;
357 else if (dir == 2)
358 x -= rotfont->per_char[ichar].width;
359 else
360 y += rotfont->per_char[ichar].width;
361 }
362 }
363}
364
365
366//Draw title string
367void DrawUtil::DrawString(Display *display, Window w, GC gc, DrawUtil::Font *font,
368 unsigned int text_w, unsigned int size_w,
369 unsigned int bevel_w, char *text) {
370
371 assert(display);
372 assert(font);
373
374 if (!text || text_w<1 || size_w < 1)
375 return;
376
377 unsigned int l = text_w;
378 int dlen=strlen(text);
379 int dx=bevel_w*2;
380
381
382 if (text_w > size_w) {
383 for (; dlen >= 0; dlen--) {
384 if (I18n::instance()->multibyte()) {
385 XRectangle ink, logical;
386 XmbTextExtents(font->set, text, dlen,
387 &ink, &logical);
388 l = logical.width;
389 } else
390 l = XTextWidth(font->fontstruct, text, dlen);
391
392 l += (dx * 4);
393
394 if (l < size_w)
395 break;
396 }
397 }
398
399 switch (font->justify) {
400 case DrawUtil::Font::RIGHT:
401 dx += size_w - l;
402 break;
403
404 case DrawUtil::Font::CENTER:
405 dx += (size_w - l) / 2;
406 break;
407 default:
408 break;
409 }
410
411 //Draw title to m_tabwin
412
413 XClearWindow(display, w);
414
415 if (I18n::instance()->multibyte()) {
416 XmbDrawString(display, w,
417 font->set, gc, dx, 1 - font->set_extents->max_ink_extent.y,
418 text, dlen);
419 } else {
420 XDrawString(display, w,
421 gc, dx, font->fontstruct->ascent + 1,
422 text, dlen);
423 }
424
425}
426
427
428void DrawUtil::DrawRotString(Display *display, Window w, GC gc, XRotFontStruct *font,
429 unsigned int align, unsigned int text_w,
430 unsigned int size_w, unsigned int size_h,
431 unsigned int bevel_w, char *text) {
432
433 assert(display);
434 assert(font);
435
436 if (!text || text_w<1 || size_w < 1)
437 return;
438
439 unsigned int l = text_w;
440 int dlen = strlen(text);
441 int dx = bevel_w * 2;
442
443 if (text_w > size_w) {
444 for (; dlen >= 0; dlen--) {
445 l = XRotTextWidth(font, text, dlen);
446
447 l += (dx * 4);
448
449 if (l < size_h)
450 break;
451 }
452 }
453
454 if (align == DrawUtil::Font::RIGHT)
455 size_h = l;
456 else if (align == DrawUtil::Font::CENTER)
457 size_h = (size_h + l) / 2;
458 else //LEFT
459 size_h -= (dx * 4);
460
461 // To get it in the "center" of the tab
462 size_w = (size_w + XRotTextWidth(font, "/", 1)) / 2;
463
464 //Draw title to m_tabwin
465 XClearWindow(display, w);
466 XRotDrawString(display, font, w, gc, size_w, size_h, text, dlen);
467}