X11 Work Bench Toolkit  1.0
font_helper.c
Go to the documentation of this file.
1 
2 // __ _ _ _ //
3 // / _| ___ _ __ | |_ | |__ ___ | | _ __ ___ _ __ ___ //
4 // | |_ / _ \ | '_ \ | __| | '_ \ / _ \| || '_ \ / _ \| '__|/ __| //
5 // | _|| (_) || | | || |_ | | | || __/| || |_) || __/| | _| (__ //
6 // |_| \___/ |_| |_| \__|_____|_| |_| \___||_|| .__/ \___||_|(_)\___| //
7 // |_____| |_| //
8 // basic font enumeration and selection //
9 // //
11 
12 /*****************************************************************************
13 
14  X11workbench - X11 programmer's 'work bench' application and toolkit
15  Copyright (c) 2010-2016 by Bob Frazier (aka 'Big Bad Bombastic Bob')
16  all rights reserved
17 
18  DISCLAIMER: The X11workbench application and toolkit software are supplied
19  'as-is', with no warranties, either implied or explicit.
20  Any claims to alleged functionality or features should be
21  considered 'preliminary', and might not function as advertised.
22 
23  BSD-like license:
24 
25  There is no restriction as to what you can do with this software, so long
26  as you include the above copyright notice and DISCLAIMER for any distributed
27  work that is equal to or derived from this one, along with this paragraph
28  that explains the terms of the license if the source is also being made
29  available. A "derived work" describes a work that uses a significant portion
30  of the source files or algorithms that are included with this one.
31  Specifically excluded from this are files that were generated by the software,
32  or anything that is included with the software that is part of another package
33  (such as files that were created or added during the 'configure' process).
34  Specifically included is the use of part or all of any of the X11 workbench
35  toolkit source or header files in your distributed application. If you do not
36  ship the source, the above copyright statement is still required to be placed
37  in a reasonably prominent place, such as documentation, splash screens, and/or
38  'about the application' dialog boxes.
39 
40  Use and distribution are in accordance with GPL, LGPL, and/or the above
41  BSD-like license. See COPYING and README files for more information.
42 
43 
44  Additional information at http://sourceforge.net/projects/X11workbench
45 
46 ******************************************************************************/
47 
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59 #include <memory.h>
60 #include <string.h>
61 #include <strings.h>
62 #include <signal.h>
63 #include <time.h>
64 #include <X11/cursorfont.h>
65 
66 #include <locale.h>
67 
68 #include "window_helper.h" // for debug output; also includes platform.h and font_helper.h
69 #include "draw_text.h"
70 
71 #define FONT_DUMP_DEBUG_LEVEL DebugLevel_Heavy
72 
73 //#define USE_FONT_LIST_FOR_FONT_SET /* define this to make a list of matching names for a font list */
74 
75 
76 typedef struct WBFontInfo
77 {
78  char *szFoundry, *szFamily;
79  int iWeight, iSlant, iWidth;
80  char *szAdStyle;
81  int iPixelSize, iPointSize, iResX, iResY, iSpacing, iAvgWidth;
82  char *szRegistry, *szEncoding;
83  char data[8];
84 } WB_FONT_INFO;
85 
86 #ifndef NO_DEBUG
87 static void WBDumpFontStruct(const XFontStruct *pFont);
88 static void WBDumpMatchingFontNames(Display *pDisplay, const char *szFontName);
89 static void WBDumpFontSet(Display *pDisplay, XFontSet fontSet);
90 #endif // NO_DEBUG
91 
92 
93 static char *InternalCheckSetLocale(void);
94 
95 
96 
97 XFontStruct *WBCopyFont(XFontStruct *pOldFont)
98 {
99 unsigned long lName;
100 XFontStruct *pRval;
101 
102  if(!pOldFont)
103  return NULL;
104 
105  if(XGetFontProperty(pOldFont, XA_FONT, &lName))
106  {
107  char *pName = WBGetAtomName(WBGetDefaultDisplay(), (Atom)lName);
108 
109  if(pName)
110  {
112  "%s(%s)\n", __FUNCTION__, pName);
113 
114  pRval = XLoadQueryFont(WBGetDefaultDisplay(), pName);
115 
116  WBFree(pName);
117 
118  return pRval;
119  }
120  else
121  {
122  WB_WARN_PRINT("%s - WARNING: %d not an atom\n", __FUNCTION__, (int)lName);
123  }
124  }
125 #ifndef NO_DEBUG /* assign this to disable debugging - most likely a -D in Makefile */
126  else if((WBGetDebugLevel() & DebugLevel_MASK) >= FONT_DUMP_DEBUG_LEVEL ||
128  {
129  WBDumpFontStruct(pOldFont);
130  }
131 #endif // NO_DEBUG
132 
133  // this is a fallback so debug output is 'light' category, like warnings
134 
136  "%s - call to XQueryFont for %d (%08xH)\n", __FUNCTION__, (int)pOldFont->fid, (int)pOldFont->fid);
137 
138  // NOTE: XQueryFont needs to have XFreeFontList free it. If I call XFreeFont
139  // it will unload the font and cause a bunch of errors if "other things"
140  // are using it. NORMALLY I do not get to this point, so I'll return NULL
141  // if I _DO_ in order to flag the error rather than create a time bomb.
142 
143  return NULL; // XQueryFont(WBGetDefaultDisplay(), pOldFont->fid);
144 }
145 
146 void WBFontNameFromAlias(const char *szFontName, char *szDest, int cbDest)
147 {
148 XFontStruct *pFSInfo=NULL;
149 char **ppNames=NULL;
150 int iCount=0;
151 
152 
153  ppNames = XListFontsWithInfo(WBGetDefaultDisplay(), szFontName, 2, &iCount, &pFSInfo);
154  // TODO: if iCount > 0 is this a bad thing? can I simply pick the 1st one anyway?
155 
156  bzero(szDest, cbDest);
157 
158  if(ppNames && iCount > 0) //== 1)
159  {
160  if(iCount > 1)
161  {
162  WB_WARN_PRINT("%s - WARNING: WBFontNameFromAlias returns iCount > 1\n", __FUNCTION__);
163  }
164 
165  strncpy(szDest, ppNames[0], cbDest);
166  }
167 
168  XFreeFontInfo(ppNames, pFSInfo, iCount);
169 }
170 
171 WB_FONT_INFO *WBParseFontName(const char *szFontName)
172 {
173 WB_FONT_INFO *pRval = NULL;
174 char tbuf[256], tbuf2[64];
175 char *p1, /* *p2,*/ *p3;
176 
177  if(!szFontName || !*szFontName)
178  return NULL;
179 
180  if(szFontName[0] != '-')
181  {
182  // get the alias
183  WBFontNameFromAlias(szFontName, tbuf, sizeof(tbuf));
184  if(!*tbuf)
185  {
186  strcpy(tbuf, "-*-");
187  strcat(tbuf, szFontName);
188  }
189  szFontName = tbuf;
190  }
191 
192  if(szFontName[0] != '-')
193  {
194  WB_WARN_PRINT("%s - * BUG * font name doesn't start with a '-' \"%s\"\n", __FUNCTION__, szFontName);
195  return NULL; // should never happen
196  }
197 
198  pRval = WBAlloc(sizeof(WB_FONT_INFO) + strlen(szFontName));
199  // -foundry-family-weight-slant-sWidth-adstyle-pixelsize-pointsize-resX-resY-spacing-avgwidth-registry-encoding
200 
201  if(!pRval)
202  return NULL;
203 
204  bzero(pRval, sizeof(WB_FONT_INFO) + strlen(szFontName));
205 
206  p1 = (char *)(pRval->data);
207  strcpy(p1, szFontName + 1); // copy everything past the leading '-'
208 
209 #define DO_FONT_PARSE_THING(X) pRval->X=p1; while(*p1 && *p1 != '-') p1++; if(*p1 == '-') *(p1++) = 0
210 #define DO_FONT_PARSE_THING1() bzero(tbuf2,sizeof(tbuf2)); p3=tbuf2; \
211  while(*p1 && *p1 != '-' && p3 < (tbuf2 + sizeof(tbuf2) - 2)) *(p3++)=*(p1++); \
212  while(*p1 && *p1 != '-') p1++; if(*p1 == '-') *(p1++) = 0
213 #define DO_FONT_PARSE_THING2(X) DO_FONT_PARSE_THING1(); \
214  if(!tbuf2[0] || tbuf2[0]=='*') pRval->X = -1; else pRval->X = atoi(tbuf2)
215 
216  DO_FONT_PARSE_THING(szFoundry);
217  DO_FONT_PARSE_THING(szFamily);
218  DO_FONT_PARSE_THING1();
219  if(!strcasecmp(tbuf2,"regular"))
220  pRval->iWeight = 1;
221  else if(!strcasecmp(tbuf2,"medium"))
222  pRval->iWeight = 2;
223  else if(!strcasecmp(tbuf2,"demibold"))
224  pRval->iWeight = 3;
225  else if(!strcasecmp(tbuf2,"bold"))
226  pRval->iWeight = 4;
227  else if(tbuf2[0] == '*')
228  pRval->iWeight = -1;
229  else
230  pRval->iWeight = 0;
231 
232  DO_FONT_PARSE_THING1();
233  if(tbuf2[0] == 'r')
234  pRval->iSlant = 1;
235  else if(tbuf2[0] == 'o')
236  pRval->iSlant = 2;
237  else if(tbuf2[0] == 'i')
238  pRval->iSlant = 3;
239  else if(tbuf2[0] == '*')
240  pRval->iSlant = -1;
241  else
242  pRval->iSlant = 0;
243 
244  DO_FONT_PARSE_THING1();
245  if(!strcasecmp(tbuf2,"normal"))
246  pRval->iWidth = 1;
247  else if(!strcasecmp(tbuf2,"semicondensed"))
248  pRval->iWidth = 2;
249  else if(!strcasecmp(tbuf2,"condensed"))
250  pRval->iWidth = 3; // not sure but it's here anyway
251  else if(tbuf2[0] == '*')
252  pRval->iWidth = -1;
253  else
254  pRval->iWidth = 0;
255 
256  DO_FONT_PARSE_THING(szAdStyle);
257  DO_FONT_PARSE_THING2(iPixelSize);
258  DO_FONT_PARSE_THING2(iPointSize);
259  DO_FONT_PARSE_THING2(iResX);
260  DO_FONT_PARSE_THING2(iResY);
261  DO_FONT_PARSE_THING1();
262  if(tbuf2[0] == 'c')
263  pRval->iSpacing = 1;
264  else if(tbuf2[0] == 'm')
265  pRval->iSpacing = 2;
266  else if(tbuf2[0] == 'p')
267  pRval->iSpacing = 7; // proportional (so it's WAY different than the others numerically)
268  else if(tbuf2[0] == '*')
269  pRval->iSpacing = -1;
270  else
271  pRval->iSpacing = 0;
272 
273  DO_FONT_PARSE_THING2(iAvgWidth);
274  DO_FONT_PARSE_THING(szRegistry);
275  DO_FONT_PARSE_THING(szEncoding);
276 
277 // TEMPORARY - when I parse a font make sure it comes out the way I want it to
278 // fprintf(stderr, "TEMPORARY: parsing font %s\n", szFontName);
279 // fprintf(stderr, " szFoundry=%s szFamily=%s iWeight=%d iSlant=%d iWidth=%d szAdStyle=%s\n"
280 // " iPixelSize=%d iPointSize=%d iResX=%d iResY=%d iSpacing=%d iAvgWidth=%d\n"
281 // " szRegistry=%s szEncoding=%s\n",
282 // pRval->szFoundry, pRval->szFamily, pRval->iWeight, pRval->iSlant,
283 // pRval->iWidth, pRval->szAdStyle, pRval->iPixelSize, pRval->iPointSize,
284 // pRval->iResX, pRval->iResY, pRval->iSpacing, pRval->iAvgWidth,
285 // pRval->szRegistry, pRval->szEncoding);
286 
287 #undef DO_FONT_PARSE_THING2
288 #undef DO_FONT_PARSE_THING1
289 #undef DO_FONT_PARSE_THING
290 
291  return pRval;
292 }
293 
294 #define FUZZY_FONT_EXACT_MATCH (3 + 10 + 5 + 5 + 2 + 4 + 3 + 3 + 1 + 5 + 4 + 4)
295 
296 static int InternalFontMatch(const WB_FONT_INFO *p1, const WB_FONT_INFO *p2)
297 {
298  int iRval = 0;
299 
300  if(!strcasecmp(p1->szFoundry, p2->szFoundry) ||
301  p1->szFoundry[0] == '*' || p2->szFoundry[0] == '*' ||
302  !p1->szFoundry[0] || !p2->szFoundry[0])
303  {
304  iRval += 3; // score 3 if the foundry matches
305  }
306 
307  if(!strcasecmp(p1->szFamily, p2->szFamily) ||
308  p1->szFamily[0] == '*' || p2->szFamily[0] == '*')
309  {
310  iRval += 10; // score 10 for font name match
311  }
312 
313  if(p1->iWeight == -1 || p2->iWeight == -1 || p1->iWeight == p2->iWeight)
314  iRval += 5; // score 5 for matching weight
315  else
316  iRval += 3 - abs(p1->iWeight - p2->iWeight); // sort of fuzzy matching
317 
318  if(p1->iSlant == -1 || p2->iSlant == -1 || p1->iSlant == p2->iSlant)
319  iRval += 5; // score 5 for matching Slant
320  else
321  iRval += 3 - abs(p1->iSlant - p2->iSlant); // sort of fuzzy matching
322 
323  if(p1->iWidth == -1 || p2->iWidth == -1 || p1->iWidth == p2->iWidth)
324  iRval += 2; // score 2 for matching Width
325 
326  // for 'szAdStyle' match, it's 'sans' 'ja' 'ko' or blank
327  // since blank may match any of them (or none) it's a 2 point delta for 'sans', 1 otherwise
328 
329  if(!strcasecmp(p1->szAdStyle,p2->szAdStyle) ||
330  p1->szAdStyle[0] == '*' || p2->szAdStyle[0] == '*')
331  {
332  iRval += 4; // score 4 for matching style (sans, ko, ja, blank)
333  }
334  else if((!p1->szAdStyle[0] || !p1->szAdStyle[1]) &&
335  (!strcasecmp(p1->szAdStyle,"sans") || !strcasecmp(p2->szAdStyle,"sans")))
336  {
337  iRval += 2; // score 2 for 'sort of matching' (blank vs sans)
338  }
339  else if(!p1->szAdStyle[0] || !p1->szAdStyle[1])
340  {
341  iRval ++; // score 1 for 'sort of matching' (blank vs something other than sans)
342  }
343  else
344  {
345  iRval -= 2; // subtract 2 if there's any other combination
346  }
347 
348  if(p1->iPixelSize == -1 || p2->iPixelSize == -1 || p1->iPixelSize == p2->iPixelSize)
349  iRval += 3; // score 3 for matching PixelSize
350  else
351  iRval += 2 - abs(p1->iPixelSize - p2->iPixelSize); // sort of fuzzy matching
352 
353  if(p1->iPointSize == -1 || p2->iPointSize == -1 || p1->iPointSize == p2->iPointSize)
354  iRval += 3; // score 3 for matching PointSize
355  else
356  iRval += 2 - abs(p1->iPointSize - p2->iPointSize) / 10; // sort of fuzzy matching
357 
358  if((p1->iResX == p2->iResX && p1->iResY == p2->iResY) ||
359  (p1->iResX == -1 && p1->iResY == -1) ||
360  (p2->iResX == -1 && p2->iResY == -1))
361  {
362  iRval++; // 1 point for resolution (exact match only)
363  }
364 
365  if(p1->iSpacing == -1 || p2->iSpacing == -1 || p1->iSpacing == p2->iSpacing)
366  iRval += 5; // 5 points if spacing matches
367  else if(p1->iSpacing == 0 || p2->iSpacing == 0)
368  iRval += 3; // 3 points if either is unspecified but not wildcard
369  else
370  iRval += 3 - abs(p1->iSpacing - p2->iSpacing) / 5; // 1/5 of the delta (somewhat relative to point sizes)
371 
372  if(!strcasecmp(p1->szRegistry,p2->szRegistry) ||
373  !p1->szRegistry[0] || !p2->szRegistry[0] ||
374  p1->szRegistry[0] == '*' || p2->szRegistry[0] == '*')
375  {
376  iRval += 4; // score 4 for matching registry (iso8859 etc.)
377  }
378 
379  if(!strcasecmp(p1->szEncoding,p2->szEncoding) ||
380  !p1->szEncoding[0] || !p2->szEncoding[0] ||
381  p1->szEncoding[0] == '*' || p2->szEncoding[0] == '*')
382  {
383  iRval += 4; // score 4 for matching character encoding
384  }
385 
386  return iRval;
387 }
388 
389 static int InternalFontMatch2(const char *p1, const char *p2)
390 {
391  int iRval = -1;
392  WB_FONT_INFO *pfi1 = p1 ? WBParseFontName(p1) : NULL;
393  WB_FONT_INFO *pfi2 = p2 ? WBParseFontName(p2) : NULL;
394 
395  if(pfi1 && pfi2)
396  {
397  iRval = InternalFontMatch(pfi1, pfi2);
398  }
399 
400  if(pfi1)
401  {
402  WBFree(pfi1);
403  }
404 
405  if(pfi2)
406  {
407  WBFree(pfi2);
408  }
409 
410  return iRval;
411 }
412 
413 // NOTE: use WB_IF_DEBUG_LEVEL( n ) macro to control output if you don't always want it
414 
415 void WBDumpFontInfo(const char *szFontName)
416 {
417 XFontStruct *pFSInfo=NULL;
418 char **ppNames=NULL;
419 int i1, i2, iCount = 0;
420 char temp[1024];
421 
422  if(!szFontName || !*szFontName)
423  {
424  strcpy(temp, "*");
425  }
426  else if(szFontName[0] != '-')
427  {
428  strcpy(temp, "*-");
429  strcat(temp, szFontName);
430  strcat(temp, "-*");
431  }
432  else
433  {
434  strcpy(temp, "*");
435  strcat(temp, szFontName);
436  strcat(temp, "*");
437  }
438 
439  if(szFontName && *szFontName)
440  {
441 // use the first one when you anticipate a LOT of entries or you know that 'szFontName'
442 // isn't an alias. Use the 2nd one for a font alias.
443 // ppNames = XListFonts(WBGetDefaultDisplay(), szFontName, 0x7fffffff, &iCount);
444 
445  ppNames = XListFontsWithInfo(WBGetDefaultDisplay(), szFontName, 16384, &iCount, &pFSInfo);
446  }
447 
448  if(!ppNames)
449  {
450 // fprintf(stderr, "TEMPORARY listing fonts for %s\n", temp);
451  ppNames = XListFonts(WBGetDefaultDisplay(), temp, 0x7fffffff, &iCount);
452  }
453 
454  if(!ppNames)
455  {
456  WBDebugPrint("%s - no matching fonts\n", __FUNCTION__);
457  return;
458  }
459 
460  // use WBDebugPrint to make sure I dump all of the font into
461 
462  WBDebugPrint("%s", "\n** FONT LIST **\n");
463 
464  for(i1=0; i1 < iCount; i1++)
465  {
466 // TEMPORARY - for debugginG purposes (remove ASAP)
467 // void *pTemp = WBParseFontName(ppNames[i1]);
468 // if(pTemp)
469 // WBFree(pTemp);
470 
471  WBDebugPrint(" %s\n", ppNames[i1]);
472 
473  if(pFSInfo)
474  {
475  WBDebugPrint(" Font %d (%08xH)\n"
476  " direction %d\n"
477  " ascent %d\n"
478  " descent %d\n",
479  (int)pFSInfo[i1].fid, (int)pFSInfo[i1].fid, pFSInfo[i1].direction,
480  pFSInfo[i1].ascent, pFSInfo[i1].descent);
481 
482  for(i2=0; i2 < pFSInfo[i1].n_properties && pFSInfo[i1].properties; i2++)
483  {
484  XFontProp *pProp = pFSInfo[i1].properties + i2;
485  char *pName = WBGetAtomName(WBGetDefaultDisplay(),pProp->name);
486 
487  if(pName)
488  {
489  strncpy(temp, pName, sizeof(temp));
490  WBFree(pName);
491  }
492  else
493  {
494  sprintf(temp, "Atom %d (%08xH)", (int)pProp->name, (int)pProp->name);
495  }
496 
497  WBDebugPrint(" %-16s %ld (%08lxH)\n",
498  temp, pProp->card32, pProp->card32);
499  }
500  }
501  }
502 
503  WBDebugPrint("%s", "\n***************\n");
504 
505  if(pFSInfo)
506  {
507  XFreeFontInfo(ppNames, pFSInfo, iCount);
508  }
509  else
510  {
511  XFreeFontNames(ppNames);
512  }
513 }
514 
515 static __inline__ int __string_valid_check(const char *pString) { return pString && *pString; }
516 
517 static void InternalBuildFontString(const char *szFontName, int iSize, int iFlags,
518  char *pBuf, int cbBuf, int bForceWildcard)
519 {
520  char *p1, /* *p2,*/ *pEnd;
521  char tbuf[64];
522  int iAvgWidth;
523  WB_FONT_INFO *pFI = WBParseFontName(szFontName);
524 
525  if(!pFI)
526  {
527  strncpy(pBuf, szFontName, cbBuf);
528  return;
529  }
530 
531  p1 = pBuf;
532  pEnd = pBuf + cbBuf;
533 
534  // build the string using 'pFI' and iFlags
535 
536 #define DO_FONT_BUILD_THING(X) if((p1 + 2) >= pEnd) return; *(p1++) = '-'; \
537  if(__string_valid_check(X)) { strncpy(p1, X, (pEnd - p1)); p1 += strlen(p1); } else *(p1++) = '*'; \
538  *p1 = 0; if((p1 + 1) >= pEnd) return
539 
540  DO_FONT_BUILD_THING(pFI->szFoundry);
541  DO_FONT_BUILD_THING(pFI->szFamily);
542 
543  *tbuf = 0;
544  switch(pFI->iWeight)
545  {
546  case 1:
547  strcpy(tbuf, "regular");
548  break;
549  case 2:
550  strcpy(tbuf, "medium");
551  break;
552  case 3:
553  strcpy(tbuf, "demibold");
554  break;
555  case 4:
556  strcpy(tbuf, "bold");
557  break;
558  case -1:
559  strcpy(tbuf, "*");
560  break;
561  default:
562  *tbuf = 0;
563  }
564 
565  switch(iFlags & WBFontFlag_WT_MASK) // iFlags overrides
566  {
568  strcpy(tbuf, "regular");
569  break;
571  strcpy(tbuf, "medium");
572  break;
574  strcpy(tbuf, "demibold");
575  break;
576  case WBFontFlag_WT_BOLD:
577  strcpy(tbuf, "bold");
578  break;
579  case WBFontFlag_WT_ANY:
580  if(bForceWildcard || !*tbuf)
581  strcpy(tbuf, "*");
582  break;
583  }
584 
585  DO_FONT_BUILD_THING(tbuf); // commit what I just did
586 
587  *tbuf = 0;
588  switch(pFI->iSlant)
589  {
590  case 1:
591  strcpy(tbuf, "r");
592  break;
593  case 2:
594  strcpy(tbuf, "o");
595  break;
596  case 3:
597  strcpy(tbuf, "i");
598  break;
599  case -1:
600  strcpy(tbuf, "*");
601  break;
602  default:
603  *tbuf = 0;
604  }
605 
606  switch(iFlags & WBFontFlag_SLANT_MASK) // iFlags overrides
607  {
609  strcpy(tbuf, "r");
610  break;
612  strcpy(tbuf, "o");
613  break;
615  strcpy(tbuf, "i");
616  break;
618  if(bForceWildcard || !*tbuf)
619  strcpy(tbuf, "*");
620  break;
621  }
622 
623  DO_FONT_BUILD_THING(tbuf); // commit what I just did
624 
625  *tbuf = 0;
626  switch(pFI->iWidth)
627  {
628  case 1:
629  strcpy(tbuf, "normal");
630  break;
631  case 2:
632  strcpy(tbuf, "semicondensed");
633  break;
634  case 3: // RESERVED (may not matter)
635  strcpy(tbuf, "condensed"); // for now I have it here anyway
636  break;
637  case -1:
638  strcpy(tbuf, "*");
639  break;
640  default:
641  *tbuf = 0;
642  }
643 
644  switch(iFlags & WBFontFlag_WIDTH_MASK)
645  {
647  strcpy(tbuf, "normal");
648  break;
650  strcpy(tbuf, "semicondensed");
651  break;
653  if(bForceWildcard || !*tbuf)
654  strcpy(tbuf, "*");
655  break;
656  }
657 
658  DO_FONT_BUILD_THING(tbuf); // commit what I just did
659 
660  strncpy(tbuf, pFI->szAdStyle, sizeof(tbuf));
661 
662  // if I'm insisting on serif then this must be blank
663  switch(iFlags & WBFontFlag_STYLE_MASK)
664  {
666  strcpy(tbuf, "sans");
667  break;
669  *tbuf = 0;
670  break;
672  if(bForceWildcard)
673  strcpy(tbuf, "*");
674  break;
675  }
676 
677  DO_FONT_BUILD_THING(tbuf);
678 
679  // NOTE: if I specify pixel size, then point size must be a wildcard
680  // unless the pixel size is <= 0 (and vice versa)
681 
682  iAvgWidth = pFI->iAvgWidth;
683 
685  {
686  if(pFI->iPixelSize > 0 && iSize < 0 && !bForceWildcard)
687  sprintf(tbuf, "%d", pFI->iPixelSize);
688  else if(iSize > 0)
689  {
690  if(pFI->iPixelSize != iSize)
691  iAvgWidth = -1; // force this to be a wildcard
692  sprintf(tbuf, "%d", iSize);
693  }
694  else
695  strcpy(tbuf, "*");
696 
697  DO_FONT_BUILD_THING(tbuf);
698 
699  if(pFI->iPointSize > 0 && !bForceWildcard)
700  {
701  if(iSize <= 0 || iSize == pFI->iPixelSize)
702  sprintf(tbuf, "%d", pFI->iPointSize);
703  else
704  sprintf(tbuf, "%d", ((pFI->iPointSize * 2 * iSize / pFI->iPixelSize) + 1) / 2);
705  }
706  else
707  strcpy(tbuf, "*");
708 
709  DO_FONT_BUILD_THING(tbuf);
710  }
711  else if((iFlags & WBFontFlag_SIZE_MASK) == WBFontFlag_SIZE_POINTS ||
712  (iFlags & WBFontFlag_SIZE_MASK) == WBFontFlag_SIZE_TWIPS)
713  {
714  if(pFI->iPointSize > 0 && !bForceWildcard)
715  {
716  if(iSize < 0 ||
717  ((iFlags & WBFontFlag_SIZE_MASK) == WBFontFlag_SIZE_POINTS
718  && iSize * 10 == pFI->iPointSize) ||
719  ((iFlags & WBFontFlag_SIZE_MASK) == WBFontFlag_SIZE_TWIPS
720  && iSize / 2 == pFI->iPointSize))
721  {
722  sprintf(tbuf, "%d", pFI->iPixelSize);
723  }
724  else if(!iSize)
725  {
726  strcpy(tbuf, "*");
727  }
728  else if((iFlags & WBFontFlag_SIZE_MASK) == WBFontFlag_SIZE_POINTS)
729  {
730  sprintf(tbuf, "%d", ((pFI->iPixelSize * 20 * iSize / pFI->iPointSize) + 1) / 2);
731  }
732  else
733  {
734  sprintf(tbuf, "%d", ((pFI->iPixelSize * iSize / pFI->iPointSize) + 1) / 2);
735  }
736  }
737  else
738  strcpy(tbuf, "*");
739 
740  DO_FONT_BUILD_THING(tbuf);
741 
742  if(pFI->iPointSize > 0 && iSize < 0 && !bForceWildcard)
743  sprintf(tbuf, "%d", pFI->iPointSize);
744  else if(iSize > 0)
745  {
746  if((iFlags & WBFontFlag_SIZE_MASK) == WBFontFlag_SIZE_POINTS)
747  {
748  sprintf(tbuf, "%d", iSize * 10);
749  if(pFI->iPointSize != iSize * 10)
750  iAvgWidth = -1; // force this to be a wildcard
751  }
752  else
753  {
754  sprintf(tbuf, "%d", iSize / 2);
755  if(pFI->iPointSize != iSize / 2)
756  iAvgWidth = -1; // force this to be a wildcard
757  }
758  }
759  else
760  strcpy(tbuf, "*");
761 
762  DO_FONT_BUILD_THING(tbuf);
763  }
764  else // a 'just in case' catchall
765  {
766  if(pFI->iPixelSize > 0 && !bForceWildcard)
767  sprintf(tbuf, "%d", pFI->iPixelSize);
768  else
769  strcpy(tbuf, "*");
770 
771  DO_FONT_BUILD_THING(tbuf);
772 
773  if(pFI->iPointSize > 0 && !bForceWildcard)
774  sprintf(tbuf, "%d", pFI->iPointSize);
775  else
776  strcpy(tbuf, "*");
777 
778  DO_FONT_BUILD_THING(tbuf);
779  }
780 
781  if(!bForceWildcard && pFI->iResX > 0) // for now wildcard applies to resX
782  sprintf(tbuf, "%d", pFI->iResX);
783  else
784  strcpy(tbuf, "*");
785 
786  DO_FONT_BUILD_THING(tbuf);
787 
788  if(!bForceWildcard && pFI->iResY > 0) // for now wildcard applies to resY
789  sprintf(tbuf, "%d", pFI->iResY);
790  else
791  strcpy(tbuf, "*");
792 
793  DO_FONT_BUILD_THING(tbuf);
794 
795  *tbuf = 0;
796  switch(pFI->iSpacing)
797  {
798  case 1:
799  strcpy(tbuf, "c");
800  break;
801  case 2:
802  strcpy(tbuf, "m");
803  break;
804  case 7:
805  strcpy(tbuf, "p");
806  break;
807  case -1:
808  strcpy(tbuf, "*");
809  break;
810  }
811 
812  switch(iFlags & WBFontFlag_PITCH_MASK)
813  {
815  strcpy(tbuf, "m");
816  break;
818  strcpy(tbuf, "c");
819  break;
821  strcpy(tbuf, "p");
822  break;
824  if(!*tbuf || bForceWildcard)
825  strcpy(tbuf, "*");
826  break;
827  }
828 
829  DO_FONT_BUILD_THING(tbuf);
830 
831  // average width (with forced wildcard, ALWAYS make it a wildcard; else actual value)
832  if(bForceWildcard || iAvgWidth <= 0) // cached from above
833  strcpy(tbuf, "*");
834  else
835  sprintf(tbuf, "%d", pFI->iAvgWidth);
836 
837  DO_FONT_BUILD_THING(tbuf);
838 
839  // registry + encoding
840 
841  if(!bForceWildcard || pFI->szRegistry[0]) // wildcard for a blank implies '*'
842  strcpy(tbuf, pFI->szRegistry);
843  else
844  strcpy(tbuf, "*");
845 
846  // TODO: the effect of 'iFlags' on these two
847 
848  DO_FONT_BUILD_THING(tbuf);
849 
850  if(!bForceWildcard || pFI->szEncoding[0]) // wildcard for a blank implies '*'
851  strcpy(tbuf, pFI->szEncoding);
852  else
853  strcpy(tbuf, "*");
854 
855  DO_FONT_BUILD_THING(tbuf);
856 }
857 
858 XFontStruct *WBLoadFont(Display *pDisplay, const char *szFontName,
859  int iFontSize, int iFlags)
860 {
861 XFontStruct *pRval=NULL, *pFSInfo=NULL;
862 char **ppNames;
863 int i1, i2, i3, iBest, iCount = 0;
864 //int iWildcardFlag = 0;
865 char tbuf[512], tbuf2[512], tbuf3[512];
866 
867 // font names follow one of these patterns...
868 //
869 // AliasName (not preceded by a '-')
870 //
871 // or
872 //
873 // -foundry-family-weight-slant-sWidth-adstyle-pixelsize-pointsize-resX-resY-spacing-avgwidth-registry-encoding
874 //
875 // foundry = adoby, b&h, xfree86, misc, etc.
876 // family = lucida, terminal, courier, etc.
877 // weight = bold, demibold, medium, regular
878 // slant = i, o, r (italic, oblique, roman) - sometimes combinations like ro, ri
879 // sWidth = normal, semicondensed, condensed, narrow, double-width
880 // adstyle = (blank), sans, ja, ko, ???
881 // pixelsize = height in pixels
882 // pointsize = width in 10*points
883 // resX, resY = resolution?
884 // spacing = c, m, p (character, monospace, proportional)
885 // avgWidth (in tenths of a pixel)
886 // registry (i.e. 'iso8859' etc.)
887 // encoding (the '-' value following the registry, such as '1' for 'iso8859-1')
888 
889 
890 //#ifndef NO_DEBUG
891 // {
892 // static int iOnce = 0;
893 // if(!iOnce) // note this is SLOW and locks up the X server while it does it's thang
894 // {
895 // iOnce = 1;
896 //
897 // WBDumpMatchingFontNames(pDisplay, "-*-*-*-*-*-*-*-*-*-*-C-*-*-*");
898 // }
899 // }
900 //#endif // NO_DEBUG
901 
902 
903  // step 1: if it's a font alias, get the REAL font info. I'll need to do this if I'm requesting
904  // a bold or italic version of an aliased font, or even a different size.
905 
906  if(szFontName && *szFontName && !strchr(szFontName, '*') && !strchr(szFontName,'-'))
907  {
908  // get the alias name
909  WBFontNameFromAlias(szFontName, tbuf, sizeof(tbuf));
910 
911  if(!*tbuf)
912  {
913  strcpy(tbuf, "-*-");
914  strncpy(tbuf + 3, szFontName, sizeof(tbuf) - 3);
915  }
916  }
917  else
918  {
919 // iWildcardFlag = 1; // additional information (TODO: use this?)
920 
921  strncpy(tbuf, szFontName, sizeof(tbuf));
922  }
923 
924  // at this point 'tbuf' is assumed to be a properly formatted font string
925 
926  if(iFlags || iFontSize)
927  {
928  InternalBuildFontString(tbuf, iFontSize, iFlags, tbuf2, sizeof(tbuf2), FALSE);
929  }
930  else
931  {
932  strncpy(tbuf2, tbuf, sizeof(tbuf2));
933  }
934 
935  ppNames = XListFontsWithInfo(pDisplay, tbuf2, 2, &iCount, &pFSInfo);
936 
937  // in this case if I only have one font returned, and there are no overrides in iFlags,
938  // then that's the one I use. This is the simplest form of font mapping
939 
940  if(iCount == 1 && ppNames) // there is only a single match
941  pRval = XLoadQueryFont(pDisplay, *ppNames);
942 
943  if(ppNames)
944  {
945  XFreeFontInfo(ppNames, pFSInfo, iCount);
946  ppNames = NULL;
947  pFSInfo = NULL;
948  iCount = 0;
949  }
950 
951  if(pRval)
952  return pRval;
953 
954  // no match or multi-match - use wildcards, pick "the best one"
955 
956  InternalBuildFontString(tbuf, iFontSize, iFlags, tbuf3, sizeof(tbuf3), TRUE);
957 // fprintf(stderr, "TEMPORARY: font string 2 %s\n", tbuf3);
958 
959  ppNames = XListFontsWithInfo(pDisplay, tbuf3, 8192, &iCount, &pFSInfo);
960 
961  if(ppNames && iCount == 1)
962  {
963  pRval = XLoadQueryFont(pDisplay, *ppNames);
964  }
965  else if(ppNames && iCount > 1)
966  {
967  iBest = -1;
968  for(i1 = 0, i2 = -1; i1 < iCount; i1++)
969  {
970  i3 = InternalFontMatch2(ppNames[i1], tbuf2); // compare with non-forced-wildcard version
971  if(i3 > iBest)
972  {
973  iBest = i3;
974  i2 = i1;
975  }
976  }
977 
978  if(i2 >= 0)
979  {
980  pRval = XLoadQueryFont(pDisplay, ppNames[i2]);
981 // fprintf(stderr, "TEMPORARY 3: best match %s\n", ppNames[i2]);
982  }
983  }
984 
985  if(ppNames)
986  {
987  XFreeFontInfo(ppNames, pFSInfo, iCount);
988  ppNames = NULL;
989  pFSInfo = NULL;
990  iCount = 0;
991  }
992 
993  // TODO: other forms of 'fuzzy' matching?
994 
995  return pRval;
996 }
997 
998 int WBFontAvgCharWidth(Display *pDisplay, const XFontStruct *pFont)
999 {
1000 unsigned long lName, lPoints;
1001 char *pName = NULL;
1002 WB_FONT_INFO *pFI;
1003 int iRval = 0;
1004 
1005 
1006  // step 1: generate font string from XFontStruct
1007 
1008  if(!pFont)
1009  {
1010  return 0;
1011  }
1012 
1013 // WBDumpFontStruct(pFont);
1014 
1015  // calculate from 'AVERAGE_WIDTH' (in pixels) using font height and point info
1016 
1017  if(XGetFontProperty((XFontStruct *)pFont, aAVERAGE_WIDTH, &lName) &&
1018  XGetFontProperty((XFontStruct *)pFont, XA_POINT_SIZE, &lPoints) &&
1019  lPoints && lName)
1020  {
1021  iRval = (pFont->ascent + pFont->descent) * lName / lPoints;
1022 
1023 // WB_ERROR_PRINT("TEMPORARY: %s - avg font width=%d\n", __FUNCTION__, iRval);
1024 
1025  return iRval; // this will be the width [fastest method]
1026  }
1027 
1028  if(XGetFontProperty((XFontStruct *)pFont, XA_QUAD_WIDTH, &lName) && lName)
1029  {
1030  return (int)lName; // 'QUAD_WIDTH' value
1031  }
1032 
1033  // if i didn't have an average character width property, do it the *HARD* way
1034 
1035  if(XGetFontProperty((XFontStruct *)pFont, XA_FONT, &lName))
1036  {
1037  pName = WBGetAtomName(pDisplay ? pDisplay : WBGetDefaultDisplay(), (Atom)lName);
1038 
1039  if(!pName && pDisplay)
1040  {
1041  pName = WBGetAtomName(WBGetDefaultDisplay(), (Atom)lName);
1042  }
1043  }
1044 
1045  if(pName)
1046  {
1047 
1048  // if the user specified 'iFontSize' of zero, and did NOT include any
1049  // font size flags, make sure I duplicate the correct font size
1050 
1051  pFI = WBParseFontName(pName);
1052 
1053  if(pFI)
1054  {
1055  if(pFI->iAvgWidth)
1056  {
1057  iRval = (pFI->iAvgWidth * pFI->iPixelSize) / pFI->iPointSize;
1058  }
1059  else
1060  {
1061  iRval = pFI->iWidth; // assuming this is right
1062  }
1063 
1064  if(!iRval)
1065  {
1066  iRval = pFI->iWidth;
1067  }
1068 
1069 // WB_ERROR_PRINT("TEMPORARY: %s - width=%d, avg=%d, rval=%d\n", __FUNCTION__, pFI->iWidth, pFI->iAvgWidth, iRval);
1070  WBFree(pFI);
1071 
1072  if(iRval)
1073  {
1074  return iRval;
1075  }
1076  }
1077 
1078  WBFree(pName);
1079  pName = NULL; // by convention to prevent re-use
1080  }
1081 
1082  iRval = XTextWidth((XFontStruct *)pFont, " ", 1); // return the width of the 'space' character as a last resort
1083 
1084  if(!iRval)
1085  {
1086  iRval = (pFont->ascent + pFont->descent) / 2; // desperate measure, return half the height
1087 
1088  WB_ERROR_PRINT("TEMPORARY: %s - desperately returning 'half-height' avg font width %d\n", __FUNCTION__, iRval);
1089  }
1090 
1091  return iRval;
1092 }
1093 
1094 int WBFontSetDescent(Display *pDisplay, XFontSet fontSet)
1095 {
1096 XFontStruct **ppFontStruct = NULL;
1097 char **ppFontNames = NULL;
1098 int i1, i2, iN, iMax;
1099 
1100 
1101  if(fontSet == None)
1102  {
1103  fontSet = WBGetDefaultFontSet(pDisplay);
1104 
1105  if(fontSet == None)
1106  {
1107  WB_ERROR_PRINT("ERROR: %s - no default font set available\n", __FUNCTION__);
1108  return 0;
1109  }
1110  }
1111 
1112  iN = XFontsOfFontSet(fontSet, &ppFontStruct, &ppFontNames);
1113 
1114  // obtain the average character width of the ENTIRE font set
1115 
1116  for(iMax=0, i1=0; i1 < iN; i1++)
1117  {
1118  if(!ppFontStruct[i1])
1119  {
1120  continue;
1121  }
1122 
1123  i2 = ppFontStruct[i1]->descent;
1124 
1125  if(i2 > iMax)
1126  {
1127  iMax = i2;
1128  }
1129 
1130 // WBDebugPrint("TEMPORARY: %s - %4d: %2d %s\n", __FUNCTION__, i1, i2, ppFontNames[i1]);
1131  }
1132 
1133  return iMax;
1134 }
1135 
1136 int WBFontSetAscent(Display *pDisplay, XFontSet fontSet)
1137 {
1138 XFontStruct **ppFontStruct = NULL;
1139 char **ppFontNames = NULL;
1140 int i1, i2, iN, iMax;
1141 
1142 
1143  if(fontSet == None)
1144  {
1145  fontSet = WBGetDefaultFontSet(pDisplay);
1146 
1147  if(fontSet == None)
1148  {
1149  WB_ERROR_PRINT("ERROR: %s - no default font set available\n", __FUNCTION__);
1150  return 0;
1151  }
1152  }
1153 
1154  iN = XFontsOfFontSet(fontSet, &ppFontStruct, &ppFontNames);
1155 
1156  // obtain the average character width of the ENTIRE font set
1157 
1158  for(iMax=0, i1=0; i1 < iN; i1++)
1159  {
1160  if(!ppFontStruct[i1])
1161  {
1162  continue;
1163  }
1164 
1165  i2 = ppFontStruct[i1]->ascent;
1166 
1167  if(i2 > iMax)
1168  {
1169  iMax = i2;
1170  }
1171 
1172 // WBDebugPrint("TEMPORARY: %s - %4d: %2d %s\n", __FUNCTION__, i1, i2, ppFontNames[i1]);
1173  }
1174 
1175  return iMax;
1176 }
1177 
1178 int WBFontSetHeight(Display *pDisplay, XFontSet fontSet)
1179 {
1180 XFontStruct **ppFontStruct = NULL;
1181 char **ppFontNames = NULL;
1182 int i1, i2, iN, iMaxD, iMaxH;
1183 
1184 
1185  if(fontSet == None)
1186  {
1187  fontSet = WBGetDefaultFontSet(pDisplay);
1188 
1189  if(fontSet == None)
1190  {
1191  WB_ERROR_PRINT("ERROR: %s - no default font set available\n", __FUNCTION__);
1192  return 0;
1193  }
1194  }
1195 
1196  iN = XFontsOfFontSet(fontSet, &ppFontStruct, &ppFontNames);
1197 
1198  // obtain the average character width of the ENTIRE font set
1199 
1200  for(iMaxD=0, iMaxH=0, i1=0; i1 < iN; i1++)
1201  {
1202  if(!ppFontStruct[i1])
1203  {
1204  continue;
1205  }
1206 
1207  i2 = ppFontStruct[i1]->descent;
1208 
1209  if(i2 > iMaxD)
1210  {
1211  iMaxD = i2;
1212  }
1213 
1214  i2 = ppFontStruct[i1]->ascent;
1215 
1216  if(i2 > iMaxH)
1217  {
1218  iMaxH = i2;
1219  }
1220 
1221 // WBDebugPrint("TEMPORARY: %s - %4d: %2d %s\n", __FUNCTION__, i1, i2, ppFontNames[i1]);
1222  }
1223 
1224  return iMaxD + iMaxH;
1225 }
1226 
1227 int WBFontSetAvgCharWidth(Display *pDisplay, XFontSet fontSet)
1228 {
1229 XFontStruct **ppFontStruct = NULL;
1230 char **ppFontNames = NULL;
1231 int i1, i2, iN, iTotal, iMax, iCount;
1232 
1233 
1234  if(fontSet == None)
1235  {
1236  fontSet = WBGetDefaultFontSet(pDisplay);
1237 
1238  if(fontSet == None)
1239  {
1240  WB_ERROR_PRINT("ERROR: %s - no default font set available\n", __FUNCTION__);
1241  return 0;
1242  }
1243  }
1244 
1245  iN = XFontsOfFontSet(fontSet, &ppFontStruct, &ppFontNames);
1246 
1247  // obtain the average character width of the ENTIRE font set
1248 
1249  for(iCount=0, iMax=0, iTotal=0, i1=0; i1 < iN; i1++)
1250  {
1251  if(!ppFontStruct[i1])
1252  {
1253  continue;
1254  }
1255 
1256  iCount++;
1257 
1258  i2 = WBFontAvgCharWidth(pDisplay, ppFontStruct[i1]);
1259 
1260  if(i2 > 0)
1261  {
1262  iTotal += i2;
1263 
1264  if(i2 > iMax)
1265  {
1266  iMax = i2;
1267  }
1268  }
1269 
1270 // WBDebugPrint("TEMPORARY: %s - %4d: %2d %s\n", __FUNCTION__, i1, i2, ppFontNames[i1]);
1271  }
1272 
1273  if(iCount)
1274  {
1275  iTotal += iCount >> 1; // rounding
1276  iTotal /= iCount;
1277  }
1278 
1279  if(iTotal > iMax)
1280  {
1281  iTotal = iMax; // sort of a safety valve, should not be a problem
1282  }
1283 
1284  return iTotal;
1285 }
1286 
1287 XCharStruct WBFontSetMaxBounds(Display *pDisplay, XFontSet fontSet)
1288 {
1289 XCharStruct rVal;
1290 XFontStruct **ppFontStruct = NULL;
1291 char **ppFontNames = NULL;
1292 int i1, iN, iMax;
1293 
1294 
1295  bzero(&rVal, sizeof(rVal));
1296 
1297  if(fontSet == None)
1298  {
1299  fontSet = WBGetDefaultFontSet(pDisplay);
1300 
1301  if(fontSet == None)
1302  {
1303  WB_ERROR_PRINT("ERROR: %s - no default font set available\n", __FUNCTION__);
1304  return rVal;
1305  }
1306  }
1307 
1308  iN = XFontsOfFontSet(fontSet, &ppFontStruct, &ppFontNames);
1309 
1310  // obtain the average character width of the ENTIRE font set
1311 
1312  for(iMax=0, i1=0; i1 < iN; i1++)
1313  {
1314  if(!ppFontStruct[i1])
1315  {
1316  continue;
1317  }
1318 
1319  if(rVal.lbearing < ppFontStruct[i1]->max_bounds.lbearing)
1320  {
1321  rVal.lbearing = ppFontStruct[i1]->max_bounds.lbearing;
1322  }
1323 
1324  if(rVal.rbearing < ppFontStruct[i1]->max_bounds.rbearing)
1325  {
1326  rVal.rbearing = ppFontStruct[i1]->max_bounds.rbearing;
1327  }
1328 
1329  if(rVal.width < ppFontStruct[i1]->max_bounds.width)
1330  {
1331  rVal.width = ppFontStruct[i1]->max_bounds.width;
1332  }
1333 
1334  if(rVal.ascent < ppFontStruct[i1]->max_bounds.ascent)
1335  {
1336  rVal.ascent = ppFontStruct[i1]->max_bounds.ascent;
1337  }
1338 
1339  if(rVal.descent < ppFontStruct[i1]->max_bounds.descent)
1340  {
1341  rVal.descent = ppFontStruct[i1]->max_bounds.descent;
1342  }
1343 
1344 // WBDebugPrint("TEMPORARY: %s - %4d: %2d %s\n", __FUNCTION__, i1, i2, ppFontNames[i1]);
1345  }
1346 
1347  return rVal;
1348 }
1349 
1350 XFontStruct *WBLoadModifyFont(Display *pDisplay, const XFontStruct *pOriginal,
1351  int iFontSize, int iFlags)
1352 {
1353 unsigned long lName;
1354 char *pName = NULL;
1355 XFontStruct *pRval;
1356 
1357  // step 1: generate font string from XFontStruct
1358 
1359  if(!pOriginal)
1360  return NULL;
1361 
1362  if(XGetFontProperty((XFontStruct *)pOriginal, XA_FONT, &lName))
1363  {
1364  pName = WBGetAtomName(pDisplay ? pDisplay : WBGetDefaultDisplay(), (Atom)lName);
1365 
1366  if(!pName && pDisplay)
1367  {
1368  pName = WBGetAtomName(WBGetDefaultDisplay(), (Atom)lName); // desperately trying to succeed
1369  }
1370  }
1371 
1372  if(!pName)
1373  {
1374  return NULL;
1375  }
1376 
1377  // if the user specified 'iFontSize' of zero, and did NOT include any
1378  // font size flags, make sure I duplicate the correct font size
1379 
1380  if(!iFontSize)
1381  {
1382  WB_FONT_INFO *pFI = WBParseFontName(pName);
1383 
1384  iFlags &= ~WBFontFlag_SIZE_MASK; // reserved for the future
1385 
1386  if(pFI)
1387  {
1388  if(pFI->iPixelSize > 0)
1389  {
1390  iFontSize = pFI->iPixelSize;
1391  iFlags |= WBFontFlag_SIZE_PIXELS;
1392  }
1393  else if(pFI->iPointSize > 0)
1394  {
1395  iFontSize = pFI->iPointSize;
1396  iFlags |= WBFontFlag_SIZE_POINTS;
1397  }
1398  else
1399  {
1400  WBFree(pFI);
1401  pFI = NULL; // flag (see below)
1402  }
1403  }
1404 
1405  if(!pFI)
1406  {
1407  iFontSize = pOriginal->ascent + pOriginal->descent;
1408  iFlags |= WBFontFlag_SIZE_PIXELS;
1409  }
1410  else
1411  {
1412  WBFree(pFI);
1413  }
1414  }
1415 
1417  "%s(%s)\n", __FUNCTION__, pName);
1418 
1419  pRval = WBLoadFont(pDisplay, pName, iFontSize, iFlags);
1420 
1421  if(!pRval)
1422  {
1423  pRval = XLoadQueryFont(pDisplay, pName); // a copy of the original
1424  }
1425 
1426  WBFree(pName); // required (no longer need XFree, using 'WBGetAtomName()'
1427  pName = NULL; // by convention to prevent re-use
1428 
1429 
1430 #ifndef NO_DEBUG /* assign this to disable debugging - most likely a -D in Makefile */
1431  if((WBGetDebugLevel() & DebugLevel_MASK) >= FONT_DUMP_DEBUG_LEVEL ||
1433  {
1434  WBDumpFontStruct(pRval);
1435  }
1436 #endif // NO_DEBUG
1437 
1438  return pRval; // the NEW font!
1439 }
1440 
1441 XFontSet WBCopyModifyFontSet(Display *pDisplay, XFontSet fsOrig, int iFontSize, int iFlags)
1442 {
1443 XFontSet fsRval = None;
1444 char *p1, *pLocale, *pName, *pDef = NULL;
1445 char **ppMissing = NULL;
1446 int nMissing = 0;
1447 char tbuf[512];
1448 
1449 
1450  if(fsOrig == None)
1451  {
1452  fsOrig = WBGetDefaultFontSet(pDisplay);
1453 
1454  if(fsOrig == None)
1455  {
1456  WB_ERROR_PRINT("ERROR: %s - no default font set available\n", __FUNCTION__);
1457  return None;
1458  }
1459  }
1460 
1461  // grab the font name as a copy in 'pName'
1462 
1463  p1 = XBaseFontNameListOfFontSet(fsOrig); // grab the base name. this is NOT an allocated pointer
1464  if(!p1)
1465  {
1466  WB_ERROR_PRINT("ERROR: %s - font set can't get base name\n", __FUNCTION__);
1467  return None;
1468  }
1469 
1470  pName = WBCopyString(p1);
1471  if(!pName)
1472  {
1473  WB_ERROR_PRINT("ERROR: %s - no memory for copying base name\n", __FUNCTION__);
1474  return None;
1475  }
1476 
1477  p1 = strchr(pName, ','); // is there a comma?
1478  if(p1)
1479  {
1480  *p1 = 0; // terminate string (use ONLY the first one)
1481  }
1482 
1483  // use the string I created the font with to load a similar font, after I
1484  // modify the settings info.
1485 
1486  // if the user specified 'iFontSize' of zero, and did NOT include any
1487  // font size flags, make sure I duplicate the correct font size
1488 
1489  if(!iFontSize && iFlags) // only if I specify flags AND didn't specify a size...
1490  {
1491  WB_FONT_INFO *pFI = WBParseFontName(pName);
1492 
1493  iFlags &= ~WBFontFlag_SIZE_MASK; // reserved for the future
1494 
1495  if(pFI)
1496  {
1497  if(pFI->iPixelSize > 0)
1498  {
1499  iFontSize = pFI->iPixelSize;
1500  iFlags |= WBFontFlag_SIZE_PIXELS;
1501  }
1502  else if(pFI->iPointSize > 0)
1503  {
1504  iFontSize = pFI->iPointSize;
1505  iFlags |= WBFontFlag_SIZE_POINTS;
1506  }
1507  else
1508  {
1509  WBFree(pFI);
1510  pFI = NULL; // flag (see below)
1511  }
1512  }
1513 
1514  if(!pFI) // usually a big problem, but I'll work around it
1515  {
1516  iFontSize = WBFontSetHeight(pDisplay, fsOrig); // just do this
1517  iFlags |= WBFontFlag_SIZE_PIXELS;
1518  }
1519  else
1520  {
1521  WBFree(pFI);
1522  }
1523  }
1524 
1525  // at this point pName is assumed to be a properly formatted font string
1526  // this is the same (more or less) as what WBLoadFont will grab, except that I'm
1527  // using what I had before.
1528 
1529  // TODO: If I get "no font set" as my return, I'll need to attempt the original font set in its place
1530 
1531  if(iFlags || iFontSize) // specifying zero for both of these gives me a direct copy
1532  {
1533  tbuf[0] = 0;
1534 
1535  InternalBuildFontString(pName, iFontSize, iFlags, tbuf, sizeof(tbuf), FALSE);
1536 
1537  // TODO: soft-match? particularly for size. see WBLoadModifyFont()
1538  }
1539  else
1540  {
1541  strncpy(tbuf, pName, sizeof(tbuf));
1542  }
1543 
1545  "%s(%s)\n", __FUNCTION__, pName);
1546 
1547 
1548  // NOW we duplicate the process of creating the original font set
1549 
1550  pLocale = InternalCheckSetLocale(); // change to correct UTF-8 supporting font
1551 
1552  // OK - allocate 'tbuf' font first, and if that fails, use 'pName' again for a copy
1553 
1554  // NOTE: 'pDef' is owned by the font set. do NOT XFree it or modify its contents
1555 
1556  fsRval = XCreateFontSet(pDisplay, tbuf, &ppMissing, &nMissing, &pDef); // 6-7 milliseconds!!! (don't do this a lot)
1557 
1558  if(fsRval == None && // try again with original string
1559  strcmp(tbuf, pName)) // they're not identical so it's worth trying this
1560  {
1561  fsRval = XCreateFontSet(pDisplay, pName, &ppMissing, &nMissing, &pDef);
1562  }
1563 
1564 // WB_ERROR_PRINT("TEMPORARY: %s - setting locale back to \"%s\"\n", __FUNCTION__, pLocale);
1565 
1566  if(pLocale)
1567  {
1568  setlocale(LC_ALL, pLocale);
1569  WBFree(pLocale);
1570  pLocale = NULL;
1571  }
1572  else
1573  {
1574  setlocale(LC_ALL, "C"); // will set things back to "the default" I hope
1575  }
1576 
1577 
1578  // TODO: dump info?
1579 
1580 
1581  if(ppMissing || nMissing > 0)
1582  {
1583  if(ppMissing)
1584  {
1585  XFreeStringList(ppMissing);
1586  }
1587  else
1588  {
1589  WB_ERROR_PRINT("*BUG* %s - nMissing is %d\n", __FUNCTION__, nMissing);
1590  }
1591  }
1592 
1593 
1594  WBFree(pName);
1595  pName = NULL; // by convention to prevent re-use
1596 
1597 
1598 #ifndef NO_DEBUG /* assign this to disable debugging - most likely a -D in Makefile */
1599  if((WBGetDebugLevel() & DebugLevel_MASK) >= FONT_DUMP_DEBUG_LEVEL ||
1601  {
1602  WBDumpFontSet(pDisplay, fsRval);
1603  }
1604 #endif // NO_DEBUG
1605 
1606 
1607  return fsRval; // the NEW font set!
1608 }
1609 
1610 
1611 
1612 #ifdef USE_FONT_LIST_FOR_FONT_SET
1613 
1614 static char * InternalGetMatchingFontNameList(Display *pDisplay, const char *szFontName)
1615 {
1616 char *pRval, *p1;
1617 char **ppNames;
1618 int i1, iCount, iLen;
1619 XFontStruct *pFSInfo;
1620 
1621  pRval = NULL;
1622 
1623  ppNames = XListFontsWithInfo(pDisplay, szFontName, 8192, &iCount, &pFSInfo);
1624 
1625  if(ppNames)
1626  {
1627  for(i1=0, iLen=1; i1 < iCount; i1++)
1628  {
1629  iLen += strlen(ppNames[i1]) + 1;
1630  }
1631 
1632  pRval = WBAlloc(iLen + 1);
1633 
1634  if(pRval)
1635  {
1636  for(i1=0, p1=pRval; i1 < iCount; i1++)
1637  {
1638  if(i1 > 0)
1639  {
1640  *(p1++) = ','; // comma-separated font name list
1641  }
1642 
1643  strcpy(p1, ppNames[i1]);
1644  p1 += strlen(p1);
1645  }
1646  }
1647 
1648  XFreeFontInfo(ppNames, pFSInfo, iCount);
1649  }
1650 
1651  if(!pRval) // fallback, try desperately to make this work
1652  {
1653  pRval = WBCopyString(szFontName);
1654  }
1655 
1656  return pRval;
1657 }
1658 
1659 #endif // USE_FONT_LIST_FOR_FONT_SET
1660 
1661 
1662 static char *InternalCheckSetLocale(void)
1663 {
1664 char *p1, *pLocale, *pNewLocale;
1665 static const char szUTF8[]=".UTF-8";
1666 
1667 
1668  p1 = setlocale(LC_CTYPE, NULL); // get the current locale
1669 
1670  if(p1)
1671  {
1672  pLocale = WBCopyString(p1);
1673  }
1674  else
1675  {
1676  WB_ERROR_PRINT("ERROR: %s - not enough memory\n", __FUNCTION__);
1677 
1678  return NULL; // error (unable to copy string)
1679  }
1680 
1681  // TODO: treat this section differently when UTF8 *NOT* supported by libX11
1682  // determine whether this is a UTF-8 locale
1683  if(!strcasecmp(pLocale + strlen(pLocale) - (sizeof(szUTF8)-1), szUTF8)) // already UTF-8 capable?
1684  {
1685 // WB_ERROR_PRINT("TEMPORARY: %s - locale \"%s\" already supports UTF-8\n", __FUNCTION__, pLocale);
1686 
1687  WBFree(pLocale);
1688  pLocale = NULL;
1689  }
1690  else
1691  {
1692  pNewLocale = NULL;
1693 
1694  if(!strcasecmp(pLocale, "C") || // is it the 'C' locale or 'POSIX' locale?
1695  !strcasecmp(pLocale, "POSIX"))
1696  {
1697  pNewLocale = WBCopyString("en_US.UTF-8"); // use THIS one (should work)
1698  }
1699  else
1700  {
1701  pNewLocale = WBCopyString(pLocale);
1702 
1703  if(pNewLocale)
1704  {
1705  p1 = pNewLocale + strlen(pNewLocale);
1706 
1707  while(p1 > pNewLocale && *(--p1) != '.') { }
1708 
1709  if(p1 > pNewLocale)
1710  {
1711  *p1 = 0; // the '.' so I can use .UTF-8 as my suffix
1712  }
1713 
1714  WBCatString(&pNewLocale, szUTF8); // tack on the '.UTF-8' thing
1715  }
1716  }
1717 
1718  if(pNewLocale) // still valid
1719  {
1720  if(setlocale(LC_CTYPE, pNewLocale)) // not NULL
1721  {
1722 // WB_ERROR_PRINT("TEMPORARY: %s - set locale to \"%s\"\n", __FUNCTION__, pNewLocale);
1723  }
1724  else
1725  {
1726 // WB_ERROR_PRINT("TEMPORARY: %s - unable to set locale to \"%s\"\n", __FUNCTION__, pNewLocale);
1727  // TODO: search for a locale that will work
1728 
1729  WBFree(pNewLocale);
1730  pNewLocale = NULL; // as a flag
1731  }
1732  }
1733 
1734  if(pNewLocale) // this is also a flag to say that I successfully changed the locale
1735  {
1736  WBFree(pNewLocale);
1737  }
1738  else
1739  {
1740  WB_ERROR_PRINT("TEMPORARY: %s - fallback, set locale to \"en_US.UTF-8\"\n", __FUNCTION__);
1741 
1742  setlocale(LC_CTYPE, "en_US.UTF-8"); // as a fallback. for now, hard-coded to simply allow UTF-8 characters
1743  }
1744  }
1745 
1746  return pLocale; // original locale I need to change back to
1747 }
1748 
1749 XFontSet WBFontSetFromFont(Display *pDisplay, const XFontStruct *pFont)
1750 {
1751 unsigned long lName;
1752 char *pName = NULL, *pDef = NULL;
1753 XFontSet rVal = None;
1754 char **ppMissing = NULL;
1755 int nMissing = 0;
1756 char *p1, *pLocale;
1757 static const char szISO[]="-ISO8859-";
1758 //#ifndef NO_DEBUG
1759 //unsigned long long ullTemp;
1760 //#endif // NO_DEBUG
1761 
1762  // step 1: generate font string from XFontStruct
1763 
1764  if(!pFont)
1765  {
1766  pFont = WBGetDefaultFont();
1767  if(!pFont)
1768  {
1769  WB_ERROR_PRINT("%s - no font, returning NULL\n", __FUNCTION__);
1770  return NULL;
1771  }
1772  }
1773 
1774  if(XGetFontProperty((XFontStruct *)pFont, XA_FONT, &lName))
1775  {
1776  pName = WBGetAtomName(pDisplay ? pDisplay : WBGetDefaultDisplay(), (Atom)lName);
1777 
1778  if(!pName && pDisplay)
1779  {
1780  pName = WBGetAtomName(WBGetDefaultDisplay(), (Atom)lName);
1781  // NOTE: 'pName' is an editable WBAlloc'd pointer that's a copy of the atom name
1782  }
1783  }
1784 
1785  if(!pName)
1786  {
1787  WB_ERROR_PRINT("%s - no font name, returning NULL\n", __FUNCTION__);
1788  return NULL;
1789  }
1790 
1791  p1 = WBReAlloc(pName, strlen(pName) * 2 + 64); // make sure it's big enough to edit it
1792 
1793  if(!p1)
1794  {
1795  WBFree(pName);
1796 
1797  WB_ERROR_PRINT("%s - no memory to update font name, returning NULL\n", __FUNCTION__);
1798  return NULL;
1799  }
1800 
1801  pName = p1; // now big enough to be edited
1802 
1803 
1804  // font name is an alias name, or starts with a '-' and is of the form:
1805  // -foundry-family-weight-slant-sWidth-adstyle-pixelsize-pointsize-resX-resY-spacing-avgwidth-registry-encoding
1806  //
1807  // foundry = adoby, b&h, xfree86, misc, etc.
1808  // family = lucida, terminal, courier, etc.
1809  // weight = bold, demibold, medium, regular
1810  // slant = i, o, r (italic, oblique, roman) - sometimes combinations like ro, ri
1811  // sWidth = normal, semicondensed, condensed, narrow, double-width
1812  // adstyle = (blank), sans, ja, ko, ???
1813  // pixelsize = height in pixels
1814  // pointsize = width in 10*points
1815  // resX, resY = resolution?
1816  // spacing = c, m, p (character, monospace, proportional)
1817  // avgWidth (in tenths of a pixel)
1818  // registry (i.e. 'iso8859' etc.)
1819  // encoding (the '-' value following the registry, such as '1' for 'iso8859-1')
1820 
1821 
1822  // using the font's name string, create a single entry font set for it
1823  // if the final entry is ISO8859-# change it to *-*
1824  // ( TODO: check for other language-dependent things, or maybe just do the last 2 '-'s ? )
1825 
1826 
1827 // // if the starting string is "-Misc-", change to "-*-" to allow ALL
1828 //
1829 // if(!strncasecmp(pName, "-Misc-", 6))
1830 // {
1831 // strcpy(pName, "-*-");
1832 // strcpy(pName + 3, pName + 6);
1833 // }
1834 
1835  p1 = pName + strlen(pName) - sizeof(szISO);
1836 
1837  while(p1 > pName && strncasecmp(p1, szISO, sizeof(szISO)-1)) // note must be case INsensitive compare...
1838  {
1839  p1--;
1840  }
1841 
1842  if(p1 > pName) // found
1843  {
1844  strcpy(p1, "-*-*"); // this allows all of the code sets to be included (fastest method)
1845  }
1846 
1847 //#ifndef NO_DEBUG
1848 // ullTemp = WBGetTimeIndex();
1849 //#endif // NO_DEBUG
1850 
1851  pLocale = InternalCheckSetLocale();
1852 
1853 //#ifndef NO_DEBUG
1854 // WB_ERROR_PRINT("TEMPORARY: %s - setlocale took %ld micros\n", __FUNCTION__, (long)(WBGetTimeIndex() - ullTemp));
1855 // ullTemp = WBGetTimeIndex();
1856 //#endif // NO_DEBUG
1857 
1858  // NOTE: 'pDef' is owned by the font set. do NOT XFree it or modify its contents
1859 
1860  rVal = XCreateFontSet(pDisplay, pName, &ppMissing, &nMissing, &pDef); // 6-7 milliseconds!!!
1861 
1862 //#ifndef NO_DEBUG
1863 // WB_ERROR_PRINT("TEMPORARY: %s - XCreateFontSet took %ld micros\n", __FUNCTION__, (long)(WBGetTimeIndex() - ullTemp));
1864 // ullTemp = WBGetTimeIndex();
1865 //#endif // NO_DEBUG
1866 
1867  if(pLocale)
1868  {
1869 // WB_ERROR_PRINT("TEMPORARY: %s - setting locale back to \"%s\"\n", __FUNCTION__, pLocale);
1870 
1871  setlocale(LC_CTYPE, pLocale);
1872 
1873  WBFree(pLocale);
1874  pLocale = NULL;
1875  }
1876 // else
1877 // {
1878 // setlocale(LC_CTYPE, "C"); // will set things back to "the default" I hope
1879 // }
1880 
1881 
1882  // TODO: dump info?
1883 
1884 
1885  if(ppMissing || nMissing > 0)
1886  {
1887  if(ppMissing)
1888  {
1889  // int i1;
1890  //
1891  // WB_ERROR_PRINT("TEMPORARY: %s\n", __FUNCTION__);
1892  //
1893  // for(i1=0; i1 < nMissing; i1++)
1894  // {
1895  // WB_ERROR_PRINT(" %d : %s\n", i1, ppMissing[i1]);
1896  // }
1897 
1898  XFreeStringList(ppMissing);
1899  }
1900  else
1901  {
1902  WB_ERROR_PRINT("*BUG* %s - nMissing is %d\n", __FUNCTION__, nMissing);
1903  }
1904  }
1905 
1906  WBFree(pName);
1907  pName = NULL; // by convention to prevent re-use
1908 
1909  if(!rVal)
1910  {
1911  WB_ERROR_PRINT("%s - no result, returning NULL\n", __FUNCTION__);
1912  }
1913 //#ifndef NO_DEBUG
1914 // else
1915 // {
1916 // WBDumpFontSet(pDisplay, rVal);
1917 // }
1918 //#endif // NO_DEBUG
1919 
1920  return rVal;
1921 }
1922 
1923 
1924 XFontSet WBFontSetFromFontSingle(Display *pDisplay, const XFontStruct *pFont)
1925 {
1926 unsigned long lName;
1927 char *pName = NULL, *pDef = NULL;
1928 XFontSet rVal = None;
1929 char **ppMissing = NULL;
1930 int nMissing = 0;
1931 char *p1, *pLocale;
1932 
1933  // step 1: generate font string from XFontStruct
1934 
1935  if(!pFont)
1936  {
1937  pFont = WBGetDefaultFont();
1938  if(!pFont)
1939  {
1940  WB_ERROR_PRINT("%s - no font, returning NULL\n", __FUNCTION__);
1941  return NULL;
1942  }
1943  }
1944 
1945  if(XGetFontProperty((XFontStruct *)pFont, XA_FONT, &lName))
1946  {
1947  pName = WBGetAtomName(pDisplay ? pDisplay : WBGetDefaultDisplay(), (Atom)lName);
1948 
1949  if(!pName && pDisplay)
1950  {
1951  pName = WBGetAtomName(WBGetDefaultDisplay(), (Atom)lName);
1952  // NOTE: 'pName' is an editable WBAlloc'd pointer that's a copy of the atom name
1953  }
1954  }
1955 
1956  if(!pName)
1957  {
1958  WB_ERROR_PRINT("%s - no font name, returning NULL\n", __FUNCTION__);
1959  return NULL;
1960  }
1961 
1962  p1 = setlocale(LC_CTYPE, NULL); // get the current locale
1963 
1964  if(p1)
1965  {
1966  pLocale = WBCopyString(p1);
1967  }
1968  else
1969  {
1970  pLocale = NULL;
1971  }
1972 
1973  setlocale(LC_CTYPE, "C"); // set to 'C' locale, which gives me a single font set only that matches THIS one
1974 
1975  // NOTE: 'pDef' is owned by the font set. do NOT XFree it or modify its contents
1976 
1977  rVal = XCreateFontSet(pDisplay, pName, &ppMissing, &nMissing, &pDef); // 6-7 milliseconds!!!
1978 
1979  WB_ERROR_PRINT("TEMPORARY: %s - setting locale back to \"%s\"\n", __FUNCTION__, pLocale);
1980 
1981  if(pLocale)
1982  {
1983  setlocale(LC_CTYPE, pLocale);
1984  WBFree(pLocale);
1985  pLocale = NULL;
1986  }
1987 // else
1988 // {
1989 // setlocale(LC_ALL, "C"); // will set things back to "the default" I hope
1990 // }
1991 
1992 
1993  // TODO: dump info?
1994 
1995 
1996  if(ppMissing || nMissing > 0)
1997  {
1998  if(ppMissing)
1999  {
2000  XFreeStringList(ppMissing);
2001  }
2002  else
2003  {
2004  WB_ERROR_PRINT("*BUG* %s - nMissing is %d\n", __FUNCTION__, nMissing);
2005  }
2006  }
2007 
2008  WBFree(pName);
2009  pName = NULL; // by convention to prevent re-use
2010 
2011  if(!rVal)
2012  {
2013  WB_ERROR_PRINT("%s - no result, returning NULL\n", __FUNCTION__);
2014  }
2015 #ifndef NO_DEBUG
2016  else
2017  {
2018  WBDumpFontSet(pDisplay, rVal);
2019  }
2020 #endif // NO_DEBUG
2021 
2022  return rVal;
2023 }
2024 
2025 
2026 XFontStruct * WBFontFromFontSet(Display *pDisplay, XFontSet fontSet)
2027 {
2028 XFontStruct **ppFontStruct = NULL;
2029 char **ppFontNames = NULL;
2030 int i1, iN;
2031 XFontStruct *pRval = NULL;
2032 
2033 
2034  if(fontSet == None)
2035  {
2036  fontSet = WBGetDefaultFontSet(pDisplay);
2037 
2038  if(fontSet == None)
2039  {
2040  WB_ERROR_PRINT("ERROR: %s - no default font set available\n", __FUNCTION__);
2041  return 0;
2042  }
2043  }
2044 
2045  iN = XFontsOfFontSet(fontSet, &ppFontStruct, &ppFontNames);
2046 
2047  // get the first valid font struct and make a copy
2048 
2049  for(i1=0; i1 < iN; i1++)
2050  {
2051  if(ppFontStruct[i1])
2052  {
2053  pRval = WBCopyFont(ppFontStruct[i1]); // first one that's valid is my bail-out point
2054 
2055  if(pRval) // bail if it worked
2056  {
2057  break;
2058  }
2059  }
2060  }
2061 
2062  return pRval;
2063 }
2064 
2065 
2066 int WBTextWidth(XFontSet fontSet, const char *szText, int cbText)
2067 {
2068 int iLen, iRval;
2069 
2070 
2071  if(!fontSet || !cbText || !szText || (cbText < 0 && !*szText))
2072  {
2073  return 0;
2074  }
2075  else if(cbText < 0)
2076  {
2077  iLen = strlen(szText);
2078  }
2079  else
2080  {
2081  iLen = cbText;
2082  }
2083 
2084  iRval = WB_TEXT_ESCAPEMENT(fontSet, szText, iLen);
2085 
2086 // if(iRval <= 0)
2087 // {
2088 // iLen = mblen(szUTF8, nLength); // width estimate
2089 // iLen = XTextWidth(pFont, " ", 1) * iLen;
2090 //
2091 // WB_ERROR_PRINT("%s WOULD BE returning %d, NOW returning %d\n", __FUNCTION__, iRval, iLen);
2092 // iRval = iLen;
2093 // }
2094 
2095  return iRval;
2096 }
2097 
2098 
2099 
2100 #ifndef NO_DEBUG
2101 
2102 static void WBDumpFontStruct(const XFontStruct *pFont)
2103 {
2104 int i1;
2105 
2106  typedef struct {
2107  XExtData *ext_data; /* hook for extension to hang data */
2108  Font fid; /* Font id for this font */
2109  unsigned direction; /* hint about the direction font is painted */
2110  unsigned min_char_or_byte2;/* first character */
2111  unsigned max_char_or_byte2;/* last character */
2112  unsigned min_byte1; /* first row that exists */
2113  unsigned max_byte1; /* last row that exists */
2114  Bool all_chars_exist; /* flag if all characters have nonzero size */
2115  unsigned default_char; /* char to print for undefined character */
2116  int n_properties; /* how many properties there are */
2117  XFontProp *properties; /* pointer to array of additional properties */
2118  XCharStruct min_bounds; /* minimum bounds over all existing char */
2119  XCharStruct max_bounds; /* maximum bounds over all existing char */
2120  XCharStruct *per_char; /* first_char to last_char information */
2121  int ascent; /* logical extent above baseline for spacing */
2122  int descent; /* logical decent below baseline for spacing */
2123  } XFontStruct;
2124 
2125 
2126  WB_WARN_PRINT("WBDumpFontStruct(%pH)\n", pFont);
2127  WB_WARN_PRINT(" ext_data = %pH\n"
2128  " fid = %d (%08xH)\n"
2129  " direction = %d\n"
2130  " min_char_or_byte2= %d\n"
2131  " max_char_or_byte2= %d\n"
2132  " min_byte1 = %d\n"
2133  " max_byte1 = %d\n"
2134  " all_chars_exist = %d\n"
2135  " default_char = %d\n"
2136  " n_properties = %d\n",
2137  pFont->ext_data,
2138  (int)pFont->fid, (int)pFont->fid,
2139  pFont->direction,
2140  pFont->min_char_or_byte2,
2141  pFont->max_char_or_byte2,
2142  pFont->min_byte1,
2143  pFont->max_byte1,
2144  pFont->all_chars_exist,
2145  pFont->default_char,
2146  pFont->n_properties);
2147 
2148  for(i1=0; i1 < pFont->n_properties; i1++)
2149  {
2150  char *p1 = WBGetAtomName(WBGetDefaultDisplay(), pFont->properties[i1].name);
2151  char *p2 = WBGetAtomName(WBGetDefaultDisplay(), (Atom)pFont->properties[i1].card32);
2152 
2153  WB_WARN_PRINT(" %5d %-20s = %ld (%08lxH) %s\n",
2154  (int)pFont->properties[i1].name,p1,
2155  pFont->properties[i1].card32,
2156  pFont->properties[i1].card32, p2);
2157 
2158  if(p1)
2159  {
2160  WBFree(p1);
2161  }
2162 
2163  if(p2)
2164  {
2165  WBFree(p2);
2166  }
2167  }
2168 
2169  WB_WARN_PRINT(" ascent = %d\n"
2170  " descent = %d\n",
2171  pFont->ascent,
2172  pFont->descent);
2173 }
2174 
2175 static void WBDumpMatchingFontNames(Display *pDisplay, const char *szFontName)
2176 {
2177 char **ppNames;
2178 int i1, iCount;
2179 XFontStruct *pFSInfo;
2180 
2181  ppNames = XListFontsWithInfo(pDisplay, szFontName, 8192, &iCount, &pFSInfo);
2182 
2183  if(ppNames)
2184  {
2185  WBDebugPrint("%s - fonts matching \"%s\"\n", __FUNCTION__, szFontName);
2186 
2187  for(i1=0; i1 < iCount; i1++)
2188  {
2189  WBDebugPrint(" %4d: %s\n", i1, ppNames[i1]);
2190  }
2191  }
2192  else
2193  {
2194  WBDebugPrint("%s - NO fonts match \"%s\"\n", __FUNCTION__, szFontName);
2195 
2196  }
2197 
2198  if(ppNames)
2199  {
2200  XFreeFontInfo(ppNames, pFSInfo, iCount);
2201  }
2202 }
2203 
2204 static void WBDumpFontSet(Display *pDisplay, XFontSet fontSet)
2205 {
2206 XFontStruct **ppFontStruct = NULL;
2207 char **ppFontNames = NULL;
2208 int i1, iN;
2209 
2210  iN = XFontsOfFontSet(fontSet, &ppFontStruct, &ppFontNames);
2211 
2212  WBDebugPrint("%s - font set contains %d fonts\n", __FUNCTION__, iN);
2213  WBDebugPrint("font set locale \"%s\"\n", XLocaleOfFontSet(fontSet));
2214 
2215  WBDebugPrint("base name: \"%s\"\n\n", XBaseFontNameListOfFontSet(fontSet));
2216 
2217  for(i1=0; i1 < iN; i1++)
2218  {
2219  WBDebugPrint(" %4d: %s\n", i1, ppFontNames[i1]);
2220  }
2221 }
2222 
2223 
2224 #endif // NO_DEBUG
2225