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