/* windMain.c -
 *
 *	This package implements overlapping windows for the
 *	Magic VLSI layout system.
 *
 * Design:
 *	Windows are structures that are kept in a doubly linked list.
 *	Windows near the front of the list are on top of windows further
 *	towards the tail of the list.  Each window has some information
 *	about what is in the window, as well as the size of the window
 *	(both unclipped and clipped to accomodate windows that overlay it).
 *	Transforms control what portion of the window's contents show up
 *	on the screen, and at what magnification.
 *
 *	Each window is owned by a client (the database, a menu package, etc.).
 *	The window package is notified of a new client by the AddClient
 *	call.  The client supplies routines to redisplay the contents of
 *	a window, and to do other things with the window (such as delete it).
 *	Each window is a view onto a surface maintained by the client.  The
 *	client may be asked to redisplay any part of this surface at any time.
 *	The client must also supply each window with an ID that uniquely
 *	identifies the surface.
 *
 *	There are currently two types of window packages supported:  Magic
 *	windows (implemented here) and Sun Windows.  In Magic windows, all
 * 	windows use the screen's coordinate system.  In Sun Windows, each
 *	window has it's own coordinate system with (0, 0) being at the lower
 *	left corner.  Also, under Sun Windows some of the screen managment
 *	stuff (such as clipping to obscuring areas and drawing of the
 *	screen background color) is ignored by us.
 *
 *
 *     ********************************************************************* 
 *     * Copyright (C) 1985, 1990 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.  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.  Export of this software outside     * 
 *     * of the United States of America may require an export license.    * 
 *     *********************************************************************
 */

#ifndef lint
static char rcsid[]="$Header: /ufs/repository/magic/windows/windMain.c,v 1.2 2001/01/12 22:13:35 jsolomon Exp $";
#endif  not lint

#include <stdio.h>
#include "misc/magic.h"
#include "utils/geometry.h"
#include "graphics/glyphs.h"
#include "windows/windows.h"
#include "windows/windInt.h"
#include "utils/stack.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "textio/textio.h"
#include "graphics/graphics.h"
#include "utils/malloc.h"

/* The type of windows that this package will implement */
int WindPackageType = WIND_MAGIC_WINDOWS;

/* The size of our scroll bars -- may be set externally (see windows.h)
 */
int WindScrollBarWidth = 7;

/* ------ Internal variables that are global within the window package ----- */
clientRec *windFirstClientRec = NULL;	/* the head of the linked list 
					 * of clients 
					 */
MagWindow *windTopWindow = NULL;		/* the topmost window */
MagWindow *windBottomWindow = NULL;	/* ...and the bottom window */
extern Plane *windRedisplayArea;	/* See windDisplay.c for details. */


/*
 * ----------------------------------------------------------------------------
 * WindInit --
 *
 *	Initialize the window package.  No windows are created, but the
 *	package will be initialized so that it can do these things in the 
 *	future.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Variables internal to the window package are initialized.
 * ----------------------------------------------------------------------------
 */

void
WindInit()
{
    extern Stack *windGrabberStack;
    extern GrGlyphs *windGlyphs;
    Rect ts;
    char glyphName[30];

    windClientInit();
    windGrabberStack = StackNew(2);
    windRedisplayArea = DBNewPlane((ClientData) TT_SPACE);

    sprintf(glyphName, "windows%d", WindScrollBarWidth);
    if (!GrReadGlyphs(glyphName, ".", SysLibPath, &windGlyphs))
	MainExit(1);
    GrTextSize("XWyqP", GR_TEXT_DEFAULT, &ts);
    windCaptionPixels = ts.r_ytop - ts.r_ybot + 3;
    WindAreaChanged((MagWindow *) NULL, (Rect *) NULL);
}


/*
 * ----------------------------------------------------------------------------
 * WindAddClient --
 *
 *	Add a new client of the window package.  The client must supply a
 *	set of routines, as described below.
 *
 * Results:
 *	A unique ID (of type WindClient) is returned.
 *	This is used to identify the client in future calls to the window 
 *	package.
 *
 * Routines supplied:
 *
 *	( A new window was just created for this client.  Do things to
 *	  initialize the window, such as filling in the caption and making
 *	  the contents be empty. The client may refuse to create a new
 *	  window by returning FALSE, otherwise the client should return
 *	  TRUE.  The client will get passed argc and argv, with the command
 *	  name stripped off.  The client may do whatever it wants with this.
 *	  It may even modify parts of the window record -- such as changing
 *	  the window's location on the screen.)
 *
 *	bool
 *	create(w, argc, argv)
 *	    MagWindow *w;
 *	    int argc;
 *	    char *argv[];
 *	{
 *	}
 *
 *	( One of the client's windows is about to be deleted.  Do whatever
 *	  needs to be done, such as freeing up dynamically allocated data
 *	  structures. Fields manipulated by the window package, such as
 *	  the caption, should not be freed by the client.  The client should
 *	  normally return TRUE.  If the client returns FALSE, the window
 *	  manager will refuse the request to delete the window.)
 *
 *	bool
 *	delete(w)
 *	    MagWindow *w;
 *	{
 *	}
 *
 *	( Redisplay an area of the screen.  The client is passed the window,
 *	  the area in his coordinate system, and a clipping rectangle in
 *	  screen coordinates. )
 *
 *	redisplay(w, clientArea, screenArea)
 *	    MagWindow *w;
 *	    Rect *clientArea, *screenArea;
 *	{
 *	}
 *
 *
 *	( The window is about to be moved or resized.  This procedure will
 *	  be called twice.  
 *
 *	  The first time (with 'final' == FALSE), the window 
 *	  will be passed in 'w' as it is now and a suggested new w_screenarea 
 *	  is passed in 'newpos'.  The client is free to modify 'newpos' to
 *	  be whatever screen location it desires.  The routine should not 
 *	  pass 'w' to any window procedure such as windMove since 'w' has
 *	  the old transform, etc. instead of the new one.
 *
 *	  On the second call ('final' == TRUE), the window 'w' has all of
 *	  it's fields updated, newpos is equal to w->w_frameArea, and the
 *	  client is free to do things like windMove which require a window
 *	  as an argument.  It should not modify newpos.
 *
 *	reposition(w, newpos, final)
 *	    MagWindow *w;
 *	    Rect *newpos	-- new w_framearea (screen area of window)
 *	    bool final;
 *	{
 *	}
 *
 *
 *	( A command has been issued to this window.  The client should
 *	  process it.  It is split into Unix-style argc and argv words. )
 *
 *	command(w, cmd)
 *	    MagWindow *w;
 *	    TxCommand *cmd;
 *	{
 *	}
 *
 *	( A command has just finished.  Update any screen info that may have
 *	  been changed as a result. )
 *
 *	update()
 *	{
 *	}
 *
 * Side effects:
 *	Internal tables are expanded to include the new client.
 * ----------------------------------------------------------------------------
 */

WindClient
WindAddClient(clientName, create, delete, redisplay, command, update, 
exitproc, reposition, table, icon)
    char *clientName;		/* A textual name for the client.  This
				 * name will be visable in the user
				 * interface as the name to use to switch
				 * a window over to a new client
				 */
    Void (*create)();
    bool (*delete)();
    Void (*redisplay)();
    Void (*command)();
    Void (*update)();
    Void (*exitproc)();
    Void (*reposition)();
    char *(table[]);		/* A table of commands that this client
				 * is willing to accept.
				 */
    GrGlyph *icon;		/* An icon to draw when the window is closed.
				 * (currently for Sun Windows only).
				 */
{
    clientRec *res;

    ASSERT( (clientName != NULL), "WindAddClient");
    ASSERT( (command != NULL), "WindAddClient");
    ASSERT( (table != NULL), "WindAddClient");

    res = (clientRec *) mallocMagic(sizeof(clientRec));
    res->w_clientName = clientName;
    res->w_create = create;
    res->w_delete = delete;
    res->w_redisplay = redisplay;
    res->w_command = command;
    res->w_update = update;
    res->w_exit = exitproc;
    res->w_reposition = reposition;
    res->w_commandTable = table;
    res->w_icon = icon;
    res->w_nextClient = windFirstClientRec;
    windFirstClientRec = res;

    return (WindClient) res;
}


/*
 * ----------------------------------------------------------------------------
 * WindGetClient --
 *
 *	Looks up the unique ID of a client of the window package.
 *
 * Results:
 *	A variable of type WindClient is returned if the client was found,
 *	otherwise NULL is returned.
 *
 * Side effects:
 *	None.
 * ----------------------------------------------------------------------------
 */

WindClient
WindGetClient(clientName)
    char *clientName;	/* the textual name of the client */
{
    clientRec *cr, *found;
    int length;

    /* Accept any unique abbreviation. */

    found = NULL;
    length = strlen(clientName);
    for (cr = windFirstClientRec; cr != (clientRec *) NULL; 
	    cr = cr->w_nextClient)
    {
	if (strncmp(clientName, cr->w_clientName, length) == 0)
	{
	    if (found != NULL) return NULL;
	    found = cr;
	}
    }

    return (WindClient) found;
}

/*
 * ----------------------------------------------------------------------------
 * WindPrintClientList --
 *
 *	Print the name of each client of the window package.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 * ----------------------------------------------------------------------------
 */

WindPrintClientList(wizard)
    bool wizard;	/* If true print the names of ALL clients, even those
			 * that don't have user-visable windows */
{
    clientRec *cr;

    for (cr = windFirstClientRec; cr != (clientRec *) NULL; 
	    cr = cr->w_nextClient) {
	if (wizard || (cr->w_clientName[0] != '*'))
	    TxError("	%s\n", cr->w_clientName);
	}
}
