diff options
-rw-r--r-- | core/args.lua | 7 | ||||
-rw-r--r-- | doc/02_Installation.md | 99 | ||||
-rw-r--r-- | init.lua | 2 | ||||
-rw-r--r-- | src/textadept.c | 94 |
4 files changed, 153 insertions, 49 deletions
diff --git a/core/args.lua b/core/args.lua index 7d2c6e4b..46ea7769 100644 --- a/core/args.lua +++ b/core/args.lua @@ -37,9 +37,10 @@ end -- Add command line switches with `args.register()`. Any unrecognized arguments -- are treated as filepaths and opened. -- Generates an `'arg_none'` event when no args are present. +-- @param arg Argument table. -- @see register -- @name process -function M.process() +function M.process(arg) local no_args = true local i = 1 while i <= #arg do @@ -53,7 +54,8 @@ function M.process() else if not arg[i]:find(not WIN32 and '^/' or '^%u:[/\\]') then -- Convert relative path to absolute path. - arg[i] = lfs.currentdir()..(not WIN32 and '/' or '\\')..arg[i] + local cwd = arg[-1] or lfs.currentdir() + arg[i] = cwd..(not WIN32 and '/' or '\\')..arg[i] end io.open_file(arg[i]) no_args = false @@ -99,5 +101,6 @@ end _G._USERHOME = userhome M.register('-u', '--userhome', 1, function() end, 'Sets alternate _USERHOME') +M.register('-f', '--force', 0, function() end, 'Forces unique instance') return M diff --git a/doc/02_Installation.md b/doc/02_Installation.md index e901ce8a..5162df3f 100644 --- a/doc/02_Installation.md +++ b/doc/02_Installation.md @@ -3,15 +3,21 @@ ## Requirements In its bid for minimalism, Textadept also needs very little to run. In fact, the -only thing it needs is [GTK+ 2.0][] >= 2.16 on Linux systems. GTK is already +only thing it needs is [GTK+][] >= 2.18 on Linux systems. GTK is already included in Windows and Mac OSX packages. Textadept also has its own version of Lua. -Note: for Win32 and Mac OSX, more than 3/4 of the download and unpackaged -application sizes are due to GTK, the cross-platform GUI toolkit Textadept uses. -Textadept itself is much smaller. +Notes: -[GTK+ 2.0]: http://gtk.org +* The Linux binaries provided require GLib >= 2.28 to support single-instance + functionality. You can compile Textadept with earlier versions of GLib down to + 2.22. For reference, Ubuntu 11.04, Debian Wheezy, Fedora 15, and openSUSE 11.4 + support GLib 2.28 or higher. +* For Win32 and Mac OSX, more than 3/4 of the download and unpackaged + application sizes are due to GTK+, the cross-platform GUI toolkit Textadept + uses. Textadept itself is much smaller. + +[GTK+]: http://gtk.org ### Linux @@ -49,20 +55,51 @@ not need to have administrator privileges. ### Linux -Unpack the archive anywhere. Run Textadept by running -`/path/to/textadept_VERSION/textadept` from the terminal. You can also create a -symlink to the executable in your `PATH` (e.g. `/usr/bin`) or make a GNOME, KDE, -XFCE, etc. button or menu launcher. +Unpack the archive anywhere. If you downloaded the set of language-specific modules, unpack it where you unpacked the Textadept archive. The modules will be contained in `/path/to/textadept_VERSION/modules/`. +### Mac OSX + +Unpack the archive and move `Textadept.app` to your user or system +`Applications` directory like any other Mac OSX application. There is also a +`ta` script for launching Textadept from the command line that you can put in +your `PATH`, but this is optional. + +If you downloaded the set of language-specific modules, unpack it, right-click +`Textadept.app`, select `Show Package Contents`, navigate to +`Contents/Resources/modules`, and copy the unpacked modules there. + +### Windows + +Unpack the archive anywhere. + +If you downloaded the set of language-specific modules, unpack it where you +unpacked the Textadept archive. The modules will be contained in +`textadept_VERSION\modules\`. + +## Running + +### Linux + +Run Textadept by running `/path/to/textadept_VERSION/textadept` from the +terminal. You can also create a symlink to the executable in your `PATH` (e.g. +`/usr/bin`) or make a GNOME, KDE, XFCE, etc. button or menu launcher. + +There is also a `textadeptjit` executable for running Textadept with [LuaJIT][]. +Please note there may be [compatibility issues][]. The `textadept` executable is +recommended. + +[LuaJIT]: http://luajit.org +[compatibility issues]: 11_Scripting.html#LuaJIT + #### Problems It is difficult to provide a single binary that runs on all Linux platforms since the versions of software installed vary widely from distribution to -distribution. Because the Linux version of Textadept uses the version of GTK +distribution. Because the Linux version of Textadept uses the version of GTK+ installed on your system, an error like: `error while loading shared libraries: <lib>: cannot open shared object file: No such file or directory` may occur when trying to run the program. @@ -81,13 +118,16 @@ actually quite painless even though it requires recompiling Textadept. See the ### Mac OSX -Unpack the archive and move `Textadept.app` to your user or system -`Applications` directory like any other Mac OSX application. Run Textadept by -double-clicking `Textadept.app`. +Run Textadept by double-clicking `Textadept.app`. -If you downloaded the set of language-specific modules, unpack it, right-click -`Textadept.app`, select `Show Package Contents`, navigate to -`Contents/Resources/modules`, and copy the unpacked modules there. +`Textadept.app` also contains an executable for running Textadept with +[LuaJIT][]. You can enable it by setting a `TEXTADEPTJIT` +[environment variable](#Environment.Variables) or using `export TEXTADEPTJIT=1` +in the terminal. Please note there may be [compatibility issues][]. The +non-LuaJIT executable is recommended. + +[LuaJIT]: http://luajit.org +[compatibility issues]: 11_Scripting.html#LuaJIT #### Environment Variables @@ -104,13 +144,28 @@ effect. ### Windows -Unpack the archive anywhere. Run Textadept by double-clicking `textadept.exe`. -You can also create shortcuts to the executable in your Start Menu, Quick Launch -toolbar, Desktop, etc. +Run Textadept by double-clicking `textadept.exe`. You can also create shortcuts +to the executable in your Start Menu, Quick Launch toolbar, Desktop, etc. -If you downloaded the set of language-specific modules, unpack it where you -unpacked the Textadept archive. The modules will be contained in -`textadept_VERSION\modules\`. +There is also a `textadeptjit.exe` executable for running Textadept with +[LuaJIT][]. Please note there may be [compatibility issues][]. The +`textadept.exe` executable is recommended. + +[LuaJIT]: http://luajit.org +[compatibility issues]: 11_Scripting.html#LuaJIT + +## Single Instance + +Textadept is a single-instance application on Linux, BSD, and Mac OSX. This +means that after Textadept is opened, running `textadept file.ext` +(`ta file.ext` on Mac OSX) from the command line or opening a file with +Textadept from a file manager will open `file.ext` in the already open instance +of Textadept. You can override this and open the file in a new instance by +passing a `-f` or `--force` switch to Textadept: `textadept -f file.ext` +(`ta -f file.ext`). When the force switch is not present, files will be opened +in the original Textadept instance, regardless of how many instances are open. + +Single instance is not supported on Windows.  @@ -9,4 +9,4 @@ package.path = table.concat({ if not user_dofile('init.lua') then require 'textadept' end -if not RESETTING then args.process() end +if not RESETTING then args.process(arg) end diff --git a/src/textadept.c b/src/textadept.c index a7092197..fca48402 100644 --- a/src/textadept.c +++ b/src/textadept.c @@ -29,16 +29,6 @@ #define SS(view, m, w, l) scintilla_send_message(SCINTILLA(view), m, w, l) #define signal(o, s, c) g_signal_connect(G_OBJECT(o), s, G_CALLBACK(c), 0) -// Defines for different GTK versions. -#if !(GTK_CHECK_VERSION(2,18,0) || GTK_CHECK_VERSION(3,0,0)) -#define gtk_widget_set_can_default(w,_) GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT) -#define gtk_widget_set_can_focus(w,_) GTK_WIDGET_UNSET_FLAGS(w, GTK_CAN_FOCUS) -#define gtk_widget_get_allocation(e, a) \ - ((a)->width = e->allocation.width, (a)->height = e->allocation.height) -#define gtk_widget_has_focus GTK_WIDGET_HAS_FOCUS -#define gtk_widget_get_visible GTK_WIDGET_VISIBLE -#define gtk_widget_get_window(w) w->window -#endif #if GTK_CHECK_VERSION(3,0,0) #define gtk_statusbar_set_has_resize_grip(_,__) #define gtk_combo_box_entry_new_with_model(m,_) \ @@ -65,8 +55,11 @@ static gboolean s_buttonpress(GtkWidget *, GdkEventButton *, gpointer); static gboolean w_focus(GtkWidget *, GdkEventFocus *, gpointer); static gboolean w_keypress(GtkWidget *, GdkEventKey *, gpointer); static gboolean w_exit(GtkWidget *, GdkEventAny *, gpointer); +#if GLIB_CHECK_VERSION(2,28,0) +static int a_command_line(GApplication *, GApplicationCommandLine *, gpointer); +#endif #if __OSX__ -GtkOSXApplication *app; +GtkOSXApplication *osxapp; #define app_signal(a, s, c) g_signal_connect(a, s, G_CALLBACK(c), 0) static gboolean w_open_osx(GtkOSXApplication *, char *, gpointer); static gboolean w_exit_osx(GtkOSXApplication *, gpointer); @@ -138,18 +131,22 @@ static int lbuf_property(lua_State *), /******************************************************************************/ /** - * Runs Textadept in Linux or Mac. - * Inits the Lua state, creates the user interface, and then runs core/init.lua - * followed by init.lua. + * Runs Textadept. + * Initializes the Lua state, creates the user interface, and then runs + * `core/init.lua` followed by `init.lua`. * @param argc The number of command line params. * @param argv The array of command line params. */ int main(int argc, char **argv) { gtk_init(&argc, &argv); + #if !(__WIN32__ || __OSX__ || __BSD__) textadept_home = g_file_read_link("/proc/self/exe", NULL); +#elif __WIN32__ + textadept_home = malloc(FILENAME_MAX); + GetModuleFileName(0, textadept_home, FILENAME_MAX); #elif __OSX__ - app = g_object_new(GTK_TYPE_OSX_APPLICATION, NULL); + osxapp = g_object_new(GTK_TYPE_OSX_APPLICATION, NULL); char *path = quartz_application_get_resource_path(); textadept_home = g_filename_from_utf8((const char *)path, -1, NULL, NULL, NULL); @@ -164,13 +161,36 @@ int main(int argc, char **argv) { char *last_slash = strrchr(textadept_home, G_DIR_SEPARATOR); if (last_slash) *last_slash = '\0'; #endif + +#if GLIB_CHECK_VERSION(2,28,0) + int force = 0; + for (int i = 0; i < argc; i++) + if (strcmp("-f", argv[i]) == 0 || strcmp("--force", argv[i]) == 0) { + force = 1; + break; + } + GApplication *app = g_application_new("textadept.editor", + G_APPLICATION_HANDLES_COMMAND_LINE); + g_signal_connect(app, "command-line", G_CALLBACK(a_command_line), 0); + gboolean registered = g_application_register(app, NULL, NULL); + if (!registered || !g_application_get_is_remote(app) || force) { +#endif + if (lua = luaL_newstate(), !lL_init(lua, argc, argv, FALSE)) return 1; new_window(); lL_dofile(lua, "init.lua"); #if __OSX__ - gtk_osxapplication_ready(app); + gtk_osxapplication_ready(osxapp); #endif + +#if GLIB_CHECK_VERSION(2,28,0) + gtk_main(); + } else g_application_run(app, argc, argv); + g_object_unref(app); +#else gtk_main(); +#endif + free(textadept_home); return 0; } @@ -181,8 +201,6 @@ int main(int argc, char **argv) { * @see main */ int WINAPI WinMain(HINSTANCE _, HINSTANCE __, LPSTR lpCmdLine, int ___) { - textadept_home = malloc(FILENAME_MAX); - GetModuleFileName(0, textadept_home, FILENAME_MAX); return main(1, &lpCmdLine); } #endif @@ -216,10 +234,10 @@ static void new_window() { accel = gtk_accel_group_new(); #if __OSX__ - gtk_osxapplication_set_use_quartz_accelerators(app, FALSE); - app_signal(app, "NSApplicationOpenFile", w_open_osx); - app_signal(app, "NSApplicationBlockTermination", w_exit_osx); - app_signal(app, "NSApplicationWillTerminate", w_quit_osx); + gtk_osxapplication_set_use_quartz_accelerators(osxapp, FALSE); + app_signal(osxapp, "NSApplicationOpenFile", w_open_osx); + app_signal(osxapp, "NSApplicationBlockTermination", w_exit_osx); + app_signal(osxapp, "NSApplicationWillTerminate", w_quit_osx); #endif GtkWidget *vbox = gtk_vbox_new(FALSE, 0); @@ -515,6 +533,34 @@ static gboolean w_exit(GtkWidget*_, GdkEventAny*__, gpointer ___) { return FALSE; } +#if GLIB_CHECK_VERSION(2,28,0) +/** + * Processes a remote Textadept's command line arguments. + */ +static int a_command_line(GApplication *app, GApplicationCommandLine *cmdline, + gpointer _) { + if (!lua) return 0; // only process argv for secondary/remote instances + int argc = 0; + char **argv = g_application_command_line_get_arguments(cmdline, &argc); + if (argc > 1) { + lua_getglobal(lua, "args"), lua_getfield(lua, -1, "process"); + lua_newtable(lua); + lua_pushstring(lua, g_application_command_line_get_cwd(cmdline)); + lua_rawseti(lua, -2, -1); + for (int i = 0; i < argc; i++) + lua_pushstring(lua, argv[i]), lua_rawseti(lua, -2, i); + if (lua_pcall(lua, 1, 0, 0) != LUA_OK) { + lL_event(lua, "error", LUA_TSTRING, lua_tostring(lua, -1), -1); + lua_pop(lua, 1); // error message + } + lua_pop(lua, 1); // args + } + g_strfreev(argv); + gtk_window_present(GTK_WINDOW(window)); + return 0; +} +#endif + #if __OSX__ /** * Signal for opening files from OSX. @@ -541,7 +587,7 @@ static gboolean w_exit_osx(GtkOSXApplication*_, gpointer __) { static void w_quit_osx(GtkOSXApplication*_, gpointer __) { l_close(lua); scintilla_release_resources(); - g_object_unref(app); + g_object_unref(osxapp); gtk_main_quit(); } #endif @@ -1575,7 +1621,7 @@ static int lgui__newindex(lua_State *L) { gtk_box_reorder_child(GTK_BOX(vbox), menubar, 0); gtk_widget_show_all(menubar); #if __OSX__ - gtk_osxapplication_set_menu_bar(app, GTK_MENU_SHELL(menubar)); + gtk_osxapplication_set_menu_bar(osxapp, GTK_MENU_SHELL(menubar)); gtk_widget_hide(menubar); #endif } else if (strcmp(key, "size") == 0) { |