Logo Search packages:      
Sourcecode: jed version File versions

wterm.c

/* Copyright (c) 1992, 1998, 2000, 2002 John E. Davis
 * This file is part of JED editor library source.
 *
 * You may distribute this file under the terms the GNU General Public
 * License.  See the file COPYING for more information.
 */
#define HAS_PALETTE_CODE 0

#include "config.h"
#include "jed-feat.h"

#include <windows.h>
#include <stdio.h>
#include <slang.h>

#include "jdmacros.h"

#include <process.h>
#include <stdlib.h>
#include <string.h>

#include <time.h>

#include <assert.h>
#include <io.h>
#include <errno.h>

#include "display.h"
#include "buffer.h"
#include "sysdep.h"
#include "screen.h"
#include "keymap.h"
#include "hooks.h"
#include "ins.h"
#include "ledit.h"
#include "misc.h"
#include "cmds.h"
#include "sig.h"
#include "vterm.h"
#include "win32.h"
#include "colors.h"

#if JED_HAS_SUBPROCESSES
# include "jprocess.h"
#endif

#ifdef __WIN32__
# define HAS_WHEEL_MOUSE_SUPPORT    1
#else
# define HAS_WHEEL_MOUSE_SUPPORT    0
#endif

#define MSW_STRING_TYPE   1
#define MSW_INT_TYPE      2
#define MSW_COLOR_TYPE    3

#define MAX_STRING_SIZE   128
#define MAX_KEYS          128

#define KEY_SHIFT         1
#define KEY_CONTROL       2
#define KEY_ALT           4

int NumLock_Is_Gold = 0;
int PC_Alt_Char = 27;
int PC_Fn_Char = 0;

#define SPACE_CHAR        (32 | (JNORMAL_COLOR << 8))

#define MAX_MENU_ID       256

#if !defined(_MSC_VER) && !defined(__CYGWIN32__) && !defined(__MINGW32__)
extern HINSTANCE _hInstance;
#else
HINSTANCE _hInstance;
#endif

#ifdef __WIN32__
HINSTANCE _hPrev;
#else
extern HINSTANCE _hPrev;
#endif

/* #define CURRENT_BG_COLOR JColors[JNORMAL_COLOR].hbrBG */
#define CURRENT_BG_COLOR This_Window.current_color->hbrBG

#if HAS_WHEEL_MOUSE_SUPPORT

#ifndef WM_MOUSEWHEEL
# define WM_MOUSEWHEEL (WM_MOUSELAST+1)  /* message that will be supported by the OS */
#endif

/* Details of the mystery mouse wheel window */

#define MOUSEZ_CLASSNAME  "MouseZ"            /* wheel window class */
#define MOUSEZ_TITLE      "Magellan MSWHEEL"  /* wheel window title */

#define MSH_WHEELMODULE_CLASS (MOUSEZ_CLASSNAME)
#define MSH_WHEELMODULE_TITLE (MOUSEZ_TITLE)
#define MSH_MOUSEWHEEL     "MSWHEEL_ROLLMSG"
#define MSH_WHEELSUPPORT   "MSH_WHEELSUPPORT_MSG"  /* name of msg to send to query for wheel support */
#define MSH_SCROLL_LINES   "MSH_SCROLL_LINES_MSG"

/* Details of the mouse wheel functionality - not all currently used by Wjed */

typedef struct
{
   HWND hwnd;                 
   UINT uiMshMsgMouseWheel,   
        uiMshMsg3DSupport,    
        uiMshMsgScrollLines;  
   INT  iScrollLines;
   BOOL fActive;
}
MS_Wheel_Type;

static MS_Wheel_Type Wheel_Mouse;

#endif                                 /* HAS_WHEEL_MOUSE_SUPPORT */


typedef struct
{
   char  *name;
   int    type;
   char  *dflt;
   void  *buf;
}
Msw_Ini_Type;

typedef struct
{
   COLORREF bg;
   COLORREF fg;
   HBRUSH   hbrBG;
}
Color_Type;

typedef struct
{
   char *name;
   int r, g, b;
}
Color_Value_Type;

typedef struct
{
   char        title[MAX_STRING_SIZE];
   HWND        w;
   HDC         hdc;
   int         ndc;

   char        font_name[MAX_STRING_SIZE];
   int         font_height;
   int         font_bold;
   int         font_width;
   HFONT       font;

   int         x;
   int         y;
   int         height;
   int         width;

   int         scroll_r1, scroll_r2;        /* scrolling region */
   int         cursor_row, cursor_col;      /* row column of cursor (1,1) origin */
   int         vis_curs_row, vis_curs_col;  /* position of VISIBLE cursor */
   int         cursor_showing;

   Color_Type *current_color;

   int         focus;
}
MSWindow_Type;

LRESULT CALLBACK JEDWndProc(HWND, UINT, WPARAM, LPARAM);

static void msw_cleanup(void);
static void msw_get_defaults(void);
static void msw_get_default(Msw_Ini_Type *t);
static void get_dc(void);
static void release_dc(void);
static void init_application(void);
static void init_instance(void);
void process_message(void);
static void show_cursor(void);
static void hide_cursor(void);
static void msw_normal_video(void);
static void set_window_name(char *s);
static void msw_define_color(char *, int *, int *, int *);
static void msw_select_font(char *, int *, int *);

static void get_menubar(void);
static void destroy_menubar(void);
static void create_popup_menu(void);
static void destroy_menu(void);
static void append_menu_item(void);
static void append_popup_menu(void);
static void append_separator(void);
static void insert_menu_item(void);
static void insert_menu_item_pos(void);
static void insert_popup_menu(void);
static void insert_popup_menu_pos(void);
static void insert_separator(void);
static void insert_separator_pos(void);
static void delete_menu_item(void);
static void delete_menu_item_pos(void);
static void get_menu_state(void);
static void get_menu_state_pos(void);
static void get_popup_menu(void);
static void check_menu_item(void);
static void check_menu_item_pos(void);
static void enable_menu_item(void);
static void enable_menu_item_pos(void);
static void redraw_menubar(void);

static void set_init_popup_callback(void);
static void msw_help(void);

static HINSTANCE hPrevInst;
static HINSTANCE hInstance;
static char *szJedSection = "WJED";

static int MSW_Screen_Cols;
static int MSW_Screen_Rows;
static int MSW_Term_Cannot_Scroll = 0;
static int MSW_Term_Cannot_Insert = 0;
static int MSW_Use_Ansi_Colors = 1;
static int MSW_Ignore_Beep = 3;
static int Performing_Update;

static MSWindow_Type This_Window;
static Color_Type JColors[JMAX_COLORS];

static char *InitPopup_Callback;
static char *Menu_Callbacks[MAX_MENU_ID];

#if HAS_PALETTE_CODE
static LPLOGPALETTE The_Lplgpl = NULL;
static HPALETTE The_Hpalette = NULL;
#endif

static char Font_Name[MAX_STRING_SIZE];
static int Font_Height;
static int Font_Bold;

static Msw_Ini_Type Msw_Ini_List[] =
{
     { "Font",         MSW_STRING_TYPE,   "fixed",         Font_Name },
     { "FontHeight",   MSW_INT_TYPE,      "12",            &Font_Height },
     { "FontBold",     MSW_INT_TYPE,      "-1",            &Font_Bold },
     { "Background",   MSW_COLOR_TYPE,    "0,0,0",         &JColors[JNORMAL_COLOR].bg },
     { "Foreground",   MSW_COLOR_TYPE,    "192,192,192",   &JColors[JNORMAL_COLOR].fg },
     { "StatusBG",     MSW_COLOR_TYPE,    "0,0,128",       &JColors[JSTATUS_COLOR].bg },
     { "StatusFG",     MSW_COLOR_TYPE,    "255,255,0",     &JColors[JSTATUS_COLOR].fg },
     { "RegionBG",     MSW_COLOR_TYPE,    "255,0,255",     &JColors[JREGION_COLOR].bg },
     { "RegionFG",     MSW_COLOR_TYPE,    "255,255,255",   &JColors[JREGION_COLOR].fg },
     { "OperatorBG",   MSW_COLOR_TYPE,    "0,0,0",         &JColors[JOP_COLOR].bg },
     { "OperatorFG",   MSW_COLOR_TYPE,    "255,255,255",   &JColors[JOP_COLOR].fg },
     { "NumberBG",     MSW_COLOR_TYPE,    "0,0,0",         &JColors[JNUM_COLOR].bg },
     { "NumberFG",     MSW_COLOR_TYPE,    "0,0,192",       &JColors[JNUM_COLOR].fg },
     { "StringBG",     MSW_COLOR_TYPE,    "0,0,0",         &JColors[JSTR_COLOR].bg },
     { "StringFG",     MSW_COLOR_TYPE,    "0,192,255",     &JColors[JSTR_COLOR].fg },
     { "CommentBG",    MSW_COLOR_TYPE,    "0,0,0",         &JColors[JCOM_COLOR].bg },
     { "CommentFG",    MSW_COLOR_TYPE,    "0,128,0",       &JColors[JCOM_COLOR].fg },
     { "KeywordBG",    MSW_COLOR_TYPE,    "0,0,0",         &JColors[JKEY_COLOR].bg },
     { "KeywordFG",    MSW_COLOR_TYPE,    "255,255,255",   &JColors[JKEY_COLOR].fg },
     { "Keyword1BG",   MSW_COLOR_TYPE,    "0,0,0",         &JColors[JKEY_COLOR + 1].bg },
     { "Keyword1FG",   MSW_COLOR_TYPE,    "255,255,255",   &JColors[JKEY_COLOR + 1].fg },
     { "DelimiterBG",  MSW_COLOR_TYPE,    "0,0,0",         &JColors[JDELIM_COLOR].bg },
     { "DelimiterFG",  MSW_COLOR_TYPE,    "255,255,255",   &JColors[JDELIM_COLOR].fg },
     { "PreprocessBG", MSW_COLOR_TYPE,    "0,0,0",         &JColors[JPREPROC_COLOR].bg },
     { "PreprocessFG", MSW_COLOR_TYPE,    "0,255,0",       &JColors[JPREPROC_COLOR].fg },
     { "MessageBG",    MSW_COLOR_TYPE,      "0,0,0",         &JColors[JMESSAGE_COLOR].bg},
     { "MessageFG",    MSW_COLOR_TYPE,      "255,255,0",     &JColors[JMESSAGE_COLOR].fg},
     { "ErrorFG",      MSW_COLOR_TYPE,      "255,0,0",       &JColors[JERROR_COLOR].fg},
     { "ErrorBG",      MSW_COLOR_TYPE,      "0,0,0",         &JColors[JERROR_COLOR].bg},
     { "MenuFG",       MSW_COLOR_TYPE,      "0,0,0",         &JColors[JMENU_COLOR].fg},
     { "MenuBG",       MSW_COLOR_TYPE,      "0,255,255",     &JColors[JMENU_COLOR].bg},
     {"CursorFG",      MSW_COLOR_TYPE,      "0,255,0",       &JColors[JCURSOR_COLOR].fg},
     {"CursorBG",      MSW_COLOR_TYPE,      "255,0,0",       &JColors[JCURSOR_COLOR].bg},
     {"DollarFG",      MSW_COLOR_TYPE,      "0,0,255",       &JColors[JDOLLAR_COLOR].fg},
     {"DollarBG",      MSW_COLOR_TYPE,      "0,0,0",         &JColors[JDOLLAR_COLOR].bg},
     {"CursorOvrFG",   MSW_COLOR_TYPE,      "255,0,0",         &JColors[JCURSOROVR_COLOR].fg},
     {"CursorOvrBG",   MSW_COLOR_TYPE,    "0,255,0",     &JColors[JCURSOROVR_COLOR].bg},
     { "Title",        MSW_STRING_TYPE,   "WJED",          This_Window.title },
     { "X",            MSW_INT_TYPE,      "0",             &This_Window.x },
     { "Y",            MSW_INT_TYPE,      "0",             &This_Window.y },
     { "Width",        MSW_INT_TYPE,      "700",           &This_Window.width },
     { "Height",       MSW_INT_TYPE,      "500",           &This_Window.height },
     { NULL,           0,                 NULL,            NULL }
};

static Color_Value_Type Msw_Std_Color[] =
{
     {"black", 0, 0, 0},
     {"blue", 0, 0, 192},
     {"green", 0, 128, 0},
     {"cyan", 0, 192, 192},
     {"red", 192, 0, 0},
     {"magenta", 192, 0, 192},
     {"lightgray", 192, 192, 192},
     {"gray", 128, 128, 128},
     {"brightblue", 0, 0, 255},
     {"brightred", 255, 0, 0},
     {"brightgreen", 0, 255, 0},
     {"brightcyan", 0, 255, 255},
     {"brightmagenta", 255, 0, 255},
     {"yellow", 255, 255, 0},
     {"white", 255, 255, 255},
     {"brown", 110, 74, 32},
     {NULL, 0, 0, 0}
};

#define S SLANG_STRING_TYPE
#define I SLANG_INT_TYPE
static SLang_Intrin_Fun_Type Jed_WinGUI_Table[] =
{
   MAKE_INTRINSIC_SII("w32_select_font", msw_select_font, VOID_TYPE),
   MAKE_INTRINSIC_S("x_set_window_name", set_window_name, VOID_TYPE),
   MAKE_INTRINSIC_4("w32_define_color", msw_define_color, VOID_TYPE, S,I,I,I),
   /*Prototype: Void msw_define_color(char *, int, int, int);*/
   MAKE_INTRINSIC("w32_get_menubar", get_menubar, VOID_TYPE, 0),
   /* Prototype: Integer get_menubar(Void);
    * Returns integer which is handle of menubar. If there is no
    * menubar, it creates it.
    * To show menubar, call `redraw_menu'
    */
   MAKE_INTRINSIC("w32_destroy_menubar", destroy_menubar, VOID_TYPE, 0),
   /* Prototype: Void destroy_menubar(Void);
    * Destroys menubar
    */
   MAKE_INTRINSIC("w32_create_popup_menu", create_popup_menu, VOID_TYPE, 0),
   /* Prototype: Integer create_popup_menu(Void);
    * Creates empty popup menu and returns integer value which is
    * it's handle. If popup is not appended to another menu, it must
    * destroyed after use.
    */
   MAKE_INTRINSIC("w32_destroy_menu", destroy_menu, VOID_TYPE, 0),
   /* Prototype: Void destroy_menu(Integer hmenu);
    * Destroys menu and all it's popup menus.
    * Note: Do not destroy menubar with this function
    *       (use `destroy_menubar')
    */
   MAKE_INTRINSIC("w32_append_menu_item", append_menu_item, VOID_TYPE, 0),
   /* Prototype: Void append_menu_item(Integer hmenu, String name, Integer id, String callback);
    * Appends menu item with name 'name' and identifier 'id' at the end
    * of 'hmenu'. When item is selected, the 'callback' will be executed.
    * Callback can be intrinsic or internal function.
    */
   MAKE_INTRINSIC("w32_append_popup_menu", append_popup_menu, VOID_TYPE, 0),
   /* Prototype: Void append_popop_menu(Integer hmenu, String name, Integer popup);
    * Appends popup menu with name 'name' and handle 'popup' at the end
    * of 'hmenu'
    */
   MAKE_INTRINSIC("w32_append_separator", append_separator, VOID_TYPE, 0),
   /* Prototype: Void append_separator(Integer hmenu);
    * Appends menu separator at the end of 'hmenu'
    */
   MAKE_INTRINSIC("w32_insert_menu_item", insert_menu_item, VOID_TYPE, 0),
   /* Prototype: Void insert_menu_item(Integer hmenu, Integer id, String name, Integer idNew, String callback);
    * Inserts menu item with name 'name' and identifier 'idNew' before
    * menu item with identifier 'id'.
    * When item is selected, the 'callback' will be executed.
    * Callback can be intrinsic or internal function.
    */
   MAKE_INTRINSIC("w32_insert_menu_item_pos", insert_menu_item_pos, VOID_TYPE, 0),
   /* Prototype: Void insert_menu_item_pos(Integer hmenu, Integer pos, String name, Integer idNew, String callback);
    * Inserts menu item with name 'name' and identifier 'idNew' before
    * menu item with zero-based position 'pos' in 'hmenu'.
    * When item is selected, the 'callback' will be executed.
    * Callback can be intrinsic or internal function.
    */
   MAKE_INTRINSIC("w32_insert_popup_menu", insert_popup_menu, VOID_TYPE, 0),
   /* Prototype: Void insert_popup_menu(Integer hmenu, Integer id, String name, Integer popup);
    * Inserts popup menu with name 'name' and handle 'popup' before
    * menu item with identifier 'id'
    */
   MAKE_INTRINSIC("w32_insert_popup_menu_pos", insert_popup_menu_pos, VOID_TYPE, 0),
   /* Prototype: Void insert_popup_menu_pos(Integer hmenu, Integer pos, String name, Integer popup);
    * Inserts popup menu with name 'name' and handle 'popup' before
    * menu item with zero-based position 'pos' in 'hmenu'
    */
   MAKE_INTRINSIC("w32_insert_separator", insert_separator, VOID_TYPE, 0),
   /* Prototype: Void insert_separator(Integer hmenu, Integer id);
    * Inserts menu separator before menu item with identifier 'id'
    */
   MAKE_INTRINSIC("w32_insert_separator_pos", insert_separator_pos, VOID_TYPE, 0),
   /* Prototype: Void insert_separator_pos(Integer hmenu, Integer pos);
    * Inserts menu separator before menu item with zero-based position 'pos'
    */
   MAKE_INTRINSIC("w32_delete_menu_item", delete_menu_item, VOID_TYPE, 0),
   /* Prototype: Void delete_menu_item(Integer hmenu, Integer id);
    * Deletes menu item with identifier id from menu with handle 'hmenu'
    */
   MAKE_INTRINSIC("w32_delete_menu_item_pos", delete_menu_item_pos, VOID_TYPE, 0),
   /* Prototype: Void delete_menu_item_pos(Integer hmenu, Integer pos);
    * Deletes menu item at zero-based position 'pos' from menu 'hmenu'
    */
   MAKE_INTRINSIC("w32_get_menu_state", get_menu_state, VOID_TYPE, 0),
   /* Prototype: Integer get_menu_state(Integer hmenu, Integer id);
    * Gets state of menu item with identifier 'id'
    * <return value> & 1 == 1 if menu item is enabled
    * <return value> & 2 == 1 if menu item is checked
    */
   MAKE_INTRINSIC("w32_get_menu_state_pos", get_menu_state_pos, VOID_TYPE, 0),
   /* Prototype: Integer get_menu_state(Integer hmenu, Integer pos);
    * Gets state of menu item at zero-based position 'pos'
    * <return value> & 1 == 1 if menu item is enabled
    * <return value> & 2 == 1 if menu item is checked
    */
   MAKE_INTRINSIC("w32_get_popup_menu", get_popup_menu, VOID_TYPE, 0),
   /* Prototype: Void get_popup_menu(Integer hmenu, Integer pos);
    * Returns handle of popup menu at zero-based position 'pos'
    * If return value is 0, there is no popup at the position.
    */
   MAKE_INTRINSIC("w32_check_menu_item", check_menu_item, VOID_TYPE, 0),
   /* Prototype: Void check_menu_item(Integer hmenu, Integer id, Integer flag);
    * This functions changes check state of menu item. If flag is nonzero,
    * it checks menu item, otherwise it unchecks it
    */
   MAKE_INTRINSIC("w32_check_menu_item_pos", check_menu_item_pos, VOID_TYPE, 0),
   /* Prototype: Void check_menu_item(Integer hmenu, Integer pos, Integer flag);
    * This functions changes check state of menu item. If flag is nonzero,
    * it checks menu item, otherwise it unchecks it
    */
   MAKE_INTRINSIC("w32_enable_menu_item", enable_menu_item, VOID_TYPE, 0),
   /* Prototype: Void check_menu_item(Integer hmenu, Integer id, Integer flag);
    * This functions enable or disable menu item. If flag is nonzero, the
    * menu item will be enabled, otherwise it'll be disabled.
    */
   MAKE_INTRINSIC("w32_enable_menu_item_pos", enable_menu_item_pos, VOID_TYPE, 0),
   /* Prototype: Void check_menu_item(Integer hmenu, Integer pos, Integer flag);
    * This functions enable or disable menu item. If flag is nonzero, the
    * menu item will be enabled, otherwise it'll be disabled.
    */
   MAKE_INTRINSIC("w32_redraw_menubar", redraw_menubar, VOID_TYPE, 0),
   /* Prototype: Void redraw_menubar(Void);
    * Redraws menubar. This functions should be called if menubar is changed
    */

   MAKE_INTRINSIC("w32_set_init_popup_callback", set_init_popup_callback, VOID_TYPE, 0),
   /* Prototype: Void set_init_popup_callback(String callback);
    * Executes callback before menu poppup was popped up.
    */

   MAKE_INTRINSIC("msw_help", msw_help, VOID_TYPE, 0),
   /* Prototype: Void msw_help(String filename, String keword, Integer Partial_Keys);
    * Starts Windows Help with 'filename' help file. If 'keyword' is not null
    * string shows topic with specified keyword. If 'Partial_Keys' != 0
    * shows Search dialog if there is more than one help topic beginnig with
    * 'keyword'
    */

   MAKE_INTRINSIC(NULL, NULL, 0, 0)
};
#undef S
#undef I

static void _putkey (char c)
{
   buffer_keystring (&c, 1);
}

/* Getting defaults from INI file */
static COLORREF msw_get_color(char *s, char *dflt)
{

   if (s[0] >= '0' && s[0] <= '9')
     {
      long r, g, b;
      char *sptr, *endptr;

      sptr = s;
      r = strtol(sptr, &endptr, 0);
      while ((*endptr == ' ') || (*endptr == '\t')) endptr++; /* skipping whitespace */
      if ((sptr == endptr) || (*endptr++ != ',')) return msw_get_color(dflt, dflt);
      sptr = endptr;

      g = strtol(sptr, &endptr, 0);
      while ((*endptr == ' ') || (*endptr == '\t')) endptr++; /* skipping whitespace */

      if ((sptr == endptr) || (*endptr++ != ',')) return msw_get_color(dflt, dflt);
      sptr = endptr;

      b = strtol(sptr, &endptr, 0);
      while ((*endptr == ' ') || (*endptr == '\t')) endptr++; /* skipping whitespace */
      if ((sptr == endptr) || (*endptr++ != 0)) return msw_get_color(dflt, dflt);

#if HAS_PALETTE_CODE
      return PALETTERGB((BYTE)r, (BYTE)g, (BYTE)b);
#else
      return RGB((BYTE)r, (BYTE)g, (BYTE)b);
#endif
     }
   else
     {
      char buf[50];
      GetProfileString(szJedSection, s, dflt, buf, sizeof(buf));
      if (buf[0] >='0' && buf[0] <= '9')
        return msw_get_color(buf, dflt);
      else
        return msw_get_color(dflt, dflt);
     }
}

static void msw_get_default(Msw_Ini_Type *t)
{
   char s[MAX_STRING_SIZE];

   GetProfileString(szJedSection, t->name, t->dflt, s, sizeof(s));

   switch (t->type)
     {
      case MSW_STRING_TYPE:
      strncpy((char *)t->buf, s, MAX_STRING_SIZE);
      ((char *)t->buf)[MAX_STRING_SIZE-1] = 0;
      break;

      case MSW_INT_TYPE:
      *(int *)t->buf = atoi(s);
      break;

      case MSW_COLOR_TYPE:
      *(COLORREF *)t->buf = msw_get_color(s, t->dflt);
      break;
     }

}

static void msw_get_defaults(void)
{
   int i = 0;
   char buf[128];

   /* Check for standard color names in INI file.
    * Add they if cannot find. */
   while (Msw_Std_Color[i].name != NULL)
     {
      if (!GetProfileString(szJedSection, Msw_Std_Color[i].name, "", buf, sizeof(buf)))
        msw_define_color(Msw_Std_Color[i].name, &Msw_Std_Color[i].r, &Msw_Std_Color[i].g, &Msw_Std_Color[i].b);

      i++;
     }

   i = 0;
   while (Msw_Ini_List[i].name != NULL)
     msw_get_default(&Msw_Ini_List[i++]);
}

static void get_dc(void)
{

   if (!This_Window.ndc)
     {
      This_Window.hdc = GetDC(This_Window.w);
#if HAS_PALETTE_CODE
      SelectPalette (This_Window.hdc, The_Hpalette, FALSE);
#endif
     }
   This_Window.ndc++;
}

static void release_dc(void)
{
   assert(This_Window.ndc);

   if (This_Window.ndc == 1) ReleaseDC(This_Window.w, This_Window.hdc);
   This_Window.ndc--;
}

void process_message(void)
{
   MSG msg;

   if (
#ifdef _MSC_VER
       GetMessage(&msg, NULL, 0, 0)
#else
       PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)
#endif
       )
     {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
     }
}

static void init_application(void)
{
   WNDCLASS wc;

   wc.style = 0;
   wc.lpfnWndProc = JEDWndProc;
   wc.cbClsExtra = 0;
   wc.cbWndExtra = 0;
   wc.hInstance = hInstance;
   wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
   wc.hCursor = LoadCursor(NULL, IDC_IBEAM);
   wc.hbrBackground = NULL;
   wc.lpszMenuName = NULL;
   wc.lpszClassName = "wjed";

   RegisterClass(&wc);
}

static int select_font(char *fontname, int fontheight, int fontbold)
{
   TEXTMETRIC tm;
   HFONT font;
   int height, weight;

   get_dc();
   SetMapMode(This_Window.hdc, MM_TEXT);

   if (fontbold < 0)
     weight = FW_DONTCARE;
   else
     weight = fontbold > 0 ? FW_BOLD : FW_NORMAL;

   height = -MulDiv(fontheight, GetDeviceCaps(This_Window.hdc, LOGPIXELSY), 72);

   font = CreateFont(height, 0, 0, 0,
                     weight, 0, 0, 0,
                     DEFAULT_CHARSET, 0, 0, 0, FIXED_PITCH,
                     fontname);

   if (font == NULL)
     {
      /* This should never happen as we've told CreateFont to use the default */
      /* character set if the requested one isn't available. */
      jed_verror ("Unable to create instance of '%s' font", fontname);
      release_dc ();
      return -1;
     }

   if(This_Window.font != NULL)
     DeleteObject(This_Window.font);

   This_Window.font        = font;
   This_Window.font_bold   = fontbold;
   This_Window.font_height = fontheight;
      
   strncpy(This_Window.font_name, fontname, MAX_STRING_SIZE-1);
   This_Window.font_name[MAX_STRING_SIZE-1] = '\0';

   /* retrieve font metrics (width and base) */
   
   SelectObject(This_Window.hdc, This_Window.font);
   GetTextMetrics(This_Window.hdc, &tm);
   This_Window.font_width = tm.tmAveCharWidth;
   This_Window.font_height = tm.tmHeight;
   
   
   release_dc();
   return 0;
}


static void init_instance (void)
{
   int i;
   TEXTMETRIC tm;

   This_Window.hdc = NULL;
   This_Window.ndc = 0;

   for (i = 0; i < MAX_MENU_ID; i++) Menu_Callbacks[i] = NULL;
   InitPopup_Callback = NULL;

   msw_get_defaults();

/* Apparantly this is wrong */
   /* if (This_Window.font_bold < 0) */
   /*   font_weight = FW_DONTCARE; */
   /* else */
   /*   font_weight = (This_Window.font_bold > 0) ? FW_BOLD : FW_NORMAL; */

   /* This_Window.font = CreateFont(-This_Window.font_height, 0, 0, 0, */
   /*                          font_weight, */
   /*                          0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, FIXED_PITCH, */
   /*                          This_Window.font_name); */
#if !HAS_PALETTE_CODE
   for (i = 0; i < JMAX_COLORS; i++)
     JColors[i].hbrBG = CreateSolidBrush(JColors[i].bg);
#endif

   msw_normal_video();

   /* creating window */
   This_Window.w = CreateWindow("wjed", This_Window.title, WS_OVERLAPPEDWINDOW, This_Window.x,
                        This_Window.y, This_Window.width,This_Window.height, NULL, NULL,
                        hInstance, NULL);
   get_dc();
#if HAS_PALETTE_CODE
   if ((RC_PALETTE & GetDeviceCaps (This_Window.hdc, RASTERCAPS)) &&
       (NULL != (The_Lplgpl = malloc (sizeof(*The_Lplgpl) - sizeof(The_Lplgpl->palPalEntry)
                              + 2*JMAX_COLORS * sizeof(PALETTEENTRY)))))
     {
      The_Lplgpl->palVersion = 0x300;
      The_Lplgpl->palNumEntries = JMAX_COLORS*2;
      for (i = 0; i < JMAX_COLORS; i++)
        {
           The_Lplgpl->palPalEntry[i*2].peRed = GetRValue (JColors[i].fg);
           The_Lplgpl->palPalEntry[i*2].peGreen = GetGValue (JColors[i].fg);
           The_Lplgpl->palPalEntry[i*2].peBlue = GetBValue (JColors[i].fg);
           The_Lplgpl->palPalEntry[i*2].peFlags = PC_NOCOLLAPSE;

           The_Lplgpl->palPalEntry[i*2+1].peRed = GetRValue (JColors[i].bg);
           The_Lplgpl->palPalEntry[i*2+1].peGreen = GetGValue (JColors[i].bg);
           The_Lplgpl->palPalEntry[i*2+1].peBlue = GetBValue (JColors[i].bg);
           The_Lplgpl->palPalEntry[i*2+1].peFlags = PC_NOCOLLAPSE;
        }
      The_Hpalette = CreatePalette (The_Lplgpl);
      if (The_Hpalette)
        {
           SelectPalette (This_Window.hdc, The_Hpalette, FALSE);
           RealizePalette (This_Window.hdc);
        }
     }
   /* ReleaseDC (This_Window.w, This_Window.hdc); */

   for (i = 0; i < JMAX_COLORS; i++)
     JColors[i].hbrBG = CreateSolidBrush(JColors[i].bg);
#endif                               /* HAS_PALETTE_CODE */

   /* creating fonts, brushes etc */
   (void) select_font (Font_Name, Font_Height, Font_Bold);

#ifdef _MSC_VER
   SetTimer (This_Window.w, 43, 100, NULL);
#endif

   /* function that will be called when jed exits (deletes fonts, brushes etc.) */
   atexit(msw_cleanup);

   /* retrieve font metrics (width and base) */
   /* get_dc(); */

   SelectObject(This_Window.hdc, This_Window.font);
   GetTextMetrics(This_Window.hdc, &tm);
   This_Window.font_width = tm.tmAveCharWidth;
   This_Window.font_height = tm.tmHeight;
   release_dc();

   ShowWindow(This_Window.w, SW_SHOW);
   UpdateWindow(This_Window.w);

#if !defined(__WIN32__) || !JED_HAS_SUBPROCESSES
   SetTimer(This_Window.w, 42, 30000, NULL);     /* used for updating display time */
#endif
}

static int msw_init_term (void)
{
   if (Batch) return 0;

   hInstance = _hInstance;
   hPrevInst = _hPrev;

   if (!hPrevInst) init_application();

   init_instance();
   return 0;
}


static void copy_rect(int x1, int y1, int x2, int y2, int x3, int y3)
{
   int dx, dy;
   RECT rcSrc;

   dx = (x3 - x1) * This_Window.font_width;
   dy = (y3 - y1) * This_Window.font_height;

   SetRect(&rcSrc, x1 * This_Window.font_width, y1 * This_Window.font_height, x2 * This_Window.font_width, y2 * This_Window.font_height);

   ScrollWindow(This_Window.w, dx, dy, &rcSrc, NULL);

#ifdef __WIN32__
   UpdateWindow(This_Window.w);
#endif
}

static void blank_rect(int x1, int y1, int x2, int y2)
{
   char blanks[256];
   
   memset (blanks, ' ', sizeof (blanks));

   if (This_Window.cursor_showing) hide_cursor();

   get_dc ();
   SelectObject(This_Window.hdc, This_Window.font);
   SetTextColor(This_Window.hdc, This_Window.current_color->fg);
   SetBkColor(This_Window.hdc, This_Window.current_color->bg);

   while (y1 < y2)
     {
      int n = x2 - x1;
      int xx = x1;

      while (n > 0)
        {
           int dn;
           if (n > (int) sizeof (blanks))
             dn = sizeof (blanks);
           else
             dn = n;

           (void) TextOut(This_Window.hdc, xx * This_Window.font_width, 
                      y1 * This_Window.font_height, blanks, dn);
           n -= dn;
           xx += dn;
        }
      y1++;
     }
   release_dc ();
#if 0
   RECT rc;

   SetRect(&rc, x1 * This_Window.font_width, y1 * This_Window.font_height, x2 * This_Window.font_width, y2 * This_Window.font_height);
   get_dc();
   FillRect(This_Window.hdc, &rc, CURRENT_BG_COLOR);
   release_dc();
#endif
}

/* This routine assumes that cursor is in the correct location.  The
 cursor is placed at the end of the string. */
static void tt_write(char *s, int n)
{
   vterm_write_nchars (s, (unsigned int) n);

   get_dc();

   if (This_Window.cursor_showing) hide_cursor();
   SelectObject(This_Window.hdc, This_Window.font);
   SetTextColor(This_Window.hdc, This_Window.current_color->fg);
   SetBkColor(This_Window.hdc, This_Window.current_color->bg);
   TextOut(This_Window.hdc, This_Window.cursor_col * This_Window.font_width, This_Window.cursor_row * This_Window.font_height, s, n);

   This_Window.cursor_col += n;

   if (This_Window.cursor_col >= MSW_Screen_Cols) This_Window.cursor_col = MSW_Screen_Cols - 1;

   release_dc();
}

static void hide_cursor(void)
{
   SLsmg_Char_Type *s;
   char ch;
   int col = This_Window.vis_curs_col, row = This_Window.vis_curs_row;
   Color_Type *color;

   if ((This_Window.cursor_showing == 0)
       || (VTerm_Display == NULL))
     return;

   This_Window.cursor_showing = 0;

   s = VTerm_Display[row] + col; 
   ch = *s & 0xFF;

   get_dc();
   color = &JColors[*s >> 8];
   SelectObject(This_Window.hdc, This_Window.font);
   SetTextColor(This_Window.hdc, color->fg);
   SetBkColor(This_Window.hdc, color->bg);
   TextOut(This_Window.hdc, This_Window.cursor_col * This_Window.font_width, This_Window.cursor_row * This_Window.font_height, &ch, 1);
   release_dc();
}


static void show_cursor(void)
{
   SLsmg_Char_Type *s;
   char ch;
   int c, r;
   Color_Type *curs_color;
   RECT rc;

   if (VTerm_Display == NULL)
     return;

   if (This_Window.cursor_showing) hide_cursor();

   This_Window.cursor_showing = 1;

   r = This_Window.vis_curs_row = This_Window.cursor_row;
   c = This_Window.vis_curs_col = This_Window.cursor_col;

   s = VTerm_Display[r] + c;
   ch = *s & 0xFF;

   ch = (char) (*s & 0xFF);
   if (CBuf && CBuf->flags & OVERWRITE_MODE)
     curs_color = &JColors[JCURSOROVR_COLOR];
   else
     curs_color = &JColors[JCURSOR_COLOR];

   get_dc();
   if (This_Window.focus)
     {
      SelectObject(This_Window.hdc, This_Window.font);
      SetTextColor(This_Window.hdc, curs_color->fg);
      SetBkColor(This_Window.hdc, curs_color->bg);
      TextOut(This_Window.hdc, This_Window.cursor_col * This_Window.font_width, This_Window.cursor_row * This_Window.font_height, &ch, 1);
     }
   else
     {
      rc.left = This_Window.cursor_col * This_Window.font_width;
      rc.top = This_Window.cursor_row * This_Window.font_height;
      rc.right = rc.left + This_Window.font_width;
      rc.bottom = rc.top + This_Window.font_height;
      FrameRect(This_Window.hdc, &rc, curs_color->hbrBG);
     }

   release_dc();
}


void sys_suspend(void)
{
   ShowWindow(This_Window.w, SW_MINIMIZE);
}

void flush_output (void)
{
   fflush (stdout);
}

/* Hooks */
static void msw_update_open (void)
{
   hide_cursor ();
   Performing_Update = 1;
}

static void msw_update_close (void)
{
   Performing_Update = 0;
   if (JWindow->trashed) return;
   show_cursor ();
}

static int msw_init_slang (void)
{
   if ((-1 == SLadd_intrin_fun_table(Jed_WinGUI_Table, "WINGUI"))
       || (-1 == SLdefine_for_ifdef ("MOUSE")))
     return -1;

   return 0;
}

static void msw_suspend (void)
{
   WINDOWPLACEMENT wndpl;

   GetWindowPlacement(This_Window.w, &wndpl);

   if (wndpl.showCmd == SW_MINIMIZE)
     ShowWindow(This_Window.w, SW_NORMAL);
   else
     ShowWindow(This_Window.w, SW_MINIMIZE);
}

static void msw_define_xkeys (SLKeyMap_List_Type *map)
{
#if 0
   /* This is set by doskeys.c */
   SLkm_define_key ("^[Ow", (FVOID_STAR) bob, map);
   SLkm_define_key ("^[Oq", (FVOID_STAR) eob, map);
#endif
   SLkm_define_key ("\xE0\xE0", (FVOID_STAR) ins_char_cmd, map);
}

/* This routine is called from S-Lang inner interpreter.  It serves
 as a poor mans version of an interrupt 9 handler */
static void msw_check_kbd(void)
{
   MSG msg;

   if (Batch) return;

   while (PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE))
     process_message();
}

/* Terminal functions */
static void msw_goto_rc(int r, int c)
{
   get_dc();
   if (This_Window.cursor_showing) hide_cursor();

   r += This_Window.scroll_r1;
   if (r >= MSW_Screen_Rows) r = MSW_Screen_Rows - 1;
   if (c >= MSW_Screen_Cols) c = MSW_Screen_Cols - 1;

   This_Window.cursor_row = r;
   This_Window.cursor_col = c;

   vterm_goto_rc (r, c);
   if (!Performing_Update) show_cursor();
   release_dc();
}

static void msw_del_eol(void)
{
   blank_rect(This_Window.cursor_col, This_Window.cursor_row, MSW_Screen_Cols, This_Window.cursor_row + 1);
   vterm_del_eol ();
}

static void msw_delete_nlines(int n)
{
   int r1, r2;
   r1 = This_Window.cursor_row;
   r2 = This_Window.scroll_r2;

   if (r1 <= r2 - n) copy_rect(0, r1 + n, MSW_Screen_Cols, r2 + 1, 0, r1);
   r2++;
   blank_rect(0, r2 - n, MSW_Screen_Cols, r2);
   vterm_delete_nlines (n);
}

#if 0                          /* UNUSED */
static void msw_delete_char(void)
{
   copy_rect(This_Window.cursor_col + 1, This_Window.cursor_row, MSW_Screen_Cols, This_Window.cursor_row + 1,
           This_Window.cursor_col, This_Window.cursor_row);
}

static void msw_erase_line(void)
{
   blank_rect(0, This_Window.cursor_row, MSW_Screen_Cols, This_Window.cursor_row + 1);
}

static void msw_begin_insert(void)
{
   hide_cursor();
   copy_rect(This_Window.cursor_col, This_Window.cursor_row, MSW_Screen_Cols - 1, This_Window.cursor_row + 1,
           This_Window.cursor_col + 1, This_Window.cursor_row);
}

static void msw_end_insert(void)
{
}

/* This function is called assuming that cursor is in correct position */
static void msw_putchar(char ch)
{
   if (ch == '\b')
     {
      ch = ' ';
      if (This_Window.cursor_col == 0) return;
      This_Window.cursor_col--;
     }

   get_dc();
   if (Rev_Vid_Flag != JNORMAL_COLOR) msw_normal_video();
   tt_write(&ch, 1);
   show_cursor ();
   release_dc();
}


#endif                               /* UNUSED */

static int Rev_Vid_Flag;
static void msw_reverse_video(int color)
{
   if ((color < 0) || (color > JMAX_COLORS))
     return;

   Rev_Vid_Flag = color;
   This_Window.current_color = &JColors[color];
   vterm_reverse_video (color);
}

static void msw_normal_video(void)
{
   msw_reverse_video (JNORMAL_COLOR);
}

static void msw_cls(void)
{
   RECT rc;

   get_dc();
   GetClientRect(This_Window.w, &rc);
   FillRect(This_Window.hdc, &rc, CURRENT_BG_COLOR);
   release_dc();
   /* Unfortunately the background color produced by FillRect is slightly different
    * from the desired background.  So patch it up with blank_rect.
    */
   blank_rect (0, 0, MSW_Screen_Cols, MSW_Screen_Rows);
   vterm_cls ();
}

static void msw_beep(void)
{
   if (MSW_Ignore_Beep & 0x1) MessageBeep(0);

   if (MSW_Ignore_Beep & 0x2)
     {
      RECT rc;

      get_dc();
      GetClientRect(This_Window.w, &rc);
      InvertRect(This_Window.hdc, &rc);
      release_dc();

      InvalidateRect(This_Window.w, NULL, TRUE);
#ifdef __WIN32__
      UpdateWindow(This_Window.w);
#endif
     }
}

static void msw_reverse_index(int n)
{
   int r1, r2;

   r1 = This_Window.scroll_r1;
   r2 = This_Window.scroll_r2;

   if (r2 >= r1 + n) copy_rect(0, r1, MSW_Screen_Cols, r2 - n + 1, 0, r1 + n);

   blank_rect(0, r1, MSW_Screen_Cols, r1 + n);
   vterm_reverse_index (n);
}

static void msw_write_string (char *s)
{
   get_dc();
   tt_write(s, strlen(s));
   if (!Performing_Update) show_cursor ();
   release_dc();
}

static void send_attr_str (SLsmg_Char_Type *s, SLsmg_Char_Type *smax)
{
   unsigned char out[256], ch, attr, *p, *pmax;
   register SLsmg_Char_Type sh;
   
   p = out;
   pmax = out + (sizeof(out)-1);
   get_dc();
   while (s < smax)
     {
      sh = *s++;
      ch = sh & 0xFF;
      attr = sh >> 8;
      if ((attr == 0) && (Rev_Vid_Flag != 0))
        {
           if (p != out)
             {
              *p = 0;
              msw_write_string ((char *) out);
              p = out;
             }
           msw_normal_video();
           /* Rev_Vid_Flag = 0; */
        }
      else if ((attr != 0) && (Rev_Vid_Flag != attr))
        {
           if (p != out)
             {
              *p = 0;
              msw_write_string ((char *) out);
              p = out;
             }
           msw_reverse_video(attr);
           /* Rev_Vid_Flag = 1; */
        }
      *p = ch;
      if (p < pmax)
        p++;
     }
   *p = 0;
   if (p != out) msw_write_string ((char *) out);
   /* if (Rev_Vid_Flag) tt_normal_video(); */
   release_dc();
}

static void msw_smart_puts(SLsmg_Char_Type *neww, SLsmg_Char_Type *oldd, int len, int row)
{
   if (0 == memcmp ((char *) neww, (char *) oldd, len * sizeof (SLsmg_Char_Type)))
     return;

   msw_goto_rc (row, 0);
   send_attr_str (neww, neww + len);
}

static void msw_set_scroll_region(int r1, int r2)
{
   This_Window.scroll_r1 = r1;
   This_Window.scroll_r2 = r2;
   vterm_set_scroll_region (r1, r2);
}

static void msw_reset_scroll_region (void)
{
   msw_set_scroll_region (0, MSW_Screen_Cols - 1);
}



static int msw_reset_video (void)
{
   if (VTerm_Display != NULL)
     {
      msw_reset_scroll_region ();
      msw_goto_rc (0, 0);
      msw_normal_video ();
     }
   return vterm_reset_display ();
}

static int msw_init_video (void)
{
   msw_reset_video ();
   if ((MSW_Screen_Rows == 0) || (MSW_Screen_Cols == 0))
     {
      MSW_Screen_Cols = 80;
      MSW_Screen_Rows = 24;
     }

   return vterm_init_display (MSW_Screen_Rows, MSW_Screen_Cols);
}

static int msw_flush_output (void)
{
   return 0;
}


static void msw_get_terminfo (void)
{
   SLsmg_Term_Type tt;

   MSW_Screen_Cols = 80;
   MSW_Screen_Rows = 24;

   (void) jed_add_init_slang_hook (msw_init_slang);

   /* init hooks */
   X_Update_Open_Hook = msw_update_open;
   X_Update_Close_Hook = msw_update_close;
   X_Suspend_Hook = msw_suspend;
   /*   X_Argc_Argv_Hook = X_eval_command_line; */
   X_Define_Keys_Hook = msw_define_xkeys;
   SLang_Interrupt = msw_check_kbd;
   X_Init_Term_Hook = msw_init_term;

   /* Set this so that main will not try to read from stdin.  It is quite
    * likely that this is started from a menu or something.
    */
   Stdin_Is_TTY = -1;
   
   memset ((char *) &tt, 0, sizeof (SLsmg_Term_Type));

   tt.tt_normal_video = msw_normal_video;
   tt.tt_set_scroll_region = msw_set_scroll_region;
   tt.tt_goto_rc = msw_goto_rc;
   tt.tt_reverse_index = msw_reverse_index;
   tt.tt_reset_scroll_region = msw_reset_scroll_region;
   tt.tt_delete_nlines = msw_delete_nlines;
   tt.tt_cls = msw_cls;
   tt.tt_del_eol = msw_del_eol;
   tt.tt_smart_puts = msw_smart_puts;
   tt.tt_flush_output = msw_flush_output;
   tt.tt_reset_video = msw_reset_video;
   tt.tt_init_video = msw_init_video;
   
   tt.tt_screen_rows = &MSW_Screen_Rows;
   tt.tt_screen_cols = &MSW_Screen_Cols;
   tt.tt_term_cannot_scroll = &MSW_Term_Cannot_Scroll;

   SLsmg_set_terminal_info (&tt);
}

static char *convert_color (char *c, char *buf)
{
   unsigned long ul;

   if ((*c != '#') 
       || (7 != strlen (c)))   /* e.g., #RRGGBB */
     return c;
   
   if (1 != sscanf (c+1, "%lX", &ul))
     return c;
   
   if (ul > 0xFFFFFFUL)
     return c;

   sprintf (buf, "%ld,%ld,%ld", (ul >> 16)&0xFF, (ul >> 8)&0xFF, ul & 0xFF);
   return buf;
}
   

static void msw_set_color (int i, char *what, char *fg, char *bg)
{
   int r, g, b;
   char buf[64];
   char fg_buf[64];
   char bg_buf[64];
   HBRUSH bgbr;

   if ((i < 0) || (i > JMAX_COLORS))
     return;

   (void) what;

   fg = convert_color (fg, fg_buf);
   bg = convert_color (bg, bg_buf);

   r = GetRValue(JColors[i].fg);
   g = GetGValue(JColors[i].fg);
   b = GetBValue(JColors[i].fg);
   sprintf(buf, "%d,%d,%d", r, g, b);
   JColors[i].fg = msw_get_color(fg, buf);

   r = GetRValue(JColors[i].bg);
   g = GetGValue(JColors[i].bg);
   b = GetBValue(JColors[i].bg);
   sprintf(buf, "%d,%d,%d", r, g, b);
   JColors[i].bg = msw_get_color(bg, buf);

#if HAS_PALETTE_CODE
   if (The_Hpalette)
     {
      The_Lplgpl->palPalEntry[i*2].peRed = GetRValue (JColors[i].fg);
      The_Lplgpl->palPalEntry[i*2].peGreen = GetGValue (JColors[i].fg);
      The_Lplgpl->palPalEntry[i*2].peBlue = GetBValue (JColors[i].fg);
      The_Lplgpl->palPalEntry[i*2].peFlags = PC_NOCOLLAPSE;
      The_Lplgpl->palPalEntry[i*2+1].peRed = GetRValue (JColors[i].bg);
      The_Lplgpl->palPalEntry[i*2+1].peGreen = GetGValue (JColors[i].bg);
      The_Lplgpl->palPalEntry[i*2+1].peBlue = GetBValue (JColors[i].bg);
      The_Lplgpl->palPalEntry[i*2+1].peFlags = PC_NOCOLLAPSE;
      SetPaletteEntries (The_Hpalette, i*2, 2, The_Lplgpl->palPalEntry+i*2);
      get_dc();
      SelectPalette (This_Window.hdc, The_Hpalette, FALSE);
      RealizePalette (This_Window.hdc);
      release_dc();
     }
#endif
   bgbr = CreateSolidBrush(JColors[i].bg);
   if (bgbr != 0)
     {
      DeleteObject(JColors[i].hbrBG);
      JColors[i].hbrBG = bgbr;
     }

#if SLANG_VERSION >= 10306
   SLsmg_touch_screen ();
#endif
   /* InvalidateRect(This_Window.w, NULL, FALSE); */
}


static void cover_exposed_area (int x, int y, int width, int height)
{
   SLsmg_Char_Type *s, *smax;
   int row, save_row, save_col, max_col, max_row, col;

   /* VTerm_Display can be NULL here, handle this
    * cpbotha@bigfoot.com
    */
   if (VTerm_Display==NULL) return;

   Performing_Update++;
   hide_cursor ();
   save_row = This_Window.cursor_row;
   save_col = This_Window.cursor_col;
   col = x / This_Window.font_width;
   row = y / This_Window.font_height;

   max_col = 2 + col + width / This_Window.font_width;
   max_row = 2 + row + height / This_Window.font_height;
   if (max_col > MSW_Screen_Cols) max_col = MSW_Screen_Cols;
   if (max_row > MSW_Screen_Rows) max_row = MSW_Screen_Rows;

   while (row < max_row)
     {
      msw_goto_rc (row, col);
      s = VTerm_Display [row];
      smax = s + max_col;
      send_attr_str(s + col, smax);
      row++;
     }
   msw_goto_rc (save_row, save_col);
   Performing_Update--;

   show_cursor ();
}

static void push_mouse_event(int button, int x, int y, int state, int type)
{
   unsigned int s = 0;
   int col, row;
   static int last_button;
   static JMouse_Type jm;
#if JED_HAS_MULTICLICK
   static long last_press_time;
   static unsigned int clicks = 0;
   static long MultiClick_Time = -1;
#endif
   int id;

   col = 1 + x / This_Window.font_width;
   row = 1 + y / This_Window.font_height;

   if ((type == JMOUSE_DRAG)
       && (col == jm.x) && (row == jm.y))
     return;

   if (button == 0)
     button = last_button;
   else
     last_button = button;

#if JED_HAS_MULTICLICK
   if (type == JMOUSE_DOWN)
     {
      long the_time = GetTickCount();
      if (MultiClick_Time == -1)
        MultiClick_Time = GetDoubleClickTime();
      if ((last_button == button)
          && (the_time - last_press_time < MultiClick_Time))
        {
           clicks++;
           if (clicks == 2)
             type = JMOUSE_DOUBLE_CLICK;
           else
             type = JMOUSE_TRIPLE_CLICK;
        }
      else
        {
           clicks = 1;
           last_button = button;
        }
      last_press_time = the_time;
     }
   else if ((clicks > 1) && (last_button == button))
     {
      /* Last was a multi-click.  Ignore this event. */
      type = JMOUSE_IGNORE_EVENT;
     }
#endif
   
   jm.button = button;

   if ((type == JMOUSE_UP)
       && (0 == (jm.state & jm.button)))
     {
      /* Make sure this button was down. */
      return;
     }

   if (state & MK_LBUTTON) s |= JMOUSE_BUTTON_1;
   if (state & MK_MBUTTON) s |= JMOUSE_BUTTON_2;
   if (state & MK_RBUTTON) s |= JMOUSE_BUTTON_3;
   if (state & MK_CONTROL) s |= JMOUSE_CTRL;
   if (state & MK_SHIFT) s |= JMOUSE_SHIFT;

   jm.state = s;
   jm.x = col;
   jm.y = row;
   jm.type = type;

   if (-1 == (id = jed_mouse_add_event (&jm)))
     {
      msg_error ("Failed!");
      return;
     }

   buffer_keystring ("\033\000", 2);
   _putkey(id);
}

static void push_wm_mouse_event (int button, int x, int y, int state, int type)
{
   switch (button)
     {
      case WM_LBUTTONUP:
      case WM_LBUTTONDOWN:
      if (!(GetKeyState(VK_MENU) & 0x8000))
        {
           button = JMOUSE_BUTTON_1;
           break;
        }
      /* drop */
      case WM_MBUTTONUP:
      case WM_MBUTTONDOWN:
      button = JMOUSE_BUTTON_2;
      break;

      case WM_RBUTTONUP:
      case WM_RBUTTONDOWN:
      button = JMOUSE_BUTTON_3;
      break;

      default:
      return;
     }
   
   push_mouse_event (button, x, y, state, type);
}

static void msw_define_color(char *color_name, int *pr, int *pg, int *pb)
{
   char buf[30];

   sprintf(buf, "%d,%d,%d", *pr, *pg, *pb);
   WriteProfileString(szJedSection, color_name, buf);
}

static void msw_select_font (char *fontname, int *height, int *bold)
{
   if (0 == select_font (fontname, *height, *bold))
     {
      jed_init_display ();
      jed_redraw_screen (1);
      return;
     }
   jed_verror ("Unable to allocate font %s", fontname);
}


static void set_window_name (char *s)
{
   if (Batch) return;
   strcpy(This_Window.title, s);
   SetWindowText(This_Window.w, s);
}

static void msw_cleanup(void)
{
   int i;
   char buf[10];
   RECT rc;

   GetWindowRect(This_Window.w, &rc);
   sprintf(buf, "%d", (int) rc.left);
   WriteProfileString(szJedSection, "X", buf);
   sprintf(buf, "%d", (int) rc.top);
   WriteProfileString(szJedSection, "Y", buf);
   sprintf(buf, "%d", (int) (rc.right - rc.left));
   WriteProfileString(szJedSection, "Width", buf);
   sprintf(buf, "%d", (int) (rc.bottom - rc.top));
   WriteProfileString(szJedSection, "Height", buf);
   KillTimer(This_Window.w, 42);
#ifdef _MSC_VER
   KillTimer (This_Window.w, 43);
#endif

   if (This_Window.w) DestroyWindow(This_Window.w);
   DeleteObject(This_Window.font);
   for(i = 0; i < JMAX_COLORS; i++)
     if (JColors[i].hbrBG) DeleteObject(JColors[i].hbrBG);
}

#if !defined(__WIN32__) || !defined(JED_HAS_SUBPROCESSES)
int sys_input_pending(int *tsecs, int unused)
{
   DWORD t = GetTickCount() + *tsecs * 100L;

   (void) unused;

   while ((!Input_Buffer_Len) && (GetTickCount() < t)) process_message();

   return Input_Buffer_Len != 0;
}

unsigned char sys_getkey(void)
{
   int n;

   while (!SLKeyBoard_Quit && !Input_Buffer_Len) process_message ();

   if (SLKeyBoard_Quit) 
     {
      SLKeyBoard_Quit = 0;
      flush_input ();
      return Jed_Abort_Char;
     }

   n = my_getkey();

   SLKeyBoard_Quit = 0;

   return n;
}
#else
int sys_input_pending(int *tsecs, int all)
{
   DWORD ret = 0;
   int i, n;

   if ((all >= 0) && (Input_Buffer_Len || Batch)) return (Input_Buffer_Len);

   if (all < 0)
     {
      /* Note: Input_Events[0] is only used by console jed. */
      ret = WaitForMultipleObjects(Num_Subprocesses, Input_Events+1, FALSE,
                             *tsecs * 100);
     }
   else
     {
      DWORD t;
      long rtime = *tsecs * 100L;

      msw_check_kbd ();
      while ((rtime > 0) && !Input_Buffer_Len)
        {
           t = GetTickCount();
           ret = MsgWaitForMultipleObjects(Num_Subprocesses, Input_Events+1,
                                   FALSE, rtime, QS_ALLINPUT);

           if ((DWORD)(WAIT_OBJECT_0 + Num_Subprocesses) != ret) break;
           msw_check_kbd ();
           rtime -= GetTickCount() - t;
        }

      if ((rtime < 0) || Input_Buffer_Len)
        return Input_Buffer_Len;
     }

   if (WAIT_TIMEOUT == ret) return 0;

   n = 0;
   i = 1;   /* First input event is not used by wjed.  Start at 1. */
   while (i <= Num_Subprocesses)
     {
       /* Check if current subprocess has input */
      if (WAIT_TIMEOUT != WaitForSingleObject(Input_Events[i], 0))
        {
           read_process_input (i);
           n++;
        }
      i++;
     }
   if (all < 0) return n;
   else return 0;
}

unsigned char sys_getkey(void)
{
   int n = 450;

   /* sleep for 45 second and try again */
   while (!SLKeyBoard_Quit && !sys_input_pending(&n, Num_Subprocesses))
     {
       /* update status line incase user is displaying time */
      if (SLKeyBoard_Quit) break;
      JWindow->trashed = 1;
      update((Line *) NULL, 0, 1, 0);
     }

   if (SLKeyBoard_Quit) 
     {
      SLKeyBoard_Quit = 0;
      flush_input ();
      return Jed_Abort_Char;
     }

   return my_getkey();
}

#endif

static int Ignore_Wchar_Message;

static char f_keys[4][12] =
{
     { 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 133, 134 },
     { 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 135, 136 },
     { 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 137, 138 },
     { 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 139, 140 }
};

static char small_keypad_keys[4][13] =
{
     { 'G', 'H', 'I', 0, 'K', 0, 'M', 0, 'O', 'P', 'Q', 'R', 'S' },   /* normal */
     { '0', '1', '2', 0, '3', 0, '4', 0, '5', '6', '7', '8', '9' },   /* shift */
     { 'w', 141, 132, 0, 's', 0, 't', 0, 'u', 145, 'v', 146, 147 },   /* ctrl */
     { 151, 152, 153, 0, 155, 0, 157, 0, 159, 160, 161, 162, 163 }   /* alt */
};

static char num_keypad_keys[4][13] =
{
     { 'w', 'x', 'y', 0, 't', 'u', 'v', 0, 'q', 'r', 's', 'p', 'n' },
     { '0', '1', '2', 0, '3',  0 , '4', 0, '5', '6', '7', '8', '9' },
     { 'w', 141, 132, 0, 's', 143, 't', 0, 'u', 145, 'v', 146, 147 },
     { 'w', 'x', 'y', 0, 't', 'u', 'v', 0, 'q', 'r', 's', 'p', 'n' }
};

static LRESULT CALLBACK process_key_down (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   unsigned int key_state = 0;
   unsigned int scan;
   char prefix, c1;
   int i, state;

   if (GetKeyState(VK_CONTROL) & 0x8000) key_state |= KEY_CONTROL;
   if (GetKeyState(VK_SHIFT) & 0x8000) key_state |= KEY_SHIFT;
   if (GetKeyState(VK_MENU) & 0x8000) key_state |= KEY_ALT;

   Ignore_Wchar_Message = 0;

   scan = (unsigned int) ((lParam >> 16) & 0x1FF);

   switch (scan)
     {
      default: return DefWindowProc(hWnd, msg, wParam, lParam);

      case 0x00E:              /* backspace */
      /* Ctrl-BS  --> ALT-@
       * Shift-BS --> ALT-?
       * BS       --> ^?
       */
      if ((key_state & KEY_ALT) == 0)
        {
           if ((key_state & KEY_CONTROL) != 0)
             {
              _putkey(PC_Alt_Char);
              _putkey('@');
             }
           else if ((key_state & KEY_SHIFT) != 0)
             {
              _putkey(PC_Alt_Char);
              _putkey('?');
             }
           else
             {
              _putkey (127);
             }
        }
      Ignore_Wchar_Message = 1;
      return 0;

      case 0x039:                    /* space */
      if (key_state & KEY_CONTROL)
        {
           Ignore_Wchar_Message = 1;
           buffer_keystring ("\000\003", 2);
        }
      return 0;

      case 0x003:              /* 2 key */
      if (((key_state & KEY_ALT) == 0)
          && (key_state & KEY_CONTROL))
        {
           Ignore_Wchar_Message = 1;
           buffer_keystring ("\000\003", 2);
           return 0;
        }
      return DefWindowProc(hWnd, msg, wParam, lParam);

      case 0x00C:              /* -/_ key */
      if (((key_state & KEY_ALT) == 0)
          && (key_state & KEY_CONTROL))
        {
           Ignore_Wchar_Message = 1;
           _putkey (31);             /* ^_ */
           return 0;
        }
      return DefWindowProc(hWnd, msg, wParam, lParam);

      /* PF1 and PF2 codes */
      /* case 0x0045: */
      case 0x0145:
      if (NumLock_Is_Gold)
        {
#if 0                          /* does not work on xp */
           BYTE keyState[256];
           /* toggle the caps-lock state */
           GetKeyboardState(keyState);
           keyState[VK_NUMLOCK] = 0;/*keyState[VK_NUMLOCK]^1;*/
           SetKeyboardState(keyState);
#endif

           buffer_keystring ("\033OP", 3);
           Ignore_Wchar_Message = 1 ;
           return 0 ;
        }
      return DefWindowProc(hWnd, msg, wParam, lParam);

      case 0x0135:
      c1 = 'Q'; break ;

      case 0xE02F:
      c1 = 'Q'; break;         /* KEYPAD SLASH */

      case 0x037:              /* KEYPAD STAR */
      c1 = 'R';
      break;

      case 0x04A:              /* KEYPAD MINUS */
      c1 = 'S';
      break;

      case 0x04E:              /* KEYPAD PLUS */
      c1 = 'm';
      break;

      case 0x047:            /* KEYPAD HOME */
      case 0x048:            /* KEYPAD UP */
      case 0x049:            /* KEYPAD PGUP */
      case 0x04B:            /* KEYPAD LEFT */
      case 0x04C:            /* KEYPAD 5 */
      case 0x04D:            /* KEYPAD RIGHT */
      case 0x04F:            /* KEYPAD END */
      case 0x050:            /* KEYPAD DOWN */
      case 0x051:            /* KEYPAD PGDN */
      case 0x053:            /* KEYPAD DEL */
      case 0x052:            /* KEYPAD INSERT */
      if (!NumLock_Is_Gold && (GetKeyState(VK_NUMLOCK) & 0x0001))
          return DefWindowProc(hWnd, msg, wParam, lParam);

      state = 0;
      if (key_state & KEY_SHIFT) state = 1;
      if (key_state & KEY_CONTROL) state = 2;
      if (key_state & KEY_ALT) state = 3;

      if (key_state & (KEY_CONTROL | KEY_ALT))
        {
           Ignore_Wchar_Message = 1;
           _putkey (0);
           _putkey (num_keypad_keys[state][scan - 0x47]);
           return 0;
        }
      else
        c1 = num_keypad_keys[state][scan - 0x47];
      break;

      case 0x11C:            /* KEYPAD ENTER */
      if (key_state & KEY_ALT)
        {
           _putkey(0);
           _putkey(166);
           Ignore_Wchar_Message = 1;
           return 0;
        }
      else
        {
           c1 = 'M';
           break;
        }

      case 0x147:                    /* home */
      case 0x148:              /* UP */
      case 0x149:              /* PGUP */
      case 0x14B:              /* LEFT */
      case 0x14D:              /* RIGHT */
      case 0x14F:              /* END */
      case 0x150:              /* DOWN */
      case 0x151:              /* PGDN */
      case 0x153:              /* DEL */
      case 0x152:              /* INSERT */
      prefix = 0xE0;
      state = 0;
      if (key_state & KEY_SHIFT) state = 1;
      if (key_state & KEY_CONTROL) state = 2;
      if (key_state & KEY_ALT)
        {
           prefix = 0;
           state = 3;
        }

      _putkey (prefix);
      _putkey (small_keypad_keys[state][scan - 0x147]);
      Ignore_Wchar_Message = 1;
      return 0;

      case 0x3b:               /* F1 */
      case 0x3c:
      case 0x3d:
      case 0x3e:
      case 0x3f:
      case 0x40:
      case 0x41:
      case 0x42:
      case 0x43:
      case 0x44:
      case 0x57:
      case 0x58:               /* F12 */
      i = scan - 0x3b;
      if (i > 9) i -= 0x12;

      state = 0;
      if (key_state & KEY_SHIFT) state = 1;
      if (key_state & KEY_CONTROL) state = 2;
      if (key_state & KEY_ALT)
        {
           if (i == 3)               /* Alt-F4 */
             return DefWindowProc(hWnd, msg, wParam, lParam);
           else
             state = 3;
        }

      _putkey(PC_Fn_Char);
      _putkey(f_keys[state][i]);
      Ignore_Wchar_Message = 1;
      return 0;
     }

   buffer_keystring ("\033O", 2);
   _putkey (c1);
   Ignore_Wchar_Message = 1;
   return 0;
}

static int load_dropped_files(HDROP hDrop, HWND hwnd)
{
   CHAR szFilename[JED_MAX_PATH_LEN];
   INT iNumFiles;

   (void) hwnd;

   iNumFiles = DragQueryFile (hDrop, 0xFFFFFFFF, NULL, JED_MAX_PATH_LEN-1);
   
   while(--iNumFiles>=0)
     {
      DragQueryFile(hDrop, iNumFiles, szFilename, JED_MAX_PATH_LEN-1);
      (void) find_file_in_window(szFilename);
      window_buffer(CBuf);
      jed_redraw_screen (1);
     }
   DragFinish(hDrop);
   
   return 0;
}

LRESULT CALLBACK JEDWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   static int mouse_button_down;
   PAINTSTRUCT ps;
   RECT rc;

   switch (msg)
     {
      case WM_CREATE:
      This_Window.w = hWnd;
      DragAcceptFiles (hWnd, TRUE);
      mouse_button_down = 0;
      return 0;

      case WM_DROPFILES:
      (void) load_dropped_files ((HANDLE) wParam, hWnd);
      return 0;

      case WM_SIZE:
      if (wParam != SIZE_MINIMIZED)
        {
           This_Window.width = LOWORD(lParam);
           This_Window.height = HIWORD(lParam);
           jed_init_display ();
           jed_redraw_screen (1);
        }
      break;

      case WM_PAINT:
      BeginPaint(This_Window.w, &ps);
#if HAS_PALETTE_CODE
      if (NULL != The_Hpalette)
        SelectPalette (ps.hdc, The_Hpalette, FALSE);
#endif
      This_Window.hdc = ps.hdc;
      This_Window.ndc = 1;
      cover_exposed_area(ps.rcPaint.left, ps.rcPaint.top,
                     ps.rcPaint.right - ps.rcPaint.left,
                     ps.rcPaint.bottom - ps.rcPaint.top);
      EndPaint(This_Window.w, &ps);
      This_Window.hdc = NULL;
      This_Window.ndc = 0;
      break;

#if HAS_PALETTE_CODE
      case WM_PALETTECHANGED:
      if (wParam != This_Window.w && The_Hpalette != NULL)
        {
           get_dc();
           UpdateColors (This_Window.hdc);
           release_dc();
        }
      break;

      case WM_QUERYNEWPALETTE:
      if (The_Hpalette != NULL)
        {
           get_dc();
           RealizePalette (This_Window.hdc);
           release_dc();
        }
      break;
#endif

      case WM_ERASEBKGND:
      GetClientRect(This_Window.w, &rc);
      FillRect((HDC)wParam, &rc, CURRENT_BG_COLOR);
      break;

      case WM_SYSCHAR:
      _putkey(PC_Alt_Char);
      if (PC_Alt_Char != 0)
        _putkey (wParam);
      else
        _putkey((lParam >> 16) & 0x1FF);/* was: _putkey(wParam); */

      return MAKELONG(0, 1);

      case WM_CHAR:
      if (Ignore_Wchar_Message == 0)
        {
           if ((int) wParam == (int) Jed_Abort_Char)
             {
              if (Ignore_User_Abort == 0) SLang_Error = USER_BREAK;
              SLKeyBoard_Quit = 1;
             }
           /* PS 28Apr98: handle shiftTAB same as DOS */
           if (wParam == 0x009)
             {
              if (GetKeyState(VK_SHIFT)<0)
                {
                   _putkey(0);
                   _putkey('o' & 31);
                   Ignore_Wchar_Message = 1;
                   break;
                }
             }
           if (wParam == 0xE0) _putkey(wParam);
           _putkey(wParam);
           break;
        }
      return DefWindowProc(hWnd, msg, wParam, lParam);

      case WM_SYSKEYDOWN:
      case WM_KEYDOWN:
      return process_key_down (hWnd, msg, wParam, lParam);

      case WM_KEYUP:
      Ignore_Wchar_Message = 0;
      break;

      case WM_SYSKEYUP:
      Ignore_Wchar_Message = 0;
      return DefWindowProc(hWnd, msg, wParam, lParam);

      case WM_LBUTTONUP:
      case WM_MBUTTONUP:
      case WM_RBUTTONUP:

      if (!mouse_button_down) break;

      push_wm_mouse_event(msg, LOWORD(lParam), HIWORD(lParam), wParam, JMOUSE_UP);
      mouse_button_down--;
      break;

      case WM_LBUTTONDOWN:
      case WM_MBUTTONDOWN:
      case WM_RBUTTONDOWN:
      mouse_button_down++;
      push_wm_mouse_event(msg, LOWORD(lParam), HIWORD(lParam), wParam, JMOUSE_DOWN);
      break;

      case WM_MOUSEMOVE:
      if (wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON))
        push_mouse_event(0, LOWORD(lParam), HIWORD(lParam), wParam, JMOUSE_DRAG);
      break;

      case WM_SETFOCUS:
      case WM_KILLFOCUS:
      hide_cursor();
      This_Window.focus = (msg == WM_SETFOCUS);
      show_cursor();
      break;

#if 0
      /* This does not quite work when coming back from a shell */
      case WM_ACTIVATE:
      if ((wParam != WA_INACTIVE) && (CBuf != NULL)) check_buffers();
      break;
#endif
      case WM_CLOSE:
      jed_exit_jed(1);
      break;

#if !defined(__WIN32__) || !JED_HAS_SUBPROCESSES
      case WM_TIMER:
      if ((wParam == 42) && Display_Time)
        {
           JWindow->trashed = 1;
           update((Line *) NULL, 0, 1, 0);
        }
      return 0;
#endif

#if defined(_MSC_VER) && JED_HAS_SUBPROCESSES
      case WM_TIMER:
      /*
       * just stop the GetMessage call...
       */
        return 0;
#endif

      case WM_COMMAND:
      if (wParam < MAX_MENU_ID)
        {
           int force = 1;
           if (Menu_Callbacks[wParam])
             {
              if (is_internal(Menu_Callbacks[wParam]))
                {
                   char buf[512];
                   _SLsnprintf(buf, sizeof (buf), ". \"%s\" call", Menu_Callbacks[wParam]);
                   SLang_load_string (buf);
                }
              else
                if (SLang_execute_function(Menu_Callbacks[wParam]) == 0) msg_error(Menu_Callbacks[wParam]);
             }

           update_cmd(&force);
        }
      return 0;

      case WM_INITMENUPOPUP:
      SLang_push_integer(wParam);
      if (InitPopup_Callback != NULL)
        if (SLang_execute_function(InitPopup_Callback) == 0)
          msg_error(InitPopup_Callback);
      return 0;

      default:

#if HAS_WHEEL_MOUSE_SUPPORT
      /* Check for a mouse wheel movement message
       * and translate it into a fake keystroke. This has now been
       * tested on Win95,98,NT4,2000
       */
        if ((Wheel_Mouse.fActive 
             && (msg == Wheel_Mouse.uiMshMsgMouseWheel))
            || (msg == WM_MOUSEWHEEL))
          {
           /* Under X, the wheel mouse produces JMOUSE_BUTTON_4 and
            * JMOUSE_BUTTON_5 events.  jed/lib/mouse.sl maps JMOUSE_BUTTON_4
            * events to upward movement and JMOUSE_BUTTON_5 to downward 
            * movement in the buffer.
            */
           if ((int) wParam < 0) 
             push_mouse_event (JMOUSE_BUTTON_5, LOWORD(lParam), HIWORD(lParam), wParam, JMOUSE_DOWN);
           else 
             push_mouse_event (JMOUSE_BUTTON_4, LOWORD(lParam), HIWORD(lParam), wParam, JMOUSE_DOWN);

           return 0;
          }
#endif
        return DefWindowProc(hWnd, msg, wParam, lParam);
     }

   return 0;
}

void get_menubar()
{
   HMENU hmenu = GetMenu(This_Window.w);

   if (!hmenu)
     {
      hmenu = CreateMenu();
      SetMenu(This_Window.w, hmenu);
      DrawMenuBar(This_Window.w);
     }

   SLang_push_integer((int) hmenu);
}

void destroy_menubar()
{
   int i;
   HMENU hmenu = GetMenu(This_Window.w);

   if (hmenu)
     {
      SetMenu(This_Window.w, NULL);
      DestroyMenu(hmenu);

     }

   for(i = 0; i < MAX_MENU_ID; i++) Menu_Callbacks[i] = NULL;
}

void create_popup_menu()
{
   HMENU hmenu = CreatePopupMenu();

   SLang_push_integer((int) hmenu);
}

void destroy_menu()
{
   HMENU hmenu;
   int count, i;
   int id;

   if (!SLang_pop_integer((int *)&hmenu))
     {
      count = GetMenuItemCount(hmenu);
      for(i = 0; i < count; i++)
        {
           id = GetMenuItemID(hmenu, i);
           if (id > 0 && Menu_Callbacks[id] != NULL)
             {
              SLfree(Menu_Callbacks[id]);
              Menu_Callbacks[id] = NULL;
             }
        }

      if (!DestroyMenu(hmenu)) msg_error("Cannot destroy menu");
     }
}

void append_menu_item()
{
   HMENU hmenu;
   char *name = NULL;
   char *callback = NULL;
   int   id;

   if (!SLpop_string(&callback) &&
       !SLang_pop_integer(&id) &&
       !SLpop_string(&name) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if ((id < 0) || (id >= MAX_MENU_ID))
        msg_error("Id is out of range.");
      else
        {
           if (!AppendMenu(hmenu, MF_STRING, id, name))
             msg_error("Cannot append menu item");
           else
             {
              if (Menu_Callbacks[id] != NULL)
                {
                   jed_verror ("Id %d is already used.", id);
                }
              else
                {
                   Menu_Callbacks[id] = callback;
                   callback = NULL;
                }
             }
        }
     }

   if (name != NULL) SLfree(name);
   if (callback != NULL) SLfree(callback);
}

void append_popup_menu()
{
   HMENU hmenu;
   char *name = NULL;
   HMENU popup;

   if (!SLang_pop_integer((int *)&popup) &&
       !SLpop_string (&name) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if (!AppendMenu(hmenu, MF_STRING | MF_POPUP, (UINT)popup, name))
        msg_error("Cannot append popup menu");

     }
   if (name != NULL) SLfree(name);
}

void append_separator()
{
   HMENU hmenu;

   if (!SLang_pop_integer((int *)&hmenu))
     {
      if (!AppendMenu(hmenu, MF_STRING | MF_SEPARATOR, 0, 0))
        msg_error("Cannot append separator");
     }
}

void insert_menu_item()
{
   HMENU hmenu;
   int   id;
   char *name = NULL;
   int   idNew;
   char *callback = NULL;

   if (!SLpop_string(&callback) &&
       !SLang_pop_integer(&idNew) &&
       !SLpop_string(&name) &&
       !SLang_pop_integer(&id) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if ((idNew < 0) || (idNew >= MAX_MENU_ID))
        msg_error("Id is out of range");
      else
        {
           if (!InsertMenu(hmenu, id, MF_STRING | MF_BYCOMMAND, idNew, name))
             msg_error("Cannot insert menu item");
           else
             {
              if (Menu_Callbacks[idNew] != NULL)
                {
                   jed_verror ("Id %d is already used.", idNew);
                }
              else
                {
                   Menu_Callbacks[idNew] = callback;
                   callback = NULL;
                }
             }
        }
     }
   if (name != NULL) SLfree(name);
   if (callback != NULL) SLfree(callback);
}

void insert_popup_menu()
{
   HMENU hmenu;
   int   id;
   char *name = NULL;
   HMENU popup;

   if (!SLang_pop_integer((int *)&popup) &&
       !SLpop_string (&name) &&
       !SLang_pop_integer(&id) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if (!InsertMenu(hmenu, id, MF_STRING | MF_POPUP | MF_BYCOMMAND, (UINT)popup, name))
        msg_error("Cannot insert popup menu");

     }
   if (name != NULL) SLfree (name);
}

void insert_separator()
{
   HMENU hmenu;
   int   id;

   if (!SLang_pop_integer(&id) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if (!InsertMenu(hmenu, id, MF_STRING | MF_SEPARATOR | MF_BYCOMMAND, 0, 0))
        msg_error("Cannot insert separator");
     }
}

void insert_menu_item_pos()
{
   HMENU hmenu;
   int   pos;
   char *name = NULL;
   int   idNew;
   char *callback = NULL;

   if (!SLpop_string(&callback) &&
       !SLang_pop_integer(&idNew) &&
       !SLpop_string(&name) &&
       !SLang_pop_integer(&pos) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if ((idNew < 0) || (idNew >= MAX_MENU_ID))
        msg_error("Id is out of range.");
      else
        {
           if (!InsertMenu(hmenu, pos, MF_STRING | MF_BYPOSITION, idNew, name))
             msg_error("Cannot insert menu item");
           else
             {
              if (Menu_Callbacks[idNew] != NULL)
                {
                   jed_verror ("Id %d is already used.", idNew);
                }
              else
                {
                   Menu_Callbacks[idNew] = callback;
                   callback = NULL;
                }
             }
        }
     }
   if (name != NULL) SLfree(name);
   if (callback != NULL) SLfree(callback);
}

void insert_popup_menu_pos()
{
   HMENU hmenu;
   int   pos;
   char *name = NULL;
   HMENU popup;

   if (!SLang_pop_integer((int *)&popup) &&
       !SLpop_string(&name) &&
       !SLang_pop_integer(&pos) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if (!InsertMenu(hmenu, pos, MF_STRING | MF_POPUP | MF_BYPOSITION, (UINT)popup, name))
        msg_error("Cannot insert popup menu");

     }
   if (name != NULL) SLfree(name);
}

void insert_separator_pos()
{
   HMENU hmenu;
   int   pos;

   if (!SLang_pop_integer(&pos) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if (!InsertMenu(hmenu, pos, MF_STRING | MF_SEPARATOR | MF_BYPOSITION, 0, 0))
        msg_error("Cannot insert separator");
     }
}

void delete_menu_item()
{
   HMENU hmenu;
   int   id;

   if (!SLang_pop_integer(&id) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if ((id < 0) || (id >= MAX_MENU_ID))
        {
           msg_error("Id is out of range.");
           return;
        }

      if (!DeleteMenu(hmenu, id, MF_BYCOMMAND))
        msg_error("Cannot delete menu");
      else
        {
           if (Menu_Callbacks[id])
             {
              SLfree(Menu_Callbacks[id]);
              Menu_Callbacks[id] = NULL;
             }
        }
     }
}

void delete_menu_item_pos()
{
   HMENU hmenu, popup;
   int   pos;
   int   id;

   if (!SLang_pop_integer(&pos) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      id = GetMenuItemID(hmenu, pos);
      if ((id > 0) && (Menu_Callbacks[id] != NULL))
        {
           SLfree(Menu_Callbacks[id]);
           Menu_Callbacks[id] = NULL;
        }
      else
        if (id == -1)
        {
           popup = GetSubMenu(hmenu, pos);
           SLang_push_integer((int)popup);
           destroy_menu();
        }

      if (!DeleteMenu(hmenu, pos, MF_BYPOSITION))
        msg_error("Cannot delete menu");
     }
}

void get_menu_state()
{
   HMENU hmenu;
   int   id;
   UINT  mstate;
   int   state;

   if (!SLang_pop_integer(&id) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if (-1 == (int)(mstate = GetMenuState(hmenu, id, MF_BYCOMMAND)))
        msg_error("Cannot get menu state");
      else
        {
           state = 0;
           if (mstate & MF_ENABLED) state = 1;
           if (mstate & MF_CHECKED) state |= 2;

           SLang_push_integer(state);
        }
     }
}

void get_menu_state_pos()
{
   HMENU hmenu;
   int   pos;
   UINT  mstate;
   int   state;

   if (!SLang_pop_integer(&pos) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if (-1 == (int)(mstate = GetMenuState(hmenu, pos, MF_BYPOSITION)))
        msg_error("Cannot get menu state");
      else
        {
           state = 0;
           if (mstate & MF_GRAYED) state = 1;
           if (mstate & MF_CHECKED) state |= 2;

           SLang_push_integer(state);
        }
     }
}

void get_popup_menu()
{
   HMENU hmenu;
   int   pos;
   HMENU popup;

   if (!SLang_pop_integer(&pos) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      popup = GetSubMenu(hmenu, pos);
      SLang_push_integer((int) popup);
     }
}

void check_menu_item()
{
   HMENU hmenu;
   int   id;
   int   flag;

   if (!SLang_pop_integer(&flag) &&
       !SLang_pop_integer(&id) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if (-1 == (int) CheckMenuItem(hmenu, id, MF_BYCOMMAND | (flag)?MF_CHECKED:MF_UNCHECKED))
        msg_error("Menu item does not exist");
     }
}

void check_menu_item_pos()
{
   HMENU hmenu;
   int   pos;
   int   flag;

   if (!SLang_pop_integer(&flag) &&
       !SLang_pop_integer(&pos) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if (!CheckMenuItem(hmenu, pos, MF_BYPOSITION | (flag)?MF_CHECKED:MF_UNCHECKED))
        msg_error("Menu item does not exist");
     }
}

void enable_menu_item()
{
   HMENU hmenu;
   int   id;
   int   flag;

   if (!SLang_pop_integer(&flag) &&
       !SLang_pop_integer(&id) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if (-1 == EnableMenuItem(hmenu, id, MF_BYCOMMAND | (flag)?MF_ENABLED:MF_GRAYED))
        msg_error("Menu item does not exist");
     }
}

void enable_menu_item_pos()
{
   HMENU hmenu;
   int   pos;
   int   flag;

   if (!SLang_pop_integer(&flag) &&
       !SLang_pop_integer(&pos) &&
       !SLang_pop_integer((int *)&hmenu))
     {
      if (-1 == EnableMenuItem(hmenu, pos, MF_BYPOSITION | (flag)?MF_ENABLED:MF_DISABLED))
        msg_error("Menu item does not exist");
     }
}

void redraw_menubar()
{
   DrawMenuBar(This_Window.w);
}

void set_init_popup_callback()
{
   char *callback;

   if (SLpop_string(&callback))
     return;

   if (InitPopup_Callback != NULL)
     SLfree(InitPopup_Callback);

   InitPopup_Callback = callback;
}

void msw_help (void)
{
   char *file = NULL;
   char *keyword = NULL;
   int   partial_keyword;
   UINT  help_type;
   DWORD dwData;

   if (!SLang_pop_integer(&partial_keyword) &&
       !SLpop_string (&keyword) &&
       !SLpop_string(&file))
     {
      help_type = (partial_keyword) ? HELP_PARTIALKEY : HELP_KEY;
      dwData = (DWORD)(LPSTR) keyword;

      if (*keyword == '\0')
        {
           help_type = HELP_CONTENTS;
           dwData = 0;
        }

      if (!WinHelp(This_Window.w, file, help_type, dwData))
        {
           msg_error("Help file not found.");
        }

     }
   if (keyword != NULL) SLfree(keyword);
   if (file != NULL) SLfree(file);
}

static void msw_get_display_size (int *rows, int *cols)
{
   *cols = MSW_Screen_Cols = This_Window.width / This_Window.font_width;
   *rows = MSW_Screen_Rows = This_Window.height / This_Window.font_height;
}

static void msw_set_mono (int i, char *what , SLtt_Char_Type unused)
{
   (void)i;
   (void)what;
   (void)unused;
}

int (*X_Argc_Argv_Hook)(int, char **);

/* the links to functions and variables here */
void (*tt_beep)(void)               = msw_beep;
void (*tt_write_string)(char *)     = msw_write_string;
void (*tt_get_terminfo)(void)             = msw_get_terminfo;
void (*tt_set_color)(int, char *, char *, char *) = msw_set_color;
void (*tt_set_mono) (int, char *, SLtt_Char_Type) = msw_set_mono;
void (*tt_get_screen_size)(int *, int *) = msw_get_display_size;

int *tt_Ignore_Beep           = &MSW_Ignore_Beep;
int *tt_Use_Ansi_Colors       = &MSW_Use_Ansi_Colors;
int *tt_Term_Cannot_Scroll    = &MSW_Term_Cannot_Scroll;
int *tt_Term_Cannot_Insert    = &MSW_Term_Cannot_Insert;

int jed_init_w32_support (void)
{
   return w32_init_subprocess_support (1);
}

#if HAS_WHEEL_MOUSE_SUPPORT

/* Initialise mouse wheel handling functionality */

static int init_wheel_mouse (void)
{
   /* Find the mystery mouse window */
   
   Wheel_Mouse.hwnd = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);

   /* Register messages to determine mousey information */
   
   Wheel_Mouse.uiMshMsgMouseWheel  = RegisterWindowMessage(MSH_MOUSEWHEEL);
   Wheel_Mouse.uiMshMsg3DSupport   = RegisterWindowMessage(MSH_WHEELSUPPORT);
   Wheel_Mouse.uiMshMsgScrollLines = RegisterWindowMessage(MSH_SCROLL_LINES);

   /* If we have a wheel enquiry message, ask about the presence of a wheel */
   
   if (Wheel_Mouse.uiMshMsg3DSupport)
     Wheel_Mouse.fActive = (BOOL)SendMessage(Wheel_Mouse.hwnd, Wheel_Mouse.uiMshMsg3DSupport, 0, 0);
   else
     Wheel_Mouse.fActive = FALSE;  

   /* If we have a scroll line enquiry message ask about that */
   
   if (Wheel_Mouse.uiMshMsgScrollLines)
     Wheel_Mouse.iScrollLines = (int)SendMessage(Wheel_Mouse.hwnd, Wheel_Mouse.uiMshMsgScrollLines, 0, 0);
   else
     Wheel_Mouse.iScrollLines = 3;
   
   return 0;
}
#endif                                 /* HAS_WHEEL_MOUSE_SUPPORT */


#if defined(__BORLANDC__) || defined(__WIN32__) || defined(__VC__)
extern int main(int, char **);

/* I do not think that this gets called.  Does it???? */
int PASCAL WinMain(HINSTANCE inst, HINSTANCE pinst, LPSTR lpszCmdLine, int nCmdShow)
{
   char **argv;
   int  argc;
   int count;
   char *pt;
   int ret;
   char *command_line;

   /* add 8 for "wjed", the separating space, and a terminating '\0' */
   if (NULL == (command_line = SLMALLOC (strlen(lpszCmdLine) + 6)))
     return 0;

#ifdef _MSC_VER
   _hInstance = inst;
#else
   (void) inst;
#endif
   (void) nCmdShow;

#if HAS_WHEEL_MOUSE_SUPPORT
   (void) init_wheel_mouse ();
#endif

   strcpy(command_line, "wjed ");
   strcat(command_line, lpszCmdLine);
   _hPrev = pinst;

   /* Handle quoted filenames containing space characters.  It is a pity
    * that the application has to do this.
    */
   while ( (*command_line != '\0') && (*command_line == ' '))
     command_line++;                 /* start on 1st non-space */

   pt = command_line;
   count = 0;
   while ( *pt != '\0' )
     {
      count++;                       /* this is an argument */
#ifdef __WIN32__
      /* If the first character of the argument is a double quote, 
       * search for a matching double-quote to end the argument,
       * otherwise, find the next space 
       */
      if (*pt == '"')
        {
           pt++;               /* Skip the initial quote */
           while ((*pt != '\0') 
                && (*pt != '"'))
             pt++;
           if (*pt != '\0')          /* Skip the end quote */
             pt++;
        }
      else
#endif
        while ((*pt != '\0') && (*pt != ' '))
          pt++;                      /* advance until a space */

      while (*pt == ' ')
        pt++;                        /* advance until a non-space */
     }

   argv = (char **) SLMALLOC( (count+3) * sizeof(char *) );
   if (argv == NULL )
     return 0;                       /* malloc error */

   argc = 0;
   pt = command_line;
   while ((argc < count) && (*pt != '\0'))
     {
      argv[ argc ] = pt;
      argc++;
#ifdef __WIN32__
      /* If the first character of the argument is a double quote, 
       * search for a matching double-quote to end the argument,
       * otherwise, find the next space 
       */
      if (*pt == '"')
        {
           pt++;               /* Skip the initial quote */
           while ((*pt != '\0') 
                && (*pt != '"'))
             pt++;
           if (*pt != '\0')          /* Skip the end quote */
             pt++;
        }
      else
#endif
      while ( *pt != '\0' && *pt != ' ' )
        pt++;                        /* advance until a space */
      if ( *pt != '\0' )
        *(pt++) = '\0';              /* parse argument here */
      while ( *pt == ' ')
        pt++;                        /* advance until a non-space */
     }
   argv [ argc ] = (char *) NULL;      /* NULL terminated list */

   ret = main(argc, argv);

   SLfree(command_line);
   return ret;
}

#endif                               /* __BORLANDC__ || __VC__ */

Generated by  Doxygen 1.6.0   Back to index