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