summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Laws <mdl@60hz.org>2015-02-27 12:43:30 +0200
committerEli Zaretskii <eliz@gnu.org>2015-02-27 12:43:30 +0200
commit805fe507087b9675a010a30a8a8840587ffdf5be (patch)
tree9b91858096495590692d1f5fe814cb64d9712f8b
parent6ef14349fa73922473ba8202e256f20e17661b25 (diff)
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.
-rw-r--r--lib-src/ChangeLog11
-rw-r--r--lib-src/emacsclient.c81
-rw-r--r--lisp/ChangeLog12
-rw-r--r--lisp/frame.el3
-rw-r--r--lisp/frameset.el4
-rw-r--r--lisp/server.el12
-rw-r--r--nt/ChangeLog5
-rw-r--r--nt/inc/ms-w32.h2
-rw-r--r--src/ChangeLog20
-rw-r--r--src/dispnew.c5
-rw-r--r--src/emacs.c37
-rw-r--r--src/keyboard.c2
-rw-r--r--src/lisp.h9
-rw-r--r--src/minibuf.c2
14 files changed, 179 insertions, 26 deletions
diff --git a/lib-src/ChangeLog b/lib-src/ChangeLog
index 5c55bcea50..83855afa67 100644
--- a/lib-src/ChangeLog
+++ b/lib-src/ChangeLog
@@ -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
diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c
index a04dda6408..806275f5b1 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 e9f62365f0..b9681d35cf 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -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.
diff --git a/lisp/frame.el b/lisp/frame.el
index 0096ef9696..c81ee9bfa6 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 4a0637439d..17fe39be84 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 166cd44bb2..9585b1755c 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 b9966fb27d..240f58c850 100644
--- a/nt/ChangeLog
+++ b/nt/ChangeLog
@@ -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)
diff --git a/nt/inc/ms-w32.h b/nt/inc/ms-w32.h
index adac2e3b4a..c06ed58881 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 bf4043666c..61bb321649 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -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,
diff --git a/src/dispnew.c b/src/dispnew.c
index a178291315..6bc24697cb 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 cb0c841779..ca5633da2d 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 c2174539ea..e1c5691324 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 9764b096ef..fb43677612 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 2dc5c54445..e7c288b251 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,