This repository has been archived on 2020-04-11. You can view files and clone it, but cannot push or open issues or pull requests.
gnoemoe/gnoemoe/gm-app.c
Jesse van den Kieboom 49e8351958 * gnoemoe/gm-app.c: make sure the main view is destroyed (otherwise
the main view still holds references to the opened worlds which then
	don't get properly finalized). Therefore not properly saving 
	command input history etc. Added proper finalization on SIGINT
	* gnoemoe/gm-scripts.c: fixed indentation
	* gnoemoe/dialogs/gm-preferences-dialog.c: added color table
	saving when dialog gets destroyed
2006-09-29 12:26:16 +00:00

648 lines
16 KiB
C

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gtk/gtk.h>
#include <libgnome/libgnome.h>
#include <libgnomevfs/gnome-vfs.h>
#include <libgnomeui/libgnomeui.h>
#include <strings.h>
#include <signal.h>
#include "widgets/gm-app-view.h"
#include "gm-world.h"
#include "gm-color-table.h"
#include "gm-app.h"
#include "gm-ansi.h"
#include "gm-debug.h"
#include "gm-pixbuf.h"
#include "gm-support.h"
#include "gm-scripts.h"
static gchar *debug_level = NULL;
static gboolean show_version = FALSE;
static gboolean recover = FALSE;
static gchar *load_worlds = NULL;
static GmApp *application;
struct poptOption poptions[] = {
{"debug", 'd', POPT_ARG_STRING, &debug_level, 0, N_("Enable debugging. "
"Specify multiple debug levels with a comma seperated list. "
"Available levels: default, mcp, all"), N_("DBGGLEVEL")},
{"version", 'v', POPT_ARG_NONE, &show_version, 0, N_("Show application "
"version"), NULL},
{"load", 'l', POPT_ARG_STRING, &load_worlds, 0, N_("Load specified worlds. "
"Specify multiple worlds with a comma separated list"),
N_("WORLDS")},
{"recover", 'r', POPT_ARG_NONE, &recover, 0, N_("Recover from previous "
"session (used with gnome session)"), NULL},
{NULL, '\0', 0, NULL, 0, NULL, NULL}
};
#define GM_APP_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \
GM_TYPE_APP, GmAppPrivate))
static void gm_app_destroy_worlds(GmApp *app);
static void on_signal_quit(int signum);
struct _GmAppPrivate {
gchar *path;
gchar *worlds_path;
gchar *options_path;
GmAppView *view;
GmOptions *options;
GmColorTable *color_table;
GnomeClient *client;
GList *worlds;
#ifdef HAVE_RUBY
GmScripts *scripts;
#endif
//tray_info tray;
};
/* Properties */
enum {
PROP_0,
PROP_WORLDS_PATH,
PROP_PATH,
PROP_OPTIONS,
PROP_WORLDS,
PROP_COLOR_TABLE
};
/* Signals */
enum {
WORLD_ADDED,
WORLD_REMOVED,
NUM_SIGNALS
};
static guint app_signals[NUM_SIGNALS] = {0};
G_DEFINE_TYPE(GmApp, gm_app, G_TYPE_OBJECT)
static void
gm_app_get_property(GObject *object, guint prop_id, GValue *value,
GParamSpec *pspec) {
GmApp *app = GM_APP(object);
switch (prop_id) {
case PROP_WORLDS_PATH:
g_value_set_string(value, gm_app_worlds_path(app));
break;
case PROP_PATH:
g_value_set_string(value, gm_app_path(app));
break;
case PROP_OPTIONS:
g_value_set_object(value, gm_app_options(app));
break;
case PROP_COLOR_TABLE:
g_value_set_object(value, gm_app_color_table(app));
break;
case PROP_WORLDS:
g_value_set_pointer(value, gm_app_worlds(app));
break;
}
}
static void
gm_app_finalize(GObject *object) {
GmApp *app = GM_APP(object);
if (GTK_IS_WIDGET(app->priv->view))
gtk_widget_destroy(GTK_WIDGET(app->priv->view));
gnome_vfs_shutdown();
#ifdef HAVE_RUBY
g_object_unref(app->priv->scripts);
#endif
gm_app_destroy_worlds(app);
gm_pixbuf_fini();
gm_options_save(app->priv->options);
g_object_unref(app->priv->options);
gm_color_table_save(app->priv->color_table);
g_object_unref(app->priv->color_table);
g_free(app->priv->path);
g_free(app->priv->worlds_path);
g_free(app->priv->options_path);
G_OBJECT_CLASS(gm_app_parent_class)->finalize(object);
}
static void
gm_app_class_init(GmAppClass *klass) {
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = gm_app_finalize;
object_class->get_property = gm_app_get_property;
g_object_class_install_property(object_class, PROP_PATH,
g_param_spec_string("path", "PATH", "The app path", NULL,
G_PARAM_READABLE));
g_object_class_install_property(object_class, PROP_WORLDS_PATH,
g_param_spec_string("worlds_path", "WORLDS_PATH", "The worlds path", NULL,
G_PARAM_READABLE));
g_object_class_install_property(object_class, PROP_OPTIONS,
g_param_spec_object("options", "OPTIONS", "Options object",
GM_TYPE_OPTIONS, G_PARAM_READABLE));
g_object_class_install_property(object_class, PROP_COLOR_TABLE,
g_param_spec_object("color_table", "COLOR_TABLE", "ColorTable object",
GM_TYPE_COLOR_TABLE, G_PARAM_READABLE));
g_object_class_install_property(object_class, PROP_WORLDS,
g_param_spec_pointer("worlds", "WORLDS", "Worlds list",
G_PARAM_READABLE));
app_signals[WORLD_ADDED] =
g_signal_new("world_added",
G_OBJECT_CLASS_TYPE(object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(GmAppClass, world_added),
NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE,
1,
G_TYPE_POINTER);
app_signals[WORLD_REMOVED] =
g_signal_new("world_removed",
G_OBJECT_CLASS_TYPE(object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(GmAppClass, world_removed),
NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE,
1,
G_TYPE_POINTER);
g_type_class_add_private(object_class, sizeof(GmAppPrivate));
}
static void
gm_app_init(GmApp *app) {
app->priv = GM_APP_GET_PRIVATE(app);
app->priv->path = NULL;
app->priv->worlds_path = NULL;
app->priv->options_path = NULL;
app->priv->options = NULL;
app->priv->client = NULL;
app->priv->worlds = NULL;
}
/* Private functions */
static void
gm_app_destroy_worlds(GmApp *app) {
GList *item;
for (item = app->priv->worlds; item; item = item->next) {
g_object_unref(GM_WORLD(item->data));
}
g_list_free(app->priv->worlds);
app->priv->worlds = NULL;
}
static void
on_gm_app_session_die(GnomeClient * client, gpointer client_data) {
gtk_main_quit();
}
static gboolean
on_gm_app_save_session(GnomeClient * client, gint phase,
GnomeSaveStyle save_style, gint is_shutdown,
GnomeInteractStyle interact_style, gint is_fast, gchar ** client_data) {
gchar **argv;
gint argc = sizeof(client_data) / sizeof(gchar *) + 1;
int i;
GString *ws = g_string_new("");
GList *elem, *list;
GmWorld *world;
argv = g_new(gchar *, argc);
argv[0] = client_data[0];
argv[1] = "--recover";
for (i = 1; i < argc - 1; i++) {
argv[i + 1] = client_data[i];
}
gnome_client_set_clone_command(client, argc, argv);
gnome_client_set_restart_command(client, argc, argv);
// Saving worlds state
list = gm_app_worlds(application);
for (elem = list; elem; elem = elem->next) {
world = (GmWorld *) (elem->data);
if (gm_world_loaded(world)) {
if (strlen(ws->str) != 0) {
ws = g_string_append_c(ws, ';');
}
ws = g_string_append(ws, gm_world_name(world));
}
}
g_list_free(list);
gm_options_set(gm_app_options(application), "worlds_saved_state", ws->str);
gm_options_save(gm_app_options(application));
g_string_free(ws, TRUE);
return TRUE;
}
static void
gm_app_create_settings(GmApp *app) {
app->priv->options = gm_options_new();
gm_options_set(app->priv->options, "editor_alternative", "0");
gm_options_set(app->priv->options, "editor_embed", "0");
gm_options_set(app->priv->options, "editor_needs_terminal", "0");
#ifdef HAVE_PARSER
gm_options_set(app->priv->options, "auto_check_syntax", "1");
#endif
gm_options_set(app->priv->options, "worlds_saved_state", "");
gm_options_set(app->priv->options, "search_direction_world", "1");
gm_options_set(app->priv->options, "search_direction", "0");
gm_options_set(app->priv->options, "search_sensitive", "0");
// Default logging settings
gm_options_set(app->priv->options, "logging_enable", "1");
gm_options_set(app->priv->options, "logging_in", "1");
gm_options_set(app->priv->options, "logging_out", "1");
gm_options_set(app->priv->options, "logging_status", "1");
gm_options_set(app->priv->options, "logging_mcp_in", "0");
gm_options_set(app->priv->options, "logging_mcp_out", "0");
gm_options_set(app->priv->options, "logging_mcp_status", "0");
gm_options_set(app->priv->options, "logging_add_timestamp", "1");
gm_options_set(app->priv->options, "logging_add_log_type", "1");
// Default logging filter settings
gm_options_set(app->priv->options, "logging_filter_in", "1");
gm_options_set(app->priv->options, "logging_filter_out", "1");
gm_options_set(app->priv->options, "logging_filter_status", "1");
gm_options_set(app->priv->options, "logging_filter_mcp_in", "0");
gm_options_set(app->priv->options, "logging_filter_mcp_out", "0");
gm_options_set(app->priv->options, "logging_filter_mcp_status", "0");
// Default userlist settings
gm_options_set(app->priv->options, "userlist_sort_type", "0");
gm_options_set(app->priv->options, "userlist_show_object_number", "0");
gm_options_set(app->priv->options, "userlist_show_status", "1");
gm_options_set(app->priv->options, "userlist_use_state_icon", "1");
}
static void
gm_app_load_worlds(GmApp *app, gboolean autoload) {
GDir *handle = g_dir_open(app->priv->worlds_path, 0, NULL);
char *name, *path;
GmWorld *new_world;
if (handle != NULL) {
while ((name = (char *) g_dir_read_name(handle)) != NULL) {
path = g_strconcat(app->priv->worlds_path, G_DIR_SEPARATOR_S,
name, NULL);
if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
new_world = gm_world_new(path);
if (new_world != NULL) {
gm_app_add_world(app, new_world);
if (autoload && gm_options_get_int(
gm_world_options(new_world), "autoload")) {
gm_world_load(new_world);
}
}
} else {
gm_debug_msg(DEBUG_ALWAYS, "Directory can't be opened: %s", path);
}
g_free(path);
}
g_dir_close(handle);
} else {
gm_debug_msg(DEBUG_DEFAULT, "GmApp.load_worlds: failed to open worlds "
"path %s", app->priv->path);
}
}
static void
gm_app_convert_old_color_configuration(GmApp *app, gchar const *colors_path) {
guint i;
gchar const *color, *value;
FILE *f;
GmColorTable *table;
gboolean is_scheme = TRUE;
f = fopen(colors_path, "w");
if (!f) {
gm_debug_msg(DEBUG_DEFAULT, "Can't open colors file (%s) for writing!",
colors_path);
return;
}
// Create a template color table with the WHITE_ON_BLACK scheme
table = gm_color_table_new();
gm_color_table_load_scheme(table, SCHEME_WHITE_ON_BLACK);
// Copy every color related item from ->options_path to colors_path
for (i = 0; i < sizeof(ansi_colors) / sizeof(ansinamepair); ++i) {
color = ansi_colors[i].name;
value = gm_options_get(app->priv->options, color);
if (value) {
is_scheme = is_scheme && strcmp(value,
gm_color_table_get_hex(table, color)) == 0;
fprintf(f, "%s=%s\n", color, value);
gm_options_remove(app->priv->options, color);
}
}
value = gm_options_get(app->priv->options, "font-family");
if (value) {
fprintf(f, "font_family=%s\n", value);
}
gm_options_remove(app->priv->options, "font-family");
gm_options_remove(app->priv->options, "bold-colors");
gm_options_remove(app->priv->options, "background_transparancy");
gm_options_remove(app->priv->options, "background_transparent");
if (is_scheme) {
fputs("color_scheme=default\n", f);
} else {
fputs("color_scheme=user\n", f);
}
fclose(f);
g_object_unref(G_OBJECT(table));
}
static void
gm_app_initialize(GmApp *app) {
gchar *colors_path;
gm_debug_set_level(debug_level);
app->priv->worlds_path = g_strconcat(app->priv->path, G_DIR_SEPARATOR_S,
"worlds", NULL);
app->priv->options_path = g_strconcat(app->priv->path, G_DIR_SEPARATOR_S,
"settings.xml", NULL);
if (!g_file_test(app->priv->path, G_FILE_TEST_EXISTS)) {
mkdir(app->priv->path, 0755);
mkdir(app->priv->worlds_path, 0755);
}
#ifdef HAVE_RUBY
app->priv->scripts = gm_scripts_new();
#endif
gm_app_create_settings(app);
_gm_options_check_old_options(app->priv->options_path);
gm_options_load(app->priv->options, app->priv->options_path);
// Load color table
colors_path = g_strconcat(app->priv->path, G_DIR_SEPARATOR_S, "colors",
NULL);
if (!g_file_test(colors_path, G_FILE_TEST_EXISTS)) {
// There is no `new` color configuration yet. Copy from general options
gm_app_convert_old_color_configuration(app, colors_path);
}
g_free(colors_path);
colors_path = g_strconcat(app->priv->path, G_DIR_SEPARATOR_S, "colors.xml",
NULL);
app->priv->color_table = gm_color_table_new_from_options(colors_path);
g_free(colors_path);
}
static void
gm_app_run(GmApp *app) {
gchar **wrlds;
const gchar *savedState;
int i = 0;
GmWorld *world;
app->priv->view = gm_app_view_new(app);
gtk_widget_show(GTK_WIDGET(app->priv->view));
#ifdef HAVE_RUBY
gm_scripts_load(app->priv->scripts);
#endif
gm_app_load_worlds(app, !(recover || load_worlds));
if (recover) {
savedState = gm_options_get(app->priv->options, "worlds_saved_state");
if (strlen(savedState) != 0) {
wrlds = g_strsplit(savedState, ";", -1);
for (i = 0; wrlds[i]; i++) {
if (strlen(wrlds[i]) != 0) {
world = gm_app_world_by_name(app, wrlds[i]);
if (world) {
gm_world_load(world);
}
}
}
g_strfreev(wrlds);
}
} else if (load_worlds) {
wrlds = g_strsplit(load_worlds, ",", -1);
for (i = 0; wrlds[i]; i++) {
world = gm_app_world_by_name(app, wrlds[i]);
if (world) {
gm_world_load(world);
}
}
g_strfreev(wrlds);
}
gtk_main();
}
/* Public functions */
GmApp *
gm_app_new(int argc, char *argv[]) {
GmApp *app = GM_APP(g_object_new(GM_TYPE_APP, NULL));
app->priv->path = gnome_util_home_file("gnoemoe");
if (!app->priv->path) {
printf(_("GnoeMoe Application: there is no application directory, "
"this is very bad!!!\n"));
return app;
}
bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
textdomain(GETTEXT_PACKAGE);
g_thread_init(NULL);
gtk_set_locale();
gtk_init(&argc, &argv);
gnome_program_init(PACKAGE, VERSION, LIBGNOMEUI_MODULE,
argc, argv, GNOME_PARAM_POPT_TABLE, poptions,
GNOME_PARAM_APP_DATADIR, PACKAGE_DATA_DIR, NULL);
app->priv->client = gnome_master_client();
gtk_signal_connect(GTK_OBJECT(app->priv->client), "save_yourself",
GTK_SIGNAL_FUNC(on_gm_app_save_session), argv);
gtk_signal_connect(GTK_OBJECT(app->priv->client), "die",
GTK_SIGNAL_FUNC(on_gm_app_session_die), NULL);
/* Initialize everything */
gnome_vfs_init();
glade_init();
gm_pixbuf_init();
gm_app_initialize(app);
if (show_version) {
g_object_unref(G_OBJECT(app));
printf(_("Current version of GnoeMoe is %s\n"), VERSION);
return NULL;
}
return app;
}
gint
gm_app_compare_worlds(GmWorld *world1, GmWorld *world2) {
return strcasecmp(gm_world_name(world1), gm_world_name(world2));
}
void
gm_app_add_world(GmApp *app, GmWorld *world) {
app->priv->worlds = g_list_insert_sorted(app->priv->worlds,
world, (GCompareFunc)(gm_app_compare_worlds));
g_signal_emit(app, app_signals[WORLD_ADDED], 0, world);
}
void
gm_app_remove_world(GmApp *app, GmWorld *world) {
// Only remove when not loaded
gchar *path;
if (!gm_world_loaded(world)) {
path = g_strdup(gm_world_path(world));
app->priv->worlds = g_list_remove(app->priv->worlds, world);
g_signal_emit(app, app_signals[WORLD_REMOVED], 0, world);
g_object_unref(world);
gm_directory_remove_all(path, TRUE);
g_free(path);
}
}
GmWorld *
gm_app_world_by_name(GmApp *app, gchar *name) {
GList *elem;
const gchar *world_name;
for (elem = app->priv->worlds; elem; elem = elem->next) {
world_name = gm_world_name(GM_WORLD(elem->data));
if (!g_strcasecmp(name, world_name)) {
return GM_WORLD(elem->data);
}
}
return NULL;
}
GmOptions *
gm_app_options(GmApp *app) {
return app->priv->options;
}
#ifdef HAVE_RUBY
GmScripts *
gm_app_scripts(GmApp *app) {
return app->priv->scripts;
}
#endif
const gchar *
gm_app_worlds_path(GmApp *app) {
return app->priv->worlds_path;
}
const gchar *
gm_app_path(GmApp *app) {
return app->priv->path;
}
GList *
gm_app_worlds(GmApp *app) {
return g_list_copy(app->priv->worlds);
}
GmColorTable *
gm_app_color_table(GmApp *app) {
return app->priv->color_table;
}
GmApp *
gm_app_instance() {
return application;
}
int
main(int argc, char *argv[]) {
g_type_init();
application = gm_app_new(argc, argv);
if (application) {
signal(SIGTERM, on_signal_quit);
signal(SIGHUP, on_signal_quit);
signal(SIGINT, on_signal_quit);
gm_app_run(application);
g_object_unref(application);
}
return 0;
}
/* Signal handlers */
static void
on_signal_quit(int signum) {
gtk_main_quit();
}