1
2 /* ********************************************************************** */
3
4 /* xvertext, Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma)
5 *
6 * Permission to use, copy, modify, and distribute this software and its
7 * documentation for any purpose and without fee is hereby granted, provided
8 * that the above copyright notice appear in all copies and that both the
9 * copyright notice and this permission notice appear in supporting
10 * documentation. All work developed as a consequence of the use of
11 * this program should duly acknowledge such use. No representations are
12 * made about the suitability of this software for any purpose. It is
13 * provided "as is" without express or implied warranty.
14 */
15
16 /* ********************************************************************** */
17
18 // Minor modifications by Chris Cannam for wm2/wmx
19 // Major modifications by Kazushi (Jam) Marukawa for wm2/wmx i18n patch
20 // Minor modifications by Sven Oliver (SvOlli) Moll for wmx multihead support
21
22 #include <X11/Xlib.h>
23 #include <X11/Xutil.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include "Config.h"
28 #include "Rotated.h"
29
30 #ifndef CONFIG_USE_XFT
31
32 /* ---------------------------------------------------------------------- */
33
34
35 int xv_errno;
36
37 static char *my_strdup(const char *);
38 static char *my_strtok(char *, const char *);
39
40
41 /* ---------------------------------------------------------------------- */
42
43
44 /* *** Routine to mimic `strdup()' (some machines don't have it) *** */
45
my_strdup(const char * str)46 static char *my_strdup(const char *str)
47 {
48 char *s;
49
50 if (str == NULL) return NULL;
51
52 s = (char *)malloc((unsigned)(strlen(str)+1));
53 /* this error is highly unlikely ... */
54 if (s == NULL) {
55 fprintf(stderr, "Fatal error: my_strdup(): Couldn't do malloc (gulp!)\n");
56 exit(1);
57 }
58
59 strcpy(s, str);
60 return s;
61 }
62
63
64 /* ---------------------------------------------------------------------- */
65
66
67 /* *** Routine to replace `strtok' : this one returns a zero
68 length string if it encounters two consecutive delimiters *** */
69
my_strtok(char * str1,const char * str2)70 static char *my_strtok(char *str1, const char *str2)
71 {
72 char *ret;
73 int i, j, stop;
74 static int start, len;
75 static char *stext;
76
77 /* this error should never occur ... */
78 if (str2 == NULL) {
79 fprintf(stderr,
80 "Fatal error: my_strtok(): recieved null delimiter string\n");
81 exit(1);
82 }
83
84 /* initialise if str1 not NULL ... */
85 if (str1 != NULL) {
86 start = 0;
87 stext = str1;
88 len = strlen(str1);
89 }
90
91 /* run out of tokens ? ... */
92 if (start >= len) return NULL;
93
94 /* loop through characters ... */
95 for (i = start; i < len; i++) {
96
97 /* loop through delimiters ... */
98 stop = 0;
99 for (j = 0; j < strlen(str2); j++)
100 if (stext[i] == str2[j]) stop = 1;
101
102 if (stop) break;
103 }
104
105 stext[i] = '\0';
106 ret = stext + start;
107 start = i+1;
108
109 return ret;
110 }
111
112
113 /* ---------------------------------------------------------------------- */
114
115
116 /* *** Routine to return version/copyright information *** */
117
XRotVersion(char * str,int n)118 float XRotVersion(char *str, int n)
119 {
120 if (str != NULL) strncpy(str, XV_COPYRIGHT, n);
121 return XV_VERSION;
122 }
123
124
125 /* ---------------------------------------------------------------------- */
126
127
128 /* *** Load the rotated version of a given font *** */
129
XRotLoadFont(Display * dpy,int screen,char * fontname,float angle)130 XRotFontStruct *XRotLoadFont(Display *dpy, int screen,
131 char *fontname, float angle)
132 {
133 char val;
134 XImage *I1, *I2;
135 Pixmap canvas;
136 Window root;
137 GC font_gc;
138 char text[3];/*, errstr[300];*/
139 XFontStruct *fontstruct;
140 XRotFontStruct *rotfont;
141 int ichar, i, j, index, boxlen = 60, dir;
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;
146 int on = 1, off = 0;
147
148 /* make angle positive ... */
149 if (angle < 0) do angle += 360; while (angle < 0);
150
151 /* get nearest vertical or horizontal direction ... */
152 dir = (int)((angle+45.)/90.)%4;
153
154 /* useful macros ... */
155 root = RootWindow(dpy,screen);
156
157 /* create the depth 1 canvas bitmap ... */
158 canvas = XCreatePixmap(dpy, root, boxlen, boxlen, 1);
159
160 /* create a GC ... */
161 font_gc = XCreateGC(dpy, canvas, 0, 0);
162 XSetBackground(dpy, font_gc, off);
163
164 /* load the font ... */
165 char **ml;
166 int mc;
167 char *ds;
168
169 XFontSet fontset;
170 fontset = XCreateFontSet(dpy, fontname, &ml, &mc, &ds);
171 if (fontset) {
172 XFontStruct **fs_list;
173 XFontsOfFontSet(fontset, &fs_list, &ml);
174 fontstruct = fs_list[0];
175 } else {
176 fontstruct = NULL;
177 }
178 #define XTextWidth(x,y,z) XmbTextEscapement(rotfont->xfontset,y,z)
179 #define XDrawString(t,u,v,w,x,y,z) XmbDrawString(t,u,rotfont->xfontset,v,w,x,y,z)
180 #define XDrawImageString(t,u,v,w,x,y,z) XmbDrawString(t,u,rotfont->xfontset,v,w,x,y,z)
181 if (fontstruct == NULL) {
182 xv_errno = XV_NOFONT;
183 return NULL;
184 }
185
186 XSetFont(dpy, font_gc, fontstruct->fid);
187
188 /* allocate space for rotated font ... */
189 rotfont = (XRotFontStruct *)malloc((unsigned)sizeof(XRotFontStruct));
190 if (rotfont == NULL) {
191 xv_errno = XV_NOMEM;
192 return NULL;
193 }
194
195 /* determine which characters are defined in font ... */
196 min_char = fontstruct->min_char_or_byte2;
197 max_char = fontstruct->max_char_or_byte2;
198
199 /* we only want printing characters ... */
200 if (min_char<32) min_char = 32;
201 // if (max_char>126) max_char = 126; // bad for non-ascii iso
202 if (max_char>255) max_char = 255;
203
204 /* some overall font data ... */
205 rotfont->name = my_strdup(fontname);
206 rotfont->dir = dir;
207 rotfont->min_char = min_char;
208 rotfont->max_char = max_char;
209 rotfont->max_ascent = fontstruct->max_bounds.ascent;
210 rotfont->max_descent = fontstruct->max_bounds.descent;
211 rotfont->height = rotfont->max_ascent+rotfont->max_descent;
212
213 /* remember xfontstruct for `normal' text ... */
214 rotfont->xfontset = fontset;
215 rotfont->xfontstruct = fontstruct;
216
217 /* free pixmap and GC ... */
218 XFreePixmap(dpy, canvas);
219 XFreeGC(dpy, font_gc);
220
221 return rotfont;
222 }
223
224
225 /* ---------------------------------------------------------------------- */
226
227
228 /* *** Free the resources associated with a rotated font *** */
229
XRotUnloadFont(Display * dpy,int screen,XRotFontStruct * rotfont)230 void XRotUnloadFont(Display *dpy, int screen, XRotFontStruct *rotfont)
231 {
232 int ichar;
233
234 XFreeFontSet(dpy, rotfont->xfontset);
235
236 /* rotfont should never be referenced again ... */
237 free((char *)rotfont->name);
238 free((char *)rotfont);
239 }
240
241
242 /* ---------------------------------------------------------------------- */
243
244
245 /* *** Return the width of a string *** */
246
XRotTextWidth(XRotFontStruct * rotfont,char * str,int len)247 int XRotTextWidth(XRotFontStruct *rotfont, char *str, int len)
248 {
249 int i, width = 0, ichar;
250
251 if (str == NULL) return 0;
252
253 width = XTextWidth(rotfont->xfontstruct, str, strlen(str));
254
255 return width;
256 }
257
258
259 /* ---------------------------------------------------------------------- */
260
261
262 /* *** A front end to XRotPaintString : mimics XDrawString *** */
263
XRotDrawString(Display * dpy,int screen,XRotFontStruct * rotfont,Drawable drawable,GC gc,int x,int y,char * str,int len)264 void XRotDrawString(Display *dpy, int screen, XRotFontStruct *rotfont,
265 Drawable drawable,
266 GC gc, int x, int y, char *str, int len)
267 {
268 static GC my_gc = 0;
269 static int lastscreen = -1;
270
271 int i, xp, yp, dir, ichar;
272
273 if (str == NULL || len<1) return;
274
275 dir = rotfont->dir;
276
277 if((lastscreen != screen) && (my_gc != 0))
278 {
279 XFreeGC(dpy,my_gc);
280 my_gc = 0;
281 }
282
283 if(my_gc == 0) my_gc = XCreateGC(dpy, drawable, 0, 0);
284
285 XCopyGC(dpy, gc, GCForeground|GCBackground, my_gc);
286
287 /* a horizontal string is easy ... */
288 if (dir == 0) {
289 XSetFillStyle(dpy, my_gc, FillSolid);
290 XSetFont(dpy, my_gc, rotfont->xfontstruct->fid);
291 XDrawString(dpy, drawable, my_gc, x, y, str, len);
292
293 return;
294 }
295
296 /* vertical or upside down ... */
297
298 XImage *I1, *I2;
299 unsigned char *vertdata, *bitdata;
300 int vert_w, vert_h, vert_len, bit_w, bit_h, bit_len;
301 char val;
302
303 /* useful macros ... */
304 Window root = RootWindow(dpy,screen);
305
306 int ascent = rotfont->max_ascent;
307 int descent = rotfont->max_descent;
308 int width = XRotTextWidth(rotfont, str, len);
309 int height = rotfont->height;
310 if (width < 1) width = 1;
311 if (height < 1) height = 1;
312
313 /* glyph width and height when vertical ... */
314 vert_w = width;
315 vert_h = height;
316
317 /* width in bytes ... */
318 vert_len = (vert_w-1)/8+1;
319
320 /* create the depth 1 canvas bitmap ... */
321 Pixmap canvas = XCreatePixmap(dpy, root, width, height, 1);
322
323 /* create a GC ... */
324 GC font_gc = XCreateGC(dpy, canvas, 0, 0);
325 XSetBackground(dpy, font_gc, 0);
326
327 /* clear canvas */
328 XSetForeground(dpy, font_gc, 0);
329 XFillRectangle(dpy, canvas, font_gc, 0, 0, width, height);
330
331 /* draw the character centre top right on canvas ... */
332 XSetForeground(dpy, font_gc, 1);
333 XSetFont(dpy, font_gc, rotfont->xfontstruct->fid);
334 XDrawImageString(dpy, canvas, font_gc, 0, height-descent, str, len);
335
336 /* reserve memory for first XImage ... */
337 vertdata = (unsigned char *) malloc((unsigned)(vert_len*vert_h));
338 if (vertdata == NULL) {
339 xv_errno = XV_NOMEM;
340 return;
341 }
342
343 /* create the XImage ... */
344 I1 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap,
345 0, (char *)vertdata, vert_w, vert_h, 8, 0);
346
347 if (I1 == NULL) {
348 xv_errno = XV_NOXIMAGE;
349 return;
350 }
351
352 I1->byte_order = I1->bitmap_bit_order = MSBFirst;
353
354 /* extract character from canvas ... */
355 XGetSubImage(dpy, canvas, 0, 0,
356 vert_w, vert_h, 1, XYPixmap, I1, 0, 0);
357 I1->format = XYBitmap;
358
359 /* width, height of rotated character ... */
360 if (dir == 2) {
361 bit_w = vert_w;
362 bit_h = vert_h;
363 } else {
364 bit_w = vert_h;
365 bit_h = vert_w;
366 }
367
368 /* width in bytes ... */
369 bit_len = (bit_w-1)/8 + 1;
370
371 /* reserve memory for the rotated image ... */
372 bitdata = (unsigned char *)calloc((unsigned)(bit_h*bit_len), 1);
373 if (bitdata == NULL) {
374 xv_errno = XV_NOMEM;
375 return;
376 }
377
378 /* create the image ... */
379 I2 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0,
380 (char *)bitdata, bit_w, bit_h, 8, 0);
381
382 if (I2 == NULL) {
383 xv_errno = XV_NOXIMAGE;
384 return;
385 }
386
387 I2->byte_order = I2->bitmap_bit_order = MSBFirst;
388
389 /* map vertical data to rotated character ... */
390 int j;
391 for (j = 0; j < bit_h; j++) {
392 for (i = 0; i < bit_w; i++) {
393 /* map bits ... */
394 if (dir == 1)
395 val = vertdata[i*vert_len + (vert_w-j-1)/8] &
396 (128>>((vert_w-j-1)%8));
397
398 else if (dir == 2)
399 val = vertdata[(vert_h-j-1)*vert_len + (vert_w-i-1)/8] &
400 (128>>((vert_w-i-1)%8));
401
402 else
403 val = vertdata[(vert_h-i-1)*vert_len + j/8] &
404 (128>>(j%8));
405
406 if (val)
407 bitdata[j*bit_len + i/8] = bitdata[j*bit_len + i/8] |
408 (128>>(i%8));
409 }
410 }
411
412 /* create this character's bitmap ... */
413 Pixmap image = XCreatePixmap(dpy, root, bit_w, bit_h, 1);
414
415 /* put the image into the bitmap ... */
416 XPutImage(dpy, image, font_gc, I2, 0, 0, 0, 0, bit_w, bit_h);
417
418 /* free the image and data ... */
419 XDestroyImage(I1);
420 XDestroyImage(I2);
421 /* free((char *)bitdata); -- XDestroyImage does this
422 free((char *)vertdata);*/
423
424 /* free pixmap and GC ... */
425 XFreePixmap(dpy, canvas);
426 XFreeGC(dpy, font_gc);
427
428 /* suitable offset ... */
429 if (dir == 1) {
430 xp = x-rotfont->max_ascent;
431 yp = y-width; //rotfont->rbearing;
432 }
433 else if (dir == 2) {
434 xp = x-width; //rotfont->rbearing;
435 yp = y-rotfont->max_descent+1;
436 }
437 else {
438 xp = x-rotfont->max_descent+1;
439 yp = y+0; //rotfont->lbearing;
440 }
441
442 XSetFillStyle(dpy, my_gc, FillStippled);
443 XSetStipple(dpy, my_gc, image);
444 XSetTSOrigin(dpy, my_gc, xp, yp);
445 XFillRectangle(dpy, drawable, my_gc, xp, yp,
446 bit_w, bit_h);
447
448 XFreePixmap(dpy, image);
449 }
450
451
452
453 /* ---------------------------------------------------------------------- */
454
455
456 /* *** A front end to XRotPaintAlignedString : uses XRotDrawString *** */
457
XRotDrawAlignedString(Display * dpy,int screen,XRotFontStruct * rotfont,Drawable drawable,GC gc,int x,int y,char * text,int align)458 void XRotDrawAlignedString(Display *dpy, int screen, XRotFontStruct *rotfont,
459 Drawable drawable, GC gc, int x, int y,
460 char *text, int align)
461 {
462 int xp = 0, yp = 0, dir;
463 int i, nl = 1, max_width = 0, this_width;
464 char *str1, *str2 = "\n\0", *str3;
465
466 if (text == NULL)
467 return;
468
469 dir = rotfont->dir;
470
471 /* count number of sections in string ... */
472 for (i = 0; i<strlen(text); i++)
473 if (text[i] == '\n')
474 nl++;
475
476 /* find width of longest section ... */
477 str1 = my_strdup(text);
478 str3 = my_strtok(str1, str2);
479 max_width = XRotTextWidth(rotfont, str3, strlen(str3));
480
481 do {
482 str3 = my_strtok((char *)NULL, str2);
483 if (str3 != NULL)
484 if (XRotTextWidth(rotfont, str3, strlen(str3))>max_width)
485 max_width = XRotTextWidth(rotfont, str3, strlen(str3));
486 }
487 while (str3 != NULL);
488
489 /* calculate vertical starting point according to alignment policy and
490 rotation angle ... */
491 if (dir == 0) {
492 if (align == TLEFT || align == TCENTRE || align == TRIGHT)
493 yp = y+rotfont->max_ascent;
494
495 else if (align == BLEFT || align == BCENTRE || align == BRIGHT)
496 yp = y-(nl-1)*rotfont->height - rotfont->max_descent;
497
498 else
499 yp = y-(nl-1)/2*rotfont->height + rotfont->max_ascent -
500 rotfont->height/2 - ((nl%2 == 0)?rotfont->height/2:0);
501 }
502
503 else if (dir == 1) {
504 if (align == TLEFT || align == TCENTRE || align == TRIGHT)
505 xp = x+rotfont->max_ascent;
506
507 else if (align == BLEFT || align == BCENTRE || align == BRIGHT)
508 xp = x-(nl-1)*rotfont->height - rotfont->max_descent;
509
510 else
511 xp = x-(nl-1)/2*rotfont->height + rotfont->max_ascent -
512 rotfont->height/2 - ((nl%2 == 0)?rotfont->height/2:0);
513 }
514
515 else if (dir == 2) {
516 if (align == TLEFT || align == TCENTRE || align == TRIGHT)
517 yp = y-rotfont->max_ascent;
518
519 else if (align == BLEFT || align == BCENTRE || align == BRIGHT)
520 yp = y+(nl-1)*rotfont->height + rotfont->max_descent;
521
522 else
523 yp = y+(nl-1)/2*rotfont->height - rotfont->max_ascent +
524 rotfont->height/2 + ((nl%2 == 0)?rotfont->height/2:0);
525 }
526
527 else {
528 if (align == TLEFT || align == TCENTRE || align == TRIGHT)
529 xp = x-rotfont->max_ascent;
530
531 else if (align == BLEFT || align == BCENTRE || align == BRIGHT)
532 xp = x+(nl-1)*rotfont->height + rotfont->max_descent;
533
534 else
535 xp = x+(nl-1)/2*rotfont->height - rotfont->max_ascent +
536 rotfont->height/2 + ((nl%2 == 0)?rotfont->height/2:0);
537 }
538
539 free(str1);
540 str1 = my_strdup(text);
541 str3 = my_strtok(str1, str2);
542
543 /* loop through each section in the string ... */
544 do {
545 /* width of this section ... */
546 this_width = XRotTextWidth(rotfont, str3, strlen(str3));
547
548 /* horizontal alignment ... */
549 if (dir == 0) {
550 if (align == TLEFT || align == MLEFT || align == BLEFT)
551 xp = x;
552
553 else if (align == TCENTRE || align == MCENTRE || align == BCENTRE)
554 xp = x-this_width/2;
555
556 else
557 xp = x-max_width;
558 }
559
560 else if (dir == 1) {
561 if (align == TLEFT || align == MLEFT || align == BLEFT)
562 yp = y;
563
564 else if (align == TCENTRE || align == MCENTRE || align == BCENTRE)
565 yp = y+this_width/2;
566
567 else
568 yp = y+max_width;
569 }
570
571 else if (dir == 2) {
572 if (align == TLEFT || align == MLEFT || align == BLEFT)
573 xp = x;
574
575 else if (align == TCENTRE || align == MCENTRE || align == BCENTRE)
576 xp = x+this_width/2;
577
578 else
579 xp = x+max_width;
580 }
581
582 else {
583 if (align == TLEFT || align == MLEFT || align == BLEFT)
584 yp = y;
585
586 else if (align == TCENTRE || align == MCENTRE || align == BCENTRE)
587 yp = y-this_width/2;
588
589 else
590 yp = y-max_width;
591 }
592
593 /* draw the section ... */
594 XRotDrawString(dpy, screen, rotfont, drawable, gc, xp, yp,
595 str3, strlen(str3));
596
597 str3 = my_strtok((char *)NULL, str2);
598
599 /* advance position ... */
600 if (dir == 0)
601 yp += rotfont->height;
602 else if (dir == 1)
603 xp += rotfont->height;
604 else if (dir == 2)
605 yp -= rotfont->height;
606 else
607 xp -= rotfont->height;
608 }
609 while (str3 != NULL);
610
611 free(str1);
612 }
613
614 #endif
615