XEmacs 21.2.19 "Shinjuku".
[chise/xemacs-chise.git.1] / src / event-msw.c
index f31da31..45e77ee 100644 (file)
@@ -28,6 +28,7 @@ Boston, MA 02111-1307, USA.  */
    Ultimately based on FSF.
    Rewritten by Ben Wing.
    Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
    Ultimately based on FSF.
    Rewritten by Ben Wing.
    Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
+   Subprocess and modal loop support by Kirill M. Katsnelson.
  */
 
 #include <config.h>
  */
 
 #include <config.h>
@@ -50,6 +51,8 @@ Boston, MA 02111-1307, USA.  */
 #include "device.h"
 #include "events.h"
 #include "frame.h"
 #include "device.h"
 #include "events.h"
 #include "frame.h"
+#include "buffer.h"
+#include "faces.h"
 #include "lstream.h"
 #include "process.h"
 #include "redisplay.h"
 #include "lstream.h"
 #include "process.h"
 #include "redisplay.h"
@@ -57,16 +60,22 @@ Boston, MA 02111-1307, USA.  */
 #include "syswait.h"
 #include "systime.h"
 #include "sysdep.h"
 #include "syswait.h"
 #include "systime.h"
 #include "sysdep.h"
+#include "objects-msw.h"
 
 #include "events-mod.h"
 #ifdef HAVE_MSG_SELECT
 #include "sysfile.h"
 
 #include "events-mod.h"
 #ifdef HAVE_MSG_SELECT
 #include "sysfile.h"
+#include "console-tty.h"
 #elif defined(__CYGWIN32__)
 typedef unsigned int SOCKET;
 #endif
 #include <io.h>
 #include <errno.h>
 
 #elif defined(__CYGWIN32__)
 typedef unsigned int SOCKET;
 #endif
 #include <io.h>
 #include <errno.h>
 
+#if defined (__CYGWIN32__) && !defined (CYGWIN_VERSION_DLL_MAJOR)
+typedef NMHDR *LPNMHDR;
+#endif
+
 #ifdef HAVE_MENUBARS
 #define ADJR_MENUFLAG TRUE
 #else
 #ifdef HAVE_MENUBARS
 #define ADJR_MENUFLAG TRUE
 #else
@@ -84,6 +93,8 @@ extern Lisp_Object
 mswindows_get_toolbar_button_text (struct frame* f, int command_id);
 extern Lisp_Object
 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id);
 mswindows_get_toolbar_button_text (struct frame* f, int command_id);
 extern Lisp_Object
 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id);
+extern Lisp_Object
+mswindows_handle_gui_wm_command (struct frame* f, HWND ctrl, WORD id);
 
 static Lisp_Object mswindows_find_frame (HWND hwnd);
 static Lisp_Object mswindows_find_console (HWND hwnd);
 
 static Lisp_Object mswindows_find_frame (HWND hwnd);
 static Lisp_Object mswindows_find_console (HWND hwnd);
@@ -115,11 +126,16 @@ static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_
 /* The number of things we can wait on */
 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
 
 /* The number of things we can wait on */
 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
 
+#ifndef HAVE_MSG_SELECT
 /* List of mswindows waitable handles. */
 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
 
 /* Number of wait handles */
 static int mswindows_waitable_count=0;
 /* List of mswindows waitable handles. */
 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
 
 /* Number of wait handles */
 static int mswindows_waitable_count=0;
+#endif /* HAVE_MSG_SELECT */
+/* Brush for painting widgets */
+static HBRUSH widget_brush = 0;
+static LONG    last_widget_brushed = 0;
 
 /* Count of quit chars currently in the queue */
 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
 
 /* Count of quit chars currently in the queue */
 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
@@ -155,7 +171,7 @@ static int mswindows_pending_timers_count;
 /* This structure is allocated by the main thread, and is deallocated
    in the thread upon exit.  There are situations when a thread
    remains blocked for a long time, much longer than the lstream
 /* This structure is allocated by the main thread, and is deallocated
    in the thread upon exit.  There are situations when a thread
    remains blocked for a long time, much longer than the lstream
-   exists. For exmaple, "start notepad" command is issued from the
+   exists. For example, "start notepad" command is issued from the
    shell, then the shell is closed by C-c C-d. Although the shell
    process exits, its output pipe will not get closed until the
    notepad process exits also, because it inherits the pipe form the
    shell, then the shell is closed by C-c C-d. Although the shell
    process exits, its output pipe will not get closed until the
    notepad process exits also, because it inherits the pipe form the
@@ -194,7 +210,7 @@ DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
                               sizeof (struct ntpipe_slurp_stream));
 
 /* This function is thread-safe, and is called from either thread
                               sizeof (struct ntpipe_slurp_stream));
 
 /* This function is thread-safe, and is called from either thread
-   context. It serializes freeing shared dtata structure */
+   context. It serializes freeing shared data structure */
 static void
 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
 {
 static void
 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
 {
@@ -268,7 +284,7 @@ slurp_thread (LPVOID vparam)
       if (s->die_p)
        break;
 
       if (s->die_p)
        break;
 
-      /* Block until the client finishes with retireving the rest of
+      /* Block until the client finishes with retrieving the rest of
         pipe data */
       WaitForSingleObject (s->hev_thread, INFINITE);
     }
         pipe data */
       WaitForSingleObject (s->hev_thread, INFINITE);
     }
@@ -470,6 +486,7 @@ struct ntpipe_shove_stream
 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
                               sizeof (struct ntpipe_shove_stream));
 
 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
                               sizeof (struct ntpipe_shove_stream));
 
+#ifndef HAVE_MSG_SELECT
 static DWORD WINAPI
 shove_thread (LPVOID vparam)
 {
 static DWORD WINAPI
 shove_thread (LPVOID vparam)
 {
@@ -541,6 +558,7 @@ get_ntpipe_output_stream_param (Lstream *stream)
   struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
   return s->user_data;
 }
   struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
   return s->user_data;
 }
+#endif
 
 static int
 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
 
 static int
 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
@@ -619,7 +637,7 @@ struct winsock_stream
   OVERLAPPED ov;               /* Overlapped I/O structure                  */
   void* buffer;                        /* Buffer. Allocated for input stream only   */
   unsigned int bufsize;                /* Number of bytes last read                 */
   OVERLAPPED ov;               /* Overlapped I/O structure                  */
   void* buffer;                        /* Buffer. Allocated for input stream only   */
   unsigned int bufsize;                /* Number of bytes last read                 */
-  unsigned int bufpos;         /* Psition in buffer for next fetch          */
+  unsigned int bufpos;         /* Position in buffer for next fetch         */
   unsigned int error_p :1;     /* I/O Error seen                            */
   unsigned int eof_p :1;       /* EOF Error seen                            */
   unsigned int pending_p :1;   /* There is a pending I/O operation          */
   unsigned int error_p :1;     /* I/O Error seen                            */
   unsigned int eof_p :1;       /* EOF Error seen                            */
   unsigned int pending_p :1;   /* There is a pending I/O operation          */
@@ -939,6 +957,13 @@ mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWO
     {
       event->event_type = button_press_event;
       SetCapture (hwnd);
     {
       event->event_type = button_press_event;
       SetCapture (hwnd);
+      /* we need this to make sure the main window regains the focus
+         from control subwindows */
+      if (GetFocus() != hwnd)
+       {
+         SetFocus (hwnd);
+         mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
+       }
     }
   else
     {
     }
   else
     {
@@ -997,18 +1022,18 @@ mswindows_dequeue_dispatch_event ()
 
 /*
  * Remove and return the first emacs event on the dispatch queue that matches
 
 /*
  * Remove and return the first emacs event on the dispatch queue that matches
- * the supplied event
- * Timeout event matches if interval_id equals to that of the given event.
+ * the supplied event.
+ * Timeout event matches if interval_id is equal to that of the given event.
  * Keypress event matches if logical AND between modifiers bitmask of the
  * Keypress event matches if logical AND between modifiers bitmask of the
- * event in the queue and that of the given event is non-zero
- * For all other event types, this function asserts.
+ * event in the queue and that of the given event is non-zero.
+ * For all other event types, this function aborts.
  */
 
 Lisp_Object
  */
 
 Lisp_Object
-mswindows_cancel_dispatch_event (struct Lisp_Event* match)
+mswindows_cancel_dispatch_event (struct Lisp_Event *match)
 {
   Lisp_Object event;
 {
   Lisp_Object event;
-  Lisp_Object previous_event=Qnil;
+  Lisp_Object previous_event = Qnil;
   int user_p = mswindows_user_event_p (match);
   Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue : 
                               &mswindows_s_dispatch_event_queue;
   int user_p = mswindows_user_event_p (match);
   Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue : 
                               &mswindows_s_dispatch_event_queue;
@@ -1020,19 +1045,12 @@ mswindows_cancel_dispatch_event (struct Lisp_Event* match)
 
   EVENT_CHAIN_LOOP (event, *head)
     {
 
   EVENT_CHAIN_LOOP (event, *head)
     {
-      int found = 1;
-      if (XEVENT_TYPE (event) != match->event_type)
-       found = 0;
-      if (found && match->event_type == timeout_event
-         && (XEVENT(event)->event.timeout.interval_id !=
-             match->event.timeout.interval_id))
-       found = 0;
-      if (found && match->event_type == key_press_event
-         && ((XEVENT(event)->event.key.modifiers &
-             match->event.key.modifiers) == 0))
-       found = 0;
-
-      if (found)
+      struct Lisp_Event *e = XEVENT (event);
+      if ((e->event_type == match->event_type) &&
+         ((e->event_type == timeout_event) ?
+          (e->event.timeout.interval_id == match->event.timeout.interval_id) :
+          /* Must be key_press_event */
+          ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
        {
          if (NILP (previous_event))
            dequeue_event (head, tail);
        {
          if (NILP (previous_event))
            dequeue_event (head, tail);
@@ -1050,6 +1068,7 @@ mswindows_cancel_dispatch_event (struct Lisp_Event* match)
   return Qnil;
 }
 \f
   return Qnil;
 }
 \f
+#ifndef HAVE_MSG_SELECT
 /************************************************************************/
 /*                     Waitable handles manipulation                    */
 /************************************************************************/
 /************************************************************************/
 /*                     Waitable handles manipulation                    */
 /************************************************************************/
@@ -1085,6 +1104,7 @@ remove_waitable_handle (HANDLE h)
   mswindows_waitable_handles [ix] = 
     mswindows_waitable_handles [--mswindows_waitable_count];
 }
   mswindows_waitable_handles [ix] = 
     mswindows_waitable_handles [--mswindows_waitable_count];
 }
+#endif /* HAVE_MSG_SELECT */
 
 \f
 /************************************************************************/
 
 \f
 /************************************************************************/
@@ -1168,7 +1188,7 @@ mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
  * neither are waitable handles checked. The function pumps
  * thus only dispatch events already queued, as well as those
  * resulted in dispatching thereof. This is done by setting
  * neither are waitable handles checked. The function pumps
  * thus only dispatch events already queued, as well as those
  * resulted in dispatching thereof. This is done by setting
- * module local variable mswidows_in_modal_loop to nonzero.
+ * module local variable mswindows_in_modal_loop to nonzero.
  *
  * Return value is Qt if no errors was trapped, or Qunbound if
  * there was an error.
  *
  * Return value is Qt if no errors was trapped, or Qunbound if
  * there was an error.
@@ -1186,7 +1206,7 @@ mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
  * If the value of mswindows_error_caught_in_modal_loop is not
  * nil already upon entry, the function just returns non-nil.
  * This situation means that a new event has been queued while
  * If the value of mswindows_error_caught_in_modal_loop is not
  * nil already upon entry, the function just returns non-nil.
  * This situation means that a new event has been queued while
- * cancleng mode. The event will be dequeued on the next regular
+ * in cancel mode. The event will be dequeued on the next regular
  * call of next-event; the pump is off since error is caught.
  * The caller must *unconditionally* cancel modal loop if the
  * value returned by this function is nil. Otherwise, everything
  * call of next-event; the pump is off since error is caught.
  * The caller must *unconditionally* cancel modal loop if the
  * value returned by this function is nil. Otherwise, everything
@@ -1214,16 +1234,24 @@ mswindows_drain_windows_queue ()
   MSG msg;
   while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
     {
   MSG msg;
   while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
     {
+      /* we have to translate messages that are not sent to the main
+         window. this is so that key presses work ok in things like
+         edit fields. however, we *musn't* translate message for the
+         main window as this is handled in the wnd proc. */
+      if ( GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD )
+       {
+         TranslateMessage (&msg);
+       }
       DispatchMessage (&msg);
       mswindows_unmodalize_signal_maybe ();
     }
 }
 
 /* 
       DispatchMessage (&msg);
       mswindows_unmodalize_signal_maybe ();
     }
 }
 
 /* 
- * This is a special flavour of the mswindows_need_event function,
+ * This is a special flavor of the mswindows_need_event function,
  * used while in event pump. Actually, there is only kind of events
  * allowed while in event pump: a timer.  An attempt to fetch any
  * used while in event pump. Actually, there is only kind of events
  * allowed while in event pump: a timer.  An attempt to fetch any
- * other event leads to a dealock, as there's no source of user input
+ * other event leads to a deadlock, as there's no source of user input
  * ('cause event pump mirrors windows modal loop, which is a sole
  * owner of thread message queue).
  *
  * ('cause event pump mirrors windows modal loop, which is a sole
  * owner of thread message queue).
  *
@@ -1299,32 +1327,11 @@ mswindows_need_event (int badly_p)
          pointer_to_this = &select_time_to_block;
        }
 
          pointer_to_this = &select_time_to_block;
        }
 
-      /* select() is slow and buggy so if we don't have any processes
-         just wait as normal */
-      if (memcmp (&process_only_mask, &zero_mask, sizeof(SELECT_TYPE))==0)
-       {
-         /* Now try getting a message or process event */
-         active = MsgWaitForMultipleObjects (0, mswindows_waitable_handles,
-                                             FALSE, badly_p ? INFINITE : 0,
-                                             QS_ALLINPUT);
-         
-         if (active == WAIT_TIMEOUT)
-           {
-             /* No luck trying - just return what we've already got */
-             return;
-           }
-         else if (active == WAIT_OBJECT_0)
-           {
-             /* Got your message, thanks */
-             mswindows_drain_windows_queue ();
-             continue;
-           }
-       }
-
       active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
       
       if (active == 0)
        {
       active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
       
       if (active == 0)
        {
+         assert (!badly_p);
          return;               /* timeout */
        }
       else if (active > 0)
          return;               /* timeout */
        }
       else if (active > 0)
@@ -1333,7 +1340,28 @@ mswindows_need_event (int badly_p)
            {
              mswindows_drain_windows_queue ();
            }
            {
              mswindows_drain_windows_queue ();
            }
-         
+#ifdef HAVE_TTY          
+         /* Look for a TTY event */
+         for (i = 0; i < MAXDESC-1; i++)
+           {
+             /* To avoid race conditions (among other things, an infinite
+                loop when called from Fdiscard_input()), we must return
+                user events ahead of process events. */
+             if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
+               {
+                 struct console *c = tty_find_console_from_fd (i);
+                 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
+                 struct Lisp_Event* event = XEVENT (emacs_event);
+                 
+                 assert (c);
+                 if (read_event_from_tty_or_stream_desc (event, c, i))
+                   {
+                     mswindows_enqueue_dispatch_event (emacs_event);
+                     return;
+                   }
+               }
+           }
+#endif
          /* Look for a process event */
          for (i = 0; i < MAXDESC-1; i++)
            {
          /* Look for a process event */
          for (i = 0; i < MAXDESC-1; i++)
            {
@@ -1346,11 +1374,6 @@ mswindows_need_event (int badly_p)
                      
                      mswindows_enqueue_process_event (p);
                    }
                      
                      mswindows_enqueue_process_event (p);
                    }
-                 else if (FD_ISSET (i, &tty_only_mask))
-                   {
-                               /* do we care about tty events? Do we
-                                   ever get tty events? */
-                   }
                  else
                    {
                      /* We might get here when a fake event came
                  else
                    {
                      /* We might get here when a fake event came
@@ -1367,7 +1390,7 @@ mswindows_need_event (int badly_p)
        {
          if (errno != EINTR)
            {
        {
          if (errno != EINTR)
            {
-             /* something bad happended */
+             /* something bad happened */
              assert(0);
            }
        }
              assert(0);
            }
        }
@@ -1401,7 +1424,7 @@ mswindows_need_event (int badly_p)
     else
       {
        int ix = active - WAIT_OBJECT_0;
     else
       {
        int ix = active - WAIT_OBJECT_0;
-       /* First, try to find which process' ouptut has signaled */
+       /* First, try to find which process' output has signaled */
        struct Lisp_Process *p = 
          get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
        if (p != NULL)
        struct Lisp_Process *p = 
          get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
        if (p != NULL)
@@ -1412,7 +1435,7 @@ mswindows_need_event (int badly_p)
        else
          {
            /* None. This means that the process handle itself has signaled.
        else
          {
            /* None. This means that the process handle itself has signaled.
-              Remove the handle from the wait vector, and make status_ntoify
+              Remove the handle from the wait vector, and make status_notify
               note the exited process */
            mswindows_waitable_handles [ix] =
              mswindows_waitable_handles [--mswindows_waitable_count];
               note the exited process */
            mswindows_waitable_handles [ix] =
              mswindows_waitable_handles [--mswindows_waitable_count];
@@ -1446,6 +1469,8 @@ mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
   event->timestamp = dwtime;
   event->event_type = timeout_event;
   event->event.timeout.interval_id = id_timer;
   event->timestamp = dwtime;
   event->event_type = timeout_event;
   event->event.timeout.interval_id = id_timer;
+  event->event.timeout.function = Qnil;
+  event->event.timeout.object = Qnil;
 
   mswindows_enqueue_dispatch_event (emacs_event);
 }
 
   mswindows_enqueue_dispatch_event (emacs_event);
 }
@@ -1576,7 +1601,7 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
 LRESULT WINAPI
 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
 LRESULT WINAPI
 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
-  /* Note: Remember to initialise emacs_event and event before use.
+  /* Note: Remember to initialize 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;
      This code calls code that can GC. You must GCPRO before calling such code. */
   Lisp_Object emacs_event = Qnil;
   Lisp_Object fobj = Qnil;
@@ -1646,7 +1671,15 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        {
          int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
          BYTE keymap_orig[256];
        {
          int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
          BYTE keymap_orig[256];
-         MSG msg = { hwnd, message, wParam, lParam, GetMessageTime(), (GetMessagePos()) };
+         POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
+         MSG msg;
+         
+         msg.hwnd = hwnd;
+         msg.message = message;
+         msg.wParam = wParam;
+         msg.lParam = lParam;
+         msg.time = GetMessageTime();
+         msg.pt = pnt;
 
          /* GetKeyboardState() does not work as documented on Win95. We have
           * to loosely track Left and Right modifiers on behalf of the OS,
 
          /* GetKeyboardState() does not work as documented on Win95. We have
           * to loosely track Left and Right modifiers on behalf of the OS,
@@ -1860,13 +1893,13 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     break;
 
   case WM_MOUSEMOVE:
     break;
 
   case WM_MOUSEMOVE:
-    /* Optimization: don't report mouse movement while size is changind */
+    /* Optimization: don't report mouse movement while size is changing */
     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
     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 */
+        as if timer has expired. This improves drag-select feedback */
       if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
          && !mswindows_button2_near_enough (msframe->last_click_point,
                                             MAKEPOINTS (lParam)))
       if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
          && !mswindows_button2_near_enough (msframe->last_click_point,
                                             MAKEPOINTS (lParam)))
@@ -1897,17 +1930,20 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
                                       Qcancel_mode_internal, Qnil);
     break;
 
                                       Qcancel_mode_internal, Qnil);
     break;
 
-#ifdef HAVE_TOOLBARS
   case WM_NOTIFY:
     {
   case WM_NOTIFY:
     {
-      LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
-      Lisp_Object btext;
-      if (tttext->hdr.code ==  TTN_NEEDTEXT)    
+      LPNMHDR nmhdr = (LPNMHDR)lParam;
+
+      if (nmhdr->code ==  TTN_NEEDTEXT)
        {
        {
+#ifdef HAVE_TOOLBARS
+         LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
+         Lisp_Object btext;
+
          /* find out which toolbar */
          frame = XFRAME (mswindows_find_frame (hwnd));
          btext = mswindows_get_toolbar_button_text ( frame, 
          /* find out which toolbar */
          frame = XFRAME (mswindows_find_frame (hwnd));
          btext = mswindows_get_toolbar_button_text ( frame, 
-                                                     tttext->hdr.idFrom );
+                                                     nmhdr->idFrom );
          
          tttext->lpszText = NULL;
          tttext->hinst = NULL;
          
          tttext->lpszText = NULL;
          tttext->hinst = NULL;
@@ -1916,15 +1952,33 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
            {
              /* I think this is safe since the text will only go away
                  when the toolbar does...*/
            {
              /* I think this is safe since the text will only go away
                  when the toolbar does...*/
-             tttext->lpszText=XSTRING_DATA (btext);
+             GET_C_STRING_EXT_DATA_ALLOCA (btext, FORMAT_OS, 
+                                           tttext->lpszText);
            }
            }
-#if 0
-         tttext->uFlags |= TTF_DI_SETITEM;
 #endif
 #endif
-       }    
+       }
+      /* handle tree view callbacks */
+      else if (nmhdr->code == TVN_SELCHANGED)
+       {
+         NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
+         frame = XFRAME (mswindows_find_frame (hwnd));
+         mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
+       }
+      /* handle tab control callbacks */
+      else if (nmhdr->code == TCN_SELCHANGE)
+       {
+         TC_ITEM item;
+         int index = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
+         frame = XFRAME (mswindows_find_frame (hwnd));
+
+         item.mask = TCIF_PARAM;
+         SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)index,
+                      (LPARAM)&item);
+         
+         mswindows_handle_gui_wm_command (frame, 0, item.lParam);
+       }
     }
     break;
     }
     break;
-#endif
     
   case WM_PAINT:
     {
     
   case WM_PAINT:
     {
@@ -2113,6 +2167,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_COMMAND:
     {
       WORD id = LOWORD (wParam);
   case WM_COMMAND:
     {
       WORD id = LOWORD (wParam);
+      WORD nid = HIWORD (wParam);
       HWND cid = (HWND)lParam;
       frame = XFRAME (mswindows_find_frame (hwnd));
 
       HWND cid = (HWND)lParam;
       frame = XFRAME (mswindows_find_frame (hwnd));
 
@@ -2120,17 +2175,85 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
        break;
 #endif
       if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
        break;
 #endif
-
+      /* widgets in a buffer only eval a callback for suitable events.*/
+      switch (nid)
+       {
+       case BN_CLICKED:
+       case EN_CHANGE:
+       case CBN_EDITCHANGE:
+       case CBN_SELCHANGE:
+         if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
+           return 0;
+       }
+      /* menubars always must come last since the hashtables do not
+         always exist*/
 #ifdef HAVE_MENUBARS
       if (!NILP (mswindows_handle_wm_command (frame, id)))
        break;
 #endif
 
 #ifdef HAVE_MENUBARS
       if (!NILP (mswindows_handle_wm_command (frame, id)))
        break;
 #endif
 
-      /* Bite me - a spurious command. This cannot happen. */
-      error ("XEMACS BUG: Cannot decode command message");
+      return DefWindowProc (hwnd, message, wParam, lParam);
+      /* Bite me - a spurious command. This used to not be able to
+         happen but with the introduction of widgets its now
+         possible. */
     }
   break;
 
     }
   break;
 
+  case WM_CTLCOLORBTN:
+  case WM_CTLCOLORLISTBOX:
+  case WM_CTLCOLOREDIT:
+  case WM_CTLCOLORSTATIC:
+  case WM_CTLCOLORSCROLLBAR:
+    {
+      /* if we get an opportunity to paint a widget then do so if
+         there is an appropriate face */
+      HWND crtlwnd = (HWND)lParam;
+      LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
+      if (ii)
+       {
+         Lisp_Object image_instance;
+         VOID_TO_LISP (image_instance, ii);
+         if (IMAGE_INSTANCEP (image_instance)
+             && 
+             IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)
+             &&
+             !NILP (XIMAGE_INSTANCE_WIDGET_FACE (image_instance)))
+           {
+             /* set colors for the buttons */
+             HDC hdc = (HDC)wParam;
+             if (last_widget_brushed != ii)
+               {
+                 if (widget_brush)
+                   DeleteObject (widget_brush);
+                 widget_brush = CreateSolidBrush 
+                   (COLOR_INSTANCE_MSWINDOWS_COLOR 
+                    (XCOLOR_INSTANCE 
+                     (FACE_BACKGROUND 
+                      (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
+                       XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
+               }
+             last_widget_brushed = ii;
+             SetTextColor
+               (hdc,
+                COLOR_INSTANCE_MSWINDOWS_COLOR 
+                (XCOLOR_INSTANCE 
+                 (FACE_FOREGROUND 
+                  (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
+                   XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
+             SetBkMode (hdc, OPAQUE);
+             SetBkColor
+               (hdc,
+                COLOR_INSTANCE_MSWINDOWS_COLOR 
+                (XCOLOR_INSTANCE 
+                 (FACE_BACKGROUND 
+                  (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
+                   XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
+             return (LRESULT)widget_brush;
+           }
+       }
+    }
+    goto defproc;
+
 #ifdef HAVE_DRAGNDROP
   case WM_DROPFILES:   /* implementation ripped-off from event-Xt.c */
     {
 #ifdef HAVE_DRAGNDROP
   case WM_DROPFILES:   /* implementation ripped-off from event-Xt.c */
     {
@@ -2454,7 +2577,7 @@ emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
 
   mswindows_need_event (1);
 
 
   mswindows_need_event (1);
 
-  event = mswindows_dequeue_dispatch_event (!NILP(mswindows_u_dispatch_event_queue));
+  event = mswindows_dequeue_dispatch_event ();
   XSETEVENT (event2, emacs_event);
   Fcopy_event (event, event2);
   Fdeallocate_event (event);
   XSETEVENT (event2, emacs_event);
   Fcopy_event (event, event2);
   Fdeallocate_event (event);
@@ -2516,6 +2639,7 @@ emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
     }
 }
 
     }
 }
 
+#ifndef HAVE_MSG_SELECT
 static HANDLE
 get_process_input_waitable (struct Lisp_Process *process)
 {
 static HANDLE
 get_process_input_waitable (struct Lisp_Process *process)
 {
@@ -2565,28 +2689,47 @@ emacs_mswindows_unselect_process (struct Lisp_Process *process)
   HANDLE hev = get_process_input_waitable (process);
   remove_waitable_handle (hev);
 }
   HANDLE hev = get_process_input_waitable (process);
   remove_waitable_handle (hev);
 }
+#endif /* HAVE_MSG_SELECT */
 
 static void
 emacs_mswindows_select_console (struct console *con)
 {
 
 static void
 emacs_mswindows_select_console (struct console *con)
 {
+#ifdef HAVE_MSG_SELECT
+  if (CONSOLE_MSWINDOWS_P (con))
+    return; /* mswindows consoles are automatically selected */
+
+  event_stream_unixoid_select_console (con);
+#endif
 }
 
 static void
 emacs_mswindows_unselect_console (struct console *con)
 {
 }
 
 static void
 emacs_mswindows_unselect_console (struct console *con)
 {
+#ifdef HAVE_MSG_SELECT
+  if (CONSOLE_MSWINDOWS_P (con))
+    return; /* mswindows consoles are automatically selected */
+
+  event_stream_unixoid_unselect_console (con);
+#endif
 }
 
 static void
 emacs_mswindows_quit_p (void)
 {
 }
 
 static void
 emacs_mswindows_quit_p (void)
 {
+  MSG msg;
+
   /* Quit cannot happen in modal loop: all program
      input is dedicated to Windows. */
   if (mswindows_in_modal_loop)
     return;
 
   /* Quit cannot happen in modal loop: all program
      input is dedicated to Windows. */
   if (mswindows_in_modal_loop)
     return;
 
-  /* Drain windows queue. This sets up number of quit
-     characters in in the queue */
-  mswindows_drain_windows_queue ();
+  /* Drain windows queue. This sets up number of quit characters in the queue
+   * (and also processes wm focus change, move, resize, etc messages).
+   * We don't want to process WM_PAINT messages because this function can be
+   * called from almost anywhere and the windows' states may be changing. */
+  while (PeekMessage (&msg, NULL, 0, WM_PAINT-1, PM_REMOVE) ||
+        PeekMessage (&msg, NULL, WM_PAINT+1, WM_USER-1, PM_REMOVE))
+      DispatchMessage (&msg);
 
   if (mswindows_quit_chars_count > 0)
     {
 
   if (mswindows_quit_chars_count > 0)
     {
@@ -2802,7 +2945,7 @@ Number of physical mouse buttons.
 
   DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
 *Maximum horizontal distance in pixels between points in which left and
 
   DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
 *Maximum horizontal distance in pixels between points in which left and
-right button clicks occured for them to be translated into single
+right button clicks occurred for them to be translated into single
 middle button event. Clicks must occur in time not longer than defined
 by the variable `mswindows-mouse-button-tolerance'.
 If negative or zero, currently set system default is used instead.
 middle button event. Clicks must occur in time not longer than defined
 by the variable `mswindows-mouse-button-tolerance'.
 If negative or zero, currently set system default is used instead.
@@ -2810,7 +2953,7 @@ If negative or zero, currently set system default is used instead.
 
   DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
 *Maximum vertical distance in pixels between points in which left and
 
   DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
 *Maximum vertical distance in pixels between points in which left and
-right button clicks occured for them to be translated into single
+right button clicks occurred for them to be translated into single
 middle button event. Clicks must occur in time not longer than defined
 by the variable `mswindows-mouse-button-tolerance'.
 If negative or zero, currently set system default is used instead.
 middle button event. Clicks must occur in time not longer than defined
 by the variable `mswindows-mouse-button-tolerance'.
 If negative or zero, currently set system default is used instead.