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

652 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");
// Default view settings
gm_options_set(app->priv->options, "show_toolbar", "1");
gm_options_set(app->priv->options, "show_userlist", "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();
}