00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #ifdef HAVE_CONFIG_H
00014 #include <config.h>
00015 #endif
00016
00017 #include <iostream>
00018 #include <fstream>
00019 #include <cstdlib>
00020 #include <cctype>
00021 #include <cstring>
00022 #include <time.h>
00023
00024 #ifdef WIN32
00025 #include <direct.h>
00026 #else
00027 #include <unistd.h>
00028 #endif
00029
00030 #include <gtk/gtk.h>
00031 #include <gtk/gtkgl.h>
00032
00033 #include <celengine/astro.h>
00034 #include <celengine/celestia.h>
00035 #include <celengine/gl.h>
00036 #include <celengine/glext.h>
00037 #include <celengine/galaxy.h>
00038 #include <celengine/simulation.h>
00039 #include <celestia/celestiacore.h>
00040 #include <celutil/debug.h>
00041
00042
00043 #ifdef GNOME
00044 #include <gnome.h>
00045 #include <libgnomeui/libgnomeui.h>
00046 #include <gconf/gconf-client.h>
00047 #endif
00048
00049
00050 #include "common.h"
00051 #include "glwidget.h"
00052 #include "menu-context.h"
00053 #include "splash.h"
00054 #include "ui.h"
00055
00056
00057 #ifdef GNOME
00058 #include "settings-gconf.h"
00059 #else
00060 #include "settings-file.h"
00061 #endif
00062
00063 #ifndef DEBUG
00064 #define G_DISABLE_ASSERT
00065 #endif
00066
00067
00068 using namespace std;
00069
00070
00071
00072 static void createMainMenu(GtkWidget* window, AppData* app);
00073 static void initRealize(GtkWidget* widget, AppData* app);
00074
00075
00076
00077 static gchar* configFile = NULL;
00078 static gchar* installDir = NULL;
00079 static gchar** extrasDir = NULL;
00080 static gboolean fullScreen = FALSE;
00081 static gboolean noSplash = FALSE;
00082
00083
00084 static GOptionEntry optionEntries[] =
00085 {
00086 { "conf", 'c', 0, G_OPTION_ARG_FILENAME, &configFile, "Alternate configuration file", "file" },
00087 { "dir", 'd', 0, G_OPTION_ARG_FILENAME, &installDir, "Alternate installation directory", "directory" },
00088 { "extrasdir", 'e', 0, G_OPTION_ARG_FILENAME_ARRAY, &extrasDir, "Additional \"extras\" directory", "directory" },
00089 { "fullscreen", 'f', 0, G_OPTION_ARG_NONE, &fullScreen, "Start full-screen", NULL },
00090 { "nosplash", 's', 0, G_OPTION_ARG_NONE, &noSplash, "Disable splash screen", NULL },
00091 { NULL },
00092 };
00093
00094
00095
00096 static void createMainMenu(GtkWidget* window, AppData* app)
00097 {
00098 GtkUIManager *ui_manager;
00099 GtkAccelGroup *accel_group;
00100 GError *error;
00101
00102 app->agMain = gtk_action_group_new ("MenuActions");
00103 app->agRender = gtk_action_group_new("RenderActions");
00104 app->agLabel = gtk_action_group_new("LabelActions");
00105 app->agOrbit = gtk_action_group_new("OrbitActions");
00106 app->agVerbosity = gtk_action_group_new("VerbosityActions");
00107 app->agStarStyle = gtk_action_group_new("StarStyleActions");
00108 app->agAmbient = gtk_action_group_new("AmbientActions");
00109
00110
00111 gtk_action_group_add_actions(app->agMain, actionsPlain, G_N_ELEMENTS(actionsPlain), app);
00112 gtk_action_group_add_toggle_actions(app->agMain, actionsToggle, G_N_ELEMENTS(actionsToggle), app);
00113 gtk_action_group_add_radio_actions(app->agVerbosity, actionsVerbosity, G_N_ELEMENTS(actionsVerbosity), 0, G_CALLBACK(actionVerbosity), app);
00114 gtk_action_group_add_radio_actions(app->agStarStyle, actionsStarStyle, G_N_ELEMENTS(actionsStarStyle), 0, G_CALLBACK(actionStarStyle), app);
00115 gtk_action_group_add_radio_actions(app->agAmbient, actionsAmbientLight, G_N_ELEMENTS(actionsAmbientLight), 0, G_CALLBACK(actionAmbientLight), app);
00116 gtk_action_group_add_toggle_actions(app->agRender, actionsRenderFlags, G_N_ELEMENTS(actionsRenderFlags), app);
00117 gtk_action_group_add_toggle_actions(app->agLabel, actionsLabelFlags, G_N_ELEMENTS(actionsLabelFlags), app);
00118 gtk_action_group_add_toggle_actions(app->agOrbit, actionsOrbitFlags, G_N_ELEMENTS(actionsOrbitFlags), app);
00119
00120 ui_manager = gtk_ui_manager_new();
00121 gtk_ui_manager_insert_action_group(ui_manager, app->agMain, 0);
00122 gtk_ui_manager_insert_action_group(ui_manager, app->agRender, 0);
00123 gtk_ui_manager_insert_action_group(ui_manager, app->agLabel, 0);
00124 gtk_ui_manager_insert_action_group(ui_manager, app->agOrbit, 0);
00125 gtk_ui_manager_insert_action_group(ui_manager, app->agStarStyle, 0);
00126 gtk_ui_manager_insert_action_group(ui_manager, app->agAmbient, 0);
00127 gtk_ui_manager_insert_action_group(ui_manager, app->agVerbosity, 0);
00128
00129 accel_group = gtk_ui_manager_get_accel_group(ui_manager);
00130 gtk_window_add_accel_group(GTK_WINDOW (window), accel_group);
00131
00132 error = NULL;
00133 if (!gtk_ui_manager_add_ui_from_file(ui_manager, "celestiaui.xml", &error))
00134 {
00135 g_message("Building menus failed: %s", error->message);
00136 g_error_free(error);
00137 exit(EXIT_FAILURE);
00138 }
00139
00140 app->mainMenu = gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
00141 }
00142
00143
00144
00145
00146
00147 class GtkWatcher : public CelestiaWatcher
00148 {
00149 public:
00150 GtkWatcher(CelestiaCore*, AppData*);
00151 virtual void notifyChange(CelestiaCore*, int);
00152 private:
00153 AppData* app;
00154 };
00155
00156 GtkWatcher::GtkWatcher(CelestiaCore* _appCore, AppData* _app) :
00157 CelestiaWatcher(*_appCore), app(_app)
00158 {
00159 }
00160
00161 void GtkWatcher::notifyChange(CelestiaCore*, int property)
00162 {
00163 if (property & CelestiaCore::LabelFlagsChanged)
00164 resyncLabelActions(app);
00165
00166 else if (property & CelestiaCore::RenderFlagsChanged)
00167 {
00168 resyncRenderActions(app);
00169 resyncOrbitActions(app);
00170 resyncStarStyleActions(app);
00171 }
00172
00173 else if (property & CelestiaCore::VerbosityLevelChanged)
00174 resyncVerbosityActions(app);
00175
00176 else if (property & CelestiaCore::TimeZoneChanged)
00177 resyncTimeZoneAction(app);
00178
00179 else if (property & CelestiaCore::AmbientLightChanged)
00180 resyncAmbientActions(app);
00181
00182
00183
00184
00185
00186
00187 else if (property == CelestiaCore::TextEnterModeChanged)
00188 {
00189 if (app->core->getTextEnterMode() != 0)
00190 {
00191
00192 gtk_widget_set_sensitive(app->mainMenu, FALSE);
00193
00194
00195
00196 gtk_action_group_set_sensitive(app->agMain, FALSE);
00197 gtk_action_group_set_sensitive(app->agRender, FALSE);
00198 gtk_action_group_set_sensitive(app->agLabel, FALSE);
00199 }
00200 else
00201 {
00202
00203 gtk_widget_set_sensitive(app->mainMenu, TRUE);
00204
00205
00206 gtk_action_group_set_sensitive(app->agMain, TRUE);
00207 gtk_action_group_set_sensitive(app->agRender, TRUE);
00208 gtk_action_group_set_sensitive(app->agLabel, TRUE);
00209 }
00210 }
00211
00212 else if (property & CelestiaCore::GalaxyLightGainChanged)
00213 resyncGalaxyGainActions(app);
00214 }
00215
00216
00217
00218
00219
00220
00221 static void initRealize(GtkWidget* widget, AppData* app)
00222 {
00223 if (!app->core->initRenderer())
00224 {
00225 cerr << "Failed to initialize renderer.\n";
00226 }
00227
00228
00229 #ifdef GNOME
00230 applySettingsGConfMain(app, app->client);
00231 #else
00232 applySettingsFileMain(app, app->settingsFile);
00233 #endif
00234
00235
00236 resyncLabelActions(app);
00237 resyncRenderActions(app);
00238 resyncOrbitActions(app);
00239 resyncVerbosityActions(app);
00240 resyncAmbientActions(app);
00241 resyncStarStyleActions(app);
00242
00243
00244 if (app->fullScreen)
00245 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(gtk_action_group_get_action(app->agMain, "FullScreen")), TRUE);
00246
00247
00248 if (app->startURL != NULL)
00249 app->core->setStartURL(app->startURL);
00250
00251
00252 app->core->start((double)time(NULL) / 86400.0 + (double)astro::Date(1970, 1, 1));
00253 updateTimeZone(app, app->showLocalTime);
00254
00255
00256
00257 app->core->setTimeZoneName("UTC");
00258
00259
00260 gdk_window_set_cursor(widget->window, gdk_cursor_new(GDK_CROSSHAIR));
00261 }
00262
00263
00264
00265 int main(int argc, char* argv[])
00266 {
00267
00268 AppData* app = g_new0(AppData, 1);
00269
00270
00271 app->bReady = FALSE;
00272
00273
00274 app->lastX = 0;
00275 app->lastY = 0;
00276 app->showLocalTime = FALSE;
00277 app->fullScreen = FALSE;
00278 app->startURL = NULL;
00279
00280
00281 GtkWatcher* gtkWatcher;
00282
00283
00284 GError *error = NULL;
00285 GOptionContext* context = g_option_context_new("");
00286 g_option_context_add_main_entries(context, optionEntries, NULL);
00287 g_option_context_add_group(context, gtk_get_option_group(TRUE));
00288 g_option_context_parse(context, &argc, &argv, &error);
00289
00290 if (error != NULL)
00291 {
00292 g_print("Error in command line options. Use --help for full list.\n");
00293 exit(1);
00294 }
00295
00296
00297
00298
00299
00300
00301
00302 if (argc > 1)
00303 app->startURL = argv[argc - 1];
00304
00305 if (installDir == NULL)
00306 installDir = (gchar*)CONFIG_DATA_DIR;
00307
00308 if (chdir(installDir) == -1)
00309 cerr << "Cannot chdir to '" << installDir << "', probably due to improper installation.\n";
00310
00311 #ifdef GNOME
00312
00313 GnomeProgram *program;
00314 program = gnome_program_init("Celestia", VERSION, LIBGNOMEUI_MODULE,
00315 argc, argv, GNOME_PARAM_NONE);
00316 #else
00317
00318 gtk_init(&argc, &argv);
00319 #endif
00320
00321
00322 SplashData* ss = splashStart(app, !noSplash);
00323 splashSetText(ss, "Initializing...");
00324
00325 SetDebugVerbosity(0);
00326
00327
00328 setlocale(LC_NUMERIC, "C");
00329 setlocale(LC_ALL, "");
00330
00331 #ifndef WIN32
00332 bindtextdomain(PACKAGE, LOCALEDIR);
00333 bind_textdomain_codeset(PACKAGE, "UTF-8");
00334 textdomain(PACKAGE);
00335 #endif
00336
00337 app->core = new CelestiaCore();
00338 if (app->core == NULL)
00339 {
00340 cerr << "Failed to initialize Celestia core.\n";
00341 return 1;
00342 }
00343
00344 app->renderer = app->core->getRenderer();
00345 g_assert(app->renderer);
00346
00347
00348 string cf;
00349 if (configFile != NULL)
00350 cf = string(configFile);
00351
00352 string* altConfig = (configFile != NULL) ? &cf : NULL;
00353
00354 vector<string> configDirs;
00355 if (extrasDir != NULL)
00356 {
00357
00358 int i = 0;
00359 while (extrasDir[i] != NULL)
00360 {
00361 configDirs.push_back(extrasDir[i]);
00362 i++;
00363 }
00364 }
00365
00366
00367 if (!app->core->initSimulation(altConfig, &configDirs, ss->notifier))
00368 return 1;
00369
00370 app->simulation = app->core->getSimulation();
00371 g_assert(app->simulation);
00372
00373 #ifdef GNOME
00374
00375 app->mainWindow = gnome_app_new("Celestia", "Celestia");
00376 #else
00377
00378 app->mainWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
00379 gtk_window_set_title(GTK_WINDOW(app->mainWindow), "Celestia");
00380 #endif
00381
00382
00383
00384 g_object_set_data(G_OBJECT(app->mainWindow), "CelestiaData", app);
00385
00386 GtkWidget* mainBox = GTK_WIDGET(gtk_vbox_new(FALSE, 0));
00387 gtk_container_set_border_width(GTK_CONTAINER(mainBox), 0);
00388
00389 g_signal_connect(GTK_OBJECT(app->mainWindow), "destroy",
00390 G_CALLBACK(actionQuit), app);
00391
00392
00393 gtk_gl_init (&argc, &argv);
00394
00395
00396 GdkGLConfig* glconfig = gdk_gl_config_new_by_mode(static_cast<GdkGLConfigMode>
00397 (GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE));
00398
00399 if (glconfig == NULL)
00400 {
00401 g_print("*** Cannot find the double-buffered visual.\n");
00402 g_print("*** Trying single-buffered visual.\n");
00403
00404
00405 glconfig = gdk_gl_config_new_by_mode(static_cast<GdkGLConfigMode>
00406 (GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH));
00407 if (glconfig == NULL)
00408 {
00409 g_print ("*** No appropriate OpenGL-capable visual found.\n");
00410 exit(1);
00411 }
00412 }
00413
00414
00415 #ifdef GNOME
00416 initSettingsGConf(app);
00417 #else
00418 initSettingsFile(app);
00419 #endif
00420
00421
00422 app->glArea = gtk_drawing_area_new();
00423
00424
00425 gtk_widget_set_gl_capability(app->glArea,
00426 glconfig,
00427 NULL,
00428 TRUE,
00429 GDK_GL_RGBA_TYPE);
00430
00431 gtk_widget_set_events(GTK_WIDGET(app->glArea),
00432 GDK_EXPOSURE_MASK |
00433 GDK_KEY_PRESS_MASK |
00434 GDK_KEY_RELEASE_MASK |
00435 GDK_BUTTON_PRESS_MASK |
00436 GDK_BUTTON_RELEASE_MASK |
00437 GDK_POINTER_MOTION_MASK);
00438
00439
00440 #ifdef GNOME
00441 applySettingsGConfPre(app, app->client);
00442 #else
00443 applySettingsFilePre(app, app->settingsFile);
00444 #endif
00445
00446
00447 if (fullScreen)
00448 app->fullScreen = TRUE;
00449
00450
00451 initGLCallbacks(app);
00452
00453
00454 g_signal_connect(GTK_OBJECT(app->glArea), "realize",
00455 G_CALLBACK(initRealize), app);
00456
00457
00458 createMainMenu(app->mainWindow, app);
00459
00460
00461 initContext(app);
00462
00463
00464 app->core->setContextMenuCallback(menuContext);
00465
00466 #ifdef GNOME
00467
00468 gnome_app_set_contents((GnomeApp *)app->mainWindow, GTK_WIDGET(mainBox));
00469 #else
00470
00471 gtk_container_add(GTK_CONTAINER(app->mainWindow), GTK_WIDGET(mainBox));
00472 #endif
00473
00474 gtk_box_pack_start(GTK_BOX(mainBox), app->mainMenu, FALSE, TRUE, 0);
00475 gtk_box_pack_start(GTK_BOX(mainBox), app->glArea, TRUE, TRUE, 0);
00476
00477 gtk_window_set_default_icon_from_file("celestia-logo.png", NULL);
00478
00479
00480 GTK_WIDGET_SET_FLAGS(app->glArea, GTK_CAN_FOCUS);
00481 gtk_widget_grab_focus(GTK_WIDGET(app->glArea));
00482
00483
00484 gtkWatcher = new GtkWatcher(app->core, app);
00485
00486
00487 splashEnd(ss);
00488
00489 gtk_widget_show_all(app->mainWindow);
00490
00491
00492 gtk_widget_set_size_request(app->glArea, 320, 240);
00493
00494 #ifdef GNOME
00495 initSettingsGConfNotifiers(app);
00496 #endif
00497
00498
00499 app->bReady = TRUE;
00500
00501
00502 gtk_main();
00503
00504 g_free(app);
00505
00506 return 0;
00507 }
00508
00509
00510 #ifdef WIN32
00511 int APIENTRY WinMain(HINSTANCE hInstance,
00512 HINSTANCE hPrevInstance,
00513 LPSTR lpCmdLine,
00514 int nCmdShow)
00515 {
00516 return main(__argc, __argv);
00517 }
00518 #endif