]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkfont-x11.c
Call setlocale (LC_ALL, ""). (#60606)
[~andy/gtk] / gdk / x11 / gdkfont-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <X11/Xlib.h>
28 #include <X11/Xos.h>
29
30 #include <pango/pangox.h>
31
32 #include "gdkfont.h"
33 #include "gdkprivate-x11.h"
34
35 typedef struct _GdkFontPrivateX        GdkFontPrivateX;
36
37 struct _GdkFontPrivateX
38 {
39   GdkFontPrivate base;
40   /* XFontStruct *xfont; */
41   /* generic pointer point to XFontStruct or XFontSet */
42   gpointer xfont;
43   Display *xdisplay;
44
45   GSList *names;
46 };
47
48 static GHashTable *font_name_hash = NULL;
49 static GHashTable *fontset_name_hash = NULL;
50
51 static void
52 gdk_font_hash_insert (GdkFontType type, GdkFont *font, const gchar *font_name)
53 {
54   GdkFontPrivateX *private = (GdkFontPrivateX *)font;
55   GHashTable **hashp = (type == GDK_FONT_FONT) ?
56     &font_name_hash : &fontset_name_hash;
57
58   if (!*hashp)
59     *hashp = g_hash_table_new (g_str_hash, g_str_equal);
60
61   private->names = g_slist_prepend (private->names, g_strdup (font_name));
62   g_hash_table_insert (*hashp, private->names->data, font);
63 }
64
65 static void
66 gdk_font_hash_remove (GdkFontType type, GdkFont *font)
67 {
68   GdkFontPrivateX *private = (GdkFontPrivateX *)font;
69   GSList *tmp_list;
70   GHashTable *hash = (type == GDK_FONT_FONT) ?
71     font_name_hash : fontset_name_hash;
72
73   tmp_list = private->names;
74   while (tmp_list)
75     {
76       g_hash_table_remove (hash, tmp_list->data);
77       g_free (tmp_list->data);
78       
79       tmp_list = tmp_list->next;
80     }
81
82   g_slist_free (private->names);
83   private->names = NULL;
84 }
85
86 static GdkFont *
87 gdk_font_hash_lookup (GdkFontType type, const gchar *font_name)
88 {
89   GdkFont *result;
90   GHashTable *hash = (type == GDK_FONT_FONT) ?
91     font_name_hash : fontset_name_hash;
92
93   if (!hash)
94     return NULL;
95   else
96     {
97       result = g_hash_table_lookup (hash, font_name);
98       if (result)
99         gdk_font_ref (result);
100       
101       return result;
102     }
103 }
104
105 GdkFont*
106 gdk_font_load (const gchar *font_name)
107 {
108   GdkFont *font;
109   GdkFontPrivateX *private;
110   XFontStruct *xfont;
111
112   g_return_val_if_fail (font_name != NULL, NULL);
113
114   font = gdk_font_hash_lookup (GDK_FONT_FONT, font_name);
115   if (font)
116     return font;
117
118   xfont = XLoadQueryFont (gdk_display, font_name);
119   if (xfont == NULL)
120     return NULL;
121
122   font = gdk_font_lookup (xfont->fid);
123   if (font != NULL)
124     {
125       private = (GdkFontPrivateX *) font;
126       if (xfont != private->xfont)
127         XFreeFont (gdk_display, xfont);
128
129       gdk_font_ref (font);
130     }
131   else
132     {
133       private = g_new (GdkFontPrivateX, 1);
134       private->xdisplay = gdk_display;
135       private->xfont = xfont;
136       private->base.ref_count = 1;
137       private->names = NULL;
138  
139       font = (GdkFont*) private;
140       font->type = GDK_FONT_FONT;
141       font->ascent =  xfont->ascent;
142       font->descent = xfont->descent;
143
144       gdk_xid_table_insert (&xfont->fid, font);
145     }
146
147   gdk_font_hash_insert (GDK_FONT_FONT, font, font_name);
148
149   return font;
150 }
151
152 static char *
153 gdk_font_charset_for_locale (void)
154 {
155   static char *charset_map[][2] = {
156     { "ANSI_X3.4-1968", "iso8859-1" },
157     { "US-ASCII",   "iso8859-1" },
158     { "ISO-8859-1", "iso8859-1" },
159     { "ISO-8859-2", "iso8859-2" },
160     { "ISO-8859-3", "iso8859-3" },
161     { "ISO-8859-4", "iso8859-4" },
162     { "ISO-8859-5", "iso8859-5" },
163     { "ISO-8859-6", "iso8859-6" },
164     { "ISO-8859-7", "iso8859-7" },
165     { "ISO-8859-8", "iso8859-8" },
166     { "ISO-8859-9", "iso8859-9" },
167     { "UTF-8",      "iso8859-1" }
168   };
169
170   const char *codeset;
171   char *result = NULL;
172   int i;
173
174   g_get_charset (&codeset);
175   
176   for (i=0; i < G_N_ELEMENTS (charset_map); i++)
177     if (strcmp (charset_map[i][0], codeset) == 0)
178       {
179         result = charset_map[i][1];
180         break;
181       }
182
183   if (result)
184     return g_strdup (result);
185   else
186     return g_strdup ("iso8859-1");
187 };
188
189 /**
190  * gdk_font_from_description:
191  * @font_desc: a #PangoFontDescription.
192  * 
193  * Load a #GdkFont based on a Pango font description. This font will
194  * only be an approximation of the Pango font, and
195  * internationalization will not be handled correctly. This function
196  * should only be used for legacy code that cannot be easily converted
197  * to use Pango. Using Pango directly will produce better results.
198  * 
199  * Return value: the newly loaded font, or %NULL if the font
200  * cannot be loaded.
201  **/
202 GdkFont*
203 gdk_font_from_description (PangoFontDescription *font_desc)
204 {
205   PangoFontMap *font_map;
206   PangoFont *font;
207   GdkFont *result = NULL;
208
209   g_return_val_if_fail (font_desc != NULL, NULL);
210
211   font_map = pango_x_font_map_for_display (GDK_DISPLAY ());
212   font = pango_font_map_load_font (font_map, font_desc);
213
214   if (font)
215     {
216       gchar *charset = gdk_font_charset_for_locale ();
217       gint n_subfonts;
218       PangoXSubfont *subfont_ids;
219       gint *subfont_charsets;
220
221       n_subfonts = pango_x_list_subfonts (font, &charset, 1,
222                                           &subfont_ids, &subfont_charsets);
223       if (n_subfonts > 0)
224         {
225           gchar *xlfd = pango_x_font_subfont_xlfd (font, subfont_ids[0]);
226           result = gdk_font_load (xlfd);
227
228           g_free (xlfd);
229         }
230
231       g_free (subfont_ids);
232       g_free (subfont_charsets);
233
234       g_free (charset);
235       g_object_unref (G_OBJECT (font));
236     }
237
238   return result;
239 }
240
241 GdkFont*
242 gdk_fontset_load (const gchar *fontset_name)
243 {
244   GdkFont *font;
245   GdkFontPrivateX *private;
246   XFontSet fontset;
247   gint  missing_charset_count;
248   gchar **missing_charset_list;
249   gchar *def_string;
250
251   font = gdk_font_hash_lookup (GDK_FONT_FONTSET, fontset_name);
252   if (font)
253     return font;
254
255   private = g_new (GdkFontPrivateX, 1);
256   font = (GdkFont*) private;
257
258   private->xdisplay = gdk_display;
259   fontset = XCreateFontSet (gdk_display, fontset_name,
260                             &missing_charset_list, &missing_charset_count,
261                             &def_string);
262
263   if (missing_charset_count)
264     {
265       gint i;
266       g_warning ("Missing charsets in FontSet creation\n");
267       for (i=0;i<missing_charset_count;i++)
268         g_warning ("    %s\n", missing_charset_list[i]);
269       XFreeStringList (missing_charset_list);
270     }
271
272   private->base.ref_count = 1;
273
274   if (!fontset)
275     {
276       g_free (font);
277       return NULL;
278     }
279   else
280     {
281       gint num_fonts;
282       gint i;
283       XFontStruct **font_structs;
284       gchar **font_names;
285       
286       private->xfont = fontset;
287       font->type = GDK_FONT_FONTSET;
288       num_fonts = XFontsOfFontSet (fontset, &font_structs, &font_names);
289
290       font->ascent = font->descent = 0;
291       
292       for (i = 0; i < num_fonts; i++)
293         {
294           font->ascent = MAX (font->ascent, font_structs[i]->ascent);
295           font->descent = MAX (font->descent, font_structs[i]->descent);
296         }
297
298       private->names = NULL;
299       gdk_font_hash_insert (GDK_FONT_FONTSET, font, fontset_name);
300       
301       return font;
302     }
303 }
304
305 void
306 _gdk_font_destroy (GdkFont *font)
307 {
308   GdkFontPrivateX *private = (GdkFontPrivateX *)font;
309   
310   gdk_font_hash_remove (font->type, font);
311       
312   switch (font->type)
313     {
314     case GDK_FONT_FONT:
315       gdk_xid_table_remove (((XFontStruct *) private->xfont)->fid);
316       XFreeFont (private->xdisplay, (XFontStruct *) private->xfont);
317       break;
318     case GDK_FONT_FONTSET:
319       XFreeFontSet (private->xdisplay, (XFontSet) private->xfont);
320       break;
321     default:
322       g_error ("unknown font type.");
323       break;
324     }
325   g_free (font);
326 }
327
328 gint
329 _gdk_font_strlen (GdkFont     *font,
330                   const gchar *str)
331 {
332   GdkFontPrivateX *font_private;
333   gint length = 0;
334
335   g_return_val_if_fail (font != NULL, -1);
336   g_return_val_if_fail (str != NULL, -1);
337
338   font_private = (GdkFontPrivateX*) font;
339
340   if (font->type == GDK_FONT_FONT)
341     {
342       XFontStruct *xfont = (XFontStruct *) font_private->xfont;
343       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
344         {
345           length = strlen (str);
346         }
347       else
348         {
349           guint16 *string_2b = (guint16 *)str;
350             
351           while (*(string_2b++))
352             length++;
353         }
354     }
355   else if (font->type == GDK_FONT_FONTSET)
356     {
357       length = strlen (str);
358     }
359   else
360     g_error("undefined font type\n");
361
362   return length;
363 }
364
365 gint
366 gdk_font_id (const GdkFont *font)
367 {
368   const GdkFontPrivateX *font_private;
369
370   g_return_val_if_fail (font != NULL, 0);
371
372   font_private = (const GdkFontPrivateX*) font;
373
374   if (font->type == GDK_FONT_FONT)
375     {
376       return ((XFontStruct *) font_private->xfont)->fid;
377     }
378   else
379     {
380       return 0;
381     }
382 }
383
384 gboolean
385 gdk_font_equal (const GdkFont *fonta,
386                 const GdkFont *fontb)
387 {
388   const GdkFontPrivateX *privatea;
389   const GdkFontPrivateX *privateb;
390
391   g_return_val_if_fail (fonta != NULL, FALSE);
392   g_return_val_if_fail (fontb != NULL, FALSE);
393
394   privatea = (const GdkFontPrivateX*) fonta;
395   privateb = (const GdkFontPrivateX*) fontb;
396
397   if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
398     {
399       return (((XFontStruct *) privatea->xfont)->fid ==
400               ((XFontStruct *) privateb->xfont)->fid);
401     }
402   else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET)
403     {
404       gchar *namea, *nameb;
405
406       namea = XBaseFontNameListOfFontSet((XFontSet) privatea->xfont);
407       nameb = XBaseFontNameListOfFontSet((XFontSet) privateb->xfont);
408       
409       return (strcmp(namea, nameb) == 0);
410     }
411   else
412     /* fontset != font */
413     return 0;
414 }
415
416 gint
417 gdk_text_width (GdkFont      *font,
418                 const gchar  *text,
419                 gint          text_length)
420 {
421   GdkFontPrivateX *private;
422   gint width;
423   XFontStruct *xfont;
424   XFontSet fontset;
425
426   g_return_val_if_fail (font != NULL, -1);
427   g_return_val_if_fail (text != NULL, -1);
428
429   private = (GdkFontPrivateX*) font;
430
431   switch (font->type)
432     {
433     case GDK_FONT_FONT:
434       xfont = (XFontStruct *) private->xfont;
435       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
436         {
437           width = XTextWidth (xfont, text, text_length);
438         }
439       else
440         {
441           width = XTextWidth16 (xfont, (XChar2b *) text, text_length / 2);
442         }
443       break;
444     case GDK_FONT_FONTSET:
445       fontset = (XFontSet) private->xfont;
446       width = XmbTextEscapement (fontset, text, text_length);
447       break;
448     default:
449       width = 0;
450     }
451   return width;
452 }
453
454 gint
455 gdk_text_width_wc (GdkFont        *font,
456                    const GdkWChar *text,
457                    gint            text_length)
458 {
459   GdkFontPrivateX *private;
460   gint width;
461   XFontStruct *xfont;
462   XFontSet fontset;
463
464   g_return_val_if_fail (font != NULL, -1);
465   g_return_val_if_fail (text != NULL, -1);
466
467   private = (GdkFontPrivateX*) font;
468
469   switch (font->type)
470     {
471     case GDK_FONT_FONT:
472       xfont = (XFontStruct *) private->xfont;
473       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
474         {
475           gchar *text_8bit;
476           gint i;
477           text_8bit = g_new (gchar, text_length);
478           for (i=0; i<text_length; i++) text_8bit[i] = text[i];
479           width = XTextWidth (xfont, text_8bit, text_length);
480           g_free (text_8bit);
481         }
482       else
483         {
484           width = 0;
485         }
486       break;
487     case GDK_FONT_FONTSET:
488       if (sizeof(GdkWChar) == sizeof(wchar_t))
489         {
490           fontset = (XFontSet) private->xfont;
491           width = XwcTextEscapement (fontset, (wchar_t *)text, text_length);
492         }
493       else
494         {
495           wchar_t *text_wchar;
496           gint i;
497           fontset = (XFontSet) private->xfont;
498           text_wchar = g_new(wchar_t, text_length);
499           for (i=0; i<text_length; i++) text_wchar[i] = text[i];
500           width = XwcTextEscapement (fontset, text_wchar, text_length);
501           g_free (text_wchar);
502         }
503       break;
504     default:
505       width = 0;
506     }
507   return width;
508 }
509
510 void
511 gdk_text_extents (GdkFont     *font,
512                   const gchar *text,
513                   gint         text_length,
514                   gint        *lbearing,
515                   gint        *rbearing,
516                   gint        *width,
517                   gint        *ascent,
518                   gint        *descent)
519 {
520   GdkFontPrivateX *private;
521   XCharStruct overall;
522   XFontStruct *xfont;
523   XFontSet    fontset;
524   XRectangle  ink, logical;
525   int direction;
526   int font_ascent;
527   int font_descent;
528
529   g_return_if_fail (font != NULL);
530   g_return_if_fail (text != NULL);
531
532   private = (GdkFontPrivateX*) font;
533
534   switch (font->type)
535     {
536     case GDK_FONT_FONT:
537       xfont = (XFontStruct *) private->xfont;
538       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
539         {
540           XTextExtents (xfont, text, text_length,
541                         &direction, &font_ascent, &font_descent,
542                         &overall);
543         }
544       else
545         {
546           XTextExtents16 (xfont, (XChar2b *) text, text_length / 2,
547                           &direction, &font_ascent, &font_descent,
548                           &overall);
549         }
550       if (lbearing)
551         *lbearing = overall.lbearing;
552       if (rbearing)
553         *rbearing = overall.rbearing;
554       if (width)
555         *width = overall.width;
556       if (ascent)
557         *ascent = overall.ascent;
558       if (descent)
559         *descent = overall.descent;
560       break;
561     case GDK_FONT_FONTSET:
562       fontset = (XFontSet) private->xfont;
563       XmbTextExtents (fontset, text, text_length, &ink, &logical);
564       if (lbearing)
565         *lbearing = ink.x;
566       if (rbearing)
567         *rbearing = ink.x + ink.width;
568       if (width)
569         *width = logical.width;
570       if (ascent)
571         *ascent = -ink.y;
572       if (descent)
573         *descent = ink.y + ink.height;
574       break;
575     }
576
577 }
578
579 void
580 gdk_text_extents_wc (GdkFont        *font,
581                      const GdkWChar *text,
582                      gint            text_length,
583                      gint           *lbearing,
584                      gint           *rbearing,
585                      gint           *width,
586                      gint           *ascent,
587                      gint           *descent)
588 {
589   GdkFontPrivateX *private;
590   XCharStruct overall;
591   XFontStruct *xfont;
592   XFontSet    fontset;
593   XRectangle  ink, logical;
594   int direction;
595   int font_ascent;
596   int font_descent;
597
598   g_return_if_fail (font != NULL);
599   g_return_if_fail (text != NULL);
600
601   private = (GdkFontPrivateX*) font;
602
603   switch (font->type)
604     {
605     case GDK_FONT_FONT:
606       {
607         gchar *text_8bit;
608         gint i;
609
610         xfont = (XFontStruct *) private->xfont;
611         g_return_if_fail ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0));
612
613         text_8bit = g_new (gchar, text_length);
614         for (i=0; i<text_length; i++) 
615           text_8bit[i] = text[i];
616
617         XTextExtents (xfont, text_8bit, text_length,
618                       &direction, &font_ascent, &font_descent,
619                       &overall);
620         g_free (text_8bit);
621         
622         if (lbearing)
623           *lbearing = overall.lbearing;
624         if (rbearing)
625           *rbearing = overall.rbearing;
626         if (width)
627           *width = overall.width;
628         if (ascent)
629           *ascent = overall.ascent;
630         if (descent)
631           *descent = overall.descent;
632         break;
633       }
634     case GDK_FONT_FONTSET:
635       fontset = (XFontSet) private->xfont;
636
637       if (sizeof(GdkWChar) == sizeof(wchar_t))
638         XwcTextExtents (fontset, (wchar_t *)text, text_length, &ink, &logical);
639       else
640         {
641           wchar_t *text_wchar;
642           gint i;
643           
644           text_wchar = g_new (wchar_t, text_length);
645           for (i = 0; i < text_length; i++)
646             text_wchar[i] = text[i];
647           XwcTextExtents (fontset, text_wchar, text_length, &ink, &logical);
648           g_free (text_wchar);
649         }
650       if (lbearing)
651         *lbearing = ink.x;
652       if (rbearing)
653         *rbearing = ink.x + ink.width;
654       if (width)
655         *width = logical.width;
656       if (ascent)
657         *ascent = -ink.y;
658       if (descent)
659         *descent = ink.y + ink.height;
660       break;
661     }
662
663 }
664
665 Display *
666 gdk_x11_font_get_xdisplay (GdkFont *font)
667 {
668   g_return_val_if_fail (font != NULL, NULL);
669
670   return ((GdkFontPrivateX *)font)->xdisplay;
671 }
672
673 gpointer
674 gdk_x11_font_get_xfont (GdkFont *font)
675 {
676   g_return_val_if_fail (font != NULL, NULL);
677
678   return ((GdkFontPrivateX *)font)->xfont;
679 }
680
681 /**
682  * gdk_x11_font_get_name:
683  * @font: a #GdkFont.
684  * 
685  * Return the X Logical Font Description (for font->type == GDK_FONT_FONT)
686  * or comma separated list of XLFDs (for font->type == GDK_FONT_FONTSET)
687  * that was used to load the font. If the same font was loaded
688  * via multiple names, which name is returned is undefined.
689  * 
690  * Return value: the name of the font. This string is owned
691  *   by GDK and must not be modified or freed.
692  **/
693 G_CONST_RETURN char *
694 gdk_x11_font_get_name (GdkFont *font)
695 {
696   GdkFontPrivateX *private = (GdkFontPrivateX *)font;
697
698   g_return_val_if_fail (font != NULL, NULL);
699
700   g_assert (private->names);
701
702   return private->names->data;
703 }
704