]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkfont-x11.c
e36fde1708254b96b9294916c97678dd97215071
[~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 #include <X11/Xlib.h>
20 #include <X11/Xos.h>
21 #include "gdk.h"
22 #include "gdkprivate.h"
23
24 GdkFont*
25 gdk_font_load (const gchar *font_name)
26 {
27   GdkFont *font;
28   GdkFontPrivate *private;
29
30   private = g_new (GdkFontPrivate, 1);
31   font = (GdkFont*) private;
32
33   private->xdisplay = gdk_display;
34   private->xfont = XLoadQueryFont (private->xdisplay, font_name);
35   private->ref_count = 1;
36
37   if (!private->xfont)
38     {
39       g_free (font);
40       return NULL;
41     }
42   else
43     {
44       font->type = GDK_FONT_FONT;
45       font->ascent =  ((XFontStruct *) private->xfont)->ascent;
46       font->descent = ((XFontStruct *) private->xfont)->descent;
47     }
48
49   gdk_xid_table_insert (&((XFontStruct *) private->xfont)->fid, font);
50
51   return font;
52 }
53
54 GdkFont*
55 gdk_fontset_load (gchar *fontset_name)
56 {
57   GdkFont *font;
58   GdkFontPrivate *private;
59   XFontSet fontset;
60   gint  missing_charset_count;
61   gchar **missing_charset_list;
62   gchar *def_string;
63
64   private = g_new (GdkFontPrivate, 1);
65   font = (GdkFont*) private;
66
67   private->xdisplay = gdk_display;
68   fontset = XCreateFontSet (gdk_display, fontset_name,
69                             &missing_charset_list, &missing_charset_count,
70                             &def_string);
71
72   if (missing_charset_count)
73     {
74       gint i;
75       g_message ("Missing charsets in FontSet creation\n");
76       for (i=0;i<missing_charset_count;i++)
77         g_message ("    %s\n", missing_charset_list[i]);
78       XFreeStringList (missing_charset_list);
79     }
80
81   private->ref_count = 1;
82
83   if (!fontset)
84     {
85       g_free (font);
86       return NULL;
87     }
88   else
89     {
90       gint num_fonts;
91       gint i;
92       XFontStruct **font_structs;
93       gchar **font_names;
94       
95       private->xfont = fontset;
96       font->type = GDK_FONT_FONTSET;
97       num_fonts = XFontsOfFontSet (fontset, &font_structs, &font_names);
98
99       font->ascent = font->descent = 0;
100       
101       for (i = 0; i < num_fonts; i++)
102         {
103           font->ascent = MAX (font->ascent, font_structs[i]->ascent);
104           font->descent = MAX (font->descent, font_structs[i]->descent);
105         }
106     }
107   return font;
108 }
109
110 GdkFont*
111 gdk_font_ref (GdkFont *font)
112 {
113   GdkFontPrivate *private;
114
115   g_return_val_if_fail (font != NULL, NULL);
116
117   private = (GdkFontPrivate*) font;
118   private->ref_count += 1;
119   return font;
120 }
121
122 void
123 gdk_font_unref (GdkFont *font)
124 {
125   GdkFontPrivate *private;
126
127   g_return_if_fail (font != NULL);
128
129   private = (GdkFontPrivate*) font;
130
131   private->ref_count -= 1;
132   if (private->ref_count == 0)
133     {
134       switch (font->type)
135         {
136         case GDK_FONT_FONT:
137           gdk_xid_table_remove (((XFontStruct *) private->xfont)->fid);
138           XFreeFont (private->xdisplay, (XFontStruct *) private->xfont);
139           break;
140         case GDK_FONT_FONTSET:
141           XFreeFontSet (private->xdisplay, (XFontSet) private->xfont);
142           break;
143         default:
144           g_error ("unknown font type.");
145           break;
146         }
147       g_free (font);
148     }
149 }
150
151 gint
152 gdk_font_id (const GdkFont *font)
153 {
154   const GdkFontPrivate *font_private;
155
156   g_return_val_if_fail (font != NULL, 0);
157
158   font_private = (const GdkFontPrivate*) font;
159
160   if (font->type == GDK_FONT_FONT)
161     {
162       return ((XFontStruct *) font_private->xfont)->fid;
163     }
164   else
165     {
166       return 0;
167     }
168 }
169
170 gint
171 gdk_font_equal (const GdkFont *fonta,
172                 const GdkFont *fontb)
173 {
174   const GdkFontPrivate *privatea;
175   const GdkFontPrivate *privateb;
176
177   g_return_val_if_fail (fonta != NULL, FALSE);
178   g_return_val_if_fail (fontb != NULL, FALSE);
179
180   privatea = (const GdkFontPrivate*) fonta;
181   privateb = (const GdkFontPrivate*) fontb;
182
183   if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
184     {
185       return (((XFontStruct *) privatea->xfont)->fid ==
186               ((XFontStruct *) privateb->xfont)->fid);
187     }
188   else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET)
189     {
190       /* how to compare two fontsets ?? by basename or XFontSet ?? */
191       return (((XFontSet) privatea->xfont) == ((XFontSet) privateb->xfont));
192     }
193   else
194     /* fontset != font */
195     return 0;
196 }
197
198 gint
199 gdk_string_width (GdkFont     *font,
200                   const gchar *string)
201 {
202   GdkFontPrivate *font_private;
203   gint width;
204   XFontStruct *xfont;
205   XFontSet fontset;
206
207   g_return_val_if_fail (font != NULL, -1);
208   g_return_val_if_fail (string != NULL, -1);
209
210   font_private = (GdkFontPrivate*) font;
211
212   switch (font->type)
213     {
214     case GDK_FONT_FONT:
215       xfont = (XFontStruct *) font_private->xfont;
216       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
217         {
218           width = XTextWidth (xfont, string, strlen (string));
219         }
220       else
221         {
222           width = XTextWidth16 (xfont, (XChar2b *) string, strlen (string) / 2);
223         }
224       break;
225     case GDK_FONT_FONTSET:
226       fontset = (XFontSet) font_private->xfont;
227       width = XmbTextEscapement (fontset, string, strlen(string));
228       break;
229     default:
230       width = 0;
231     }
232
233   return width;
234 }
235
236 gint
237 gdk_text_width (GdkFont      *font,
238                 const gchar  *text,
239                 gint          text_length)
240 {
241   GdkFontPrivate *private;
242   gint width;
243   XFontStruct *xfont;
244   XFontSet fontset;
245
246   g_return_val_if_fail (font != NULL, -1);
247   g_return_val_if_fail (text != NULL, -1);
248
249   private = (GdkFontPrivate*) font;
250
251   switch (font->type)
252     {
253     case GDK_FONT_FONT:
254       xfont = (XFontStruct *) private->xfont;
255       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
256         {
257           width = XTextWidth (xfont, text, text_length);
258         }
259       else
260         {
261           width = XTextWidth16 (xfont, (XChar2b *) text, text_length / 2);
262         }
263       break;
264     case GDK_FONT_FONTSET:
265       fontset = (XFontSet) private->xfont;
266       width = XmbTextEscapement (fontset, text, text_length);
267       break;
268     default:
269       width = 0;
270     }
271   return width;
272 }
273
274 gint
275 gdk_text_width_wc (GdkFont        *font,
276                    const GdkWChar *text,
277                    gint            text_length)
278 {
279   GdkFontPrivate *private;
280   gint width;
281   XFontStruct *xfont;
282   XFontSet fontset;
283
284   g_return_val_if_fail (font != NULL, -1);
285   g_return_val_if_fail (text != NULL, -1);
286
287   private = (GdkFontPrivate*) font;
288
289   switch (font->type)
290     {
291     case GDK_FONT_FONT:
292       xfont = (XFontStruct *) private->xfont;
293       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
294         {
295           gchar *text_8bit;
296           gint i;
297           text_8bit = g_new (gchar, text_length);
298           for (i=0; i<text_length; i++) text_8bit[i] = text[i];
299           width = XTextWidth (xfont, text_8bit, text_length);
300           g_free (text_8bit);
301         }
302       else
303         {
304           width = 0;
305         }
306       break;
307     case GDK_FONT_FONTSET:
308       if (sizeof(GdkWChar) == sizeof(wchar_t))
309         {
310           fontset = (XFontSet) private->xfont;
311           width = XwcTextEscapement (fontset, (wchar_t *)text, text_length);
312         }
313       else
314         {
315           wchar_t *text_wchar;
316           gint i;
317           fontset = (XFontSet) private->xfont;
318           text_wchar = g_new(wchar_t, text_length);
319           for (i=0; i<text_length; i++) text_wchar[i] = text[i];
320           width = XwcTextEscapement (fontset, text_wchar, text_length);
321           g_free (text_wchar);
322         }
323       break;
324     default:
325       width = 0;
326     }
327   return width;
328 }
329
330 /* Problem: What if a character is a 16 bits character ?? */
331 gint
332 gdk_char_width (GdkFont *font,
333                 gchar    character)
334 {
335   GdkFontPrivate *private;
336   XCharStruct *chars;
337   gint width;
338   guint ch = character & 0xff;  /* get rid of sign-extension */
339   XFontStruct *xfont;
340   XFontSet fontset;
341
342   g_return_val_if_fail (font != NULL, -1);
343
344   private = (GdkFontPrivate*) font;
345
346   switch (font->type)
347     {
348     case GDK_FONT_FONT:
349       /* only 8 bits characters are considered here */
350       xfont = (XFontStruct *) private->xfont;
351       if ((xfont->min_byte1 == 0) &&
352           (xfont->max_byte1 == 0) &&
353           (ch >= xfont->min_char_or_byte2) &&
354           (ch <= xfont->max_char_or_byte2))
355         {
356           chars = xfont->per_char;
357           if (chars)
358             width = chars[ch - xfont->min_char_or_byte2].width;
359           else
360             width = xfont->min_bounds.width;
361         }
362       else
363         {
364           width = XTextWidth (xfont, &character, 1);
365         }
366       break;
367     case GDK_FONT_FONTSET:
368       fontset = (XFontSet) private->xfont;
369       width = XmbTextEscapement (fontset, &character, 1) ;
370       break;
371     default:
372       width = 0;
373     }
374   return width;
375 }
376
377 gint
378 gdk_char_width_wc (GdkFont *font,
379                    GdkWChar character)
380 {
381   GdkFontPrivate *private;
382   XCharStruct *chars;
383   gint width;
384   guint ch = character & 0xff;  /* get rid of sign-extension */
385   XFontStruct *xfont;
386   XFontSet fontset;
387
388   g_return_val_if_fail (font != NULL, -1);
389
390   private = (GdkFontPrivate*) font;
391
392   switch (font->type)
393     {
394     case GDK_FONT_FONT:
395       /* only 8 bits characters are considered here */
396       xfont = (XFontStruct *) private->xfont;
397       if ((xfont->min_byte1 == 0) &&
398           (xfont->max_byte1 == 0) &&
399           (ch >= xfont->min_char_or_byte2) &&
400           (ch <= xfont->max_char_or_byte2))
401         {
402           chars = xfont->per_char;
403           if (chars)
404             width = chars[ch - xfont->min_char_or_byte2].width;
405           else
406             width = xfont->min_bounds.width;
407         }
408       else
409         {
410           char ch2 = character;
411           width = XTextWidth (xfont, &ch2, 1);
412         }
413       break;
414     case GDK_FONT_FONTSET:
415       fontset = (XFontSet) private->xfont;
416       {
417         wchar_t char_wc = character;
418         width = XwcTextEscapement (fontset, &char_wc, 1) ;
419       }
420       break;
421     default:
422       width = 0;
423     }
424   return width;
425 }
426
427 gint
428 gdk_string_measure (GdkFont     *font,
429                     const gchar *string)
430 {
431   g_return_val_if_fail (font != NULL, -1);
432   g_return_val_if_fail (string != NULL, -1);
433
434   return gdk_text_measure (font, string, strlen (string));
435 }
436
437 void
438 gdk_text_extents (GdkFont     *font,
439                   const gchar *text,
440                   gint         text_length,
441                   gint        *lbearing,
442                   gint        *rbearing,
443                   gint        *width,
444                   gint        *ascent,
445                   gint        *descent)
446 {
447   GdkFontPrivate *private;
448   XCharStruct overall;
449   XFontStruct *xfont;
450   XFontSet    fontset;
451   XRectangle  ink, logical;
452   int direction;
453   int font_ascent;
454   int font_descent;
455
456   g_return_if_fail (font != NULL);
457   g_return_if_fail (text != NULL);
458
459   private = (GdkFontPrivate*) font;
460
461   switch (font->type)
462     {
463     case GDK_FONT_FONT:
464       xfont = (XFontStruct *) private->xfont;
465       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
466         {
467           XTextExtents (xfont, text, text_length,
468                         &direction, &font_ascent, &font_descent,
469                         &overall);
470         }
471       else
472         {
473           XTextExtents16 (xfont, (XChar2b *) text, text_length / 2,
474                           &direction, &font_ascent, &font_descent,
475                           &overall);
476         }
477       if (lbearing)
478         *lbearing = overall.lbearing;
479       if (rbearing)
480         *rbearing = overall.rbearing;
481       if (width)
482         *width = overall.width;
483       if (ascent)
484         *ascent = overall.ascent;
485       if (descent)
486         *descent = overall.descent;
487       break;
488     case GDK_FONT_FONTSET:
489       fontset = (XFontSet) private->xfont;
490       XmbTextExtents (fontset, text, text_length, &ink, &logical);
491       if (lbearing)
492         *lbearing = ink.x;
493       if (rbearing)
494         *rbearing = ink.x + ink.width;
495       if (width)
496         *width = logical.width;
497       if (ascent)
498         *ascent = -ink.y;
499       if (descent)
500         *descent = ink.y + ink.height;
501       break;
502     }
503
504 }
505
506 void
507 gdk_text_extents_wc (GdkFont        *font,
508                      const GdkWChar *text,
509                      gint            text_length,
510                      gint           *lbearing,
511                      gint           *rbearing,
512                      gint           *width,
513                      gint           *ascent,
514                      gint           *descent)
515 {
516   GdkFontPrivate *private;
517   XCharStruct overall;
518   XFontStruct *xfont;
519   XFontSet    fontset;
520   XRectangle  ink, logical;
521   int direction;
522   int font_ascent;
523   int font_descent;
524   gint i;
525
526   g_return_if_fail (font != NULL);
527   g_return_if_fail (text != NULL);
528
529   private = (GdkFontPrivate*) font;
530
531   switch (font->type)
532     {
533     case GDK_FONT_FONT:
534       {
535         gchar *text_8bit;
536         gint i;
537
538         xfont = (XFontStruct *) private->xfont;
539         g_return_if_fail ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0));
540
541         text_8bit = g_new (gchar, text_length);
542         for (i=0; i<text_length; i++) 
543           text_8bit[i] = text[i];
544
545         XTextExtents (xfont, text_8bit, text_length,
546                       &direction, &font_ascent, &font_descent,
547                       &overall);
548         g_free (text_8bit);
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       }
562     case GDK_FONT_FONTSET:
563       fontset = (XFontSet) private->xfont;
564       XwcTextExtents (fontset, text, text_length, &ink, &logical);
565       if (lbearing)
566         *lbearing = ink.x;
567       if (rbearing)
568         *rbearing = ink.x + ink.width;
569       if (width)
570         *width = logical.width;
571       if (ascent)
572         *ascent = -ink.y;
573       if (descent)
574         *descent = ink.y + ink.height;
575       break;
576     }
577
578 }
579
580 void
581 gdk_string_extents (GdkFont     *font,
582                     const gchar *string,
583                     gint        *lbearing,
584                     gint        *rbearing,
585                     gint        *width,
586                     gint        *ascent,
587                     gint        *descent)
588 {
589   g_return_if_fail (font != NULL);
590   g_return_if_fail (string != NULL);
591
592   gdk_text_extents (font, string, strlen (string),
593                     lbearing, rbearing, width, ascent, descent);
594 }
595
596
597 gint
598 gdk_text_measure (GdkFont     *font,
599                   const gchar *text,
600                   gint         text_length)
601 {
602   GdkFontPrivate *private;
603   XCharStruct overall;
604   XFontStruct *xfont;
605   XFontSet    fontset;
606   XRectangle  ink, log;
607   int direction;
608   int font_ascent;
609   int font_descent;
610   gint width;
611
612   g_return_val_if_fail (font != NULL, -1);
613   g_return_val_if_fail (text != NULL, -1);
614
615   private = (GdkFontPrivate*) font;
616
617   switch (font->type)
618     {
619     case GDK_FONT_FONT:
620       xfont = (XFontStruct *) private->xfont;
621       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
622         {
623           XTextExtents (xfont, text, text_length,
624                         &direction, &font_ascent, &font_descent,
625                         &overall);
626         }
627       else
628         {
629           XTextExtents16 (xfont, (XChar2b *) text, text_length / 2,
630                           &direction, &font_ascent, &font_descent,
631                           &overall);
632         }
633       width = overall.rbearing;
634       break;
635     case GDK_FONT_FONTSET:
636       fontset = (XFontSet) private->xfont;
637       XmbTextExtents (fontset, text, text_length, &ink, &log);
638       width = log.width;
639       break;
640     default:
641       width = 0;
642     }
643   return width;
644 }
645
646 gint
647 gdk_char_measure (GdkFont *font,
648                   gchar    character)
649 {
650   g_return_val_if_fail (font != NULL, -1);
651
652   return gdk_text_measure (font, &character, 1);
653 }
654
655 gint
656 gdk_string_height (GdkFont     *font,
657                    const gchar *string)
658 {
659   g_return_val_if_fail (font != NULL, -1);
660   g_return_val_if_fail (string != NULL, -1);
661
662   return gdk_text_height (font, string, strlen (string));
663 }
664
665 gint
666 gdk_text_height (GdkFont     *font,
667                  const gchar *text,
668                  gint         text_length)
669 {
670   GdkFontPrivate *private;
671   XCharStruct overall;
672   XFontStruct *xfont;
673   XFontSet    fontset;
674   XRectangle  ink, log;
675   int direction;
676   int font_ascent;
677   int font_descent;
678   gint height;
679
680   g_return_val_if_fail (font != NULL, -1);
681   g_return_val_if_fail (text != NULL, -1);
682
683   private = (GdkFontPrivate*) font;
684
685   switch (font->type)
686     {
687     case GDK_FONT_FONT:
688       xfont = (XFontStruct *) private->xfont;
689       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
690         {
691           XTextExtents (xfont, text, text_length,
692                         &direction, &font_ascent, &font_descent,
693                         &overall);
694         }
695       else
696         {
697           XTextExtents16 (xfont, (XChar2b *) text, text_length / 2,
698                           &direction, &font_ascent, &font_descent,
699                           &overall);
700         }
701       height = overall.ascent + overall.descent;
702       break;
703     case GDK_FONT_FONTSET:
704       fontset = (XFontSet) private->xfont;
705       XmbTextExtents (fontset, text, text_length, &ink, &log);
706       height = log.height;
707       break;
708     default:
709       height = 0;
710     }
711   return height;
712 }
713
714 gint
715 gdk_char_height (GdkFont *font,
716                  gchar    character)
717 {
718   g_return_val_if_fail (font != NULL, -1);
719
720   return gdk_text_height (font, &character, 1);
721 }