Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtcm / dtcm / font.c
1 /* $XConsortium: font.c /main/4 1995/11/09 12:59:38 rswiston $ */
2 /*
3  *  (c) Copyright 1993, 1994 Hewlett-Packard Company
4  *  (c) Copyright 1993, 1994 International Business Machines Corp.
5  *  (c) Copyright 1993, 1994 Novell, Inc.
6  *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
7  */
8
9 #include <X11/Xlib.h>
10 #include <Xm/Xm.h>
11 #include <Xm/AtomMgr.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include "calendar.h"
15
16 #ifndef ABS
17 #define ABS(x) (((x) > 0) ? (x) : (-(x)))
18 #endif /* ABS */
19
20 /*
21  * Walk a font_list looking for a FontSet with the 
22  * XmFONTLIST_DEFAULT_TAG set.  If we fail to find a FontSet with this tag,
23  * return the first FontSet found.  If we fail to find a FontSet return
24  * the first font found.
25  *
26  * This function returns either a XFontStruct or a XFontSet.  The type can
27  * be determined by the value of type_return which will equal either
28  * XmFONT_IS_FONTSET or XmFONT_IS_FONT.
29  *
30  * The XFontStruct or XFontSet that is returned is not a copy and should
31  * not be freed.
32  */
33 static XtPointer
34 get_font(
35         XmFontList       font_list,
36         XmFontType      *type_return)
37 {
38         XmFontContext    fl_context;
39         XmFontListEntry  fl_entry;
40         XtPointer        fl_entry_font,
41                          font_to_use;
42         char            *fl_entry_font_tag;
43         Boolean          found_font_set = False,
44                          found_font_struct = False;
45
46         *type_return = XmFONT_IS_FONT;
47
48         if (!XmFontListInitFontContext(&fl_context, font_list))
49                 return (XtPointer)NULL;
50
51         do {
52                 fl_entry = XmFontListNextEntry(fl_context);
53                 if (fl_entry) {
54                         fl_entry_font = 
55                                 XmFontListEntryGetFont(fl_entry, type_return);
56                         if (*type_return == XmFONT_IS_FONTSET) {
57                                 fl_entry_font_tag = 
58                                                 XmFontListEntryGetTag(fl_entry);
59                                         /* 
60                                          * Save the first font set found in-
61                                          * case the default tag is not set.
62                                          */
63                                 if (!found_font_set) {
64                                         font_to_use = fl_entry_font;
65                                         found_font_set = True;
66                                         found_font_struct = True;
67
68                                         if (!strcmp(XmFONTLIST_DEFAULT_TAG,
69                                                     fl_entry_font_tag))
70                                                 break;
71                                 } else if (!strcmp(XmFONTLIST_DEFAULT_TAG, 
72                                                     fl_entry_font_tag)) {
73                                         /* Found right font set */
74                                         font_to_use = fl_entry_font;
75                                         break;
76                                 }
77                         } else if (!found_font_struct) {
78                                 font_to_use = fl_entry_font;
79                                 found_font_struct = True;
80                         }
81                 }
82         } while (fl_entry != NULL);
83
84         XmFontListFreeFontContext(fl_context);
85
86         if (!found_font_set && !found_font_struct)
87                 return (XtPointer)NULL;
88
89         return (XtPointer)font_to_use;
90 }
91
92 extern Boolean
93 fontlist_to_font(
94         XmFontList       font_list,
95         Cal_Font        *cal_font)
96 {
97         XmFontType       type_return;
98         XtPointer        font_data;
99
100         if (!font_list) return False;
101
102         font_data = get_font(font_list, &type_return);
103
104         if (!font_data) 
105                 return False;
106
107         cal_font->cf_type = type_return;
108
109         if (type_return == XmFONT_IS_FONTSET)
110                 cal_font->f.cf_fontset = (XFontSet)font_data;
111         else
112                 cal_font->f.cf_font = (XFontStruct *)font_data;
113
114         return True;
115 }
116
117 /*
118  * Look for a font that is closest to the requested point size and resolution
119  * using the weight and family name specified.
120  */
121 static Boolean
122 ProbeForFont(
123         Calendar        *cal, 
124         Font_Weight      weight, 
125         unsigned long    target_pixel_size, 
126         int              with_foundry,
127         char            *font_name)
128 {
129         char           **font_names,
130                          notused[48];
131         int              i, 
132                          nnames,
133                          size = 0,
134                          closest_size_diff = 100000,
135                          closest_size,
136                          closest_index = -1;
137
138         if (!strcmp(cal->app_data->app_font_family, "application")) {
139                 sprintf (font_name, "-%s-%s-%s-r-normal-sans-*-*-*-*-p-*",
140                                 (with_foundry)?"dt":"*",
141                                 cal->app_data->app_font_family,
142                                 (weight == BOLD)?"bold":"medium");
143         } else {
144                 sprintf (font_name, "-%s-%s-%s-r-normal--*-*-*-*-*-*",
145                                 (with_foundry)?"dt":"*",
146                                 cal->app_data->app_font_family,
147                                 (weight == BOLD)?"bold":"medium");
148         }
149
150         /* See if the font exists */
151         font_names = XListFonts(XtDisplay(cal->frame), font_name, 80, &nnames);
152         if (!nnames) {
153                 if (with_foundry)
154                         return ProbeForFont(cal, weight, target_pixel_size, 
155                                                              FALSE, font_name);
156                 else
157                         return FALSE;
158         }
159
160         /* For the fonts that match, get their pixel size and 
161          * look for the one with the pixel size closest to the size we are 
162          * looking for.
163          */
164         for (i = 0; i < nnames; i++) {
165                 sscanf(font_names[i], 
166                        "-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]-%d-%s",
167                         notused, notused, notused, notused, notused, notused,
168                         &size, notused);
169
170                 if (!size)
171                         sscanf(font_names[i], 
172                             "-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]--%d-%s",
173                              notused, notused, notused, notused, notused,
174                              &size, notused);
175
176                 if (size) {
177                         if ((ABS((int)(target_pixel_size - size)) <= 
178                                                         closest_size_diff)) {
179                                 closest_size_diff = 
180                                         ABS((int)(target_pixel_size - size));
181                                 closest_size = size;
182                                 closest_index = i;
183                                 if (closest_size_diff == 0)
184                                         break;
185                         }
186                         size = 0;
187                 }
188         }
189
190         if (closest_index == -1)
191                 return FALSE;
192
193         /* This one is the closest in size */
194         sprintf (font_name, "-%s-%s-%s-r-normal-%s-%d-*-*-*-*-*",
195                  (with_foundry)?"dt":"*",
196                  cal->app_data->app_font_family,
197                  (weight == BOLD)?"bold":"medium",
198                  (!strcmp(cal->app_data->app_font_family, "application")) ?
199                                                                 "sans": "",
200                  closest_size);
201                 
202         XFreeFontNames(font_names);
203
204         return TRUE;
205 }
206
207 extern void
208 load_app_font(
209         Calendar        *cal, 
210         Font_Weight      weight,
211         Cal_Font        *userfont,
212         Cal_Font        *return_font)
213 {
214         unsigned long    pixel_size;
215         Display         *dpy = XtDisplay(cal->frame);
216         char             font_name[128],
217                         *font_name_ptr = font_name,
218                        **font_names;
219         int              nnames;
220         XrmValue         in_font;
221         XrmValue         out_fontlist;
222         XmFontList       font_list;
223         Atom             pixel_atom = XmInternAtom(dpy, "PIXEL_SIZE", FALSE);
224
225         /* First get the pixel size from the User Font */
226         if (userfont->cf_type == XmFONT_IS_FONT) {
227                 /* If we can't get the pixel size from the user font we
228                  * defaults to a 12 pixel font.
229                  */
230                 if (!XGetFontProperty(userfont->f.cf_font, pixel_atom, 
231                                                         &pixel_size))
232                         pixel_size = 12;
233         } else {
234                 XFontStruct     **font_struct_list;
235                 char            **font_name_list;
236                 int               list_size;
237
238                 if (!(list_size = XFontsOfFontSet(userfont->f.cf_fontset,
239                                             &font_struct_list,
240                                             &font_name_list))) {
241                         pixel_size = 12;
242                 } else {
243                         int i;
244                         if (!XGetFontProperty(font_struct_list[0],
245                                               pixel_atom, 
246                                               &pixel_size))
247                                 pixel_size = 12;
248                 }
249         }
250
251         /* If the font family is not ``application'' then it is probably
252          * multibyte so we can't assume there is an add-style or a proportional
253          * version available.
254          */
255         if (!strcmp(cal->app_data->app_font_family, "application")) {
256                 sprintf (font_name, "-dt-%s-%s-r-normal-sans-%d-*-*-*-p-*",
257                                 cal->app_data->app_font_family,
258                                 (weight == BOLD)?"bold":"medium",
259                                 pixel_size);
260         } else {
261                 sprintf (font_name, "-dt-%s-%s-r-normal--%d-*-*-*-*-*",
262                                 cal->app_data->app_font_family,
263                                 (weight == BOLD)?"bold":"medium",
264                                 pixel_size);
265         }
266
267         /* See if the font exists */
268         font_names = XListFonts(dpy, font_name, 1, &nnames);
269         if (!nnames) {
270                 if (!ProbeForFont(cal, weight, pixel_size, TRUE, 
271                                                         font_name_ptr)) {
272                         /* We didn't find anything */
273                         *return_font = *userfont;
274                         return;
275                 }
276         } else
277                 XFreeFontNames(font_names);
278
279         strcat(font_name, ":");
280         in_font.size = strlen(font_name);
281         in_font.addr = font_name;
282         out_fontlist.size = sizeof(XmFontList);
283         out_fontlist.addr = (XPointer)&font_list;
284
285         /* Convert font string to a font list. */
286         if (!XtConvertAndStore(cal->frame, XtRString, &in_font, XmRFontList,
287                                 &out_fontlist)) {
288                 *return_font = *userfont;
289         }
290
291         if (!fontlist_to_font(font_list, return_font)) {
292                 *return_font = *userfont;
293         }
294 }
295
296 /*
297  * Given a font or fontset, return the extents of the text.
298  */
299 void
300 CalTextExtents(
301         Cal_Font        *font,
302         char            *string,
303         int              nbytes,
304         int             *x_return,
305         int             *y_return,
306         int             *width_return,
307         int             *height_return)
308 {
309         
310         if (!font) return;
311
312         if (font->cf_type == XmFONT_IS_FONT) {
313                 int             direction,
314                                 ascent,
315                                 descent;
316                 XCharStruct     overall;
317
318                 XTextExtents(font->f.cf_font, string, nbytes,
319                                 &direction, &ascent, &descent, &overall);
320
321                 *x_return = overall.lbearing;
322                 *y_return = overall.ascent;
323                 *width_return = overall.width;
324                 *height_return = overall.ascent + overall.descent;
325         } else {
326                 XRectangle      ink,
327                                 logical;
328
329                 XmbTextExtents(font->f.cf_fontset, string, nbytes,
330                                 &ink, &logical);
331
332                 *x_return = logical.x;
333                 *y_return = logical.y;
334                 *width_return = logical.width;
335                 *height_return = logical.height;
336         }
337 }
338
339 /*
340  * Given a font or fontset, render the text.
341  */
342 void
343 CalDrawString(
344         Display         *dpy,
345         Drawable         draw,
346         Cal_Font        *font,
347         GC               gc,
348         int              x,
349         int              y,
350         char            *string,
351         int              length)
352 {
353
354         if (font->cf_type == XmFONT_IS_FONT) {
355                 XSetFont(dpy, gc, font->f.cf_font->fid);
356                 XDrawString(dpy, draw, gc, x, y, string, length);
357         } else {
358                 XmbDrawString(dpy, draw, font->f.cf_fontset, gc, x, y, 
359                                                         string, length);
360         }
361 }
362
363 void
364 CalFontExtents(
365         Cal_Font        *font,
366         XFontSetExtents *fse)
367 {
368         if (font->cf_type == XmFONT_IS_FONT) {
369                 /*
370                  * These computations are stolen from _XsimlCreateFontSet()
371                  * in Xlib.
372                  */
373                 fse->max_ink_extent.x = font->f.cf_font->min_bounds.lbearing;
374                 fse->max_ink_extent.y = - font->f.cf_font->max_bounds.ascent;
375                 fse->max_ink_extent.width = font->f.cf_font->min_bounds.width;
376                 fse->max_ink_extent.height = 
377                                          font->f.cf_font->max_bounds.ascent +
378                                          font->f.cf_font->max_bounds.descent;
379
380                 fse->max_logical_extent.x = 0;
381                 fse->max_logical_extent.y = - font->f.cf_font->ascent;
382                 fse->max_logical_extent.width = 
383                                          font->f.cf_font->max_bounds.width;
384                 fse->max_logical_extent.height = 
385                                          font->f.cf_font->ascent +
386                                          font->f.cf_font->descent;
387         } else {
388                 *fse = *XExtentsOfFontSet(font->f.cf_fontset);
389         }
390 }