e7bf115295
couldn't be succesfully loaded * gnoemoe/gm-editor.c: allways write \n (also on last line) * gnoemoe/gm-options.c: set file path even if it couldn't be loaded so that when there is no options file it will be saved correctly. return false when loading fails * gnoemoe/widgets/gm-external-view.c: use default gnome terminal when terminal is needed * gnoemoe/widgets/gm-world-tab.c: fix tab close button
265 lines
5.9 KiB
C
265 lines
5.9 KiB
C
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <libgnome/libgnome.h>
|
|
#include <gconf/gconf-client.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "gm-external-view.h"
|
|
#include "gm-debug.h"
|
|
#include "gm-app.h"
|
|
#include "gm-options.h"
|
|
|
|
void on_gm_external_view_exited(GPid pid, gint status, GmExternalView *view);
|
|
void on_gm_external_view_file_changed(GnomeVFSMonitorHandle *handle,
|
|
const gchar *monitor_uri, const gchar *info_uri,
|
|
GnomeVFSMonitorEventType event_type, GmExternalView *view);
|
|
|
|
void
|
|
gm_external_view_destroy(GmExternalView *view) {
|
|
struct stat buf;
|
|
|
|
if (view->monitor) {
|
|
gnome_vfs_monitor_cancel(view->monitor);
|
|
}
|
|
|
|
g_source_remove(view->child_watch);
|
|
g_spawn_close_pid(view->pid);
|
|
|
|
if (GM_IS_EDITOR(view->editor)) {
|
|
if (stat(view->filename, &buf) != -1) {
|
|
if (buf.st_mtime > view->last_modified) {
|
|
gm_editor_save(view->editor);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (view->filename) {
|
|
unlink(view->filename);
|
|
g_free(view->filename);
|
|
}
|
|
}
|
|
|
|
void
|
|
gm_external_view_update_last_modified(GmExternalView *view) {
|
|
struct stat buf;
|
|
|
|
if (stat(view->filename, &buf) != -1) {
|
|
view->last_modified = buf.st_mtime;
|
|
}
|
|
}
|
|
|
|
gboolean
|
|
gm_external_view_spawn(GmExternalView *view, gchar **argv) {
|
|
GError *err = NULL;
|
|
|
|
g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH |
|
|
G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &(view->pid), &err);
|
|
|
|
if (err) {
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmExternalView.Spawn: couldn't spawn "
|
|
"editor: %s", err->message);
|
|
g_error_free(err);
|
|
return FALSE;
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
typedef struct {
|
|
gchar const *terminal;
|
|
gchar const *arguments;
|
|
} Terminal;
|
|
|
|
static Terminal terminals[] = {
|
|
{"gnome-terminal", "--disable-factory"},
|
|
{"gnome-terminal.wrapper", "--disable-factory"},
|
|
{NULL, NULL}
|
|
};
|
|
|
|
static gchar *
|
|
resolve_file(gchar const *file) {
|
|
GSList *paths = NULL;
|
|
GSList *item;
|
|
|
|
gchar *resolve;
|
|
gchar *prog;
|
|
|
|
prog = g_find_program_in_path(file);
|
|
|
|
while (prog && g_file_test(prog, G_FILE_TEST_IS_SYMLINK)) {
|
|
paths = g_slist_prepend(paths, prog);
|
|
|
|
resolve = g_file_read_link(prog, NULL);
|
|
|
|
if (g_slist_find_custom(paths, resolve, (GCompareFunc)strcmp)) {
|
|
prog = NULL;
|
|
g_free(resolve);
|
|
break;
|
|
}
|
|
|
|
prog = resolve;
|
|
}
|
|
|
|
for (item = paths; item; item = item->next)
|
|
if (item->data != prog)
|
|
g_free(item->data);
|
|
|
|
g_slist_free(paths);
|
|
return prog;
|
|
}
|
|
|
|
static Terminal *
|
|
find_terminal(gchar const *term) {
|
|
gchar *prog;
|
|
gchar *basename;
|
|
Terminal *terminal;
|
|
|
|
prog = resolve_file(term);
|
|
|
|
if (prog) {
|
|
basename = g_path_get_basename(prog);
|
|
g_message("%s", basename);
|
|
|
|
for (terminal = terminals; terminal->terminal != NULL; ++terminal)
|
|
if (strcmp(terminal->terminal, basename) == 0)
|
|
break;
|
|
|
|
g_free(basename);
|
|
g_free(prog);
|
|
|
|
if (terminal->terminal)
|
|
return terminal;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static gchar **
|
|
build_terminal_command(gchar const *editor_command) {
|
|
GConfClient *client;
|
|
gchar *term;
|
|
gchar *term_extra_args = NULL;
|
|
gchar *term_args = NULL;
|
|
gchar **spawn_command = NULL;
|
|
Terminal *terminal;
|
|
gchar **argv;
|
|
gint argc;
|
|
gint i;
|
|
|
|
client = gconf_client_get_default();
|
|
term = gconf_client_get_string(client,
|
|
"/desktop/gnome/applications/terminal/exec", NULL);
|
|
|
|
if (term != NULL)
|
|
term_extra_args = gconf_client_get_string(client,
|
|
"/desktop/gnome/applications/terminal/exec_arg", NULL);
|
|
else {
|
|
term = g_strdup(getenv("TERM"));
|
|
|
|
if (term == NULL)
|
|
term = g_strdup("xterm");
|
|
|
|
term_extra_args = g_strdup("-e");
|
|
}
|
|
|
|
terminal = find_terminal(term);
|
|
|
|
if (terminal)
|
|
term_args = (gchar *)(terminal->arguments);
|
|
|
|
if (term_args || (term_extra_args && *term_extra_args != '\0')) {
|
|
term_args = g_strdup_printf("%s %s %s", term_args ? term_args : "",
|
|
term_extra_args ? term_extra_args : "", editor_command);
|
|
|
|
if (g_shell_parse_argv(term_args, &argc, &argv, NULL)) {
|
|
spawn_command = g_new0(gchar *, argc + 2);
|
|
spawn_command[0] = term;
|
|
|
|
for (i = 0; i < argc; ++i)
|
|
spawn_command[i + 1] = argv[i];
|
|
|
|
g_free(argv);
|
|
}
|
|
|
|
g_free(term_args);
|
|
}
|
|
|
|
g_free(term_extra_args);
|
|
g_object_unref(client);
|
|
|
|
for (i = 0; spawn_command[i]; ++i)
|
|
printf("'%s' ", spawn_command[i]);
|
|
|
|
printf("\n");
|
|
|
|
return spawn_command;
|
|
}
|
|
|
|
GmExternalView *
|
|
gm_external_view_new(GmWorld *world, GmEditor *editor) {
|
|
GmExternalView *obj = g_new0(GmExternalView, 1);
|
|
gchar **spawn_command = NULL;
|
|
gchar *filename;
|
|
gchar *command;
|
|
gint argc;
|
|
GmOptions *options = gm_app_options(gm_app_instance());
|
|
|
|
obj->world = world;
|
|
obj->editor = editor;
|
|
obj->filename = gm_editor_write_lines(editor);
|
|
|
|
gm_external_view_update_last_modified(obj);
|
|
|
|
gnome_vfs_monitor_add(&(obj->monitor), obj->filename,
|
|
GNOME_VFS_MONITOR_FILE,
|
|
(GnomeVFSMonitorCallback)on_gm_external_view_file_changed, obj);
|
|
|
|
filename = g_shell_quote(obj->filename);
|
|
command = g_strconcat(gm_options_get(options, "editor_alternative"),
|
|
" ", filename, NULL);
|
|
g_free(filename);
|
|
|
|
if (gm_options_get_int(options, "editor_needs_terminal")) {
|
|
spawn_command = build_terminal_command(command);
|
|
} else {
|
|
g_shell_parse_argv(command, &argc, &spawn_command, NULL);
|
|
}
|
|
|
|
gm_external_view_spawn(obj, spawn_command);
|
|
g_strfreev(spawn_command);
|
|
g_free(command);
|
|
|
|
obj->child_watch = g_child_watch_add(obj->pid,
|
|
(GChildWatchFunc)on_gm_external_view_exited, obj);
|
|
|
|
return obj;
|
|
}
|
|
|
|
/* Callbacks */
|
|
|
|
void
|
|
on_gm_external_view_exited(GPid pid, gint status, GmExternalView *view) {
|
|
gm_editor_close(view->editor);
|
|
}
|
|
|
|
void
|
|
on_gm_external_view_file_changed(GnomeVFSMonitorHandle *handle,
|
|
const gchar *monitor_uri, const gchar *info_uri,
|
|
GnomeVFSMonitorEventType event_type, GmExternalView *view) {
|
|
switch (event_type) {
|
|
case GNOME_VFS_MONITOR_EVENT_CHANGED:
|
|
case GNOME_VFS_MONITOR_EVENT_CREATED:
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmExternalView.OnFileChanged: "
|
|
"change event detected!");
|
|
|
|
gm_editor_set_lines_from_file(view->editor,
|
|
view->filename);
|
|
gm_editor_save(view->editor);
|
|
gm_external_view_update_last_modified(view);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|