1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #ifdef HAVE_LIBDMALLOC
31 #define GSCHEM_THEME_ICON_NAME "geda-gschem"
33 /*! \todo Finish function documentation!!!
35 * \par Function Description
38 void x_window_setup (GSCHEM_TOPLEVEL
*w_current
)
40 TOPLEVEL
*toplevel
= w_current
->toplevel
;
42 /* immediately setup user params */
43 i_vars_set(w_current
);
45 /* Initialize the autosave callback */
46 s_page_autosave_init(toplevel
);
48 /* Initialize the clipboard callback */
49 x_clipboard_init (w_current
);
51 /* x_window_setup_world() - BEGIN */
52 toplevel
->init_left
= -45;
53 toplevel
->init_top
= -45;
54 /* init_right and _bottom are set before this function is called */
56 toplevel
->width
= default_width
;
57 toplevel
->height
= default_height
;
59 w_current
->win_width
= toplevel
->width
;
60 w_current
->win_height
= toplevel
->height
;
61 /* x_window_setup_world() - END */
63 /* Add to the list of windows */
64 global_window_list
= g_list_append (global_window_list
, w_current
);
67 x_window_create_main (w_current
);
69 x_menu_attach_recent_files_submenu(w_current
);
72 /*! \todo Finish function documentation!!!
74 * \par Function Description
77 void x_window_setup_gc(GSCHEM_TOPLEVEL
*w_current
)
79 w_current
->gc
= gdk_gc_new(w_current
->window
);
81 if (w_current
->gc
== NULL
) {
82 fprintf(stderr
, _("Couldn't allocate gc\n"));
87 /*! \todo Finish function documentation!!!
89 * \par Function Description
92 void x_window_free_gc(GSCHEM_TOPLEVEL
*w_current
)
94 gdk_gc_unref(w_current
->gc
);
97 /*! \todo Finish function documentation!!!
99 * \par Function Description
102 void x_window_create_drawing(GtkWidget
*drawbox
, GSCHEM_TOPLEVEL
*w_current
)
105 w_current
->drawing_area
= gtk_drawing_area_new ();
106 /* Set the size here. Be sure that it has an aspect ratio of 1.333
107 * We could calculate this based on root window size, but for now
108 * lets just set it to:
109 * Width = root_width*3/4 Height = Width/1.3333333333
110 * 1.3333333 is the desired aspect ratio!
113 gtk_drawing_area_size (GTK_DRAWING_AREA (w_current
->drawing_area
),
114 w_current
->win_width
,
115 w_current
->win_height
);
117 gtk_box_pack_start (GTK_BOX (drawbox
), w_current
->drawing_area
,
119 GTK_WIDGET_SET_FLAGS (w_current
->drawing_area
, GTK_CAN_FOCUS
);
120 gtk_widget_grab_focus (w_current
->drawing_area
);
121 gtk_widget_show (w_current
->drawing_area
);
125 /*! \todo Finish function documentation!!!
127 * \par Function Description
130 void x_window_setup_draw_events(GSCHEM_TOPLEVEL
*w_current
)
133 gchar
*detailed_signal
;
137 struct event_reg_t drawing_area_events
[] = {
138 { "expose_event", G_CALLBACK(x_event_expose
) },
139 { "button_press_event", G_CALLBACK(x_event_button_pressed
) },
140 { "button_release_event", G_CALLBACK(x_event_button_released
) },
141 { "motion_notify_event", G_CALLBACK(x_event_motion
) },
142 { "configure_event", G_CALLBACK(x_event_configure
) },
143 { "key_press_event", G_CALLBACK(x_event_key
) },
144 { "key_release_event", G_CALLBACK(x_event_key
) },
146 struct event_reg_t main_window_events
[] = {
147 { "enter_notify_event", G_CALLBACK(x_event_enter
) },
148 { "scroll_event", G_CALLBACK(x_event_scroll
) },
150 struct event_reg_t
*tmp
;
152 /* is the configure event type missing here? hack */
153 gtk_widget_set_events (w_current
->drawing_area
,
155 GDK_POINTER_MOTION_MASK
|
156 GDK_BUTTON_PRESS_MASK
|
157 GDK_ENTER_NOTIFY_MASK
|
159 GDK_BUTTON_RELEASE_MASK
);
161 for (tmp
= drawing_area_events
; tmp
->detailed_signal
!= NULL
; tmp
++) {
162 g_signal_connect (w_current
->drawing_area
,
163 tmp
->detailed_signal
,
168 for (tmp
= main_window_events
; tmp
->detailed_signal
!= NULL
; tmp
++) {
169 g_signal_connect (w_current
->main_window
,
170 tmp
->detailed_signal
,
177 /*! \brief Creates a new GtkImage displaying a GTK stock icon if available.
179 * If a stock GTK icon with the requested name was not found, this function
180 * falls back to the bitmap icons provided in the distribution.
182 * \param stock Name of the stock icon ("new", "open", etc.)
183 * \param w_current Schematic top level
184 * \return Pointer to the new GtkImage object.
186 static GtkWidget
*x_window_stock_pixmap(const char *stock
, GSCHEM_TOPLEVEL
*w_current
)
188 GtkWidget
*wpixmap
= NULL
;
193 GdkWindow
*window
=w_current
->main_window
->window
;
194 GdkColor
*background
=&w_current
->main_window
->style
->bg
[GTK_STATE_NORMAL
];
196 gchar
*filename
=g_strconcat(w_current
->toplevel
->bitmap_directory
,
198 "gschem-", stock
, ".xpm", NULL
);
200 gchar
*stockid
=g_strconcat("gtk-", stock
, NULL
);
202 /* First check if GTK knows this stock icon */
203 if(gtk_stock_lookup(stockid
, &item
)) {
204 wpixmap
= gtk_image_new_from_stock(stockid
,
205 GTK_ICON_SIZE_SMALL_TOOLBAR
);
207 /* Fallback to the original custom icon */
208 pixmap
= gdk_pixmap_create_from_xpm (window
, &mask
,
209 background
, filename
);
210 if (pixmap
!= NULL
) {
211 wpixmap
= gtk_image_new_from_pixmap (pixmap
, mask
);
213 s_log_message("Could not find image at file: %s.\n", filename
);
214 wpixmap
= gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE
,
215 GTK_ICON_SIZE_SMALL_TOOLBAR
);
225 static void x_window_invoke_macro(GtkEntry
*entry
, void *userdata
)
227 GSCHEM_TOPLEVEL
*w_current
= userdata
;
230 interpreter
= scm_list_2(scm_from_utf8_symbol("invoke-macro"),
231 scm_from_utf8_string(gtk_entry_get_text(entry
)));
233 scm_dynwind_begin (0);
234 g_dynwind_window (w_current
);
235 g_scm_eval_protected(interpreter
, SCM_UNDEFINED
);
238 gtk_widget_hide(w_current
->macro_box
);
239 gtk_widget_grab_focus(w_current
->drawing_area
);
242 /*! \todo Finish function documentation!!!
244 * \par Function Description
247 void x_window_create_main(GSCHEM_TOPLEVEL
*w_current
)
249 TOPLEVEL
*toplevel
= w_current
->toplevel
;
251 GtkWidget
*label
=NULL
;
252 GtkWidget
*main_box
=NULL
;
253 GtkWidget
*menubar
=NULL
;
254 GtkWidget
*drawbox
=NULL
;
255 GtkWidget
*bottom_box
=NULL
;
256 GtkWidget
*toolbar
=NULL
;
257 GtkWidget
*handlebox
=NULL
;
259 /* used to signify that the window isn't mapped yet */
260 w_current
->window
= NULL
;
262 w_current
->main_window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
264 gtk_widget_set_name (w_current
->main_window
, "gschem");
265 gtk_window_set_policy (GTK_WINDOW (w_current
->main_window
), TRUE
, TRUE
, TRUE
);
267 /* We want the widgets to flow around the drawing area, so we don't
268 * set a size of the main window. The drawing area's size is fixed,
273 * normally we let the window manager handle locating and sizing
274 * the window. However, for some batch processing of schematics
275 * (generating a pdf of all schematics for example) we want to
276 * override this. Hence "auto_place_mode".
278 if( auto_place_mode
)
279 gtk_widget_set_uposition (w_current
->main_window
, 10, 10);
281 /* this should work fine */
282 g_signal_connect (G_OBJECT (w_current
->main_window
), "delete_event",
283 G_CALLBACK (i_callback_close_wm
),
286 /* Containers first */
287 main_box
= gtk_vbox_new(FALSE
, 1);
288 gtk_container_border_width(GTK_CONTAINER(main_box
), 0);
289 gtk_container_add(GTK_CONTAINER(w_current
->main_window
), main_box
);
291 menubar
= get_main_menu (w_current
);
292 if (w_current
->handleboxes
) {
293 handlebox
= gtk_handle_box_new ();
294 gtk_box_pack_start(GTK_BOX(main_box
), handlebox
, FALSE
, FALSE
, 0);
295 gtk_container_add (GTK_CONTAINER (handlebox
), menubar
);
297 gtk_box_pack_start(GTK_BOX(main_box
), menubar
, FALSE
, FALSE
, 0);
300 w_current
->menubar
= menubar
;
301 gtk_widget_realize (w_current
->main_window
);
303 if (w_current
->handleboxes
&& w_current
->toolbars
) {
304 handlebox
= gtk_handle_box_new ();
305 gtk_box_pack_start (GTK_BOX (main_box
), handlebox
, FALSE
, FALSE
, 0);
308 if (w_current
->toolbars
) {
309 toolbar
= gtk_toolbar_new();
310 gtk_toolbar_set_orientation (GTK_TOOLBAR(toolbar
),
311 GTK_ORIENTATION_HORIZONTAL
);
312 gtk_toolbar_set_style (GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_ICONS
);
314 if (w_current
->handleboxes
) {
315 gtk_container_add (GTK_CONTAINER (handlebox
), toolbar
);
317 gtk_box_pack_start(GTK_BOX(main_box
), toolbar
, FALSE
, FALSE
, 0);
320 gtk_toolbar_append_item (GTK_TOOLBAR (toolbar
),
324 x_window_stock_pixmap("new", w_current
),
325 (GtkSignalFunc
) i_callback_toolbar_file_new
,
327 gtk_toolbar_append_item (GTK_TOOLBAR (toolbar
),
331 x_window_stock_pixmap("open", w_current
),
332 (GtkSignalFunc
) i_callback_toolbar_file_open
,
334 gtk_toolbar_append_item (GTK_TOOLBAR (toolbar
),
338 x_window_stock_pixmap("save", w_current
),
339 (GtkSignalFunc
) i_callback_toolbar_file_save
,
341 gtk_toolbar_append_space (GTK_TOOLBAR(toolbar
));
342 gtk_toolbar_append_item (GTK_TOOLBAR (toolbar
),
344 _("Undo last operation"),
346 x_window_stock_pixmap("undo", w_current
),
347 (GtkSignalFunc
) i_callback_toolbar_edit_undo
,
349 gtk_toolbar_append_item (GTK_TOOLBAR (toolbar
),
353 x_window_stock_pixmap("redo", w_current
),
354 (GtkSignalFunc
) i_callback_toolbar_edit_redo
,
356 gtk_toolbar_append_space (GTK_TOOLBAR(toolbar
));
357 /* not part of any radio button group */
358 gtk_toolbar_append_item (GTK_TOOLBAR (toolbar
),
360 _("Add component...\nSelect library and component from list, move the mouse into main window, click to place\nRight mouse button to cancel"),
362 x_window_stock_pixmap("comp", w_current
),
363 (GtkSignalFunc
) i_callback_toolbar_add_component
,
365 w_current
->toolbar_net
=
366 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar
),
367 GTK_TOOLBAR_CHILD_RADIOBUTTON
,
370 _("Add nets mode\nRight mouse button to cancel"),
372 x_window_stock_pixmap("net", w_current
),
373 (GtkSignalFunc
) i_callback_toolbar_add_net
,
375 w_current
->toolbar_bus
=
376 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar
),
377 GTK_TOOLBAR_CHILD_RADIOBUTTON
,
378 w_current
->toolbar_net
,
380 _("Add buses mode\nRight mouse button to cancel"),
382 x_window_stock_pixmap("bus", w_current
),
383 (GtkSignalFunc
) i_callback_toolbar_add_bus
,
385 /* not part of any radio button group */
386 gtk_toolbar_append_item (GTK_TOOLBAR (toolbar
),
390 x_window_stock_pixmap("text", w_current
),
391 (GtkSignalFunc
) i_callback_toolbar_add_text
,
393 gtk_toolbar_append_space (GTK_TOOLBAR(toolbar
));
394 w_current
->toolbar_select
=
395 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar
),
396 GTK_TOOLBAR_CHILD_RADIOBUTTON
,
397 w_current
->toolbar_bus
,
401 x_window_stock_pixmap("select", w_current
),
402 (GtkSignalFunc
) i_callback_toolbar_edit_select
,
406 gtk_toolbar_append_space (GTK_TOOLBAR(toolbar
));
407 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_current
->toolbar_select
),
412 /* Try to create popup menu (appears in right mouse button */
413 w_current
->popup_menu
= (GtkWidget
*) get_main_popup(w_current
);
415 drawbox
= gtk_hbox_new(FALSE
, 0);
416 gtk_container_border_width(GTK_CONTAINER(drawbox
), 0);
417 gtk_container_add(GTK_CONTAINER(main_box
), drawbox
);
419 x_window_create_drawing(drawbox
, w_current
);
420 x_window_setup_draw_events(w_current
);
422 if (w_current
->scrollbars_flag
== TRUE
) {
423 /* setup scroll bars */
424 w_current
->v_adjustment
= GTK_ADJUSTMENT (
425 gtk_adjustment_new (toplevel
->init_bottom
, 0.0, toplevel
->init_bottom
,
426 100.0, 100.0, 10.0));
428 w_current
->v_scrollbar
= gtk_vscrollbar_new (w_current
->v_adjustment
);
430 gtk_range_set_update_policy (GTK_RANGE (w_current
->v_scrollbar
),
431 GTK_UPDATE_CONTINUOUS
);
433 gtk_box_pack_start (GTK_BOX (drawbox
), w_current
->v_scrollbar
,
436 g_signal_connect (w_current
->v_adjustment
,
438 G_CALLBACK (x_event_vschanged
),
441 w_current
->h_adjustment
= GTK_ADJUSTMENT (
442 gtk_adjustment_new (0.0, 0.0, toplevel
->init_right
, 100.0, 100.0, 10.0));
444 w_current
->h_scrollbar
= gtk_hscrollbar_new (w_current
->h_adjustment
);
446 gtk_range_set_update_policy (GTK_RANGE (w_current
->h_scrollbar
),
447 GTK_UPDATE_CONTINUOUS
);
449 gtk_box_pack_start (GTK_BOX (main_box
), w_current
->h_scrollbar
,
452 g_signal_connect (w_current
->h_adjustment
,
454 G_CALLBACK (x_event_hschanged
),
459 w_current
->macro_entry
= gtk_entry_new();
460 g_signal_connect(w_current
->macro_entry
, "activate",
461 G_CALLBACK(&x_window_invoke_macro
), w_current
);
463 w_current
->macro_box
= gtk_hbox_new(FALSE
, 0);
464 gtk_box_pack_start(GTK_BOX (w_current
->macro_box
),
465 gtk_label_new (_("Evaluate:")), FALSE
, FALSE
, 2);
466 gtk_box_pack_start(GTK_BOX(w_current
->macro_box
), w_current
->macro_entry
,
468 gtk_container_border_width(GTK_CONTAINER(w_current
->macro_box
), 1);
469 gtk_box_pack_start (GTK_BOX (main_box
), w_current
->macro_box
,
473 bottom_box
= gtk_hbox_new(FALSE
, 0);
474 gtk_container_border_width(GTK_CONTAINER(bottom_box
), 1);
475 gtk_box_pack_start (GTK_BOX (main_box
), bottom_box
, FALSE
, FALSE
, 0);
477 /* label = gtk_label_new ("Mouse buttons:");
478 gtk_box_pack_start (GTK_BOX (bottom_box), label, FALSE, FALSE, 10);
481 label
= gtk_label_new (" ");
482 gtk_box_pack_start (GTK_BOX (bottom_box
), label
, FALSE
, FALSE
, 2);
484 w_current
->left_label
= gtk_label_new (_("Pick"));
485 gtk_box_pack_start (GTK_BOX (bottom_box
), w_current
->left_label
,
488 label
= gtk_label_new ("|");
489 gtk_box_pack_start (GTK_BOX (bottom_box
), label
, FALSE
, FALSE
, 5);
491 if (w_current
->middle_button
== STROKE
) {
492 #ifdef HAVE_LIBSTROKE
493 w_current
->middle_label
= gtk_label_new (_("Stroke"));
495 w_current
->middle_label
= gtk_label_new (_("none"));
497 } else if (w_current
->middle_button
== ACTION
) {
498 w_current
->middle_label
= gtk_label_new (_("Action"));
500 w_current
->middle_label
= gtk_label_new (_("Repeat/none"));
503 gtk_box_pack_start (GTK_BOX (bottom_box
), w_current
->middle_label
,
506 label
= gtk_label_new ("|");
507 gtk_box_pack_start (GTK_BOX (bottom_box
), label
, FALSE
, FALSE
, 5);
509 if (default_third_button
== POPUP_ENABLED
) {
510 w_current
->right_label
= gtk_label_new (_("Menu/Cancel"));
512 w_current
->right_label
= gtk_label_new (_("Pan/Cancel"));
514 gtk_box_pack_start (GTK_BOX (bottom_box
), w_current
->right_label
,
517 label
= gtk_label_new (" ");
518 gtk_box_pack_start (GTK_BOX (bottom_box
), label
, FALSE
, FALSE
, 5);
520 w_current
->grid_label
= gtk_label_new (" ");
521 gtk_box_pack_start (GTK_BOX (bottom_box
), w_current
->grid_label
,
524 w_current
->status_label
= gtk_label_new (_("Select Mode"));
525 gtk_box_pack_end (GTK_BOX (bottom_box
), w_current
->status_label
, FALSE
,
528 gtk_widget_show_all (w_current
->main_window
);
529 gtk_widget_hide(w_current
->macro_box
);
531 w_current
->window
= w_current
->drawing_area
->window
;
533 w_current
->drawable
= w_current
->window
;
535 x_window_setup_gc(w_current
);
538 /*! \todo Finish function documentation!!!
540 * \par Function Description
543 void x_window_close(GSCHEM_TOPLEVEL
*w_current
)
545 TOPLEVEL
*toplevel
= w_current
->toplevel
;
546 gboolean last_window
= FALSE
;
548 /* If we're closing whilst inside a move action, re-wind the
549 * page contents back to their state before we started */
550 if (w_current
->inside_action
&&
551 (w_current
->event_state
== MOVE
||
552 w_current
->event_state
== ENDMOVE
)) {
553 o_move_cancel (w_current
);
556 /* last chance to save possible unsaved pages */
557 if (!x_dialog_close_window (w_current
)) {
558 /* user somehow cancelled the close */
562 x_clipboard_finish (w_current
);
565 o_conn_print_hash(w_current
->page_current
->conn_table
);
568 /* close all the dialog boxes */
569 if (w_current
->sowindow
)
570 gtk_widget_destroy(w_current
->sowindow
);
572 if (w_current
->cswindow
)
573 gtk_widget_destroy(w_current
->cswindow
);
575 if (w_current
->tiwindow
)
576 gtk_widget_destroy(w_current
->tiwindow
);
578 if (w_current
->tewindow
)
579 gtk_widget_destroy(w_current
->tewindow
);
581 if (w_current
->aawindow
)
582 gtk_widget_destroy(w_current
->aawindow
);
584 x_multiattrib_close (w_current
);
586 if (w_current
->aewindow
)
587 gtk_widget_destroy(w_current
->aewindow
);
589 if (w_current
->trwindow
)
590 gtk_widget_destroy(w_current
->trwindow
);
592 x_pagesel_close (w_current
);
594 if (w_current
->tswindow
)
595 gtk_widget_destroy(w_current
->tswindow
);
597 if (w_current
->iwindow
)
598 gtk_widget_destroy(w_current
->iwindow
);
600 if (w_current
->hkwindow
)
601 gtk_widget_destroy(w_current
->hkwindow
);
603 if (w_current
->cowindow
)
604 gtk_widget_destroy(w_current
->cowindow
);
606 if (w_current
->clwindow
)
607 gtk_widget_destroy(w_current
->clwindow
);
609 if (w_current
->sewindow
)
610 gtk_widget_destroy(w_current
->sewindow
);
612 if (g_list_length (global_window_list
) == 1) {
613 /* no more window after this one, remember to quit */
617 if (toplevel
->major_changed_refdes
) {
618 GList
* current
= toplevel
->major_changed_refdes
;
621 /* printf("yeah freeing: %s\n", (char*) current->data); */
622 g_free(current
->data
);
623 current
= g_list_next(current
);
625 g_list_free(toplevel
->major_changed_refdes
);
628 /* stuff that has to be done before we free w_current */
630 /* close the log file */
632 /* free the buffers */
633 o_buffer_free (w_current
);
636 x_window_free_gc(w_current
);
638 /* Clear Guile smob weak ref */
639 if (w_current
->smob
!= SCM_UNDEFINED
) {
640 SCM_SET_SMOB_DATA (w_current
->smob
, NULL
);
641 w_current
->smob
= SCM_UNDEFINED
;
644 /* finally close the main window */
645 gtk_widget_destroy(w_current
->main_window
);
647 s_toplevel_delete (toplevel
);
648 global_window_list
= g_list_remove (global_window_list
, w_current
);
651 /* just closed last window, so quit */
657 /*! \todo Finish function documentation!!!
659 * \par Function Description
662 void x_window_close_all(GSCHEM_TOPLEVEL
*w_current
)
664 GSCHEM_TOPLEVEL
*current
;
665 GList
*list_copy
, *iter
;
667 iter
= list_copy
= g_list_copy (global_window_list
);
668 while (iter
!= NULL
) {
669 current
= (GSCHEM_TOPLEVEL
*)iter
->data
;
670 iter
= g_list_next (iter
);
671 x_window_close (current
);
673 g_list_free (list_copy
);
676 /*! \brief Opens a new page from a file.
677 * \par Function Description
678 * This function opens the file whose name is <B>filename</B> in a
679 * new PAGE of <B>toplevel</B>.
681 * If there is no page for <B>filename</B> in <B>toplevel</B>'s list
682 * of pages, it creates a new PAGE, loads the file in it and returns
683 * a pointer on the new page. Otherwise it returns a pointer on the
686 * If the filename passed is NULL, this function creates an empty,
687 * untitled page. The name of the untitled page is build from
688 * configuration data ('untitled-name') and a counter for uniqueness.
690 * The opened page becomes the current page of <B>toplevel</B>.
692 * \param [in] w_current The toplevel environment.
693 * \param [in] filename The name of the file to open or NULL for a blank page.
694 * \returns A pointer on the new page.
696 * \bug This code should check to make sure any untitled filename
697 * does not conflict with a file on disk.
700 x_window_open_page (GSCHEM_TOPLEVEL
*w_current
, const gchar
*filename
)
702 TOPLEVEL
*toplevel
= w_current
->toplevel
;
703 PAGE
*old_current
, *page
;
706 g_return_val_if_fail (toplevel
!= NULL
, NULL
);
708 /* Generate untitled filename if none was specified */
709 if (filename
== NULL
) {
711 cwd
= g_get_current_dir ();
712 tmp
= g_strdup_printf ("%s_%d.sch",
713 toplevel
->untitled_name
,
714 ++w_current
->num_untitled
);
715 fn
= g_build_filename (cwd
, tmp
, NULL
);
719 fn
= g_strdup (filename
);
722 /* Return existing page if it is already loaded */
723 page
= s_page_search (toplevel
, fn
);
724 if ( page
!= NULL
) {
729 old_current
= toplevel
->page_current
;
730 page
= s_page_new (toplevel
, fn
);
731 s_page_goto (toplevel
, page
);
733 /* Load from file if necessary, otherwise just print a message */
734 if (filename
!= NULL
) {
737 s_log_message (_("Loading schematic [%s]\n"), fn
);
739 if (!f_open (toplevel
, page
, (gchar
*) fn
, &err
)) {
742 g_warning ("%s\n", err
->message
);
743 dialog
= gtk_message_dialog_new (GTK_WINDOW (w_current
->main_window
),
744 GTK_DIALOG_DESTROY_WITH_PARENT
,
749 gtk_window_set_title (GTK_WINDOW (dialog
), _("Failed to load file"));
750 gtk_dialog_run (GTK_DIALOG (dialog
));
751 gtk_widget_destroy (dialog
);
754 gtk_recent_manager_add_item (recent_manager
, g_filename_to_uri(fn
, NULL
, NULL
));
758 s_log_message (_("New file [%s]\n"),
759 toplevel
->page_current
->page_filename
);
761 g_run_hook_page (w_current
, "%new-page-hook", toplevel
->page_current
);
764 a_zoom_extents (w_current
,
765 s_page_objects (toplevel
->page_current
),
768 o_undo_savestate (w_current
, UNDO_ALL
);
770 if ( old_current
!= NULL
)
771 s_page_goto (toplevel
, old_current
);
773 /* This line is generally un-needed, however if some code
774 * wants to open a page, yet not bring it to the front, it is
775 * needed needed to add it into the page manager. Otherwise,
776 * it will get done in x_window_set_current_page(...)
778 x_pagesel_update (w_current
); /* ??? */
785 /*! \brief Changes the current page.
786 * \par Function Description
787 * This function displays the specified page <B>page</B> in the
788 * window attached to <B>toplevel</B>.
790 * It changes the <B>toplevel</B>'s current page to <B>page</B>,
791 * draws it and updates the user interface.
793 * <B>page</B> has to be in the list of PAGEs attached to <B>toplevel</B>.
795 * \param [in] w_current The toplevel environment.
796 * \param [in] page The page to become current page.
799 x_window_set_current_page (GSCHEM_TOPLEVEL
*w_current
, PAGE
*page
)
801 TOPLEVEL
*toplevel
= w_current
->toplevel
;
803 g_return_if_fail (toplevel
!= NULL
);
804 g_return_if_fail (page
!= NULL
);
806 o_redraw_cleanstates (w_current
);
808 s_page_goto (toplevel
, page
);
810 i_update_menus (w_current
);
811 i_set_filename (w_current
, page
->page_filename
);
813 x_pagesel_update (w_current
);
814 x_multiattrib_update (w_current
);
816 x_manual_resize (w_current
);
817 x_hscrollbar_update (w_current
);
818 x_vscrollbar_update (w_current
);
820 o_invalidate_all (w_current
);
823 /*! \brief Saves a page to a file.
824 * \par Function Description
825 * This function saves the page <B>page</B> to a file named
828 * It returns the value returned by function <B>f_save()</B> trying
829 * to save page <B>page</B> to file <B>filename</B> (1 on success, 0
832 * <B>page</B> may not be the current page of <B>toplevel</B>. The
833 * current page of <B>toplevel</B> is not affected by this function.
835 * \param [in] w_current The toplevel environment.
836 * \param [in] page The page to save.
837 * \param [in] filename The name of the file in which to save page.
838 * \returns 1 on success, 0 otherwise.
841 x_window_save_page (GSCHEM_TOPLEVEL
*w_current
, PAGE
*page
, const gchar
*filename
)
843 TOPLEVEL
*toplevel
= w_current
->toplevel
;
845 const gchar
*log_msg
, *state_msg
;
849 g_return_val_if_fail (toplevel
!= NULL
, 0);
850 g_return_val_if_fail (page
!= NULL
, 0);
851 g_return_val_if_fail (filename
!= NULL
, 0);
853 /* save current page for restore after opening */
854 old_current
= toplevel
->page_current
;
857 s_page_goto (toplevel
, page
);
858 /* and try saving current page to filename */
859 ret
= (gint
)f_save (toplevel
, toplevel
->page_current
, filename
, &err
);
861 log_msg
= _("Could NOT save page [%s]\n");
862 state_msg
= _("Error while trying to save");
866 dialog
= gtk_message_dialog_new (GTK_WINDOW (w_current
->main_window
),
867 GTK_DIALOG_DESTROY_WITH_PARENT
,
872 gtk_window_set_title (GTK_WINDOW (dialog
), _("Failed to save file"));
873 gtk_dialog_run (GTK_DIALOG (dialog
));
874 gtk_widget_destroy (dialog
);
875 g_clear_error (&err
);
877 /* successful save of page to file, update page... */
878 /* change page name if necessary and prepare log message */
879 if (g_ascii_strcasecmp (page
->page_filename
, filename
) != 0) {
880 g_free (page
->page_filename
);
881 page
->page_filename
= g_strdup (filename
);
883 log_msg
= _("Saved as [%s]\n");
885 log_msg
= _("Saved [%s]\n");
887 state_msg
= _("Saved");
889 /* reset page CHANGED flag */
892 /* add to recent file list */
893 gtk_recent_manager_add_item (recent_manager
, g_filename_to_uri(filename
, NULL
, NULL
));
896 /* log status of operation */
897 s_log_message (log_msg
, filename
);
899 /* update display and page manager */
900 x_window_set_current_page (w_current
, old_current
);
902 i_set_state_msg (w_current
, SELECT
, state_msg
);
903 i_update_toolbar (w_current
);
908 /*! \brief Closes a page.
909 * \par Function Description
910 * This function closes the page <B>page</B> of toplevel
913 * If necessary, the current page of <B>toplevel</B> is changed to
914 * the next valid page or to a new untitled page.
916 * \param [in] w_current The toplevel environment.
917 * \param [in] page The page to close.
920 x_window_close_page (GSCHEM_TOPLEVEL
*w_current
, PAGE
*page
)
922 TOPLEVEL
*toplevel
= w_current
->toplevel
;
923 PAGE
*new_current
= NULL
;
926 g_return_if_fail (toplevel
!= NULL
);
927 g_return_if_fail (page
!= NULL
);
929 g_assert (page
->pid
!= -1);
931 /* If we're closing whilst inside a move action, re-wind the
932 * page contents back to their state before we started */
933 if (w_current
->inside_action
&&
934 (w_current
->event_state
== MOVE
||
935 w_current
->event_state
== ENDMOVE
)) {
936 o_move_cancel (w_current
);
939 if (page
== toplevel
->page_current
) {
940 /* as it will delete current page, select new current page */
941 /* first look up in page hierarchy */
942 new_current
= s_page_search_by_page_id (toplevel
->pages
, page
->up
);
944 if (new_current
== NULL
) {
945 /* no up in hierarchy, choice is prev, next, new page */
946 iter
= g_list_find( geda_list_get_glist( toplevel
->pages
), page
);
948 if ( g_list_previous( iter
) ) {
949 new_current
= (PAGE
*)g_list_previous( iter
)->data
;
950 } else if ( g_list_next( iter
) ) {
951 new_current
= (PAGE
*)g_list_next( iter
)->data
;
953 /* need to add a new untitled page */
957 /* new_current will be the new current page at the end of the function */
960 s_log_message (page
->CHANGED
?
961 _("Discarding page [%s]\n") : _("Closing [%s]\n"),
962 page
->page_filename
);
963 /* remove page from toplevel list of page and free */
964 s_page_delete (toplevel
, page
);
966 /* Switch to a different page if we just removed the current */
967 if (toplevel
->page_current
== NULL
) {
969 /* Create a new page if there wasn't another to switch to */
970 if (new_current
== NULL
) {
971 new_current
= x_window_open_page (w_current
, NULL
);
974 /* change to new_current and update display */
975 x_window_set_current_page (w_current
, new_current
);
980 /*! \brief Setup default icon for GTK windows
982 * \par Function Description
983 * Sets the default window icon by name, to be found in the current icon
984 * theme. The name used is \#defined above as GSCHEM_THEME_ICON_NAME.
986 void x_window_set_default_icon( void )
988 gtk_window_set_default_icon_name( GSCHEM_THEME_ICON_NAME
);