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.
This commit is contained in:
Mark Laws 2015-02-27 12:43:30 +02:00 committed by Eli Zaretskii
parent 6ef14349fa
commit 805fe50708
14 changed files with 179 additions and 26 deletions

View 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

View 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

View 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.

View 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)

View 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)

View 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))

View 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)

View 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"
/* ============================================================ */

View 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,

View 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

View 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");

View 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);

View 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;

View 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,