diff options
-rw-r--r-- | THANKS.md | 1 | ||||
-rw-r--r-- | core/args.lua | 8 | ||||
-rw-r--r-- | doc/manual.md | 28 | ||||
-rw-r--r-- | src/textadept.c | 74 |
4 files changed, 77 insertions, 34 deletions
@@ -31,6 +31,7 @@ private contract work related to Textadept. * Bill Meahan * Brian Schott * Callum Wilson +* Carl Sturtivant * Chris Emerson * Daniel Wutke * Gilles Grégoire diff --git a/core/args.lua b/core/args.lua index 9b90d4ab..c27da28e 100644 --- a/core/args.lua +++ b/core/args.lua @@ -88,14 +88,6 @@ if not CURSES then end) end --- For Windows, create arg table from single command line string (arg[0]). -if WIN32 and not CURSES and #arg[0] > 0 then - local P, C = lpeg.P, lpeg.C - local param = P('"') * C((1 - P('"'))^0) * '"' + C((1 - P(' '))^1) - local params = lpeg.match(lpeg.Ct(param * (P(' ')^1 * param)^0), arg[0]) - for i = 1, #params do arg[#arg + 1] = params[i] end -end - -- Set `_G._USERHOME`. _USERHOME = os.getenv(not WIN32 and 'HOME' or 'USERPROFILE')..'/.textadept' for i = 1, #arg do diff --git a/doc/manual.md b/doc/manual.md index d40acc8f..0cb2fd71 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -117,10 +117,9 @@ Most Linux and BSD systems already have GTK+ installed. If not, your package manager probably makes it available. Otherwise, compile and install GTK+from the [GTK+ website][]. -The Linux binaries for the GUI versions of Textadept require GLib version 2.28 -or later to support [single-instance](#Single.Instance) functionality. However, -Textadept compiles with versions of GLib as early as 2.22. For reference, Ubuntu -11.04, Debian Wheezy, Fedora 15, and openSUSE 11.4 support GLib 2.28 or later. +The GUI versions of Textadept require GLib version 2.28 or later to support +[single-instance](#Single.Instance) functionality. For reference, Ubuntu 11.04, +Debian Wheezy, Fedora 15, and openSUSE 11.4 support GLib 2.28 or later. Most Linux and BSD systems already have a curses implementation like ncurses installed. If not, look for one in your package manager, or compile and install @@ -265,16 +264,17 @@ The manual gives more information on this folder later. ## Single Instance -Textadept is a single-instance application on Linux, BSD, and Mac OSX. This -means that after starting Textadept, running `textadept file.ext` (`ta file.ext` -on Mac OSX) from the command line or opening a file with Textadept from a file -manager opens *file.ext* in the original Textadept instance. Passing a `-f` or -`--force` switch to Textadept overrides this behavior and opens the file in a -new instance: `textadept -f file.ext` (`ta -f file.ext`). Without the force -switch, the original Textadept instance opens files, regardless of the number of -instances open. - -The Windows and terminal versions of Textadept do not support single instance. +Textadept is a single-instance application. This means that after starting +Textadept, running `textadept file.ext` on Linux or BSD (`ta file.ext` on Mac +OSX) from the command line or opening a file with Textadept from a file manager +(e.g. Windows) opens *file.ext* in the original Textadept instance. Passing a +`-f` or `--force` switch to Textadept overrides this behavior and opens the file +in a new instance: `textadept -f file.ext` (`ta -f file.ext`); on Windows, you +can create a separate shortcut to *textadept.exe* that passes the switch. +Without the force switch, the original Textadept instance opens files, +regardless of the number of instances open. + +The terminal versions of Textadept do not support single instance. <span style="display: block; text-align: right; margin-left: -10em;">  diff --git a/src/textadept.c b/src/textadept.c index 461a06bb..d608b205 100644 --- a/src/textadept.c +++ b/src/textadept.c @@ -12,6 +12,7 @@ #include <unistd.h> #elif _WIN32 #include <windows.h> +#include <fcntl.h> #define main main_ #elif __APPLE__ #include <mach-o/dyld.h> @@ -72,6 +73,23 @@ typedef GtkWidget Scintilla; #define gtk_vbox_new(_,s) gtk_box_new(GTK_ORIENTATION_VERTICAL, s) #define gtk_hbox_new(_,s) gtk_box_new(GTK_ORIENTATION_HORIZONTAL, s) #endif +// Win32 single-instance functionality. +#if _WIN32 +#define g_application_command_line_get_arguments(_,__) \ + g_strsplit((char *)data, "\n", 0); argc = g_strv_length(argv); +#define g_application_command_line_get_cwd(_) argv[0] +#define g_application_register(_,__,___) TRUE +#define g_application_get_is_remote(_) \ + (WaitNamedPipe("\\\\.\\pipe\\textadept.editor", NMPWAIT_WAIT_FOREVER) != 0) +#define g_application_run(_,__,___) win32_application_run() +#define gtk_main() \ + HANDLE pipe = CreateNamedPipe("\\\\.\\pipe\\textadept.editor", \ + PIPE_ACCESS_INBOUND, PIPE_WAIT, 1, 0, 0, \ + INFINITE, NULL); \ + HANDLE thread = CreateThread(NULL, 0, &pipe_listener, pipe, 0, NULL); \ + gtk_main(); \ + CloseHandle(thread), CloseHandle(pipe); +#endif #endif // Lua definitions and macros. @@ -270,10 +288,9 @@ static int lL_event(lua_State *L, const char *name, ...) { } #if GTK -#if GLIB_CHECK_VERSION(2,28,0) /** Processes a remote Textadept's command line arguments. */ static int a_command_line(GApplication*_, GApplicationCommandLine *cmdline, - void*__) { + void *data) { if (!lua) return 0; // only process argv for secondary/remote instances int argc = 0; char **argv = g_application_command_line_get_arguments(cmdline, &argc); @@ -288,7 +305,6 @@ static int a_command_line(GApplication*_, GApplicationCommandLine *cmdline, return (gtk_window_present(GTK_WINDOW(window)), 0); } #endif -#endif #if CURSES /** @@ -2340,6 +2356,44 @@ static void new_window() { register_command_entry_doc(); } +#if GTK && _WIN32 +/** Reads and processes a remote Textadept's command line arguments. */ +static int pipe_read(GIOChannel *source, GIOCondition _, HANDLE pipe) { + char *buf; + size_t len; + g_io_channel_read_to_end(source, &buf, &len, NULL); + for (char *p = buf; p < buf + len - 2; p++) if (!*p) *p = '\n'; // '\0\0' end + a_command_line(NULL, NULL, buf); + g_free(buf), DisconnectNamedPipe(pipe); + return FALSE; +} + +/** Listens for remote Textadept communications. */ +static DWORD WINAPI pipe_listener(HANDLE pipe) { + while (1) + if (pipe != INVALID_HANDLE_VALUE && ConnectNamedPipe(pipe, NULL)) { + int fd = _open_osfhandle((intptr_t)pipe, _O_RDONLY); + GIOChannel *channel = g_io_channel_win32_new_fd(fd); + g_io_add_watch(channel, G_IO_IN, pipe_read, pipe); + g_io_channel_unref(channel); + } + return 0; +} + +/** Replacement for `g_application_run()` that handles multiple instances. */ +static void win32_application_run() { + HANDLE pipe = CreateFile("\\\\.\\pipe\\textadept.editor", GENERIC_WRITE, 0, + NULL, OPEN_EXISTING, 0, NULL); + char cwd[FILENAME_MAX + 1]; + GetCurrentDirectory(FILENAME_MAX + 1, cwd); + DWORD len_written; + WriteFile(pipe, cwd, strlen(cwd) + 1, &len_written, NULL); + for (int i = 1; i < __argc; i++) + WriteFile(pipe, __argv[i], strlen(__argv[i]) + 1, &len_written, NULL); + CloseHandle(pipe); +} +#endif + #if (CURSES && !_WIN32) /** * Signal for a terminal suspend, continue, and resize. @@ -2387,6 +2441,8 @@ static TermKeyResult textadept_waitkey(TermKey *tk, TermKeyKey *key) { * Runs Textadept. * Initializes the Lua state, creates the user interface, and then runs * `core/init.lua` followed by `init.lua`. + * On Windows, creates a pipe and thread for communication with remote + * instances. * @param argc The number of command line params. * @param argv The array of command line params. */ @@ -2412,7 +2468,7 @@ int main(int argc, char **argv) { platform = "LINUX"; #elif _WIN32 textadept_home = malloc(FILENAME_MAX); - GetModuleFileName(0, textadept_home, FILENAME_MAX); + GetModuleFileName(NULL, textadept_home, FILENAME_MAX); if ((last_slash = strrchr(textadept_home, '\\'))) *last_slash = '\0'; platform = "WIN32"; #elif __APPLE__ @@ -2436,7 +2492,6 @@ int main(int argc, char **argv) { #endif #if GTK -#if GLIB_CHECK_VERSION(2,28,0) int force = FALSE; for (int i = 0; i < argc; i++) if (strcmp("-f", argv[i]) == 0 || strcmp("--force", argv[i]) == 0) { @@ -2449,7 +2504,6 @@ int main(int argc, char **argv) { int registered = g_application_register(app, NULL, NULL); if (!registered || !g_application_get_is_remote(app) || force) { #endif -#endif setlocale(LC_COLLATE, "C"), setlocale(LC_NUMERIC, "C"); // for Lua if (lua = luaL_newstate(), !lL_init(lua, argc, argv, FALSE)) return 1; @@ -2464,13 +2518,9 @@ int main(int argc, char **argv) { #endif #if GTK -#if GLIB_CHECK_VERSION(2,28,0) gtk_main(); } else g_application_run(app, argc, argv); g_object_unref(app); -#else - gtk_main(); -#endif #elif CURSES refresh_all(); @@ -2568,7 +2618,7 @@ int main(int argc, char **argv) { * Runs Textadept in Windows. * @see main */ -int WINAPI WinMain(HINSTANCE _, HINSTANCE __, LPSTR lpCmdLine, int ___) { - return main(1, &lpCmdLine); +int WINAPI WinMain(HINSTANCE _, HINSTANCE __, LPSTR ___, int ____) { + return main(__argc, __argv); // MSVC extensions } #endif |