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 GDK_WINDOWING_X11
32 #include "actions.decl.x"
34 #include "gschem_compselect_dockable.h"
35 #include "gschem_object_properties_dockable.h"
36 #include "gschem_text_properties_dockable.h"
37 #include "gschem_multiattrib_dockable.h"
38 #include "gschem_options_dockable.h"
39 #include "gschem_log_dockable.h"
40 #include "gschem_find_text_dockable.h"
41 #include "gschem_patch_dockable.h"
42 #include "gschem_pagesel_dockable.h"
44 #define GSCHEM_THEME_ICON_NAME "geda-gschem"
46 /*! \todo Finish function documentation!!!
48 * \par Function Description
51 void x_window_setup (GschemToplevel
*w_current
)
53 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
55 /* immediately setup user params */
56 i_vars_set(w_current
);
58 /* Initialize the autosave callback */
59 s_page_autosave_init(toplevel
);
61 /* Initialize the clipboard callback */
62 x_clipboard_init (w_current
);
64 /* Add to the list of windows */
65 global_window_list
= g_list_append (global_window_list
, w_current
);
68 x_menus_create_submenus (w_current
);
69 x_window_create_main (w_current
);
71 /* disable terminal REPL action if stdin is not a terminal */
72 gschem_action_set_sensitive (action_file_repl
, isatty (STDIN_FILENO
),
76 /*! \todo Finish function documentation!!!
78 * \par Function Description
81 void x_window_create_drawing(GtkWidget
*scrolled
, GschemToplevel
*w_current
)
84 w_current
->drawing_area
= GTK_WIDGET (gschem_page_view_new_with_page (w_current
->toplevel
->page_current
));
85 /* Set the size here. Be sure that it has an aspect ratio of 1.333
86 * We could calculate this based on root window size, but for now
87 * lets just set it to:
88 * Width = root_width*3/4 Height = Width/1.3333333333
89 * 1.3333333 is the desired aspect ratio!
92 gtk_container_add(GTK_CONTAINER(scrolled
), w_current
->drawing_area
);
94 GTK_WIDGET_SET_FLAGS (w_current
->drawing_area
, GTK_CAN_FOCUS
);
95 gtk_widget_grab_focus (w_current
->drawing_area
);
96 gtk_widget_show (w_current
->drawing_area
);
99 /*! \brief Set up callbacks for window events that affect drawing.
100 * \par Function Description
102 * Installs GTK+ callback handlers for signals that are emitted by
103 * the drawing area, and some for the main window that affect the drawing
106 * \param [in] w_current The toplevel environment.
108 void x_window_setup_draw_events(GschemToplevel
*w_current
)
111 gchar
*detailed_signal
;
115 struct event_reg_t drawing_area_events
[] = {
116 { "expose_event", G_CALLBACK(x_event_expose
) },
117 { "expose_event", G_CALLBACK(x_event_raise_dialog_boxes
) },
118 { "button_press_event", G_CALLBACK(x_event_button_pressed
) },
119 { "button_release_event", G_CALLBACK(x_event_button_released
) },
120 { "motion_notify_event", G_CALLBACK(x_event_motion
) },
121 { "configure_event", G_CALLBACK(x_event_configure
) },
122 { "key_press_event", G_CALLBACK(x_event_key
) },
123 { "key_release_event", G_CALLBACK(x_event_key
) },
124 { "scroll_event", G_CALLBACK(x_event_scroll
) },
125 { "update-grid-info", G_CALLBACK(i_update_grid_info_callback
) },
126 { "notify::page", G_CALLBACK(gschem_toplevel_notify_page_callback
) },
128 struct event_reg_t main_window_events
[] = {
129 { "enter_notify_event", G_CALLBACK(x_event_enter
) },
131 struct event_reg_t
*tmp
;
133 /* is the configure event type missing here? hack */
134 gtk_widget_set_events (w_current
->drawing_area
,
136 GDK_POINTER_MOTION_MASK
|
137 GDK_BUTTON_PRESS_MASK
|
138 GDK_ENTER_NOTIFY_MASK
|
140 GDK_BUTTON_RELEASE_MASK
);
142 for (tmp
= drawing_area_events
; tmp
->detailed_signal
!= NULL
; tmp
++) {
143 g_signal_connect (w_current
->drawing_area
,
144 tmp
->detailed_signal
,
149 for (tmp
= main_window_events
; tmp
->detailed_signal
!= NULL
; tmp
++) {
150 g_signal_connect (w_current
->main_window
,
151 tmp
->detailed_signal
,
159 x_window_find_text (GtkWidget
*widget
, gint response
, GschemToplevel
*w_current
)
164 g_return_if_fail (w_current
!= NULL
);
165 g_return_if_fail (w_current
->toplevel
!= NULL
);
168 case GTK_RESPONSE_OK
:
169 count
= gschem_find_text_dockable_find (
170 GSCHEM_FIND_TEXT_DOCKABLE (w_current
->find_text_dockable
),
171 geda_list_get_glist (w_current
->toplevel
->pages
),
172 gschem_find_text_widget_get_find_type (GSCHEM_FIND_TEXT_WIDGET (w_current
->find_text_widget
)),
173 gschem_find_text_widget_get_find_text_string (GSCHEM_FIND_TEXT_WIDGET (w_current
->find_text_widget
)),
174 gschem_find_text_widget_get_descend (GSCHEM_FIND_TEXT_WIDGET (w_current
->find_text_widget
)));
176 gschem_dockable_present (w_current
->find_text_dockable
);
181 case GTK_RESPONSE_CANCEL
:
182 case GTK_RESPONSE_DELETE_EVENT
:
187 printf("x_window_find_text(): strange signal %d\n", response
);
191 gtk_widget_grab_focus (w_current
->drawing_area
);
192 gtk_widget_hide (GTK_WIDGET (widget
));
199 x_window_hide_text (GtkWidget
*widget
, gint response
, GschemToplevel
*w_current
)
201 g_return_if_fail (w_current
!= NULL
);
202 g_return_if_fail (w_current
->toplevel
!= NULL
);
204 if (response
== GTK_RESPONSE_OK
) {
205 o_edit_hide_specific_text (w_current
,
206 s_page_objects (w_current
->toplevel
->page_current
),
207 gschem_show_hide_text_widget_get_text_string (GSCHEM_SHOW_HIDE_TEXT_WIDGET (widget
)));
210 gtk_widget_grab_focus (w_current
->drawing_area
);
211 gtk_widget_hide (GTK_WIDGET (widget
));
216 x_window_show_text (GtkWidget
*widget
, gint response
, GschemToplevel
*w_current
)
218 g_return_if_fail (w_current
!= NULL
);
219 g_return_if_fail (w_current
->toplevel
!= NULL
);
221 if (response
== GTK_RESPONSE_OK
) {
222 o_edit_show_specific_text (w_current
,
223 s_page_objects (w_current
->toplevel
->page_current
),
224 gschem_show_hide_text_widget_get_text_string (GSCHEM_SHOW_HIDE_TEXT_WIDGET (widget
)));
227 gtk_widget_grab_focus (w_current
->drawing_area
);
228 gtk_widget_hide (GTK_WIDGET (widget
));
233 x_window_invoke_macro (GschemMacroWidget
*widget
, int response
, GschemToplevel
*w_current
)
235 if (response
== GTK_RESPONSE_OK
) {
236 const char *macro
= gschem_macro_widget_get_macro_string (widget
);
238 SCM interpreter
= scm_list_2(scm_from_utf8_symbol("invoke-macro"),
239 scm_from_utf8_string(macro
));
241 scm_dynwind_begin (0);
242 g_dynwind_window (w_current
);
243 g_scm_eval_protected(interpreter
, SCM_UNDEFINED
);
247 gtk_widget_grab_focus (w_current
->drawing_area
);
248 gtk_widget_hide (GTK_WIDGET (widget
));
252 x_window_select_text (GschemFindTextDockable
*dockable
, OBJECT
*object
, GschemToplevel
*w_current
)
254 GschemPageView
*view
= gschem_toplevel_get_current_page_view (w_current
);
255 g_return_if_fail (view
!= NULL
);
259 g_return_if_fail (object
!= NULL
);
260 page_obj
= gschem_page_get_page_object(object
);
261 g_return_if_fail (page_obj
!= NULL
);
263 x_window_set_current_page (w_current
, page_obj
->page
);
265 gschem_page_view_zoom_text (view
, object
, TRUE
);
269 x_window_state_event (GtkWidget
*widget
,
270 GdkEventWindowState
*event
,
273 eda_config_set_string (
274 eda_config_get_user_context (),
275 "gschem.window-geometry", "state",
276 (event
->new_window_state
&
277 GDK_WINDOW_STATE_FULLSCREEN
) ? "fullscreen" :
278 (event
->new_window_state
&
279 GDK_WINDOW_STATE_MAXIMIZED
) ? "maximized" : "normal");
281 return FALSE
; /* propagate the event further */
285 x_window_save_menu_geometry (GtkMenuShell
*menu_shell
,
286 GschemToplevel
*w_current
)
288 for (GList
*l
= gtk_container_get_children (GTK_CONTAINER (menu_shell
));
289 l
!= NULL
; l
= l
->next
) {
290 GtkMenuItem
*menu_item
= GTK_MENU_ITEM (l
->data
);
292 GtkWidget
*menu
= menu_item
->submenu
;
297 char *settings_name
= g_object_get_data (G_OBJECT (menu
), "settings-name");
298 if (settings_name
== NULL
)
299 /* menu doesn't have a settings name set */
305 if (GTK_MENU (menu
)->torn_off
) {
306 GtkWidget
*window
= GTK_MENU (menu
)->tearoff_window
;
307 g_return_if_fail (window
!= NULL
);
309 gtk_window_get_position (GTK_WINDOW (window
), &coords
[0], &coords
[1]);
310 gtk_window_get_size (GTK_WINDOW (window
), &coords
[2], &coords
[3]);
314 eda_config_set_int_list (
315 eda_config_get_user_context (),
316 "gschem.menu-geometry", settings_name
, coords
, length
);
318 x_window_save_menu_geometry (GTK_MENU_SHELL (menu
), w_current
);
323 x_window_save_geometry (GschemToplevel
*w_current
)
326 GtkAllocation allocation
;
328 /* save window geometry */
329 window_state
= eda_config_get_string (eda_config_get_user_context (),
330 "gschem.window-geometry",
332 if (window_state
!= NULL
&& strcmp (window_state
, "normal") == 0) {
333 gint width
= -1, height
= -1;
334 gtk_window_get_size (GTK_WINDOW (w_current
->main_window
), &width
, &height
);
335 if (width
> 0 && height
> 0) {
336 eda_config_set_int (eda_config_get_user_context (),
337 "gschem.window-geometry", "width", width
);
338 eda_config_set_int (eda_config_get_user_context (),
339 "gschem.window-geometry", "height", height
);
343 /* save torn-off menus */
344 if (w_current
->menubar
!= NULL
)
345 x_window_save_menu_geometry (
346 GTK_MENU_SHELL (w_current
->menubar
), w_current
);
348 /* save dock area geometry */
349 gtk_widget_get_allocation (w_current
->left_notebook
, &allocation
);
350 if (allocation
.width
> 0)
351 eda_config_set_int (eda_config_get_user_context (),
352 "gschem.dock-geometry.left",
353 "size", allocation
.width
);
355 gtk_widget_get_allocation (w_current
->bottom_notebook
, &allocation
);
356 if (allocation
.height
> 0)
357 eda_config_set_int (eda_config_get_user_context (),
358 "gschem.dock-geometry.bottom",
359 "size", allocation
.height
);
361 gtk_widget_get_allocation (w_current
->right_notebook
, &allocation
);
362 if (allocation
.width
> 0)
363 eda_config_set_int (eda_config_get_user_context (),
364 "gschem.dock-geometry.right",
365 "size", allocation
.width
);
369 x_window_restore_menu_geometry (GtkMenuShell
*menu_shell
,
370 GschemToplevel
*w_current
)
372 for (GList
*l
= gtk_container_get_children (GTK_CONTAINER (menu_shell
));
373 l
!= NULL
; l
= l
->next
) {
374 GtkMenuItem
*menu_item
= GTK_MENU_ITEM (l
->data
);
376 GtkWidget
*menu
= menu_item
->submenu
;
381 char *settings_name
= g_object_get_data (G_OBJECT (menu
), "settings-name");
382 if (settings_name
== NULL
)
383 /* menu doesn't have a settings name set */
387 gint
*coords
= eda_config_get_int_list (
388 eda_config_get_user_context (),
389 "gschem.menu-geometry", settings_name
, &length
, NULL
);
391 if (coords
!= NULL
&& length
== 4) {
392 gtk_menu_set_tearoff_state (GTK_MENU (menu
), TRUE
);
394 GtkWidget
*window
= GTK_MENU (menu
)->tearoff_window
;
395 g_return_if_fail (window
!= NULL
);
397 gtk_window_move (GTK_WINDOW (window
), coords
[0], coords
[1]);
398 gtk_window_resize (GTK_WINDOW (window
), coords
[2], coords
[3]);
402 x_window_restore_menu_geometry (GTK_MENU_SHELL (menu
), w_current
);
407 x_window_restore_all_menu_geometry (GschemToplevel
*w_current
)
409 g_signal_handlers_disconnect_by_func(
410 G_OBJECT (w_current
->main_window
),
411 G_CALLBACK (x_window_restore_all_menu_geometry
), w_current
);
413 if (w_current
->menubar
!= NULL
)
414 x_window_restore_menu_geometry (
415 GTK_MENU_SHELL (w_current
->menubar
), w_current
);
421 x_window_restore_geometry (GschemToplevel
*w_current
)
423 gint width
, height
, dock_size
;
426 /* restore main window size */
427 width
= eda_config_get_int (eda_config_get_user_context (),
428 "gschem.window-geometry", "width", NULL
);
429 height
= eda_config_get_int (eda_config_get_user_context (),
430 "gschem.window-geometry", "height", NULL
);
431 if (width
<= 0 || height
<= 0) {
435 g_object_set (w_current
->main_window
,
436 "default-width", width
,
437 "default-height", height
,
440 /* restore main window state */
441 window_state
= eda_config_get_string (eda_config_get_user_context (),
442 "gschem.window-geometry",
444 if (window_state
!= NULL
&& strcmp (window_state
, "fullscreen") == 0)
445 gtk_window_fullscreen (GTK_WINDOW (w_current
->main_window
));
446 else if (window_state
!= NULL
&& strcmp (window_state
, "maximized") == 0)
447 gtk_window_maximize (GTK_WINDOW (w_current
->main_window
));
449 /* defer restoring torn-off menus until main window is shown */
450 g_signal_connect_swapped (
451 G_OBJECT (w_current
->main_window
), "focus-in-event",
452 G_CALLBACK (x_window_restore_all_menu_geometry
), w_current
);
454 /* restore docking area dimensions */
455 dock_size
= eda_config_get_int (eda_config_get_user_context (),
456 "gschem.dock-geometry.left", "size", NULL
);
459 gtk_widget_set_size_request (w_current
->left_notebook
, dock_size
, 0);
461 dock_size
= eda_config_get_int (eda_config_get_user_context (),
462 "gschem.dock-geometry.bottom", "size", NULL
);
465 gtk_widget_set_size_request (w_current
->bottom_notebook
, 0, dock_size
);
467 dock_size
= eda_config_get_int (eda_config_get_user_context (),
468 "gschem.dock-geometry.right", "size", NULL
);
471 gtk_widget_set_size_request (w_current
->right_notebook
, dock_size
, 0);
475 /*! \todo Finish function documentation!!!
477 * \par Function Description
480 * When invoked (via signal delete_event), closes the current window
481 * if this is the last window, quit gschem
482 * used when you click the close button on the window which sends a DELETE
486 x_window_close_wm (GtkWidget
*widget
, GdkEvent
*event
, gpointer data
)
488 GschemToplevel
*w_current
= GSCHEM_TOPLEVEL (data
);
489 g_return_val_if_fail ((w_current
!= NULL
), TRUE
);
491 x_window_close(w_current
);
493 /* stop further propagation of the delete_event signal for window: */
494 /* - if user has cancelled the close the window should obvioulsy */
495 /* not be destroyed */
496 /* - otherwise window has already been destroyed, nothing more to */
503 x_window_update_file_change_notification (GschemToplevel
*w_current
,
506 if (page
->is_untitled
) {
507 g_object_set (w_current
->file_change_notification
,
514 gchar
*basename
= g_path_get_basename (page
->page_filename
);
515 gchar
*markup
= page
->exists_on_disk
516 ? g_markup_printf_escaped (
517 _("<b>The file \"%s\" has changed on disk.</b>\n\n%s"),
520 ? _("Do you want to drop your changes and reload the file?")
521 : _("Do you want to reload it?"))
522 : g_markup_printf_escaped (
523 _("<b>The file \"%s\" has been created on disk.</b>\n\n%s"),
526 ? _("Do you want to drop your changes and load the file?")
527 : _("Do you want to open it?"));
528 g_object_set (w_current
->file_change_notification
,
530 "path", page
->page_filename
,
531 "has-known-mtime", page
->exists_on_disk
,
532 "known-mtime", &page
->last_modified
,
533 "button-stock-id", page
->CHANGED
534 ? GTK_STOCK_REVERT_TO_SAVED
535 : page
->exists_on_disk
? GTK_STOCK_REFRESH
537 "button-label", page
->CHANGED
539 : page
->exists_on_disk
? _("_Reload")
548 x_window_file_change_response (GschemChangeNotification
*chnot
,
549 gint response_id
, gpointer user_data
)
551 if (response_id
== GTK_RESPONSE_ACCEPT
)
552 x_lowlevel_revert_page (chnot
->w_current
, chnot
->page
);
554 chnot
->page
->exists_on_disk
= chnot
->has_current_mtime
;
555 chnot
->page
->last_modified
= chnot
->current_mtime
;
556 x_window_update_file_change_notification (chnot
->w_current
, chnot
->page
);
562 x_window_update_patch_change_notification (GschemToplevel
*w_current
,
565 gchar
*patch_filename
= x_patch_guess_filename (page
);
566 gchar
*basename
, *markup
;
568 if (patch_filename
== NULL
) {
573 basename
= g_path_get_basename (patch_filename
);
574 if (page
->patch_filename
!= NULL
)
575 markup
= g_markup_printf_escaped (
576 _("<b>The back-annotation patch \"%s\" has been updated.</b>\n\n"
577 "Do you want to re-import it?"),
579 else if (page
->patch_seen_on_disk
)
580 markup
= g_markup_printf_escaped (
581 _("<b>The back-annotation patch \"%s\" has been updated.</b>\n\n"
582 "Do you want to import it?"),
584 else if (stat (patch_filename
, &buf
) != -1)
585 markup
= g_markup_printf_escaped (
586 _("<b>This file appears to have a back-annotation patch \"%s\" "
587 "associated with it.</b>\n\nDo you want to import it?"),
590 markup
= g_markup_printf_escaped (
591 _("<b>A back-annotation patch \"%s\" has been created.</b>\n\n"
592 "Do you want to import it?"),
596 g_object_set (w_current
->patch_change_notification
,
598 "path", patch_filename
,
599 "has-known-mtime", page
->patch_seen_on_disk
,
600 "known-mtime", &page
->patch_mtime
,
601 "button-label", _("_Import"),
606 g_free (patch_filename
);
610 x_window_patch_change_response (GschemChangeNotification
*chnot
,
611 gint response_id
, gpointer user_data
)
613 if (response_id
== GTK_RESPONSE_ACCEPT
) {
614 if (chnot
->page
->patch_filename
== NULL
)
615 chnot
->page
->patch_filename
= g_strdup (chnot
->path
);
616 x_patch_do_import (chnot
->w_current
, chnot
->page
);
618 chnot
->page
->patch_seen_on_disk
= chnot
->has_current_mtime
;
619 chnot
->page
->patch_mtime
= chnot
->current_mtime
;
620 x_window_update_patch_change_notification (chnot
->w_current
, chnot
->page
);
625 /*! \todo Finish function documentation!!!
627 * \par Function Description
630 void x_window_create_main(GschemToplevel
*w_current
)
632 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
634 GtkPolicyType policy
;
635 GtkWidget
*main_box
=NULL
;
636 GtkWidget
*handlebox
=NULL
;
638 GtkAdjustment
*hadjustment
;
639 GtkAdjustment
*vadjustment
;
640 char *right_button_text
;
641 GtkWidget
*left_hpaned
, *right_hpaned
;
645 w_current
->main_window
= GTK_WIDGET (gschem_main_window_new ());
647 gtk_widget_set_name (w_current
->main_window
, "gschem");
648 gtk_window_set_policy (GTK_WINDOW (w_current
->main_window
), TRUE
, TRUE
, TRUE
);
650 /* We want the widgets to flow around the drawing area, so we don't
651 * set a size of the main window. The drawing area's size is fixed,
656 * normally we let the window manager handle locating and sizing
657 * the window. However, for some batch processing of schematics
658 * (generating a pdf of all schematics for example) we want to
659 * override this. Hence "auto_place_mode".
661 if( auto_place_mode
)
662 gtk_widget_set_uposition (w_current
->main_window
, 10, 10);
664 /* this should work fine */
665 g_signal_connect (G_OBJECT (w_current
->main_window
), "delete_event",
666 G_CALLBACK (x_window_close_wm
), w_current
);
668 /* Containers first */
669 main_box
= gtk_vbox_new(FALSE
, 1);
670 gtk_container_set_border_width (GTK_CONTAINER (main_box
), 0);
671 gtk_container_add(GTK_CONTAINER(w_current
->main_window
), main_box
);
673 x_menus_create_main_menu (w_current
);
674 if (w_current
->menubar
!= NULL
) {
675 if (w_current
->handleboxes
) {
676 handlebox
= gtk_handle_box_new ();
677 gtk_box_pack_start (GTK_BOX (main_box
), handlebox
, FALSE
, FALSE
, 0);
678 gtk_container_add (GTK_CONTAINER (handlebox
), w_current
->menubar
);
680 gtk_box_pack_start (GTK_BOX (main_box
), w_current
->menubar
,
684 gschem_action_set_sensitive (action_view_menubar
, w_current
->menubar
!= NULL
,
686 gschem_action_set_active (action_view_menubar
, w_current
->menubar
!= NULL
,
689 gtk_widget_realize (w_current
->main_window
);
691 x_menus_create_toolbar (w_current
);
692 if (w_current
->toolbar
!= NULL
) {
693 if (w_current
->handleboxes
) {
694 handlebox
= gtk_handle_box_new ();
695 gtk_box_pack_start (GTK_BOX (main_box
), handlebox
, FALSE
, FALSE
, 0);
696 gtk_container_add (GTK_CONTAINER (handlebox
), w_current
->toolbar
);
697 gtk_widget_set_visible (handlebox
, w_current
->toolbars
);
698 gtk_widget_set_no_show_all (handlebox
, TRUE
);
700 gtk_box_pack_start (GTK_BOX (main_box
), w_current
->toolbar
,
702 gtk_widget_set_visible (w_current
->toolbar
, w_current
->toolbars
);
703 gtk_widget_set_no_show_all (w_current
->toolbar
, TRUE
);
706 gschem_action_set_sensitive (action_view_toolbar
, w_current
->toolbar
!= NULL
,
708 gschem_action_set_active (action_view_toolbar
,
709 w_current
->toolbars
&& w_current
->toolbar
!= NULL
,
712 left_hpaned
= gtk_hpaned_new ();
713 gtk_container_add (GTK_CONTAINER(main_box
), left_hpaned
);
715 w_current
->left_notebook
= gtk_notebook_new ();
716 gtk_paned_pack1 (GTK_PANED (left_hpaned
),
717 w_current
->left_notebook
,
720 gtk_notebook_set_group_name (GTK_NOTEBOOK (w_current
->left_notebook
),
723 right_hpaned
= gtk_hpaned_new ();
724 gtk_paned_pack2 (GTK_PANED (left_hpaned
),
729 w_current
->right_notebook
= gtk_notebook_new ();
730 gtk_paned_pack2 (GTK_PANED (right_hpaned
),
731 w_current
->right_notebook
,
734 gtk_notebook_set_group_name (GTK_NOTEBOOK (w_current
->right_notebook
),
737 vpaned
= gtk_vpaned_new ();
738 gtk_paned_pack1 (GTK_PANED (right_hpaned
),
743 w_current
->bottom_notebook
= gtk_notebook_new ();
744 gtk_paned_pack2 (GTK_PANED (vpaned
),
745 w_current
->bottom_notebook
,
748 gtk_notebook_set_group_name (GTK_NOTEBOOK (w_current
->bottom_notebook
),
751 work_box
= gtk_vbox_new (FALSE
, 0);
752 gtk_paned_pack1 (GTK_PANED (vpaned
),
757 w_current
->file_change_notification
=
758 g_object_new (GSCHEM_TYPE_CHANGE_NOTIFICATION
,
759 "gschem-toplevel", w_current
,
760 "message-type", GTK_MESSAGE_QUESTION
,
762 g_signal_connect (w_current
->file_change_notification
, "response",
763 G_CALLBACK (x_window_file_change_response
), NULL
);
764 gtk_box_pack_start (GTK_BOX (work_box
),
765 w_current
->file_change_notification
->info_bar
,
768 w_current
->patch_change_notification
=
769 g_object_new (GSCHEM_TYPE_CHANGE_NOTIFICATION
,
770 "gschem-toplevel", w_current
,
771 "message-type", GTK_MESSAGE_INFO
,
773 g_signal_connect (w_current
->patch_change_notification
, "response",
774 G_CALLBACK (x_window_patch_change_response
), NULL
);
775 gtk_box_pack_start (GTK_BOX (work_box
),
776 w_current
->patch_change_notification
->info_bar
,
779 /* Try to create popup menu (appears in right mouse button */
780 x_menus_create_main_popup (w_current
);
783 /* Setup a GtkScrolledWindow for the drawing area */
784 hadjustment
= GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
786 toplevel
->init_right
,
791 vadjustment
= GTK_ADJUSTMENT (gtk_adjustment_new (toplevel
->init_bottom
,
793 toplevel
->init_bottom
- toplevel
->init_top
,
798 scrolled
= gtk_scrolled_window_new (hadjustment
, vadjustment
);
799 gtk_container_add (GTK_CONTAINER (work_box
), scrolled
);
800 x_window_create_drawing(scrolled
, w_current
);
801 x_window_setup_draw_events(w_current
);
803 policy
= (w_current
->scrollbars_flag
) ? GTK_POLICY_ALWAYS
: GTK_POLICY_NEVER
;
804 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
), policy
, policy
);
805 gschem_action_set_active (action_view_scrollbars
, w_current
->scrollbars_flag
,
809 w_current
->find_text_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_FIND_TEXT_WIDGET
, NULL
));
811 gtk_box_pack_start (GTK_BOX (work_box
),
812 w_current
->find_text_widget
,
817 g_signal_connect (w_current
->find_text_widget
,
819 G_CALLBACK (&x_window_find_text
),
823 w_current
->hide_text_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_SHOW_HIDE_TEXT_WIDGET
,
824 "button-text", pgettext ("actuate", "Hide"),
825 "label-text", _("Hide text starting with:"),
828 gtk_box_pack_start (GTK_BOX (work_box
),
829 w_current
->hide_text_widget
,
834 g_signal_connect (w_current
->hide_text_widget
,
836 G_CALLBACK (&x_window_hide_text
),
840 w_current
->show_text_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_SHOW_HIDE_TEXT_WIDGET
,
841 "button-text", pgettext ("actuate", "Show"),
842 "label-text", _("Show text starting with:"),
845 gtk_box_pack_start (GTK_BOX (work_box
),
846 w_current
->show_text_widget
,
851 g_signal_connect (w_current
->show_text_widget
,
853 G_CALLBACK (&x_window_show_text
),
857 w_current
->macro_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_MACRO_WIDGET
, NULL
));
859 gtk_box_pack_start (GTK_BOX (work_box
),
860 w_current
->macro_widget
,
865 g_signal_connect (w_current
->macro_widget
,
867 G_CALLBACK (&x_window_invoke_macro
),
871 w_current
->compselect_dockable
= g_object_new (
872 GSCHEM_TYPE_COMPSELECT_DOCKABLE
,
873 "title", _("Library"),
874 "settings-name", "compselect",
876 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
,
877 "initial-width", 500,
878 "initial-height", 600,
879 "gschem-toplevel", w_current
,
882 w_current
->object_properties_dockable
= g_object_new (
883 GSCHEM_TYPE_OBJECT_PROPERTIES_DOCKABLE
,
884 "title", _("Object"),
885 "settings-name", "object-properties", /* line-type */
886 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
,
887 "initial-width", 400,
888 "initial-height", 600,
889 "gschem-toplevel", w_current
,
892 w_current
->text_properties_dockable
= g_object_new (
893 GSCHEM_TYPE_TEXT_PROPERTIES_DOCKABLE
,
895 "settings-name", "text-edit",
896 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
,
897 "initial-width", 400,
898 "initial-height", 450,
899 "gschem-toplevel", w_current
,
902 w_current
->multiattrib_dockable
= g_object_new (
903 GSCHEM_TYPE_MULTIATTRIB_DOCKABLE
,
904 "title", _("Attributes"),
905 "settings-name", "multiattrib",
906 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
,
907 "initial-width", 450,
908 "initial-height", 450,
909 "gschem-toplevel", w_current
,
912 w_current
->options_dockable
= g_object_new (
913 GSCHEM_TYPE_OPTIONS_DOCKABLE
,
914 "title", _("Options"),
915 "settings-name", "options", /* snap-size */
916 "initial-state", GSCHEM_DOCKABLE_STATE_HIDDEN
,
917 "initial-width", 320,
918 "initial-height", 350,
919 "gschem-toplevel", w_current
,
922 w_current
->log_dockable
= g_object_new (
923 GSCHEM_TYPE_LOG_DOCKABLE
,
924 "title", _("Status"),
925 "settings-name", "log",
926 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
,
927 "initial-width", 640,
928 "initial-height", 480,
929 "gschem-toplevel", w_current
,
932 w_current
->find_text_dockable
= g_object_new (
933 GSCHEM_TYPE_FIND_TEXT_DOCKABLE
,
934 "title", _("Search results"),
935 "settings-name", "find-text",
936 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
,
937 "initial-width", 500,
938 "initial-height", 300,
939 "gschem-toplevel", w_current
,
941 g_signal_connect (w_current
->find_text_dockable
,
943 G_CALLBACK (&x_window_select_text
),
946 w_current
->patch_dockable
= g_object_new (
947 GSCHEM_TYPE_PATCH_DOCKABLE
,
949 "settings-name", "patch",
950 "initial-state", GSCHEM_DOCKABLE_STATE_HIDDEN
,
951 "initial-width", 500,
952 "initial-height", 300,
953 "gschem-toplevel", w_current
,
956 w_current
->pagesel_dockable
= g_object_new (
957 GSCHEM_TYPE_PAGESEL_DOCKABLE
,
959 "settings-name", "pagesel",
960 "initial-state", GSCHEM_DOCKABLE_STATE_HIDDEN
,
961 "initial-width", 515,
962 "initial-height", 180,
963 "gschem-toplevel", w_current
,
966 gschem_dockable_initialize_toplevel (w_current
);
970 if (default_third_button
== POPUP_ENABLED
) {
971 right_button_text
= _("Menu/Cancel");
973 right_button_text
= _("Pan/Cancel");
976 w_current
->bottom_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_BOTTOM_WIDGET
,
977 "grid-mode", gschem_options_get_grid_mode (w_current
->options
),
978 "grid-size", gschem_options_get_snap_size (w_current
->options
), /* x_grid_query_drawn_spacing (w_current), -- occurs before the page is set */
979 "left-button-text", _("Pick"),
980 "middle-button-text", _("none"),
981 "right-button-text", right_button_text
,
982 "snap-mode", gschem_options_get_snap_mode (w_current
->options
),
983 "snap-size", gschem_options_get_snap_size (w_current
->options
),
984 "status-text", _("Select Mode"),
987 i_update_middle_button (w_current
, NULL
, NULL
);
989 gtk_box_pack_start (GTK_BOX (main_box
), w_current
->bottom_widget
, FALSE
, FALSE
, 0);
991 x_window_restore_geometry (w_current
);
992 g_signal_connect (G_OBJECT (w_current
->main_window
), "window-state-event",
993 G_CALLBACK (x_window_state_event
), w_current
);
995 gtk_widget_show_all (w_current
->main_window
);
997 /* hide unused notebooks */
998 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (w_current
->left_notebook
)) == 0)
999 gtk_widget_hide (w_current
->left_notebook
);
1000 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (w_current
->bottom_notebook
)) == 0)
1001 gtk_widget_hide (w_current
->bottom_notebook
);
1002 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (w_current
->right_notebook
)) == 0)
1003 gtk_widget_hide (w_current
->right_notebook
);
1006 /*! \todo Finish function documentation!!!
1008 * \par Function Description
1011 void x_window_close(GschemToplevel
*w_current
)
1013 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
1014 gboolean last_window
= FALSE
;
1016 /* If we're closing whilst inside an action, re-wind the
1017 * page contents back to their state before we started */
1018 if (w_current
->inside_action
) {
1019 i_cancel (w_current
);
1022 /* last chance to save possible unsaved pages */
1023 if (!x_dialog_close_window (w_current
)) {
1024 /* user somehow cancelled the close */
1028 x_clipboard_finish (w_current
);
1031 o_conn_print_hash(w_current
->page_current
->conn_table
);
1034 w_current
->dont_invalidate
= TRUE
;
1036 /* save window geometry */
1037 x_window_save_geometry (w_current
);
1039 /* close all the dialog boxes */
1040 if (w_current
->sowindow
)
1041 gtk_widget_destroy(w_current
->sowindow
);
1043 if (w_current
->tiwindow
)
1044 gtk_widget_destroy(w_current
->tiwindow
);
1046 if (w_current
->aawindow
)
1047 gtk_widget_destroy(w_current
->aawindow
);
1049 if (w_current
->aewindow
)
1050 gtk_widget_destroy(w_current
->aewindow
);
1052 if (w_current
->hkwindow
)
1053 gtk_widget_destroy(w_current
->hkwindow
);
1055 if (w_current
->cowindow
)
1056 gtk_widget_destroy(w_current
->cowindow
);
1058 if (w_current
->sewindow
)
1059 gtk_widget_destroy(w_current
->sewindow
);
1061 /* save dock window geometry, close dock windows, disconnect signals */
1062 gschem_dockable_cleanup_toplevel (w_current
);
1064 g_clear_object (&w_current
->compselect_dockable
);
1065 g_clear_object (&w_current
->object_properties_dockable
);
1066 g_clear_object (&w_current
->text_properties_dockable
);
1067 g_clear_object (&w_current
->multiattrib_dockable
);
1068 g_clear_object (&w_current
->options_dockable
);
1069 g_clear_object (&w_current
->log_dockable
);
1070 g_clear_object (&w_current
->find_text_dockable
);
1071 g_clear_object (&w_current
->patch_dockable
);
1072 g_clear_object (&w_current
->pagesel_dockable
);
1074 if (g_list_length (global_window_list
) == 1) {
1075 /* no more window after this one, remember to quit */
1079 if (toplevel
->major_changed_refdes
) {
1080 GList
* current
= toplevel
->major_changed_refdes
;
1083 /* printf("yeah freeing: %s\n", (char*) current->data); */
1084 g_free(current
->data
);
1085 current
= g_list_next(current
);
1087 g_list_free(toplevel
->major_changed_refdes
);
1090 /* stuff that has to be done before we free w_current */
1092 /* close the log file */
1094 /* free the buffers */
1095 o_buffer_free (w_current
);
1098 /* Clear Guile smob weak ref */
1099 if (w_current
->smob
!= SCM_UNDEFINED
) {
1100 SCM_SET_SMOB_DATA (w_current
->smob
, NULL
);
1101 w_current
->smob
= SCM_UNDEFINED
;
1104 /* finally close the main window */
1105 gtk_widget_destroy(w_current
->main_window
);
1107 global_window_list
= g_list_remove (global_window_list
, w_current
);
1108 gschem_toplevel_free (w_current
);
1110 /* just closed last window, so quit */
1116 /*! \todo Finish function documentation!!!
1118 * \par Function Description
1121 void x_window_close_all(GschemToplevel
*w_current
)
1123 GschemToplevel
*current
;
1124 GList
*list_copy
, *iter
;
1126 iter
= list_copy
= g_list_copy (global_window_list
);
1127 while (iter
!= NULL
) {
1128 current
= (GschemToplevel
*)iter
->data
;
1129 iter
= g_list_next (iter
);
1130 x_window_close (current
);
1132 g_list_free (list_copy
);
1135 /*! \brief Changes the current page.
1136 * \par Function Description
1137 * This function displays the specified page <B>page</B> in the
1138 * window attached to <B>toplevel</B>.
1140 * It changes the <B>toplevel</B>'s current page to <B>page</B>,
1141 * draws it and updates the user interface.
1143 * <B>page</B> has to be in the list of PAGEs attached to <B>toplevel</B>.
1145 * \param [in] w_current The toplevel environment.
1146 * \param [in] page The page to become current page.
1149 x_window_set_current_page (GschemToplevel
*w_current
, PAGE
*page
)
1151 GschemPageView
*page_view
= gschem_toplevel_get_current_page_view (w_current
);
1152 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
1155 g_return_if_fail (page_view
!= NULL
);
1156 g_return_if_fail (toplevel
!= NULL
);
1157 g_return_if_fail (page
!= NULL
);
1159 g_warn_if_fail (page_view
->page
== toplevel
->page_current
||
1160 page_view
->page
== NULL
);
1162 if (page
== toplevel
->page_current
&& page_view
->page
!= NULL
)
1166 o_redraw_cleanstates (w_current
);
1168 gschem_page_view_set_page (page_view
, page
);
1170 gschem_action_set_sensitive (action_page_revert
,
1171 page
->is_untitled
== FALSE
&&
1172 g_file_test (page
->page_filename
,
1173 G_FILE_TEST_EXISTS
|
1174 G_FILE_TEST_IS_REGULAR
),
1177 o_undo_update_actions (w_current
, page
);
1179 iter
= g_list_find (geda_list_get_glist (toplevel
->pages
), page
);
1180 gschem_action_set_sensitive (action_page_prev
,
1181 w_current
->enforce_hierarchy
1182 ? s_hierarchy_find_prev_page (
1183 toplevel
->pages
, page
) != NULL
1184 : iter
!= NULL
&& iter
->prev
!= NULL
,
1186 gschem_action_set_sensitive (action_page_next
,
1187 w_current
->enforce_hierarchy
1188 ? s_hierarchy_find_next_page(
1189 toplevel
->pages
, page
) != NULL
1190 : iter
!= NULL
&& iter
->next
!= NULL
,
1192 gschem_action_set_sensitive (action_hierarchy_up
, page
->up
>= 0, w_current
);
1194 i_update_menus (w_current
);
1195 /* i_set_filename (w_current, page->page_filename); */
1197 x_window_update_file_change_notification (w_current
, page
);
1198 x_window_update_patch_change_notification (w_current
, page
);
1200 x_pagesel_update (w_current
);
1201 x_multiattrib_update (w_current
);
1204 /*! \brief Raise the main window to the front.
1206 * This is mostly equivalent to
1207 * gtk_window_present (GTK_WINDOW (w_current->main_window));
1209 * One of the two actions that \c gtk_window_present performs on an
1210 * already-visible window (\c gdk_window_show) is triggering a bug
1211 * with toolbar icon drawing, the other (\c gdk_window_focus) is the
1212 * one we actually want. In order to work around that bug, just call
1213 * \c gdk_window_focus directly.
1215 * \param [in] w_current the toplevel environment
1217 void x_window_present (GschemToplevel
*w_current
)
1219 //gdk_window_show (w_current->main_window->window); /* the culprit */
1221 #ifdef GDK_WINDOWING_X11
1222 GdkDisplay
*display
= gtk_widget_get_display (w_current
->main_window
);
1223 guint32 timestamp
= gdk_x11_display_get_user_time (display
);
1225 guint32 timestamp
= gtk_get_current_event_time ();
1228 gdk_window_focus (w_current
->main_window
->window
, timestamp
);
1231 /*! \brief Setup default icon for GTK windows
1233 * \par Function Description
1234 * Sets the default window icon by name, to be found in the current icon
1235 * theme. The name used is \#defined above as GSCHEM_THEME_ICON_NAME.
1237 void x_window_set_default_icon( void )
1239 gtk_window_set_default_icon_name( GSCHEM_THEME_ICON_NAME
);
1242 /*! \brief Setup icon search paths.
1243 * \par Function Description
1244 * Add the icons installed by gschem to the search path for the
1245 * default icon theme, so that they can be automatically found by GTK.
1248 x_window_init_icons (void)
1252 g_return_if_fail (s_path_sys_data () != NULL
);
1254 icon_path
= g_build_filename (s_path_sys_data (), "icons", NULL
);
1255 gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
1260 /*! \brief Creates a new X window.
1262 * \par Function description
1264 * Creates and initializes new GschemToplevel object and then sets
1265 * and setups its libgeda \a toplevel.
1267 * \param toplevel The libgeda TOPLEVEL object.
1268 * \return Pointer to the new GschemToplevel object.
1270 GschemToplevel
* x_window_new (TOPLEVEL
*toplevel
)
1272 GschemToplevel
*w_current
;
1274 w_current
= gschem_toplevel_new ();
1275 gschem_toplevel_set_toplevel (w_current
,
1276 (toplevel
!= NULL
) ? toplevel
: s_toplevel_new ());
1278 gschem_toplevel_get_toplevel (w_current
)->load_newer_backup_func
= x_fileselect_load_backup
;
1279 gschem_toplevel_get_toplevel (w_current
)->load_newer_backup_data
= w_current
;
1281 o_text_set_rendered_bounds_func (gschem_toplevel_get_toplevel (w_current
),
1282 o_text_get_rendered_bounds
, w_current
);
1284 /* Damage notifications should invalidate the object on screen */
1285 o_add_change_notify (gschem_toplevel_get_toplevel (w_current
),
1286 (ChangeNotifyFunc
) o_invalidate
,
1287 (ChangeNotifyFunc
) o_invalidate
, w_current
);
1289 x_window_setup (w_current
);