1 /*-- ggobi.c --*/
2 /*
3 * ggobi
4 * Copyright (C) AT&T, Duncan Temple Lang, Dianne Cook 1999-2005
5 *
6 * ggobi is free software; you may use, redistribute, and/or modify it
7 * under the terms of the Eclipse Public License, which is distributed
8 * with the source code and displayed on the ggobi web site,
9 * www.ggobi.org. For more information, contact the authors:
10 *
11 * Deborah F. Swayne dfs@research.att.com
12 * Di Cook dicook@iastate.edu
13 * Duncan Temple Lang duncan@wald.ucdavis.edu
14 * Andreas Buja andreas.buja@wharton.upenn.edu
15 */
16
17 #define GGOBIINTERN
18 #define GGOBI_C
19
20 #include <math.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <gtk/gtk.h>
25
26 #include "config.h"
27
28 #include "GGobiApp.h"
29
30 #include "ggobi.h"
31
32 #include "vars.h"
33 #include "externs.h"
34
35 #include "print.h"
36
37 #include "read_init.h"
38 #include "colorscheme.h"
39
40 #include "plugin.h" /* For registerDefaultPlugin. */
41
42 #include "ggobi-intl.h"
43
44 #ifdef WIN32
45 #undef GGOBI_LOCALEDIR
46 static gchar* ggobi_win32_get_localedir();
47 #define GGOBI_LOCALEDIR ggobi_win32_get_localedir()
48 #undef GGOBI_DATADIR
49 #define GGOBI_DATADIR NULL
50 #include <windows.h>
51 #endif
52
53 GGobiApp *ggobiApp;
54
55 static GGobiOptions sessionoptions;
56 GGobiOptions *sessionOptions;
57
58
59 ggobid **all_ggobis;
60 gint num_ggobis;
61 gint totalNumGGobis;
62
63 /* Needs to be connected to MAXNVARS in scatmat.c
64 and MAXNPCPLOTS in parcoords.c
65 */
66 #define MAXNVARS 4
67 #define MAXNPCPLOTS 5
68 #define MAXNTSPLOTS 6
69
70 #include "ggobiClass.h"
71
72 const GTypeLoad typeLoaders[] = {
73 ggobi_scatterplot_display_get_type,
74 ggobi_scatmat_display_get_type,
75 ggobi_par_coords_display_get_type,
76 ggobi_time_series_display_get_type,
77 ggobi_barchart_display_get_type
78 };
79
80 const gchar *const ViewTypes[] = {
81 "Scatterplot",
82 "Scatterplot Matrix",
83 };
84 const gint ViewTypeIndices[];
85
86 static gchar *computeGGobiHome (char *str);
87
88 GGobiApp *
getGGobiApp()89 getGGobiApp ()
90 {
91 return (ggobiApp);
92 }
93
94 gint
parse_command_line(gint * argc,gchar ** av)95 parse_command_line (gint * argc, gchar ** av)
96 {
97 static gboolean print_version = false;
98 static gchar *active_color_scheme = NULL;
99 static gchar *color_scheme_file = NULL;
100 static gchar *data_mode = NULL;
101 static gchar *initialization_file = NULL;
102 static gboolean quit_with_no_ggobi = true;
103 static gint verbosity = GGOBI_CHATTY;
104 static GOptionEntry entries[] =
105 {
106 {
107 "activeColorScheme", 'c', 0, G_OPTION_ARG_STRING, &active_color_scheme,
108 "name of the default color scheme to use", "scheme"
109 }, {
110 "colorSchemes", 's', 0, G_OPTION_ARG_FILENAME, &color_scheme_file,
111 "name of XML file containing color schemes", "file"
112 }, {
113 "dataMode", 'd', 0, G_OPTION_ARG_STRING, &data_mode,
114 "mode of data supplied on command line", "mode"
115 }, {
116 "init", 'i', 0, G_OPTION_ARG_FILENAME, &initialization_file,
117 "name of initialization file", "file"
118 }, {
119 "keepalive", 'k', G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,
120 &quit_with_no_ggobi, "do not quit GGobi if all windows are closed", NULL,
121 }, {
122 "verbosity", 'l', 0, G_OPTION_ARG_INT, &verbosity,
123 "verbosity of GGobi, 0 = silent, 1 = chatty (default), 2 = verbose", "level"
124 }, {
125 "version", 'v', 0, G_OPTION_ARG_NONE, &print_version,
126 "print the GGobi version and exit", NULL
127 }, { NULL }
128 };
129
130 GError *error = NULL;
131 GOptionContext *ctx = g_option_context_new("- platform for interactive graphics");
132
133 g_option_context_add_main_entries (ctx, entries, PACKAGE);
134 g_option_context_add_group (ctx, gtk_get_option_group (TRUE));
135 g_option_group_set_translation_domain (g_option_context_get_main_group (ctx), PACKAGE);
136 g_option_context_parse (ctx, argc, &av, &error);
137
138 if (error) {
139 g_printerr ("Error parsing command line: %s\n", error->message);
140 exit(0);
141 }
142
143 if (print_version) {
144 g_printerr ("%s\n", GGOBI (getVersionString ()));
145 exit(0);
146 }
147
148 sessionOptions->activeColorScheme = active_color_scheme;
149 if (color_scheme_file)
150 sessionOptions->info->colorSchemeFile = color_scheme_file;
151 sessionOptions->data_type = data_mode;
152 sessionOptions->initializationFile = initialization_file;
153 sessionOptions->info->quitWithNoGGobi = quit_with_no_ggobi;
154 sessionOptions->verbose = verbosity;
155
156 (*argc)--;
157 av++;
158
159 /*
160 * Test the values
161 */
162
163 if (*argc == 0)
164 sessionOptions->data_in = NULL;
165 else
166 sessionOptions->data_in = g_strdup (av[0]);
167
168 g_option_context_free(ctx);
169
170 return 1;
171 }
172
173 gint
ggobi_remove(ggobid * gg)174 ggobi_remove (ggobid * gg)
175 {
176 gint i;
177 for (i = 0; i < num_ggobis; i++) {
178 if (all_ggobis[i] == gg) {
179 return (ggobi_remove_by_index (gg, i));
180 }
181 }
182
183 return (-1);
184 }
185
186 /*
187 Also, need to close and free the displays associated with the ggobi.
188 */
189 gint
ggobi_remove_by_index(ggobid * gg,gint which)190 ggobi_remove_by_index (ggobid * gg, gint which)
191 {
192 GSList *l;
193 GGobiData *d;
194 gint numDatasets, i;
195
196 /* Move all the entries after the one being removed
197 down by one in the array to compact it.
198 */
199 if (which < num_ggobis - 1) {
200 memcpy (all_ggobis + which,
201 all_ggobis + which +
202 1, sizeof (ggobid *) * (num_ggobis - which - 1));
203 }
204 /* Now patch up the array so that it has the correct number of elements. */
205 num_ggobis--;
206 if (num_ggobis > 0)
207 all_ggobis = (ggobid **)
208 g_realloc (all_ggobis, sizeof (ggobid *) * num_ggobis);
209 else
210 all_ggobis = NULL;
211
212 /*
213 This was crashing in R. Probably because when we exhaust the list
214 and remove the final element, we get back garbage.
215 This isn't a problem in stand-alone as it never gets called.
216 */
217 numDatasets = g_slist_length (gg->d);
218 for (i = 0, l = gg->d; l != NULL && i < numDatasets; i++, l = gg->d) {
219 d = (GGobiData *) l->data;
220 datad_free (d, gg);
221 gg->d = g_slist_remove (gg->d, d);
222 }
223
224 g_object_unref (G_OBJECT (gg));
225 /* gtk_object_destroy(GTK_OBJECT(gg)); */
226 /* g_free (gg); */
227
228 return (which);
229 }
230
231 /*
232 The code within the TEST_KEYS sections performs a test of handling key presses on
233 the numbered keys. It registers a function
234 */
235 #ifdef TEST_KEYS
236 gboolean
DummyKeyTest(guint keyval,GtkWidget * w,GdkEventKey * event,cpaneld * cpanel,splotd * sp,ggobid * gg,void * userData)237 DummyKeyTest (guint keyval, GtkWidget * w, GdkEventKey * event,
238 cpaneld * cpanel, splotd * sp, ggobid * gg, void *userData)
239 {
240 static gint count = 0;
241 fprintf (stderr, "Key press event (count = %d): key = %d, data = %s\n",
242 count, (gint) keyval, (gchar *) userData);
243 fflush (stderr);
244
245 if (++count == 4) {
246 count = 0;
247 GGOBI (removeNumberedKeyEventHandler) (gg);
248 }
249 return (true);
250 }
251 #endif
252
253 /**
254 Find the color scheme element in the list with the specified
255 name.
256 */
257 colorschemed *
findColorSchemeByName(GList * schemes,const gchar * name)258 findColorSchemeByName (GList * schemes, const gchar * name)
259 {
260 colorschemed *s;
261 gint i, n;
262
263 n = g_list_length (schemes);
264 for (i = 0; i < n; i++) {
265 s = (colorschemed *) g_list_nth_data (schemes, i);
266 if (strcmp (name, s->name) == 0)
267 return (s);
268 }
269 return (NULL);
270 }
271
272 ggobid * /*XXX should be void. Change when gtk-object setup settles. */
ggobi_alloc(ggobid * tmp)273 ggobi_alloc (ggobid * tmp)
274 {
275 if (tmp == NULL) {
276 /* Should never happen in new GObject-based version.
277 tmp = (ggobid*) g_malloc (sizeof (ggobid));
278 memset (tmp, '\0', sizeof (ggobid));
279 */
280 tmp = g_object_new (GGOBI_TYPE_GGOBI, NULL);
281 }
282
283 tmp->firsttime = true;
284 tmp->brush.firsttime = true;
285
286 tmp->d = NULL;
287 tmp->displays = NULL;
288 tmp->current_display = NULL;
289
290 /*-- initialize to NULLMODE and check for ncols later --*/
291 tmp->pmode = NULL_PMODE;
292 tmp->pmode_prev = NULL_PMODE;
293 tmp->imode = NULL_IMODE;
294 tmp->imode_prev = NULL_IMODE;
295 /*-- --*/
296
297 /*-- initialize main window, tool windows to NULL --*/
298 tmp->main_window = NULL;
299 tmp->display_tree.window = NULL;
300 tmp->vartable_ui.window = NULL;
301 tmp->sphere_ui.window = NULL;
302 tmp->cluster_ui.window = NULL;
303 tmp->color_ui.symbol_window = NULL;
304 /*-- --*/
305
306 tmp->color_ui.margin = 10;
307 tmp->tour2d.idled = 0;
308 tmp->tour1d.idled = 0;
309 tmp->tourcorr.idled = 0;
310 tmp->tour1d.fade_vars = true;
311 tmp->tour2d.fade_vars = true;
312 tmp->tourcorr.fade_vars = true;
313 tmp->tour1d.all_vars = false;
314 tmp->tour2d.all_vars = false;
315 // tmp->brush.updateAlways_p = true;
316
317 tmp->tour2d3.idled = 0;
318
319 tmp->printOptions = NULL;
320 tmp->pluginInstances = NULL;
321
322 tmp->plot_GC = NULL;
323
324
325 tmp->colorSchemes = sessionOptions->colorSchemes;
326 if (sessionOptions->activeColorScheme)
327 tmp->activeColorScheme = findColorSchemeByName (tmp->colorSchemes,
328 sessionOptions->
329 activeColorScheme);
330 else {
331 /*-- use "Set1 9" by default, if it's present --*/
332 sessionOptions->activeColorScheme = "Set1 9";
333 tmp->activeColorScheme = findColorSchemeByName (tmp->colorSchemes,
334 sessionOptions->
335 activeColorScheme);
336 if (!tmp->activeColorScheme)
337 tmp->activeColorScheme = (colorschemed *)
338 g_list_nth_data (tmp->colorSchemes, 0);
339 }
340 if (!tmp->activeColorScheme) {
341 g_error ("failed to find color scheme");
342 }
343 else
344 colorscheme_init (tmp->activeColorScheme);
345 /*
346 * the number of colors in use will be tested against the
347 * scheme->n the first time we plot, and the color ids will
348 * be adjusted if necessary.
349 */
350
351 totalNumGGobis++;
352
353 all_ggobis = (ggobid **)
354 g_realloc (all_ggobis, sizeof (ggobid *) * (num_ggobis + 1));
355 all_ggobis[num_ggobis] = tmp;
356 num_ggobis++;
357
358 #ifdef TEST_KEYS
359 GGOBI (registerNumberedKeyEventHandler) (DummyKeyTest,
360 g_strdup
361 ("A string for the key handler"),
362 "Test handler", NULL, tmp, C);
363 #endif
364
365 g_signal_emit_by_name (G_OBJECT (ggobiApp), "new_ggobi", tmp);
366
367 return (tmp);
368 }
369
370 void
ggobiInit(int * argc,char ** argv[])371 ggobiInit (int *argc, char **argv[])
372 {
373
374
375 if (ExtendedDisplayTypes)
376 return;
377
378 gtk_init (argc, argv);
379
380 ggobiApp = g_object_new (GGOBI_TYPE_APP, NULL);
381
382 #ifdef TEST_GGOBI_APPP
383 /*XXX FIX */
384 GGOBI (registerNumberedKeyEventHandler) (DummyKeyTest,
385 g_strdup
386 ("A string for the key handler"),
387 "Test handler", NULL, tmp, C);
388 #endif
389
390 initSessionOptions (*argc, *argv);
391
392 plugin_init ();
393
394 GGOBI_TYPE_GGOBI;
395 registerDisplayTypes ((GTypeLoad *) typeLoaders,
396 sizeof (typeLoaders) / sizeof (typeLoaders)[0]);
397
398 registerDefaultPlugins (sessionOptions->info);
399 }
400
401
402 /* Available so that we can call this from R
403 without any confusion between which main().
404 */
GGOBI(main)405 gint GGOBI (main) (gint argc, gchar * argv[], gboolean processEvents)
406 {
407 GdkVisual *vis;
408 ggobid *gg;
409
410 bindtextdomain (PACKAGE, GGOBI_LOCALEDIR);
411 bind_textdomain_codeset (PACKAGE, "UTF-8");
412 textdomain (PACKAGE);
413
414 ggobiInit (&argc, &argv);
415
416 vis = gdk_visual_get_system ();
417
418 parse_command_line (&argc, argv);
419
420 process_initialization_files ();
421
422 if (sessionOptions->verbose == GGOBI_VERBOSE)
423 g_printerr ("progname = %s\n", g_get_prgname ());
424
425 if (sessionOptions->verbose == GGOBI_VERBOSE)
426 g_printerr ("data_in = %s\n", sessionOptions->data_in);
427
428 if (DefaultPrintHandler.callback == NULL)
429 setStandardPrintHandlers ();
430
431 if (sessionOptions->info->colorSchemeFile
432 && sessionOptions->colorSchemes == NULL) {
433 read_colorscheme (sessionOptions->info->colorSchemeFile,
434 &sessionOptions->colorSchemes);
435 }
436
437 if (sessionOptions->colorSchemes == NULL) {
438 colorschemed *scheme = default_scheme_init ();
439 sessionOptions->colorSchemes =
440 g_list_append (sessionOptions->colorSchemes, scheme);
441 sessionOptions->activeColorScheme = scheme->name;
442 }
443
444
445 gg = g_object_new (GGOBI_TYPE_GGOBI, NULL);
446
447 gg->mono_p = (vis->depth == 1 ||
448 vis->type == GDK_VISUAL_STATIC_GRAY ||
449 vis->type == GDK_VISUAL_GRAYSCALE);
450
451 make_ggobi (sessionOptions, processEvents, gg);
452
453 /* g_free (sessionOptions->data_in); */
454
455 return (num_ggobis);
456 }
457
458 /*XX
459 This might usefully be changed to workd directly from the
460 XML tree and avoid having the GGobiDisplayDescription.
461 As we include more information (e.g. brushing information)
462 we end up copying it for little reason.
463 However, this works for the restore file, but not necessarily
464 the initialization file as we won't have created the ggobid
465 when we read that. We could just re-parse the file and find the
466 appropriate node. Probably the wisest.
467 */
468 gboolean
processRestoreFile(const gchar * const fileName,ggobid * gg)469 processRestoreFile (const gchar * const fileName, ggobid * gg)
470 {
471 xmlDocPtr doc;
472 xmlNodePtr node;
473 GGobiDescription desc;
474 GList *el;
475 doc = xmlParseFile (fileName);
476 if (!doc)
477 return (false);
478
479 node = xmlDocGetRootElement (doc);
480
481 if (!node)
482 return (false);
483
484 getPreviousDisplays (node, &desc);
485
486 el = desc.displays;
487 while (el) {
488 displayd *dpy;
489 GGobiDisplayDescription *dpyDesc;
490 dpyDesc = (GGobiDisplayDescription *) el->data;
491 dpy = createDisplayFromDescription (gg, dpyDesc);
492 /*XX free dpyDesc here and remove from list. */
493 el = el->next;
494 }
495
496 xmlFreeDoc (doc);
497
498 return (true);
499 }
500
501 /*
502 Computes where GGobi directory is located.
503 Search order: $GGOBI_HOME or 'str' stripped of file
504 */
505 static gchar *
computeGGobiHome(char * str)506 computeGGobiHome (char *str)
507 {
508 gchar *dir;
509 const gchar *env;
510
511 env = g_getenv ("GGOBI_HOME");
512
513 if (env)
514 dir = g_strdup (env);
515 else
516 dir = g_path_get_dirname (str);
517
518 return (dir);
519 }
520
521 void
initSessionOptions(int argc,char ** argv)522 initSessionOptions (int argc, char **argv)
523 {
524 gchar *tmp;
525 sessionOptions = &sessionoptions;
526 sessionOptions->data_mode = unknown_data;
527
528 sessionOptions->showControlPanel = true;
529 sessionOptions->verbose = GGOBI_CHATTY;
530
531 sessionOptions->cmdArgs = argv;
532 sessionOptions->numArgs = argc;
533
534 sessionOptions->ggobiHome = computeGGobiHome (argv[0]);
535
536
537 sessionOptions->info = (GGobiInitInfo *) g_malloc0 (sizeof (GGobiInitInfo));
538 sessionOptions->info->glyph.size = sessionOptions->info->glyph.type = -1;
539 sessionOptions->info->createInitialScatterPlot = true;
540 sessionOptions->info->allowCloseLastDisplay = false;
541 sessionOptions->info->quitWithNoGGobi = true;
542 sessionOptions->info->numScatMatrixVars = MAXNVARS;
543 sessionOptions->info->numParCoordsVars = MAXNPCPLOTS;
544 sessionOptions->info->numTimePlotVars = MAXNTSPLOTS;
545
546 sessionOptions->useRadioMenuItems = false;
547
548 tmp = g_build_filename("share", "colorschemes.xml", NULL);
549 sessionOptions->info->colorSchemeFile = ggobi_find_data_file(tmp);
550 g_free(tmp);
551
552 sessionOptions->defaultTourSpeed = 50.0;
553 sessionOptions->defaultTour1dSpeed = 40.0;
554 }
555
556 gboolean
ggobi_close(ggobid * gg)557 ggobi_close (ggobid * gg)
558 {
559 GGOBI (close) (gg, true);
560 return (true);
561 }
562
563
564 /*
565 Key for storing a reference to a ggobid instance in a widget
566 so that we can retrieve it within a callback.
567 */
568 static const gchar *GGobiGTKey = "GGobi";
569
570 const gchar *
key_get(void)571 key_get (void)
572 {
573 return GGobiGTKey;
574 }
575
576 /*
577 Computes the ggobid pointer associated with the specified
578 widget. It does so by looking in the window associated with the widget
579 and then looking for an entry in the window's association table.
580 This assumes that the ggobid reference was stored in the window
581 when it was created.
582 */
583 ggobid *
GGobiFromWidget(GtkWidget * w,gboolean useWindow)584 GGobiFromWidget (GtkWidget * w, gboolean useWindow)
585 {
586 ggobid *gg = NULL;
587 GObject *obj;
588 obj = g_object_get_data (G_OBJECT (w), GGobiGTKey);
589 if (obj) {
590 gg = (ggobid *) obj;
591 ValidateGGobiRef (gg, true);
592 }
593
594 return (gg);
595 }
596
597 ggobid *
GGobiFromWindow(GdkWindow * win)598 GGobiFromWindow (GdkWindow * win)
599 {
600 ggobid *gg = NULL;
601 GObject *obj;
602 obj = g_object_get_data (G_OBJECT (win), GGobiGTKey);
603 if (obj) {
604 gg = (ggobid *) obj;
605 ValidateGGobiRef (gg, true);
606 }
607
608 return (gg);
609 }
610
611 ggobid *
GGobiFromSPlot(splotd * sp)612 GGobiFromSPlot (splotd * sp)
613 {
614 ggobid *gg = NULL;
615 displayd *display = NULL;
616 if ((sp) && sp->displayptr) {
617 display = (displayd *) sp->displayptr;
618 if (display) {
619 gg = ValidateGGobiRef (display->ggobi, false);
620 }
621 }
622 return gg;
623 }
624
625 ggobid *
GGobiFromDisplay(displayd * display)626 GGobiFromDisplay (displayd * display)
627 {
628 return (display->ggobi);
629 }
630
631 void
GGobi_widget_set(GtkWidget * w,ggobid * gg,gboolean asIs)632 GGobi_widget_set (GtkWidget * w, ggobid * gg, gboolean asIs)
633 {
634 GtkWidget *wid = w;
635 if (!asIs)
636 wid = GTK_WIDGET (gtk_widget_get_parent_window (wid));
637
638 g_object_set_data (G_OBJECT (wid), GGobiGTKey, gg);
639 }
640
641
642 ggobid *
ggobi_get(gint which)643 ggobi_get (gint which)
644 {
645 extern ggobid **all_ggobis;
646 if (which > -1 && which < num_ggobis)
647 return (all_ggobis[which]);
648 else
649 return (NULL);
650 }
651
652 gint
ggobi_getIndex(ggobid * gg)653 ggobi_getIndex (ggobid * gg)
654 {
655 gint i;
656 for (i = 0; i < num_ggobis; i++) {
657 if (all_ggobis[i] == gg)
658 return (i);
659 }
660
661 return (-1);
662 }
663
664 GGobiData *
GGobi_get_data(gint which,const ggobid * const gg)665 GGobi_get_data (gint which, const ggobid * const gg)
666 {
667 GGobiData *d;
668 d = g_slist_nth_data (gg->d, which);
669
670 return (d);
671 }
672
673 GGobiData *
GGobi_get_data_by_name(const gchar * const name,const ggobid * const gg)674 GGobi_get_data_by_name (const gchar * const name, const ggobid * const gg)
675 {
676 GGobiData *d;
677 GSList *l;
678
679 for (l = gg->d; l; l = l->next) {
680 d = (GGobiData *) l->data;
681 if (strcmp (d->name, name) == 0)
682 return (d);
683 }
684 return (NULL);
685 }
686
687
688 ggobid *
ValidateGGobiRef(ggobid * gg,gboolean fatal)689 ValidateGGobiRef (ggobid * gg, gboolean fatal)
690 {
691 static gchar *error_msg = "Incorrect reference to ggobid.";
692 extern ggobid **all_ggobis;
693 extern gint num_ggobis;
694 gint i;
695 for (i = 0; i < num_ggobis; i++) {
696 if (all_ggobis[i] == gg)
697 return (gg);
698 }
699
700 if (fatal) {
701 g_error ("%s", error_msg);
702 }
703 else
704 g_critical ("%s", error_msg);
705
706 return (NULL);
707 }
708
709 GGobiData *
ValidateDatadRef(GGobiData * d,ggobid * gg,gboolean fatal)710 ValidateDatadRef (GGobiData * d, ggobid * gg, gboolean fatal)
711 {
712 static gchar *error_msg = "Incorrect reference to datad.";
713 gint i, n;
714 n = g_slist_length (gg->d);
715 for (i = 0; i < n; i++) {
716 if (g_slist_nth_data (gg->d, i) == d)
717 return (d);
718 }
719
720 if (fatal)
721 g_error ("%s", error_msg);
722 else
723 g_critical ("%s", error_msg);
724
725 return (NULL);
726 }
727
728
729
730 displayd *
ValidateDisplayRef(displayd * d,ggobid * gg,gboolean fatal)731 ValidateDisplayRef (displayd * d, ggobid * gg, gboolean fatal)
732 {
733 static gchar *error_msg = "Incorrect reference to display.";
734 gint i, n;
735 n = g_list_length (gg->displays);
736 for (i = 0; i < n; i++) {
737 if (g_list_nth_data (gg->displays, i) == d)
738 return (d);
739 }
740
741 if (fatal)
742 g_error ("%s", error_msg);
743 else
744 g_critical ("%s", error_msg);
745
746 return (NULL);
747 }
748
749 static gchar *
ggobi_find_file_in_dir(const gchar * name,const gchar * dir,gboolean ggobi)750 ggobi_find_file_in_dir(const gchar *name, const gchar *dir, gboolean ggobi)
751 {
752 gchar *tmp_name = g_build_filename(dir, ggobi ? "ggobi" : "", name, NULL);
753 if (file_is_readable(tmp_name))
754 return(tmp_name);
755 g_free(tmp_name);
756 return(NULL);
757 }
758
759 #ifdef WIN32
760 static gchar*
ggobi_win32_get_localedir()761 ggobi_win32_get_localedir()
762 {
763 static char *ggobi_localedir = NULL;
764 if (ggobi_localedir == NULL) {
765 gchar *temp, *path;
766
767 temp = g_win32_get_package_installation_directory_of_module (NULL);
768 path = g_build_path (temp, "locale");
769 g_free (temp);
770
771 /* ggobi_localedir is passed to bindtextdomain() which isn't
772 * UTF-8-aware.
773 */
774 ggobi_localedir = g_win32_locale_filename_from_utf8 (path);
775 g_free (path);
776 }
777 return ggobi_localedir;
778 }
779
780 static gchar*
ggobi_win32_get_packagedir()781 ggobi_win32_get_packagedir()
782 {
783 static char *ggobi_datadir = NULL;
784 if (ggobi_datadir == NULL)
785 ggobi_datadir = g_win32_get_package_installation_directory_of_module (NULL);
786 return(ggobi_datadir);
787 }
788 #endif
789
790 static gchar *
ggobi_find_file(const gchar * name,const gchar * user,const gchar * const * dirs)791 ggobi_find_file(const gchar *name, const gchar* user, const gchar* const *dirs)
792 {
793 gchar *tmp_name, *cur_dir = g_get_current_dir();
794 gint i;
795
796 //g_debug("Looking for %s", name);
797 if (sessionOptions && sessionOptions->ggobiHome) {
798 tmp_name = ggobi_find_file_in_dir(name, sessionOptions->ggobiHome, false);
799 if (tmp_name)
800 return(tmp_name);
801 }
802
803 tmp_name = ggobi_find_file_in_dir(name, cur_dir, false);
804 g_free(cur_dir);
805 if (tmp_name)
806 return(tmp_name);
807
808 tmp_name = ggobi_find_file_in_dir(name, user, true);
809 if (tmp_name)
810 return(tmp_name);
811
812 for (i = 0; dirs[i]; i++) {
813 tmp_name = ggobi_find_file_in_dir(name, dirs[i], true);
814 if (tmp_name)
815 return(tmp_name);
816 }
817
818 #ifdef WIN32
819 tmp_name = ggobi_find_file_in_dir(name, ggobi_win32_get_packagedir(), false);
820 if (tmp_name)
821 return(tmp_name);
822 #endif
823
824 return(NULL);
825 }
826
827 /* Looks in (by default, XDG environment can override some of these):
828 $GGOBI_HOME
829 Current directory
830 $HOME/.local/share/ggobi (Windows: Documents, Application Data for user)
831 $prefix/share/ggobi (Windows: GGobi installation directory)
832 */
833 gchar*
ggobi_find_data_file(const gchar * name)834 ggobi_find_data_file(const gchar *name)
835 {
836 const gchar* data_dirs[] = { GGOBI_DATADIR, NULL };
837 gchar *path = ggobi_find_file(name, g_get_user_data_dir(), data_dirs);
838 //g_debug("Found data file: %s", path);
839 return(path);
840 }
841 /* Looks in (by default, XDG environment can override some of these):
842 $GGOBI_HOME
843 Current directory
844 $HOME/.config/ggobi (Windows: Documents, Application Data for user)
845 /etc/xdg/ggobi (Windows: Documents, Application Data for All Users)
846 (Windows: GGobi installation directory)
847 */
848 gchar*
ggobi_find_config_file(const gchar * name)849 ggobi_find_config_file(const gchar *name)
850 {
851 gchar *path = ggobi_find_file(name, g_get_user_config_dir(), g_get_system_config_dirs());
852 //g_debug("Found config file: %s", path);
853 return(path);
854 }
855
856 /*
857 Determines which initialization file to use
858 Checks for the one specified by
859 1) the -init command line option
860 2) the GGOBIRC environment variable
861 3) the $HOME/.ggobirc file.
862 4) user and system GGobi config dirs
863 */
864 void
process_initialization_files()865 process_initialization_files ()
866 {
867 GGobiInitInfo *info;
868 gchar *fileName = NULL;
869
870 if (sessionOptions->initializationFile)
871 fileName = g_strdup (sessionOptions->initializationFile);
872 else {
873 fileName = g_strdup (g_getenv ("GGOBIRC"));
874 if (!fileName || !fileName[0]) {
875 const gchar *tmp;
876 tmp = g_get_home_dir ();
877 if (tmp) {
878 fileName = g_build_filename (tmp, ".ggobirc", NULL);
879 if (!file_is_readable (fileName)) {
880 g_free (fileName);
881 fileName = NULL;
882 }
883 }
884 if (!fileName)
885 fileName = ggobi_find_config_file("ggobirc");
886 }
887 if (fileName)
888 sessionOptions->initializationFile = g_strdup (fileName);
889 }
890
891 if (fileName && fileName[0] && file_is_readable (fileName)) {
892 info = read_init_file (fileName, sessionOptions->info);
893 g_free (fileName);
894 /* sessionOptions->info = info; */
895 }
896
897 if (sessionOptions->pluginFiles) {
898 GSList *el = sessionOptions->pluginFiles;
899 while (el) {
900 readPluginFile ((char *) el->data, sessionOptions->info);
901 el = el->next;
902 }
903 }
904 }
905
906 GGobiOptions *
GGOBI_getSessionOptions()907 GGOBI_getSessionOptions ()
908 {
909 return (sessionOptions);
910 }
911
912
913 /* This includes code that provides information about the
914 sizes of the data structures in GGobi when it was compiled.
915 */
916
917 #define GGOBI_MAIN 1
918 #include "GGStructSizes.c"
919
920 gint
ndatad_with_vars_get(ggobid * gg)921 ndatad_with_vars_get (ggobid *gg)
922 {
923 gint nd;
924 GSList *l;
925 GGobiData *d;
926
927 /*-- silly to do this every time, perhaps, but harmless, I think --*/
928 if (g_slist_length (gg->d) > 1) {
929 nd = 0;
930 for (l = gg->d; l; l = l->next) {
931 d = (GGobiData *) l->data;
932 if (g_slist_length (d->vartable) > 0)
933 nd++;
934 }
935 } else nd = 1;
936
937 return nd;
938 }
939
940