X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/d7a89815b6d69c3b1793d34bcad8bf0aa21d48c8..44517b21abc4c243cdc7df264c629d592d9fb4cf:/lib-src/emacsclient.c diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c index a04dda6408..7792d0a2c7 100644 --- a/lib-src/emacsclient.c +++ b/lib-src/emacsclient.c @@ -1,13 +1,13 @@ /* Client process that communicates with GNU Emacs acting as server. -Copyright (C) 1986-1987, 1994, 1999-2015 Free Software Foundation, Inc. +Copyright (C) 1986-1987, 1994, 1999-2016 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -39,7 +39,7 @@ along with GNU Emacs. If not, see . */ # define CLOSE_SOCKET closesocket # define INITIALIZE() (initialize_sockets ()) -char *w32_getenv (char *); +char *w32_getenv (const char *); #define egetenv(VAR) w32_getenv(VAR) #else /* !WINDOWSNT */ @@ -107,13 +107,13 @@ char *w32_getenv (char *); /* Name used to invoke this program. */ const char *progname; -/* The second argument to main. */ +/* The second argument to main. */ char **main_argv; /* Nonzero means don't wait for a response from Emacs. --no-wait. */ int nowait = 0; -/* Nonzero means don't print messages for successful operations. --quiet. */ +/* Nonzero means don't print messages for successful operations. --quiet. */ int quiet = 0; /* Nonzero means args are expressions to be evaluated. --eval. */ @@ -131,7 +131,7 @@ const char *alt_display = NULL; /* The parent window ID, if we are opening a frame via XEmbed. */ char *parent_id = NULL; -/* Nonzero means open a new Emacs frame on the current terminal. */ +/* Nonzero means open a new Emacs frame on the current terminal. */ int tty = 0; /* If non-NULL, the name of an editor to fallback to if the server @@ -148,7 +148,7 @@ const char *server_file = NULL; int emacs_pid = 0; /* If non-NULL, a string that should form a frame parameter alist to - be used for the new frame */ + be used for the new frame. */ const char *frame_parameters = NULL; static _Noreturn void print_help_and_exit (void); @@ -254,6 +254,7 @@ get_current_dir_name (void) #ifdef WINDOWSNT /* Like strdup but get a fatal error if memory is exhausted. */ +char *xstrdup (const char *); char * xstrdup (const char *s) @@ -269,11 +270,13 @@ xstrdup (const char *s) #define REG_ROOT "SOFTWARE\\GNU\\Emacs" +char *w32_get_resource (HKEY, const char *, LPDWORD); + /* Retrieve an environment variable from the Emacs subkeys of the registry. Return NULL if the variable was not found, or it was empty. This code is based on w32_get_resource (w32.c). */ char * -w32_get_resource (HKEY predefined, char *key, LPDWORD type) +w32_get_resource (HKEY predefined, const char *key, LPDWORD type) { HKEY hrootkey = NULL; char *result = NULL; @@ -285,7 +288,7 @@ w32_get_resource (HKEY predefined, char *key, LPDWORD type) { result = (char *) xmalloc (cbData); - if ((RegQueryValueEx (hrootkey, key, NULL, type, result, &cbData) != ERROR_SUCCESS) + if ((RegQueryValueEx (hrootkey, key, NULL, type, (LPBYTE)result, &cbData) != ERROR_SUCCESS) || (*result == 0)) { free (result); @@ -308,7 +311,7 @@ w32_get_resource (HKEY predefined, char *key, LPDWORD type) environment variables in the registry if they don't appear in the environment. */ char * -w32_getenv (char *envvar) +w32_getenv (const char *envvar) { char *value; DWORD dwType; @@ -356,6 +359,7 @@ w32_getenv (char *envvar) return NULL; } +int w32_window_app (void); int w32_window_app (void) @@ -383,11 +387,13 @@ w32_window_app (void) predictably bad results. By contrast, POSIX execvp passes the arguments directly into the argv array of the child process. */ +int w32_execvp (const char *, char **); +extern int execvp (const char*, char **); + int w32_execvp (const char *path, char **argv) { int i; - extern int execvp (const char*, char **); /* Required to allow a .BAT script as alternate editor. */ argv[0] = (char *) alternate_editor; @@ -407,7 +413,8 @@ w32_execvp (const char *path, char **argv) #define execvp w32_execvp /* Emulation of ttyname for Windows. */ -char * +const char *ttyname (int); +const char * ttyname (int fd) { return "CONOUT$"; @@ -539,7 +546,7 @@ decode_options (int argc, char **argv) break; default: - message (true, "Try `%s --help' for more information\n", progname); + message (true, "Try '%s --help' for more information\n", progname); exit (EXIT_FAILURE); break; } @@ -595,13 +602,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 +642,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); @@ -861,6 +859,7 @@ file_name_absolute_p (const char *filename) #ifdef WINDOWSNT /* Wrapper to make WSACleanup a cdecl, as required by atexit. */ +void __cdecl close_winsock (void); void __cdecl close_winsock (void) { @@ -868,6 +867,7 @@ close_winsock (void) } /* Initialize the WinSock2 library. */ +void initialize_sockets (void); void initialize_sockets (void) { @@ -970,6 +970,13 @@ set_tcp_socket (const char *local_server_file) /* Open up an AF_INET socket. */ if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + /* Since we have an alternate to try out, this is not an error + yet; popping out a modal dialog at this stage would make -a + option totally useless for emacsclientw -- the user will + still get an error message if the alternate editor fails. */ +#ifdef WINDOWSNT + if(!(w32_window_app () && alternate_editor)) +#endif sock_err_message ("socket"); return INVALID_SOCKET; } @@ -977,6 +984,9 @@ set_tcp_socket (const char *local_server_file) /* Set up the socket. */ if (connect (s, (struct sockaddr *) &server, sizeof server) < 0) { +#ifdef WINDOWSNT + if(!(w32_window_app () && alternate_editor)) +#endif sock_err_message ("connect"); return INVALID_SOCKET; } @@ -1185,7 +1195,7 @@ set_local_socket (const char *local_socket_name) int use_tmpdir = 0; int saved_errno; const char *server_name = local_socket_name; - const char *tmpdir IF_LINT ( = NULL); + const char *tmpdir; char *tmpdir_storage = NULL; char *socket_name_storage = NULL; @@ -1379,11 +1389,13 @@ set_socket (int no_exit_if_error) FARPROC set_fg; /* Pointer to AllowSetForegroundWindow. */ FARPROC get_wc; /* Pointer to RealGetWindowClassA. */ +void w32_set_user_model_id (void); + void w32_set_user_model_id (void) { HMODULE shell; - HRESULT (WINAPI * set_user_model) (wchar_t * id); + HRESULT (WINAPI * set_user_model) (const wchar_t * id); /* On Windows 7 and later, we need to set the user model ID to associate emacsclient launched files with Emacs frames @@ -1406,6 +1418,8 @@ w32_set_user_model_id (void) } } +BOOL CALLBACK w32_find_emacs_process (HWND, LPARAM); + BOOL CALLBACK w32_find_emacs_process (HWND hWnd, LPARAM lParam) { @@ -1432,6 +1446,7 @@ w32_find_emacs_process (HWND hWnd, LPARAM lParam) /* Search for a window of class "Emacs" and owned by a process with process id = emacs_pid. If found, allow it to grab the focus. */ +void w32_give_focus (void); void w32_give_focus (void) @@ -1511,7 +1526,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, (LPSTR)"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) + { + const 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 @@ -1540,7 +1625,7 @@ main (int argc, char **argv) if ((argc - optind < 1) && !eval && current_frame) { message (true, "%s: file name or argument required\n" - "Try `%s --help' for more information\n", + "Try '%s --help' for more information\n", progname, progname); exit (EXIT_FAILURE); }