Commits

Anonymous committed 83b3d10

Import from CVS: tag r20-5b23

  • Participants
  • Parent commits ad40ac2
  • Tags r20-5b23

Comments (0)

Files changed (51)

File CHANGES-beta

 							-*- indented-text -*-
+to 20.5 beta23 "Jining Grey"
+-- MS Windows DnD stuffs courtesy of Jonathon Harris
+-- Miscellaneous bug fixes
+
 to 20.5 beta22 "Grison's Striped"
 -- Port to mklinux courtesy of Kaoru Fukui
 -- Miscellaneous bug fixes
+1998-02-03  SL Baur  <steve@altair.xemacs.org>
+
+	* XEmacs 20.5-beta23 is released.
+
+1998-02-01  SL Baur  <steve@altair.xemacs.org>
+
+	* etc/aliases.ksh: igrep from the shell command line.
+	From Karl M. Hegbloom <karlheg@bittersweet.inetarena.com>
+
+1998-01-31  SL Baur  <steve@altair.xemacs.org>
+
+	* etc/aliases.ksh: Add `mak' function to create beta.err for
+	build-report.
+	From Adrian Aichner <aichner@ecf.teradyne.com>
+	Suggested by Karl M. Hegbloom <karlheg@bittersweet.inetarena.com>
+
 1998-01-27  SL Baur  <steve@altair.xemacs.org>
 
 	* XEmacs 20.5-beta22 is released.
     with_dialogs=msw
     with_toolbars=no
     with_tty=no
-    extra_objs="$extra_objs console-msw.o device-msw.o event-msw.o frame-msw.o objects-msw.o select-msw.o redisplay-msw.o msw-proc.o" &&  if test "$extra_verbose" = "yes"; then
-   echo "    xemacs will be linked with \"console-msw.o device-msw.o event-msw.o frame-msw.o objects-msw.o select-msw.o redisplay-msw.o msw-proc.o\""
+    extra_objs="$extra_objs console-msw.o device-msw.o event-msw.o frame-msw.o objects-msw.o select-msw.o redisplay-msw.o" &&  if test "$extra_verbose" = "yes"; then
+   echo "    xemacs will be linked with \"console-msw.o device-msw.o event-msw.o frame-msw.o objects-msw.o select-msw.o redisplay-msw.o\""
  fi
   fi
 fi

File configure.in

     with_dialogs=msw
     with_toolbars=no
     with_tty=no
-    XE_ADD_OBJS(console-msw.o device-msw.o event-msw.o frame-msw.o objects-msw.o select-msw.o redisplay-msw.o msw-proc.o)
+    XE_ADD_OBJS(console-msw.o device-msw.o event-msw.o frame-msw.o objects-msw.o select-msw.o redisplay-msw.o)
   fi
 fi
 
 This information is used to control the customize-changed-options
 command.
 
+** The new command `add-log-convert' can be used to convert the
+old-style (pre-20.3) ChangeLog buffers to new style, for
+consistency.  A reminder: if you wish to revert to old-style
+ChangeLogs instead, customize the value of `add-log-time-format'
+variable.
+
 ** XEmacs/Mule (internationalization) changes.
 
 *** Egg/SJ3 input method is now officially supported.  Quail and

File etc/aliases.ksh

 
 # Shortcuts for sh-derived Unix shells (ksh, zsh, bash)
 
+# From Steve Baur <steve@altair.xemacs.org>
+# Run temacs as XEmacs
 function runtemacs
 {
 	if [ ! -x temacs ]; then
 
 	./temacs -batch -l loadup.el run-temacs "$@"
 }
+
+# From Adrian Aichner <aichner@ecf.teradyne.com>
+# Convenience function for running build-report
+function mak
+{
+	make "$@" 2>&1 | tee beta.err
+}
+# export -f mak
+
+# From Karl Hegbloom <karlheg@bittersweet.inetarena.com>
+# igrep from the shell command line
+function listargs
+{
+	for arg in "$@"; do
+		echo " \"$arg\""
+	done
+}
+
+function igrep
+{
+	exp="$1"; shift
+	gnudoit -q "(igrep nil \"$exp\" '($(listargs "$@")))"
+}

File lisp/ChangeLog

+1997-12-30  Colin Rafferty  <colin@xemacs.org>
+
+	* help.el (describe-beta): Made it use `locate-data-file'.
+	(describe-distribution): Ditto.
+	(describe-copying): Ditto.
+	(describe-project): Ditto.
+	(view-emacs-news): Ditto.
+
+	* help-nomule.el (help-with-tutorial): Made it use
+ 	`locate-data-file' to find tutorial.
+
+1998-01-28  Jonathon Harris  <jhar@tardis.ed.ac.uk>
+
+	* about.el: Corrected my email address.
+
+	* mouse.el: Added 'mouse-mswindows-drop' similar to
+	'mouse-offix-drop'.
+
 1998-01-27  SL Baur  <steve@altair.xemacs.org>
 
 	* loadup.el (running-xemacs): Spelling fix.

File lisp/about.el

        (print-short "ChangGil Han" "cghan@phys401.phys.pusan.ac.kr")
        (print-short "Derek Harding" "dharding@lssec.bt.co.uk")
        (print-short "Michael Harnois" "mharnois@sbt.net")
-       (print-short "Jonathan Harris" "jharris@tardis.co.uk")
+       (print-short "Jonathan Harris" "jhar@tardis.ed.ac.uk")
        (print-short "John Haxby" "J.Haxby@isode.com")
        (print-short "Karl M. Hegbloom" "karlheg@inetarena.com")
        (print-short "Benedikt Heinen" "beh@icemark.thenet.ch")

File lisp/help-nomule.el

 	    ;; independently, so we must guess the coding according to
 	    ;; the language.
 	    (let ((coding-system-for-read (nth 2 language)))
-	      (insert-file-contents (expand-file-name tutorial
-						      data-directory)))
+	      (insert-file-contents (locate-data-file tutorial)))
 	    (goto-char (point-min))
 	    ;; The 'didactic' blank lines: possibly insert blank lines
 	    ;; around <<nya nya nya>> and replace << >> with [ ].

File lisp/help.el

   "Display info on how to obtain the latest version of XEmacs."
   (interactive)
   (find-file-read-only
-   (expand-file-name "DISTRIB" data-directory)))
+   (locate-data-file "DISTRIB")))
 
 (defun describe-beta ()
   "Display info on how to deal with Beta versions of XEmacs."
   (interactive)
   (find-file-read-only
-   (expand-file-name "BETA" data-directory))
+   (locate-data-file "BETA"))
   (goto-char (point-min)))
 
 (defun describe-copying ()
   "Display info on how you may redistribute copies of XEmacs."
   (interactive)
   (find-file-read-only
-   (expand-file-name "COPYING" data-directory))
+   (locate-data-file "COPYING"))
   (goto-char (point-min)))
 
 (defun describe-pointer ()
   "Display info on the GNU project."
   (interactive)
   (find-file-read-only
-   (expand-file-name "GNU" data-directory))
+   (locate-data-file "GNU"))
   (goto-char (point-min)))
 
 (defun describe-no-warranty ()
 (defun view-emacs-news ()
   "Display info on recent changes to XEmacs."
   (interactive)
-  (find-file (expand-file-name "NEWS" data-directory)))
+  (find-file (locate-data-file "NEWS")))
 
 (defun xemacs-www-page ()
   "Go to the XEmacs World Wide Web page."

File lisp/loadup.el

     (message "Dumping under the name xemacs")
     ;; This is handled earlier in the build process.
     ;; (condition-case () (delete-file "xemacs") (file-error nil))
-  (when (fboundp 'really-free)
-    (really-free))
-  (dump-emacs "xemacs" "temacs")
-  (kill-emacs))
+    (test-atoms)
+    (when (fboundp 'really-free)
+      (really-free))
+    (test-atoms)
+    (dump-emacs "xemacs" "temacs")
+    (test-atoms)
+    (kill-emacs))
 
 (when (member "run-temacs" command-line-args)
   (message "\nBootstrapping from temacs...")

File lisp/mouse.el

 
 ;; enable drag regions (ograf@fga.de)
 ;; if button2 is dragged from within a region, this becomes a drop
-(if (featurep '(or offix cde))
+(if (featurep '(or offix cde mswindows))
     (global-set-key 'button2 'mouse-drag-or-yank)
   (global-set-key 'button2 'mouse-yank))
 
-;; enable drops from OffiX (ograf@fga.de)
-;; accept any button1,2,3 drop with `mouse-offix-drop'
+;; enable drops from OffiX (ograf@fga.de) or mswindows
+;; accept any button1,2,3 drop with `mouse-offix-drop' or 'mswindows-mouse-drop'
 (cond ((featurep 'offix)
        (global-set-key 'drop1 'mouse-offix-drop)
        (global-set-key 'drop2 'mouse-offix-drop)
-       (global-set-key 'drop3 'mouse-offix-drop)))
+       (global-set-key 'drop3 'mouse-offix-drop))
+      ((featurep 'mswindows)
+       (global-set-key 'drop0 'mouse-mswindows-drop)
+       (global-set-key 'drop1 'mouse-mswindows-drop)
+       (global-set-key 'drop2 'mouse-mswindows-drop)
+       (global-set-key 'drop3 'mouse-mswindows-drop)))
 
 (defgroup mouse nil
   "Window system-independent mouse support."
 	     (make-frame-visible frame))))
     (undo-boundary)))
 
+(defun mouse-mswindows-drop (event)
+  "Do something with a drop event. Inserts Text drops and
+ executes appropriate commands for specific drops.
+ Text drops follow the `mouse-yank-at-point' variable."
+  (interactive "e")
+  (let* ((type (car (event-drag-and-drop-data event)))
+	(data (cadr (event-drag-and-drop-data event)))
+	(frame (event-channel event))
+	(window (if frame (event-window event) (frame-selected-window))))
+    (cond ((= type 2)	;; file
+	   (let ((x pop-up-windows))
+	     (setq pop-up-windows nil)
+	     (cond (window
+		    (select-window window)))
+	     (switch-to-buffer (find-file-noselect data))
+	     (make-frame-visible frame)
+	     (setq pop-up-windows x)))
+	  ((= type 3)	;; files
+	   (let ((x pop-up-windows))
+	     (setq pop-up-windows nil)
+	     (while (not (eq data ()))
+	       (pop-to-buffer (find-file-noselect (car data)) nil frame)
+	       (setq data (cdr data)))
+	     (make-frame-visible frame)
+	     (setq pop-up-windows x)))
+	  ((= type 4)	;; text
+	   (and (not mouse-yank-at-point)
+		(mouse-set-point event))
+	   (insert data))
+	  (t ;; this is raw data or unknown stuff
+	   (let ((buf (generate-new-buffer "DndRawData")))
+	     (set-buffer buf)
+	     (pop-to-buffer buf nil frame)
+	     (insert data)
+	     (hexlify-buffer)
+	     (make-frame-visible frame))))
+    (undo-boundary)))
+
 (defun mouse-eval-sexp (click force-window)
   "Evaluate the sexp under the mouse.  Usually, this is the last sexp before
 the click, but if you click on a left paren, then it is the sexp beginning

File lisp/msw-select.el

 
 ;;; Code:
 
-;(defun mswindows-paste-clipboard ()
-;  "Insert the current contents of the Clipboard at point."
-;  (interactive "*")
-;  (setq last-command nil)
-;  (setq this-command 'yank) ; so that yank-pop works.
-; (let ((clip (mswindows-get-clipboard)))
-;    (or clip (error "there is no clipboard selection"))
-;    (push-mark)
-;    (insert clip)))
-
 (defun mswindows-paste-clipboard ()
   "Insert the current contents of the mswindows clipboard at point,
 replacing the active selection if there is one."

File nt/ChangeLog

+1998-01-28  Jonathon Harris  <jhar@tardis.ed.ac.uk>
+
+	* xemacs.mak: Updated accordingly.
+	Creates the MSVC browse info immediately after the link.
+
 1997-12-29  Kirill M. Katsnelson  <kkm@kis.ru>
 
 	* config.h: Suppressed MSVC warning 'relational' : signed/unsigned

File nt/xemacs.mak

  $(XEMACS)\src\objects-msw.c \
  $(XEMACS)\src\redisplay-msw.c \
  $(XEMACS)\src\scrollbar-msw.c \
- $(XEMACS)\src\select-msw.c \
- $(XEMACS)\src\msw-proc.c
+ $(XEMACS)\src\select-msw.c
 !endif
 
 !if $(HAVE_MULE)
 	$(OUTDIR)\objects-msw.obj \
 	$(OUTDIR)\redisplay-msw.obj \
 	$(OUTDIR)\scrollbar-msw.obj \
-	$(OUTDIR)\select-msw.obj \
-	$(OUTDIR)\msw-proc.obj
+	$(OUTDIR)\select-msw.obj
 !endif
 
 !if $(HAVE_MULE)
 	link.exe @<<
   $(TEMACS_LFLAGS) $(TEMACS_OBJS) $(TEMACS_LIBS)
 <<
-	!$(TEMACS) -batch -l update-elc.el
 
 xemacs.res: xemacs.rc
 	rc xemacs.rc
 	!$(LIB_SRC)\make-docfile.exe -a $(DOC) -d $(TEMACS_SRC) $(DOC_SRC8)
 	!$(LIB_SRC)\make-docfile.exe -a $(DOC) -d $(TEMACS_SRC) $(DOC_SRC9)
 
-update-elc: $(LOADPATH)\startup.el
+update-elc:
 	!$(TEMACS) -batch -l update-elc.el
 
 rebuild: $(TEMACS_DIR)\puresize-adjust.h
 #------------------------------------------------------------------------------
 
 # use this rule to build the complete system
-all: $(LASTFILE) $(LWLIB) $(SUPPORT_PROGS) $(TEMACS) $(TEMACS_BROWSE) $(DOC) dump-xemacs
+all: $(LASTFILE) $(LWLIB) $(SUPPORT_PROGS) $(TEMACS) $(TEMACS_BROWSE) update-elc $(DOC) dump-xemacs
 	-del rebuild
 
 temacs:  $(TEMACS)
 	-del /s /q *.bak *.elc *.orig *.rej
 
 depend:
-	mkdepend -f xemacs.mak -p$(OUTDIR)\ -o.obj -w9999 -- $(TEMACS_CPP_FLAGS) --  $(DOC_SRC1) $(DOC_SRC2) $(DOC_SRC3) $(DOC_SRC4) $(DOC_SRC5) $(DOC_SRC6) $(DOC_SRC7) $(DOC_SRC8) $(LASTFILE_SRC)\lastfile.c $(LIB_SRC)\make-docfile.c .\runemacs.c
+	mkdepend -f xemacs.mak -p$(OUTDIR)\ -o.obj -w2048 -- $(TEMACS_CPP_FLAGS) --  $(DOC_SRC1) $(DOC_SRC2) $(DOC_SRC3) $(DOC_SRC4) $(DOC_SRC5) $(DOC_SRC6) $(DOC_SRC7) $(DOC_SRC8) $(LASTFILE_SRC)\lastfile.c $(LIB_SRC)\make-docfile.c .\runemacs.c
 
 # DO NOT DELETE THIS LINE -- make depend depends on it.
 	mkdepend -f xemacs.mak -p$(OUTDIR)\ -o.obj -w9999 -- $(TEMACS_CPP_FLAGS) --  $(DOC_SRC1) $(DOC_SRC2) $(DOC_SRC3) $(DOC_SRC4) $(DOC_SRC5) $(DOC_SRC6) $(DOC_SRC7) $(DOC_SRC8) $(DOC_SRC9) $(LASTFILE_SRC)\lastfile.c $(LIB_SRC)\make-docfile.c .\runemacs.c

File src/ChangeLog

+1998-02-01  Kyle Jones  <kyle_jones@wonderworks.com>
+
+	* redisplay.c (redisplay_window): After outputting
+	  the window, invalidate its the line start cache if the
+	  we're displaying the minibuffer window and the echo
+	  area is active.  The cache is only valid for the echo
+	  area buffer, and that buffer isn't associated with the
+	  minibuffer window anymore.
+
+1998-01-31  SL Baur  <steve@altair.xemacs.org>
+
+	* alloc.c (disksave_object_finalization): Additional checking for
+	sanity when zeroing out unused portions of string_chars_block's.
+	(Fpurecopy): Spelling fixes in comment.
+	(PURESIZE_SLOP): Set default slop to 0.
+
+1998-01-31  Kyle Jones  <kyle_jones@wonderworks.com>
+
+	* chartab.c (make_char_table): Initialize mirror
+	  tables with Spunct in all the slots.  Syntax table
+	  initialization doesn't touch slots for nonexistent
+	  characters sets.  If character sets corresponding to
+	  those slots are created later Qnil values in the slots
+	  will cause crashes.
+	(copy_char_table_entry): Return copy not original.
+
+1998-01-28  Jonathon Harris  <jhar@tardis.ed.ac.uk>
+
+	* msw-proc.c:
+	* event-msw.h:
+	* event-msw.c:
+	* console-msw.h:
+	Deleted the first two and merged them into the last two files.
+
+	* device-msw.c:
+	* event-msw.c:
+ 	* frame-msw.c:
+	Added file-based drag and drop support. The "System/Open" DDE command
+	is also implemented as if it were a drag and drop operation.
+	
+	* emacsfns.h:
+	* event-stream.c:
+	* events.c:
+	* events.h:
+	* frame.c:
+	* keymap.c:
+	Replaced all "#ifdef HAVE_OFFIX_DND" with
+	"#if defined(HAVE_OFFIX_DND) || defined(HAVE_MS_WINDOWS)"
+
+	* device.h: Added DEVICE_MSWINDOWS_P and related macros.
+
+	* objects-msw.c:
+	* select-msw.c:
+	Eliminated warnings.
+
+	* redisplay-msw.c: Changed color of "dead" box between scrollbars
+	to windows' "button" color for compatibility with other windows apps.
+
+1998-01-20  Stephen Turnbull  <turnbull@sk.tsukuba.ac.jp>
+
+	* Makefile.in.in: move `rm puresize-adjust.h' from distclean
+	  to mostlyclean
+
+1998-01-29  SL Baur  <steve@altair.xemacs.org>
+
+	* Makefile.in.in (dlopen.o): Add dependencies.
+
+	* s/sunos4-0.h: Conditionalize use of broken-sun.h for old Gccs.
+	Suggested by Amir J Katz <amir@ndsoft.com>
+
+1998-01-28  SL Baur  <steve@altair.xemacs.org>
+
+	* faces.c (init_device_faces): This function can call lisp.
+
+1998-01-28  P. E. Jareth Hein  <jareth@camelot-soft.com>
+
+	* mule-coding.h:
+	* mule-coding.c: (determine_real_coding_system): removed the
+	static declaration to allow reuse.
+
+	* md5.c (Fmd5): Rewrote to fully support MULE, as well as streamline
+	the code.
+
+	* mule-ccl.c (ccl_driver): Set initial values of variables to shut up
+ 	the compiler and to give better error message if a quit happens before
+	any ccl_code is generated.
+
+1998-01-28  SL Baur  <steve@altair.xemacs.org>
+
+	* glyphs.c (allocate_glyph): This function can GC.
+	Wrap GCPRO around unprotected function calls.
+	(specifier_vars_of_glyphs): Comment change -- Can we GC here?
+
 1998-01-27  SL Baur  <steve@altair.xemacs.org>
 
+	* lread.c (Fload_internal): Add extra GCPRO around call to
+	Fassoc.
+	Enable purespace usage counts always.
+
 	* m/powerpc.h: Isolate changes for mklinux from AIX.
 
 1998-01-27  Hrvoje Niksic  <hniksic@srce.hr>

File src/Makefile.in.in

 
 .PHONY: mostlyclean clean distclean realclean versionclean extraclean
 mostlyclean:
-	$(RM) temacs puremacs quantmacs prefix-args depend.* *.o *.i core
+	$(RM) temacs puremacs quantmacs prefix-args depend.* *.o *.i \
+	  core puresize-adjust.h
 clean: mostlyclean versionclean
 	$(RM) libextcli* update-elc.stamp
 ## This is used in making a distribution.
 ## Do not use it on development directories!
 distclean: clean
-	$(RM) config.h paths.h puresize-adjust.h Emacs.ad.h \
+	$(RM) config.h paths.h Emacs.ad.h \
 	  Makefile Makefile.in TAGS xemacs.*
 realclean: distclean
 versionclean:
 dired.o: regex.h
 dired.o: sysdir.h
 dired.o: sysfile.h
+dlopen.o: config.h
+dlopen.o: buffer.h
 doc.o: blocktype.h
 doc.o: buffer.h
 doc.o: bufslots.h
 	     * But purified aggregate objects like lists and vectors
 	     * can contain uninterned symbols.  If there are no
 	     * other non-pure references to the symbol, then the
-	     * symbol is not proteted from garabge colelction
+	     * symbol is not protected from garbage collection
 	     * because the collector does not mark the contents of
 	     * purified objects.  So to protect the symbols, an impure
 	     * reference has to be kept for each uninterned symbol
 	     * that is referenced by a pure object.  All such
 	     * symbols are stored in the hashtable pointed to by
-	     * Vpure_uninterened_symbol_table, which is itself
+	     * Vpure_uninterned_symbol_table, which is itself
 	     * staticpro'd.
 	     */
 	    if (EQ (XSYMBOL (obj)->obarray, Vobarray))
       extern Lisp_Object Vemacs_beta_version;
       /* This used to be NILP(Vemacs_beta_version) ? 512 : 4; */
 #ifndef PURESIZE_SLOP
-#define PURESIZE_SLOP 4
+#define PURESIZE_SLOP 0
 #endif
       int slop = PURESIZE_SLOP;
 
       sprintf (buf, "Purespace usage: %ld of %ld (%d%%",
                pureptr, (long) get_PURESIZE(),
                (int) (pureptr / (get_PURESIZE() / 100.0) + 0.5));
-      if (lost > 2) {
+      if (lost > ((slop ? slop : 1) / 1024)) {
         sprintf (buf + strlen (buf), " -- %dk wasted", lost);
 	if (die_if_pure_storage_exceeded) {
 	  puresize_adjust_h (pureptr + slop);
   /* Run the disksave finalization methods of all live objects. */
   disksave_object_finalization_1 ();
 
+#if 0 /* I don't see any point in this.  The purespace starts out all 0's */
   /* Zero out the unused portion of purespace */
   if (!pure_lossage)
     memset (  (char *) (PUREBEG + pureptr), 0,
 	    (((char *) (PUREBEG + get_PURESIZE())) -
 	     ((char *) (PUREBEG + pureptr))));
+#endif
 
   /* Zero out the uninitialized (really, unused) part of the containers
      for the live strings. */
   {
     struct string_chars_block *scb;
     for (scb = first_string_chars_block; scb; scb = scb->next)
-      /* from the block's fill ptr to the end */
-      memset ((scb->string_chars + scb->pos), 0,
-              sizeof (scb->string_chars) - scb->pos);
+      {
+	int count = sizeof (scb->string_chars) - scb->pos;
+
+	assert (count >= 0 && count < STRING_CHARS_BLOCK_SIZE);
+	if (count != 0) {
+	  /* from the block's fill ptr to the end */
+	  memset ((scb->string_chars + scb->pos), 0, count);
+	}
+      }
   }
 
   /* There, that ought to be enough... */

File src/chartab.c

   if (ty == CHAR_TABLE_TYPE_SYNTAX)
     {
       ct->mirror_table = Fmake_char_table (Qgeneric);
+      fill_char_table (XCHAR_TABLE (ct->mirror_table), 
+                       make_int (Spunct)); 
     }
   else
     ct->mirror_table = Qnil;
 	ctenew->level2[i] = new;
     }
 
-  XSETCHAR_TABLE_ENTRY (obj, cte);
+  XSETCHAR_TABLE_ENTRY (obj, ctenew);
   return obj;
 }
 

File src/console-msw.c

 
 #include "console-msw.h"
 
+
 DEFINE_CONSOLE_TYPE (mswindows);
 
 
 {
   Fprovide (Qmswindows);
 }
+
+
+#ifdef DEBUG_XEMACS
+#include "events.h"
+#include "opaque.h"
+/*
+ * Random helper functions for debugging.
+ * Intended for use in the MSVC "Watch" window which doesn't like
+ * the aborts that the error_check_foo() functions can make.
+ */
+struct lrecord_header *DHEADER(Lisp_Object obj)
+{
+  return (LRECORDP (obj)) ? XRECORD_LHEADER (obj) : NULL;
+}
+
+int *DOPAQUE_DATA (Lisp_Object obj)
+{
+  return (OPAQUEP (obj)) ? OPAQUE_DATA (XOPAQUE (obj)) : NULL;
+}
+
+struct Lisp_Event *DEVENT(Lisp_Object obj)
+{
+  return (EVENTP (obj)) ? XEVENT (obj) : NULL;
+}
+
+struct Lisp_Cons *DCONS(Lisp_Object obj)
+{
+  return (CONSP (obj)) ? XCONS (obj) : NULL;
+}
+
+Lisp_Object DCAR(Lisp_Object obj)
+{
+  return (CONSP (obj)) ? XCAR (obj) : 0;
+}
+
+Lisp_Object DCDR(Lisp_Object obj)
+{
+  return (CONSP (obj)) ? XCDR (obj) : 0;
+}
+
+struct Lisp_Cons *DCONSCDR(Lisp_Object obj)
+{
+  return ((CONSP (obj)) && (CONSP (XCDR (obj)))) ? XCONS (XCDR (obj)) : 0;
+}
+
+Lisp_Object DCARCDR(Lisp_Object obj)
+{
+  return ((CONSP (obj)) && (CONSP (XCDR (obj)))) ? XCAR (XCDR (obj)) : 0;
+}
+
+char *DSTRING(Lisp_Object obj)
+{
+  return (STRINGP (obj)) ? XSTRING_DATA (obj) : NULL;
+}
+
+struct Lisp_Vector *DVECTOR(Lisp_Object obj)
+{
+  return (VECTORP (obj)) ? XVECTOR (obj) : NULL;
+}
+
+struct Lisp_Symbol *DSYMBOL(Lisp_Object obj)
+{
+  return (SYMBOLP (obj)) ? XSYMBOL (obj) : NULL;
+}
+
+char *DSYMNAME(Lisp_Object obj)
+{
+  return (SYMBOLP (obj)) ? XSYMBOL (obj)->name->_data : NULL;
+}
+
+#endif

File src/console-msw.h

-/* Define mswindowsindows-specific console, device, and frame object for XEmacs.
+/* Define mswindows-specific console, device, and frame object for XEmacs.
    Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
 
 #include "console.h"
 
 #include "windows.h"
+#include "ddeml.h"	/* DDE management library */
+#include "shellapi.h"	/* FileManager/Explorer drag and drop */
+
+/*
+ * XXX FIXME: The following X modifier defs in events-mod.h clash with win32
+ * hotkey defs in winuser.h. For the moment lose the win32 versions.
+ * Maybe we should rename all of MOD_* to something that doesn't clash.
+ */
+#ifdef MOD_CONTROL
+#  undef MOD_CONTROL
+#endif  
+#ifdef MOD_ALT
+#  undef MOD_ALT
+#endif  
+#ifdef MOD_SHIFT
+#  undef MOD_SHIFT
+#endif  
+
+
+/* The name of the main window class */
+#define XEMACS_CLASS "XEmacs"
+
+
+/*
+ * Console
+ */
 
 DECLARE_CONSOLE_TYPE (mswindows);
 
 };
 
 
+/*
+ * Device
+ */
+
 struct mswindows_device
 {
   int logpixelsx, logpixelsy;
 #define DEVICE_MSWINDOWS_VERTSIZE(d) 	(DEVICE_MSWINDOWS_DATA (d)->vertsize)
 
 
+/*
+ * Frame
+ */
+
 struct mswindows_frame
 {
   /* win32 window handle */
 #define FRAME_MSWINDOWS_MENU_HASHTABLE(f) (FRAME_MSWINDOWS_DATA (f)->menu_hashtable)
 #define FRAME_MSWINDOWS_MENU_CHECKSUM(f)  (FRAME_MSWINDOWS_DATA (f)->menu_checksum)
 
+/* win32 window LONG indices */
+#define XWL_FRAMEOBJ	0
+#define XWL_COUNT	1	/* Number of LONGs that we use */
+#define MSWINDOWS_WINDOW_EXTRA_BYTES	(XWL_COUNT*4)
+
+
 /*
- * Redisplay functions
+ * Events
  */
+
+/* win32 messages / magic event types */
+#define EVENT_MSWINDOWS_MAGIC_TYPE(e)	\
+	((e)->event.magic.underlying_mswindows_event)
+#define XM_BUMPQUEUE	(WM_USER + 101)
+#define XM_MAPFRAME	(WM_USER + 102)
+#define XM_UNMAPFRAME	(WM_USER + 103)
+
+
+/*
+ * Random globals
+ */
+
+/* win32 "Windows" procedure */
+LRESULT WINAPI mswindows_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam,
+				   LPARAM lParam);
+
 void mswindows_redraw_exposed_area (struct frame *f, int x, int y, 
-			      int width, int height);
+				    int width, int height);
+
+/* win32 DDE management library */
+#define MSWINDOWS_DDE_ITEM_OPEN "Open"
+extern DWORD mswindows_dde_mlid;
+extern HSZ mswindows_dde_service;
+extern HSZ mswindows_dde_topic_system;
+extern HSZ mswindows_dde_item_open;
+HDDEDATA CALLBACK mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
+					  HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
+					  DWORD dwData1, DWORD dwData2);
+
+void mswindows_enqueue_dispatch_event (Lisp_Object event);
+void mswindows_enqueue_magic_event (HWND hwnd, UINT message);
+Lisp_Object mswindows_cancel_dispatch_event (struct Lisp_Event* event);
+Lisp_Object mswindows_pump_outstanding_events (void);
 
 #endif /* _XEMACS_CONSOLE_MSW_H_ */

File src/device-msw.c

 #include "console-msw.h"
 #include "console-stream.h"
 #include "events.h"
-#include "event-msw.h"
 #include "faces.h"
 #include "frame.h"
+#include "sysdep.h"
+
+/* win32 DDE management library globals */
+DWORD mswindows_dde_mlid;
+HSZ mswindows_dde_service;
+HSZ mswindows_dde_topic_system;
+HSZ mswindows_dde_item_open;
 
 Lisp_Object Qinit_pre_mswindows_win, Qinit_post_mswindows_win;
 
 static void
 mswindows_init_device (struct device *d, Lisp_Object props)
 {
-  WNDCLASS wc;
+  WNDCLASSEX wc;
   HWND desktop;
   HDC hdc;
 
   DEVICE_CLASS(d) = Qcolor;
 
   /* Register the main window class */
+  wc.cbSize = sizeof (WNDCLASSEX);
   wc.style = CS_OWNDC;	/* One DC per window */
   wc.lpfnWndProc = (WNDPROC) mswindows_wnd_proc;
   wc.cbClsExtra = 0;
   wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
   wc.lpszMenuName = NULL;
   wc.lpszClassName = XEMACS_CLASS;
-  RegisterClass(&wc);		/* XXX FIXME: Should use RegisterClassEx */
+  wc.hIconSm = LoadImage (GetModuleHandle (NULL), XEMACS_CLASS,
+			  IMAGE_ICON, 16, 16, 0);
+  RegisterClassEx (&wc);
+}
+
+static void
+mswindows_finish_init_device (struct device *d, Lisp_Object props)
+{
+  /* Initialise DDE management library and our related globals */
+  mswindows_dde_mlid = 0;
+  DdeInitialize (&mswindows_dde_mlid, mswindows_dde_callback,
+		 APPCMD_FILTERINITS|CBF_FAIL_SELFCONNECTIONS|CBF_FAIL_ADVISES|
+		 CBF_FAIL_POKES|CBF_FAIL_REQUESTS|CBF_SKIP_ALLNOTIFICATIONS, 0);
+  
+  mswindows_dde_service = DdeCreateStringHandle (mswindows_dde_mlid, XEMACS_CLASS, 0);
+  mswindows_dde_topic_system = DdeCreateStringHandle (mswindows_dde_mlid, SZDDESYS_TOPIC, 0);
+  mswindows_dde_item_open = DdeCreateStringHandle (mswindows_dde_mlid,
+						   TEXT(MSWINDOWS_DDE_ITEM_OPEN), 0);
+  DdeNameService (mswindows_dde_mlid, mswindows_dde_service, 0L, DNS_REGISTER);
+}
+
+static void
+mswindows_delete_device (struct device *d)
+{
+  DdeNameService (mswindows_dde_mlid, 0L, 0L, DNS_REGISTER);
+  DdeUninitialize (mswindows_dde_mlid);
 }
 
 static int
 console_type_create_device_mswindows (void)
 {
   CONSOLE_HAS_METHOD (mswindows, init_device);
-/*  CONSOLE_HAS_METHOD (mswindows, finish_init_device); */
+  CONSOLE_HAS_METHOD (mswindows, finish_init_device);
 /*  CONSOLE_HAS_METHOD (mswindows, mark_device); */
-/*  CONSOLE_HAS_METHOD (mswindows, delete_device); */
+  CONSOLE_HAS_METHOD (mswindows, delete_device);
   CONSOLE_HAS_METHOD (mswindows, device_pixel_width);
   CONSOLE_HAS_METHOD (mswindows, device_pixel_height);
   CONSOLE_HAS_METHOD (mswindows, device_mm_width);

File src/device.h

 #define CHECK_X_DEVICE(z) CHECK_DEVICE_TYPE (z, x)
 #define CONCHECK_X_DEVICE(z) CONCHECK_DEVICE_TYPE (z, x)
 
+#define DEVICE_MSWINDOWS_P(dev) CONSOLE_TYPESYM_MSWINDOWS_P (DEVICE_TYPE (dev))
+#define CHECK_MSWINDOWS_DEVICE(z) CHECK_DEVICE_TYPE (z, mswindows)
+#define CONCHECK_MSWINDOWS_DEVICE(z) CONCHECK_DEVICE_TYPE (z, mswindows)
+
 #define DEVICE_TTY_P(dev) CONSOLE_TYPESYM_TTY_P (DEVICE_TYPE (dev))
 #define CHECK_TTY_DEVICE(z) CHECK_DEVICE_TYPE (z, tty)
 #define CONCHECK_TTY_DEVICE(z) CONCHECK_DEVICE_TYPE (z, tty)

File src/emacsfns.h

 extern Lisp_Object Qdevice;
 extern Lisp_Object Qdimension;
 extern Lisp_Object Qdisplay;
-#ifdef HAVE_OFFIX_DND
+#if defined(HAVE_OFFIX_DND) || defined(HAVE_MS_WINDOWS)
 extern Lisp_Object Qdnd_data;
 #endif
 extern Lisp_Object Qdoc_string;
 */
        (stream, detailed))
 {
+  /* This function can GC */
   struct backtrace *backlist = backtrace_list;
   struct catchtag *catches = catchlist;
   int speccount = specpdl_depth_counter;

File src/event-msw.c

 #include <config.h>
 #include "lisp.h"
 
+#include "console-msw.h"
+
+#ifdef HAVE_SCROLLBARS
+# include "scrollbar-msw.h"
+#endif
+
+#ifdef HAVE_MENUBARS
+# include "menubar-msw.h"
+#endif
+
 #include "device.h"
-#include "console-msw.h"
 #include "emacsfns.h"
 #include "events.h"
 #include "frame.h"
 #include "syswait.h"
 #include "systime.h"
 
-#include "event-msw.h"
+#include "events-mod.h"
+
+#ifdef HAVE_MENUBARS
+#define ADJR_MENUFLAG TRUE
+#else
+#define ADJR_MENUFLAG FALSE
+#endif
+
+/* Fake key modifier which is attached to a quit char event.
+   Removed upon dequeueing an event */
+#define FAKE_MOD_QUIT	0x80
+
+/* Timer ID used for button2 emulation */
+#define BUTTON_2_TIMER_ID 1
+
+/* Drag and drop event data types (subset of types in offix-types.h) */
+#define DndFile		2
+#define	DndFiles	3
+#define	DndText		4
+
+
+static Lisp_Object mswindows_find_frame (HWND hwnd);
+static Lisp_Object mswindows_find_console (HWND hwnd);
+static Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods);
+static int mswindows_modifier_state (BYTE* keymap, int has_AltGr);
+static void mswindows_set_chord_timer (HWND hwnd);
+static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
+static int mswindows_current_layout_has_AltGr (void);
+
 
 static struct event_stream *mswindows_event_stream;
 
 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
 
-/*
- * List of mswindows waitable handles.
- * Apart from the dispatch queue semaphore, all of these handles may be waited
- * on multiple times in emacs_mswindows_next_event before being processed and so
- * must be manual-reset events.
- */
+/* The number of things we can wait on */
+#define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
+
+/* List of mswindows waitable handles. */
 static HANDLE mswindows_waitable[MAX_WAITABLE];
 
-/* random emacs info associated with each of the wait handles */
-static mswindows_waitable_info_type mswindows_waitable_info[MAX_WAITABLE];
-
 /* Count of quit chars currently in the queue */
-/* Incremented in WM_CHAR handler in msw-proc.c
+/* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
    Decremented in mswindows_dequeue_dispatch_event() */
 int mswindows_quit_chars_count = 0;
 
 {
   return (sevt->event_type == key_press_event
 	  || sevt->event_type == button_press_event
-	  || sevt->event_type == button_release_event);
+	  || sevt->event_type == button_release_event
+	  || sevt->event_type == dnd_drop_event);
 }
 
-/*
+/************************************************************************/
+/*                     Dispatch queue management                        */
+/************************************************************************/
+
+/* 
  * Add an emacs event to the proper dispatch queue
  */
 void
   PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
 }
 
+void
+mswindows_enqueue_magic_event (HWND hwnd, UINT message)
+{
+  Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
+  struct Lisp_Event* event = XEVENT (emacs_event);
+
+  event->channel = mswindows_find_frame (hwnd);
+  event->timestamp = GetMessageTime();
+  event->event_type = magic_event;
+  EVENT_MSWINDOWS_MAGIC_TYPE (event) = message;
+
+  mswindows_enqueue_dispatch_event (emacs_event);
+}
+
+static void
+mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWORD when)
+{
+
+  /* We always use last message time, because mouse button
+     events may get delayed, and XEmacs double click
+     recognition will fail */
+
+  Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
+  struct Lisp_Event* event = XEVENT(emacs_event);
+
+  event->channel = mswindows_find_frame(hwnd);
+  event->timestamp = when;
+  event->event.button.button =
+    (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 :
+    ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2);
+  event->event.button.x = where.x;
+  event->event.button.y = where.y;
+  event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
+      
+  if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN ||
+      message==WM_RBUTTONDOWN)
+    {
+      event->event_type = button_press_event;
+      SetCapture (hwnd);
+    }
+  else
+    {
+      event->event_type = button_release_event;
+      ReleaseCapture ();
+    }
+  
+  mswindows_enqueue_dispatch_event (emacs_event);
+}
+
+static void
+mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
+{
+  Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
+  struct Lisp_Event* event = XEVENT(emacs_event);
+
+  event->channel = mswindows_find_console(hwnd);
+  event->timestamp = GetMessageTime();
+  event->event_type = key_press_event;
+  event->event.key.keysym = keysym;
+  event->event.key.modifiers = mods;
+  mswindows_enqueue_dispatch_event (emacs_event);
+}
+
 /*
  * Remove and return the first emacs event on the dispatch queue.
  * Give a preference to user events over non-user ones.
   return Qnil;
 }
 
+
+/************************************************************************/
+/*                             Event pump                               */
+/************************************************************************/
+
 static Lisp_Object
 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
 				    Lisp_Object u_n_u_s_e_d)
   /* This function can call lisp */
 
   Lisp_Object result = Qt;
-
+  struct gcpro gcpro1;
+  GCPRO1 (result);
+  
   if (NILP(mswindows_error_caught_in_modal_loop))
       result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
+  UNGCPRO;
   return result;
 }
 
-/*
- * Find a free waitable slot
- */
-#if 0 /* NOTUSED */
-static int
-mswindows_find_free_waitable(void)
-{
-  int i;
-  for (i=0; i<mswindows_waitable_count; i++)
-    if (mswindows_waitable_info[i].type == mswindows_waitable_type_none)
-      return i;
-  assert (mswindows_waitable_count < MAX_WAITABLE);
-  return mswindows_waitable_count++;
-}
-#endif
 
-/*
- * Create a new waitable using the type and data passed in by the info structure
- * Returns a pointer to the info associated with the assigned waitable object
- */
-mswindows_waitable_info_type *
-mswindows_add_waitable(mswindows_waitable_info_type *info)
-{
-  int waitable;
-
-  switch (info->type)
-  {
-  case mswindows_waitable_type_dispatch:
-    assert (0); /* kkm - should not get here */
-    /* Can only have one waitable for the dispatch queue, and it's the first one */
-    assert (mswindows_waitable_count++ == 0);
-    waitable=0;
-#if 0
-    InitializeCriticalSection(&mswindows_dispatch_crit);
-#endif
-    assert (mswindows_waitable[0] = CreateSemaphore (NULL, 0, 0x7fffffff, NULL));
-    return mswindows_waitable_info+0;
-
-  default:
-    assert(0);
-  }
-  mswindows_waitable_info[waitable].type = info->type;
-  return mswindows_waitable_info+waitable;
-}
-
-/*
- * Remove a waitable using the type and data passed in by the info structure.
- */
-void
-mswindows_remove_waitable(mswindows_waitable_info_type *info)
-{
-  int waitable;
-
-  switch (info->type)
-  {
-
-  default:
-    assert(0);
-  }
-
-  CloseHandle(mswindows_waitable[waitable]);
-  mswindows_waitable[waitable] = 0;
-  mswindows_waitable_info[waitable].type = mswindows_waitable_type_none;
-  if (waitable == mswindows_waitable_count-1)
-    --mswindows_waitable_count;
-}
-
-/* 
- * Callback procedure for synchronous timer messages
- */
-static void CALLBACK
-mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
-{
-  Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
-  struct Lisp_Event *event = XEVENT (emacs_event);
-
-  if (KillTimer (NULL, id_timer))
-    --mswindows_pending_timers_count;
-
-  event->channel = Qnil;
-  event->timestamp = dwtime;
-  event->event_type = timeout_event;
-  event->event.timeout.interval_id = id_timer;
-
-  mswindows_enqueue_dispatch_event (emacs_event);
-}
 
 static void 
 mswindows_drain_windows_queue ()
       {
 	/* XXX FIXME: We should do some kind of round-robin scheme to ensure fairness */
 	int waitable = active - WAIT_OBJECT_0;
-	mswindows_waitable_info_type *info  = mswindows_waitable_info + waitable;
-
-	switch (info->type)
-	  {
-	    /* XXX FIXME: Should enque subprocess event here so that it is not lost */
-	  default:
-	    assert(0);
-	  }
+	assert(0);	/* #### */
       }
   } /* while */
 
   return;
 }
 
+/************************************************************************/
+/*                           Event generators                           */
+/************************************************************************/
+
+/* 
+ * Callback procedure for synchronous timer messages
+ */
+static void CALLBACK
+mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
+{
+  Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
+  struct Lisp_Event *event = XEVENT (emacs_event);
+
+  if (KillTimer (NULL, id_timer))
+    --mswindows_pending_timers_count;
+
+  event->channel = Qnil;
+  event->timestamp = dwtime;
+  event->event_type = timeout_event;
+  event->event.timeout.interval_id = id_timer;
+
+  mswindows_enqueue_dispatch_event (emacs_event);
+}
+
+/* 
+ * Callback procedure for dde messages
+ */
+HDDEDATA CALLBACK
+mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
+			HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
+			DWORD dwData1, DWORD dwData2)
+{ 
+  switch (uType)
+    { 
+    case XTYP_CONNECT:
+      if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
+	return (HDDEDATA)TRUE;
+      return (HDDEDATA)FALSE;
+
+    case XTYP_WILDCONNECT:
+      {
+	/* We only support one {service,topic} pair */
+	HSZPAIR pairs[2] = {
+	  { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
+
+	if (!(hszItem  || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
+	    !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)));
+	  return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
+				       sizeof (pairs), 0L, 0, uFmt, 0));
+      }
+      return (HDDEDATA)NULL; 
+
+    case XTYP_EXECUTE:
+      if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
+	{
+	  DWORD len = DdeGetData (hdata, NULL, 0, 0);
+	  char *cmd = alloca (len+1);
+	  char *end;
+          Lisp_Object l_dndlist;
+	  Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
+	  struct Lisp_Event *event = XEVENT (emacs_event);
+
+	  DdeGetData (hdata, cmd, len, 0);
+	  cmd[len] = '\0';
+	  DdeFreeDataHandle (hdata);
+
+	  /* Check syntax & that it's an [Open("foo")] command */
+	  /* #### Ought to be generalised and accept some other commands */
+	  if (*cmd == '[')
+	    cmd++;
+	  if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
+			strlen (MSWINDOWS_DDE_ITEM_OPEN)))
+	    return DDE_FNOTPROCESSED;
+	  cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
+	  while (*cmd==' ')
+	    cmd++;
+	  if (*cmd!='(' || *(cmd+1)!='\"')
+	    return DDE_FNOTPROCESSED;
+	  end = (cmd+=2);
+	  while (*end && *end!='\"')
+	    end++;
+	  if (!*end)
+	    return DDE_FNOTPROCESSED;
+	  *end = '\0';
+	  if (*(++end)!=')')
+	    return DDE_FNOTPROCESSED;
+	  if (*(++end)==']')
+	    end++;
+	  if (*end)
+	    return DDE_FNOTPROCESSED;
+
+	  l_dndlist = make_ext_string (cmd, strlen(cmd), FORMAT_FILENAME);
+
+	  event->channel = Qnil;
+	  event->timestamp = GetTickCount();
+	  event->event_type = dnd_drop_event;
+	  event->event.dnd_drop.button = 0;
+	  event->event.dnd_drop.modifiers = 0;
+	  event->event.dnd_drop.x = -1;
+	  event->event.dnd_drop.y = -1;
+	  event->event.dnd_drop.data = Fcons (make_int (DndFile),
+					      Fcons (l_dndlist, Qnil));
+	  mswindows_enqueue_dispatch_event (emacs_event);
+
+	  return (HDDEDATA) DDE_FACK;
+	}
+      DdeFreeDataHandle (hdata); 
+      return (HDDEDATA) DDE_FNOTPROCESSED;
+
+    default: 
+      return (HDDEDATA) NULL; 
+    } 
+
+}
+
+/*
+ * The windows procedure for the window class XEMACS_CLASS
+ */
+LRESULT WINAPI
+mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+  /* Note: Remember to initialise emacs_event and event before use.
+     This code calls code that can GC. You must GCPRO before calling such code. */
+  Lisp_Object emacs_event = Qnil;
+  Lisp_Object fobj = Qnil;
+
+  struct Lisp_Event *event;
+  struct frame *frame;
+  struct mswindows_frame* msframe;
+
+  switch (message)
+  {
+  case WM_ERASEBKGND:
+    /* Erase background only during non-dynamic sizing */
+    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+    if (msframe->sizing && !mswindows_dynamic_frame_resize)
+      goto defproc;
+    return 1;
+
+  case WM_CLOSE:
+    fobj = mswindows_find_frame (hwnd);
+    enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
+    mswindows_enqueue_magic_event (hwnd, XM_BUMPQUEUE);
+    break;
+
+  case WM_KEYDOWN:
+  case WM_SYSKEYDOWN:
+    {
+      BYTE keymap[256];
+      int has_AltGr = mswindows_current_layout_has_AltGr ();
+      int mods;
+      Lisp_Object keysym;
+
+      GetKeyboardState (keymap);
+      mods = mswindows_modifier_state (keymap, has_AltGr);
+
+      /* Handle those keys that TranslateMessage won't generate a WM_CHAR for */
+      if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods)))
+	mswindows_enqueue_keypress_event (hwnd, keysym, mods);
+      else
+	{
+	  int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
+	  BYTE keymap_orig[256];
+	  MSG msg = { hwnd, message, wParam, lParam, GetMessageTime(), (GetMessagePos()) };
+	  memcpy (keymap_orig, keymap, 256);
+
+	  /* Clear control and alt modifiers out of the keymap */
+	  keymap [VK_RCONTROL] = 0;
+	  keymap [VK_LMENU] = 0;
+	  if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80))
+	    {
+	      keymap [VK_LCONTROL] = 0;
+	      keymap [VK_CONTROL] = 0;
+	      keymap [VK_RMENU] = 0;
+	      keymap [VK_MENU] = 0;
+	    }
+	  SetKeyboardState (keymap);
+
+	  /* Have some WM_[SYS]CHARS in the queue */
+	  TranslateMessage (&msg);
+
+	  while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
+		 ||PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
+	    {
+	      int ch = msg.wParam;
+	      /* CH is a character code for the key: 
+		 'C' for Shift+C and Ctrl+Shift+C
+		 'c' for c and Ctrl+c */
+
+	      /* #### If locale is not C, US or other latin-1,
+		 isalpha() maybe not what do we mean */
+	      
+	      /* XEmacs doesn't seem to like Shift on non-alpha keys */
+	      if (!isalpha(ch))
+		mods &= ~MOD_SHIFT;
+
+	      /* Un-capitalise alpha control keys */
+	      if ((mods & MOD_CONTROL) && isalpha(ch))
+		ch |= ('A' ^ 'a');
+
+	      /* If a quit char with no modifiers other than control and
+		 shift, then mark it with a fake modifier, which is removed
+		 upon dequeueing the event */
+	      /* #### This might also not withstand localization, if
+		 quit character is not a latin-1 symbol */
+	      if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
+		   || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch))
+		  && ((mods  & ~(MOD_CONTROL | MOD_SHIFT)) == 0))
+		{
+		  mods |= FAKE_MOD_QUIT;
+		  ++mswindows_quit_chars_count;
+		}
+
+	      mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods);
+	    } /* while */
+	  SetKeyboardState (keymap_orig);
+	} /* else */
+    }
+    goto defproc;
+
+  case WM_MBUTTONDOWN:
+  case WM_MBUTTONUP:
+    /* Real middle mouse button has nothing to do with emulated one:
+       if one wants to exercise fingers playing chords on the mouse,
+       he is allowed to do that! */
+    mswindows_enqueue_mouse_button_event (hwnd, message,
+					  MAKEPOINTS (lParam), GetMessageTime());
+    break;
+    
+  case WM_LBUTTONUP:
+    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+    msframe->last_click_time =  GetMessageTime();
+
+    KillTimer (hwnd, BUTTON_2_TIMER_ID);
+    msframe->button2_need_lbutton = 0;
+    if (msframe->ignore_next_lbutton_up)
+      {
+	msframe->ignore_next_lbutton_up = 0;
+      }
+    else if (msframe->button2_is_down)
+      {
+	msframe->button2_is_down = 0;
+	msframe->ignore_next_rbutton_up = 1;
+	mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
+					      MAKEPOINTS (lParam), GetMessageTime());
+      }
+    else
+      {
+	if (msframe->button2_need_rbutton)
+	  {
+	    msframe->button2_need_rbutton = 0;
+	    mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
+						  MAKEPOINTS (lParam), GetMessageTime());
+	  }
+	mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
+					      MAKEPOINTS (lParam), GetMessageTime());
+      }
+    break;
+
+  case WM_RBUTTONUP:
+    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+    msframe->last_click_time =  GetMessageTime();
+
+    KillTimer (hwnd, BUTTON_2_TIMER_ID);
+    msframe->button2_need_rbutton = 0;
+    if (msframe->ignore_next_rbutton_up)
+      {
+	msframe->ignore_next_rbutton_up = 0;
+      }
+    else if (msframe->button2_is_down)
+      {
+	msframe->button2_is_down = 0;
+	msframe->ignore_next_lbutton_up = 1;
+	mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
+					      MAKEPOINTS (lParam), GetMessageTime());
+      }
+    else
+      {
+	if (msframe->button2_need_lbutton)
+	  {
+	    msframe->button2_need_lbutton = 0;
+	    mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
+						  MAKEPOINTS (lParam), GetMessageTime());
+	  }
+	mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
+					      MAKEPOINTS (lParam), GetMessageTime());
+      }
+    break;
+
+  case WM_LBUTTONDOWN:
+    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+
+    if (msframe->button2_need_lbutton)
+      {
+	KillTimer (hwnd, BUTTON_2_TIMER_ID);
+	msframe->button2_need_lbutton = 0;
+	msframe->button2_need_rbutton = 0;
+	if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
+	  {
+	    mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
+						  MAKEPOINTS (lParam), GetMessageTime());
+	    msframe->button2_is_down = 1;
+	  }
+	else
+	  {
+	    mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
+			msframe->last_click_point, msframe->last_click_time);
+	    mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
+						  MAKEPOINTS (lParam), GetMessageTime());
+	  }
+      }
+    else
+      {
+	mswindows_set_chord_timer (hwnd);
+	msframe->button2_need_rbutton = 1;
+	msframe->last_click_point = MAKEPOINTS (lParam);
+      }
+    msframe->last_click_time =  GetMessageTime();
+    break;
+
+  case WM_RBUTTONDOWN:
+    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+
+    if (msframe->button2_need_rbutton)
+      {
+	KillTimer (hwnd, BUTTON_2_TIMER_ID);
+	msframe->button2_need_lbutton = 0;
+	msframe->button2_need_rbutton = 0;
+	if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
+	  {
+	    mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
+						  MAKEPOINTS (lParam), GetMessageTime());
+	    msframe->button2_is_down = 1;
+	  }
+	else
+	  {
+	    mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
+				msframe->last_click_point, msframe->last_click_time);
+	    mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
+						  MAKEPOINTS (lParam), GetMessageTime());
+	  }
+      }
+    else
+      {
+	mswindows_set_chord_timer (hwnd);
+	msframe->button2_need_lbutton = 1;
+	msframe->last_click_point = MAKEPOINTS (lParam);
+      }
+    msframe->last_click_time =  GetMessageTime();
+    break;
+	
+  case WM_TIMER:
+    if (wParam == BUTTON_2_TIMER_ID)
+      {
+	msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+	KillTimer (hwnd, BUTTON_2_TIMER_ID);
+
+	if (msframe->button2_need_lbutton)
+	  {
+	    msframe->button2_need_lbutton = 0;
+	    mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
+				msframe->last_click_point, msframe->last_click_time);
+	  }
+	else if (msframe->button2_need_rbutton)
+	  {
+	    msframe->button2_need_rbutton = 0;
+	    mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
+				msframe->last_click_point, msframe->last_click_time);
+	  }
+      }
+    else
+      assert ("Spurious timer fired" == 0);
+    break;
+
+  case WM_MOUSEMOVE:
+    /* Optimization: don't report mouse movement while size is changind */
+    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+    if (!msframe->sizing)
+    {
+      /* When waiting for the second mouse button to finish
+	 button2 emulation, and have moved too far, just pretend
+	 as if timer has expired. This impoves drag-select feedback */
+      if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
+	  && !mswindows_button2_near_enough (msframe->last_click_point,
+					     MAKEPOINTS (lParam)))
+	{
+	  KillTimer (hwnd, BUTTON_2_TIMER_ID);
+	  SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
+	}
+
+      emacs_event = Fmake_event (Qnil, Qnil);
+      event = XEVENT(emacs_event);
+
+      event->channel = mswindows_find_frame(hwnd);
+      event->timestamp = GetMessageTime();
+      event->event_type = pointer_motion_event;
+      event->event.motion.x = MAKEPOINTS(lParam).x;
+      event->event.motion.y = MAKEPOINTS(lParam).y;
+      event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
+      
+      mswindows_enqueue_dispatch_event (emacs_event);
+    }
+    break;
+
+  case WM_PAINT:
+    {
+      PAINTSTRUCT paintStruct;
+      
+      frame = XFRAME (mswindows_find_frame (hwnd));
+
+      BeginPaint (hwnd, &paintStruct);
+      mswindows_redraw_exposed_area (frame,
+			paintStruct.rcPaint.left, paintStruct.rcPaint.top,
+			paintStruct.rcPaint.right, paintStruct.rcPaint.bottom);
+      EndPaint (hwnd, &paintStruct);
+    }
+    break;
+
+  case WM_SIZE:
+    /* We only care about this message if our size has really changed */
+    if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
+    {
+      RECT rect;
+      int columns, rows;
+
+      fobj = mswindows_find_frame (hwnd);
+      frame = XFRAME (fobj);
+      msframe  = FRAME_MSWINDOWS_DATA (frame);
+
+      /* We cannot handle frame map and unmap hooks right in
+	 this routine, because these may throw. We queue
+	 magic events to run these hooks instead - kkm */
+
+      if (wParam==SIZE_MINIMIZED)
+	{
+	  /* Iconified */
+	  FRAME_VISIBLE_P (frame) = 0;
+	  mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
+	  Fframe_iconified_p (fobj);
+	}
+      else
+	{
+	  int was_visible = FRAME_VISIBLE_P (frame);
+	  if (!msframe->sizing && !was_visible)
+	    mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
+	  
+	  GetClientRect(hwnd, &rect);
+      	  FRAME_VISIBLE_P(frame) = 1;
+	  FRAME_PIXWIDTH(frame) = rect.right;
+	  FRAME_PIXHEIGHT(frame) = rect.bottom;
+	  pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
+	  change_frame_size (frame, rows, columns, 1);
+
+	  if (msframe->sizing && mswindows_dynamic_frame_resize)
+	    redisplay ();
+	}
+    }
+    break;
+
+  /* Misc magic events which only require that the frame be identified */
+  case WM_SETFOCUS:
+  case WM_KILLFOCUS:
+    mswindows_enqueue_magic_event (hwnd, message);
+    break;
+
+  case WM_WINDOWPOSCHANGING:
+    {
+      WINDOWPOS *wp = (LPWINDOWPOS) lParam;
+      WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
+      GetWindowPlacement(hwnd, &wpl);
+
+      /* Only interested if size is changing and we're not being iconified */
+      if ((wpl.showCmd != SW_SHOWMINIMIZED) && !(wp->flags & SWP_NOSIZE))
+      {
+	RECT ncsize = { 0, 0, 0, 0 };
+	int pixwidth, pixheight;
+ 	AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
+ 			    GetMenu(hwnd) != NULL,
+			    GetWindowLong (hwnd, GWL_EXSTYLE));
+
+	round_size_to_char (XFRAME (mswindows_find_frame (hwnd)),
+			    wp->cx - (ncsize.right - ncsize.left),
+			    wp->cy - (ncsize.bottom - ncsize.top),
+			    &pixwidth, &pixheight);
+
+	/* Convert client sizes to window sizes */
+	pixwidth += (ncsize.right - ncsize.left);
+	pixheight += (ncsize.bottom - ncsize.top);
+
+	if (wpl.showCmd != SW_SHOWMAXIMIZED)
+	  {
+	    /* Adjust so that the bottom or right doesn't move if it's
+	     * the top or left that's being changed */
+	    RECT rect;
+	    GetWindowRect (hwnd, &rect);
+
+	    if (rect.left != wp->x)
+	      wp->x += wp->cx - pixwidth;
+	    if (rect.top != wp->y)
+	      wp->y += wp->cy - pixheight;
+	  }
+
+	wp->cx = pixwidth;
+	wp->cy = pixheight;
+      }
+    }
+    break;
+
+  case WM_ENTERSIZEMOVE:
+    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+    msframe->sizing = 1;
+    return 0;
+
+  case WM_EXITSIZEMOVE:
+    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+    msframe->sizing = 0;
+    /* Queue noop event */
+    mswindows_enqueue_magic_event (hwnd, XM_BUMPQUEUE);
+    return 0;
+
+#ifdef HAVE_SCROLLBARS
+  case WM_VSCROLL:
+  case WM_HSCROLL:
+    {
+      /* Direction of scroll is determined by scrollbar instance. */
+      int code = (int) LOWORD(wParam);
+      int pos = (short int) HIWORD(wParam);
+      HWND hwndScrollBar = (HWND) lParam;
+      struct gcpro gcpro1, gcpro2;
+
+      mswindows_handle_scrollbar_event (hwndScrollBar, code,  pos);
+      GCPRO2 (emacs_event, fobj);
+      if (UNBOUNDP(mswindows_pump_outstanding_events()))	/* Can GC */
+	{
+	  /* Error during event pumping - cancel scroll */
+	  SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
+	}
+      UNGCPRO;
+      break;     
+    }
+#endif
+
+#ifdef HAVE_MENUBARS
+  case WM_INITMENU:
+    if (UNBOUNDP (mswindows_handle_wm_initmenu (
+			(HMENU) wParam,
+			XFRAME (mswindows_find_frame (hwnd)))))
+      SendMessage (hwnd, WM_CANCELMODE, 0, 0);
+    break;
+
+  case WM_INITMENUPOPUP:
+    if (!HIWORD(lParam))
+      {
+	if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
+			(HMENU) wParam,
+			 XFRAME (mswindows_find_frame (hwnd)))))
+	  SendMessage (hwnd, WM_CANCELMODE, 0, 0);
+      }
+    break;
+
+  case WM_EXITMENULOOP:
+    if (UNBOUNDP (mswindows_handle_wm_exitmenuloop (
+			XFRAME (mswindows_find_frame (hwnd)))))
+      SendMessage (hwnd, WM_CANCELMODE, 0, 0);
+    break;
+
+#endif /* HAVE_MENUBARS */
+
+  case WM_COMMAND:
+    {
+      WORD id = LOWORD (wParam);
+      frame = XFRAME (mswindows_find_frame (hwnd));
+
+#ifdef HAVE_MENUBARS
+      if (!NILP (mswindows_handle_wm_command (frame, id)))
+	break;
+#endif
+
+#ifdef HAVE_TOOLBARS
+      O Toolbar Implementor, this place may have something for you!;
+#endif
+
+      /* Bite me - a spurious command. No abort(), for safety */
+      /* #### Perhaps, this message should be changed */
+      error ("Cannot decode command. Tell kkm he's a parallelogramm, if you know"
+	     " what does that mean!");
+    }
+  break;
+
+  case WM_DROPFILES:	/* implementation ripped-off from event-Xt.c */
+    {
+      UINT filecount, i, len;
+      POINT point;
+      char filename[MAX_PATH];
+      Lisp_Object l_type, l_dndlist = Qnil, l_item;
+
+      emacs_event = Fmake_event (Qnil, Qnil);
+      event = XEVENT(emacs_event);
+
+      if (!DragQueryPoint ((HANDLE) wParam, &point))
+	point.x = point.y = -1;		/* outside client area */
+
+      filecount = DragQueryFile ((HANDLE) wParam, -1, NULL, 0);
+      if (filecount == 1)
+	{
+      	  l_type = make_int (DndFile);
+	  len = DragQueryFile ((HANDLE) wParam, 0, filename, MAX_PATH);
+	  l_dndlist = make_ext_string (filename, len, FORMAT_FILENAME);
+	}
+      else
+	{
+	  l_type = make_int (DndFiles);	  
+	  for (i=0; i<filecount; i++)
+	    {
+  	      len = DragQueryFile ((HANDLE) wParam, i, filename, MAX_PATH);
+	      l_item = make_ext_string (filename, len, FORMAT_FILENAME);
+	      l_dndlist = Fcons (l_item, l_dndlist);	/* reverse order */
+	    }
+	}
+      DragFinish ((HANDLE) wParam);
+      
+      event->channel = mswindows_find_frame(hwnd);
+      event->timestamp = GetMessageTime();
+      event->event_type = dnd_drop_event;
+      event->event.dnd_drop.button = 1;		/* #### Should try harder */
+      event->event.dnd_drop.modifiers = mswindows_modifier_state (NULL, 0);
+      event->event.dnd_drop.x = point.x;
+      event->event.dnd_drop.y = point.y;
+      event->event.dnd_drop.data = Fcons (l_type, Fcons (l_dndlist, Qnil));
+
+      mswindows_enqueue_dispatch_event (emacs_event);
+    }
+  break;
+
+  defproc:
+  default:
+    return DefWindowProc (hwnd, message, wParam, lParam);
+  }
+  return (0);
+}
+
+
+/************************************************************************/
+/*      keyboard, mouse & other helpers for the windows procedure       */
+/************************************************************************/
+static void
+mswindows_set_chord_timer (HWND hwnd)
+{
+  int interval;
+
+  /* We get half system threshold as it seems to
+     long before drag-selection is shown */
+  if (mswindows_button2_chord_time <= 0)
+    interval = GetDoubleClickTime () / 2;
+  else
+    interval = mswindows_button2_chord_time;
+
+  SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
+}
+
+static int
+mswindows_button2_near_enough (POINTS p1, POINTS p2)
+{
+  int dx, dy;
+  if (mswindows_button2_max_skew_x <= 0)
+    dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
+  else
+    dx = mswindows_button2_max_skew_x;
+
+  if (mswindows_button2_max_skew_y <= 0)
+    dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
+  else
+    dy = mswindows_button2_max_skew_y;
+
+  return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
+}
+
+static int
+mswindows_current_layout_has_AltGr (void)
+{
+  /* This simple caching mechanism saves 10% of CPU
+     time when a key typed at autorepeat rate of 30 cps! */
+  static HKL last_hkl = 0;
+  static int last_hkl_has_AltGr;
+
+  HKL current_hkl = GetKeyboardLayout (0);
+  if (current_hkl != last_hkl)
+    {
+      TCHAR c;
+      last_hkl_has_AltGr = 0;
+      /* In this loop, we query whether a character requires
+	 AltGr to be down to generate it. If at least such one
+	 found, this means that the layout does regard AltGr */
+      for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
+	if (HIBYTE (VkKeyScan (c)) == 6)
+	  last_hkl_has_AltGr = 1;
+      last_hkl = current_hkl;
+    }
+  return last_hkl_has_AltGr;
+}
+
+
+/* Returns the state of the modifier keys in the format expected by the
+ * Lisp_Event key_data, button_data and motion_data modifiers member */
+int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
+{
+  int mods = 0;
+
+  if (keymap == NULL)
+    {
+      keymap = (BYTE*) alloca(256);
+      GetKeyboardState (keymap);
+      has_AltGr = mswindows_current_layout_has_AltGr ();
+    }
+
+  if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
+    {
+      mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
+      mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
+    }
+  else
+    {
+      mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
+      mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
+    }
+
+  mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
+
+  return mods;
+}
+
+/*
+ * Translate a mswindows virtual key to a keysym.
+ * Only returns non-Qnil for keys that don't generate WM_CHAR messages
+ * or whose ASCII codes (like space) xemacs doesn't like.
+ * Virtual key values are defined in winresrc.h
+ * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
+ */
+Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods)
+{
+  switch (mswindows_key)
+  {
+  /* First the predefined ones */
+  case VK_BACK:		return QKbackspace;
+  case VK_TAB:		return QKtab;
+  case '\n':		return QKlinefeed;  /* No VK_LINEFEED in winresrc.h */
+  case VK_RETURN:	return QKreturn;
+  case VK_ESCAPE:	return QKescape;
+  case VK_SPACE:	return QKspace;
+  case VK_DELETE:	return QKdelete;
+
+  /* The rest */
+  case VK_CLEAR:	return KEYSYM ("clear");  /* Should do ^L ? */
+  case VK_PRIOR:	return KEYSYM ("prior");
+  case VK_NEXT:		return KEYSYM ("next");
+  case VK_END:		return KEYSYM ("end");
+  case VK_HOME:		return KEYSYM ("home");
+  case VK_LEFT:		return KEYSYM ("left");
+  case VK_UP:		return KEYSYM ("up");
+  case VK_RIGHT:	return KEYSYM ("right");
+  case VK_DOWN:		return KEYSYM ("down");
+  case VK_SELECT:	return KEYSYM ("select");
+  case VK_PRINT:	return KEYSYM ("print");
+  case VK_EXECUTE:	return KEYSYM ("execute");
+  case VK_SNAPSHOT:	return KEYSYM ("print");
+  case VK_INSERT:	return KEYSYM ("insert");
+  case VK_HELP:		return KEYSYM ("help");
+#if 0	/* XXX What are these supposed to do? */
+  case VK_LWIN		return KEYSYM ("");
+  case VK_RWIN		return KEYSYM ("");
+#endif
+  case VK_APPS:		return KEYSYM ("menu");
+  case VK_F1:		return KEYSYM ("f1");
+  case VK_F2:		return KEYSYM ("f2");
+  case VK_F3:		return KEYSYM ("f3");
+  case VK_F4:		return KEYSYM ("f4");
+  case VK_F5:		return KEYSYM ("f5");
+  case VK_F6:		return KEYSYM ("f6");
+  case VK_F7:		return KEYSYM ("f7");
+  case VK_F8:		return KEYSYM ("f8");
+  case VK_F9:		return KEYSYM ("f9");
+  case VK_F10:		return KEYSYM ("f10");
+  case VK_F11:		return KEYSYM ("f11");
+  case VK_F12:		return KEYSYM ("f12");
+  case VK_F13:		return KEYSYM ("f13");
+  case VK_F14:		return KEYSYM ("f14");
+  case VK_F15:		return KEYSYM ("f15");
+  case VK_F16:		return KEYSYM ("f16");
+  case VK_F17:		return KEYSYM ("f17");
+  case VK_F18:		return KEYSYM ("f18");
+  case VK_F19:		return KEYSYM ("f19");
+  case VK_F20:		return KEYSYM ("f20");
+  case VK_F21:		return KEYSYM ("f21");
+  case VK_F22:		return KEYSYM ("f22");
+  case VK_F23:		return KEYSYM ("f23");
+  case VK_F24:		return KEYSYM ("f24");
+  }
+  return Qnil;
+}
+
+/*
+ * Find the console that matches the supplied mswindows window handle
+ */
+Lisp_Object
+mswindows_find_console (HWND hwnd)
+{
+  Lisp_Object concons;
+
+  CONSOLE_LOOP (concons)
+    {
+      Lisp_Object console = XCAR (concons);
+      /* We only support one console so this must be it */
+      return console;
+    }
+
+  return Qnil;
+}
+
+/*
+ * Find the frame that matches the supplied mswindows window handle
+ */
+static Lisp_Object
+mswindows_find_frame (HWND hwnd)
+{
+  return (Lisp_Object) GetWindowLong (hwnd, XWL_FRAMEOBJ);
+}
+
+
 
 /************************************************************************/
 /*                            methods                                   */
   if (milliseconds < 1)
     milliseconds = 1;
   ++mswindows_pending_timers_count;
-  return SetTimer (NULL, 0, milliseconds, mswindows_wm_timer_callback);
+  return SetTimer (NULL, 0, milliseconds,
+		   (TIMERPROC) mswindows_wm_timer_callback);
 }
 
 static void
 static void
 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
 {
-#if 0  
-  stderr_out("magic %x, (%d,%d), (%d,%d)\n",
-	     EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event),
-	     rect->left, rect->top, rect->right, rect->bottom);
-#endif
   switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
   {
   case WM_SETFOCUS:
     }
     break;
 			    
-      /* XXX What about Enter & Leave */
+      /* #### What about Enter & Leave */
 #if 0
       va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
 			     Qmouse_leave_frame_hook, 1, frame);

File src/event-msw.h

-/* mswindows-specific defines for event-handling.
-   Copyright (C) 1997 Jonathan Harris.
-
-This file is part of XEmacs.
-
-XEmacs is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
-later version.
-
-XEmacs is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with XEmacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-/* Synched up with: Not in FSF. */
-
-/* Authorship:
-
-   Jonathan Harris, November 1997 for 20.4.