#ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #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(); }