/* Initialization for the tcl/tk interface to Xconq.
   Copyright (C) 1998, 1999 Stanley T. Shebs.

Xconq is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.  See the file COPYING.  */

#include "conq.h"
#include "tkconq.h"

extern ImageFamily *get_generic_images();

XColor *request_color(char *name);
void set_colors(void);
void init_emblem(Side *side2);

#ifndef __STDC__
void abort ();
#endif

Pixmap tranpics[NUMPOWERS];
Pixmap bordpics[NUMPOWERS];
Pixmap connpics[NUMPOWERS];
Pixmap windpics[5][NUMDIRS];
Pixmap antpic;

static void set_optional_colors(void);
static void init_cursors(void);
static Tk_Cursor make_cursor(Tk_Window tkwin, char *cursbits, char *maskbits, int x, int y);
static void init_bitmaps(void);

static void init_unit_images(void);
static void init_terrain_images(void);
static void init_emblem_images(void);
static void report_missing_images(void);
static void tk_describe_image PARAMS ((Side *side, Image *img));

#if 0
static char *variant_default PARAMS ((Variant *var));
static char *variant_name PARAMS ((Variant *var));
static void implement_variant PARAMS ((char *value, Variant *var));
static int valid_variant PARAMS ((char *value, Variant *var));
static int type_player PARAMS ((char *value));
static void init_assignw_player PARAMS ((Assignw *assignw, Player *player));
static int can_open_display PARAMS ((char *dpyname));
static int boolean_lisp PARAMS ((char *value));
#endif

extern char *tclbuf;

static int loop, chosen_game;

/* we could share this buffers with other modules */
char buf1[BUFSIZE], buf2[BUFSIZE], buf3[BUFSIZE], errormess[BUFSIZE];

Obj *variants;

char *imflib = IMFLIB;

/* Display and window globals used in callbacks from generic imf
   handling code. */

extern int tmp_valid;

extern Tk_Window tmp_root_window;

/* How much space to leave for a unit image, if all images should get
   the same amount (such as for a list of unit types). */

int min_w_for_unit_image = 16;
int min_h_for_unit_image = 16;

/* various bitmap definitions. */
#include "bitmaps/lookglass.b"
#include "bitmaps/lookmask.b"
#include "bitmaps/movecurs.b"
#include "bitmaps/movemask.b"
#include "bitmaps/shootcurs.b"
#include "bitmaps/shootmask.b"
#include "bitmaps/buildcurs.b"
#include "bitmaps/buildmask.b"

#include "bitmaps/closer.b"
#include "bitmaps/farther.b"

#if 0
#include "bitmaps/gray.b"
#include "bitmaps/darkgray.b"
#endif

#include "bitmaps/hex16.b"
#include "bitmaps/hex16b.b"
#include "bitmaps/hex32.b"
#include "bitmaps/hex32b.b"
#include "bitmaps/hex64.b"
#include "bitmaps/hex64b.b"

#include "bitmaps/tran16.b"
#include "bitmaps/tran32.b"

#include "bitmaps/bord16.b"
#include "bitmaps/bord32.b"
#include "bitmaps/bord64.b"

#include "bitmaps/conn16.b"
#include "bitmaps/conn32.b"

#include "bitmaps/wind0.b"
#include "bitmaps/wind1ne.b"
#include "bitmaps/wind1e.b"
#include "bitmaps/wind1se.b"
#include "bitmaps/wind1sw.b"
#include "bitmaps/wind1w.b"
#include "bitmaps/wind1nw.b"
#include "bitmaps/wind2ne.b"
#include "bitmaps/wind2e.b"
#include "bitmaps/wind2se.b"
#include "bitmaps/wind2sw.b"
#include "bitmaps/wind2w.b"
#include "bitmaps/wind2nw.b"
#include "bitmaps/wind3ne.b"
#include "bitmaps/wind3e.b"
#include "bitmaps/wind3se.b"
#include "bitmaps/wind3sw.b"
#include "bitmaps/wind3w.b"
#include "bitmaps/wind3nw.b"
#include "bitmaps/wind4ne.b"
#include "bitmaps/wind4e.b"
#include "bitmaps/wind4se.b"
#include "bitmaps/wind4sw.b"
#include "bitmaps/wind4w.b"
#include "bitmaps/wind4nw.b"


#include "bitmaps/miss.b"
#include "bitmaps/hit.b"
#include "bitmaps/kill.b"

#include "bitmaps/dots.b"
#include "bitmaps/ants.b"

#include "bitmaps/laurels.b"

#ifdef DESIGNERS
#include "bitmaps/curscell.b"
#include "bitmaps/curscellm.b"
#include "bitmaps/cursbord.b"
#include "bitmaps/cursbordm.b"
#include "bitmaps/cursconn.b"
#include "bitmaps/cursconnm.b"
#include "bitmaps/curscoat.b"
#include "bitmaps/curscoatm.b"
#include "bitmaps/cursunit.b"
#include "bitmaps/cursunitm.b"
#include "bitmaps/curspeop.b"
#include "bitmaps/curspeopm.b"
#include "bitmaps/cursfeat.b"
#include "bitmaps/cursfeatm.b"
#include "bitmaps/cursmaterial.b"
#include "bitmaps/cursmaterialm.b"
#include "bitmaps/curselev.b"
#include "bitmaps/curselevm.b"
#include "bitmaps/curstemp.b"
#include "bitmaps/curstempm.b"
#include "bitmaps/cursclouds.b"
#include "bitmaps/curscloudsm.b"
#include "bitmaps/curswinds.b"
#include "bitmaps/curswindsm.b"
#include "bitmaps/cursview.b"
#include "bitmaps/cursviewm.b"
#endif /* DESIGNERS */

void
init_ui(side)
Side *side;
{
    if (side_wants_display(side)) {
        side->ui = (UI *) xmalloc(sizeof(UI));
	Dprintf("One UI is %d bytes.\n", sizeof(UI));
    } else {
	side->ui = NULL;
    }
}

/* Open display, create all the windows we'll need, do misc setup
   things, and initialize some globals to out-of-range values for
   recognition later. */

int toplevel_display_used = FALSE;

void
init_display()
{
    int argc, p, u, t, s, depth;
    char *dpyname, *str;
    Display *dpy;

    dpyname = dside->player->displayname;

    Dprintf("Will try to open %s display `%s'...\n",
	    side_desig(dside), dpyname);

    /* Detect the placeholder for the default display. */
    if (strcmp("_", dpyname) == 0)
      dpyname = getenv("DISPLAY");

    /* Set up things shared by all the windows. */
    dside->ui->dflt_color_terr_images = TRUE;
    dside->ui->dflt_color_unit_images = TRUE;
    dside->ui->dflt_color_embl_images = TRUE;
    dside->ui->default_latlong_interval = 600;
#if 0
    dside->ui->bonw = BLACKONWHITE;
    depth = XDisplayCells(dpy, dside->ui->screen);
    DGprintf("%d different colors available ...\n", depth);
    dside->ui->monochrome = (depth <= 2);
#endif
    for (p = 0; p < NUMPOWERS; ++p) {
	for_all_terrain_types(t) {
	    /* Decide what display technique to use at each power. */
	    dside->ui->terrpics[p][t] = None;
	    dside->ui->terrchars[p][t] = '\0';
	}
	for_all_unit_types(u) {
	    dside->ui->unitpics[p][u] = None;
	    dside->ui->unitmasks[p][u] = None;
	    dside->ui->unitchars[p][u] = '\0';
#if 0
	    dside->ui->ulegendfonts[p][u] = NULL;
#endif
	}
    }
    for (s = 0; s < MAXSIDES; ++s) {
	dside->ui->emblempics[s] = None;
	dside->ui->emblemmasks[s] = None;
    }
    set_colors();
    tmp_root_window = Tk_MainWindow(interp);
    tmp_valid = TRUE;
    init_unit_images();
    init_terrain_images();
    init_emblem_images();
    init_other_images();
    tmp_valid = FALSE;
    report_missing_images();
    imf_describe_hook = tk_describe_image;
    set_optional_colors();
    init_bitmaps();
    init_cursors();
    update_view_controls_info();

    /* Create the generic windows. */
    dside->ui->maps = NULL;

    create_map();

#ifdef DESIGNERS
    /* If this side is already a designer (perhaps via command-line option)
       popup the design controls now. */
    if (dside->designer)
      really_do_design(dside);
#endif /* DESIGNERS */

    Dprintf("Successfully initialized `%s'!\n", dpyname);
}

/* This will set up the correct set of colors at any point in the game.
   Colors are all specified by name; if any are not available, it is up to
   the graphics interface to supply a substitute. */

void
set_colors()
{
    int	t;

    dside->ui->fgcolor = request_color("black");
    dside->ui->bgcolor = request_color("white");
    dside->ui->whitecolor = request_color("white");
    dside->ui->blackcolor = request_color("black");
    dside->ui->diffcolor = dside->ui->blackcolor;
    dside->ui->graycolor = dside->ui->whitecolor;
    dside->ui->badcolor = dside->ui->whitecolor;
    dside->ui->warncolor = dside->ui->whitecolor;
    dside->ui->grid_color = dside->ui->fgcolor;
    dside->ui->unseen_color = dside->ui->fgcolor;
    dside->ui->contour_color = dside->ui->fgcolor;
    dside->ui->country_border_color = dside->ui->fgcolor;
    dside->ui->feature_color = dside->ui->fgcolor;
    dside->ui->frontline_color = dside->ui->fgcolor;
    dside->ui->meridian_color = dside->ui->fgcolor;
    dside->ui->shoreline_color = dside->ui->fgcolor;
    dside->ui->unit_name_color = dside->ui->fgcolor;
    /* Set colors to distinctive default; will set usefully later. */
    for_all_terrain_types(t) {
	dside->ui->cellcolor[t] = NULL;
    }
}

/* This will set up colors that are not crucial to the game.  By doing
   after basic image color allocation, these won't suck up colormap
   space that should go to images. */

static void
set_optional_colors()
{
    XColor *color;

    if (!dside->ui->monochrome) {
	if ((color = request_color("maroon")) != NULL)
	  dside->ui->diffcolor = color;
	if ((color = request_color("light gray")) != NULL)
	  dside->ui->graycolor = color;
	if ((color = request_color(g_contour_color())) != NULL)
	  dside->ui->contour_color = color;
	if ((color = request_color(g_country_border_color())) != NULL)
	  dside->ui->country_border_color = color;
#if 0 /* need to work with a list here */
	dside->ui->feature_color = request_color(g_feature_color());
#endif
	if ((color = request_color(g_frontline_color())) != NULL)
	  dside->ui->frontline_color = color;
	if ((color = request_color(g_meridian_color())) != NULL)
	  dside->ui->meridian_color = color;
	if ((color = request_color(g_shoreline_color())) != NULL)
	  dside->ui->shoreline_color = color;
	if ((color = request_color(g_unit_name_color())) != NULL)
	  dside->ui->unit_name_color = color;
	if ((color = request_color("red")) != NULL)
	  dside->ui->badcolor = color;
	if ((color = request_color("yellow")) != NULL)
	  dside->ui->warncolor = color;
    }
}

/* Collect all the names of types etc for which no images could be found,
   report them all at once. */

static void
report_missing_images()
{
    int u, t, e;
    Side *side2;

    for_all_terrain_types(t) {
	if (dside->ui->timages[t] == NULL
	    || dside->ui->timages[t]->ersatz)
	  record_missing_image(TTYP, t_type_name(t));
    }
    for_all_unit_types(u) {
	if (dside->ui->uimages[u] == NULL
	    || dside->ui->uimages[u]->ersatz)
	  record_missing_image(UTYP, u_type_name(u));
    }
    for_all_sides(side2) {
	e = side_number(side2);
	if (dside->ui->eimages[e] == NULL
	    || dside->ui->eimages[e]->ersatz)
	  record_missing_image(3, side_desig(dside));
    }
    if (missing_images(tmpbuf))
      init_warning("Could not find %s", tmpbuf);
}

/* A predicate that tests whether our display can safely be written to. */

int
active_display(side)
Side *side;
{
    return (side && side->ui && side->ui->active);
}

/* Make all the different kinds of cursors we intend to use.  Should be
   one for each kind of mode or tool.  Cursors should always be 16x16. */

static void
init_cursors()
{
    int i;
    Tk_Window rootwin = Tk_MainWindow(interp);
    Display *dpy = Tk_Display(rootwin);

    Tk_MakeWindowExist(rootwin);

    for (i = 0; i < nummodes; ++i)
      dside->ui->cursors[i] = None;
    dside->ui->cursors[survey_mode] =
      make_cursor(rootwin, lookglass_bits, lookmask_bits,
		  lookglass_x_hot, lookglass_y_hot);
    dside->ui->cursors[move_mode] =
      make_cursor(rootwin, shootcursor_bits, shootmask_bits,
		  shootcursor_x_hot, shootcursor_y_hot);
#if 0
    dside->ui->cursors[unitmovetool] =
      make_cursor(rootwin, movecursor_bits, movemask_bits,
		  movecursor_x_hot, movecursor_y_hot);
#endif
    dside->ui->cursors[fire_mode] =
      make_cursor(rootwin, shootcursor_bits, shootmask_bits,
		  shootcursor_x_hot, shootcursor_y_hot);
    dside->ui->cursors[build_mode] =
      make_cursor(rootwin, buildcursor_bits, buildmask_bits,
		  buildcursor_x_hot, buildcursor_y_hot);
#ifdef DESIGNERS
    dside->ui->cursors[cell_paint_mode] =
      make_cursor(rootwin, curscell_bits, curscellm_bits,
		  curscell_x_hot, curscell_y_hot);
    dside->ui->cursors[bord_paint_mode] =
      make_cursor(rootwin, cursbord_bits, cursbordm_bits,
		  cursbord_x_hot, cursbord_y_hot);
    dside->ui->cursors[conn_paint_mode] =
      make_cursor(rootwin, cursconn_bits, cursconnm_bits,
		  cursconn_x_hot, cursconn_y_hot);
    dside->ui->cursors[coat_paint_mode] =
      make_cursor(rootwin, curscoat_bits, curscoatm_bits,
		  curscoat_x_hot, curscoat_y_hot);
    dside->ui->cursors[unit_paint_mode] =
      make_cursor(rootwin, cursunit_bits, cursunitm_bits,
		  cursunit_x_hot, cursunit_y_hot);
    dside->ui->cursors[people_paint_mode] =
      make_cursor(rootwin, curspeop_bits, curspeopm_bits,
		  curspeop_x_hot, curspeop_y_hot);
    dside->ui->cursors[control_paint_mode] =
      make_cursor(rootwin, curspeop_bits, curspeopm_bits,
		  curspeop_x_hot, curspeop_y_hot);
    dside->ui->cursors[feature_paint_mode] =
      make_cursor(rootwin, cursfeat_bits, cursfeatm_bits,
		  cursfeat_x_hot, cursfeat_y_hot);
    dside->ui->cursors[material_paint_mode] =
      make_cursor(rootwin, cursmaterial_bits, cursmaterialm_bits,
		  cursmaterial_x_hot, cursmaterial_y_hot);
    dside->ui->cursors[elevation_paint_mode] =
      make_cursor(rootwin, curselev_bits, curselevm_bits,
		  curselev_x_hot, curselev_y_hot);
    dside->ui->cursors[temperature_paint_mode] =
      make_cursor(rootwin, curstemp_bits, curstempm_bits,
		  curstemp_x_hot, curstemp_y_hot);
    dside->ui->cursors[clouds_paint_mode] =
      make_cursor(rootwin, cursclouds_bits, curscloudsm_bits,
		  cursclouds_x_hot, cursclouds_y_hot);
    dside->ui->cursors[winds_paint_mode] =
      make_cursor(rootwin, curswinds_bits, curswindsm_bits,
		  curswinds_x_hot, curswinds_y_hot);
    dside->ui->cursors[view_paint_mode] =
      make_cursor(rootwin, cursview_bits, cursviewm_bits,
		  cursview_x_hot, cursview_y_hot);
#endif /* DESIGNERS */
    DGprintf("Cursors stored ...\n");
}

static Tk_Cursor
make_cursor(Tk_Window tkwin, char *cursbits, char *maskbits, int x, int y)
{
    return Tk_GetCursorFromData(interp, tkwin, cursbits, maskbits, 16, 16,
				x, y, Tk_GetUid("black"), Tk_GetUid("white"));
}

/* Get a pointer to the color of the given name. */

XColor *
request_color(char *name)
{
    XColor *rslt;
    Tk_Window tkwin = Tk_MainWindow(interp);

    DGprintf("Requesting color %s\n", (name ? name : "<null>"));
    /* This might be called to get user-specified colors, even on a mono
       display, so deal with it. */
    if (empty_string(name)) {
	init_warning(
          "Requesting anonymous color on display \"%s\", substituting white",
		     dside->player->displayname);
	rslt = Tk_GetColor(interp, tkwin, Tk_GetUid("white"));
    } else if (dside->ui->monochrome) {
	if (strcmp("white", name) == 0) {
	    rslt = Tk_GetColor(interp, tkwin, Tk_GetUid("white"));
	} else if (strcmp("black", name) == 0) {
	    rslt = Tk_GetColor(interp, tkwin, Tk_GetUid("black"));
	} else {
	    init_warning(
              "No color \"%s\" on the mono display \"%s\", substituting white",
			 name, dside->player->displayname);
	    rslt = Tk_GetColor(interp, tkwin, Tk_GetUid("white"));
	}
    } else {
	/* Try the generic Tk mechanism first. */
	rslt = Tk_GetColor(interp, tkwin, Tk_GetUid(name));
	/* Now try the imf library. */
	if (rslt == NULL) {
	    int dummy, red, grn, blu;
	    ImageFamily *imf = get_generic_images(dside, name);
	    Image *img;
	    XColor col;

	    if (imf != NULL
		&& imf->numsizes > 0
		&& imf->images != NULL
		&& imf->images->w == 1
		&& imf->images->h == 1
		&& imf->images->palette != lispnil) {
		img = imf->images;
		parse_lisp_palette_entry(car(img->palette),
					 &dummy, &red, &grn, &blu);
		col.red = red;  col.green = grn;  col.blue = blu;
		rslt = Tk_GetColorByValue(tkwin, &col);
	    }
	}
    }
    if (rslt == NULL)
      init_warning("Request for \"%s\" failed", name);
    return rslt;
}

static void
init_bitmaps()
{
    int i, dir;
    Tk_Window rootwin = Tk_MainWindow(interp);
    Display *dpy = Tk_Display(rootwin);

    Tk_MakeWindowExist(rootwin);

    /* Get the solid hex outlines. */
    Tk_DefineBitmap(interp, Tk_GetUid("hex16"),
		    hex16_bits, hex16_width, hex16_height);
    dside->ui->hexpics[4] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("hex16"));
    Tk_DefineBitmap(interp, Tk_GetUid("hex16b"),
		    hex16b_bits, hex16b_width, hex16b_height);
    dside->ui->bhexpics[4] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("hex16b"));
    Tk_DefineBitmap(interp, Tk_GetUid("hex32"),
		    hex32_bits, hex32_width, hex32_height);
    dside->ui->hexpics[5] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("hex32"));
    Tk_DefineBitmap(interp, Tk_GetUid("hex32b"),
		    hex32b_bits, hex32b_width, hex32b_height);
    dside->ui->bhexpics[5] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("hex32b"));
    Tk_DefineBitmap(interp, Tk_GetUid("hex64"),
		    hex64_bits, hex64_width, hex64_height);
    dside->ui->hexpics[6] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("hex64"));
    Tk_DefineBitmap(interp, Tk_GetUid("hex64b"),
		    hex64b_bits, hex64b_width, hex64b_height);
    dside->ui->bhexpics[6] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("hex64b"));

    Tk_DefineBitmap(interp, Tk_GetUid("tran16"),
		    tran16_bits, tran16_width, tran16_height);
    tranpics[4] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("tran16"));
    Tk_DefineBitmap(interp, Tk_GetUid("tran32"),
		    tran32_bits, tran32_width, tran32_height);
    tranpics[5] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("tran32"));


    Tk_DefineBitmap(interp, Tk_GetUid("bord16"),
		    bord16_bits, bord16_width, bord16_height);
    bordpics[4] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("bord16"));
    Tk_DefineBitmap(interp, Tk_GetUid("bord32"),
		    bord32_bits, bord32_width, bord32_height);
    bordpics[5] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("bord32"));
    Tk_DefineBitmap(interp, Tk_GetUid("bord64"),
		    bord64_bits, bord64_width, bord64_height);
    bordpics[6] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("bord64"));

    Tk_DefineBitmap(interp, Tk_GetUid("conn16"),
		    conn16_bits, conn16_width, conn16_height);
    connpics[4] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("conn16"));
    Tk_DefineBitmap(interp, Tk_GetUid("conn32"),
		    conn32_bits, conn32_width, conn32_height);
    connpics[5] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("conn32"));

    Tk_DefineBitmap(interp, Tk_GetUid("wind0"),
		    wind0_bits, wind0_width, wind0_height);
    for_all_directions(dir) {
	windpics[0][dir] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind0"));
    }
    Tk_DefineBitmap(interp, Tk_GetUid("wind1ne"),
		    wind1ne_bits, wind1ne_width, wind1ne_height);
    windpics[1][NORTHEAST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind1ne"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind1e"),
		    wind1e_bits, wind1e_width, wind1e_height);
    windpics[1][EAST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind1e"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind1se"),
		    wind1se_bits, wind1se_width, wind1se_height);
    windpics[1][SOUTHEAST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind1se"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind1sw"),
		    wind1sw_bits, wind1sw_width, wind1sw_height);
    windpics[1][SOUTHWEST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind1sw"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind1w"),
		    wind1w_bits, wind1w_width, wind1w_height);
    windpics[1][WEST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind1w"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind1nw"),
		    wind1nw_bits, wind1nw_width, wind1nw_height);
    windpics[1][NORTHWEST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind1nw"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind2ne"),
		    wind2ne_bits, wind2ne_width, wind2ne_height);
    windpics[2][NORTHEAST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind2ne"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind2e"),
		    wind2e_bits, wind2e_width, wind2e_height);
    windpics[2][EAST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind2e"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind2se"),
		    wind2se_bits, wind2se_width, wind2se_height);
    windpics[2][SOUTHEAST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind2se"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind2sw"),
		    wind2sw_bits, wind2sw_width, wind2sw_height);
    windpics[2][SOUTHWEST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind2sw"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind2w"),
		    wind2w_bits, wind2w_width, wind2w_height);
    windpics[2][WEST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind2w"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind2nw"),
		    wind2nw_bits, wind2nw_width, wind2nw_height);
    windpics[2][NORTHWEST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind2nw"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind3ne"),
		    wind3ne_bits, wind3ne_width, wind3ne_height);
    windpics[3][NORTHEAST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind3ne"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind3e"),
		    wind3e_bits, wind3e_width, wind3e_height);
    windpics[3][EAST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind3e"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind3se"),
		    wind3se_bits, wind3se_width, wind3se_height);
    windpics[3][SOUTHEAST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind3se"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind3sw"),
		    wind3sw_bits, wind3sw_width, wind3sw_height);
    windpics[3][SOUTHWEST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind3sw"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind3w"),
		    wind3w_bits, wind3w_width, wind3w_height);
    windpics[3][WEST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind3w"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind3nw"),
		    wind3nw_bits, wind3nw_width, wind3nw_height);
    windpics[3][NORTHWEST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind3nw"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind4ne"),
		    wind4ne_bits, wind4ne_width, wind4ne_height);
    windpics[4][NORTHEAST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind4ne"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind4e"),
		    wind4e_bits, wind4e_width, wind4e_height);
    windpics[4][EAST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind4e"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind4se"),
		    wind4se_bits, wind4se_width, wind4se_height);
    windpics[4][SOUTHEAST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind4se"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind4sw"),
		    wind4sw_bits, wind4sw_width, wind4sw_height);
    windpics[4][SOUTHWEST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind4sw"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind4w"),
		    wind4w_bits, wind4w_width, wind4w_height);
    windpics[4][WEST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind4w"));
    Tk_DefineBitmap(interp, Tk_GetUid("wind4nw"),
		    wind4nw_bits, wind4nw_width, wind4nw_height);
    windpics[4][NORTHWEST] = Tk_GetBitmap(interp, rootwin, Tk_GetUid("wind4nw"));


    Tk_DefineBitmap(interp, Tk_GetUid("miss"),
		    miss_bits, miss_width, miss_height);
    dside->ui->hitpics[0] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("miss"));
    Tk_DefineBitmap(interp, Tk_GetUid("hit"),
		    hit_bits, hit_width, hit_height);
    dside->ui->hitpics[1] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("hit"));
    Tk_DefineBitmap(interp, Tk_GetUid("kill"),
		    kill_bits, kill_width, kill_height);
    dside->ui->hitpics[2] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("kill"));
    dside->ui->grays[gray] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("gray50"));
    dside->ui->grays[darkgray] =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("gray25"));
    Tk_DefineBitmap(interp, Tk_GetUid("dotdotdot"),
		    dots_bits, dots_width, dots_height);
    dside->ui->dots =
      Tk_GetBitmap(interp, rootwin, Tk_GetUid("dotdotdot"));
    Tk_DefineBitmap(interp, Tk_GetUid("ants"),
		    ants_bits, ants_width, ants_height);
    antpic = Tk_GetBitmap(interp, rootwin, Tk_GetUid("ants"));
    /* These bitmaps are used only by tcl code, don't need to be assigned
       to a C variable. */
    Tk_DefineBitmap(interp, Tk_GetUid("shoot_cursor"),
		    shootcursor_bits, shootcursor_width, shootcursor_height);
    Tk_DefineBitmap(interp, Tk_GetUid("build"),
		    buildcursor_bits, buildcursor_width, buildcursor_height);
    Tk_DefineBitmap(interp, Tk_GetUid("looking_glass"),
		    lookglass_bits, lookglass_width, lookglass_height);
    Tk_DefineBitmap(interp, Tk_GetUid("closer"),
		    closer_bits, closer_width, closer_height);
    Tk_DefineBitmap(interp, Tk_GetUid("farther"),
		    farther_bits, farther_width, farther_height);
    Tk_DefineBitmap(interp, Tk_GetUid("laurels"),
		    laurels_bits, laurels_width, laurels_height);
}

static void
init_unit_images()
{
    int u;
    ImageFamily *imf;
    Image *smallest;
    Tk_Window tkwin = Tk_MainWindow(interp);

    dside->ui->uimages =
      (ImageFamily **) xmalloc(numutypes * sizeof(ImageFamily *));
    tmp_root_window = tkwin;
    for_all_unit_types(u) {
	imf = get_unit_type_images(dside, u);
	if (DebugG)
	  describe_imf(dside, "unit type", u_type_name(u), imf);
	dside->ui->uimages[u] = imf;
	smallest = smallest_image(imf);
	if (smallest) {
	    if (smallest->w > min_w_for_unit_image)
	      min_w_for_unit_image = smallest->w;
	    if (smallest->h > min_h_for_unit_image)
	      min_h_for_unit_image = smallest->h;
	}
    }
}

/* Collect images for all the terrain types. */

static void
init_terrain_images()
{
    int t, p;
    ImageFamily *imf;
    Image *img, *timg;
    TkImage *tkimg;

    dside->ui->timages =
      (ImageFamily **) xmalloc(numttypes * sizeof(ImageFamily *));
    for_all_terrain_types(t) {
	imf = get_terrain_type_images(dside, t);
	if (DebugG)
	  describe_imf(dside, "terrain type", t_type_name(t), imf);
	dside->ui->timages[t] = imf;
	/* Precalculate which images to use at which magnifications. */
	for (p = 0; p < NUMPOWERS; ++p) {
	    timg = best_image(dside->ui->timages[t], hws[p], hhs[p]);
	    if (timg != NULL) {
		tkimg = (TkImage *) timg->hook;
		if (tkimg != NULL) {
		    if (!dside->ui->monochrome
			/* if somebody changes their mind about using
                           the color images, this will lose */
			&& dside->ui->dflt_color_terr_images
			&& tkimg->colr != None)
		      dside->ui->terrpics[p][t] = tkimg->colr;
		    else
		      dside->ui->terrpics[p][t] = tkimg->mono;
		}
	    }
	}
	/* Look for a solid color. */
	timg = NULL;
	for_all_images(dside->ui->timages[t], img) {
	    if (img->w == 1 && img->h == 1) {
		timg = img;
		break;
	    }
	}
	if (timg != NULL && timg->w == 1 && timg->h == 1) {
	    if (timg->hook) {
		tkimg = (TkImage *) timg->hook;
		/* Save the color if found. */
		if (tkimg->solid) 
		  dside->ui->cellcolor[t] = tkimg->solid;
	    }
	}
    }
}

/* Set up a side's view of everybody else's colors and emblems. */

static void
init_emblem_images()
{
    Side *side2;
    
    dside->ui->eimages =
      (ImageFamily **) xmalloc((g_sides_max() + 1) * sizeof(ImageFamily *));
    dside->ui->eimages_loaded =
      (short *) xmalloc((g_sides_max() + 1) * sizeof(short));
    /* Independent units may have a distinguishing emblem, so the
       indepside is included here. */
    for_all_sides_plus_indep(side2) {
	init_emblem(side2);
    }
}

/* Compute the distinctive emblem by which one side will recognize units
   of another side.  This does both our view of ourselves and others
   orthogonally.  Note that sides without displays can still have emblems
   and colors that the sides with displays will see, but that sides
   without displays don't need to do any emblem init. */

void
init_emblem(Side *side2)
{
    char cbuf[BUFSIZ], *s, *c;
    int s2 = side_number(side2), i;
    ImageFamily *imf;
    Tk_Window tkwin = Tk_MainWindow(interp);
    XColor *color;

    /* Collect the color names of the other side and try to request
       them for our own display. */
    if (!dside->ui->monochrome && !empty_string(side2->colorscheme)) {
	/* take spec apart and iterate for multiple colors */
        /* (should be generic code) */
	for (s = side2->colorscheme, c = cbuf, i = 0; i < 3; ++s) {
	    if (*s == ',' || *s == '\0') {
		*c = '\0';
		c = cbuf;
		color = request_color(cbuf);
		if (color != NULL)
		  dside->ui->colors[s2][i++] = color;
	    } else {
		*c++ = *s;
	    }
	    if (*s == '\0')
	      break;
	}
	dside->ui->numcolors[s2] = i;
    } else {
	dside->ui->numcolors[s2] = 0;
    }
    tmp_root_window = tkwin;
    tmp_valid = TRUE;
    imf = get_emblem_images(dside, side2);
    tmp_valid = FALSE;
    if (DebugG)
      describe_imf(dside, "emblem", side_desig(side2), imf);
    dside->ui->eimages[s2] = imf;
    dside->ui->eimages_loaded[s2] = TRUE;
}

init_other_images()
{
    ImageFamily *imf;
    Tk_Window tkwin = Tk_MainWindow(interp);

    tmp_root_window = tkwin;
    tmp_valid = TRUE;
    imf = get_generic_images(dside, "miss");
    record_imf_get(imf);
    if (DebugG)
      describe_imf(dside, "blast", side_desig(dside), imf);
    dside->ui->blastimages[0] = imf;
    imf = get_generic_images(dside, "hit");
    record_imf_get(imf);
    if (DebugG)
      describe_imf(dside, "blast", side_desig(dside), imf);
    dside->ui->blastimages[1] = imf;
    imf = get_generic_images(dside, "kill");
    record_imf_get(imf);
    if (DebugG)
      describe_imf(dside, "blast", side_desig(dside), imf);
    tmp_valid = FALSE;
    dside->ui->blastimages[2] = imf;
}

/* Describe (for debugging) Tk-specific parts of an image. */

static void
tk_describe_image(Side *side, Image *img)
{
    TkImage *tkimg;

    tkimg = (TkImage *) img->hook;
    if (tkimg)
      DGprintf(" (tk mono %d color %d mask %d solid %d)",
	       tkimg->mono, tkimg->colr, tkimg->mask, tkimg->solid);
}

update_view_controls_info()
{
    eval_tcl_cmd("update_view_controls_info %d %d %d %d %d %d %d %d %d",
		 all_see_all,
		 dside->may_set_see_all,
		 people_sides_defined(),
		 control_sides_defined(),
		 elevations_defined(),
		 (world.daylength != 1),
		 temperatures_defined(),
		 winds_defined(),
		 clouds_defined());
}
