Take page as input and take advantage of s_visit_page.
[geda-gaf/berndj.git] / gschem / src / gschem.c
blob5f6ef7cd618c29e671b71d3b855570e598eb7742
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2007 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 #include <config.h>
22 #include <stdio.h>
23 #ifdef HAVE_STRING_H
24 #include <string.h>
25 #endif
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #if DEBUG
30 #include <signal.h>
31 #endif
33 #include <glib.h>
35 #include "gschem.h"
36 #include "support.h"
38 #ifdef HAVE_LIBDMALLOC
39 #include <dmalloc.h>
40 #endif
42 #ifdef HAVE_LOCALE_H
43 #include <locale.h>
44 #endif
46 typedef struct {
47 gschem_atexit_func func;
48 gpointer arg;
49 } gschem_atexit_struct;
51 static GList *exit_functions = NULL;
53 /*! \brief Register a function to be called on program exit
55 * \par Function Description
56 * This function registers a function to be called on
57 * program exit. Multiple functions will be executed in
58 * the order they are registered.
60 * \param [in] func a pointer to the function to be registered
61 * \param [in] data an arbitrary argument provided to the function
62 * when it is called
64 void gschem_atexit(gschem_atexit_func func, gpointer data)
66 gschem_atexit_struct *p;
68 p = g_new(gschem_atexit_struct, 1);
69 p->func = func;
70 p->arg = data;
71 exit_functions = g_list_append(exit_functions, p);
74 /*! \brief Cleanup gSchem on exit.
75 * \par Function Description
76 * This function cleans up all memory objects allocated during the
77 * gSchem runtime.
79 void gschem_quit(void)
81 GList *list;
82 gschem_atexit_struct *p;
84 /* Call all registered functions in order */
85 list = exit_functions;
86 while(list != NULL) {
87 p = (gschem_atexit_struct *) list->data;
88 p->func(p->arg);
89 g_free(p);
90 list = g_list_next(list);
92 g_list_free(exit_functions);
94 s_clib_free();
95 s_slib_free();
96 s_menu_free();
97 /* o_text_freeallfonts();*/
98 s_attrib_free();
99 s_papersizes_free();
100 #ifdef HAS_LIBSTROKE
101 x_stroke_free ();
102 #endif /* HAS_LIBSTROKE */
103 s_color_destroy_all();
104 o_undo_cleanup();
105 /* s_stroke_free(); no longer needed */
107 i_vars_freedefaults();
108 i_vars_libgeda_freenames();
109 libgeda_fini();
111 /* x_window_free_head(); can't do this since it causes a
112 * condition in which window_head->... is still being referenced
113 * after this */
115 /* enable this to get more memory usage from glib */
116 /* You also have to enable something in glib I think */
117 /* g_mem_profile();*/
120 gtk_main_quit();
123 #if DEBUG
124 GSCHEM_TOPLEVEL *w_current_global = NULL;
125 void sig_handler_int(int sig)
127 void s_slot_dumpall(TOPLEVEL *toplevel);
128 if (w_current_global) {
129 s_slot_dumpall(w_current_global->toplevel);
132 #endif
134 /*! \brief Main Scheme(GUILE) program function.
135 * \par Function Description
136 * This function is the main program called from scm_boot_guile.
137 * It handles initializing all libraries and gSchem variables
138 * and passes control to the gtk main loop.
140 void main_prog(void *closure, int argc, char *argv[])
142 int i;
143 char *cwd = NULL;
144 GSCHEM_TOPLEVEL *w_current = NULL;
145 char *input_str = NULL;
146 int argv_index;
147 int first_page = 1;
148 char *geda_data = NULL;
149 char *filename;
150 gboolean save_grid;
151 SCM scm_tmp;
153 #ifdef HAVE_GTHREAD
154 /* Gschem isn't threaded, but some of GTK's file chooser
155 * backends uses threading so we need to call g_thread_init().
156 * GLib requires threading be initialised before any other GLib
157 * functions are called. Do it now if its not already setup. */
158 if (!g_thread_supported ()) g_thread_init (NULL);
159 #endif
161 #if ENABLE_NLS
162 /* this should be equivalent to setlocale (LC_ALL, "") */
163 gtk_set_locale();
165 /* This must be the same for all locales */
166 setlocale(LC_NUMERIC, "POSIX");
168 /* Disable gtk's ability to set the locale. */
169 /* If gtk is allowed to set the locale, then it will override the */
170 /* setlocale for LC_NUMERIC (which is important for proper PS output. */
171 /* This may look funny here, given we make a call to gtk_set_locale() */
172 /* above. I don't know yet, if this is really the right thing to do. */
173 gtk_disable_setlocale();
175 #endif
177 gtk_init(&argc, &argv);
179 argv_index = parse_commandline(argc, argv);
180 cwd = g_get_current_dir();
182 libgeda_init(TRUE);
184 /* Install various libgeda callbacks */
185 arc_draw_func = o_arc_draw;
186 box_draw_func = o_box_draw;
187 bus_draw_func = o_bus_draw;
188 circle_draw_func = o_circle_draw;
189 complex_draw_func = o_complex_draw;
190 line_draw_func = o_line_draw;
191 net_draw_func = o_net_draw;
192 picture_draw_func = o_picture_draw;
193 path_draw_func = o_path_draw;
194 pin_draw_func = o_pin_draw;
195 slot_draw_func = &o_slot_draw;
196 text_draw_func = o_text_draw;
197 load_newer_backup_func = x_fileselect_load_backup;
199 #ifndef USE_LIBGLADE
200 add_pixmap_directory(GEDADATADIR "/glade");
201 #endif
203 /*! \todo Probably the file name should be defined elsewhere */
204 /* create log file right away even if logging is enabled */
205 filename = g_build_filename (cwd, "gschem.log", NULL);
206 s_log_init (filename);
207 g_free (filename);
209 s_log_message(
210 _("gEDA/gschem version %s%s.%s\n"), PREPEND_VERSION_STRING,
211 DOTTED_VERSION, DATE_VERSION);
212 s_log_message(
213 _("gEDA/gschem comes with ABSOLUTELY NO WARRANTY; see COPYING for more details.\n"));
214 s_log_message(
215 _("This is free software, and you are welcome to redistribute it under certain\n"));
216 s_log_message(
217 _("conditions; please see the COPYING file for more details.\n\n"));
219 if (!quiet_mode) {
220 fprintf(stderr,
221 _("gEDA/gschem version %s%s.%s\n"), PREPEND_VERSION_STRING,
222 DOTTED_VERSION, DATE_VERSION);
223 fprintf(stderr,
224 _("gEDA/gschem comes with ABSOLUTELY NO WARRANTY; see COPYING for more details.\n"));
225 fprintf(stderr,
226 _("This is free software, and you are welcome to redistribute it under certain\n"));
227 fprintf(stderr,
228 _("conditions; please see the COPYING file for more details.\n\n"));
231 #ifdef __MINGW32__
232 fprintf(stderr, _("This is the MINGW32 port.\n"));
233 #endif
235 #if DEBUG
236 fprintf(stderr, _("Current locale settings: %s\n"), setlocale(LC_ALL, NULL));
237 #endif
239 /* init global buffers */
240 o_buffer_init();
242 /* register guile (scheme) functions */
243 g_register_funcs();
245 o_undo_init();
247 geda_data = getenv("GEDADATA");
248 if (geda_data == NULL) {
249 fprintf(stderr, _("You must set the GEDADATA environment variable!\n"));
250 exit(-1);
253 /* Allocate w_current */
254 w_current = gschem_toplevel_new ();
255 w_current->toplevel = s_toplevel_new ();
256 x_set_window_current(w_current);
258 #if DEBUG
259 w_current_global = w_current;
260 signal(SIGQUIT, &sig_handler_int);
261 #endif
263 /* Now read in RC files. */
264 g_rc_parse_gtkrc();
265 g_rc_parse(w_current->toplevel, "gschemrc", rc_filename);
267 /* By this point, libgeda should have setup the Guile load path, so
268 * we can take advantage of that. */
269 scm_tmp = scm_sys_search_load_path (scm_from_locale_string ("gschem.scm"));
270 if (scm_is_false (scm_tmp)) {
271 s_log_message (_("Couldn't find init scm file [%s]\n"), "gschem.scm");
273 scm_dynwind_begin(0);
274 input_str = scm_to_locale_string (scm_tmp);
275 scm_dynwind_free(input_str);
276 if (g_read_file(input_str) != -1) {
277 s_log_message(_("Read init scm file [%s]\n"), input_str);
278 } else {
279 /*! \todo These two messages are the same. Should be
280 * integrated. */
281 s_log_message(_("Failed to read init scm file [%s]\n"),
282 input_str);
284 scm_dynwind_end();
285 scm_remember_upto_here_1 (scm_tmp);
287 /* Load recent files list. This must be done
288 * before calling x_window_setup(). */
289 recent_files_load();
290 gschem_atexit(recent_files_save, NULL);
292 /* Set default icon */
293 x_window_set_default_icon();
295 /* At end, complete set up of window. */
296 colormap = gdk_colormap_get_system ();
297 x_color_init();
298 x_window_setup (w_current);
300 /* Repaint the background in-case we have to throw up a "restore backup?"
301 * dialog box. Disable grid drawing as there is no page loaded, hence no
302 * scale factor to draw the grid at. (gschem will segfault otherwise.)
304 save_grid = w_current->grid;
305 w_current->grid = FALSE;
306 x_repaint_background (w_current);
307 w_current->grid = save_grid;
309 #ifdef HAS_LIBSTROKE
310 x_stroke_init ();
311 #endif /* HAS_LIBSTROKE */
313 for (i = argv_index; i < argc; i++) {
315 if (g_path_is_absolute(argv[i]))
317 /* Path is already absolute so no need to do any concat of cwd */
318 filename = g_strdup (argv[i]);
319 } else {
320 filename = g_build_filename (cwd, argv[i], NULL);
323 if ( first_page )
324 first_page = 0;
327 * SDB notes: at this point the filename might be unnormalized, like
328 * /path/to/foo/../bar/baz.sch. Bad filenames will be normalized in
329 * f_open (called by x_window_open_page). This works for Linux and MINGW32.
331 x_window_open_page(w_current, filename);
332 g_free (filename);
335 g_free(cwd);
337 /* If no page has been loaded (wasn't specified in the command line.) */
338 /* Then create an untitled page */
339 if ( first_page ) {
340 x_window_open_page( w_current, NULL );
343 /* Update the window to show the current page */
344 x_window_set_current_page( w_current, w_current->toplevel->page_current );
347 #if DEBUG
348 scm_c_eval_string ("(display \"hello guile\n\")");
349 #endif
351 if (w_current->toplevel->scheme_directory == NULL) {
352 fprintf(stderr, _("Scheme directory NOT set!\n"));
353 exit(-1);
357 /* Execute a script if it exists */
358 if (script_filename) {
359 s_log_message(_("Executing guile script [%s]\n"),
360 script_filename);
361 g_read_file(script_filename);
364 /* open up log window on startup */
365 if (w_current->log_window == MAP_ON_STARTUP) {
366 x_log_open ();
369 /* if there were any symbols which had major changes, put up an error */
370 /* dialog box */
371 major_changed_dialog(w_current);
373 /* enter main loop */
374 gtk_main();
377 /*! \brief Main executable entrance point.
378 * \par Function Description
379 * This is the main function for gSchem. It sets up the Scheme(GUILE)
380 * environment and passes control to via scm_boot_guile to
381 * the #main_prog function.
383 int main (int argc, char *argv[])
386 #if ENABLE_NLS
387 setlocale(LC_ALL, "");
388 setlocale(LC_NUMERIC, "POSIX");
389 bindtextdomain(PACKAGE, LOCALEDIR);
390 textdomain(PACKAGE);
391 bind_textdomain_codeset(PACKAGE, "UTF-8");
392 #endif
394 /* disable the deprecated warnings in guile 1.6.3 */
395 /* Eventually the warnings will need to be fixed */
396 if(getenv("GUILE_WARN_DEPRECATED") == NULL)
397 putenv("GUILE_WARN_DEPRECATED=no");
399 /* Doesn't return! */
400 scm_boot_guile (argc, argv, main_prog, 0);
402 return 0;