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
26 #ifdef HAVE_LIBDMALLOC
30 #define GSCHEM_THEME_ICON_NAME "geda-gschem"
32 /*! \todo Finish function documentation!!!
34 * \par Function Description
37 void x_window_setup (GSCHEM_TOPLEVEL
*w_current
)
39 TOPLEVEL
*toplevel
= w_current
->toplevel
;
41 /* immediately setup user params */
42 i_vars_set(w_current
);
44 /* Use an alternate factory. */
45 toplevel
->factory
= gschem_factory(w_current
);
47 /* Initialize the autosave callback */
48 s_page_autosave_init(toplevel
);
50 /* x_window_setup_world() - BEGIN */
51 toplevel
->init_left
= -45;
52 toplevel
->init_top
= -45;
53 /* init_right and _bottom are set before this function is called */
55 w_current
->win_width
= default_width
;
56 w_current
->win_height
= default_height
;
57 /* x_window_setup_world() - END */
59 /* Add to the list of windows */
60 global_window_list
= g_list_append (global_window_list
, w_current
);
63 x_window_create_main (w_current
);
65 x_menu_attach_recent_files_submenu(w_current
);
68 /*! \todo Finish function documentation!!!
70 * \par Function Description
73 void x_window_setup_gc(GSCHEM_TOPLEVEL
*w_current
)
76 GdkGCValuesMask values_mask
;
78 w_current
->gc
= gdk_gc_new(w_current
->window
);
80 if (w_current
->gc
== NULL
) {
81 fprintf(stderr
, _("Couldn't allocate gc\n"));
85 values
.foreground
= white
;
86 values
.background
= black
;
88 values
.function
= GDK_XOR
;
89 values_mask
= GDK_GC_FOREGROUND
| GDK_GC_BACKGROUND
| GDK_GC_FUNCTION
;
90 w_current
->xor_gc
= gdk_gc_new_with_values(w_current
->window
,
91 &values
, values_mask
);
93 if (w_current
->xor_gc
== NULL
) {
94 fprintf(stderr
, _("Couldn't allocate xor_gc\n"));
98 values
.foreground
= white
;
99 values
.background
= black
;
101 values
.function
= GDK_XOR
;
102 values_mask
= GDK_GC_FOREGROUND
| GDK_GC_BACKGROUND
| GDK_GC_FUNCTION
;
103 w_current
->outline_xor_gc
= gdk_gc_new_with_values(w_current
->window
,
104 &values
, values_mask
);
106 if (w_current
->outline_xor_gc
== NULL
) {
107 fprintf(stderr
, _("Couldn't allocate outline_xor_gc\n"));
111 values
.foreground
= white
;
112 values
.background
= black
;
114 values
.function
= GDK_XOR
;
115 values
.line_style
= GDK_LINE_ON_OFF_DASH
;
116 values_mask
= GDK_GC_FOREGROUND
| GDK_GC_BACKGROUND
|
117 GDK_GC_LINE_STYLE
| GDK_GC_FUNCTION
;
119 w_current
->bounding_xor_gc
= gdk_gc_new_with_values(w_current
->window
,
120 &values
, values_mask
);
122 if (w_current
->bounding_xor_gc
== NULL
) {
123 fprintf(stderr
, _("Couldn't allocate bounding_xor_gc\n"));
127 w_current
->bus_gc
= gdk_gc_new(w_current
->window
);
129 if (w_current
->bus_gc
== NULL
) {
130 fprintf(stderr
, _("Couldn't allocate bus_gc\n"));
135 /*! \todo Finish function documentation!!!
137 * \par Function Description
140 void x_window_free_gc(GSCHEM_TOPLEVEL
*w_current
)
142 gdk_gc_unref(w_current
->gc
);
143 gdk_gc_unref(w_current
->xor_gc
);
144 gdk_gc_unref(w_current
->bus_gc
);
145 gdk_gc_unref(w_current
->bounding_xor_gc
);
146 gdk_gc_unref(w_current
->outline_xor_gc
);
149 /*! \todo Finish function documentation!!!
151 * \par Function Description
154 void x_window_create_drawing(GtkWidget
*drawbox
, GSCHEM_TOPLEVEL
*w_current
)
157 w_current
->drawing_area
= gtk_drawing_area_new ();
158 /* Set the size here. Be sure that it has an aspect ratio of 1.333
159 * We could calculate this based on root window size, but for now
160 * lets just set it to:
161 * Width = root_width*3/4 Height = Width/1.3333333333
162 * 1.3333333 is the desired aspect ratio!
165 gtk_drawing_area_size (GTK_DRAWING_AREA (w_current
->drawing_area
),
166 w_current
->win_width
,
167 w_current
->win_height
);
169 gtk_box_pack_start (GTK_BOX (drawbox
), w_current
->drawing_area
,
171 GTK_WIDGET_SET_FLAGS (w_current
->drawing_area
, GTK_CAN_FOCUS
);
172 gtk_widget_grab_focus (w_current
->drawing_area
);
173 gtk_widget_show (w_current
->drawing_area
);
177 /*! \brief Set up callbacks for window events that affect drawing.
178 * \par Function Description
180 * Installs GTK+ callback handlers for signals that are emitted by
181 * the drawing area, and some for the main window that affect the drawing
184 * \param [in] w_current The toplevel environment.
186 void x_window_setup_draw_events(GSCHEM_TOPLEVEL
*w_current
)
189 gchar
*detailed_signal
;
193 struct event_reg_t drawing_area_events
[] = {
194 { "expose_event", G_CALLBACK(x_event_expose
) },
195 { "button_press_event", G_CALLBACK(x_event_button_pressed
) },
196 { "button_release_event", G_CALLBACK(x_event_button_released
) },
197 { "motion_notify_event", G_CALLBACK(x_event_motion
) },
198 { "configure_event", G_CALLBACK(x_event_configure
) },
199 { "key_press_event", G_CALLBACK(x_event_key_press
) },
201 struct event_reg_t main_window_events
[] = {
202 { "enter_notify_event", G_CALLBACK(x_event_enter
) },
203 { "scroll_event", G_CALLBACK(x_event_scroll
) },
205 struct event_reg_t
*tmp
;
207 /* is the configure event type missing here? hack */
208 gtk_widget_set_events (w_current
->drawing_area
,
210 GDK_POINTER_MOTION_MASK
|
211 GDK_BUTTON_PRESS_MASK
|
212 GDK_ENTER_NOTIFY_MASK
|
214 GDK_BUTTON_RELEASE_MASK
);
216 for (tmp
= drawing_area_events
; tmp
->detailed_signal
!= NULL
; tmp
++) {
217 g_signal_connect (w_current
->drawing_area
,
218 tmp
->detailed_signal
,
223 for (tmp
= main_window_events
; tmp
->detailed_signal
!= NULL
; tmp
++) {
224 g_signal_connect (w_current
->main_window
,
225 tmp
->detailed_signal
,
232 /*! \brief Creates a new GtkImage displaying a GTK stock icon if available.
234 * If a stock GTK icon with the requested name was not found, this function
235 * falls back to the bitmap icons provided in the distribution.
237 * \param stock Name of the stock icon ("new", "open", etc.)
238 * \return Pointer to the new GtkImage object.
240 static GtkWidget
*x_window_stock_pixmap(const char *stock
, GSCHEM_TOPLEVEL
*w_current
)
242 GtkWidget
*wpixmap
= NULL
;
247 GdkWindow
*window
=w_current
->main_window
->window
;
248 GdkColor
*background
=&w_current
->main_window
->style
->bg
[GTK_STATE_NORMAL
];
250 gchar
*filename
=g_strconcat(w_current
->toplevel
->bitmap_directory
,
252 "gschem-", stock
, ".xpm", NULL
);
254 gchar
*stockid
=g_strconcat("gtk-", stock
, NULL
);
256 /* First check if GTK knows this stock icon */
257 if(gtk_stock_lookup(stockid
, &item
)) {
258 wpixmap
= gtk_image_new_from_stock(stockid
,
259 GTK_ICON_SIZE_SMALL_TOOLBAR
);
261 /* Fallback to the original custom icon */
262 pixmap
= gdk_pixmap_create_from_xpm (window
, &mask
,
263 background
, filename
);
264 if (pixmap
!= NULL
) {
265 wpixmap
= gtk_image_new_from_pixmap (pixmap
, mask
);
267 s_log_message("Could not find image at file: %s.\n", filename
);
268 wpixmap
= gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE
,
269 GTK_ICON_SIZE_SMALL_TOOLBAR
);
279 /*! \todo Finish function documentation!!!
281 * \par Function Description
284 void x_window_create_main(GSCHEM_TOPLEVEL
*w_current
)
286 TOPLEVEL
*toplevel
= w_current
->toplevel
;
288 GtkWidget
*label
=NULL
;
289 GtkWidget
*main_box
=NULL
;
290 GtkWidget
*menubar
=NULL
;
291 GtkWidget
*drawbox
=NULL
;
292 GtkWidget
*bottom_box
=NULL
;
293 GtkWidget
*toolbar
=NULL
;
294 GtkWidget
*handlebox
=NULL
;
296 /* used to signify that the window isn't mapped yet */
297 w_current
->window
= NULL
;
299 w_current
->main_window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
301 gtk_widget_set_name (w_current
->main_window
, "gschem");
302 gtk_window_set_policy (GTK_WINDOW (w_current
->main_window
), TRUE
, TRUE
, TRUE
);
304 /* We want the widgets to flow around the drawing area, so we don't
305 * set a size of the main window. The drawing area's size is fixed,
310 * normally we let the window manager handle locating and sizing
311 * the window. However, for some batch processing of schematics
312 * (generating a pdf of all schematics for example) we want to
313 * override this. Hence "auto_place_mode".
315 if( auto_place_mode
)
316 gtk_widget_set_uposition (w_current
->main_window
, 10, 10);
318 /* this should work fine */
319 gtk_signal_connect (GTK_OBJECT (w_current
->main_window
), "delete_event",
320 GTK_SIGNAL_FUNC (i_callback_close_wm
),
323 /* Containers first */
324 main_box
= gtk_vbox_new(FALSE
, 1);
325 gtk_container_border_width(GTK_CONTAINER(main_box
), 0);
326 gtk_container_add(GTK_CONTAINER(w_current
->main_window
), main_box
);
328 get_main_menu(&menubar
);
329 if (w_current
->handleboxes
) {
330 handlebox
= gtk_handle_box_new ();
331 gtk_box_pack_start(GTK_BOX(main_box
), handlebox
, FALSE
, FALSE
, 0);
332 gtk_container_add (GTK_CONTAINER (handlebox
), menubar
);
334 gtk_box_pack_start(GTK_BOX(main_box
), menubar
, FALSE
, FALSE
, 0);
337 w_current
->menubar
= menubar
;
338 gtk_widget_realize (w_current
->main_window
);
340 if (w_current
->handleboxes
&& w_current
->toolbars
) {
341 handlebox
= gtk_handle_box_new ();
342 gtk_box_pack_start (GTK_BOX (main_box
), handlebox
, FALSE
, FALSE
, 0);
345 if (w_current
->toolbars
) {
346 toolbar
= gtk_toolbar_new();
347 gtk_toolbar_set_orientation (GTK_TOOLBAR(toolbar
),
348 GTK_ORIENTATION_HORIZONTAL
);
349 gtk_toolbar_set_style (GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_ICONS
);
351 if (w_current
->handleboxes
) {
352 gtk_container_add (GTK_CONTAINER (handlebox
), toolbar
);
354 gtk_box_pack_start(GTK_BOX(main_box
), toolbar
, FALSE
, FALSE
, 0);
357 gtk_toolbar_append_item (GTK_TOOLBAR (toolbar
),
361 x_window_stock_pixmap("new", w_current
),
362 (GtkSignalFunc
) i_callback_toolbar_file_new
,
364 gtk_toolbar_append_item (GTK_TOOLBAR (toolbar
),
368 x_window_stock_pixmap("open", w_current
),
369 (GtkSignalFunc
) i_callback_toolbar_file_open
,
371 gtk_toolbar_append_item (GTK_TOOLBAR (toolbar
),
375 x_window_stock_pixmap("save", w_current
),
376 (GtkSignalFunc
) i_callback_toolbar_file_save
,
378 gtk_toolbar_append_space (GTK_TOOLBAR(toolbar
));
379 gtk_toolbar_append_item (GTK_TOOLBAR (toolbar
),
381 _("Undo last operation"),
383 x_window_stock_pixmap("undo", w_current
),
384 (GtkSignalFunc
) i_callback_toolbar_edit_undo
,
386 gtk_toolbar_append_item (GTK_TOOLBAR (toolbar
),
390 x_window_stock_pixmap("redo", w_current
),
391 (GtkSignalFunc
) i_callback_toolbar_edit_redo
,
393 gtk_toolbar_append_space (GTK_TOOLBAR(toolbar
));
394 /* not part of any radio button group */
395 gtk_toolbar_append_item (GTK_TOOLBAR (toolbar
),
397 _("Add component...\nSelect library and component from list, move the mouse into main window, click to place\nRight mouse button to cancel"),
399 x_window_stock_pixmap("comp", w_current
),
400 (GtkSignalFunc
) i_callback_toolbar_add_component
,
402 w_current
->toolbar_net
=
403 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar
),
404 GTK_TOOLBAR_CHILD_RADIOBUTTON
,
407 _("Add nets mode\nRight mouse button to cancel"),
409 x_window_stock_pixmap("net", w_current
),
410 (GtkSignalFunc
) i_callback_toolbar_add_net
,
412 w_current
->toolbar_bus
=
413 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar
),
414 GTK_TOOLBAR_CHILD_RADIOBUTTON
,
415 w_current
->toolbar_net
,
417 _("Add buses mode\nRight mouse button to cancel"),
419 x_window_stock_pixmap("bus", w_current
),
420 (GtkSignalFunc
) i_callback_toolbar_add_bus
,
422 /* not part of any radio button group */
423 gtk_toolbar_append_item (GTK_TOOLBAR (toolbar
),
427 x_window_stock_pixmap("text", w_current
),
428 (GtkSignalFunc
) i_callback_toolbar_add_text
,
430 gtk_toolbar_append_space (GTK_TOOLBAR(toolbar
));
431 w_current
->toolbar_select
=
432 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar
),
433 GTK_TOOLBAR_CHILD_RADIOBUTTON
,
434 w_current
->toolbar_bus
,
438 x_window_stock_pixmap("select", w_current
),
439 (GtkSignalFunc
) i_callback_toolbar_edit_select
,
443 gtk_toolbar_append_space (GTK_TOOLBAR(toolbar
));
444 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_current
->toolbar_select
),
449 /* Try to create popup menu (appears in right mouse button */
450 w_current
->popup_menu
= (GtkWidget
*) get_main_popup(w_current
);
452 drawbox
= gtk_hbox_new(FALSE
, 0);
453 gtk_container_border_width(GTK_CONTAINER(drawbox
), 0);
454 gtk_container_add(GTK_CONTAINER(main_box
), drawbox
);
456 x_window_create_drawing(drawbox
, w_current
);
457 x_window_setup_draw_events(w_current
);
459 if (w_current
->scrollbars_flag
== TRUE
) {
460 /* setup scroll bars */
461 w_current
->v_adjustment
=
462 gtk_adjustment_new (toplevel
->init_bottom
,
463 0.0, toplevel
->init_bottom
,
466 w_current
->v_scrollbar
= gtk_vscrollbar_new (GTK_ADJUSTMENT (
467 w_current
->v_adjustment
));
469 gtk_range_set_update_policy (GTK_RANGE (w_current
->v_scrollbar
),
470 GTK_UPDATE_CONTINUOUS
);
472 gtk_box_pack_start (GTK_BOX (drawbox
), w_current
->v_scrollbar
,
475 gtk_signal_connect (GTK_OBJECT (w_current
->v_adjustment
),
477 GTK_SIGNAL_FUNC (x_event_vschanged
),
480 w_current
->h_adjustment
= gtk_adjustment_new (0.0, 0.0,
481 toplevel
->init_right
,
484 w_current
->h_scrollbar
= gtk_hscrollbar_new (GTK_ADJUSTMENT (
485 w_current
->h_adjustment
));
487 gtk_range_set_update_policy (GTK_RANGE (w_current
->h_scrollbar
),
488 GTK_UPDATE_CONTINUOUS
);
490 gtk_box_pack_start (GTK_BOX (main_box
), w_current
->h_scrollbar
,
493 gtk_signal_connect (GTK_OBJECT (w_current
->h_adjustment
),
495 GTK_SIGNAL_FUNC (x_event_hschanged
),
500 bottom_box
= gtk_hbox_new(FALSE
, 0);
501 gtk_container_border_width(GTK_CONTAINER(bottom_box
), 1);
502 gtk_box_pack_start (GTK_BOX (main_box
), bottom_box
, FALSE
, FALSE
, 0);
504 /* label = gtk_label_new ("Mouse buttons:");
505 gtk_box_pack_start (GTK_BOX (bottom_box), label, FALSE, FALSE, 10);
508 label
= gtk_label_new (" ");
509 gtk_box_pack_start (GTK_BOX (bottom_box
), label
, FALSE
, FALSE
, 2);
511 w_current
->left_label
= gtk_label_new (_("Pick"));
512 gtk_box_pack_start (GTK_BOX (bottom_box
), w_current
->left_label
,
515 label
= gtk_label_new ("|");
516 gtk_box_pack_start (GTK_BOX (bottom_box
), label
, FALSE
, FALSE
, 5);
518 if (w_current
->middle_button
== STROKE
) {
520 w_current
->middle_label
= gtk_label_new (_("Stroke"));
522 w_current
->middle_label
= gtk_label_new (_("none"));
524 } else if (w_current
->middle_button
== ACTION
) {
525 w_current
->middle_label
= gtk_label_new (_("Action"));
527 w_current
->middle_label
= gtk_label_new (_("Repeat/none"));
530 gtk_box_pack_start (GTK_BOX (bottom_box
), w_current
->middle_label
,
533 label
= gtk_label_new ("|");
534 gtk_box_pack_start (GTK_BOX (bottom_box
), label
, FALSE
, FALSE
, 5);
536 switch (default_third_button
) {
538 w_current
->right_label
= gtk_label_new (_("Menu/Cancel"));
540 case MOUSEPAN_ENABLED
:
541 w_current
->right_label
= gtk_label_new (_("Pan/Cancel"));
544 gtk_box_pack_start (GTK_BOX (bottom_box
), w_current
->right_label
,
547 label
= gtk_label_new (" ");
548 gtk_box_pack_start (GTK_BOX (bottom_box
), label
, FALSE
, FALSE
, 5);
550 w_current
->grid_label
= gtk_label_new (" ");
551 gtk_box_pack_start (GTK_BOX (bottom_box
), w_current
->grid_label
,
554 w_current
->status_label
= gtk_label_new (_("Select Mode"));
555 gtk_box_pack_end (GTK_BOX (bottom_box
), w_current
->status_label
, FALSE
,
559 GtkCellRenderer
*prompt_cell
;
562 l
= gtk_list_store_new(SCM_PROMPT_N_COLUMNS
,
566 w_current
->scm_prompts
= gtk_combo_box_new_with_model(GTK_TREE_MODEL(l
));
567 g_object_set(G_OBJECT(w_current
->scm_prompts
),
568 "focus-on-click", FALSE
, NULL
);
569 g_signal_connect(w_current
->scm_prompts
, "changed",
570 G_CALLBACK(x_event_scm_prompt_changed
), w_current
);
572 prompt_cell
= gtk_cell_renderer_text_new();
573 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(w_current
->scm_prompts
),
576 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(w_current
->scm_prompts
),
577 prompt_cell
, "text", SCM_PROMPT_MESSAGE
);
579 gtk_box_pack_end(GTK_BOX(bottom_box
), w_current
->scm_prompts
, FALSE
,
583 gtk_widget_show_all (w_current
->main_window
);
585 w_current
->window
= w_current
->drawing_area
->window
;
587 w_current
->backingstore
= gdk_pixmap_new(w_current
->window
,
588 w_current
->drawing_area
->allocation
.width
,
589 w_current
->drawing_area
->allocation
.height
,
591 x_window_setup_gc(w_current
);
594 static void x_window_close_widgets(GSCHEM_TOPLEVEL
*w_current
)
596 if (w_current
->sowindow
)
597 gtk_widget_destroy(w_current
->sowindow
);
599 if (w_current
->cswindow
)
600 gtk_widget_destroy(w_current
->cswindow
);
602 if (w_current
->tiwindow
)
603 gtk_widget_destroy(w_current
->tiwindow
);
605 if (w_current
->tewindow
)
606 gtk_widget_destroy(w_current
->tewindow
);
608 if (w_current
->aawindow
)
609 gtk_widget_destroy(w_current
->aawindow
);
611 x_multiattrib_close (w_current
);
613 if (w_current
->aewindow
)
614 gtk_widget_destroy(w_current
->aewindow
);
616 if (w_current
->trwindow
)
617 gtk_widget_destroy(w_current
->trwindow
);
619 x_pagesel_close (w_current
);
621 if (w_current
->tswindow
)
622 gtk_widget_destroy(w_current
->tswindow
);
624 if (w_current
->abwindow
)
625 gtk_widget_destroy(w_current
->abwindow
);
627 if (w_current
->iwindow
)
628 gtk_widget_destroy(w_current
->iwindow
);
630 if (w_current
->hkwindow
)
631 gtk_widget_destroy(w_current
->hkwindow
);
633 if (w_current
->cowindow
)
634 gtk_widget_destroy(w_current
->cowindow
);
636 if (w_current
->clwindow
)
637 gtk_widget_destroy(w_current
->clwindow
);
639 if (w_current
->sewindow
)
640 gtk_widget_destroy(w_current
->sewindow
);
642 /* finally close the main window */
643 gtk_widget_destroy(w_current
->main_window
);
646 /*! \todo Finish function documentation!!!
648 * \par Function Description
651 void x_window_close(GSCHEM_TOPLEVEL
*w_current
)
653 TOPLEVEL
*toplevel
= w_current
->toplevel
;
654 gboolean last_window
= FALSE
;
656 /* last chance to save possible unsaved pages */
657 if (!x_dialog_close_window (w_current
)) {
658 /* user somehow cancelled the close */
663 o_conn_print_hash(w_current
->page_current
->conn_table
);
666 if (g_list_length (global_window_list
) == 1) {
667 /* no more window after this one, remember to quit */
671 if (toplevel
->major_changed_refdes
) {
672 GList
* current
= toplevel
->major_changed_refdes
;
675 /* printf("yeah freeing: %s\n", (char*) current->data); */
676 g_free(current
->data
);
677 current
= g_list_next(current
);
679 g_list_free(toplevel
->major_changed_refdes
);
682 /* stuff that has to be done before we free w_current */
685 o_text_freeallfonts (toplevel
);
686 /* close the log file */
690 * FIXME: this is a double-bind: either we risk leaving pointers to stale
691 * objects in the global buffers, or we clear out the buffers when we don't
692 * need to. Fix this by keeping buffer objects in their very own TOPLEVEL.
694 o_buffer_free (w_current
);
697 toplevel
->DONT_REDRAW
= 1; /* Bernd's slotting mechanism would make o_text.c angry. */
698 g_object_unref(G_OBJECT(toplevel
));
699 global_window_list
= g_list_remove (global_window_list
, w_current
);
701 /* close all the dialog boxes and release GDK resources */
702 x_window_close_widgets(w_current
);
703 if (w_current
->backingstore
) {
704 gdk_pixmap_unref(w_current
->backingstore
);
707 x_window_free_gc(w_current
);
709 i_vars_freestrings(w_current
);
712 /* just closed last window, so quit */
718 /*! \todo Finish function documentation!!!
720 * \par Function Description
723 void x_window_close_all(GSCHEM_TOPLEVEL
*w_current
)
725 GSCHEM_TOPLEVEL
*current
;
726 GList
*list_copy
, *iter
;
728 iter
= list_copy
= g_list_copy (global_window_list
);
729 while (iter
!= NULL
) {
730 current
= (GSCHEM_TOPLEVEL
*)iter
->data
;
731 iter
= g_list_next (iter
);
732 x_window_close (current
);
734 g_list_free (list_copy
);
737 /*! \brief Opens a new page from a file.
738 * \par Function Description
739 * This function opens the file whose name is <B>filename</B> in a
740 * new PAGE of <B>toplevel</B>.
742 * If there is no page for <B>filename</B> in <B>toplevel</B>'s list
743 * of pages, it creates a new PAGE, loads the file in it and returns
744 * a pointer on the new page. Otherwise it returns a pointer on the
747 * If the filename passed is NULL, this function creates an empty,
748 * untitled page. The name of the untitled page is build from
749 * configuration data ('untitled-name') and a counter for uniqueness.
751 * The opened page becomes the current page of <B>toplevel</B>.
753 * \param [in] toplevel The toplevel environment.
754 * \param [in] filename The name of the file to open or NULL for a blank page.
755 * \returns A pointer on the new page.
757 * \bug This code should check to make sure any untitled filename
758 * does not conflict with a file on disk.
761 x_window_open_page (GSCHEM_TOPLEVEL
*w_current
, const gchar
*filename
)
763 TOPLEVEL
*toplevel
= w_current
->toplevel
;
764 PAGE
*old_current
, *page
;
767 g_return_val_if_fail (toplevel
!= NULL
, NULL
);
769 /* Generate untitled filename if none was specified */
770 if (filename
== NULL
) {
772 cwd
= g_get_current_dir ();
773 tmp
= g_strdup_printf ("%s_%d.sch",
774 toplevel
->untitled_name
,
775 ++w_current
->num_untitled
);
776 fn
= g_build_filename (cwd
, tmp
, NULL
);
780 fn
= g_strdup (filename
);
783 /* Return existing page if it is already loaded */
784 page
= s_page_search (toplevel
, fn
);
785 if ( page
!= NULL
) {
790 old_current
= toplevel
->page_current
;
791 page
= s_page_new (toplevel
, fn
);
792 page
->width
= w_current
->win_width
;
793 page
->height
= w_current
->win_height
;
794 s_toplevel_goto_page(toplevel
, page
);
795 set_window(toplevel
, page
,
796 toplevel
->init_left
, toplevel
->init_right
,
797 toplevel
->init_top
, toplevel
->init_bottom
);
799 /* Load from file if necessary, otherwise just print a message */
800 if (filename
!= NULL
) {
803 s_log_message (_("Loading schematic [%s]\n"), fn
);
805 if (!f_open(toplevel
, page
, (gchar
*) fn
, &err
)) {
808 g_warning ("%s\n", err
->message
);
809 dialog
= gtk_message_dialog_new (GTK_WINDOW (w_current
->main_window
),
810 GTK_DIALOG_DESTROY_WITH_PARENT
,
815 gtk_window_set_title (GTK_WINDOW (dialog
), _("Failed to load file"));
816 gtk_dialog_run (GTK_DIALOG (dialog
));
817 gtk_widget_destroy (dialog
);
820 recent_files_add (fn
);
824 s_log_message (_("New file [%s]\n"),
825 toplevel
->page_current
->page_filename
);
828 if (scm_hook_empty_p (new_page_hook
) == SCM_BOOL_F
)
829 scm_run_hook (new_page_hook
,
830 scm_cons (g_make_page_smob (toplevel
, page
), SCM_EOL
));
832 a_zoom_extents(w_current
, toplevel
->page_current
, A_PAN_DONT_REDRAW
);
834 o_undo_savestate (w_current
, UNDO_ALL
);
836 if ( old_current
!= NULL
)
837 s_toplevel_goto_page(toplevel
, old_current
);
839 /* This line is generally un-needed, however if some code
840 * wants to open a page, yet not bring it to the front, it is
841 * needed needed to add it into the page manager. Otherwise,
842 * it will get done in x_window_set_current_page(...)
844 x_pagesel_update (w_current
); /* ??? */
851 /*! \brief Changes the current page.
852 * \par Function Description
853 * This function displays the specified page <B>page</B> in the
854 * window attached to <B>toplevel</B>.
856 * It changes the <B>toplevel</B>'s current page to <B>page</B>,
857 * draws it and updates the user interface.
859 * <B>page</B> has to be in the list of PAGEs attached to <B>toplevel</B>.
861 * \param [in] toplevel The toplevel environment.
862 * \param [in] page The page to become current page.
865 x_window_set_current_page (GSCHEM_TOPLEVEL
*w_current
, PAGE
*page
)
867 TOPLEVEL
*toplevel
= w_current
->toplevel
;
869 g_return_if_fail (toplevel
!= NULL
);
870 g_return_if_fail (page
!= NULL
);
872 s_toplevel_goto_page(toplevel
, page
);
874 i_update_menus (w_current
);
875 i_set_filename (w_current
, page
->page_filename
);
877 x_pagesel_update (w_current
);
878 x_multiattrib_update(w_current
,
879 w_current
->toplevel
->page_current
->selection_list
);
881 toplevel
->DONT_REDRAW
= 1;
882 x_repaint_background (w_current
);
883 x_manual_resize (w_current
);
884 x_hscrollbar_update (w_current
);
885 x_vscrollbar_update (w_current
);
886 toplevel
->DONT_REDRAW
= 0;
888 o_redraw_all (w_current
);
891 /*! \brief Saves a page to a file.
892 * \par Function Description
893 * This function saves the page <B>page</B> to a file named
896 * It returns the value returned by function <B>f_save()</B> trying
897 * to save page <B>page</B> to file <B>filename</B> (1 on success, 0
900 * <B>page</B> may not be the current page of <B>toplevel</B>. The
901 * current page of <B>toplevel</B> is not affected by this function.
903 * \param [in] toplevel The toplevel environment.
904 * \param [in] page The page to save.
905 * \param [in] filename The name of the file in which to save page.
906 * \returns 1 on success, 0 otherwise.
909 x_window_save_page (GSCHEM_TOPLEVEL
*w_current
, PAGE
*page
, const gchar
*filename
)
911 TOPLEVEL
*toplevel
= w_current
->toplevel
;
913 const gchar
*log_msg
, *state_msg
;
916 g_return_val_if_fail (toplevel
!= NULL
, 0);
917 g_return_val_if_fail (page
!= NULL
, 0);
918 g_return_val_if_fail (filename
!= NULL
, 0);
920 /* save current page for restore after opening */
921 old_current
= toplevel
->page_current
;
924 s_toplevel_goto_page(toplevel
, page
);
925 /* and try saving current page to filename */
926 ret
= f_save(toplevel
, page
, filename
);
928 /* an error occurred when saving page to file */
929 log_msg
= _("Could NOT save page [%s]\n");
930 state_msg
= _("Error while trying to save");
933 /* successful save of page to file, update page... */
934 /* change page name if necessary and prepare log message */
935 if (g_ascii_strcasecmp (page
->page_filename
, filename
) != 0) {
936 g_free (page
->page_filename
);
937 page
->page_filename
= g_strdup (filename
);
939 log_msg
= _("Saved as [%s]\n");
941 log_msg
= _("Saved [%s]\n");
943 state_msg
= _("Saved");
945 /* reset page CHANGED flag */
948 /* update recent file list */
949 recent_files_add(filename
);
952 /* log status of operation */
953 s_log_message (log_msg
, filename
);
955 /* update display and page manager */
956 x_window_set_current_page (w_current
, old_current
);
958 i_set_state_msg (w_current
, SELECT
, state_msg
);
959 i_update_toolbar (w_current
);
964 /*! \brief Closes a page.
965 * \par Function Description
966 * This function closes the page <B>page</B> of toplevel
969 * If necessary, the current page of <B>toplevel</B> is changed to
970 * the next valid page or to a new untitled page.
972 * \param [in] toplevel The toplevel environment.
973 * \param [in] page The page to close.
976 x_window_close_page (GSCHEM_TOPLEVEL
*w_current
, PAGE
*page
)
978 TOPLEVEL
*toplevel
= w_current
->toplevel
;
979 PAGE
*new_current
= NULL
;
982 g_return_if_fail (toplevel
!= NULL
);
983 g_return_if_fail (page
!= NULL
);
985 if (page
== toplevel
->page_current
) {
986 /* as it will delete current page, select new current page */
987 /* first look up in page hierarchy */
988 new_current
= page
->up_page
;
990 if (new_current
== NULL
) {
991 /* no up in hierarchy, choice is prev, next, new page */
992 iter
= g_list_find( geda_list_get_glist( toplevel
->pages
), page
);
994 if ( g_list_previous( iter
) ) {
995 new_current
= (PAGE
*)g_list_previous( iter
)->data
;
996 } else if ( g_list_next( iter
) ) {
997 new_current
= (PAGE
*)g_list_next( iter
)->data
;
999 /* need to add a new untitled page */
1003 /* new_current will be the new current page at the end of the function */
1006 s_log_message (page
->CHANGED
?
1007 _("Discarding page [%s]\n") : _("Closing [%s]\n"),
1008 page
->page_filename
);
1009 /* remove page from toplevel list of page and free */
1010 s_page_delete (toplevel
, page
);
1012 /* Switch to a different page if we just removed the current */
1013 if (toplevel
->page_current
== NULL
) {
1015 /* Create a new page if there wasn't another to switch to */
1016 if (new_current
== NULL
) {
1017 new_current
= x_window_open_page (w_current
, NULL
);
1020 /* change to new_current and update display */
1021 x_window_set_current_page (w_current
, new_current
);
1026 /*! \brief Setup default icon for GTK windows
1028 * \par Function Description
1029 * Sets the default window icon by name, to be found in the current icon
1030 * theme. The name used is #defined above as GSCHEM_THEME_ICON_NAME.
1032 void x_window_set_default_icon( void )
1034 gtk_window_set_default_icon_name( GSCHEM_THEME_ICON_NAME
);