*** empty log message ***
[bpt/emacs.git] / src / w32proc.c
index 81cdcbf..0397e16 100644 (file)
@@ -1,5 +1,5 @@
 /* Process support for GNU Emacs on the Microsoft W32 API.
-   Copyright (C) 1992, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1995, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -38,6 +38,10 @@ Boston, MA 02111-1307, USA.
 #undef kill
 
 #include <windows.h>
+#ifdef __GNUC__
+/* This definition is missing from mingw32 headers. */
+extern BOOL WINAPI IsValidLocale(LCID, DWORD);
+#endif
 
 #include "lisp.h"
 #include "w32.h"
@@ -91,10 +95,6 @@ Lisp_Object Vw32_get_true_file_attributes;
 
 Lisp_Object Qhigh, Qlow;
 
-#ifndef SYS_SIGLIST_DECLARED
-extern char *sys_siglist[];
-#endif
-
 #ifdef EMACSDEBUG
 void _DebPrint (const char *fmt, ...)
 {
@@ -308,7 +308,9 @@ create_child (char *exe, char *cmdline, char *env,
 {
   STARTUPINFO start;
   SECURITY_ATTRIBUTES sec_attrs;
+#if 0
   SECURITY_DESCRIPTOR sec_desc;
+#endif
   DWORD flags;
   char dir[ MAXPATHLEN ];
   
@@ -329,13 +331,15 @@ create_child (char *exe, char *cmdline, char *env,
   start.hStdError = GetStdHandle (STD_ERROR_HANDLE);
 #endif /* HAVE_NTGUI */
 
+#if 0
   /* Explicitly specify no security */
   if (!InitializeSecurityDescriptor (&sec_desc, SECURITY_DESCRIPTOR_REVISION))
     goto EH_Fail;
   if (!SetSecurityDescriptorDacl (&sec_desc, TRUE, NULL, FALSE))
     goto EH_Fail;
+#endif
   sec_attrs.nLength = sizeof (sec_attrs);
-  sec_attrs.lpSecurityDescriptor = &sec_desc;
+  sec_attrs.lpSecurityDescriptor = NULL /* &sec_desc */;
   sec_attrs.bInheritHandle = FALSE;
   
   strcpy (dir, process_dir);
@@ -546,13 +550,11 @@ get_result:
       else if (WIFSIGNALED (retval))
        {
          int code = WTERMSIG (retval);
-         char *signame = 0;
-         
-         if (code < NSIG)
-           {
-             /* Suppress warning if the table has const char *.  */
-             signame = (char *) sys_siglist[code];
-           }
+         char *signame;
+
+         synchronize_system_messages_locale ();
+         signame = strsignal (code);
+
          if (signame == 0)
            signame = "unknown";
 
@@ -639,7 +641,10 @@ w32_executable_type (char * filename, int * is_dos_app, int * is_cygnus_app)
            {
              char * dllname = RVA_TO_PTR (imports->Name, section, executable);
 
-             if (strcmp (dllname, "cygwin.dll") == 0)
+             /* The exact name of the cygwin dll has changed with
+                various releases, but hopefully this will be reasonably
+                future proof.  */
+             if (strncmp (dllname, "cygwin", 6) == 0)
                {
                  *is_cygnus_app = TRUE;
                  break;
@@ -653,15 +658,17 @@ unwind:
 }
 
 int
-compare_env (const char **strp1, const char **strp2)
+compare_env (const void *strp1, const void *strp2)
 {
-  const char *str1 = *strp1, *str2 = *strp2;
+  const char *str1 = *(const char **)strp1, *str2 = *(const char **)strp2;
 
   while (*str1 && *str2 && *str1 != '=' && *str2 != '=')
     {
-      if (tolower (*str1) > tolower (*str2))
+      /* Sort order in command.com/cmd.exe is based on uppercasing
+         names, so do the same here.  */
+      if (toupper (*str1) > toupper (*str2))
        return 1;
-      else if (tolower (*str1) < tolower (*str2))
+      else if (toupper (*str1) < toupper (*str2))
        return -1;
       str1++, str2++;
     }
@@ -1172,9 +1179,15 @@ count_children:
       return 0;
     }
   
-  /* Wait for input or child death to be signalled.  */
   start_time = GetTickCount ();
-  active = WaitForMultipleObjects (nh + nc, wait_hnd, FALSE, timeout_ms);
+
+  /* Wait for input or child death to be signalled.  If user input is
+     allowed, then also accept window messages.  */
+  if (FD_ISSET (0, &orfds))
+    active = MsgWaitForMultipleObjects (nh + nc, wait_hnd, FALSE, timeout_ms,
+                                       QS_ALLINPUT);
+  else
+    active = WaitForMultipleObjects (nh + nc, wait_hnd, FALSE, timeout_ms);
 
   if (active == WAIT_FAILED)
     {
@@ -1210,7 +1223,26 @@ count_children:
      processed - otherwise higher numbered channels could be starved. */
   do
     {
-      if (active >= nh)
+      if (active == nh + nc)
+       {
+         /* There are messages in the lisp thread's queue; we must
+             drain the queue now to ensure they are processed promptly,
+             because if we don't do so, we will not be woken again until
+             further messages arrive.
+
+            NB. If ever we allow window message procedures to callback
+            into lisp, we will need to ensure messages are dispatched
+            at a safe time for lisp code to be run (*), and we may also
+            want to provide some hooks in the dispatch loop to cater
+            for modeless dialogs created by lisp (ie. to register
+            window handles to pass to IsDialogMessage).
+
+            (*) Note that MsgWaitForMultipleObjects above is an
+            internal dispatch point for messages that are sent to
+            windows created by this thread.  */
+         drain_message_queue ();
+       }
+      else if (active >= nh)
        {
          cp = cps[active - nh];
 
@@ -1280,8 +1312,9 @@ count_children:
 /* Substitute for certain kill () operations */
 
 static BOOL CALLBACK
-find_child_console (HWND hwnd, child_process * cp)
+find_child_console (HWND hwnd, LPARAM arg)
 {
+  child_process * cp = (child_process *) arg;
   DWORD thread_id;
   DWORD process_id;
 
@@ -1356,25 +1389,58 @@ sys_kill (int pid, int sig)
            }
 
          foreground_window = GetForegroundWindow ();
-         if (foreground_window && SetForegroundWindow (cp->hwnd))
+         if (foreground_window)
            {
-             /* Generate keystrokes as if user had typed Ctrl-Break or
-                 Ctrl-C.  */
-             keybd_event (VK_CONTROL, control_scan_code, 0, 0);
-             keybd_event (vk_break_code, break_scan_code,
-                          (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY), 0);
-             keybd_event (vk_break_code, break_scan_code,
-                          (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY)
-                          | KEYEVENTF_KEYUP, 0);
-             keybd_event (VK_CONTROL, control_scan_code, KEYEVENTF_KEYUP, 0);
-
-             /* Sleep for a bit to give time for Emacs frame to respond
-                to focus change events (if Emacs was active app).  */
-             Sleep (10);
-
-             SetForegroundWindow (foreground_window);
-           }
-       }
+              /* NT 5.0, and apparently also Windows 98, will not allow
+                a Window to be set to foreground directly without the
+                user's involvement. The workaround is to attach
+                ourselves to the thread that owns the foreground
+                window, since that is the only thread that can set the
+                foreground window.  */
+              DWORD foreground_thread, child_thread;
+              foreground_thread =
+               GetWindowThreadProcessId (foreground_window, NULL);
+             if (foreground_thread == GetCurrentThreadId ()
+                  || !AttachThreadInput (GetCurrentThreadId (),
+                                         foreground_thread, TRUE))
+                foreground_thread = 0;
+
+              child_thread = GetWindowThreadProcessId (cp->hwnd, NULL);
+             if (child_thread == GetCurrentThreadId ()
+                  || !AttachThreadInput (GetCurrentThreadId (),
+                                         child_thread, TRUE))
+                child_thread = 0;
+
+              /* Set the foreground window to the child.  */
+              if (SetForegroundWindow (cp->hwnd))
+                {
+                  /* Generate keystrokes as if user had typed Ctrl-Break or
+                     Ctrl-C.  */
+                  keybd_event (VK_CONTROL, control_scan_code, 0, 0);
+                  keybd_event (vk_break_code, break_scan_code,
+                   (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY), 0);
+                  keybd_event (vk_break_code, break_scan_code,
+                    (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY)
+                    | KEYEVENTF_KEYUP, 0);
+                  keybd_event (VK_CONTROL, control_scan_code,
+                               KEYEVENTF_KEYUP, 0);
+
+                  /* Sleep for a bit to give time for Emacs frame to respond
+                     to focus change events (if Emacs was active app).  */
+                  Sleep (100);
+
+                  SetForegroundWindow (foreground_window);
+                }
+              /* Detach from the foreground and child threads now that
+                 the foreground switching is over.  */
+              if (foreground_thread)
+                AttachThreadInput (GetCurrentThreadId (),
+                                   foreground_thread, FALSE);
+              if (child_thread)
+                AttachThreadInput (GetCurrentThreadId (),
+                                   child_thread, FALSE);
+            }
+        }
       /* Ctrl-Break is NT equivalent of SIGINT.  */
       else if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid))
         {
@@ -2007,11 +2073,11 @@ If successful, the new layout id is returned, otherwise nil.")
   DWORD kl;
 
   CHECK_CONS (layout, 0);
-  CHECK_NUMBER (XCONS (layout)->car, 0);
-  CHECK_NUMBER (XCONS (layout)->cdr, 0);
+  CHECK_NUMBER (XCAR (layout), 0);
+  CHECK_NUMBER (XCDR (layout), 0);
 
-  kl = (XINT (XCONS (layout)->car) & 0xffff)
-    | (XINT (XCONS (layout)->cdr) << 16);
+  kl = (XINT (XCAR (layout)) & 0xffff)
+    | (XINT (XCDR (layout)) << 16);
 
   /* Synchronize layout with input thread.  */
   if (dwWindowsThreadId)