]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkfont-x11.c
Use g_get_charset() instead of g_get_codeset().
[~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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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-1999.  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 static GHashTable *font_name_hash = NULL;
36 static GHashTable *fontset_name_hash = NULL;
37
38 static void
39 gdk_font_hash_insert (GdkFontType type, GdkFont *font, const gchar *font_name)
40 {
41   GdkFontPrivateX *private = (GdkFontPrivateX *)font;
42   GHashTable **hashp = (type == GDK_FONT_FONT) ?
43     &font_name_hash : &fontset_name_hash;
44
45   if (!*hashp)
46     *hashp = g_hash_table_new (g_str_hash, g_str_equal);
47
48   private->names = g_slist_prepend (private->names, g_strdup (font_name));
49   g_hash_table_insert (*hashp, private->names->data, font);
50 }
51
52 static void
53 gdk_font_hash_remove (GdkFontType type, GdkFont *font)
54 {
55   GdkFontPrivateX *private = (GdkFontPrivateX *)font;
56   GSList *tmp_list;
57   GHashTable *hash = (type == GDK_FONT_FONT) ?
58     font_name_hash : fontset_name_hash;
59
60   tmp_list = private->names;
61   while (tmp_list)
62     {
63       g_hash_table_remove (hash, tmp_list->data);
64       g_free (tmp_list->data);
65       
66       tmp_list = tmp_list->next;
67     }
68
69   g_slist_free (private->names);
70   private->names = NULL;
71 }
72
73 static GdkFont *
74 gdk_font_hash_lookup (GdkFontType type, const gchar *font_name)
75 {
76   GdkFont *result;
77   GHashTable *hash = (type == GDK_FONT_FONT) ?
78     font_name_hash : fontset_name_hash;
79
80   if (!hash)
81     return NULL;
82   else
83     {
84       result = g_hash_table_lookup (hash, font_name);
85       if (result)
86         gdk_font_ref (result);
87       
88       return result;
89     }
90 }
91
92 GdkFont*
93 gdk_font_load (const gchar *font_name)
94 {
95   GdkFont *font;
96   GdkFontPrivateX *private;
97   XFontStruct *xfont;
98
99   g_return_val_if_fail (font_name != NULL, NULL);
100
101   font = gdk_font_hash_lookup (GDK_FONT_FONT, font_name);
102   if (font)
103     return font;
104
105   xfont = XLoadQueryFont (gdk_display, font_name);
106   if (xfont == NULL)
107     return NULL;
108
109   font = gdk_font_lookup (xfont->fid);
110   if (font != NULL)
111     {
112       private = (GdkFontPrivateX *) font;
113       if (xfont != private->xfont)
114         XFreeFont (gdk_display, xfont);
115
116       gdk_font_ref (font);
117     }
118   else
119     {
120       private = g_new (GdkFontPrivateX, 1);
121       private->xdisplay = gdk_display;
122       private->xfont = xfont;
123       private->base.ref_count = 1;
124       private->names = NULL;
125  
126       font = (GdkFont*) private;
127       font->type = GDK_FONT_FONT;
128       font->ascent =  xfont->ascent;
129       font->descent = xfont->descent;
130
131       gdk_xid_table_insert (&xfont->fid, font);
132     }
133
134   gdk_font_hash_insert (GDK_FONT_FONT, font, font_name);
135
136   return font;
137 }
138
139 static char *
140 gdk_font_charset_for_locale ()
141 {
142   static char *charset_map[][2] = {
143     { "ANSI_X3.4-1968", "iso8859-1" },
144     { "ISO-8859-1", "iso8859-1" },
145     { "ISO-8859-2", "iso8859-2" },
146     { "ISO-8859-3", "iso8859-3" },
147     { "ISO-8859-4", "iso8859-4" },
148     { "ISO-8859-5", "iso8859-5" },
149     { "ISO-8859-6", "iso8859-6" },
150     { "ISO-8859-7", "iso8859-7" },
151     { "ISO-8859-8", "iso8859-8" },
152     { "ISO-8859-9", "iso8859-9" },
153     { "UTF-8", "iso8859-1" }
154   };
155
156   char *codeset;
157   char *result = NULL;
158   int i;
159
160   g_get_charset (&codeset);
161   
162   for (i=0; i < G_N_ELEMENTS (charset_map); i++)
163     if (strcmp (charset_map[i][0], codeset) == 0)
164       {
165         result = charset_map[i][1];
166         break;
167       }
168
169   if (result)
170     return g_strdup (result);
171   else
172     return g_strdup ("iso-8859-1");
173 };
174
175 /**
176  * gdk_font_from_description:
177  * @font_desc: a #PangoFontDescription.
178  * 
179  * Load a #GdkFont based on a Pango font description. This font will
180  * only be an approximation of the Pango font, and
181  * internationalization will not be handled correctly. This function
182  * should only be used for legacy code that cannot be easily converted
183  * to use Pango. Using Pango directly will produce better results.
184  * 
185  * Return value: the newly loaded font, or %NULL if the font
186  * cannot be loaded.
187  **/
188 GdkFont*
189 gdk_font_from_description (PangoFontDescription *font_desc)
190 {
191   PangoFontMap *font_map;
192   PangoFont *font;
193   GdkFont *result = NULL;
194
195   g_return_val_if_fail (font_desc != NULL, NULL);
196
197   font_map = pango_x_font_map_for_display (GDK_DISPLAY ());
198   font = pango_font_map_load_font (font_map, font_desc);
199
200   if (font)
201     {
202       gchar *charset = gdk_font_charset_for_locale ();
203       gint n_subfonts;
204       PangoXSubfont *subfont_ids;
205       gint *subfont_charsets;
206
207       n_subfonts = pango_x_list_subfonts (font, &charset, 1,
208                                           &subfont_ids, &subfont_charsets);
209       if (n_subfonts > 0)
210         {
211           gchar *xlfd = pango_x_font_subfont_xlfd (font, subfont_ids[0]);
212           result = gdk_font_load (xlfd);
213
214           g_free (xlfd);
215         }
216
217       g_free (subfont_ids);
218       g_free (subfont_charsets);
219
220       g_free (charset);
221       g_object_unref (G_OBJECT (font));
222     }
223
224   return result;
225 }
226
227 GdkFont*
228 gdk_fontset_load (const gchar *fontset_name)
229 {
230   GdkFont *font;
231   GdkFontPrivateX *private;
232   XFontSet fontset;
233   gint  missing_charset_count;
234   gchar **missing_charset_list;
235   gchar *def_string;
236
237   font = gdk_font_hash_lookup (GDK_FONT_FONTSET, fontset_name);
238   if (font)
239     return font;
240
241   private = g_new (GdkFontPrivateX, 1);
242   font = (GdkFont*) private;
243
244   private->xdisplay = gdk_display;
245   fontset = XCreateFontSet (gdk_display, fontset_name,
246                             &missing_charset_list, &missing_charset_count,
247                             &def_string);
248
249   if (missing_charset_count)
250     {
251       gint i;
252       g_warning ("Missing charsets in FontSet creation\n");
253       for (i=0;i<missing_charset_count;i++)
254         g_warning ("    %s\n", missing_charset_list[i]);
255       XFreeStringList (missing_charset_list);
256     }
257
258   private->base.ref_count = 1;
259
260   if (!fontset)
261     {
262       g_free (font);
263       return NULL;
264     }
265   else
266     {
267       gint num_fonts;
268       gint i;
269       XFontStruct **font_structs;
270       gchar **font_names;
271       
272       private->xfont = fontset;
273       font->type = GDK_FONT_FONTSET;
274       num_fonts = XFontsOfFontSet (fontset, &font_structs, &font_names);
275
276       font->ascent = font->descent = 0;
277       
278       for (i = 0; i < num_fonts; i++)
279         {
280           font->ascent = MAX (font->ascent, font_structs[i]->ascent);
281           font->descent = MAX (font->descent, font_structs[i]->descent);
282         }
283
284       private->names = NULL;
285       gdk_font_hash_insert (GDK_FONT_FONTSET, font, fontset_name);
286       
287       return font;
288     }
289 }
290
291 void
292 _gdk_font_destroy (GdkFont *font)
293 {
294   GdkFontPrivateX *private = (GdkFontPrivateX *)font;
295   
296   gdk_font_hash_remove (font->type, font);
297       
298   switch (font->type)
299     {
300     case GDK_FONT_FONT:
301       gdk_xid_table_remove (((XFontStruct *) private->xfont)->fid);
302       XFreeFont (private->xdisplay, (XFontStruct *) private->xfont);
303       break;
304     case GDK_FONT_FONTSET:
305       XFreeFontSet (private->xdisplay, (XFontSet) private->xfont);
306       break;
307     default:
308       g_error ("unknown font type.");
309       break;
310     }
311   g_free (font);
312 }
313
314 gint
315 _gdk_font_strlen (GdkFont     *font,
316                   const gchar *str)
317 {
318   GdkFontPrivateX *font_private;
319   gint length = 0;
320
321   g_return_val_if_fail (font != NULL, -1);
322   g_return_val_if_fail (str != NULL, -1);
323
324   font_private = (GdkFontPrivateX*) font;
325
326   if (font->type == GDK_FONT_FONT)
327     {
328       XFontStruct *xfont = (XFontStruct *) font_private->xfont;
329       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
330         {
331           length = strlen (str);
332         }
333       else
334         {
335           guint16 *string_2b = (guint16 *)str;
336             
337           while (*(string_2b++))
338             length++;
339         }
340     }
341   else if (font->type == GDK_FONT_FONTSET)
342     {
343       length = strlen (str);
344     }
345   else
346     g_error("undefined font type\n");
347
348   return length;
349 }
350
351 gint
352 gdk_font_id (const GdkFont *font)
353 {
354   const GdkFontPrivateX *font_private;
355
356   g_return_val_if_fail (font != NULL, 0);
357
358   font_private = (const GdkFontPrivateX*) font;
359
360   if (font->type == GDK_FONT_FONT)
361     {
362       return ((XFontStruct *) font_private->xfont)->fid;
363     }
364   else
365     {
366       return 0;
367     }
368 }
369
370 gboolean
371 gdk_font_equal (const GdkFont *fonta,
372                 const GdkFont *fontb)
373 {
374   const GdkFontPrivateX *privatea;
375   const GdkFontPrivateX *privateb;
376
377   g_return_val_if_fail (fonta != NULL, FALSE);
378   g_return_val_if_fail (fontb != NULL, FALSE);
379
380   privatea = (const GdkFontPrivateX*) fonta;
381   privateb = (const GdkFontPrivateX*) fontb;
382
383   if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
384     {
385       return (((XFontStruct *) privatea->xfont)->fid ==
386               ((XFontStruct *) privateb->xfont)->fid);
387     }
388   else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET)
389     {
390       gchar *namea, *nameb;
391
392       namea = XBaseFontNameListOfFontSet((XFontSet) privatea->xfont);
393       nameb = XBaseFontNameListOfFontSet((XFontSet) privateb->xfont);
394       
395       return (strcmp(namea, nameb) == 0);
396     }
397   else
398     /* fontset != font */
399     return 0;
400 }
401
402 gint
403 gdk_text_width (GdkFont      *font,
404                 const gchar  *text,
405                 gint          text_length)
406 {
407   GdkFontPrivateX *private;
408   gint width;
409   XFontStruct *xfont;
410   XFontSet fontset;
411
412   g_return_val_if_fail (font != NULL, -1);
413   g_return_val_if_fail (text != NULL, -1);
414
415   private = (GdkFontPrivateX*) font;
416
417   switch (font->type)
418     {
419     case GDK_FONT_FONT:
420       xfont = (XFontStruct *) private->xfont;
421       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
422         {
423           width = XTextWidth (xfont, text, text_length);
424         }
425       else
426         {
427           width = XTextWidth16 (xfont, (XChar2b *) text, text_length / 2);
428         }
429       break;
430     case GDK_FONT_FONTSET:
431       fontset = (XFontSet) private->xfont;
432       width = XmbTextEscapement (fontset, text, text_length);
433       break;
434     default:
435       width = 0;
436     }
437   return width;
438 }
439
440 gint
441 gdk_text_width_wc (GdkFont        *font,
442                    const GdkWChar *text,
443                    gint            text_length)
444 {
445   GdkFontPrivateX *private;
446   gint width;
447   XFontStruct *xfont;
448   XFontSet fontset;
449
450   g_return_val_if_fail (font != NULL, -1);
451   g_return_val_if_fail (text != NULL, -1);
452
453   private = (GdkFontPrivateX*) font;
454
455   switch (font->type)
456     {
457     case GDK_FONT_FONT:
458       xfont = (XFontStruct *) private->xfont;
459       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
460         {
461           gchar *text_8bit;
462           gint i;
463           text_8bit = g_new (gchar, text_length);
464           for (i=0; i<text_length; i++) text_8bit[i] = text[i];
465           width = XTextWidth (xfont, text_8bit, text_length);
466           g_free (text_8bit);
467         }
468       else
469         {
470           width = 0;
471         }
472       break;
473     case GDK_FONT_FONTSET:
474       if (sizeof(GdkWChar) == sizeof(wchar_t))
475         {
476           fontset = (XFontSet) private->xfont;
477           width = XwcTextEscapement (fontset, (wchar_t *)text, text_length);
478         }
479       else
480         {
481           wchar_t *text_wchar;
482           gint i;
483           fontset = (XFontSet) private->xfont;
484           text_wchar = g_new(wchar_t, text_length);
485           for (i=0; i<text_length; i++) text_wchar[i] = text[i];
486           width = XwcTextEscapement (fontset, text_wchar, text_length);
487           g_free (text_wchar);
488         }
489       break;
490     default:
491       width = 0;
492     }
493   return width;
494 }
495
496 void
497 gdk_text_extents (GdkFont     *font,
498                   const gchar *text,
499                   gint         text_length,
500                   gint        *lbearing,
501                   gint        *rbearing,
502                   gint        *width,
503                   gint        *ascent,
504                   gint        *descent)
505 {
506   GdkFontPrivateX *private;
507   XCharStruct overall;
508   XFontStruct *xfont;
509   XFontSet    fontset;
510   XRectangle  ink, logical;
511   int direction;
512   int font_ascent;
513   int font_descent;
514
515   g_return_if_fail (font != NULL);
516   g_return_if_fail (text != NULL);
517
518   private = (GdkFontPrivateX*) font;
519
520   switch (font->type)
521     {
522     case GDK_FONT_FONT:
523       xfont = (XFontStruct *) private->xfont;
524       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
525         {
526           XTextExtents (xfont, text, text_length,
527                         &direction, &font_ascent, &font_descent,
528                         &overall);
529         }
530       else
531         {
532           XTextExtents16 (xfont, (XChar2b *) text, text_length / 2,
533                           &direction, &font_ascent, &font_descent,
534                           &overall);
535         }
536       if (lbearing)
537         *lbearing = overall.lbearing;
538       if (rbearing)
539         *rbearing = overall.rbearing;
540       if (width)
541         *width = overall.width;
542       if (ascent)
543         *ascent = overall.ascent;
544       if (descent)
545         *descent = overall.descent;
546       break;
547     case GDK_FONT_FONTSET:
548       fontset = (XFontSet) private->xfont;
549       XmbTextExtents (fontset, text, text_length, &ink, &logical);
550       if (lbearing)
551         *lbearing = ink.x;
552       if (rbearing)
553         *rbearing = ink.x + ink.width;
554       if (width)
555         *width = logical.width;
556       if (ascent)
557         *ascent = -ink.y;
558       if (descent)
559         *descent = ink.y + ink.height;
560       break;
561     }
562
563 }
564
565 void
566 gdk_text_extents_wc (GdkFont        *font,
567                      const GdkWChar *text,
568                      gint            text_length,
569                      gint           *lbearing,
570                      gint           *rbearing,
571                      gint           *width,
572                      gint           *ascent,
573                      gint           *descent)
574 {
575   GdkFontPrivateX *private;
576   XCharStruct overall;
577   XFontStruct *xfont;
578   XFontSet    fontset;
579   XRectangle  ink, logical;
580   int direction;
581   int font_ascent;
582   int font_descent;
583
584   g_return_if_fail (font != NULL);
585   g_return_if_fail (text != NULL);
586
587   private = (GdkFontPrivateX*) font;
588
589   switch (font->type)
590     {
591     case GDK_FONT_FONT:
592       {
593         gchar *text_8bit;
594         gint i;
595
596         xfont = (XFontStruct *) private->xfont;
597         g_return_if_fail ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0));
598
599         text_8bit = g_new (gchar, text_length);
600         for (i=0; i<text_length; i++) 
601           text_8bit[i] = text[i];
602
603         XTextExtents (xfont, text_8bit, text_length,
604                       &direction, &font_ascent, &font_descent,
605                       &overall);
606         g_free (text_8bit);
607         
608         if (lbearing)
609           *lbearing = overall.lbearing;
610         if (rbearing)
611           *rbearing = overall.rbearing;
612         if (width)
613           *width = overall.width;
614         if (ascent)
615           *ascent = overall.ascent;
616         if (descent)
617           *descent = overall.descent;
618         break;
619       }
620     case GDK_FONT_FONTSET:
621       fontset = (XFontSet) private->xfont;
622
623       if (sizeof(GdkWChar) == sizeof(wchar_t))
624         XwcTextExtents (fontset, (wchar_t *)text, text_length, &ink, &logical);
625       else
626         {
627           wchar_t *text_wchar;
628           gint i;
629           
630           text_wchar = g_new (wchar_t, text_length);
631           for (i = 0; i < text_length; i++)
632             text_wchar[i] = text[i];
633           XwcTextExtents (fontset, text_wchar, text_length, &ink, &logical);
634           g_free (text_wchar);
635         }
636       if (lbearing)
637         *lbearing = ink.x;
638       if (rbearing)
639         *rbearing = ink.x + ink.width;
640       if (width)
641         *width = logical.width;
642       if (ascent)
643         *ascent = -ink.y;
644       if (descent)
645         *descent = ink.y + ink.height;
646       break;
647     }
648
649 }