/* 
 * sxUtils.c --
 *
 *	This file provides routines and variables shared by all of
 *	the files in the sx module, but not used outside this module.
 *
 * Copyright (C) 1986, 1988 Regents of the University of California.
 * Permission to use, copy, modify, and distribute this
 * software and its documentation for any purpose and without
 * fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright
 * notice and this permission notice appear in supporting
 * documentation.  The University of California makes no
 * representations about the suitability of this software for
 * any purpose.  It is provided "as is" without express or
 * implied warranty.
 */

#ifndef lint
static char rcsid[] = "$Header: /sprite/src/lib/sx/RCS/sxUtils.c,v 1.6 90/03/12 14:51:07 ouster Exp $ SPRITE (Berkeley)";
#endif not lint

#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <sys/time.h>
#include <strings.h>
#include "sx.h"
#include "sxInt.h"

/*
 * The include below is for information about the shadow pattern.
 */

#include "bitmaps/shadow"

/*
 * The default font:
 */

static XFontStruct *defaultFontPtr = NULL;

/*
 *----------------------------------------------------------------------
 *
 * Sx_SetDefaultFont --
 *
 *	Specify a font to be used by default in all Sx routines.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	After this call, the font described in fontPtr will be
 *	used in all Sx routines whenever a font isn't specified
 *	explicitly.  The caller must ensure that the font
 *	information in *fontPtr never changes or becomes
 *	invalid.
 *
 *----------------------------------------------------------------------
 */

void
Sx_SetDefaultFont(fontPtr)
    XFontStruct *fontPtr;		/* Describes default font. */
{
    defaultFontPtr = fontPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * Sx_GetDefaultFont --
 *
 *	Provides information about the font to use when users don't
 *	care.
 *
 * Results:
 *	Returns a pointer to a FontInfo structure describing the default
 *	Sx font.  If the font couldn't be opened then NULL is returned.
 *
 * Side effects:
 *	The font gets registered with X, if it wasn't already.
 *
 *----------------------------------------------------------------------
 */

XFontStruct *
Sx_GetDefaultFont(display)
    Display *display;		/* Connection to server. */
{
    if (defaultFontPtr == NULL) {
	defaultFontPtr = XLoadQueryFont(display, "fixed");
	if (defaultFontPtr == NULL) {
	    defaultFontPtr = XLoadQueryFont(display, "8x13");
	    if (defaultFontPtr == NULL) {
		Sx_Panic(display, "Couldn't locate a default font.");
	    }
	}
    }
    return defaultFontPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * Sx_DefaultHeight --
 *
 *	Returns a "reasonable" height to use for windows that will
 *	contain text in the given font.
 *
 * Results:
 *	The return value is a suggested inside dimension for windows
 *	that will display a single line of text in fontPtr.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
Sx_DefaultHeight(display, fontPtr)
    Display *display;			/* Connection to server. */
    XFontStruct *fontPtr;		/* Font to be used for text. */
{
    if (fontPtr == NULL) {
	fontPtr = Sx_GetDefaultFont(display);
    }
    return (fontPtr->ascent + fontPtr->descent + 4);
}

/*
 *----------------------------------------------------------------------
 *
 * Sx_FocusEnabled --
 *
 *	Tell whether or not applications should use keyboard focussing.
 *
 * Results:
 *	If the "Focus" Xdefault has been set to "on", then 1 is
 *	returned as a sign to the caller that it should use keyboard
 *	focussing wherever possible.  Otherwise, 0 is returned.
 *
 * Side effects:
 *	On the first call to this procedure, the .Xdefaults file
 *	is checked.
 *
 *----------------------------------------------------------------------
 */

int
Sx_FocusEnabled(display)
    Display *display;		/* Connection to server. */
{
    static int init = 0;
    static int focusOK = 0;

    if (!init) {
	char *string;

	string = XGetDefault(display, "sx", "focus");
	if ((string != NULL) && (strcmp(string, "on") == 0)) {
	    focusOK = 1;
	}
	init = 1;
    }
    return focusOK;
}

/*
 *----------------------------------------------------------------------
 *
 * SxFlashWait --
 *
 *	This procedure flushes X output and waits the "correct"
 *	amount of time for a button or menu entry to flash on or
 *	off.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Time goes by.  Also, X output gets flushed.
 *
 *----------------------------------------------------------------------
 */

void
SxFlashWait(display)
    Display *display;		/* Connection to server. */
{
    static struct timeval delay = {0, 50000};

    XFlush(display);
    (void) select(0, (int *) 0, (int *) 0, (int *) 0, &delay);
}

/*
 *----------------------------------------------------------------------
 *
 * SxDrawShadow --
 *
 *	This procedure is used to draw boxes with shadows underneath
 *	them, like the box around a pull-down menu or a notifier.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	A box gets drawn with a shadow around its right and bottom
 *	edges.  At the end of this procedure, the fill_style of gc
 *	is set to FillSolid and gc's stipple gets trashed.
 *
 *----------------------------------------------------------------------
 */

void
SxDrawShadow(display, w, gc, x, y, width, height)
    Display *display;		/* Connection to X server. */
    Window w;			/* Window in which to draw shadowed box. */
    GC gc;			/* Graphics context for drawing.  Fill_style
				 * must be FillSolid. */
    int x, y;			/* UL corner of shadowed box (gives location
				 * of outside pixel of box/shadow). */
    int width, height;		/* Dimensions of useable area INSIDE
				 * shadowed box. */
{
    static Pixmap shadowPixmap = 0;

    XFillRectangle(display, w, gc, x, y,
	    width + 2*SHADOW_BORDER, SHADOW_BORDER);
    XFillRectangle(display, w, gc, x, y,
	    SHADOW_BORDER, height + 2*SHADOW_BORDER);
    XFillRectangle(display, w, gc, x + width + SHADOW_BORDER, y,
	    SHADOW_BORDER, height + 2*SHADOW_BORDER);
    XFillRectangle(display, w, gc, x, y + height + SHADOW_BORDER,
	    width + 2*SHADOW_BORDER, SHADOW_BORDER);
    
    if (shadowPixmap == 0) {
	shadowPixmap = XCreateBitmapFromData(display,
		RootWindow(display, DefaultScreen(display)),
		shadow_bits, shadow_width, shadow_height);
    }

    XSetFillStyle(display, gc, FillStippled);
    XSetStipple(display, gc, shadowPixmap);
    XFillRectangle(display, w, gc, x + SHADOW_WIDTH,
	    y + height + 2*SHADOW_BORDER, width + 2*SHADOW_BORDER,
	    SHADOW_WIDTH);
    XFillRectangle(display, w, gc, x + width + 2*SHADOW_BORDER,
	    y + SHADOW_WIDTH, SHADOW_WIDTH, height + 2*SHADOW_WIDTH);
    XSetFillStyle(display, gc, FillSolid);
}

/*
 *----------------------------------------------------------------------
 *
 * Sx_NullProc --
 *
 *	Does nothing but return zero.
 *
 * Results:
 *	0.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
Sx_NullProc()
{
    return 0;
}

/*
 *----------------------------------------------------------------------
 *
 * SxUnmapCarefully --
 *
 *	Unmap a window, ignoring any errors that might occur because
 *	the window doesn't exist.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Window gets unmapped, if it exists.
 *
 *----------------------------------------------------------------------
 */

void
SxUnmapCarefully(display, window)
    Display *display;			/* Connection to server. */
    Window window;			/* Window to unmap. */
{
    /*
     * This procedure assumes that Sx_SetErrorHandler has already
     * been called, which makes life pretty easy.
     */

    XUnmapWindow(display, window);
}

/*
 *----------------------------------------------------------------------
 *
 * Sx_SetErrorHandler --
 *
 *	Replace the standard X error handler with a new one that
 *	will ignore all "bad window" errors.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	A new error handler is installed.
 *
 *----------------------------------------------------------------------
 */

static int (*savedHandler)();
void
Sx_SetErrorHandler()
{
    extern int SxErrorHandler();		/* Forward reference. */
    extern int (*_XErrorFunction)();
    extern int _XDefaultError();

    if (_XErrorFunction != SxErrorHandler) {
	savedHandler = _XErrorFunction;
	if (savedHandler == NULL) {
	    savedHandler = _XDefaultError;
	}
	_XErrorFunction = SxErrorHandler;
    }
}

int
SxErrorHandler(display, errorPtr)
    Display *display;			/* Connection to server. */
    XErrorEvent *errorPtr;		/* Event that occurred. */
{
    if ((errorPtr->error_code == BadWindow)
	    || (errorPtr->error_code == BadDrawable)) {
	return 0;
    }
    return (*savedHandler)(display, errorPtr);
}
