update.
[chise/xemacs-chise.git.1] / src / event-msw.c
index 4745a66..2b41016 100644 (file)
@@ -93,7 +93,7 @@ typedef unsigned int SOCKET;
 /* Timer ID used for button2 emulation */
 #define BUTTON_2_TIMER_ID 1
 
-static Lisp_Object mswindows_find_frame (HWND hwnd);
+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,
                                                  int extendedp);
@@ -186,7 +186,7 @@ static DWORD mswindows_last_mouse_button_state;
    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
+   notepad process exits also, because it inherits the pipe from the
    shell. In this case, we abandon the thread, and let it live until
    all such processes exit. While struct ntpipe_slurp_stream is
    deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
@@ -232,6 +232,7 @@ slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
       CloseHandle (s->hev_thread);
       CloseHandle (s->hev_caller);
       CloseHandle (s->hev_unsleep);
+      CloseHandle (s->hpipe);
       s->inuse_p = 0;
     }
 }
@@ -811,7 +812,7 @@ winsock_closer (Lstream *lstr)
   else
     shutdown (str->s, 1);
 
-  CloseHandle ((HANDLE)str->s);
+  closesocket (str->s);
   if (str->pending_p)
     WaitForSingleObject (str->ov.hEvent, INFINITE);
 
@@ -980,6 +981,9 @@ mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where,
   int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN ||
               msg == WM_RBUTTONDOWN);
 
+  /* Wheel rotation amount: positive is away from user, negative towards user */
+  int delta = (short) HIWORD (mods);
+  
   /* We always use last message time, because mouse button
      events may get delayed, and XEmacs double click
      recognition will fail */
@@ -992,7 +996,9 @@ mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where,
   event->timestamp = when;
   event->event.button.button =
     (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
-    ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2);
+    (msg==WM_MBUTTONDOWN || msg==WM_MBUTTONUP) ? 2 :
+    (msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 :
+    (msg==WM_MOUSEWHEEL && delta>0) ? 4 : 5;
   event->event.button.x = where.x;
   event->event.button.y = where.y;
   event->event.button.modifiers = mswindows_modifier_state (NULL, mods, 0);
@@ -1068,7 +1074,7 @@ mswindows_dequeue_dispatch_event (void)
  * 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
  * event in the queue and that of the given event is non-zero.
- * For all other event types, this function aborts.
+ * For all other event types, this function ABORTs.
  */
 
 Lisp_Object
@@ -1148,6 +1154,21 @@ remove_waitable_handle (HANDLE h)
 }
 #endif /* HAVE_MSG_SELECT */
 
+/*
+ * Given a lisp process pointer remove the corresponding process handle
+ * from mswindows_waitable_handles if it is in it.  Normally the handle is
+ * removed when the process terminates, but if the lisp process structure
+ * is deleted before the process terminates we must delete the process
+ * handle since it will be invalid and will cause the wait to fail
+ */
+void
+mswindows_unwait_process (Lisp_Process *p)
+{
+#ifndef HAVE_MSG_SELECT
+  remove_waitable_handle (get_nt_process_handle (p));
+#endif /* HAVE_MSG_SELECT */
+}
+
 \f
 /************************************************************************/
 /*                             Event pump                               */
@@ -1493,6 +1514,8 @@ mswindows_need_event (int badly_p)
 #else
       /* Now try getting a message or process event */
       DWORD what_events;
+      MSG msg;
+
       if (mswindows_in_modal_loop)
        /* In a modal loop, only look for timer events, and only if
           we really need one. */
@@ -1506,10 +1529,23 @@ mswindows_need_event (int badly_p)
        /* Look for any event */
        what_events = QS_ALLINPUT;
 
-      active = MsgWaitForMultipleObjects (mswindows_waitable_count,
-                                         mswindows_waitable_handles,
-                                         FALSE, badly_p ? INFINITE : 0,
-                                         what_events);
+      /* This fixes a long outstanding bug, where XEmacs would occasionally
+       * not redraw its window (or process other events) until "something
+       * happened" - usually the mouse moving over a frame.
+       *
+       * The problem is that MsgWaitForMultipleObjects only checks to see
+       * if NEW messages have been placed into the thread queue. So we
+       * specifically check to see if the queue is empty (using PeekMessage
+       * with the PM_NOREMOVE flag) before we wait.
+       */
+      if (what_events == QS_ALLINPUT && badly_p &&
+         PeekMessage (&msg, 0, 0, 0, PM_NOREMOVE))
+       active = WAIT_OBJECT_0 + mswindows_waitable_count;
+      else
+       active = MsgWaitForMultipleObjects (mswindows_waitable_count,
+                                           mswindows_waitable_handles,
+                                           FALSE, badly_p ? INFINITE : 0,
+                                           what_events);
 
       /* This will assert if handle being waited for becomes abandoned.
         Not the case currently tho */
@@ -1525,10 +1561,10 @@ mswindows_need_event (int badly_p)
       else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
        {
          /* Got your message, thanks */
-         if (mswindows_in_modal_loop)
-           mswindows_need_event_in_modal_loop (badly_p);
-         else
-           mswindows_drain_windows_queue ();
+         if (mswindows_in_modal_loop)
+           mswindows_need_event_in_modal_loop (badly_p);
+         else
+           mswindows_drain_windows_queue ();
        }
       else
        {
@@ -1610,6 +1646,8 @@ mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
  * depends on dnd support.
  */
 #ifdef HAVE_DRAGNDROP
+extern int mswindows_dde_enable;
+
 HDDEDATA CALLBACK
 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
                        HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
@@ -1636,6 +1674,9 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
       return (HDDEDATA)NULL;
 
     case XTYP_EXECUTE:
+      if (!mswindows_dde_enable)
+       return (HDDEDATA) DDE_FBUSY;
+
       if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
        {
          DWORD len = DdeGetData (hdata, NULL, 0, 0);
@@ -1643,7 +1684,7 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
          char *end;
          char *filename;
          struct gcpro gcpro1, gcpro2;
-          Lisp_Object l_dndlist = Qnil;
+         Lisp_Object l_dndlist = Qnil;
          Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
          Lisp_Object frmcons, devcons, concons;
          Lisp_Event *event = XEVENT (emacs_event);
@@ -2064,17 +2105,9 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
   struct frame *frame;
   struct mswindows_frame* msframe;
 
-  /* Not perfect but avoids crashes. There is potential for wierd
-     behavior here. */
-  if (gc_in_progress)
-    {
-      mswindows_output_console_string ("Window procedure called during GC???????\n", 41);
-      /* Yes, this assert always triggers in a --debug XEmacs.  But
-        --debug=no is default in the stable branches.
-         #### How about patch in <200106081225.IAA31075@gwyn.tux.org>? */
-      assert (!gc_in_progress);
-      goto defproc;
-    }
+  /* If you hit this, rewrite the offending API call to occur after GC,
+     using register_post_gc_action(). */
+  assert (!gc_in_progress);
 
 #ifdef DEBUG_XEMACS
   if (debug_mswindows_events)
@@ -2621,6 +2654,70 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
       mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
       break;
 
+    case WM_ACTIVATE:
+      {
+        /*
+         * If we receive a WM_ACTIVATE message that indicates that our frame
+         * is being activated, make sure that the frame is marked visible
+         * if the window itself is visible. This seems to fix the problem
+         * where XEmacs appears to lock-up after switching desktops with
+         * some virtual window managers.
+         */
+        int state = (int)(short) LOWORD(wParam);
+#ifdef DEBUG_XEMACS
+        if (debug_mswindows_events)
+          stderr_out("state = %d\n", state);
+#endif /* DEBUG_XEMACS */
+        if (state == WA_ACTIVE || state == WA_CLICKACTIVE)
+          {
+#ifdef DEBUG_XEMACS
+            if (debug_mswindows_events)
+              stderr_out("  activating\n");
+#endif /* DEBUG_XEMACS */
+            
+            fobj = mswindows_find_frame (hwnd);
+            frame = XFRAME (fobj);
+            if (IsWindowVisible (hwnd))
+              {
+#ifdef DEBUG_XEMACS
+                if (debug_mswindows_events)
+                  stderr_out("  window is visible\n");
+#endif /* DEBUG_XEMACS */
+                if (!FRAME_VISIBLE_P (frame))
+                  {
+#ifdef DEBUG_XEMACS
+                    if (debug_mswindows_events)
+                      stderr_out("  frame is not visible\n");
+#endif /* DEBUG_XEMACS */
+                    /*
+                     * It seems that we have to enqueue the XM_MAPFRAME event
+                     * prior to setting the frame visible so that
+                     * suspend-or-iconify-emacs works properly.
+                     */
+                    mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
+                    FRAME_VISIBLE_P (frame) = 1;
+                    FRAME_ICONIFIED_P (frame) = 0;
+                  }
+#ifdef DEBUG_XEMACS
+                else
+                  {
+                    if (debug_mswindows_events)
+                      stderr_out("  frame is visible\n");
+                  }
+#endif /* DEBUG_XEMACS */
+              }
+#ifdef DEBUG_XEMACS
+            else
+              {     
+                if (debug_mswindows_events)
+                  stderr_out("  window is not visible\n");
+              }
+#endif /* DEBUG_XEMACS */
+          }
+       return DefWindowProc (hwnd, message_, wParam, lParam);
+      }
+      break;
+      
     case WM_WINDOWPOSCHANGED:
       /* This is sent before WM_SIZE; in fact, the processing of this
         by DefWindowProc() sends WM_SIZE.  But WM_SIZE is not sent when
@@ -2636,7 +2733,11 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
          }
        else if (IsWindowVisible (hwnd))
          {
-           FRAME_VISIBLE_P (frame) = 1;
+           /* APA: It's too early here to set the frame visible.
+            * Let's do this later, in WM_SIZE processing, after the
+            * magic XM_MAPFRAME event has been sent (just like 21.1
+            * did). */
+           /* FRAME_VISIBLE_P (frame) = 1; */
            FRAME_ICONIFIED_P (frame) = 0;
          }
        else
@@ -2648,6 +2749,30 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
        return DefWindowProc (hwnd, message_, wParam, lParam);
       }
 
+    case WM_SHOWWINDOW:
+      /*
+         The WM_SHOWWINDOW message is sent to a window when the window
+         is about to be hidden or shown.
+         APA: This message is also sent when switching to a virtual
+         desktop under the virtuawin virtual window manager.
+      
+      */
+      {
+       fobj = mswindows_find_frame (hwnd);
+       frame = XFRAME (fobj);
+        if (wParam == TRUE)
+          {
+            mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
+            FRAME_VISIBLE_P (frame) = 1;
+          }
+        else
+          {
+            mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
+            FRAME_VISIBLE_P (frame) = 0;
+          }
+      }
+      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)
@@ -2700,7 +2825,13 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
              else
                {
                  if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
-                   mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
+                    {
+                      mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
+                      /* APA: Now that the magic XM_MAPFRAME event has
+                       * been sent we can mark the frame as visible (just
+                       * like 21.1 did). */
+                      FRAME_VISIBLE_P (frame) = 1;
+                    }
 
                  if (!msframe->sizing || mswindows_dynamic_frame_resize)
                    redisplay ();
@@ -2823,19 +2954,19 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
       {
        int keys = LOWORD (wParam); /* Modifier key flags */
        int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
-       struct gcpro gcpro1, gcpro2;
 
-       if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd),
+        /* enqueue button4/5 events if mswindows_handle_mousewheel_event
+           doesn't handle the event, such as when the scrollbars are not
+           displayed */
+       if (!mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd),
                                               keys, delta,
                                               MAKEPOINTS (lParam)))
-         {
-           GCPRO2 (emacs_event, fobj);
-           mswindows_pump_outstanding_events ();       /* Can GC */
-           UNGCPRO;
-         }
-       else
-         goto defproc;
-       break;
+          mswindows_enqueue_mouse_button_event (hwnd, message_,
+                                                MAKEPOINTS (lParam),
+                                                wParam,
+                                                GetMessageTime());
+        /* We are not in a modal loop so no pumping is necessary. */
+        break;
       }
 #endif
 
@@ -3279,7 +3410,7 @@ mswindows_find_console (HWND hwnd)
 /*
  * Find the frame that matches the supplied mswindows window handle
  */
-static Lisp_Object
+Lisp_Object
 mswindows_find_frame (HWND hwnd)
 {
   LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
@@ -3744,7 +3875,7 @@ FROB (WM_SETHOTKEY)
 FROB (WM_GETHOTKEY)
 FROB (WM_QUERYDRAGICON)
 FROB (WM_COMPAREITEM)
-#if(WINVER >= 0x0500)
+#if(WINVER >= 0x0500) && defined(WM_GETOBJECT)
 FROB (WM_GETOBJECT)
 #endif /* WINVER >= 0x0500 */
 FROB (WM_COMPACTING)
@@ -3781,7 +3912,9 @@ FROB (WM_NCHITTEST)
 FROB (WM_NCPAINT)
 FROB (WM_NCACTIVATE)
 FROB (WM_GETDLGCODE)
+#ifdef WM_SYNCPAINT /* not in VC 5 */
 FROB (WM_SYNCPAINT)
+#endif /* WM_SYNCPAINT */
 FROB (WM_NCMOUSEMOVE)
 FROB (WM_NCLBUTTONDOWN)
 FROB (WM_NCLBUTTONUP)
@@ -3804,12 +3937,12 @@ FROB (WM_SYSCHAR)
 FROB (WM_SYSDEADCHAR)
 FROB (WM_KEYLAST)
 
-#if(WINVER >= 0x0400) && !defined(CYGWIN)
+#if(WINVER >= 0x0400) && defined (WM_IME_STARTCOMPOSITION)
 FROB (WM_IME_STARTCOMPOSITION)
 FROB (WM_IME_ENDCOMPOSITION)
 FROB (WM_IME_COMPOSITION)
 FROB (WM_IME_KEYLAST)
-#endif /* WINVER >= 0x0400 */
+#endif /* WINVER >= 0x0400 && defined (WM_IME_STARTCOMPOSITION) */
 
 FROB (WM_INITDIALOG)
 FROB (WM_COMMAND)
@@ -3824,10 +3957,18 @@ FROB (WM_MENUCHAR)
 FROB (WM_ENTERIDLE)
 #if(WINVER >= 0x0500)
 FROB (WM_MENURBUTTONUP)
+#ifdef WM_MENUDRAG
 FROB (WM_MENUDRAG)
+#endif
+#ifdef WM_MENUGETOBJECT
 FROB (WM_MENUGETOBJECT)
+#endif
+#ifdef WM_UNINITMENUPOPUP
 FROB (WM_UNINITMENUPOPUP)
+#endif
+#ifdef WM_MENUCOMMAND
 FROB (WM_MENUCOMMAND)
+#endif
 #endif /* WINVER >= 0x0500 */
 
 
@@ -3893,6 +4034,7 @@ FROB (WM_EXITSIZEMOVE)
 FROB (WM_DROPFILES)
 FROB (WM_MDIREFRESHMENU)
 
+#ifdef WM_IME_SETCONTEXT /* not in Cygwin? */
 
 #if(WINVER >= 0x0400) && !defined(CYGWIN)
 FROB (WM_IME_SETCONTEXT)
@@ -3902,7 +4044,7 @@ FROB (WM_IME_COMPOSITIONFULL)
 FROB (WM_IME_SELECT)
 FROB (WM_IME_CHAR)
 #endif /* WINVER >= 0x0400 */
-#if(WINVER >= 0x0500)
+#if(WINVER >= 0x0500) && defined(WM_IME_REQUEST)
 FROB (WM_IME_REQUEST)
 #endif /* WINVER >= 0x0500 */
 #if(WINVER >= 0x0400) && !defined(CYGWIN)
@@ -3910,6 +4052,7 @@ FROB (WM_IME_KEYDOWN)
 FROB (WM_IME_KEYUP)
 #endif /* WINVER >= 0x0400 */
 
+#endif /* WM_IME_SETCONTEXT */
 
 #if(_WIN32_WINNT >= 0x0400)
 FROB (WM_MOUSEHOVER)
@@ -3981,6 +4124,25 @@ debug_output_mswin_message (HWND hwnd, UINT message_, WPARAM wParam,
       stderr_out (" wparam=%d lparam=%d hwnd=%x frame: ",
                  wParam, (int) lParam, (unsigned int) hwnd);
       debug_print (frame);
+      if (message_ == WM_WINDOWPOSCHANGED ||
+          message_ == WM_WINDOWPOSCHANGING)
+        {
+          WINDOWPOS *wp = (WINDOWPOS *) lParam;
+          stderr_out("  WINDOWPOS: x=%d, y=%d, h=%d, w=%d\n",
+                     wp->x, wp->y, wp->cx, wp->cy);
+        }
+      else if (message_ == WM_MOVE)
+        {
+          int x = (int)(short) LOWORD(lParam);   /* horizontal position */
+          int y = (int)(short) HIWORD(lParam);   /* vertical position */
+          stderr_out("  MOVE: x=%d, y=%d\n", x, y);
+        }
+      else if (message_ == WM_SIZE)
+        {
+          int w = (int)(short) LOWORD(lParam);   /* width */
+          int h = (int)(short) HIWORD(lParam);   /* height */
+          stderr_out("  SIZE: w=%d, h=%d\n", w, h);
+        }
     }
   else
     stderr_out ("\n");