]> git.eshelyaron.com Git - emacs.git/commitdiff
Support daemon mode on MS-Windows (bug#19688)
authorMark Laws <mdl@60hz.org>
Fri, 27 Feb 2015 10:43:30 +0000 (12:43 +0200)
committerEli Zaretskii <eliz@gnu.org>
Fri, 27 Feb 2015 10:43:30 +0000 (12:43 +0200)
 src/emacs.c <w32_daemon_event> [WINDOWSNT]: New global var.
 (main) [WINDOWSNT]: Initialize it to NULL.  Create the event to
 signal clients we are ready for connections.
 (Fdaemon_initialized): Use DAEMON_RUNNING.
 [WINDOWSNT]: MS-Windows specific code to signal clients we are
 ready for connections.
 src/lisp.h (DAEMON_RUNNING): New macro, encapsulates Posix and
 MS-Windows conditions for running in daemon mode.
 src/minibuf.c (read_minibuf): Use DAEMON_RUNNING.
 src/keyboard.c (kbd_buffer_get_event): Use DAEMON_RUNNING.
 src/dispnew.c (init_display) [WINDOWSNT]: Initialize frames/terminal
 even in daemon mode.

 nt/inc/ms-w32.h (W32_DAEMON_EVENT): New macro.

 lib-src/emacsclient.c (decode_options) [WINDOWSNT]: Don't reject empty
 arguments for --alternate-editor.
 (print_help_and_exit) [WINDOWSNT]: Don't refrain from advertising
 empty arguments for --alternate-editor.
 (start_daemon_and_retry_set_socket) [WINDOWSNT]: MS-Windows
 specific code to start Emacs in daemon mode and wait for it to be
 ready for client connections.

 lisp/server.el (server-process-filter): Force GUI frames on
 MS-Windows in daemon mode, even if a TTY frame was requested.
 lisp/frameset.el (frameset-keep-original-display-p): Don't assume
 windows-nt cannot be in daemon mode.
 lisp/frame.el (window-system-for-display): Don't assume windows-nt
 cannot be in daemon mode.

14 files changed:
lib-src/ChangeLog
lib-src/emacsclient.c
lisp/ChangeLog
lisp/frame.el
lisp/frameset.el
lisp/server.el
nt/ChangeLog
nt/inc/ms-w32.h
src/ChangeLog
src/dispnew.c
src/emacs.c
src/keyboard.c
src/lisp.h
src/minibuf.c

index 5c55bcea506ceb1efae1f3461301aa048f5529f2..83855afa675e48e832364dd17e2802fbe9d2afe5 100644 (file)
@@ -1,3 +1,14 @@
+2015-02-27  Mark Laws  <mdl@60hz.org>
+
+       Support daemon mode on MS-Windows (bug#19688)
+       * emacsclient.c (decode_options) [WINDOWSNT]: Don't reject empty
+       arguments for --alternate-editor.
+       (print_help_and_exit) [WINDOWSNT]: Don't refrain from advertising
+       empty arguments for --alternate-editor.
+       (start_daemon_and_retry_set_socket) [WINDOWSNT]: MS-Windows
+       specific code to start Emacs in daemon mode and wait for it to be
+       ready for client connections.
+
 2015-02-23  Pete Williamson  <petewil0@googlemail.com>  (tiny change)
 
        Use ${EXEEXT} more uniformly in makefiles
index a04dda6408f520a201a180b0ff3d10c1284c36c2..806275f5b1d90fb8fb038cbfa1a22c5cab238ab0 100644 (file)
@@ -595,13 +595,6 @@ decode_options (int argc, char **argv)
       display = NULL;
       tty = 1;
     }
-
-  if (alternate_editor && alternate_editor[0] == '\0')
-    {
-      message (true, "--alternate-editor argument or ALTERNATE_EDITOR variable cannot be\n\
-an empty string");
-      exit (EXIT_FAILURE);
-    }
 #endif /* WINDOWSNT */
 }
 
@@ -642,10 +635,8 @@ The following OPTIONS are accepted:\n\
                        Set filename of the TCP authentication file\n\
 -a EDITOR, --alternate-editor=EDITOR\n\
                        Editor to fallback to if the server is not running\n"
-#ifndef WINDOWSNT
 "                      If EDITOR is the empty string, start Emacs in daemon\n\
                        mode and try connecting again\n"
-#endif /* not WINDOWSNT */
 "\n\
 Report bugs with M-x report-emacs-bug.\n");
   exit (EXIT_SUCCESS);
@@ -1511,7 +1502,77 @@ start_daemon_and_retry_set_socket (void)
       execvp ("emacs", d_argv);
       message (true, "%s: error starting emacs daemon\n", progname);
     }
-#endif /* WINDOWSNT */
+#else  /* WINDOWSNT */
+  DWORD wait_result;
+  HANDLE w32_daemon_event;
+  STARTUPINFO si;
+  PROCESS_INFORMATION pi;
+
+  ZeroMemory (&si, sizeof si);
+  si.cb = sizeof si;
+  ZeroMemory (&pi, sizeof pi);
+
+  /* We start Emacs in daemon mode, and then wait for it to signal us
+     it is ready to accept client connections, by asserting an event
+     whose name is known to the daemon (defined by nt/inc/ms-w32.h).  */
+
+  if (!CreateProcess (NULL, "emacs --daemon", NULL, NULL, FALSE,
+                      CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
+    {
+      char* msg = NULL;
+
+      FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
+                    | FORMAT_MESSAGE_ALLOCATE_BUFFER
+                    | FORMAT_MESSAGE_ARGUMENT_ARRAY,
+                    NULL, GetLastError (), 0, (LPTSTR)&msg, 0, NULL);
+      message (true, "%s: error starting emacs daemon (%s)\n", progname, msg);
+      exit (EXIT_FAILURE);
+    }
+
+  w32_daemon_event = CreateEvent (NULL, TRUE, FALSE, W32_DAEMON_EVENT);
+  if (w32_daemon_event == NULL)
+    {
+      message (true, "Couldn't create Windows daemon event");
+      exit (EXIT_FAILURE);
+    }
+  if ((wait_result = WaitForSingleObject (w32_daemon_event, INFINITE))
+      != WAIT_OBJECT_0)
+    {
+      char *msg = NULL;
+
+      switch (wait_result)
+       {
+       case WAIT_ABANDONED:
+         msg = "The daemon exited unexpectedly";
+         break;
+       case WAIT_TIMEOUT:
+         /* Can't happen due to INFINITE.  */
+       default:
+       case WAIT_FAILED:
+         FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
+                        | FORMAT_MESSAGE_ALLOCATE_BUFFER
+                        | FORMAT_MESSAGE_ARGUMENT_ARRAY,
+                        NULL, GetLastError (), 0, (LPTSTR)&msg, 0, NULL);
+         break;
+       }
+      message (true, "Error: Could not start the Emacs daemon: %s\n", msg);
+      exit (EXIT_FAILURE);
+    }
+  CloseHandle (w32_daemon_event);
+
+  /* Try connecting, the daemon should have started by now.  */
+  /* It's just a progress message, so don't pop a dialog if this is
+     emacsclientw.  */
+  if (!w32_window_app ())
+    message (true,
+            "Emacs daemon should have started, trying to connect again\n");
+  if ((emacs_socket = set_socket (1)) == INVALID_SOCKET)
+    {
+      message (true,
+              "Error: Cannot connect even after starting the Emacs daemon\n");
+      exit (EXIT_FAILURE);
+    }
+#endif /* WINDOWSNT */
 }
 
 int
index e9f62365f038bcf29a331ed99144cb4966647b05..b9681d35cf0b00b4b471ce41750e81e0f914112d 100644 (file)
@@ -1,3 +1,15 @@
+2015-02-27  Mark Laws  <mdl@60hz.org>
+
+       Support daemon mode on MS-Windows (bug#19688)
+       * server.el (server-process-filter): Force GUI frames on
+       MS-Windows in daemon mode, even if a TTY frame was requested.
+
+       * frameset.el (frameset-keep-original-display-p): Don't assume
+       windows-nt cannot be in daemon mode.
+
+       * frame.el (window-system-for-display): Don't assume windows-nt
+       cannot be in daemon mode.
+
 2015-02-26  Ivan Shmakov  <ivan@siamics.net>
 
        * faces.el (face-list-p): Split from face-at-point.
index 0096ef9696a722cf33005e6963e0c955d3fed9a5..c81ee9bfa615773adccd2b727fae422cdd15f10c 100644 (file)
@@ -546,7 +546,8 @@ is not considered (see `next-frame')."
 Return nil if we don't know how to interpret DISPLAY."
   ;; MS-Windows doesn't know how to create a GUI frame in a -nw session.
   (if (and (eq system-type 'windows-nt)
-          (null (window-system)))
+          (null (window-system))
+          (not (daemonp)))
       nil
     (cl-loop for descriptor in display-format-alist
             for pattern = (car descriptor)
index 4a0637439dbc71141964aba1ea32020cf466d731..17fe39be8448bc5f8362580139f4a0cee0d3c29c 100644 (file)
@@ -1022,8 +1022,8 @@ Internal use only."
 (defun frameset-keep-original-display-p (force-display)
   "True if saved frames' displays should be honored.
 For the meaning of FORCE-DISPLAY, see `frameset-restore'."
-  (cond ((daemonp) t)
-       ((eq system-type 'windows-nt) nil) ;; Does ns support more than one display?
+  (cond ((eq system-type 'windows-nt) nil) ;; Does ns support more than one display?
+       ((daemonp) t)
        (t (not force-display))))
 
 (defun frameset-minibufferless-first-p (frame1 _frame2)
index 166cd44bb2ea79818d7ed0cbb069eadfed8fc6ef..9585b1755c6bc93a3801e3e50588df1159371ecb 100644 (file)
@@ -1139,9 +1139,12 @@ The following commands are accepted by the client:
                  ;; frame.  If running a GUI server, force the frame
                  ;; type to GUI.  (Cygwin is perfectly happy with
                  ;; multi-tty support, so don't override the user's
-                 ;; choice there.)
+                 ;; choice there.)  In daemon mode on Windows, we can't
+                 ;; make tty frames, so force the frame type to GUI
+                 ;; there too.
                  (when (and (eq system-type 'windows-nt)
-                            (eq window-system 'w32))
+                            (or (daemonp)
+                                (eq window-system 'w32)))
                    (push "-window-system" args-left)))
 
                 ;; -position LINE[:COLUMN]:  Set point to the given
@@ -1215,7 +1218,10 @@ The following commands are accepted by the client:
                                           terminal-frame)))))
                    (setq tty-name nil tty-type nil)
                    (if display (server-select-display display)))
-                  ((eq tty-name 'window-system)
+                  ((or (and (eq system-type 'windows-nt)
+                            (daemonp)
+                            (setq display "w32"))
+                       (eq tty-name 'window-system))
                    (server-create-window-system-frame display nowait proc
                                                       parent-id
                                                       frame-parameters))
index b9966fb27d8cbf57f1f4798f4df949d12b2b54e2..240f58c850b07f008dd007a3ea77ad6cd8a29a9a 100644 (file)
@@ -1,3 +1,8 @@
+2015-02-27  Mark Laws  <mdl@60hz.org>
+
+       Support daemon mode on MS-Windows (bug#19688)
+       * inc/ms-w32.h (W32_DAEMON_EVENT): New macro.
+
 2015-01-16  Eli Zaretskii  <eliz@gnu.org>
 
        * Makefile.in (AM_V_CC, am__v_CC_, am__v_CC_0, am__v_CC_1)
index adac2e3b4a1563eea83541df6bd92f773f20affb..c06ed588818239f94314ad9878bcd0daab513be9 100644 (file)
@@ -597,5 +597,7 @@ extern void _DebPrint (const char *fmt, ...);
 #endif
 #endif
 
+/* Event name for when emacsclient starts the Emacs daemon on Windows.  */
+#define W32_DAEMON_EVENT "EmacsServerEvent"
 
 /* ============================================================ */
index bf4043666c65417323154db6c7d99ec5c88aabe3..61bb321649f08458d0030127b03872305bd84db8 100644 (file)
@@ -1,3 +1,23 @@
+2015-02-27  Mark Laws  <mdl@60hz.org>
+
+       Support daemon mode on MS-Windows (bug#19688)
+       * emacs.c <w32_daemon_event> [WINDOWSNT]: New global var.
+       (main) [WINDOWSNT]: Initialize it to NULL.  Create the event to
+       signal clients we are ready for connections.
+       (Fdaemon_initialized): Use DAEMON_RUNNING.
+       [WINDOWSNT]: MS-Windows specific code to signal clients we are
+       ready for connections.
+
+       * lisp.h (DAEMON_RUNNING): New macro, encapsulates Posix and
+       MS-Windows conditions for running in daemon mode.
+
+       * minibuf.c (read_minibuf): Use DAEMON_RUNNING.
+
+       * keyboard.c (kbd_buffer_get_event): Use DAEMON_RUNNING.
+
+       * dispnew.c (init_display) [WINDOWSNT]: Initialize frames/terminal
+       even in daemon mode.
+
 2015-02-26  Jan Djärv  <jan.h.d@swipnet.se>
 
        * xmenu.c (create_and_show_popup_menu): Call XTranslateCoordinates,
index a1782913154ab451a395b7b7e1e29056948e27d5..6bc24697cb7de7056de687a026d1ca40057ca5ad 100644 (file)
@@ -5949,9 +5949,12 @@ init_display (void)
     }
 #endif /* SIGWINCH */
 
-  /* If running as a daemon, no need to initialize any frames/terminal. */
+  /* If running as a daemon, no need to initialize any frames/terminal,
+     except on Windows, where we at least want to initialize it.  */
+#ifndef WINDOWSNT
   if (IS_DAEMON)
       return;
+#endif
 
   /* If the user wants to use a window system, we shouldn't bother
      initializing the terminal.  This is especially important when the
index cb0c8417794f82f3ed4aa544084b98ebb4322cfa..ca5633da2ddace894b4e39375446a32fc29e4cd0 100644 (file)
@@ -195,9 +195,13 @@ bool no_site_lisp;
 /* Name for the server started by the daemon.*/
 static char *daemon_name;
 
+#ifndef WINDOWSNT
 /* Pipe used to send exit notification to the daemon parent at
    startup.  */
 int daemon_pipe[2];
+#else
+HANDLE w32_daemon_event;
+#endif
 
 /* Save argv and argc.  */
 char **initial_argv;
@@ -982,8 +986,12 @@ main (int argc, char **argv)
       exit (0);
     }
 
+#ifndef WINDOWSNT
   /* Make sure IS_DAEMON starts up as false.  */
   daemon_pipe[1] = 0;
+#else
+  w32_daemon_event = NULL;
+#endif
 
   if (argmatch (argv, argc, "-daemon", "--daemon", 5, NULL, &skip_args)
       || argmatch (argv, argc, "-daemon", "--daemon", 5, &dname_arg, &skip_args))
@@ -1107,16 +1115,25 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
       }
 #endif /* DAEMON_MUST_EXEC */
 
-      if (dname_arg)
-               daemon_name = xstrdup (dname_arg);
       /* Close unused reading end of the pipe.  */
       emacs_close (daemon_pipe[0]);
 
       setsid ();
-#else /* DOS_NT */
+#elif defined(WINDOWSNT)
+      /* Indicate that we want daemon mode.  */
+      w32_daemon_event = CreateEvent (NULL, TRUE, FALSE, W32_DAEMON_EVENT);
+      if (w32_daemon_event == NULL)
+        {
+          fprintf (stderr, "Couldn't create MS-Windows event for daemon: %s\n",
+                  w32_strerror (0));
+          exit (1);
+        }
+#else /* MSDOS */
       fprintf (stderr, "This platform does not support the -daemon flag.\n");
       exit (1);
-#endif /* DOS_NT */
+#endif /* MSDOS */
+      if (dname_arg)
+       daemon_name = xstrdup (dname_arg);
     }
 
 #if defined HAVE_PTHREAD && !defined SYSTEM_MALLOC \
@@ -2313,17 +2330,18 @@ This finishes the daemonization process by doing the other half of detaching
 from the parent process and its tty file descriptors.  */)
   (void)
 {
-  int nfd;
   bool err = 0;
 
   if (!IS_DAEMON)
     error ("This function can only be called if emacs is run as a daemon");
 
-  if (daemon_pipe[1] < 0)
+  if (!DAEMON_RUNNING)
     error ("The daemon has already been initialized");
 
   if (NILP (Vafter_init_time))
     error ("This function can only be called after loading the init files");
+#ifndef WINDOWSNT
+  int nfd;
 
   /* Get rid of stdin, stdout and stderr.  */
   nfd = emacs_open ("/dev/null", O_RDWR, 0);
@@ -2344,6 +2362,13 @@ from the parent process and its tty file descriptors.  */)
   err |= emacs_close (daemon_pipe[1]) != 0;
   /* Set it to an invalid value so we know we've already run this function.  */
   daemon_pipe[1] = -1;
+#else  /* WINDOWSNT */
+  /* Signal the waiting emacsclient process.  */
+  err |= SetEvent (w32_daemon_event) == 0;
+  err |= CloseHandle (w32_daemon_event) == 0;
+  /* Set it to an invalid value so we know we've already run this function.  */
+  w32_daemon_event = INVALID_HANDLE_VALUE;
+#endif
 
   if (err)
     error ("I/O error during daemon initialization");
index c2174539ea747a96e969aa2a63e19aebad4e53a8..e1c5691324d767797742fb9746f2f6629f66e92e 100644 (file)
@@ -3853,7 +3853,7 @@ kbd_buffer_get_event (KBOARD **kbp,
   if (noninteractive
       /* In case we are running as a daemon, only do this before
         detaching from the terminal.  */
-      || (IS_DAEMON && daemon_pipe[1] >= 0))
+      || (IS_DAEMON && DAEMON_RUNNING))
     {
       int c = getchar ();
       XSETINT (obj, c);
index 9764b096ef02b33a4fcb4b705fec7f344581621c..fb4367761214ca7750309e65f58f06b52a4a54af 100644 (file)
@@ -4222,9 +4222,16 @@ extern bool noninteractive;
 extern bool no_site_lisp;
 
 /* Pipe used to send exit notification to the daemon parent at
-   startup.  */
+   startup.  On Windows, we use a kernel event instead.  */
+#ifndef WINDOWSNT
 extern int daemon_pipe[2];
 #define IS_DAEMON (daemon_pipe[1] != 0)
+#define DAEMON_RUNNING (daemon_pipe[1] >= 0)
+#else  /* WINDOWSNT */
+extern void *w32_daemon_event;
+#define IS_DAEMON (w32_daemon_event != NULL)
+#define DAEMON_RUNNING (w32_daemon_event != INVALID_HANDLE_VALUE)
+#endif
 
 /* True if handling a fatal error already.  */
 extern bool fatal_error_in_progress;
index 2dc5c544457cfcfcf7f630ac5d190d3bd9307d1d..e7c288b251be965295128ce793ecb1748c77f9a8 100644 (file)
@@ -459,7 +459,7 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt,
   if ((noninteractive
        /* In case we are running as a daemon, only do this before
          detaching from the terminal.  */
-       || (IS_DAEMON && (daemon_pipe[1] >= 0)))
+       || (IS_DAEMON && DAEMON_RUNNING))
       && NILP (Vexecuting_kbd_macro))
     {
       val = read_minibuf_noninteractive (map, initial, prompt,