emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 805fe50: Support daemon mode on MS-Windows (bug#196


From: Eli Zaretskii
Subject: [Emacs-diffs] master 805fe50: Support daemon mode on MS-Windows (bug#19688)
Date: Fri, 27 Feb 2015 10:44:14 +0000

branch: master
commit 805fe507087b9675a010a30a8a8840587ffdf5be
Author: Mark Laws <address@hidden>
Commit: Eli Zaretskii <address@hidden>

    Support daemon mode on MS-Windows (bug#19688)
    
     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.
---
 lib-src/ChangeLog     |   11 +++++++
 lib-src/emacsclient.c |   81 +++++++++++++++++++++++++++++++++++++++++++------
 lisp/ChangeLog        |   12 +++++++
 lisp/frame.el         |    3 +-
 lisp/frameset.el      |    4 +-
 lisp/server.el        |   12 +++++--
 nt/ChangeLog          |    5 +++
 nt/inc/ms-w32.h       |    2 +
 src/ChangeLog         |   20 ++++++++++++
 src/dispnew.c         |    5 ++-
 src/emacs.c           |   37 +++++++++++++++++++----
 src/keyboard.c        |    2 +-
 src/lisp.h            |    9 +++++-
 src/minibuf.c         |    2 +-
 14 files changed, 179 insertions(+), 26 deletions(-)

diff --git a/lib-src/ChangeLog b/lib-src/ChangeLog
index 5c55bce..83855af 100644
--- a/lib-src/ChangeLog
+++ b/lib-src/ChangeLog
@@ -1,3 +1,14 @@
+2015-02-27  Mark Laws  <address@hidden>
+
+       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  <address@hidden>  (tiny change)
 
        Use ${EXEEXT} more uniformly in makefiles
diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c
index a04dda6..806275f 100644
--- a/lib-src/emacsclient.c
+++ b/lib-src/emacsclient.c
@@ -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
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index e9f6236..b9681d3 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,15 @@
+2015-02-27  Mark Laws  <address@hidden>
+
+       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  <address@hidden>
 
        * faces.el (face-list-p): Split from face-at-point.
diff --git a/lisp/frame.el b/lisp/frame.el
index 0096ef9..c81ee9b 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -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)
diff --git a/lisp/frameset.el b/lisp/frameset.el
index 4a06374..17fe39b 100644
--- a/lisp/frameset.el
+++ b/lisp/frameset.el
@@ -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)
diff --git a/lisp/server.el b/lisp/server.el
index 166cd44..9585b17 100644
--- a/lisp/server.el
+++ b/lisp/server.el
@@ -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))
diff --git a/nt/ChangeLog b/nt/ChangeLog
index b9966fb..240f58c 100644
--- a/nt/ChangeLog
+++ b/nt/ChangeLog
@@ -1,3 +1,8 @@
+2015-02-27  Mark Laws  <address@hidden>
+
+       Support daemon mode on MS-Windows (bug#19688)
+       * inc/ms-w32.h (W32_DAEMON_EVENT): New macro.
+
 2015-01-16  Eli Zaretskii  <address@hidden>
 
        * Makefile.in (AM_V_CC, am__v_CC_, am__v_CC_0, am__v_CC_1)
diff --git a/nt/inc/ms-w32.h b/nt/inc/ms-w32.h
index adac2e3..c06ed58 100644
--- a/nt/inc/ms-w32.h
+++ b/nt/inc/ms-w32.h
@@ -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"
 
 /* ============================================================ */
diff --git a/src/ChangeLog b/src/ChangeLog
index bf40436..61bb32164 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,23 @@
+2015-02-27  Mark Laws  <address@hidden>
+
+       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  <address@hidden>
 
        * xmenu.c (create_and_show_popup_menu): Call XTranslateCoordinates,
diff --git a/src/dispnew.c b/src/dispnew.c
index a178291..6bc2469 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -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
diff --git a/src/emacs.c b/src/emacs.c
index cb0c841..ca5633d 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -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");
diff --git a/src/keyboard.c b/src/keyboard.c
index c217453..e1c5691 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -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);
diff --git a/src/lisp.h b/src/lisp.h
index 9764b09..fb43677 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -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;
diff --git a/src/minibuf.c b/src/minibuf.c
index 2dc5c54..e7c288b 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -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,



reply via email to

[Prev in Thread] Current Thread [Next in Thread]