]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkfont-x11.c
0b3a55a9993190a7c2530a0cf3267ae7efd961fa
[~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 #undef GDK_DISABLE_DEPRECATED
28
29 #include <X11/Xlib.h>
30 #include <X11/Xos.h>
31 #include <locale.h>
32
33 #include <pango/pangox.h>
34
35 #include "gdkx.h"
36 #include "gdkfont.h"
37 #include "gdkprivate-x11.h"
38 #include "gdkinternals.h"
39 #include "gdkdisplay-x11.h"
40 #include "gdkscreen-x11.h"
41
42 typedef struct _GdkFontPrivateX        GdkFontPrivateX;
43
44 struct _GdkFontPrivateX
45 {
46   GdkFontPrivate base;
47   /* XFontStruct *xfont; */
48   /* generic pointer point to XFontStruct or XFontSet */
49   gpointer xfont;
50   GdkDisplay *display;
51
52   GSList *names;
53 };
54
55 static GHashTable *
56 gdk_font_name_hash_get (GdkDisplay *display)
57 {
58   GHashTable *result;
59   static GQuark font_name_quark = 0;
60
61   if (!font_name_quark)
62     font_name_quark = g_quark_from_static_string ("gdk-font-hash");
63
64   result = g_object_get_qdata (G_OBJECT (display), font_name_quark);
65
66   if (!result)
67     {
68       result = g_hash_table_new (g_str_hash, g_str_equal);
69       g_object_set_qdata (G_OBJECT (display), font_name_quark, result);
70     }
71
72   return result;
73 }
74
75 static GHashTable *
76 gdk_fontset_name_hash_get (GdkDisplay *display)
77 {
78   GHashTable *result;
79   static GQuark fontset_name_quark = 0;
80   
81   if (!fontset_name_quark)
82     fontset_name_quark = g_quark_from_static_string ("gdk-fontset-hash");
83
84   result = g_object_get_qdata (G_OBJECT (display), fontset_name_quark);
85
86   if (!result)
87     {
88       result = g_hash_table_new (g_str_hash, g_str_equal);
89       g_object_set_qdata (G_OBJECT (display), fontset_name_quark, result);
90     }
91
92   return result;
93 }
94
95 /** 
96  * gdk_font_get_display:
97  * @font: the #GdkFont.
98  *
99  * Returns the #GdkDisplay for @font.
100  *
101  * Returns : the corresponding #GdkDisplay.
102  **/
103 GdkDisplay* 
104 gdk_font_get_display (GdkFont* font)
105 {
106   return ((GdkFontPrivateX *)font)->display;
107 }
108
109 static void
110 gdk_font_hash_insert (GdkFontType  type, 
111                       GdkFont     *font, 
112                       const gchar *font_name)
113 {
114   GdkFontPrivateX *private = (GdkFontPrivateX *)font;
115   GHashTable *hash = (type == GDK_FONT_FONT) ?
116     gdk_font_name_hash_get (private->display) : gdk_fontset_name_hash_get (private->display);
117
118   private->names = g_slist_prepend (private->names, g_strdup (font_name));
119   g_hash_table_insert (hash, private->names->data, font);
120 }
121
122 static void
123 gdk_font_hash_remove (GdkFontType type, 
124                       GdkFont    *font)
125 {
126   GdkFontPrivateX *private = (GdkFontPrivateX *)font;
127   GSList *tmp_list;
128   GHashTable *hash = (type == GDK_FONT_FONT) ?
129     gdk_font_name_hash_get (private->display) : gdk_fontset_name_hash_get (private->display);
130
131   tmp_list = private->names;
132   while (tmp_list)
133     {
134       g_hash_table_remove (hash, tmp_list->data);
135       g_free (tmp_list->data);
136       
137       tmp_list = tmp_list->next;
138     }
139
140   g_slist_free (private->names);
141   private->names = NULL;
142 }
143
144 static GdkFont *
145 gdk_font_hash_lookup (GdkDisplay  *display, 
146                       GdkFontType  type, 
147                       const gchar *font_name)
148 {
149   GdkFont *result;
150   GHashTable *hash;
151   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
152
153   hash = (type == GDK_FONT_FONT) ? gdk_font_name_hash_get (display) : 
154                                    gdk_fontset_name_hash_get (display);
155   if (!hash)
156     return NULL;
157   else
158     {
159       result = g_hash_table_lookup (hash, font_name);
160       if (result)
161         gdk_font_ref (result);
162       
163       return result;
164     }
165 }
166
167 /**
168  * gdk_font_load_for_display:
169  * @display: a #GdkDisplay
170  * @font_name: a XLFD describing the font to load.
171  * @returns: a #GdkFont, or %NULL if the font could not be loaded.
172  *
173  * Loads a font for use on @display.
174  *
175  * The font may be newly loaded or looked up the font in a cache. 
176  * You should make no assumptions about the initial reference count.
177  */
178 GdkFont *
179 gdk_font_load_for_display (GdkDisplay  *display, 
180                            const gchar *font_name)
181 {
182   GdkFont *font;
183   GdkFontPrivateX *private;
184   XFontStruct *xfont;
185
186   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
187   g_return_val_if_fail (font_name != NULL, NULL);
188   
189   font = gdk_font_hash_lookup (display, GDK_FONT_FONT, font_name);
190   if (font)
191     return font;
192
193   xfont = XLoadQueryFont (GDK_DISPLAY_XDISPLAY (display), font_name);
194   if (xfont == NULL)
195     return NULL;
196
197   font = gdk_font_lookup_for_display (display, xfont->fid);
198   if (font != NULL) 
199     {
200       private = (GdkFontPrivateX *) font;
201       if (xfont != private->xfont)
202         XFreeFont (GDK_DISPLAY_XDISPLAY (display), xfont);
203
204       gdk_font_ref (font);
205     }
206   else
207     {
208       private = g_new (GdkFontPrivateX, 1);
209       private->display = display;
210       private->xfont = xfont;
211       private->base.ref_count = 1;
212       private->names = NULL;
213  
214       font = (GdkFont*) private;
215       font->type = GDK_FONT_FONT;
216       font->ascent =  xfont->ascent;
217       font->descent = xfont->descent;
218       
219       _gdk_xid_table_insert (display, &xfont->fid, font);
220     }
221
222   gdk_font_hash_insert (GDK_FONT_FONT, font, font_name);
223
224   return font;
225 }
226
227 static char *
228 gdk_font_charset_for_locale (void)
229 {
230   static char *charset_map[][2] = {
231     { "ANSI_X3.4-1968", "iso8859-1" },
232     { "US-ASCII",   "iso8859-1" },
233     { "ISO-8859-1", "iso8859-1" },
234     { "ISO-8859-2", "iso8859-2" },
235     { "ISO-8859-3", "iso8859-3" },
236     { "ISO-8859-4", "iso8859-4" },
237     { "ISO-8859-5", "iso8859-5" },
238     { "ISO-8859-6", "iso8859-6" },
239     { "ISO-8859-7", "iso8859-7" },
240     { "ISO-8859-8", "iso8859-8" },
241     { "ISO-8859-9", "iso8859-9" },
242     { "UTF-8",      "iso8859-1" }
243   };
244
245   const char *codeset;
246   char *result = NULL;
247   int i;
248
249   g_get_charset (&codeset);
250   
251   for (i=0; i < G_N_ELEMENTS (charset_map); i++)
252     if (strcmp (charset_map[i][0], codeset) == 0)
253       {
254         result = charset_map[i][1];
255         break;
256       }
257
258   if (result)
259     return g_strdup (result);
260   else
261     return g_strdup ("iso8859-1");
262 }
263
264 /**
265  * gdk_font_from_description_for_display:
266  * @display: a #GdkDisplay
267  * @font_desc: a #PangoFontDescription.
268  * 
269  * Loads a #GdkFont based on a Pango font description for use on @display. 
270  * This font will only be an approximation of the Pango font, and
271  * internationalization will not be handled correctly. This function
272  * should only be used for legacy code that cannot be easily converted
273  * to use Pango. Using Pango directly will produce better results.
274  * 
275  * Return value: the newly loaded font, or %NULL if the font
276  * cannot be loaded.
277  */
278 GdkFont *
279 gdk_font_from_description_for_display (GdkDisplay           *display,
280                                        PangoFontDescription *font_desc)
281 {
282   PangoFontMap *font_map;
283   PangoFont *font;
284   GdkFont *result = NULL;
285
286   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
287   g_return_val_if_fail (font_desc != NULL, NULL);
288
289   font_map = pango_x_font_map_for_display (GDK_DISPLAY_XDISPLAY (display));
290   font = pango_font_map_load_font (font_map, NULL, font_desc);
291
292   if (font)
293     {
294       gchar *charset = gdk_font_charset_for_locale ();
295       gint n_subfonts;
296       PangoXSubfont *subfont_ids;
297       gint *subfont_charsets;
298
299       n_subfonts = pango_x_list_subfonts (font, &charset, 1,
300                                           &subfont_ids, &subfont_charsets);
301       if (n_subfonts > 0)
302         {
303           gchar *xlfd = pango_x_font_subfont_xlfd (font, subfont_ids[0]);
304           result = gdk_font_load_for_display (display, xlfd);
305
306           g_free (xlfd);
307         }
308
309       g_free (subfont_ids);
310
311       g_free (subfont_charsets);
312
313       g_free (charset);
314       g_object_unref (font);
315     }
316
317   return result;
318 }
319
320 /**
321  * gdk_fontset_load_for_display:
322  * @display: a #GdkDisplay
323  * @fontset_name: a comma-separated list of XLFDs describing
324  *   the component fonts of the fontset to load.
325  * @returns: a #GdkFont, or %NULL if the fontset could not be loaded.
326  * 
327  * Loads a fontset for use on @display.
328  *
329  * The fontset may be newly loaded or looked up in a cache. 
330  * You should make no assumptions about the initial reference count.
331  */
332 GdkFont *
333 gdk_fontset_load_for_display (GdkDisplay  *display,
334                               const gchar *fontset_name)
335 {
336   GdkFont *font;
337   GdkFontPrivateX *private;
338   XFontSet fontset;
339   gint  missing_charset_count;
340   gchar **missing_charset_list;
341   gchar *def_string;
342
343   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
344   
345   font = gdk_font_hash_lookup (display, GDK_FONT_FONTSET, fontset_name);
346   if (font)
347     return font;
348
349   private = g_new (GdkFontPrivateX, 1);
350   font = (GdkFont*) private;
351
352   private->display = display;
353   fontset = XCreateFontSet (GDK_DISPLAY_XDISPLAY (display), fontset_name,
354                             &missing_charset_list, &missing_charset_count,
355                             &def_string);
356
357   if (missing_charset_count)
358     {
359       gint i;
360       g_printerr ("The font \"%s\" does not support all the required character sets for the current locale \"%s\"\n",
361                  fontset_name, setlocale (LC_ALL, NULL));
362       for (i=0;i<missing_charset_count;i++)
363         g_printerr ("  (Missing character set \"%s\")\n",
364                     missing_charset_list[i]);
365       XFreeStringList (missing_charset_list);
366     }
367
368   private->base.ref_count = 1;
369
370   if (!fontset)
371     {
372       g_free (font);
373       return NULL;
374     }
375   else
376     {
377       gint num_fonts;
378       gint i;
379       XFontStruct **font_structs;
380       gchar **font_names;
381       
382       private->xfont = fontset;
383       font->type = GDK_FONT_FONTSET;
384       num_fonts = XFontsOfFontSet (fontset, &font_structs, &font_names);
385
386       font->ascent = font->descent = 0;
387       
388       for (i = 0; i < num_fonts; i++)
389         {
390           font->ascent = MAX (font->ascent, font_structs[i]->ascent);
391           font->descent = MAX (font->descent, font_structs[i]->descent);
392         }
393  
394       private->names = NULL;
395       gdk_font_hash_insert (GDK_FONT_FONTSET, font, fontset_name);
396       
397       return font;
398     }
399 }
400
401 /**
402  * gdk_fontset_load:
403  * @fontset_name: a comma-separated list of XLFDs describing
404  *     the component fonts of the fontset to load.
405  * 
406  * Loads a fontset.
407  *
408  * The fontset may be newly loaded or looked up in a cache. 
409  * You should make no assumptions about the initial reference count.
410  * 
411  * Return value: a #GdkFont, or %NULL if the fontset could not be loaded.
412  **/
413 GdkFont*
414 gdk_fontset_load (const gchar *fontset_name)
415 {
416   return gdk_fontset_load_for_display (gdk_display_get_default (), fontset_name);
417 }
418
419 void
420 _gdk_font_destroy (GdkFont *font)
421 {
422   GdkFontPrivateX *private = (GdkFontPrivateX *)font;
423   
424   gdk_font_hash_remove (font->type, font);
425       
426   switch (font->type)
427     {
428     case GDK_FONT_FONT:
429       _gdk_xid_table_remove (private->display, ((XFontStruct *) private->xfont)->fid);
430       XFreeFont (GDK_DISPLAY_XDISPLAY (private->display),
431                   (XFontStruct *) private->xfont);
432       break;
433     case GDK_FONT_FONTSET:
434       XFreeFontSet (GDK_DISPLAY_XDISPLAY (private->display),
435                     (XFontSet) private->xfont);
436       break;
437     default:
438       g_error ("unknown font type.");
439       break;
440     }
441   g_free (font);
442 }
443
444 gint
445 _gdk_font_strlen (GdkFont     *font,
446                   const gchar *str)
447 {
448   GdkFontPrivateX *font_private;
449   gint length = 0;
450
451   g_return_val_if_fail (font != NULL, -1);
452   g_return_val_if_fail (str != NULL, -1);
453
454   font_private = (GdkFontPrivateX*) font;
455
456   if (font->type == GDK_FONT_FONT)
457     {
458       XFontStruct *xfont = (XFontStruct *) font_private->xfont;
459       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
460         {
461           length = strlen (str);
462         }
463       else
464         {
465           guint16 *string_2b = (guint16 *)str;
466             
467           while (*(string_2b++))
468             length++;
469         }
470     }
471   else if (font->type == GDK_FONT_FONTSET)
472     {
473       length = strlen (str);
474     }
475   else
476     g_error("undefined font type\n");
477
478   return length;
479 }
480
481 /**
482  * gdk_font_id:
483  * @font: a #GdkFont.
484  * 
485  * Returns the X Font ID for the given font. 
486  * 
487  * Return value: the numeric X Font ID
488  **/
489 gint
490 gdk_font_id (const GdkFont *font)
491 {
492   const GdkFontPrivateX *font_private;
493
494   g_return_val_if_fail (font != NULL, 0);
495
496   font_private = (const GdkFontPrivateX*) font;
497
498   if (font->type == GDK_FONT_FONT)
499     {
500       return ((XFontStruct *) font_private->xfont)->fid;
501     }
502   else
503     {
504       return 0;
505     }
506 }
507
508 /**
509  * gdk_font_equal:
510  * @fonta: a #GdkFont.
511  * @fontb: another #GdkFont.
512  * 
513  * Compares two fonts for equality. Single fonts compare equal
514  * if they have the same X font ID. This operation does
515  * not currently work correctly for fontsets.
516  * 
517  * Return value: %TRUE if the fonts are equal.
518  **/
519 gboolean
520 gdk_font_equal (const GdkFont *fonta,
521                 const GdkFont *fontb)
522 {
523   const GdkFontPrivateX *privatea;
524   const GdkFontPrivateX *privateb;
525
526   g_return_val_if_fail (fonta != NULL, FALSE);
527   g_return_val_if_fail (fontb != NULL, FALSE);
528
529   privatea = (const GdkFontPrivateX*) fonta;
530   privateb = (const GdkFontPrivateX*) fontb;
531
532   if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
533     {
534       return (((XFontStruct *) privatea->xfont)->fid ==
535               ((XFontStruct *) privateb->xfont)->fid);
536     }
537   else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET)
538     {
539       gchar *namea, *nameb;
540
541       namea = XBaseFontNameListOfFontSet((XFontSet) privatea->xfont);
542       nameb = XBaseFontNameListOfFontSet((XFontSet) privateb->xfont);
543       
544       return (strcmp(namea, nameb) == 0);
545     }
546   else
547     /* fontset != font */
548     return 0;
549 }
550
551 /**
552  * gdk_text_width:
553  * @font: a #GdkFont
554  * @text: the text to measure.
555  * @text_length: the length of the text in bytes.
556  * 
557  * Determines the width of a given string.
558  * 
559  * Return value: the width of the string in pixels.
560  **/
561 gint
562 gdk_text_width (GdkFont      *font,
563                 const gchar  *text,
564                 gint          text_length)
565 {
566   GdkFontPrivateX *private;
567   gint width;
568   XFontStruct *xfont;
569   XFontSet fontset;
570
571   g_return_val_if_fail (font != NULL, -1);
572   g_return_val_if_fail (text != NULL, -1);
573
574   private = (GdkFontPrivateX*) font;
575
576   switch (font->type)
577     {
578     case GDK_FONT_FONT:
579       xfont = (XFontStruct *) private->xfont;
580       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
581         {
582           width = XTextWidth (xfont, text, text_length);
583         }
584       else
585         {
586           width = XTextWidth16 (xfont, (XChar2b *) text, text_length / 2);
587         }
588       break;
589     case GDK_FONT_FONTSET:
590       fontset = (XFontSet) private->xfont;
591       width = XmbTextEscapement (fontset, text, text_length);
592       break;
593     default:
594       width = 0;
595     }
596   return width;
597 }
598
599 /**
600  * gdk_text_width_wc:
601  * @font: a #GdkFont
602  * @text: the text to measure.
603  * @text_length: the length of the text in characters.
604  * 
605  * Determines the width of a given wide-character string.
606  * 
607  * Return value: the width of the string in pixels.
608  **/
609 gint
610 gdk_text_width_wc (GdkFont        *font,
611                    const GdkWChar *text,
612                    gint            text_length)
613 {
614   GdkFontPrivateX *private;
615   gint width;
616   XFontStruct *xfont;
617   XFontSet fontset;
618
619   g_return_val_if_fail (font != NULL, -1);
620   g_return_val_if_fail (text != NULL, -1);
621
622   private = (GdkFontPrivateX*) font;
623
624   switch (font->type)
625     {
626     case GDK_FONT_FONT:
627       xfont = (XFontStruct *) private->xfont;
628       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
629         {
630           gchar *text_8bit;
631           gint i;
632           text_8bit = g_new (gchar, text_length);
633           for (i=0; i<text_length; i++) text_8bit[i] = text[i];
634           width = XTextWidth (xfont, text_8bit, text_length);
635           g_free (text_8bit);
636         }
637       else
638         {
639           width = 0;
640         }
641       break;
642     case GDK_FONT_FONTSET:
643       if (sizeof(GdkWChar) == sizeof(wchar_t))
644         {
645           fontset = (XFontSet) private->xfont;
646           width = XwcTextEscapement (fontset, (wchar_t *)text, text_length);
647         }
648       else
649         {
650           wchar_t *text_wchar;
651           gint i;
652           fontset = (XFontSet) private->xfont;
653           text_wchar = g_new(wchar_t, text_length);
654           for (i=0; i<text_length; i++) text_wchar[i] = text[i];
655           width = XwcTextEscapement (fontset, text_wchar, text_length);
656           g_free (text_wchar);
657         }
658       break;
659     default:
660       width = 0;
661     }
662   return width;
663 }
664
665 /**
666  * gdk_text_extents:
667  * @font: a #GdkFont
668  * @text: the text to measure
669  * @text_length: the length of the text in bytes. (If the
670  *    font is a 16-bit font, this is twice the length
671  *    of the text in characters.)
672  * @lbearing: the left bearing of the string.
673  * @rbearing: the right bearing of the string.
674  * @width: the width of the string.
675  * @ascent: the ascent of the string.
676  * @descent: the descent of the string.
677  * 
678  * Gets the metrics of a string.
679  **/
680 void
681 gdk_text_extents (GdkFont     *font,
682                   const gchar *text,
683                   gint         text_length,
684                   gint        *lbearing,
685                   gint        *rbearing,
686                   gint        *width,
687                   gint        *ascent,
688                   gint        *descent)
689 {
690   GdkFontPrivateX *private;
691   XCharStruct overall;
692   XFontStruct *xfont;
693   XFontSet    fontset;
694   XRectangle  ink, logical;
695   int direction;
696   int font_ascent;
697   int font_descent;
698
699   g_return_if_fail (font != NULL);
700   g_return_if_fail (text != NULL);
701
702   private = (GdkFontPrivateX*) font;
703
704   switch (font->type)
705     {
706     case GDK_FONT_FONT:
707       xfont = (XFontStruct *) private->xfont;
708       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
709         {
710           XTextExtents (xfont, text, text_length,
711                         &direction, &font_ascent, &font_descent,
712                         &overall);
713         }
714       else
715         {
716           XTextExtents16 (xfont, (XChar2b *) text, text_length / 2,
717                           &direction, &font_ascent, &font_descent,
718                           &overall);
719         }
720       if (lbearing)
721         *lbearing = overall.lbearing;
722       if (rbearing)
723         *rbearing = overall.rbearing;
724       if (width)
725         *width = overall.width;
726       if (ascent)
727         *ascent = overall.ascent;
728       if (descent)
729         *descent = overall.descent;
730       break;
731     case GDK_FONT_FONTSET:
732       fontset = (XFontSet) private->xfont;
733       XmbTextExtents (fontset, text, text_length, &ink, &logical);
734       if (lbearing)
735         *lbearing = ink.x;
736       if (rbearing)
737         *rbearing = ink.x + ink.width;
738       if (width)
739         *width = logical.width;
740       if (ascent)
741         *ascent = -ink.y;
742       if (descent)
743         *descent = ink.y + ink.height;
744       break;
745     }
746
747 }
748
749 /**
750  * gdk_text_extents_wc:
751  * @font: a #GdkFont
752  * @text: the text to measure.
753  * @text_length: the length of the text in character.
754  * @lbearing: the left bearing of the string.
755  * @rbearing: the right bearing of the string.
756  * @width: the width of the string.
757  * @ascent: the ascent of the string.
758  * @descent: the descent of the string.
759  * 
760  * Gets the metrics of a string of wide characters.
761  **/
762 void
763 gdk_text_extents_wc (GdkFont        *font,
764                      const GdkWChar *text,
765                      gint            text_length,
766                      gint           *lbearing,
767                      gint           *rbearing,
768                      gint           *width,
769                      gint           *ascent,
770                      gint           *descent)
771 {
772   GdkFontPrivateX *private;
773   XCharStruct overall;
774   XFontStruct *xfont;
775   XFontSet    fontset;
776   XRectangle  ink, logical;
777   int direction;
778   int font_ascent;
779   int font_descent;
780
781   g_return_if_fail (font != NULL);
782   g_return_if_fail (text != NULL);
783
784   private = (GdkFontPrivateX*) font;
785
786   switch (font->type)
787     {
788     case GDK_FONT_FONT:
789       {
790         gchar *text_8bit;
791         gint i;
792
793         xfont = (XFontStruct *) private->xfont;
794         g_return_if_fail ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0));
795
796         text_8bit = g_new (gchar, text_length);
797         for (i=0; i<text_length; i++) 
798           text_8bit[i] = text[i];
799
800         XTextExtents (xfont, text_8bit, text_length,
801                       &direction, &font_ascent, &font_descent,
802                       &overall);
803         g_free (text_8bit);
804         
805         if (lbearing)
806           *lbearing = overall.lbearing;
807         if (rbearing)
808           *rbearing = overall.rbearing;
809         if (width)
810           *width = overall.width;
811         if (ascent)
812           *ascent = overall.ascent;
813         if (descent)
814           *descent = overall.descent;
815         break;
816       }
817     case GDK_FONT_FONTSET:
818       fontset = (XFontSet) private->xfont;
819
820       if (sizeof(GdkWChar) == sizeof(wchar_t))
821         XwcTextExtents (fontset, (wchar_t *)text, text_length, &ink, &logical);
822       else
823         {
824           wchar_t *text_wchar;
825           gint i;
826           
827           text_wchar = g_new (wchar_t, text_length);
828           for (i = 0; i < text_length; i++)
829             text_wchar[i] = text[i];
830           XwcTextExtents (fontset, text_wchar, text_length, &ink, &logical);
831           g_free (text_wchar);
832         }
833       if (lbearing)
834         *lbearing = ink.x;
835       if (rbearing)
836         *rbearing = ink.x + ink.width;
837       if (width)
838         *width = logical.width;
839       if (ascent)
840         *ascent = -ink.y;
841       if (descent)
842         *descent = ink.y + ink.height;
843       break;
844     }
845
846 }
847
848 /**
849  * gdk_x11_font_get_xdisplay:
850  * @font: a #GdkFont.
851  * 
852  * Returns the display of a #GdkFont.
853  * 
854  * Return value:  an Xlib <type>Display*</type>.
855  **/
856 Display *
857 gdk_x11_font_get_xdisplay (GdkFont *font)
858 {
859   g_return_val_if_fail (font != NULL, NULL);
860
861   return GDK_DISPLAY_XDISPLAY (((GdkFontPrivateX *)font)->display);
862 }
863
864 /**
865  * gdk_x11_font_get_xfont:
866  * @font: a #GdkFont.
867  * 
868  * Returns the X font belonging to a #GdkFont.
869  * 
870  * Return value: an Xlib <type>XFontStruct*</type> or an <type>XFontSet</type>.
871  **/
872 gpointer
873 gdk_x11_font_get_xfont (GdkFont *font)
874 {
875   g_return_val_if_fail (font != NULL, NULL);
876
877   return ((GdkFontPrivateX *)font)->xfont;
878 }
879
880 /**
881  * gdk_x11_font_get_name:
882  * @font: a #GdkFont.
883  * 
884  * Return the X Logical Font Description (for font->type == GDK_FONT_FONT)
885  * or comma separated list of XLFDs (for font->type == GDK_FONT_FONTSET)
886  * that was used to load the font. If the same font was loaded
887  * via multiple names, which name is returned is undefined.
888  * 
889  * Return value: the name of the font. This string is owned
890  *   by GDK and must not be modified or freed.
891  **/
892 G_CONST_RETURN char *
893 gdk_x11_font_get_name (GdkFont *font)
894 {
895   GdkFontPrivateX *private = (GdkFontPrivateX *)font;
896
897   g_return_val_if_fail (font != NULL, NULL);
898
899   g_assert (private->names);
900
901   return private->names->data;
902 }
903