X11workbench Toolkit  1.0
font_helper.c
Go to the documentation of this file.
1 // __ _ _ _ //
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-2018 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  {
111  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Font,
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 ||
127  (WBGetDebugLevel() & DebugSubSystem_Font))
128  {
129  WBDumpFontStruct(pOldFont);
130  }
131 #endif // NO_DEBUG
132 
133  // this is a fallback so debug output is 'light' category, like warnings
134 
135  WB_DEBUG_PRINT(DebugLevel_WARN | DebugSubSystem_Font,
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 
1416  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Font,
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 ||
1432  (WBGetDebugLevel() & DebugSubSystem_Font))
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 
1544  WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Font,
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 ||
1600 // (WBGetDebugLevel() & DebugSubSystem_Font))
1601  WB_IF_DEBUG_LEVEL(FONT_DUMP_DEBUG_LEVEL | DebugSubSystem_Font)
1602  {
1603  WBDumpFontSet(pDisplay, fsRval);
1604  }
1605 #endif // NO_DEBUG
1606 
1607 
1608  return fsRval; // the NEW font set!
1609 }
1610 
1611 
1612 
1613 #ifdef USE_FONT_LIST_FOR_FONT_SET
1614 
1615 static char * InternalGetMatchingFontNameList(Display *pDisplay, const char *szFontName)
1616 {
1617 char *pRval, *p1;
1618 char **ppNames;
1619 int i1, iCount, iLen;
1620 XFontStruct *pFSInfo;
1621 
1622  pRval = NULL;
1623 
1624  ppNames = XListFontsWithInfo(pDisplay, szFontName, 8192, &iCount, &pFSInfo);
1625 
1626  if(ppNames)
1627  {
1628  for(i1=0, iLen=1; i1 < iCount; i1++)
1629  {
1630  iLen += strlen(ppNames[i1]) + 1;
1631  }
1632 
1633  pRval = WBAlloc(iLen + 1);
1634 
1635  if(pRval)
1636  {
1637  for(i1=0, p1=pRval; i1 < iCount; i1++)
1638  {
1639  if(i1 > 0)
1640  {
1641  *(p1++) = ','; // comma-separated font name list
1642  }
1643 
1644  strcpy(p1, ppNames[i1]);
1645  p1 += strlen(p1);
1646  }
1647  }
1648 
1649  XFreeFontInfo(ppNames, pFSInfo, iCount);
1650  }
1651 
1652  if(!pRval) // fallback, try desperately to make this work
1653  {
1654  pRval = WBCopyString(szFontName);
1655  }
1656 
1657  return pRval;
1658 }
1659 
1660 #endif // USE_FONT_LIST_FOR_FONT_SET
1661 
1662 
1663 static char *InternalCheckSetLocale(void)
1664 {
1665 char *p1, *pLocale, *pNewLocale;
1666 static const char szUTF8[]=".UTF-8";
1667 
1668 
1669  p1 = setlocale(LC_CTYPE, NULL); // get the current locale
1670 
1671  if(p1)
1672  {
1673  pLocale = WBCopyString(p1);
1674  }
1675  else
1676  {
1677  WB_ERROR_PRINT("ERROR: %s - not enough memory\n", __FUNCTION__);
1678 
1679  return NULL; // error (unable to copy string)
1680  }
1681 
1682  // TODO: treat this section differently when UTF8 *NOT* supported by libX11
1683  // determine whether this is a UTF-8 locale
1684  if(!strcasecmp(pLocale + strlen(pLocale) - (sizeof(szUTF8)-1), szUTF8)) // already UTF-8 capable?
1685  {
1686 // WB_ERROR_PRINT("TEMPORARY: %s - locale \"%s\" already supports UTF-8\n", __FUNCTION__, pLocale);
1687 
1688  WBFree(pLocale);
1689  pLocale = NULL;
1690  }
1691  else
1692  {
1693  pNewLocale = NULL;
1694 
1695  if(!strcasecmp(pLocale, "C") || // is it the 'C' locale or 'POSIX' locale?
1696  !strcasecmp(pLocale, "POSIX"))
1697  {
1698  pNewLocale = WBCopyString("en_US.UTF-8"); // use THIS one (should work)
1699  }
1700  else
1701  {
1702  pNewLocale = WBCopyString(pLocale);
1703 
1704  if(pNewLocale)
1705  {
1706  p1 = pNewLocale + strlen(pNewLocale);
1707 
1708  while(p1 > pNewLocale && *(--p1) != '.') { }
1709 
1710  if(p1 > pNewLocale)
1711  {
1712  *p1 = 0; // the '.' so I can use .UTF-8 as my suffix
1713  }
1714 
1715  WBCatString(&pNewLocale, szUTF8); // tack on the '.UTF-8' thing
1716  }
1717  }
1718 
1719  if(pNewLocale) // still valid
1720  {
1721  if(setlocale(LC_CTYPE, pNewLocale)) // not NULL
1722  {
1723 // WB_ERROR_PRINT("TEMPORARY: %s - set locale to \"%s\"\n", __FUNCTION__, pNewLocale);
1724  }
1725  else
1726  {
1727 // WB_ERROR_PRINT("TEMPORARY: %s - unable to set locale to \"%s\"\n", __FUNCTION__, pNewLocale);
1728  // TODO: search for a locale that will work
1729 
1730  WBFree(pNewLocale);
1731  pNewLocale = NULL; // as a flag
1732  }
1733  }
1734 
1735  if(pNewLocale) // this is also a flag to say that I successfully changed the locale
1736  {
1737  WBFree(pNewLocale);
1738  }
1739  else
1740  {
1741  WB_ERROR_PRINT("TEMPORARY: %s - fallback, set locale to \"en_US.UTF-8\"\n", __FUNCTION__);
1742 
1743  setlocale(LC_CTYPE, "en_US.UTF-8"); // as a fallback. for now, hard-coded to simply allow UTF-8 characters
1744  }
1745  }
1746 
1747  return pLocale; // original locale I need to change back to
1748 }
1749 
1750 XFontSet WBFontSetFromFont(Display *pDisplay, const XFontStruct *pFont)
1751 {
1752 unsigned long lName;
1753 char *pName = NULL, *pDef = NULL;
1754 XFontSet rVal = None;
1755 char **ppMissing = NULL;
1756 int nMissing = 0;
1757 char *p1, *pLocale;
1758 static const char szISO[]="-ISO8859-";
1759 //#ifndef NO_DEBUG
1760 //unsigned long long ullTemp;
1761 //#endif // NO_DEBUG
1762 
1763  // step 1: generate font string from XFontStruct
1764 
1765  if(!pFont)
1766  {
1767  pFont = WBGetDefaultFont();
1768  if(!pFont)
1769  {
1770  WB_ERROR_PRINT("%s - no font, returning NULL\n", __FUNCTION__);
1771  return NULL;
1772  }
1773  }
1774 
1775  if(XGetFontProperty((XFontStruct *)pFont, XA_FONT, &lName))
1776  {
1777  pName = WBGetAtomName(pDisplay ? pDisplay : WBGetDefaultDisplay(), (Atom)lName);
1778 
1779  if(!pName && pDisplay)
1780  {
1781  pName = WBGetAtomName(WBGetDefaultDisplay(), (Atom)lName);
1782  // NOTE: 'pName' is an editable WBAlloc'd pointer that's a copy of the atom name
1783  }
1784  }
1785 
1786  if(!pName)
1787  {
1788  WB_ERROR_PRINT("%s - no font name, returning NULL\n", __FUNCTION__);
1789  return NULL;
1790  }
1791 
1792  p1 = WBReAlloc(pName, strlen(pName) * 2 + 64); // make sure it's big enough to edit it
1793 
1794  if(!p1)
1795  {
1796  WBFree(pName);
1797 
1798  WB_ERROR_PRINT("%s - no memory to update font name, returning NULL\n", __FUNCTION__);
1799  return NULL;
1800  }
1801 
1802  pName = p1; // now big enough to be edited
1803 
1804 
1805  // font name is an alias name, or starts with a '-' and is of the form:
1806  // -foundry-family-weight-slant-sWidth-adstyle-pixelsize-pointsize-resX-resY-spacing-avgwidth-registry-encoding
1807  //
1808  // foundry = adoby, b&h, xfree86, misc, etc.
1809  // family = lucida, terminal, courier, etc.
1810  // weight = bold, demibold, medium, regular
1811  // slant = i, o, r (italic, oblique, roman) - sometimes combinations like ro, ri
1812  // sWidth = normal, semicondensed, condensed, narrow, double-width
1813  // adstyle = (blank), sans, ja, ko, ???
1814  // pixelsize = height in pixels
1815  // pointsize = width in 10*points
1816  // resX, resY = resolution?
1817  // spacing = c, m, p (character, monospace, proportional)
1818  // avgWidth (in tenths of a pixel)
1819  // registry (i.e. 'iso8859' etc.)
1820  // encoding (the '-' value following the registry, such as '1' for 'iso8859-1')
1821 
1822 
1823  // using the font's name string, create a single entry font set for it
1824  // if the final entry is ISO8859-# change it to *-*
1825  // ( TODO: check for other language-dependent things, or maybe just do the last 2 '-'s ? )
1826 
1827 
1828 // // if the starting string is "-Misc-", change to "-*-" to allow ALL
1829 //
1830 // if(!strncasecmp(pName, "-Misc-", 6))
1831 // {
1832 // strcpy(pName, "-*-");
1833 // strcpy(pName + 3, pName + 6);
1834 // }
1835 
1836  p1 = pName + strlen(pName) - sizeof(szISO);
1837 
1838  while(p1 > pName && strncasecmp(p1, szISO, sizeof(szISO)-1)) // note must be case INsensitive compare...
1839  {
1840  p1--;
1841  }
1842 
1843  if(p1 > pName) // found
1844  {
1845  strcpy(p1, "-*-*"); // this allows all of the code sets to be included (fastest method)
1846  }
1847 
1848 //#ifndef NO_DEBUG
1849 // ullTemp = WBGetTimeIndex();
1850 //#endif // NO_DEBUG
1851 
1852  pLocale = InternalCheckSetLocale();
1853 
1854 //#ifndef NO_DEBUG
1855 // WB_ERROR_PRINT("TEMPORARY: %s - setlocale took %ld micros\n", __FUNCTION__, (long)(WBGetTimeIndex() - ullTemp));
1856 // ullTemp = WBGetTimeIndex();
1857 //#endif // NO_DEBUG
1858 
1859  // NOTE: 'pDef' is owned by the font set. do NOT XFree it or modify its contents
1860 
1861  rVal = XCreateFontSet(pDisplay, pName, &ppMissing, &nMissing, &pDef); // 6-7 milliseconds!!!
1862 
1863 //#ifndef NO_DEBUG
1864 // WB_ERROR_PRINT("TEMPORARY: %s - XCreateFontSet took %ld micros\n", __FUNCTION__, (long)(WBGetTimeIndex() - ullTemp));
1865 // ullTemp = WBGetTimeIndex();
1866 //#endif // NO_DEBUG
1867 
1868  if(pLocale)
1869  {
1870 // WB_ERROR_PRINT("TEMPORARY: %s - setting locale back to \"%s\"\n", __FUNCTION__, pLocale);
1871 
1872  setlocale(LC_CTYPE, pLocale);
1873 
1874  WBFree(pLocale);
1875  pLocale = NULL;
1876  }
1877 // else
1878 // {
1879 // setlocale(LC_CTYPE, "C"); // will set things back to "the default" I hope
1880 // }
1881 
1882 
1883  // TODO: dump info?
1884 
1885 
1886  if(ppMissing || nMissing > 0)
1887  {
1888  if(ppMissing)
1889  {
1890  // int i1;
1891  //
1892  // WB_ERROR_PRINT("TEMPORARY: %s\n", __FUNCTION__);
1893  //
1894  // for(i1=0; i1 < nMissing; i1++)
1895  // {
1896  // WB_ERROR_PRINT(" %d : %s\n", i1, ppMissing[i1]);
1897  // }
1898 
1899  XFreeStringList(ppMissing);
1900  }
1901  else
1902  {
1903  WB_ERROR_PRINT("*BUG* %s - nMissing is %d\n", __FUNCTION__, nMissing);
1904  }
1905  }
1906 
1907  WBFree(pName);
1908  pName = NULL; // by convention to prevent re-use
1909 
1910  if(!rVal)
1911  {
1912  WB_ERROR_PRINT("%s - no result, returning NULL\n", __FUNCTION__);
1913  }
1914 //#ifndef NO_DEBUG
1915 // else
1916 // {
1917 // WBDumpFontSet(pDisplay, rVal);
1918 // }
1919 //#endif // NO_DEBUG
1920 
1921  return rVal;
1922 }
1923 
1924 
1925 XFontSet WBFontSetFromFontSingle(Display *pDisplay, const XFontStruct *pFont)
1926 {
1927 unsigned long lName;
1928 char *pName = NULL, *pDef = NULL;
1929 XFontSet rVal = None;
1930 char **ppMissing = NULL;
1931 int nMissing = 0;
1932 char *p1, *pLocale;
1933 
1934  // step 1: generate font string from XFontStruct
1935 
1936  if(!pFont)
1937  {
1938  pFont = WBGetDefaultFont();
1939  if(!pFont)
1940  {
1941  WB_ERROR_PRINT("%s - no font, returning NULL\n", __FUNCTION__);
1942  return NULL;
1943  }
1944  }
1945 
1946  if(XGetFontProperty((XFontStruct *)pFont, XA_FONT, &lName))
1947  {
1948  pName = WBGetAtomName(pDisplay ? pDisplay : WBGetDefaultDisplay(), (Atom)lName);
1949 
1950  if(!pName && pDisplay)
1951  {
1952  pName = WBGetAtomName(WBGetDefaultDisplay(), (Atom)lName);
1953  // NOTE: 'pName' is an editable WBAlloc'd pointer that's a copy of the atom name
1954  }
1955  }
1956 
1957  if(!pName)
1958  {
1959  WB_ERROR_PRINT("%s - no font name, returning NULL\n", __FUNCTION__);
1960  return NULL;
1961  }
1962 
1963  p1 = setlocale(LC_CTYPE, NULL); // get the current locale
1964 
1965  if(p1)
1966  {
1967  pLocale = WBCopyString(p1);
1968  }
1969  else
1970  {
1971  pLocale = NULL;
1972  }
1973 
1974  setlocale(LC_CTYPE, "C"); // set to 'C' locale, which gives me a single font set only that matches THIS one
1975 
1976  // NOTE: 'pDef' is owned by the font set. do NOT XFree it or modify its contents
1977 
1978  rVal = XCreateFontSet(pDisplay, pName, &ppMissing, &nMissing, &pDef); // 6-7 milliseconds!!!
1979 
1980  WB_ERROR_PRINT("TEMPORARY: %s - setting locale back to \"%s\"\n", __FUNCTION__, pLocale);
1981 
1982  if(pLocale)
1983  {
1984  setlocale(LC_CTYPE, pLocale);
1985  WBFree(pLocale);
1986  pLocale = NULL;
1987  }
1988 // else
1989 // {
1990 // setlocale(LC_ALL, "C"); // will set things back to "the default" I hope
1991 // }
1992 
1993 
1994  // TODO: dump info?
1995 
1996 
1997  if(ppMissing || nMissing > 0)
1998  {
1999  if(ppMissing)
2000  {
2001  XFreeStringList(ppMissing);
2002  }
2003  else
2004  {
2005  WB_ERROR_PRINT("*BUG* %s - nMissing is %d\n", __FUNCTION__, nMissing);
2006  }
2007  }
2008 
2009  WBFree(pName);
2010  pName = NULL; // by convention to prevent re-use
2011 
2012  if(!rVal)
2013  {
2014  WB_ERROR_PRINT("%s - no result, returning NULL\n", __FUNCTION__);
2015  }
2016 #ifndef NO_DEBUG
2017  else
2018  {
2019  WBDumpFontSet(pDisplay, rVal);
2020  }
2021 #endif // NO_DEBUG
2022 
2023  return rVal;
2024 }
2025 
2026 
2027 XFontStruct * WBFontFromFontSet(Display *pDisplay, XFontSet fontSet)
2028 {
2029 XFontStruct **ppFontStruct = NULL;
2030 char **ppFontNames = NULL;
2031 int i1, iN;
2032 XFontStruct *pRval = NULL;
2033 
2034 
2035  if(fontSet == None)
2036  {
2037  fontSet = WBGetDefaultFontSet(pDisplay);
2038 
2039  if(fontSet == None)
2040  {
2041  WB_ERROR_PRINT("ERROR: %s - no default font set available\n", __FUNCTION__);
2042  return 0;
2043  }
2044  }
2045 
2046  iN = XFontsOfFontSet(fontSet, &ppFontStruct, &ppFontNames);
2047 
2048  // get the first valid font struct and make a copy
2049 
2050  for(i1=0; i1 < iN; i1++)
2051  {
2052  if(ppFontStruct[i1])
2053  {
2054  pRval = WBCopyFont(ppFontStruct[i1]); // first one that's valid is my bail-out point
2055 
2056  if(pRval) // bail if it worked
2057  {
2058  break;
2059  }
2060  }
2061  }
2062 
2063  return pRval;
2064 }
2065 
2066 
2067 int WBTextWidth(XFontSet fontSet, const char *szText, int cbText)
2068 {
2069 int iLen, iRval;
2070 
2071 
2072  if(fontSet == None || !cbText || !szText || (cbText < 0 && !*szText))
2073  {
2074  WB_ERROR_PRINT("TEMPORARY: %s - returning zero (bad parameter)\n", __FUNCTION__);
2075  return 0;
2076  }
2077  else if(cbText < 0)
2078  {
2079  iLen = strlen(szText);
2080  }
2081  else
2082  {
2083  iLen = cbText;
2084  }
2085 
2086  iRval = WB_TEXT_ESCAPEMENT(fontSet, szText, iLen);
2087 
2088 // WB_ERROR_PRINT("TEMPORARY: %s - escapement for '%.*s' is %d\n", __FUNCTION__, iLen, szText, iRval);
2089 
2090 // if(iRval <= 0)
2091 // {
2092 // iLen = mblen(szUTF8, nLength); // width estimate
2093 // iLen = XTextWidth(pFont, " ", 1) * iLen;
2094 //
2095 // WB_ERROR_PRINT("%s WOULD BE returning %d, NOW returning %d\n", __FUNCTION__, iRval, iLen);
2096 // iRval = iLen;
2097 // }
2098 
2099  return iRval;
2100 }
2101 
2102 void WBTextExtent(XFontSet fontSet, const char *szText, int cbText, WB_EXTENT *pExtent)
2103 {
2104 XRectangle rct, rct2;
2105 int iLen;
2106 
2107 
2108  if(fontSet == None || !cbText || !szText || (cbText < 0 && !*szText))
2109  {
2110  WB_ERROR_PRINT("TEMPORARY: %s - returning zero (bad parameter)\n", __FUNCTION__);
2111  return;
2112  }
2113  else if(cbText < 0)
2114  {
2115  iLen = strlen(szText);
2116  }
2117  else
2118  {
2119  iLen = cbText;
2120  }
2121 
2122  memset(&rct2, 0, sizeof(rct2));
2123 
2125  WB_TEXT_EXTENTS(fontSet, szText, iLen, &rct, &rct2);
2127 
2128  pExtent->width = rct2.width;
2129  pExtent->height = rct2.height;
2130 }
2131 
2132 
2133 
2134 #ifndef NO_DEBUG
2135 
2136 static void WBDumpFontStruct(const XFontStruct *pFont)
2137 {
2138 int i1;
2139 
2140  typedef struct {
2141  XExtData *ext_data; /* hook for extension to hang data */
2142  Font fid; /* Font id for this font */
2143  unsigned direction; /* hint about the direction font is painted */
2144  unsigned min_char_or_byte2;/* first character */
2145  unsigned max_char_or_byte2;/* last character */
2146  unsigned min_byte1; /* first row that exists */
2147  unsigned max_byte1; /* last row that exists */
2148  Bool all_chars_exist; /* flag if all characters have nonzero size */
2149  unsigned default_char; /* char to print for undefined character */
2150  int n_properties; /* how many properties there are */
2151  XFontProp *properties; /* pointer to array of additional properties */
2152  XCharStruct min_bounds; /* minimum bounds over all existing char */
2153  XCharStruct max_bounds; /* maximum bounds over all existing char */
2154  XCharStruct *per_char; /* first_char to last_char information */
2155  int ascent; /* logical extent above baseline for spacing */
2156  int descent; /* logical decent below baseline for spacing */
2157  } XFontStruct;
2158 
2159 
2160  WB_WARN_PRINT("WBDumpFontStruct(%pH)\n", pFont);
2161  WB_WARN_PRINT(" ext_data = %pH\n"
2162  " fid = %d (%08xH)\n"
2163  " direction = %d\n"
2164  " min_char_or_byte2= %d\n"
2165  " max_char_or_byte2= %d\n"
2166  " min_byte1 = %d\n"
2167  " max_byte1 = %d\n"
2168  " all_chars_exist = %d\n"
2169  " default_char = %d\n"
2170  " n_properties = %d\n",
2171  pFont->ext_data,
2172  (int)pFont->fid, (int)pFont->fid,
2173  pFont->direction,
2174  pFont->min_char_or_byte2,
2175  pFont->max_char_or_byte2,
2176  pFont->min_byte1,
2177  pFont->max_byte1,
2178  pFont->all_chars_exist,
2179  pFont->default_char,
2180  pFont->n_properties);
2181 
2182  for(i1=0; i1 < pFont->n_properties; i1++)
2183  {
2184  char *p1 = WBGetAtomName(WBGetDefaultDisplay(), pFont->properties[i1].name);
2185  char *p2 = WBGetAtomName(WBGetDefaultDisplay(), (Atom)pFont->properties[i1].card32);
2186 
2187  WB_WARN_PRINT(" %5d %-20s = %ld (%08lxH) %s\n",
2188  (int)pFont->properties[i1].name,p1,
2189  pFont->properties[i1].card32,
2190  pFont->properties[i1].card32, p2);
2191 
2192  if(p1)
2193  {
2194  WBFree(p1);
2195  }
2196 
2197  if(p2)
2198  {
2199  WBFree(p2);
2200  }
2201  }
2202 
2203  WB_WARN_PRINT(" ascent = %d\n"
2204  " descent = %d\n",
2205  pFont->ascent,
2206  pFont->descent);
2207 }
2208 
2209 static void WBDumpMatchingFontNames(Display *pDisplay, const char *szFontName)
2210 {
2211 char **ppNames;
2212 int i1, iCount;
2213 XFontStruct *pFSInfo;
2214 
2215  ppNames = XListFontsWithInfo(pDisplay, szFontName, 8192, &iCount, &pFSInfo);
2216 
2217  if(ppNames)
2218  {
2219  WBDebugPrint("%s - fonts matching \"%s\"\n", __FUNCTION__, szFontName);
2220 
2221  for(i1=0; i1 < iCount; i1++)
2222  {
2223  WBDebugPrint(" %4d: %s\n", i1, ppNames[i1]);
2224  }
2225  }
2226  else
2227  {
2228  WBDebugPrint("%s - NO fonts match \"%s\"\n", __FUNCTION__, szFontName);
2229 
2230  }
2231 
2232  if(ppNames)
2233  {
2234  XFreeFontInfo(ppNames, pFSInfo, iCount);
2235  }
2236 }
2237 
2238 static void WBDumpFontSet(Display *pDisplay, XFontSet fontSet)
2239 {
2240 XFontStruct **ppFontStruct = NULL;
2241 char **ppFontNames = NULL;
2242 int i1, iN;
2243 
2244  iN = XFontsOfFontSet(fontSet, &ppFontStruct, &ppFontNames);
2245 
2246  WBDebugPrint("%s - font set contains %d fonts\n", __FUNCTION__, iN);
2247  WBDebugPrint("font set locale \"%s\"\n", XLocaleOfFontSet(fontSet));
2248 
2249  WBDebugPrint("base name: \"%s\"\n\n", XBaseFontNameListOfFontSet(fontSet));
2250 
2251  for(i1=0; i1 < iN; i1++)
2252  {
2253  WBDebugPrint(" %4d: %s\n", i1, ppFontNames[i1]);
2254  }
2255 }
2256 
2257 
2258 #endif // NO_DEBUG
2259 
XFontStruct * WBFontFromFontSet(Display *pDisplay, XFontSet fontSet)
Creates an &#39;XFontStruct&#39; from the first font assigned to a Font Set.
Definition: font_helper.c:2027
XFontStruct * WBLoadFont(Display *pDisplay, const char *szFontName, int iFontSize, int iFlags)
load a font based on a font name, size, and font flags
Definition: font_helper.c:858
font size is in &#39;twips&#39; (when font size > 0)
Definition: font_helper.h:431
internal wrapper struct for &#39;extent&#39; definition
font size is in &#39;points&#39; (when font size > 0)
Definition: font_helper.h:430
&#39;window helper&#39; main header file for the X11workbench Toolkit API
static __inline__ Display * WBGetDefaultDisplay(void)
Returns the default Display.
static __inline__ unsigned int WBGetDebugLevel(void)
Returns the current debug level assigned by WBSetDebugLevel.
Definition: debug_helper.h:124
#define WB_DEBUG_PRINT(L,...)
Preferred method of implementing conditional debug output.
Definition: debug_helper.h:299
Utilities for copying and drawing text, determining text extents, and so on.
bold font weight (mutually exclusive0
Definition: font_helper.h:439
condensed (alternate to &#39;fixed&#39;)
Definition: font_helper.h:411
XFontStruct * WBLoadModifyFont(Display *pDisplay, const XFontStruct *pOriginal, int iFontSize, int iFlags)
load and modify a font according to the specified size and flags
Definition: font_helper.c:1350
&#39;oblique&#39; slant (mutually exclusive)
Definition: font_helper.h:445
int WBTextWidth(XFontSet fontSet, const char *szText, int cbText)
Obtain the pixel width of specified text for a specified XFontSet.
Definition: font_helper.c:2067
semicondensed width (mutually exclusive)
Definition: font_helper.h:451
#define WB_TEXT_ESCAPEMENT
Definition: font_helper.h:95
XFontSet WBFontSetFromFont(Display *pDisplay, const XFontStruct *pFont)
Creates an &#39;XFontSet&#39; from an XFontStruct for a given display.
Definition: font_helper.c:1750
&#39;Any&#39; pitch (default, zero)
Definition: font_helper.h:412
void WBTextExtent(XFontSet fontSet, const char *szText, int cbText, WB_EXTENT *pExtent)
Obtain the pixel extent of specified text for a specified XFontSet.
Definition: font_helper.c:2102
XFontSet WBFontSetFromFontSingle(Display *pDisplay, const XFontStruct *pFont)
Creates an &#39;XFontSet&#39; from an XFontStruct for a given display, with only a single font in the set...
Definition: font_helper.c:1925
font weight bit mask
Definition: font_helper.h:442
void * WBReAlloc(void *pBuf, int nNewSize)
High performance memory sub-allocator &#39;re-allocate&#39;.
force fixed pitch
Definition: font_helper.h:409
&#39;pitch mask&#39;
Definition: font_helper.h:413
medium font weight (mutually exclusive0
Definition: font_helper.h:437
unsigned int width
the &#39;width&#39; value of the extent.
&#39;regular&#39; slant (mutually exclusive)
Definition: font_helper.h:444
regular font weight (mutually exclusive0
Definition: font_helper.h:436
Atom aAVERAGE_WIDTH
Atoms for fonts - Average Character Width.
font size is in &#39;pixels&#39; (when font size > 0)
Definition: font_helper.h:429
void * WBAlloc(int nSize)
High performance memory sub-allocator &#39;allocate&#39;.
#define END_XCALL_DEBUG_WRAPPER
wrapper macro for calls into the X11 library. This macro follows the call(s)
XFontSet WBCopyModifyFontSet(Display *pDisplay, XFontSet fsOrig, int iFontSize, int iFlags)
copy and modify a font set according to the specified size and flags
Definition: font_helper.c:1441
int WBFontSetHeight(Display *pDisplay, XFontSet fontSet)
Get the maximum character height from a font set.
Definition: font_helper.c:1178
int WBFontSetAvgCharWidth(Display *pDisplay, XFontSet fontSet)
Get the average character width for a font set.
Definition: font_helper.c:1227
#define WB_ERROR_PRINT(...)
Preferred method of implementing an &#39;error level&#39; debug message for all subsystems.
Definition: debug_helper.h:356
normal width (mutually exclusive)
Definition: font_helper.h:450
demi-bold font weight (mutually exclusive0
Definition: font_helper.h:438
void WBFree(void *pBuf)
High performance memory sub-allocator &#39;free&#39;.
Any font weight specification (mutually exclusive)
Definition: font_helper.h:435
&#39;size mask&#39; for font size > 0
Definition: font_helper.h:433
force sans-serif
Definition: font_helper.h:415
&#39;italic&#39; slant (mutually exclusive)
Definition: font_helper.h:446
force serif (i.e. &#39;not sans&#39;)
Definition: font_helper.h:416
int WBFontSetDescent(Display *pDisplay, XFontSet fontSet)
Get the maximum character descent from a font set.
Definition: font_helper.c:1094
int WBFontAvgCharWidth(Display *pDisplay, const XFontStruct *pFont)
Get the average character width for a font.
Definition: font_helper.c:998
int WBFontSetAscent(Display *pDisplay, XFontSet fontSet)
Get the maximum character ascent from a font set.
Definition: font_helper.c:1136
XFontStruct * WBGetDefaultFont(void)
Returns a pointer to the default font&#39;s XFontStruct.
XCharStruct WBFontSetMaxBounds(Display *pDisplay, XFontSet fontSet)
Get a &#39;maximized&#39; copy of the &#39;max_bounds&#39; member for the font set.
Definition: font_helper.c:1287
#define BEGIN_XCALL_DEBUG_WRAPPER
wrapper macro for calls into the X11 library. This macro precedes the call(s)
&#39;default&#39; slant (zero; mutually exclusive; may return an italic or oblique font)
Definition: font_helper.h:447
void WBDumpFontInfo(const char *szFontName)
Dump debug information about fonts according to pSpec.
Definition: font_helper.c:415
char * WBGetAtomName(Display *pDisplay, Atom aAtom)
Lookup and/or allocate an internal Atom for a named string.
void WBDebugPrint(const char *pFmt,...) __attribute__((format(printf
conditional debug message output
#define WB_TEXT_EXTENTS
Definition: font_helper.h:94
char * WBCopyString(const char *pSrc)
A simple utility that returns a WBAlloc() copy of a 0-byte terminated string.
unsigned int height
the &#39;height&#39; value of the extent.
&#39;Any&#39; width (zero; mutually exclusive)
Definition: font_helper.h:453
#define WB_IF_DEBUG_LEVEL(L)
Preferred method of implementing conditional debug &#39;if block&#39; code.
Definition: debug_helper.h:339
&#39;Any&#39; style (default, zero)
Definition: font_helper.h:419
XFontStruct * WBCopyFont(XFontStruct *pOldFont)
make a copy of an existing font (best when assigning to a window)
Definition: font_helper.c:97
#define WB_WARN_PRINT(...)
Preferred method of implementing a &#39;warning level&#39; debug message for all subsystems.
Definition: debug_helper.h:349
force variable pitch
Definition: font_helper.h:410
XFontSet WBGetDefaultFontSet(Display *pDisplay)
Returns an XFontSet for the default font.
void WBCatString(char **ppDest, const char *pSrc)
A simple utility that concatenates a string onto the end of a 0-byte terminated WBAlloc() string...