aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/args.lua7
-rw-r--r--doc/02_Installation.md99
-rw-r--r--init.lua2
-rw-r--r--src/textadept.c94
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.
![Linux](images/linux.png)
&nbsp;&nbsp;
diff --git a/init.lua b/init.lua
index 806dbb49..bf688019 100644
--- a/init.lua
+++ b/init.lua
@@ -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) {