/*
 * UX11 Utiltity Functions
 */

#include <stdio.h>
#include <strings.h>
#include "ux11.h"
#include "ux11_internal.h"
#include <X11/Xatom.h>

#define MAX_FONTS	100

int ux11_find_font(disp, scrn_num, pat, good_func, data_p, rtn_font, rtn_name)
Display *disp;			/* What display to examine */
int scrn_num;			/* Screen number           */
char *pat;			/* Font pattern            */
long (*good_func)();		/* Desirablity function    */
VOID_P data_p;			/* Data to function        */
XFontStruct **rtn_font;		/* Returned font           */
char **rtn_name;		/* Font name (returned)    */
/*
 * Locates an appropriate font.  Uses `good_func' to evaluate
 * the list of fonts from the server.  `good_func' has the
 * following form:
 *   long good_func(disp, scrn_num, font, data)
 *   Display *disp;
 *   int scrn_num;
 *   XFontStruct *font;
 *   VOID_P data;
 * This should return the desirability of the font (larger values
 * mean better visuals).  The `data' parameter is passed to
 * the function unchanged.  Returns a non-zero status if successful.
 */
{
    int font_count, i;
    long max_eval, eval;
    char **font_list;
    XFontStruct *font_data, *chosen_data;

    font_list = XListFonts(disp, pat, MAX_FONTS, &font_count);
    if (font_count <= 0) return 0;

    font_data = XLoadQueryFont(disp, font_list[0]);
    max_eval = (*good_func)(disp, scrn_num, font_data, data_p);
    *rtn_name = font_list[0];
    *rtn_font = font_data;

    for (i = 1;  i < font_count;  i++) {
	font_data = XLoadQueryFont(disp, font_list[i]);
	if (font_data) {
	    if ((eval = (*good_func)(disp, scrn_num, font_data, data_p)) > max_eval) {
		max_eval = eval;
		*rtn_name = font_list[i];
		XFreeFont(disp, *rtn_font);
		*rtn_font = font_data;
	    } else {
		XFreeFont(disp, font_data);
	    }
	}
    }
    *rtn_name = strcpy(malloc((unsigned) (strlen(*rtn_name)+1)), *rtn_name);
    XFreeFontNames(font_list);
    return 1;
}



typedef struct font_size_defn {
    long micrometers;		/* Size in micrometers (10e-6 meters) */
} font_size;

#define MAX_VALUE	23400L
#define ABS(val)	((val) < 0 ? (-(val)) : (val))

static long ux11_size_eval(disp, scrn_num, font, data)
Display *disp;			/* Display          */
int scrn_num;			/* Screen number    */
XFontStruct *font;		/* Font to examine  */
VOID_P data;			/* Data to function */
/*
 * This routine examines the font `font' and returns an evaluation
 * of it based on size.  The size is passed in as `data'.  If it
 * is close between fonts,  whether one is proportionally spaced
 * counts for a few more points.
 */
{
    font_size *desired_size = (font_size *) data;
    double um_per_pixel;
    long height;

    um_per_pixel = ((double) (DisplayHeightMM(disp, scrn_num) * 1000)) /
      ((double) DisplayHeight(disp, scrn_num));
    height = (int) ((((double)
		      (font->max_bounds.ascent + font->max_bounds.descent))
		     * um_per_pixel) + 0.5);
    return  (MAX_VALUE - ABS(height - desired_size->micrometers)) +
      (font->per_char ? 300 : 0);
}

int ux11_size_font(disp, scrn_num, size, rtn_font, rtn_name)
Display *disp;			/* What display to examine */
int scrn_num;			/* Screen number           */
long size;			/* Font size (micrometers) */
XFontStruct **rtn_font;		/* Returned font           */
char **rtn_name;		/* Returned name           */
/*
 * Finds the closest font supported on the indicated screen of
 * the supplied display whose size is `size' measured in micrometers.
 * The font is returned in `rtn_font' and its name is returned
 * in `rtn_name'.  The routine returns a non-zero status if
 * successful.  Only normal roman style fonts are examined.
 */
{
    font_size data;

    data.micrometers = size;
    return ux11_find_font(disp, scrn_num,
			  "*-medium-r-normal-*", ux11_size_eval, (VOID_P) &data,
			  rtn_font, rtn_name);
}
