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