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