]> granicus.if.org Git - xconq/blobdiff - tcltk/tkisamp.c
commits for 7.5.0 pre-release tarball
[xconq] / tcltk / tkisamp.c
index 9e409cc47d14ca1f6b62f49cf33caa24dec775d8..ad06af0ff22d541c946f6357d8420b59880550cd 100644 (file)
@@ -14,62 +14,71 @@ any later version.  See the file COPYING.  */
 /* Note that this widget depends only on image machinery, and has
    no knowledge of Xconq constructs such as units and sides. */
 
-#include "config.h"
-#include "misc.h"
-#include "lisp.h"
-#include "imf.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For tcltk 8.4.0 source compatibility. */
+#define USE_NON_CONST
 
+#ifdef MAC
+#include <tclMacCommonPch.h>
+#include <tclMac.h>                    /* Includes tcl.h. */
+#include <tkMac.h>                     /* Includes tk.h. */
+#else
 #include <tcl.h>
 #include <tk.h>
+#endif /* MAC */
 
-#include <math.h>
-
-#include "tkimf.h"
-
-int imfsample_cmd(ClientData cldata, Tcl_Interp *interp,
-                 int argc, char *argv[]);
+#ifdef __cplusplus
+}
+#endif
 
-extern Tcl_Interp *interp;
+#include <math.h>
 
-/* MAXROWS, MAXCOLS, MINROWS, and MINCOLS can be changed safely */
-#define MAXROWS 50
-#define MAXCOLS 16
-#define MINROWS 2
-#define MINCOLS 8
+#include "config.h"
+#include "misc.h"
+#include "lisp.h"
+#include "imf.h"
 
-#define MAXFAMS (MAXROWS*MAXCOLS)
+#ifndef MAC
+#include "xlibstuff.h"
+#endif
 
-extern int tmp_valid;
+#include "tkimf.h"
 
 extern Display *tmp_display;
+extern Tcl_Interp *interp;
+extern int tmp_valid;
 
-static XColor *black_color;
-static XColor *white_color;
+static XColor *black_color = NULL;
+static XColor *white_color = NULL;
 
 /* Image family list display widget. */
 
 typedef struct {
-    Tk_Window tkwin;           /* Window that embodies the imfsample.  NULL
-                                * means window has been deleted but
-                                * widget record hasn't been cleaned up yet. */
-    Display *display;          /* X's token for the window's display. */
-    Tcl_Interp *interp;                /* Interpreter associated with widget. */
-    Tcl_Command widgetCmd;     /* Token for imfsample's widget command. */
-    int border_width;          /* Width of 3-D border around whole widget. */
-    Tk_3DBorder bg_border;     /* Used for drawing background. */
-    Tk_3DBorder fg_border;     /* Used for drawing foreground. */
-    int relief;                        /* Indicates whether window as a whole is
-                                * raised, sunken, or flat. */
-    GC copygc;                 /* Graphics context for copying from
-                                * off-screen pixmap onto screen. */
+    Tk_Window tkwin;                   /* Window that embodies the imfsample.  NULL
+                                               * means window has been deleted but
+                                               * widget record hasn't been cleaned up yet. */
+    Display *display;                  /* X's token for the window's display. */
+    Tcl_Interp *interp;                        /* Interpreter associated with widget. */
+    Tcl_Command widgetCmd;             /* Token for imfsample's widget command. */
+    int border_width;                  /* Width of 3-D border around whole widget. */
+    Tk_3DBorder bg_border;             /* Used for drawing background. */
+    Tk_3DBorder fg_border;             /* Used for drawing foreground. */
+    Tk_3DBorder cu_border;             /* Used for drawing closeups. */
+    int relief;                                /* Indicates whether window as a whole is
+                                               * raised, sunken, or flat. */
+    GC copygc;                         /* Graphics context for copying from
+                                                * off-screen pixmap onto screen. */
     GC gc;
-    int double_buffer;         /* Non-zero means double-buffer redisplay
-                                * with pixmap;  zero means draw straight
-                                * onto the display. */
-    int update_pending;                /* Non-zero means a call to imfsample_display
-                                * has already been scheduled. */
+    int double_buffer;                 /* Non-zero means double-buffer redisplay
+                                                * with pixmap;  zero means draw straight
+                                                * onto the display. */
+    int update_pending;                        /* Non-zero means a call to imfsample_display
+                                               * has already been scheduled. */
  
-    int pad;                   /* Extra space between images. */
+    int pad;                                   /* Extra space between images. */
     int iwidth, iheight;
     int show_color;
     int show_names;
@@ -86,7 +95,6 @@ typedef struct {
     int numimages;
     ImageFamily **imf_list;
 
-    int selected;
     int with_terrain;
     int with_emblem;
 
@@ -95,14 +103,19 @@ typedef struct {
 
     int numvisrows;
     int firstvisrow;
+    
+    /* IMFAapp-specific stuff. */
+    int imfapp;                                /* True if we are running IMFAapp. */
+    int selected;                              /* The selected image in IMFAapp. */
+    int previous;                              /* The previously selected image. */
+    int oldfirst;                              /* Cache of first visible row. */
+    int redraw;                                /* True if the widget should be redrawn. */
 
 } Imfsample;
 
 static Tk_ConfigSpec config_specs[] = {
     {TK_CONFIG_BORDER, "-background", "background", "Background",
        "white", Tk_Offset(Imfsample, bg_border), TK_CONFIG_COLOR_ONLY},
-    {TK_CONFIG_BORDER, "-background", "background", "Background",
-       "white", Tk_Offset(Imfsample, bg_border), TK_CONFIG_MONO_ONLY},
     {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
        (char *) NULL, 0, 0},
     {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
@@ -114,11 +127,11 @@ static Tk_ConfigSpec config_specs[] = {
     {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
        (char *) NULL, 0, 0},
     {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground",
-       "white", Tk_Offset(Imfsample, fg_border), TK_CONFIG_COLOR_ONLY},
-    {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground",
-       "white", Tk_Offset(Imfsample, fg_border), TK_CONFIG_MONO_ONLY},
+       "black", Tk_Offset(Imfsample, fg_border), TK_CONFIG_COLOR_ONLY},
+    {TK_CONFIG_BORDER, "-closeup", "closeup", "Closeup",
+       "white", Tk_Offset(Imfsample, cu_border), TK_CONFIG_COLOR_ONLY},
     {TK_CONFIG_PIXELS, "-height", "height", "Height",
-       "32", Tk_Offset(Imfsample, height), 0},
+       "0", Tk_Offset(Imfsample, height), 0},
 #if 0 /* disabled until we debug */
     {TK_CONFIG_STRING, "-imf", "imf", "Imf",
        "0", Tk_Offset(Imfsample, main_imf_name), 0},
@@ -143,10 +156,16 @@ static Tk_ConfigSpec config_specs[] = {
        "1", Tk_Offset(Imfsample, show_masks), 0},
     {TK_CONFIG_INT, "-showsolid", "showSolid", "ShowSolid",
        "0", Tk_Offset(Imfsample, show_solid), 0},
+    {TK_CONFIG_INT, "-imfapp", "imfApp", "ImfApp",
+       "0", Tk_Offset(Imfsample, imfapp), 0},
     {TK_CONFIG_COLOR, "-fillcolor", "fillColor", "FillColor",
        "gray", Tk_Offset(Imfsample, fill_color), 0},
     {TK_CONFIG_PIXELS, "-width", "width", "Width",
-       "32", Tk_Offset(Imfsample, width), 0},
+       "0", Tk_Offset(Imfsample, width), 0},
+    {TK_CONFIG_PIXELS, "-emblem", "emblem", "Emblem",
+       "-1", Tk_Offset(Imfsample, with_emblem), 0},
+    {TK_CONFIG_PIXELS, "-terrain", "terrain", "Terrain",
+       "-1", Tk_Offset(Imfsample, with_terrain), 0},
     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
        (char *) NULL, 0, 0}
 };
@@ -172,7 +191,7 @@ static void draw_one_image(Imfsample *imfsample, Drawable d, GC gc,
 /* The command to create an image sample window. */
 
 int
-imfsample_cmd(ClientData cldata, Tcl_Interp *interp, int argc, char **argv)
+imfsample_cmd(ClientData cldata, Tcl_Interp *interp, int argc, char *argv[])
 {
     Tk_Window mainw = (Tk_Window) cldata;
     Imfsample *imfsample;
@@ -203,6 +222,7 @@ imfsample_cmd(ClientData cldata, Tcl_Interp *interp, int argc, char **argv)
     imfsample->border_width = 0;
     imfsample->bg_border = NULL;
     imfsample->fg_border = NULL;
+    imfsample->cu_border = NULL;
     imfsample->relief = TK_RELIEF_FLAT;
     imfsample->copygc = None;
     imfsample->gc = None;
@@ -213,17 +233,24 @@ imfsample_cmd(ClientData cldata, Tcl_Interp *interp, int argc, char **argv)
     imfsample->show_masks = 0;
     imfsample->show_grid = 0;
     imfsample->fill_color = NULL;
-    imfsample->selected = -1;
+    
     imfsample->with_terrain = -1;
     imfsample->with_emblem = -1;
 
     imfsample->main_imf_name = "";
     imfsample->numimages = 0;
     imfsample->imf_list =
-      (ImageFamily **) xmalloc(MAXFAMS * sizeof(ImageFamily *));
+      (ImageFamily **) xmalloc(MAXIMAGEFAMILIES * sizeof(ImageFamily *));
     imfsample->numvisrows = 0;
     imfsample->firstvisrow = 0;
 
+    /* IMFApp-specific stuff. */
+    imfsample->imfapp = 0;
+    imfsample->selected = -1;
+    imfsample->previous = -1;
+    imfsample->oldfirst = 0;    
+    imfsample->redraw = 0;    
+    
     Tk_CreateEventHandler(imfsample->tkwin, ExposureMask|StructureNotifyMask,
                          imfsample_event_proc, (ClientData) imfsample);
     if (imfsample_configure(interp, imfsample, argc-2, argv+2, 0) != TCL_OK) {
@@ -236,17 +263,15 @@ imfsample_cmd(ClientData cldata, Tcl_Interp *interp, int argc, char **argv)
 }
 
 static int
-imfsample_widget_cmd(cldata, interp, argc, argv)
-ClientData cldata;
-Tcl_Interp *interp;
-int argc;
-char **argv;
+imfsample_widget_cmd(ClientData cldata, Tcl_Interp *interp, int argc, char **argv)
 {
     Imfsample *imfsample = (Imfsample *) cldata;
     int result = TCL_OK;
-    size_t length;
+    size_t cmdlength;
     char c;
     int x, y, col, row, n;
+    char tclbuf[100];
+    int rslt;
 
     if (argc < 2) {
        Tcl_AppendResult(interp, "wrong # args: should be \"",
@@ -255,9 +280,9 @@ char **argv;
     }
     Tcl_Preserve((ClientData) imfsample);
     c = argv[1][0];
-    length = strlen(argv[1]);
-    if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
-       && (length >= 2)) {
+    cmdlength = strlen(argv[1]);
+    if ((c == 'c') && (strncmp(argv[1], "cget", cmdlength) == 0)
+       && (cmdlength >= 2)) {
        if (argc != 3) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " cget option\"",
@@ -266,8 +291,8 @@ char **argv;
        }
        result = Tk_ConfigureValue(interp, imfsample->tkwin, config_specs,
                (char *) imfsample, argv[2], 0);
-    } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
-              && (length >= 2)) {
+    } else if ((c == 'c') && (strncmp(argv[1], "configure", cmdlength) == 0)
+              && (cmdlength >= 2)) {
        if (argc == 2) {
            result = Tk_ConfigureInfo(interp, imfsample->tkwin, config_specs,
                    (char *) imfsample, (char *) NULL, 0);
@@ -278,76 +303,115 @@ char **argv;
            result = imfsample_configure(interp, imfsample, argc-2, argv+2,
                    TK_CONFIG_ARGV_ONLY);
        }
-    } else if ((c == 'c') && (strncmp(argv[1], "curselection", length) == 0)
-              && (length >= 2)) {
+    } else if ((c == 'c') && (strncmp(argv[1], "curselection", cmdlength) == 0)
+              && (cmdlength >= 2)) {
        sprintf(interp->result, "%d", imfsample->selected);
-    } else if ((c == 'a') && (strncmp(argv[1], "add", length) == 0)
-              && (length >= 2)) {
+    } else if ((c == 'a') && (strncmp(argv[1], "add", cmdlength) == 0)
+              && (cmdlength >= 2)) {
        if (strcmp(argv[2], "imf") == 0) {
            imfsample_add_imf(imfsample, argv[3]);
        } else if (strcmp(argv[2], "all") == 0) {
            imfsample_add_imf(imfsample, "-all");
        }
-    } else if ((c == 'e') && (strncmp(argv[1], "emblem", length) == 0)
-              && (length >= 2)) {
+    } else if ((c == 'e') && (strncmp(argv[1], "emblem", cmdlength) == 0)
+              && (cmdlength >= 2)) {
        n = strtol(argv[2], NULL, 10);
        imfsample->with_emblem = n;
-    } else if ((c == 'r') && (strncmp(argv[1], "replace", length) == 0)
-              && (length >= 2)) {
+    } else if ((c == 'r') && (strncmp(argv[1], "redraw", cmdlength) == 0)
+              && (cmdlength >= 2)) {
+       imfsample->redraw = TRUE;
+       if (!imfsample->update_pending) {
+               Tcl_DoWhenIdle(imfsample_display, cldata);
+               imfsample->update_pending = 1;
+       }
+    } else if ((c == 'r') && (strncmp(argv[1], "replace", cmdlength) == 0)
+              && (cmdlength >= 2)) {
        if (strcmp(argv[2], "imf") == 0) {
            imfsample_replace_imf(imfsample, argv[3]);
        } else if (strcmp(argv[2], "emblem") == 0) {
            imfsample_replace_emblem(imfsample, argv[3]);
        }
-    } else if ((c == 'r') && (strncmp(argv[1], "remove", length) == 0)
-              && (length >= 2)) {
+    } else if ((c == 'r') && (strncmp(argv[1], "remove", cmdlength) == 0)
+              && (cmdlength >= 2)) {
        if (strcmp(argv[2], "imf") == 0) {
            imfsample_remove_imf(imfsample, argv[3]);
        } else if (strcmp(argv[2], "emblem") == 0) {
            imfsample->numimages = 1;
        } else if (strcmp(argv[2], "all") == 0) {
-           imfsample->numimages = 0;
+           imfsample_remove_imf(imfsample, "-all");
+           if (imfsample->imfapp) {
+                   imfsample->selected = -1;
+                   imfsample->previous = -1;
+                   /* Turn off the scrollbar. */
+                   sprintf(tclbuf, ".images.scroll set 0 1");
+                   rslt = Tcl_Eval(interp, tclbuf);
+                   if (rslt == TCL_ERROR) {
+                       fprintf(stderr, "Error: %s\n", interp->result);
+                   }
+           }
+       }
+    } else if ((c == 's') && (strncmp(argv[1], "select", cmdlength) == 0)
+              && (cmdlength >= 2)) {
+       if (imfsample->numimages) {
+               x = strtol(argv[2], NULL, 10);
+               y = strtol(argv[3], NULL, 10);
+               col = x / imfsample->eltw;
+               row = y / imfsample->elth + imfsample->firstvisrow;
+               n = row * imfsample->cols + col;
+               if (n < 0 
+                   || n >= imfsample->numimages
+                   || col >= imfsample->cols) {
+                       n = -1;
+               }
+               /* This rather complicated scheme is to ensure that we can both select
+               images and then deselect them by clicking a second time on the image or
+               by clicking in an empty region. */
+               if (imfsample->selected != n) {
+                       imfsample->previous = imfsample->selected;
+                       imfsample->selected = n;
+               } else if (n == -1) {
+                       imfsample->selected = -1;
+               } else {
+                       imfsample->previous = n;
+                       imfsample->selected = -1;
+               }
        }
-    } else if ((c == 's') && (strncmp(argv[1], "select", length) == 0)
-              && (length >= 2)) {
-       x = strtol(argv[2], NULL, 10);
-       y = strtol(argv[3], NULL, 10);
-       col = x / imfsample->eltw;
-       row = y / imfsample->elth + imfsample->firstvisrow;
-       n = row * imfsample->cols + col;
-       if (n < 0 || n >= imfsample->numimages)
-         n = -1;
-       imfsample->selected = n;
-    } else if ((c == 't') && (strncmp(argv[1], "terrain", length) == 0)
-              && (length >= 2)) {
+    } else if ((c == 't') && (strncmp(argv[1], "terrain", cmdlength) == 0)
+              && (cmdlength >= 2)) {
        n = strtol(argv[2], NULL, 10);
        imfsample->with_terrain = n;
-    } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) {
-    } else if ((c == 'y') && (strncmp(argv[1], "yview", length) == 0)) {
+    } else if ((c == 'x') && (strncmp(argv[1], "xview", cmdlength) == 0)) {
+    } else if ((c == 'y') && (strncmp(argv[1], "yview", cmdlength) == 0)) {
        int count, type, nrow = imfsample->firstvisrow;
        double fraction, fraction2;
 
-       if (argc == 2) {
-           fraction = 0;
-           fraction2 = 1;
-           printf("imfsample yview %g %g\n", fraction, fraction2);
-           sprintf(interp->result, "%g %g", fraction, fraction2);
-       } else {
-           type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count);
-           switch (type) {
-             case TK_SCROLL_ERROR:
+       type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count);
+       switch (type) {
+                 case TK_SCROLL_ERROR:
                goto error;
-             case TK_SCROLL_MOVETO:
-               /*              nsy = ((mapw->vp->symax - mapw->vp->symin) * fraction); */
+                 case TK_SCROLL_MOVETO:
+               nrow = fraction * imfsample->rows;
                break;
-             case TK_SCROLL_PAGES:
+                 case TK_SCROLL_PAGES:
                nrow += (count * imfsample->numvisrows * 4) / 5;
                break;
-             case TK_SCROLL_UNITS:
+                 case TK_SCROLL_UNITS:
                nrow += count;
                break;
-           }
-           imfsample->firstvisrow = nrow;
+       }
+       /* Don't allow negative row numbers. */
+       imfsample->firstvisrow = max(0, nrow);
+       /* Compute the bounds of the visible window. */
+       fraction = (double) imfsample->firstvisrow / imfsample->rows;
+       fraction2 = (double) (imfsample->firstvisrow + imfsample->numvisrows) / imfsample->rows;
+       if (imfsample->imfapp) {
+               /* We must set the scrollbar explicitly since the imfsample widget
+               lacks a built-in yscrollcommand. */
+               sprintf(tclbuf, ".images.scroll set %f %f", fraction, fraction2);
+               rslt = Tcl_Eval(interp, tclbuf);
+               if (rslt == TCL_ERROR) {
+                       fprintf(stderr, "Error: %s\n", interp->result);
+               }
        }
     } else {
        Tcl_AppendResult(interp, "bad option \"", argv[1],
@@ -372,10 +436,31 @@ imfsample_add_imf(Imfsample *imfsample, char *imfname)
 {
     int i;
     ImageFamily *imf = NULL;
+    char tclbuf[100];
+    int rslt;
 
     if (strcmp(imfname, "-all") == 0) {
        imfsample->numimages = 0;
        for (i = 0; i < numimages; ++i) {
+           if (imfsample->imfapp) {
+               sprintf(tclbuf, 
+".closeup.content itemconfigure status -text \"Loading %s\"", 
+                       images[i]->name);
+               rslt = Tcl_Eval(interp, tclbuf);
+               if (rslt == TCL_ERROR) {
+                   fprintf(stderr, "Error: %s\n", interp->result);
+               }
+               sprintf(tclbuf, "update idletasks");
+               rslt = Tcl_Eval(interp, tclbuf);
+               if (rslt == TCL_ERROR) {
+                   fprintf(stderr, "Error: %s\n", interp->result);
+               }
+           }
+           imf = tk_find_imf(images[i]->name);
+           if (imf == NULL) {
+               fprintf(stderr, "Missing imf %s\n", imfname);
+               return;
+           }
            imfsample->imf_list[imfsample->numimages++] = images[i];
        }
        return;
@@ -393,6 +478,10 @@ imfsample_replace_imf(Imfsample *imfsample, char *imfname)
 {
     ImageFamily *imf = NULL;
 
+    if (empty_string(imfname)) {
+       imfsample->imf_list[0] = NULL;
+       return;
+    }
     if (imfsample->numimages == 0) {
        imfsample_add_imf(imfsample, imfname);
        return;
@@ -422,10 +511,17 @@ imfsample_replace_emblem(Imfsample *imfsample, char *imfname)
     imfsample->imf_list[1] = imf;
 }
 
+extern int numtkimages;
+
 static void
 imfsample_remove_imf(Imfsample *imfsample, char *imfname)
 {
-    /* (should look for specific imf) */
+    if (imfsample->imfapp) {
+           if (strcmp(imfname, "-all") == 0) {
+               numtkimages = 0;
+               numimages = 0;
+           }
+    }
     imfsample->numimages = 0;
 }
 
@@ -444,6 +540,8 @@ imfsample_configure(Tcl_Interp *interp, Imfsample *imfsample,
                           Tk_3DBorderColor(imfsample->fg_border)->pixel);
     Tk_SetWindowBackground(imfsample->tkwin,
                           Tk_3DBorderColor(imfsample->bg_border)->pixel);
+    Tk_SetWindowBackground(imfsample->tkwin,
+                          Tk_3DBorderColor(imfsample->cu_border)->pixel);
     if ((imfsample->copygc == None) && 1/*imfsample->double_buffer*/) {
        XGCValues gcValues;
 
@@ -464,6 +562,8 @@ imfsample_configure(Tcl_Interp *interp, Imfsample *imfsample,
        the window to be redisplayed.  */
     Tk_GeometryRequest(imfsample->tkwin, imfsample->width, imfsample->height);
     Tk_SetInternalBorder(imfsample->tkwin, imfsample->border_width);
+    /* Make sure the resized widget is redrawn. */
+    imfsample->redraw = TRUE;
     if (!imfsample->update_pending) {
        Tcl_DoWhenIdle(imfsample_display, (ClientData) imfsample);
        imfsample->update_pending = 1;
@@ -472,21 +572,19 @@ imfsample_configure(Tcl_Interp *interp, Imfsample *imfsample,
 }
 
 static void
-imfsample_event_proc(cldata, eventPtr)
-ClientData cldata;
-XEvent *eventPtr;
+imfsample_event_proc(ClientData cldata, XEvent *eventPtr)
 {
     Imfsample *imfsample = (Imfsample *) cldata;
 
     if (eventPtr->type == Expose) {
        if (!imfsample->update_pending) {
-           Tcl_DoWhenIdle(imfsample_display, cldata);
-           imfsample->update_pending = 1;
+               Tcl_DoWhenIdle(imfsample_display, cldata);
+               imfsample->update_pending = 1;
        }
     } else if (eventPtr->type == ConfigureNotify) {
        if (!imfsample->update_pending) {
-           Tcl_DoWhenIdle(imfsample_display, cldata);
-           imfsample->update_pending = 1;
+               Tcl_DoWhenIdle(imfsample_display, cldata);
+               imfsample->update_pending = 1;
        }
     } else if (eventPtr->type == DestroyNotify) {
        if (imfsample->tkwin != NULL) {
@@ -503,8 +601,7 @@ XEvent *eventPtr;
 }
 
 static void
-imfsample_cmd_deleted_proc(cldata)
-ClientData cldata;
+imfsample_cmd_deleted_proc(ClientData cldata)
 {
     Imfsample *imfsample = (Imfsample *) cldata;
     Tk_Window tkwin = imfsample->tkwin;
@@ -515,11 +612,15 @@ ClientData cldata;
     }
 }
 
+/* Needed for drawing directly to the screen on the Mac. */
+static Tk_3DBorder black_border = NULL;
+static Tk_3DBorder white_border = NULL;
+
 static void
 imfsample_display(ClientData cldata)
 {
     char *str;
-    int row, col, namex, namey, n, sx, sy;
+    int row, col, namex, namey, n, sx, sy, update = FALSE, done;
     Imfsample *imfsample = (Imfsample *) cldata;
     Display *dpy = imfsample->display;
     Tk_Window tkwin = imfsample->tkwin;
@@ -527,13 +628,26 @@ imfsample_display(ClientData cldata)
     Pixmap pm = None;
     Drawable d;
     Tk_Font tkfont;
-    int winwidth = Tk_Width(tkwin), winheight = Tk_Height(tkwin);
-
+    int winwidth = Tk_Width(Tk_Parent(tkwin)); 
+    int winheight = Tk_Height(Tk_Parent(tkwin));
+    char tclbuf[100];
+    int rslt;
+       
     imfsample->update_pending = 0;
-    if (!Tk_IsMapped(tkwin))
-      return;
+    if (!Tk_IsMapped(tkwin)) {
+       return;
+    }
+    /* Check if we need to redraw the entire imfsample. */
+    if (imfsample->imfapp) {
+       if (imfsample->oldfirst != imfsample->firstvisrow
+           || imfsample->redraw) {
+               imfsample->oldfirst = imfsample->firstvisrow;
+               update = TRUE;
+       }
+    }
     /* Create a pixmap for double-buffering if necessary. */
     if (imfsample->double_buffer) {
+       update = TRUE;
        pm = Tk_GetPixmap(imfsample->display, Tk_WindowId(tkwin),
                          Tk_Width(tkwin), Tk_Height(tkwin),
                          DefaultDepthOfScreen(Tk_Screen(tkwin)));
@@ -541,38 +655,64 @@ imfsample_display(ClientData cldata)
     } else {
        d = Tk_WindowId(tkwin);
     }
-    if (black_color == NULL)
-      black_color = Tk_GetColor(interp, tkwin, Tk_GetUid("black"));
-    if (white_color == NULL)
-      white_color = Tk_GetColor(interp, tkwin, Tk_GetUid("white"));
+    if (black_color == NULL) {
+       black_color = Tk_GetColor(interp, tkwin, Tk_GetUid("black"));
+    }
+    if (white_color == NULL) {
+       white_color = Tk_GetColor(interp, tkwin, Tk_GetUid("white"));
+    }
+    if (black_border == NULL) {
+       black_border = Tk_Get3DBorder(interp, tkwin, "black");
+    }
+    if (white_border == NULL) {
+       white_border = Tk_Get3DBorder(interp, tkwin, "white");
+    }
     /* Collect GC and font for subsequent work. */
     gc = imfsample->gc;
     XSetClipMask(dpy, gc, None);
     if (imfsample->show_names) {
-       tkfont = Tk_GetFont(interp, tkwin, "-size 10");
+#ifdef WIN32
+       tkfont = Tk_GetFont(interp, tkwin, "-family arial -size 8");
+#elif defined (MAC)
+       tkfont = Tk_GetFont(interp, tkwin, "-family helvetica -size 11");
+#else
+       tkfont = Tk_GetFont(interp, tkwin, "-family helvetica -size 12");
+#endif
        XSetFont(imfsample->display, gc, Tk_FontId(tkfont));
     }
 
-    /* Redraw the widget's background/border. */
-    if (imfsample->with_terrain >= 0) {
-       ImageFamily *timf = imfsample->imf_list[imfsample->with_terrain];
-       Image *timg;
-       TkImage *tkimg;
-
-       timg = best_image(timf, 64, 64);
-       if (timg != NULL) {
-           tkimg = (TkImage *) timg->hook;
-           if (tkimg != NULL) {
-               XSetFillStyle(dpy, gc, FillTiled);
-               XSetTile(dpy, gc, tkimg->colr);
-               XFillRectangle(dpy, d, gc, 0, 0,
-                              Tk_Width(tkwin), Tk_Height(tkwin));
+    /* Redraw the entire widget background/border, but not if we
+       are just updating the selected image. */
+    if (imfsample->selected == imfsample->previous
+       /* Always redraw if we have only one image (e.g. closeups). */
+       || (imfsample->numimages == 1 && imfsample->selected == -1)
+       || update) {
+           done = FALSE;
+           if (imfsample->with_terrain >= 0
+               /* Terrain tiles are not supported on Windows yet. */
+               && use_clip_mask) {
+               ImageFamily *timf = 
+                   imfsample->imf_list[imfsample->with_terrain];
+               Image *timg;
+               TkImage *tkimg;
+
+               timg = best_image(timf, 64, 64);
+               if (timg) {
+                   tkimg = (TkImage *) timg->hook;
+                   if (tkimg && tkimg->colr) {
+                       XSetFillStyle(dpy, gc, FillTiled);
+                       XSetTile(dpy, gc, tkimg->colr);
+                       XFillRectangle(dpy, d, gc, 0, 0,
+                                      Tk_Width(tkwin), Tk_Height(tkwin));
+                       done = TRUE;
+                   }
+               }
+           }
+           if (!done) {
+               Tk_Fill3DRectangle(tkwin, d, imfsample->bg_border, 0, 0,
+                                  Tk_Width(tkwin), Tk_Height(tkwin),
+                                  imfsample->border_width, imfsample->relief);
            }
-       }
-    } else {
-       Tk_Fill3DRectangle(tkwin, d, imfsample->bg_border, 0, 0,
-                          Tk_Width(tkwin), Tk_Height(tkwin),
-                          imfsample->border_width, imfsample->relief);
     }
 #if 0
     for (i = 0; i < imfsample->numimages; i++) {
@@ -629,47 +769,158 @@ imfsample_display(ClientData cldata)
       imfsample->numvisrows = min(1, imfsample->rows);
     if (imfsample->firstvisrow + imfsample->numvisrows > imfsample->rows)
       imfsample->firstvisrow = imfsample->rows - imfsample->numvisrows;
+    /* Imfapp-specific code that adjusts the canvas content to fit a resized
+    window and also sets the canvas scrollregion correctly. */
+    if (imfsample->imfapp
+       && imfsample->redraw) {  
+           imfsample->width = Tk_Width(Tk_Parent(tkwin));
+           imfsample->height = imfsample->rows * imfsample->elth + 7;
+           Tk_GeometryRequest(tkwin, imfsample->width, imfsample->height);
+           /* There must be a better way to do this ... */
+           sprintf(tclbuf, 
+                   ".images.canvas configure -scrollregion [ list 0 0 0 %d ]", 
+                   imfsample->height);
+           rslt = Tcl_Eval(interp, tclbuf);
+           if (rslt == TCL_ERROR) {
+               fprintf(stderr, "Error: %s\n", interp->result);
+           }
+           /* Force a redraw of the scrollbar if the window was resized. */
+           if (imfsample->numimages) {
+               sprintf(tclbuf, ".images.canvas.content yview scroll 0 units");
+           } else {
+               sprintf(tclbuf, ".images.scroll set 0 1");
+          }
+           rslt = Tcl_Eval(interp, tclbuf);
+           if (rslt == TCL_ERROR) {
+               fprintf(stderr, "Error: %s\n", interp->result);
+           }
+    }
     /* Now iterate through all the images we want to draw. */
     for (row = imfsample->firstvisrow;
-        row < (imfsample->firstvisrow + imfsample->numvisrows);
+        row <= (imfsample->firstvisrow + imfsample->numvisrows);
         ++row) {
+       if (row < 0)
+         continue;
        for (col = 0; col < imfsample->cols; ++col) {
            n = row * imfsample->cols + col;
            if (n >= imfsample->numimages)
              break;
            sx = col * imfsample->eltw;
            sy = (row - imfsample->firstvisrow) * imfsample->elth;
-           if (imfsample->show_grid)
-             Tk_Fill3DRectangle(tkwin, d, imfsample->fg_border,
-                                sx + 2, sy + 2,
-                                imfsample->iwidth, imfsample->iheight,
-                                imfsample->border_width, imfsample->relief);
-           draw_one_main_image(imfsample, d, gc, imfsample->imf_list[n],
-                          sx + imfsample->pad, sy + imfsample->pad,
-                          imfsample->iwidth, imfsample->iheight);
-           if (imfsample->show_names && !imfsample->show_grid) {
-               namex = sx + imfsample->pad + imfsample->iwidth + 2;
-               namey = sy + (imfsample->elth / 2) + 5;
-               XSetClipMask(dpy, gc, None);
-               XSetFillStyle(dpy, gc, FillSolid);
-               /* Draw the text in black only. */
-               /* (should invent a way to make show up when black bg; an
-                  offset version in white is semi-OK, but hard on eyes) */
-               XSetForeground(dpy, gc, black_color->pixel);
-               str = imfsample->imf_list[n]->name;
-               Tk_DrawChars(dpy, d, gc, tkfont, str, strlen(str),
-                            namex, namey);
+           /* Erase the old selected imf if we picked a new one. */
+           if (n == imfsample->previous && n != imfsample->selected) {
+               done = FALSE; 
+               if (imfsample->with_terrain >= 0
+                     /* Terrain tiles are not supported on Windows yet. */
+                   && use_clip_mask) {
+                   ImageFamily *timf = 
+                       imfsample->imf_list[imfsample->with_terrain];
+                   Image *timg;
+                   TkImage *tkimg;
+
+                   timg = best_image(timf, 64, 64);
+                   if (timg) {
+                       tkimg = (TkImage *) timg->hook;
+                       if (tkimg && tkimg->colr) {
+                           XSetFillStyle(dpy, gc, FillTiled);
+                           XSetTile(dpy, gc, tkimg->colr);
+                           if (imfsample->show_grid) {
+                               XFillRectangle(dpy, d, gc, sx, sy + 2,
+                                              imfsample->eltw, 
+                                              imfsample->elth);
+                           } else {
+                               XFillRectangle(dpy, d, gc, sx, sy + 7,
+                                              imfsample->eltw, 
+                                              imfsample->elth);
+                           }
+                           done = TRUE;
+                       }
+                   }
+               }
+               if (!done) {
+                   if (imfsample->show_grid) {
+                       Tk_Fill3DRectangle(tkwin, d, imfsample->bg_border, 
+                                          sx, sy + 2,
+                                          imfsample->eltw, imfsample->elth,
+                                          imfsample->border_width, 
+                                          imfsample->relief);
+                   } else {
+                       Tk_Fill3DRectangle(tkwin, d, imfsample->bg_border, 
+                                          sx, sy + 7,
+                                          imfsample->eltw, imfsample->elth,
+                                          imfsample->border_width, 
+                                          imfsample->relief);
+                   }
+               }
            }
-           /* Indicate the selected imf. */
+           /* Just draw the old erased image if we selected a new one, else
+              draw every image. */
+           if (imfsample->selected == imfsample->previous
+               || n == imfsample->previous
+               || update) {
+                   if (imfsample->show_grid) {
+                       Tk_Fill3DRectangle(tkwin, d, imfsample->cu_border,
+                               sx + 2, sy + 2,
+                               imfsample->iwidth, imfsample->iheight,
+                               imfsample->border_width, imfsample->relief);
+                       draw_one_main_image(imfsample, d, gc, 
+                                           imfsample->imf_list[n],
+                                           sx + 2, sy + 2,
+                                           imfsample->iwidth, 
+                                           imfsample->iheight);
+                   } else {
+                       draw_one_main_image(imfsample, d, gc, 
+                                           imfsample->imf_list[n],
+                                           sx + imfsample->pad, 
+                                           sy + imfsample->pad,
+                                           imfsample->iwidth, 
+                                           imfsample->iheight);
+                   }
+                   if (imfsample->show_names && !imfsample->show_grid) {
+                       namex = sx + 5;
+                       namey = sy + imfsample->elth + 3;
+                       XSetClipMask(dpy, gc, None);
+                       XSetFillStyle(dpy, gc, FillSolid);
+                       XSetForeground(dpy, gc, 
+                                      Tk_3DBorderColor(
+                                       imfsample->fg_border)->pixel);
+                       str = imfsample->imf_list[n]->name;
+                       Tk_DrawChars(dpy, d, gc, tkfont, str, strlen(str),
+                                    namex, namey);
+                   }
+           }
+           /* Box the selected imf. */
            if (n == imfsample->selected) {
                XSetClipMask(dpy, gc, None);
                XSetFillStyle(dpy, gc, FillSolid);
-               XSetForeground(dpy, gc, black_color->pixel);
-               XDrawRectangle(dpy, d, gc, sx, sy,
-                              imfsample->eltw, imfsample->elth);
+               XSetForeground(dpy, gc, Tk_3DBorderColor(imfsample->fg_border)->pixel);
+               if (imfsample->show_grid) {
+               /* A rectangle on the Mac is 1 pixel smaller in both directions. */
+#ifdef MAC
+                       XDrawRectangle(dpy, d, gc, sx + 2, sy + 2,
+                                      imfsample->eltw - 2, imfsample->elth - 2);
+#else
+                       XDrawRectangle(dpy, d, gc, sx + 2, sy + 2,
+                                      imfsample->eltw - 3, imfsample->elth - 3);
+#endif
+               } else {
+#ifdef MAC
+                       XDrawRectangle(dpy, d, gc, sx, sy + 7,
+                                      imfsample->eltw, imfsample->elth);
+#else
+                       XDrawRectangle(dpy, d, gc, sx, sy + 7,
+                                      imfsample->eltw - 1, imfsample->elth - 1);
+#endif
+               }
            }
        }
     }
+    /* Reset the old selected image to the new one if it exists. */
+    if (imfsample->selected != -1) {
+       imfsample->previous = imfsample->selected;
+    }
+    /* Reset the redraw flag. */
+    imfsample->redraw = FALSE;
     /* If double-buffered, copy to the screen and release the pixmap.  */
     if (imfsample->double_buffer) {
        XCopyArea(imfsample->display, pm, Tk_WindowId(tkwin),
@@ -677,8 +928,9 @@ imfsample_display(ClientData cldata)
                  0, 0, (unsigned) winwidth, (unsigned) winheight, 0, 0);
        Tk_FreePixmap(imfsample->display, pm);
     }
-    if (imfsample->show_names)
-      Tk_FreeFont(tkfont);
+    if (imfsample->show_names) {
+       Tk_FreeFont(tkfont);
+    }
     /* In theory this shouldn't be necessary, but in practice the
        interface widgets (esp. the progress bar fill color) are
        affected by the last value of the foreground left over from
@@ -722,7 +974,7 @@ draw_one_main_image(Imfsample *imfsample, Drawable d, GC gc, ImageFamily *imf,
        eimf = imfsample->imf_list[imfsample->with_emblem];
        if (eimf != NULL
            && emblem_position(img, eimf->name, eimf, sw, sh,
-                              &ex, &ey, &ew, &eh)) {
+                              sh, sh, &ex, &ey, &ew, &eh)) {
          eimg = best_image(eimf, ew, eh);
          if (eimg == NULL)
            return;
@@ -747,7 +999,8 @@ draw_one_image(Imfsample *imfsample, Drawable d, GC gc, Image *img,
     if (!img->istile) {
        /* Offset the image to draw in the middle of its area,
           whether larger or smaller than the given area. */
-       sx2 = sx + (sw - img->w) / 2;  sy2 = sy + (sh - img->h) / 2;
+       sx2 = sx + (sw - img->w) / 2;  
+       sy2 = sy + (sh - img->h) / 2;
        /* Only change the size of the rectangle being drawn if it's
           smaller than what was passed in. */
        if (img->w < sw) {
@@ -796,25 +1049,65 @@ draw_one_image(Imfsample *imfsample, Drawable d, GC gc, Image *img,
        XFillRectangle(dpy, d, gc, sx, sy, sw, sh);
     } else if (tkimg->mono != None || tkimg->mask != None) {
        if (use_clip_mask) {
-           XSetFillStyle(dpy, gc, FillSolid);
-           /* Set the color we're going to use for the mask; use the
-              imagecolor if we'll be using the mask as the only image. */
-           XSetForeground(dpy, gc,
-                          (tkimg->mono == None ? imagecolor : maskcolor)->pixel);
-           XSetClipOrigin(dpy, gc, sx2, sy2);
-           /* Set the clip mask to be explicit mask or unit's image. */
-           if (tkimg->mask && imfsample->show_masks)
-             XSetClipMask(dpy, gc, tkimg->mask);
-           else
-             XSetClipMask(dpy, gc, tkimg->mono);
-           /* Draw the mask. */
-           XFillRectangle(dpy, d, gc, sx, sy, sw, sh);
-           /* Draw the image proper. */
-           if (tkimg->mono != None) {
-               XSetForeground(dpy, gc, imagecolor->pixel);
-               XSetClipMask(dpy, gc, tkimg->mono);
-               XFillRectangle(dpy, d, gc, sx, sy, sw, sh);
+           /* The XFillRectangle code below does not work when we draw 
+               directly to the screen on the Mac, so we use XCopyArea with a 
+               small colored offscreen pixmap instead (this method does not 
+               work on Unix or during double buffered drawing on the Mac). */ 
+#ifdef MAC
+           if (!imfsample->double_buffer) {
+               Pixmap pm = 
+                   Tk_GetPixmap(dpy, Tk_WindowId(tkwin), sw, sh, 
+                                DefaultDepthOfScreen(Tk_Screen(tkwin)));
+
+               /* Draw the mask. */
+               if (tkimg->mask && imfsample->show_masks) {
+                   XSetClipMask(dpy, gc, tkimg->mask);
+               } else {
+                   XSetClipMask(dpy, gc, tkimg->mono);
+               }
+               if (tkimg->mono != None) {
+                   Tk_Fill3DRectangle(tkwin, pm, white_border, 0, 0, 
+                                      sw, sh, 0, 0);
+               } else {
+                   Tk_Fill3DRectangle(tkwin, pm, black_border, 0, 0, 
+                                      sw, sh, 0, 0);
+               }
+               XCopyArea(dpy, pm, Tk_WindowId(tkwin), gc, 0, 0, 
+                         sw, sh, sx, sy);
+               /* Draw the image proper. */
+               if (tkimg->mono != None) {
+                   XSetClipMask(dpy, gc, tkimg->mono);
+                   Tk_Fill3DRectangle(tkwin, pm, black_border, 0, 0, 
+                                      sw, sh, 0, 0);
+                   XCopyArea(dpy, pm, Tk_WindowId(tkwin), gc, 0, 0, 
+                             sw, sh, sx, sy);
+               }
+               Tk_FreePixmap(dpy, pm);
+               return;
            }
+#endif
+
+               XSetFillStyle(dpy, gc, FillSolid);
+               /* Set the color we're going to use for the mask; use the
+               imagecolor if we'll be using the mask as the only image. */
+               XSetForeground(dpy, gc,
+                       (tkimg->mono == None ? imagecolor : maskcolor)->pixel);
+               XSetClipOrigin(dpy, gc, sx2, sy2);
+               /* Set the clip mask to be explicit mask or unit's image. */
+               if (tkimg->mask && imfsample->show_masks) {
+                       XSetClipMask(dpy, gc, tkimg->mask);
+               } else {
+                       XSetClipMask(dpy, gc, tkimg->mono);
+               }
+               /* Draw the mask. */
+               XFillRectangle(dpy, d, gc, sx, sy, sw, sh);
+               /* Draw the image proper. */
+               if (tkimg->mono != None) {
+                   XSetForeground(dpy, gc, imagecolor->pixel);
+                   XSetClipMask(dpy, gc, tkimg->mono);
+                   XFillRectangle(dpy, d, gc, sx, sy, sw, sh);
+               }
+       /* The Win32 case. */
        } else {
            if (tkimg->mask != None && imfsample->show_masks) {
                XSetFunction(dpy, gc, GXand);