1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 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 /* update sensitivity of paste action */
72 x_clipboard_update_menus (w_current
);
74 gschem_action_set_sensitive (action_add_last_component
, FALSE
, w_current
);
76 /* disable terminal REPL action if stdin is not a terminal */
77 gschem_action_set_sensitive (action_file_repl
, isatty (STDIN_FILENO
),
81 /*! \todo Finish function documentation!!!
83 * \par Function Description
86 void x_window_create_drawing(GtkWidget
*scrolled
, GschemToplevel
*w_current
)
89 w_current
->drawing_area
= GTK_WIDGET (gschem_page_view_new_with_page (w_current
->toplevel
->page_current
));
90 /* Set the size here. Be sure that it has an aspect ratio of 1.333
91 * We could calculate this based on root window size, but for now
92 * lets just set it to:
93 * Width = root_width*3/4 Height = Width/1.3333333333
94 * 1.3333333 is the desired aspect ratio!
97 gtk_container_add(GTK_CONTAINER(scrolled
), w_current
->drawing_area
);
99 GTK_WIDGET_SET_FLAGS (w_current
->drawing_area
, GTK_CAN_FOCUS
);
100 gtk_widget_grab_focus (w_current
->drawing_area
);
101 gtk_widget_show (w_current
->drawing_area
);
104 /*! \brief Set up callbacks for window events that affect drawing.
105 * \par Function Description
107 * Installs GTK+ callback handlers for signals that are emitted by
108 * the drawing area, and some for the main window that affect the drawing
111 * \param [in] w_current The toplevel environment.
113 void x_window_setup_draw_events(GschemToplevel
*w_current
)
116 gchar
*detailed_signal
;
120 struct event_reg_t drawing_area_events
[] = {
121 { "expose_event", G_CALLBACK(x_event_expose
) },
122 { "expose_event", G_CALLBACK(x_event_raise_dialog_boxes
) },
123 { "button_press_event", G_CALLBACK(x_event_button_pressed
) },
124 { "button_release_event", G_CALLBACK(x_event_button_released
) },
125 { "motion_notify_event", G_CALLBACK(x_event_motion
) },
126 { "configure_event", G_CALLBACK(x_event_configure
) },
127 { "key_press_event", G_CALLBACK(x_event_key
) },
128 { "key_release_event", G_CALLBACK(x_event_key
) },
129 { "scroll_event", G_CALLBACK(x_event_scroll
) },
130 { "update-grid-info", G_CALLBACK(i_update_grid_info_callback
) },
131 { "notify::page", G_CALLBACK(gschem_toplevel_notify_page_callback
) },
133 struct event_reg_t main_window_events
[] = {
134 { "enter_notify_event", G_CALLBACK(x_event_enter
) },
136 struct event_reg_t
*tmp
;
138 /* is the configure event type missing here? hack */
139 gtk_widget_set_events (w_current
->drawing_area
,
141 GDK_POINTER_MOTION_MASK
|
142 GDK_BUTTON_PRESS_MASK
|
143 GDK_ENTER_NOTIFY_MASK
|
145 GDK_BUTTON_RELEASE_MASK
);
147 for (tmp
= drawing_area_events
; tmp
->detailed_signal
!= NULL
; tmp
++) {
148 g_signal_connect (w_current
->drawing_area
,
149 tmp
->detailed_signal
,
154 for (tmp
= main_window_events
; tmp
->detailed_signal
!= NULL
; tmp
++) {
155 g_signal_connect (w_current
->main_window
,
156 tmp
->detailed_signal
,
164 x_window_find_text (GtkWidget
*widget
, gint response
, GschemToplevel
*w_current
)
169 g_return_if_fail (w_current
!= NULL
);
170 g_return_if_fail (w_current
->toplevel
!= NULL
);
173 case GTK_RESPONSE_OK
:
174 count
= gschem_find_text_dockable_find (
175 GSCHEM_FIND_TEXT_DOCKABLE (w_current
->find_text_dockable
),
176 geda_list_get_glist (w_current
->toplevel
->pages
),
177 gschem_find_text_widget_get_find_type (GSCHEM_FIND_TEXT_WIDGET (w_current
->find_text_widget
)),
178 gschem_find_text_widget_get_find_text_string (GSCHEM_FIND_TEXT_WIDGET (w_current
->find_text_widget
)),
179 gschem_find_text_widget_get_descend (GSCHEM_FIND_TEXT_WIDGET (w_current
->find_text_widget
)));
181 gschem_dockable_present (w_current
->find_text_dockable
);
186 case GTK_RESPONSE_CANCEL
:
187 case GTK_RESPONSE_DELETE_EVENT
:
192 printf("x_window_find_text(): strange signal %d\n", response
);
196 gtk_widget_grab_focus (w_current
->drawing_area
);
197 gtk_widget_hide (GTK_WIDGET (widget
));
204 x_window_hide_text (GtkWidget
*widget
, gint response
, GschemToplevel
*w_current
)
206 g_return_if_fail (w_current
!= NULL
);
207 g_return_if_fail (w_current
->toplevel
!= NULL
);
209 if (response
== GTK_RESPONSE_OK
) {
210 o_edit_hide_specific_text (w_current
,
211 s_page_objects (w_current
->toplevel
->page_current
),
212 gschem_show_hide_text_widget_get_text_string (GSCHEM_SHOW_HIDE_TEXT_WIDGET (widget
)));
215 gtk_widget_grab_focus (w_current
->drawing_area
);
216 gtk_widget_hide (GTK_WIDGET (widget
));
221 x_window_show_text (GtkWidget
*widget
, gint response
, GschemToplevel
*w_current
)
223 g_return_if_fail (w_current
!= NULL
);
224 g_return_if_fail (w_current
->toplevel
!= NULL
);
226 if (response
== GTK_RESPONSE_OK
) {
227 o_edit_show_specific_text (w_current
,
228 s_page_objects (w_current
->toplevel
->page_current
),
229 gschem_show_hide_text_widget_get_text_string (GSCHEM_SHOW_HIDE_TEXT_WIDGET (widget
)));
232 gtk_widget_grab_focus (w_current
->drawing_area
);
233 gtk_widget_hide (GTK_WIDGET (widget
));
238 x_window_invoke_macro (GschemMacroWidget
*widget
, int response
, GschemToplevel
*w_current
)
240 if (response
== GTK_RESPONSE_OK
) {
241 const char *macro
= gschem_macro_widget_get_macro_string (widget
);
243 SCM interpreter
= scm_list_2(scm_from_utf8_symbol("invoke-macro"),
244 scm_from_utf8_string(macro
));
246 scm_dynwind_begin (0);
247 g_dynwind_window (w_current
);
248 g_scm_eval_protected(interpreter
, SCM_UNDEFINED
);
252 gtk_widget_grab_focus (w_current
->drawing_area
);
253 gtk_widget_hide (GTK_WIDGET (widget
));
257 x_window_select_text (GschemFindTextDockable
*dockable
, OBJECT
*object
, GschemToplevel
*w_current
)
259 GschemPageView
*view
= gschem_toplevel_get_current_page_view (w_current
);
260 g_return_if_fail (view
!= NULL
);
264 g_return_if_fail (object
!= NULL
);
265 page_obj
= gschem_page_get_page_object(object
);
266 g_return_if_fail (page_obj
!= NULL
);
268 x_window_set_current_page (w_current
, page_obj
->page
);
270 gschem_page_view_zoom_text (view
, object
, TRUE
);
274 x_window_state_event (GtkWidget
*widget
,
275 GdkEventWindowState
*event
,
278 eda_config_set_string (
279 eda_config_get_user_context (),
280 "gschem.window-geometry", "state",
281 (event
->new_window_state
&
282 GDK_WINDOW_STATE_FULLSCREEN
) ? "fullscreen" :
283 (event
->new_window_state
&
284 GDK_WINDOW_STATE_MAXIMIZED
) ? "maximized" : "normal");
286 return FALSE
; /* propagate the event further */
290 x_window_save_menu_geometry (GtkMenuShell
*menu_shell
,
291 GschemToplevel
*w_current
)
293 for (GList
*l
= gtk_container_get_children (GTK_CONTAINER (menu_shell
));
294 l
!= NULL
; l
= l
->next
) {
295 GtkMenuItem
*menu_item
= GTK_MENU_ITEM (l
->data
);
297 GtkWidget
*menu
= menu_item
->submenu
;
302 char *settings_name
= g_object_get_data (G_OBJECT (menu
), "settings-name");
303 if (settings_name
== NULL
)
304 /* menu doesn't have a settings name set */
310 if (GTK_MENU (menu
)->torn_off
) {
311 GtkWidget
*window
= GTK_MENU (menu
)->tearoff_window
;
312 g_return_if_fail (window
!= NULL
);
314 gtk_window_get_position (GTK_WINDOW (window
), &coords
[0], &coords
[1]);
315 gtk_window_get_size (GTK_WINDOW (window
), &coords
[2], &coords
[3]);
319 eda_config_set_int_list (
320 eda_config_get_user_context (),
321 "gschem.menu-geometry", settings_name
, coords
, length
);
323 x_window_save_menu_geometry (GTK_MENU_SHELL (menu
), w_current
);
328 x_window_save_geometry (GschemToplevel
*w_current
)
331 GtkAllocation allocation
;
333 /* save window geometry */
334 window_state
= eda_config_get_string (eda_config_get_user_context (),
335 "gschem.window-geometry",
337 if (window_state
!= NULL
&& strcmp (window_state
, "normal") == 0) {
338 gint width
= -1, height
= -1;
339 gtk_window_get_size (GTK_WINDOW (w_current
->main_window
), &width
, &height
);
340 if (width
> 0 && height
> 0) {
341 eda_config_set_int (eda_config_get_user_context (),
342 "gschem.window-geometry", "width", width
);
343 eda_config_set_int (eda_config_get_user_context (),
344 "gschem.window-geometry", "height", height
);
347 g_free (window_state
);
349 /* save torn-off menus */
350 if (w_current
->menubar
!= NULL
)
351 x_window_save_menu_geometry (
352 GTK_MENU_SHELL (w_current
->menubar
), w_current
);
354 /* save dock area geometry */
355 gtk_widget_get_allocation (w_current
->left_notebook
, &allocation
);
356 if (allocation
.width
> 0)
357 eda_config_set_int (eda_config_get_user_context (),
358 "gschem.dock-geometry.left",
359 "size", allocation
.width
);
361 gtk_widget_get_allocation (w_current
->bottom_notebook
, &allocation
);
362 if (allocation
.height
> 0)
363 eda_config_set_int (eda_config_get_user_context (),
364 "gschem.dock-geometry.bottom",
365 "size", allocation
.height
);
367 gtk_widget_get_allocation (w_current
->right_notebook
, &allocation
);
368 if (allocation
.width
> 0)
369 eda_config_set_int (eda_config_get_user_context (),
370 "gschem.dock-geometry.right",
371 "size", allocation
.width
);
375 x_window_restore_menu_geometry (GtkMenuShell
*menu_shell
,
376 GschemToplevel
*w_current
)
378 for (GList
*l
= gtk_container_get_children (GTK_CONTAINER (menu_shell
));
379 l
!= NULL
; l
= l
->next
) {
380 GtkMenuItem
*menu_item
= GTK_MENU_ITEM (l
->data
);
382 GtkWidget
*menu
= menu_item
->submenu
;
387 char *settings_name
= g_object_get_data (G_OBJECT (menu
), "settings-name");
388 if (settings_name
== NULL
)
389 /* menu doesn't have a settings name set */
393 gint
*coords
= eda_config_get_int_list (
394 eda_config_get_user_context (),
395 "gschem.menu-geometry", settings_name
, &length
, NULL
);
397 if (coords
!= NULL
&& length
== 4) {
398 gtk_menu_set_tearoff_state (GTK_MENU (menu
), TRUE
);
400 GtkWidget
*window
= GTK_MENU (menu
)->tearoff_window
;
401 g_return_if_fail (window
!= NULL
);
403 gtk_window_move (GTK_WINDOW (window
), coords
[0], coords
[1]);
404 gtk_window_resize (GTK_WINDOW (window
), coords
[2], coords
[3]);
408 x_window_restore_menu_geometry (GTK_MENU_SHELL (menu
), w_current
);
413 x_window_restore_all_menu_geometry (GschemToplevel
*w_current
)
415 g_signal_handlers_disconnect_by_func(
416 G_OBJECT (w_current
->main_window
),
417 G_CALLBACK (x_window_restore_all_menu_geometry
), w_current
);
419 if (w_current
->menubar
!= NULL
)
420 x_window_restore_menu_geometry (
421 GTK_MENU_SHELL (w_current
->menubar
), w_current
);
427 x_window_restore_geometry (GschemToplevel
*w_current
)
429 gint width
, height
, dock_size
;
432 /* restore main window size */
433 width
= eda_config_get_int (eda_config_get_user_context (),
434 "gschem.window-geometry", "width", NULL
);
435 height
= eda_config_get_int (eda_config_get_user_context (),
436 "gschem.window-geometry", "height", NULL
);
437 if (width
<= 0 || height
<= 0) {
441 g_object_set (w_current
->main_window
,
442 "default-width", width
,
443 "default-height", height
,
446 /* restore main window state */
447 window_state
= eda_config_get_string (eda_config_get_user_context (),
448 "gschem.window-geometry",
450 if (window_state
!= NULL
&& strcmp (window_state
, "fullscreen") == 0)
451 gtk_window_fullscreen (GTK_WINDOW (w_current
->main_window
));
452 else if (window_state
!= NULL
&& strcmp (window_state
, "maximized") == 0)
453 gtk_window_maximize (GTK_WINDOW (w_current
->main_window
));
454 g_free (window_state
);
456 /* defer restoring torn-off menus until main window is shown */
457 g_signal_connect_swapped (
458 G_OBJECT (w_current
->main_window
), "focus-in-event",
459 G_CALLBACK (x_window_restore_all_menu_geometry
), w_current
);
461 /* restore docking area dimensions */
462 dock_size
= eda_config_get_int (eda_config_get_user_context (),
463 "gschem.dock-geometry.left", "size", NULL
);
466 gtk_widget_set_size_request (w_current
->left_notebook
, dock_size
, 0);
468 dock_size
= eda_config_get_int (eda_config_get_user_context (),
469 "gschem.dock-geometry.bottom", "size", NULL
);
472 gtk_widget_set_size_request (w_current
->bottom_notebook
, 0, dock_size
);
474 dock_size
= eda_config_get_int (eda_config_get_user_context (),
475 "gschem.dock-geometry.right", "size", NULL
);
478 gtk_widget_set_size_request (w_current
->right_notebook
, dock_size
, 0);
482 /*! \todo Finish function documentation!!!
484 * \par Function Description
487 * When invoked (via signal delete_event), closes the current window
488 * if this is the last window, quit gschem
489 * used when you click the close button on the window which sends a DELETE
493 x_window_close_wm (GtkWidget
*widget
, GdkEvent
*event
, gpointer data
)
495 GschemToplevel
*w_current
= GSCHEM_TOPLEVEL (data
);
496 g_return_val_if_fail ((w_current
!= NULL
), TRUE
);
498 x_window_close(w_current
);
500 /* stop further propagation of the delete_event signal for window: */
501 /* - if user has cancelled the close the window should obvioulsy */
502 /* not be destroyed */
503 /* - otherwise window has already been destroyed, nothing more to */
510 x_window_update_file_change_notification (GschemToplevel
*w_current
,
513 if (page
->is_untitled
) {
514 g_object_set (w_current
->file_change_notification
,
521 gchar
*basename
= g_path_get_basename (page
->page_filename
);
522 gchar
*markup
= page
->exists_on_disk
523 ? g_markup_printf_escaped (
524 _("<b>The file \"%s\" has changed on disk.</b>\n\n%s"),
527 ? _("Do you want to drop your changes and reload the file?")
528 : _("Do you want to reload it?"))
529 : g_markup_printf_escaped (
530 _("<b>The file \"%s\" has been created on disk.</b>\n\n%s"),
533 ? _("Do you want to drop your changes and load the file?")
534 : _("Do you want to open it?"));
535 g_object_set (w_current
->file_change_notification
,
537 "path", page
->page_filename
,
538 "has-known-mtime", page
->exists_on_disk
,
539 "known-mtime", &page
->last_modified
,
540 "button-stock-id", page
->CHANGED
541 ? GTK_STOCK_REVERT_TO_SAVED
542 : page
->exists_on_disk
? GTK_STOCK_REFRESH
544 "button-label", page
->CHANGED
546 : page
->exists_on_disk
? _("_Reload")
555 x_window_file_change_response (GschemChangeNotification
*chnot
,
556 gint response_id
, gpointer user_data
)
558 if (response_id
== GTK_RESPONSE_ACCEPT
)
559 x_lowlevel_revert_page (chnot
->w_current
, chnot
->page
);
561 chnot
->page
->exists_on_disk
= chnot
->has_current_mtime
;
562 chnot
->page
->last_modified
= chnot
->current_mtime
;
563 x_window_update_file_change_notification (chnot
->w_current
, chnot
->page
);
569 x_window_update_patch_change_notification (GschemToplevel
*w_current
,
572 gchar
*patch_filename
= x_patch_guess_filename (page
);
573 gchar
*basename
, *markup
;
575 if (patch_filename
== NULL
) {
580 basename
= g_path_get_basename (patch_filename
);
581 if (page
->patch_filename
!= NULL
)
582 markup
= g_markup_printf_escaped (
583 _("<b>The back-annotation patch \"%s\" has been updated.</b>\n\n"
584 "Do you want to re-import it?"),
586 else if (page
->patch_seen_on_disk
)
587 markup
= g_markup_printf_escaped (
588 _("<b>The back-annotation patch \"%s\" has been updated.</b>\n\n"
589 "Do you want to import it?"),
591 else if (stat (patch_filename
, &buf
) != -1)
592 markup
= g_markup_printf_escaped (
593 _("<b>This file appears to have a back-annotation patch \"%s\" "
594 "associated with it.</b>\n\nDo you want to import it?"),
597 markup
= g_markup_printf_escaped (
598 _("<b>A back-annotation patch \"%s\" has been created.</b>\n\n"
599 "Do you want to import it?"),
603 g_object_set (w_current
->patch_change_notification
,
605 "path", patch_filename
,
606 "has-known-mtime", page
->patch_seen_on_disk
,
607 "known-mtime", &page
->patch_mtime
,
608 "button-label", _("_Import"),
613 g_free (patch_filename
);
617 x_window_patch_change_response (GschemChangeNotification
*chnot
,
618 gint response_id
, gpointer user_data
)
620 if (response_id
== GTK_RESPONSE_ACCEPT
) {
621 if (chnot
->page
->patch_filename
== NULL
)
622 chnot
->page
->patch_filename
= g_strdup (chnot
->path
);
623 x_patch_do_import (chnot
->w_current
, chnot
->page
);
625 chnot
->page
->patch_seen_on_disk
= chnot
->has_current_mtime
;
626 chnot
->page
->patch_mtime
= chnot
->current_mtime
;
627 x_window_update_patch_change_notification (chnot
->w_current
, chnot
->page
);
632 /*! \todo Finish function documentation!!!
634 * \par Function Description
637 void x_window_create_main(GschemToplevel
*w_current
)
639 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
641 GtkPolicyType policy
;
642 GtkWidget
*main_box
=NULL
;
643 GtkWidget
*handlebox
=NULL
;
645 GtkAdjustment
*hadjustment
;
646 GtkAdjustment
*vadjustment
;
647 char *right_button_text
;
648 GtkWidget
*left_hpaned
, *right_hpaned
;
652 w_current
->main_window
= GTK_WIDGET (gschem_main_window_new ());
654 gtk_widget_set_name (w_current
->main_window
, "gschem");
655 gtk_window_set_policy (GTK_WINDOW (w_current
->main_window
), TRUE
, TRUE
, TRUE
);
657 /* We want the widgets to flow around the drawing area, so we don't
658 * set a size of the main window. The drawing area's size is fixed,
663 * normally we let the window manager handle locating and sizing
664 * the window. However, for some batch processing of schematics
665 * (generating a pdf of all schematics for example) we want to
666 * override this. Hence "auto_place_mode".
668 if( auto_place_mode
)
669 gtk_widget_set_uposition (w_current
->main_window
, 10, 10);
671 /* this should work fine */
672 g_signal_connect (G_OBJECT (w_current
->main_window
), "delete_event",
673 G_CALLBACK (x_window_close_wm
), w_current
);
675 /* Containers first */
676 main_box
= gtk_vbox_new(FALSE
, 1);
677 gtk_container_set_border_width (GTK_CONTAINER (main_box
), 0);
678 gtk_container_add(GTK_CONTAINER(w_current
->main_window
), main_box
);
680 x_menus_create_main_menu (w_current
);
681 if (w_current
->menubar
!= NULL
) {
682 if (w_current
->handleboxes
) {
683 handlebox
= gtk_handle_box_new ();
684 gtk_box_pack_start (GTK_BOX (main_box
), handlebox
, FALSE
, FALSE
, 0);
685 gtk_container_add (GTK_CONTAINER (handlebox
), w_current
->menubar
);
687 gtk_box_pack_start (GTK_BOX (main_box
), w_current
->menubar
,
691 gschem_action_set_sensitive (action_view_menubar
, w_current
->menubar
!= NULL
,
693 gschem_action_set_active (action_view_menubar
, w_current
->menubar
!= NULL
,
696 gtk_widget_realize (w_current
->main_window
);
698 x_menus_create_toolbar (w_current
);
699 if (w_current
->toolbar
!= NULL
) {
700 if (w_current
->handleboxes
) {
701 handlebox
= gtk_handle_box_new ();
702 gtk_box_pack_start (GTK_BOX (main_box
), handlebox
, FALSE
, FALSE
, 0);
703 gtk_container_add (GTK_CONTAINER (handlebox
), w_current
->toolbar
);
704 gtk_widget_set_visible (handlebox
, w_current
->toolbars
);
705 gtk_widget_set_no_show_all (handlebox
, TRUE
);
707 gtk_box_pack_start (GTK_BOX (main_box
), w_current
->toolbar
,
709 gtk_widget_set_visible (w_current
->toolbar
, w_current
->toolbars
);
710 gtk_widget_set_no_show_all (w_current
->toolbar
, TRUE
);
713 gschem_action_set_sensitive (action_view_toolbar
, w_current
->toolbar
!= NULL
,
715 gschem_action_set_active (action_view_toolbar
,
716 w_current
->toolbars
&& w_current
->toolbar
!= NULL
,
719 left_hpaned
= gtk_hpaned_new ();
720 gtk_container_add (GTK_CONTAINER(main_box
), left_hpaned
);
722 w_current
->left_notebook
= gtk_notebook_new ();
723 gtk_paned_pack1 (GTK_PANED (left_hpaned
),
724 w_current
->left_notebook
,
727 gtk_notebook_set_group_name (GTK_NOTEBOOK (w_current
->left_notebook
),
730 right_hpaned
= gtk_hpaned_new ();
731 gtk_paned_pack2 (GTK_PANED (left_hpaned
),
736 w_current
->right_notebook
= gtk_notebook_new ();
737 gtk_paned_pack2 (GTK_PANED (right_hpaned
),
738 w_current
->right_notebook
,
741 gtk_notebook_set_group_name (GTK_NOTEBOOK (w_current
->right_notebook
),
744 vpaned
= gtk_vpaned_new ();
745 gtk_paned_pack1 (GTK_PANED (right_hpaned
),
750 w_current
->bottom_notebook
= gtk_notebook_new ();
751 gtk_paned_pack2 (GTK_PANED (vpaned
),
752 w_current
->bottom_notebook
,
755 gtk_notebook_set_group_name (GTK_NOTEBOOK (w_current
->bottom_notebook
),
758 work_box
= gtk_vbox_new (FALSE
, 0);
759 gtk_paned_pack1 (GTK_PANED (vpaned
),
764 w_current
->file_change_notification
=
765 g_object_new (GSCHEM_TYPE_CHANGE_NOTIFICATION
,
766 "gschem-toplevel", w_current
,
767 "message-type", GTK_MESSAGE_QUESTION
,
769 g_signal_connect (w_current
->file_change_notification
, "response",
770 G_CALLBACK (x_window_file_change_response
), NULL
);
771 gtk_box_pack_start (GTK_BOX (work_box
),
772 w_current
->file_change_notification
->info_bar
,
775 w_current
->patch_change_notification
=
776 g_object_new (GSCHEM_TYPE_CHANGE_NOTIFICATION
,
777 "gschem-toplevel", w_current
,
778 "message-type", GTK_MESSAGE_INFO
,
780 g_signal_connect (w_current
->patch_change_notification
, "response",
781 G_CALLBACK (x_window_patch_change_response
), NULL
);
782 gtk_box_pack_start (GTK_BOX (work_box
),
783 w_current
->patch_change_notification
->info_bar
,
786 /* Try to create popup menu (appears in right mouse button */
787 x_menus_create_main_popup (w_current
);
790 /* Setup a GtkScrolledWindow for the drawing area */
791 hadjustment
= GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
793 toplevel
->init_right
,
798 vadjustment
= GTK_ADJUSTMENT (gtk_adjustment_new (toplevel
->init_bottom
,
800 toplevel
->init_bottom
- toplevel
->init_top
,
805 scrolled
= gtk_scrolled_window_new (hadjustment
, vadjustment
);
806 gtk_container_add (GTK_CONTAINER (work_box
), scrolled
);
807 x_window_create_drawing(scrolled
, w_current
);
808 x_window_setup_draw_events(w_current
);
810 policy
= (w_current
->scrollbars_flag
) ? GTK_POLICY_ALWAYS
: GTK_POLICY_NEVER
;
811 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
), policy
, policy
);
812 gschem_action_set_active (action_view_scrollbars
, w_current
->scrollbars_flag
,
816 w_current
->find_text_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_FIND_TEXT_WIDGET
, NULL
));
818 gtk_box_pack_start (GTK_BOX (work_box
),
819 w_current
->find_text_widget
,
824 g_signal_connect (w_current
->find_text_widget
,
826 G_CALLBACK (&x_window_find_text
),
830 w_current
->hide_text_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_SHOW_HIDE_TEXT_WIDGET
,
831 "button-text", pgettext ("actuate", "Hide"),
832 "label-text", _("Hide text starting with:"),
835 gtk_box_pack_start (GTK_BOX (work_box
),
836 w_current
->hide_text_widget
,
841 g_signal_connect (w_current
->hide_text_widget
,
843 G_CALLBACK (&x_window_hide_text
),
847 w_current
->show_text_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_SHOW_HIDE_TEXT_WIDGET
,
848 "button-text", pgettext ("actuate", "Show"),
849 "label-text", _("Show text starting with:"),
852 gtk_box_pack_start (GTK_BOX (work_box
),
853 w_current
->show_text_widget
,
858 g_signal_connect (w_current
->show_text_widget
,
860 G_CALLBACK (&x_window_show_text
),
864 w_current
->macro_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_MACRO_WIDGET
, NULL
));
866 gtk_box_pack_start (GTK_BOX (work_box
),
867 w_current
->macro_widget
,
872 g_signal_connect (w_current
->macro_widget
,
874 G_CALLBACK (&x_window_invoke_macro
),
878 w_current
->compselect_dockable
= g_object_new (
879 GSCHEM_TYPE_COMPSELECT_DOCKABLE
,
880 "title", _("Library"),
881 "settings-name", "compselect",
883 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
,
884 "initial-width", 500,
885 "initial-height", 600,
886 "gschem-toplevel", w_current
,
889 w_current
->object_properties_dockable
= g_object_new (
890 GSCHEM_TYPE_OBJECT_PROPERTIES_DOCKABLE
,
891 "title", _("Object"),
892 "settings-name", "object-properties", /* line-type */
893 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
,
894 "initial-width", 400,
895 "initial-height", 600,
896 "gschem-toplevel", w_current
,
899 w_current
->text_properties_dockable
= g_object_new (
900 GSCHEM_TYPE_TEXT_PROPERTIES_DOCKABLE
,
902 "settings-name", "text-edit",
903 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
,
904 "initial-width", 400,
905 "initial-height", 450,
906 "gschem-toplevel", w_current
,
909 w_current
->multiattrib_dockable
= g_object_new (
910 GSCHEM_TYPE_MULTIATTRIB_DOCKABLE
,
911 "title", _("Attributes"),
912 "settings-name", "multiattrib",
913 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
,
914 "initial-width", 450,
915 "initial-height", 450,
916 "gschem-toplevel", w_current
,
919 w_current
->options_dockable
= g_object_new (
920 GSCHEM_TYPE_OPTIONS_DOCKABLE
,
921 "title", _("Options"),
922 "settings-name", "options", /* snap-size */
923 "initial-state", GSCHEM_DOCKABLE_STATE_HIDDEN
,
924 "initial-width", 320,
925 "initial-height", 350,
926 "gschem-toplevel", w_current
,
929 w_current
->log_dockable
= g_object_new (
930 GSCHEM_TYPE_LOG_DOCKABLE
,
931 "title", _("Status"),
932 "settings-name", "log",
933 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
,
934 "initial-width", 640,
935 "initial-height", 480,
936 "gschem-toplevel", w_current
,
939 w_current
->find_text_dockable
= g_object_new (
940 GSCHEM_TYPE_FIND_TEXT_DOCKABLE
,
941 "title", _("Search results"),
942 "settings-name", "find-text",
943 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
,
944 "initial-width", 500,
945 "initial-height", 300,
946 "gschem-toplevel", w_current
,
948 g_signal_connect (w_current
->find_text_dockable
,
950 G_CALLBACK (&x_window_select_text
),
953 w_current
->patch_dockable
= g_object_new (
954 GSCHEM_TYPE_PATCH_DOCKABLE
,
956 "settings-name", "patch",
957 "initial-state", GSCHEM_DOCKABLE_STATE_HIDDEN
,
958 "initial-width", 500,
959 "initial-height", 300,
960 "gschem-toplevel", w_current
,
963 w_current
->pagesel_dockable
= g_object_new (
964 GSCHEM_TYPE_PAGESEL_DOCKABLE
,
966 "settings-name", "pagesel",
967 "initial-state", GSCHEM_DOCKABLE_STATE_HIDDEN
,
968 "initial-width", 515,
969 "initial-height", 180,
970 "gschem-toplevel", w_current
,
973 gschem_dockable_initialize_toplevel (w_current
);
977 if (default_third_button
== POPUP_ENABLED
) {
978 right_button_text
= _("Menu/Cancel");
980 right_button_text
= _("Pan/Cancel");
983 w_current
->bottom_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_BOTTOM_WIDGET
,
984 "grid-mode", gschem_options_get_grid_mode (w_current
->options
),
985 "grid-size", gschem_options_get_snap_size (w_current
->options
), /* x_grid_query_drawn_spacing (w_current), -- occurs before the page is set */
986 "left-button-text", _("Pick"),
987 "middle-button-text", _("none"),
988 "right-button-text", right_button_text
,
989 "snap-mode", gschem_options_get_snap_mode (w_current
->options
),
990 "snap-size", gschem_options_get_snap_size (w_current
->options
),
991 "status-text", _("Select Mode"),
994 i_update_middle_button (w_current
, NULL
, NULL
);
996 gtk_box_pack_start (GTK_BOX (main_box
), w_current
->bottom_widget
, FALSE
, FALSE
, 0);
998 x_window_restore_geometry (w_current
);
999 g_signal_connect (G_OBJECT (w_current
->main_window
), "window-state-event",
1000 G_CALLBACK (x_window_state_event
), w_current
);
1002 gtk_widget_show_all (w_current
->main_window
);
1004 /* hide unused notebooks */
1005 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (w_current
->left_notebook
)) == 0)
1006 gtk_widget_hide (w_current
->left_notebook
);
1007 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (w_current
->bottom_notebook
)) == 0)
1008 gtk_widget_hide (w_current
->bottom_notebook
);
1009 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (w_current
->right_notebook
)) == 0)
1010 gtk_widget_hide (w_current
->right_notebook
);
1013 /*! \todo Finish function documentation!!!
1015 * \par Function Description
1018 void x_window_close(GschemToplevel
*w_current
)
1020 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
1021 gboolean last_window
= FALSE
;
1023 /* If we're closing whilst inside an action, re-wind the
1024 * page contents back to their state before we started */
1025 if (w_current
->inside_action
) {
1026 i_cancel (w_current
);
1029 /* last chance to save possible unsaved pages */
1030 if (!x_dialog_close_window (w_current
)) {
1031 /* user somehow cancelled the close */
1035 x_clipboard_finish (w_current
);
1038 o_conn_print_hash(w_current
->page_current
->conn_table
);
1041 w_current
->dont_invalidate
= TRUE
;
1043 /* save window geometry */
1044 x_window_save_geometry (w_current
);
1046 /* close all the dialog boxes */
1047 if (w_current
->sowindow
)
1048 gtk_widget_destroy(w_current
->sowindow
);
1050 if (w_current
->tiwindow
)
1051 gtk_widget_destroy(w_current
->tiwindow
);
1053 if (w_current
->aawindow
)
1054 gtk_widget_destroy(w_current
->aawindow
);
1056 if (w_current
->aewindow
)
1057 gtk_widget_destroy(w_current
->aewindow
);
1059 if (w_current
->hkwindow
)
1060 gtk_widget_destroy(w_current
->hkwindow
);
1062 if (w_current
->sewindow
)
1063 gtk_widget_destroy(w_current
->sewindow
);
1065 /* save dock window geometry, close dock windows, disconnect signals */
1066 gschem_dockable_cleanup_toplevel (w_current
);
1068 g_clear_object (&w_current
->compselect_dockable
);
1069 g_clear_object (&w_current
->object_properties_dockable
);
1070 g_clear_object (&w_current
->text_properties_dockable
);
1071 g_clear_object (&w_current
->multiattrib_dockable
);
1072 g_clear_object (&w_current
->options_dockable
);
1073 g_clear_object (&w_current
->log_dockable
);
1074 g_clear_object (&w_current
->find_text_dockable
);
1075 g_clear_object (&w_current
->patch_dockable
);
1076 g_clear_object (&w_current
->pagesel_dockable
);
1078 if (g_list_length (global_window_list
) == 1) {
1079 /* no more window after this one, remember to quit */
1083 if (toplevel
->major_changed_refdes
) {
1084 GList
* current
= toplevel
->major_changed_refdes
;
1087 /* printf("yeah freeing: %s\n", (char*) current->data); */
1088 g_free(current
->data
);
1089 current
= g_list_next(current
);
1091 g_list_free(toplevel
->major_changed_refdes
);
1094 /* stuff that has to be done before we free w_current */
1096 /* close the log file */
1098 /* free the buffers */
1099 o_buffer_free (w_current
);
1102 /* Allow Scheme value for this window to be garbage-collected */
1103 if (!SCM_UNBNDP (w_current
->smob
)) {
1104 SCM_SET_SMOB_DATA (w_current
->smob
, NULL
);
1105 scm_gc_unprotect_object (w_current
->smob
);
1106 w_current
->smob
= SCM_UNDEFINED
;
1109 /* finally close the main window */
1110 gtk_widget_destroy(w_current
->main_window
);
1112 global_window_list
= g_list_remove (global_window_list
, w_current
);
1113 gschem_toplevel_free (w_current
);
1115 /* just closed last window, so quit */
1121 /*! \todo Finish function documentation!!!
1123 * \par Function Description
1126 void x_window_close_all(GschemToplevel
*w_current
)
1128 GschemToplevel
*current
;
1129 GList
*list_copy
, *iter
;
1131 iter
= list_copy
= g_list_copy (global_window_list
);
1132 while (iter
!= NULL
) {
1133 current
= (GschemToplevel
*)iter
->data
;
1134 iter
= g_list_next (iter
);
1135 x_window_close (current
);
1137 g_list_free (list_copy
);
1140 /*! \brief Changes the current page.
1141 * \par Function Description
1142 * This function displays the specified page <B>page</B> in the
1143 * window attached to <B>toplevel</B>.
1145 * It changes the <B>toplevel</B>'s current page to <B>page</B>,
1146 * draws it and updates the user interface.
1148 * <B>page</B> has to be in the list of PAGEs attached to <B>toplevel</B>.
1150 * \param [in] w_current The toplevel environment.
1151 * \param [in] page The page to become current page.
1154 x_window_set_current_page (GschemToplevel
*w_current
, PAGE
*page
)
1156 GschemPageView
*page_view
= gschem_toplevel_get_current_page_view (w_current
);
1157 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
1160 g_return_if_fail (page_view
!= NULL
);
1161 g_return_if_fail (toplevel
!= NULL
);
1162 g_return_if_fail (page
!= NULL
);
1164 g_warn_if_fail (page_view
->page
== toplevel
->page_current
||
1165 page_view
->page
== NULL
);
1167 if (page
== toplevel
->page_current
&& page_view
->page
!= NULL
)
1171 o_redraw_cleanstates (w_current
);
1173 gschem_page_view_set_page (page_view
, page
);
1175 gschem_action_set_sensitive (action_page_revert
,
1176 page
->is_untitled
== FALSE
&&
1177 g_file_test (page
->page_filename
,
1178 G_FILE_TEST_EXISTS
|
1179 G_FILE_TEST_IS_REGULAR
),
1182 o_undo_update_actions (w_current
, page
);
1184 iter
= g_list_find (geda_list_get_glist (toplevel
->pages
), page
);
1185 gschem_action_set_sensitive (action_page_prev
,
1186 w_current
->enforce_hierarchy
1187 ? s_hierarchy_find_prev_page (
1188 toplevel
->pages
, page
) != NULL
1189 : iter
!= NULL
&& iter
->prev
!= NULL
,
1191 gschem_action_set_sensitive (action_page_next
,
1192 w_current
->enforce_hierarchy
1193 ? s_hierarchy_find_next_page(
1194 toplevel
->pages
, page
) != NULL
1195 : iter
!= NULL
&& iter
->next
!= NULL
,
1197 gschem_action_set_sensitive (action_hierarchy_up
, page
->up
>= 0, w_current
);
1199 i_update_menus (w_current
);
1200 /* i_set_filename (w_current, page->page_filename); */
1202 x_window_update_file_change_notification (w_current
, page
);
1203 x_window_update_patch_change_notification (w_current
, page
);
1205 x_pagesel_update (w_current
);
1206 x_multiattrib_update (w_current
);
1209 /*! \brief Raise the main window to the front.
1211 * This is mostly equivalent to
1212 * gtk_window_present (GTK_WINDOW (w_current->main_window));
1214 * One of the two actions that \c gtk_window_present performs on an
1215 * already-visible window (\c gdk_window_show) is triggering a bug
1216 * with toolbar icon drawing, the other (\c gdk_window_focus) is the
1217 * one we actually want. In order to work around that bug, just call
1218 * \c gdk_window_focus directly.
1220 * \param [in] w_current the toplevel environment
1222 void x_window_present (GschemToplevel
*w_current
)
1224 //gdk_window_show (w_current->main_window->window); /* the culprit */
1226 #ifdef GDK_WINDOWING_X11
1227 GdkDisplay
*display
= gtk_widget_get_display (w_current
->main_window
);
1228 guint32 timestamp
= gdk_x11_display_get_user_time (display
);
1230 guint32 timestamp
= gtk_get_current_event_time ();
1233 gdk_window_focus (w_current
->main_window
->window
, timestamp
);
1236 /*! \brief Setup default icon for GTK windows
1238 * \par Function Description
1239 * Sets the default window icon by name, to be found in the current icon
1240 * theme. The name used is \#defined above as GSCHEM_THEME_ICON_NAME.
1242 void x_window_set_default_icon( void )
1244 gtk_window_set_default_icon_name( GSCHEM_THEME_ICON_NAME
);
1247 /*! \brief Setup icon search paths.
1248 * \par Function Description
1249 * Add the icons installed by gschem to the search path for the
1250 * default icon theme, so that they can be automatically found by GTK.
1253 x_window_init_icons (void)
1257 g_return_if_fail (s_path_sys_data () != NULL
);
1259 icon_path
= g_build_filename (s_path_sys_data (), "icons", NULL
);
1260 gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
1265 /*! \brief Creates a new X window.
1267 * \par Function description
1269 * Creates and initializes new GschemToplevel object and then sets
1270 * and setups its libgeda \a toplevel.
1272 * \param toplevel The libgeda TOPLEVEL object.
1273 * \return Pointer to the new GschemToplevel object.
1275 GschemToplevel
* x_window_new (TOPLEVEL
*toplevel
)
1277 GschemToplevel
*w_current
;
1279 w_current
= gschem_toplevel_new ();
1280 gschem_toplevel_set_toplevel (w_current
,
1281 (toplevel
!= NULL
) ? toplevel
: s_toplevel_new ());
1283 gschem_toplevel_get_toplevel (w_current
)->load_newer_backup_func
= x_fileselect_load_backup
;
1284 gschem_toplevel_get_toplevel (w_current
)->load_newer_backup_data
= w_current
;
1286 o_text_set_rendered_bounds_func (gschem_toplevel_get_toplevel (w_current
),
1287 o_text_get_rendered_bounds
, w_current
);
1289 /* Damage notifications should invalidate the object on screen */
1290 o_add_change_notify (gschem_toplevel_get_toplevel (w_current
),
1291 (ChangeNotifyFunc
) o_invalidate
,
1292 (ChangeNotifyFunc
) o_invalidate
, w_current
);
1294 x_window_setup (w_current
);