1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2019 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_messages_dockable.h"
41 #include "gschem_find_text_dockable.h"
42 #include "gschem_patch_dockable.h"
43 #include "gschem_pagesel_dockable.h"
45 #define GSCHEM_THEME_ICON_NAME "geda-gschem"
47 /*! \todo Finish function documentation!!!
49 * \par Function Description
52 void x_window_setup (GschemToplevel
*w_current
)
54 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
56 /* immediately setup user params */
57 i_vars_set(w_current
);
59 /* Initialize the autosave callback */
60 s_page_autosave_init(toplevel
);
62 /* Initialize the clipboard callback */
63 x_clipboard_init (w_current
);
65 /* Add to the list of windows */
66 global_window_list
= g_list_append (global_window_list
, w_current
);
69 x_menus_create_submenus (w_current
);
70 x_window_create_main (w_current
);
72 /* update sensitivity of paste action */
73 x_clipboard_update_menus (w_current
);
75 gschem_action_set_sensitive (action_add_last_component
, FALSE
, w_current
);
77 /* disable terminal REPL action if stdin is not a terminal */
78 gschem_action_set_sensitive (action_file_repl
, isatty (STDIN_FILENO
),
82 /*! \todo Finish function documentation!!!
84 * \par Function Description
87 void x_window_create_drawing(GtkWidget
*scrolled
, GschemToplevel
*w_current
)
90 w_current
->drawing_area
= GTK_WIDGET (gschem_page_view_new_with_page (w_current
->toplevel
->page_current
));
91 /* Set the size here. Be sure that it has an aspect ratio of 1.333
92 * We could calculate this based on root window size, but for now
93 * lets just set it to:
94 * Width = root_width*3/4 Height = Width/1.3333333333
95 * 1.3333333 is the desired aspect ratio!
98 gtk_container_add(GTK_CONTAINER(scrolled
), w_current
->drawing_area
);
100 GTK_WIDGET_SET_FLAGS (w_current
->drawing_area
, GTK_CAN_FOCUS
);
101 gtk_widget_grab_focus (w_current
->drawing_area
);
102 gtk_widget_show (w_current
->drawing_area
);
105 /*! \brief Set up callbacks for window events that affect drawing.
106 * \par Function Description
108 * Installs GTK+ callback handlers for signals that are emitted by
109 * the drawing area, and some for the main window that affect the drawing
112 * \param [in] w_current The toplevel environment.
114 void x_window_setup_draw_events(GschemToplevel
*w_current
)
117 gchar
*detailed_signal
;
121 struct event_reg_t drawing_area_events
[] = {
122 { "expose_event", G_CALLBACK(x_event_expose
) },
123 { "expose_event", G_CALLBACK(x_event_raise_dialog_boxes
) },
124 { "button_press_event", G_CALLBACK(x_event_button_pressed
) },
125 { "button_release_event", G_CALLBACK(x_event_button_released
) },
126 { "motion_notify_event", G_CALLBACK(x_event_motion
) },
127 { "configure_event", G_CALLBACK(x_event_configure
) },
128 { "key_press_event", G_CALLBACK(x_event_key
) },
129 { "key_release_event", G_CALLBACK(x_event_key
) },
130 { "scroll_event", G_CALLBACK(x_event_scroll
) },
131 { "update-grid-info", G_CALLBACK(i_update_grid_info_callback
) },
132 { "notify::page", G_CALLBACK(gschem_toplevel_notify_page_callback
) },
134 struct event_reg_t main_window_events
[] = {
135 { "enter_notify_event", G_CALLBACK(x_event_enter
) },
137 struct event_reg_t
*tmp
;
139 /* is the configure event type missing here? hack */
140 gtk_widget_set_events (w_current
->drawing_area
,
142 GDK_POINTER_MOTION_MASK
|
143 GDK_BUTTON_PRESS_MASK
|
144 GDK_ENTER_NOTIFY_MASK
|
146 GDK_BUTTON_RELEASE_MASK
);
148 for (tmp
= drawing_area_events
; tmp
->detailed_signal
!= NULL
; tmp
++) {
149 g_signal_connect (w_current
->drawing_area
,
150 tmp
->detailed_signal
,
155 for (tmp
= main_window_events
; tmp
->detailed_signal
!= NULL
; tmp
++) {
156 g_signal_connect (w_current
->main_window
,
157 tmp
->detailed_signal
,
165 x_window_find_text (GtkWidget
*widget
, gint response
, GschemToplevel
*w_current
)
170 g_return_if_fail (w_current
!= NULL
);
171 g_return_if_fail (w_current
->toplevel
!= NULL
);
174 case GTK_RESPONSE_OK
:
175 count
= gschem_find_text_dockable_find (
176 GSCHEM_FIND_TEXT_DOCKABLE (w_current
->find_text_dockable
),
177 geda_list_get_glist (w_current
->toplevel
->pages
),
178 gschem_find_text_widget_get_find_type (GSCHEM_FIND_TEXT_WIDGET (w_current
->find_text_widget
)),
179 gschem_find_text_widget_get_find_text_string (GSCHEM_FIND_TEXT_WIDGET (w_current
->find_text_widget
)),
180 gschem_find_text_widget_get_descend (GSCHEM_FIND_TEXT_WIDGET (w_current
->find_text_widget
)));
182 gschem_dockable_present (w_current
->find_text_dockable
);
187 case GTK_RESPONSE_CANCEL
:
188 case GTK_RESPONSE_DELETE_EVENT
:
193 printf("x_window_find_text(): strange signal %d\n", response
);
197 gtk_widget_grab_focus (w_current
->drawing_area
);
198 gtk_widget_hide (GTK_WIDGET (widget
));
205 x_window_hide_text (GtkWidget
*widget
, gint response
, GschemToplevel
*w_current
)
207 g_return_if_fail (w_current
!= NULL
);
208 g_return_if_fail (w_current
->toplevel
!= NULL
);
210 if (response
== GTK_RESPONSE_OK
) {
211 o_edit_hide_specific_text (w_current
,
212 s_page_objects (w_current
->toplevel
->page_current
),
213 gschem_show_hide_text_widget_get_text_string (GSCHEM_SHOW_HIDE_TEXT_WIDGET (widget
)));
216 gtk_widget_grab_focus (w_current
->drawing_area
);
217 gtk_widget_hide (GTK_WIDGET (widget
));
222 x_window_show_text (GtkWidget
*widget
, gint response
, GschemToplevel
*w_current
)
224 g_return_if_fail (w_current
!= NULL
);
225 g_return_if_fail (w_current
->toplevel
!= NULL
);
227 if (response
== GTK_RESPONSE_OK
) {
228 o_edit_show_specific_text (w_current
,
229 s_page_objects (w_current
->toplevel
->page_current
),
230 gschem_show_hide_text_widget_get_text_string (GSCHEM_SHOW_HIDE_TEXT_WIDGET (widget
)));
233 gtk_widget_grab_focus (w_current
->drawing_area
);
234 gtk_widget_hide (GTK_WIDGET (widget
));
239 x_window_invoke_macro (GschemMacroWidget
*widget
, int response
, GschemToplevel
*w_current
)
241 if (response
== GTK_RESPONSE_OK
) {
242 const char *macro
= gschem_macro_widget_get_macro_string (widget
);
244 SCM interpreter
= scm_list_2(scm_from_utf8_symbol("invoke-macro"),
245 scm_from_utf8_string(macro
));
247 scm_dynwind_begin (0);
248 g_dynwind_window (w_current
);
249 g_scm_eval_protected(interpreter
, SCM_UNDEFINED
);
253 gtk_widget_grab_focus (w_current
->drawing_area
);
254 gtk_widget_hide (GTK_WIDGET (widget
));
258 x_window_select_text (GschemFindTextDockable
*dockable
, OBJECT
*object
, GschemToplevel
*w_current
)
260 GschemPageView
*view
= gschem_toplevel_get_current_page_view (w_current
);
261 g_return_if_fail (view
!= NULL
);
265 g_return_if_fail (object
!= NULL
);
266 page_obj
= gschem_page_get_page_object(object
);
267 g_return_if_fail (page_obj
!= NULL
);
269 x_window_set_current_page (w_current
, page_obj
->page
);
271 gschem_page_view_zoom_text (view
, object
, TRUE
);
275 x_window_state_event (GtkWidget
*widget
,
276 GdkEventWindowState
*event
,
279 eda_config_set_string (
280 eda_config_get_user_context (),
281 "gschem.window-geometry", "state",
282 (event
->new_window_state
&
283 GDK_WINDOW_STATE_FULLSCREEN
) ? "fullscreen" :
284 (event
->new_window_state
&
285 GDK_WINDOW_STATE_MAXIMIZED
) ? "maximized" : "normal");
287 return FALSE
; /* propagate the event further */
291 x_window_save_menu_geometry (GtkMenuShell
*menu_shell
,
292 GschemToplevel
*w_current
)
294 for (GList
*l
= gtk_container_get_children (GTK_CONTAINER (menu_shell
));
295 l
!= NULL
; l
= l
->next
) {
296 GtkMenuItem
*menu_item
= GTK_MENU_ITEM (l
->data
);
298 GtkWidget
*menu
= menu_item
->submenu
;
303 char *settings_name
= g_object_get_data (G_OBJECT (menu
), "settings-name");
304 if (settings_name
== NULL
)
305 /* menu doesn't have a settings name set */
311 if (GTK_MENU (menu
)->torn_off
) {
312 GtkWidget
*window
= GTK_MENU (menu
)->tearoff_window
;
313 g_return_if_fail (window
!= NULL
);
315 gtk_window_get_position (GTK_WINDOW (window
), &coords
[0], &coords
[1]);
316 gtk_window_get_size (GTK_WINDOW (window
), &coords
[2], &coords
[3]);
320 eda_config_set_int_list (
321 eda_config_get_user_context (),
322 "gschem.menu-geometry", settings_name
, coords
, length
);
324 x_window_save_menu_geometry (GTK_MENU_SHELL (menu
), w_current
);
329 x_window_save_geometry (GschemToplevel
*w_current
)
332 GtkAllocation allocation
;
334 /* save window geometry */
335 window_state
= eda_config_get_string (eda_config_get_user_context (),
336 "gschem.window-geometry",
338 if (window_state
!= NULL
&& strcmp (window_state
, "normal") == 0) {
339 gint width
= -1, height
= -1;
340 gtk_window_get_size (GTK_WINDOW (w_current
->main_window
), &width
, &height
);
341 if (width
> 0 && height
> 0) {
342 eda_config_set_int (eda_config_get_user_context (),
343 "gschem.window-geometry", "width", width
);
344 eda_config_set_int (eda_config_get_user_context (),
345 "gschem.window-geometry", "height", height
);
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
));
455 /* defer restoring torn-off menus until main window is shown */
456 g_signal_connect_swapped (
457 G_OBJECT (w_current
->main_window
), "focus-in-event",
458 G_CALLBACK (x_window_restore_all_menu_geometry
), w_current
);
460 /* restore docking area dimensions */
461 dock_size
= eda_config_get_int (eda_config_get_user_context (),
462 "gschem.dock-geometry.left", "size", NULL
);
465 gtk_widget_set_size_request (w_current
->left_notebook
, dock_size
, 0);
467 dock_size
= eda_config_get_int (eda_config_get_user_context (),
468 "gschem.dock-geometry.bottom", "size", NULL
);
471 gtk_widget_set_size_request (w_current
->bottom_notebook
, 0, dock_size
);
473 dock_size
= eda_config_get_int (eda_config_get_user_context (),
474 "gschem.dock-geometry.right", "size", NULL
);
477 gtk_widget_set_size_request (w_current
->right_notebook
, dock_size
, 0);
481 /*! \todo Finish function documentation!!!
483 * \par Function Description
486 * When invoked (via signal delete_event), closes the current window
487 * if this is the last window, quit gschem
488 * used when you click the close button on the window which sends a DELETE
492 x_window_close_wm (GtkWidget
*widget
, GdkEvent
*event
, gpointer data
)
494 GschemToplevel
*w_current
= GSCHEM_TOPLEVEL (data
);
495 g_return_val_if_fail ((w_current
!= NULL
), TRUE
);
497 x_window_close(w_current
);
499 /* stop further propagation of the delete_event signal for window: */
500 /* - if user has cancelled the close the window should obvioulsy */
501 /* not be destroyed */
502 /* - otherwise window has already been destroyed, nothing more to */
509 x_window_update_file_change_notification (GschemToplevel
*w_current
,
512 if (page
->is_untitled
) {
513 g_object_set (w_current
->file_change_notification
,
520 gchar
*basename
= g_path_get_basename (page
->page_filename
);
521 gchar
*markup
= page
->exists_on_disk
522 ? g_markup_printf_escaped (
523 _("<b>The file \"%s\" has changed on disk.</b>\n\n%s"),
526 ? _("Do you want to drop your changes and reload the file?")
527 : _("Do you want to reload it?"))
528 : g_markup_printf_escaped (
529 _("<b>The file \"%s\" has been created on disk.</b>\n\n%s"),
532 ? _("Do you want to drop your changes and load the file?")
533 : _("Do you want to open it?"));
534 g_object_set (w_current
->file_change_notification
,
536 "path", page
->page_filename
,
537 "has-known-mtime", page
->exists_on_disk
,
538 "known-mtime", &page
->last_modified
,
539 "button-stock-id", page
->CHANGED
540 ? GTK_STOCK_REVERT_TO_SAVED
541 : page
->exists_on_disk
? GTK_STOCK_REFRESH
543 "button-label", page
->CHANGED
545 : page
->exists_on_disk
? _("_Reload")
554 x_window_file_change_response (GschemChangeNotification
*chnot
,
555 gint response_id
, gpointer user_data
)
557 if (response_id
== GTK_RESPONSE_ACCEPT
)
558 x_lowlevel_revert_page (chnot
->w_current
, chnot
->page
);
560 chnot
->page
->exists_on_disk
= chnot
->has_current_mtime
;
561 chnot
->page
->last_modified
= chnot
->current_mtime
;
562 x_window_update_file_change_notification (chnot
->w_current
, chnot
->page
);
568 x_window_update_patch_change_notification (GschemToplevel
*w_current
,
571 gchar
*patch_filename
= x_patch_guess_filename (page
);
572 gchar
*basename
, *markup
;
574 if (patch_filename
== NULL
) {
579 basename
= g_path_get_basename (patch_filename
);
580 if (page
->patch_filename
!= NULL
)
581 markup
= g_markup_printf_escaped (
582 _("<b>The back-annotation patch \"%s\" has been updated.</b>\n\n"
583 "Do you want to re-import it?"),
585 else if (page
->patch_seen_on_disk
)
586 markup
= g_markup_printf_escaped (
587 _("<b>The back-annotation patch \"%s\" has been updated.</b>\n\n"
588 "Do you want to import it?"),
590 else if (stat (patch_filename
, &buf
) != -1)
591 markup
= g_markup_printf_escaped (
592 _("<b>This file appears to have a back-annotation patch \"%s\" "
593 "associated with it.</b>\n\nDo you want to import it?"),
596 markup
= g_markup_printf_escaped (
597 _("<b>A back-annotation patch \"%s\" has been created.</b>\n\n"
598 "Do you want to import it?"),
602 g_object_set (w_current
->patch_change_notification
,
604 "path", patch_filename
,
605 "has-known-mtime", page
->patch_seen_on_disk
,
606 "known-mtime", &page
->patch_mtime
,
607 "button-label", _("_Import"),
612 g_free (patch_filename
);
616 x_window_patch_change_response (GschemChangeNotification
*chnot
,
617 gint response_id
, gpointer user_data
)
619 if (response_id
== GTK_RESPONSE_ACCEPT
) {
620 if (chnot
->page
->patch_filename
== NULL
)
621 chnot
->page
->patch_filename
= g_strdup (chnot
->path
);
622 x_patch_do_import (chnot
->w_current
, chnot
->page
);
624 chnot
->page
->patch_seen_on_disk
= chnot
->has_current_mtime
;
625 chnot
->page
->patch_mtime
= chnot
->current_mtime
;
626 x_window_update_patch_change_notification (chnot
->w_current
, chnot
->page
);
631 /*! \todo Finish function documentation!!!
633 * \par Function Description
636 void x_window_create_main(GschemToplevel
*w_current
)
638 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
640 GtkPolicyType policy
;
641 GtkWidget
*main_box
=NULL
;
642 GtkWidget
*handlebox
=NULL
;
644 GtkAdjustment
*hadjustment
;
645 GtkAdjustment
*vadjustment
;
646 char *right_button_text
;
647 GtkWidget
*left_hpaned
, *right_hpaned
;
651 w_current
->main_window
= GTK_WIDGET (gschem_main_window_new ());
653 gtk_widget_set_name (w_current
->main_window
, "gschem");
654 gtk_window_set_policy (GTK_WINDOW (w_current
->main_window
), TRUE
, TRUE
, TRUE
);
656 /* We want the widgets to flow around the drawing area, so we don't
657 * set a size of the main window. The drawing area's size is fixed,
662 * normally we let the window manager handle locating and sizing
663 * the window. However, for some batch processing of schematics
664 * (generating a pdf of all schematics for example) we want to
665 * override this. Hence "auto_place_mode".
667 if( auto_place_mode
)
668 gtk_widget_set_uposition (w_current
->main_window
, 10, 10);
670 /* this should work fine */
671 g_signal_connect (G_OBJECT (w_current
->main_window
), "delete_event",
672 G_CALLBACK (x_window_close_wm
), w_current
);
674 /* Containers first */
675 main_box
= gtk_vbox_new(FALSE
, 1);
676 gtk_container_set_border_width (GTK_CONTAINER (main_box
), 0);
677 gtk_container_add(GTK_CONTAINER(w_current
->main_window
), main_box
);
679 x_menus_create_main_menu (w_current
);
680 if (w_current
->menubar
!= NULL
) {
681 if (w_current
->handleboxes
) {
682 handlebox
= gtk_handle_box_new ();
683 gtk_box_pack_start (GTK_BOX (main_box
), handlebox
, FALSE
, FALSE
, 0);
684 gtk_container_add (GTK_CONTAINER (handlebox
), w_current
->menubar
);
686 gtk_box_pack_start (GTK_BOX (main_box
), w_current
->menubar
,
690 gschem_action_set_sensitive (action_view_menubar
, w_current
->menubar
!= NULL
,
692 gschem_action_set_active (action_view_menubar
, w_current
->menubar
!= NULL
,
695 gtk_widget_realize (w_current
->main_window
);
697 x_menus_create_toolbar (w_current
);
698 if (w_current
->toolbar
!= NULL
) {
699 if (w_current
->handleboxes
) {
700 handlebox
= gtk_handle_box_new ();
701 gtk_box_pack_start (GTK_BOX (main_box
), handlebox
, FALSE
, FALSE
, 0);
702 gtk_container_add (GTK_CONTAINER (handlebox
), w_current
->toolbar
);
703 gtk_widget_set_visible (handlebox
, w_current
->toolbars
);
704 gtk_widget_set_no_show_all (handlebox
, TRUE
);
706 gtk_box_pack_start (GTK_BOX (main_box
), w_current
->toolbar
,
708 gtk_widget_set_visible (w_current
->toolbar
, w_current
->toolbars
);
709 gtk_widget_set_no_show_all (w_current
->toolbar
, TRUE
);
712 gschem_action_set_sensitive (action_view_toolbar
, w_current
->toolbar
!= NULL
,
714 gschem_action_set_active (action_view_toolbar
,
715 w_current
->toolbars
&& w_current
->toolbar
!= NULL
,
718 left_hpaned
= gtk_hpaned_new ();
719 gtk_container_add (GTK_CONTAINER(main_box
), left_hpaned
);
721 w_current
->left_notebook
= gtk_notebook_new ();
722 gtk_paned_pack1 (GTK_PANED (left_hpaned
),
723 w_current
->left_notebook
,
726 gtk_notebook_set_group_name (GTK_NOTEBOOK (w_current
->left_notebook
),
729 right_hpaned
= gtk_hpaned_new ();
730 gtk_paned_pack2 (GTK_PANED (left_hpaned
),
735 w_current
->right_notebook
= gtk_notebook_new ();
736 gtk_paned_pack2 (GTK_PANED (right_hpaned
),
737 w_current
->right_notebook
,
740 gtk_notebook_set_group_name (GTK_NOTEBOOK (w_current
->right_notebook
),
743 vpaned
= gtk_vpaned_new ();
744 gtk_paned_pack1 (GTK_PANED (right_hpaned
),
749 w_current
->bottom_notebook
= gtk_notebook_new ();
750 gtk_paned_pack2 (GTK_PANED (vpaned
),
751 w_current
->bottom_notebook
,
754 gtk_notebook_set_group_name (GTK_NOTEBOOK (w_current
->bottom_notebook
),
757 work_box
= gtk_vbox_new (FALSE
, 0);
758 gtk_paned_pack1 (GTK_PANED (vpaned
),
763 w_current
->file_change_notification
=
764 g_object_new (GSCHEM_TYPE_CHANGE_NOTIFICATION
,
765 "gschem-toplevel", w_current
,
766 "message-type", GTK_MESSAGE_QUESTION
,
768 g_signal_connect (w_current
->file_change_notification
, "response",
769 G_CALLBACK (x_window_file_change_response
), NULL
);
770 gtk_box_pack_start (GTK_BOX (work_box
),
771 w_current
->file_change_notification
->info_bar
,
774 w_current
->patch_change_notification
=
775 g_object_new (GSCHEM_TYPE_CHANGE_NOTIFICATION
,
776 "gschem-toplevel", w_current
,
777 "message-type", GTK_MESSAGE_INFO
,
779 g_signal_connect (w_current
->patch_change_notification
, "response",
780 G_CALLBACK (x_window_patch_change_response
), NULL
);
781 gtk_box_pack_start (GTK_BOX (work_box
),
782 w_current
->patch_change_notification
->info_bar
,
785 /* Try to create popup menu (appears in right mouse button */
786 x_menus_create_main_popup (w_current
);
789 /* Setup a GtkScrolledWindow for the drawing area */
790 hadjustment
= GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
792 toplevel
->init_right
,
797 vadjustment
= GTK_ADJUSTMENT (gtk_adjustment_new (toplevel
->init_bottom
,
799 toplevel
->init_bottom
- toplevel
->init_top
,
804 scrolled
= gtk_scrolled_window_new (hadjustment
, vadjustment
);
805 gtk_container_add (GTK_CONTAINER (work_box
), scrolled
);
806 x_window_create_drawing(scrolled
, w_current
);
807 x_window_setup_draw_events(w_current
);
809 policy
= (w_current
->scrollbars_flag
) ? GTK_POLICY_ALWAYS
: GTK_POLICY_NEVER
;
810 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
), policy
, policy
);
811 gschem_action_set_active (action_view_scrollbars
, w_current
->scrollbars_flag
,
815 w_current
->find_text_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_FIND_TEXT_WIDGET
, NULL
));
817 gtk_box_pack_start (GTK_BOX (work_box
),
818 w_current
->find_text_widget
,
823 g_signal_connect (w_current
->find_text_widget
,
825 G_CALLBACK (&x_window_find_text
),
829 w_current
->hide_text_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_SHOW_HIDE_TEXT_WIDGET
,
830 "button-text", pgettext ("actuate", "Hide"),
831 "label-text", _("Hide text starting with:"),
834 gtk_box_pack_start (GTK_BOX (work_box
),
835 w_current
->hide_text_widget
,
840 g_signal_connect (w_current
->hide_text_widget
,
842 G_CALLBACK (&x_window_hide_text
),
846 w_current
->show_text_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_SHOW_HIDE_TEXT_WIDGET
,
847 "button-text", pgettext ("actuate", "Show"),
848 "label-text", _("Show text starting with:"),
851 gtk_box_pack_start (GTK_BOX (work_box
),
852 w_current
->show_text_widget
,
857 g_signal_connect (w_current
->show_text_widget
,
859 G_CALLBACK (&x_window_show_text
),
863 w_current
->macro_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_MACRO_WIDGET
, NULL
));
865 gtk_box_pack_start (GTK_BOX (work_box
),
866 w_current
->macro_widget
,
871 g_signal_connect (w_current
->macro_widget
,
873 G_CALLBACK (&x_window_invoke_macro
),
877 w_current
->compselect_dockable
= g_object_new (
878 GSCHEM_TYPE_COMPSELECT_DOCKABLE
,
879 "title", _("Library"),
880 "settings-name", "compselect",
882 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
,
883 "initial-width", 500,
884 "initial-height", 600,
885 "gschem-toplevel", w_current
,
888 w_current
->object_properties_dockable
= g_object_new (
889 GSCHEM_TYPE_OBJECT_PROPERTIES_DOCKABLE
,
890 "title", _("Object"),
891 "settings-name", "object-properties", /* line-type */
892 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
,
893 "initial-width", 400,
894 "initial-height", 600,
895 "gschem-toplevel", w_current
,
898 w_current
->text_properties_dockable
= g_object_new (
899 GSCHEM_TYPE_TEXT_PROPERTIES_DOCKABLE
,
901 "settings-name", "text-edit",
902 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
,
903 "initial-width", 400,
904 "initial-height", 450,
905 "gschem-toplevel", w_current
,
908 w_current
->multiattrib_dockable
= g_object_new (
909 GSCHEM_TYPE_MULTIATTRIB_DOCKABLE
,
910 "title", _("Attributes"),
911 "settings-name", "multiattrib",
912 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
,
913 "initial-width", 450,
914 "initial-height", 450,
915 "gschem-toplevel", w_current
,
918 w_current
->options_dockable
= g_object_new (
919 GSCHEM_TYPE_OPTIONS_DOCKABLE
,
920 "title", _("Options"),
921 "settings-name", "options", /* snap-size */
922 "initial-state", GSCHEM_DOCKABLE_STATE_HIDDEN
,
923 "initial-width", 320,
924 "initial-height", 350,
925 "gschem-toplevel", w_current
,
928 w_current
->log_dockable
= g_object_new (
929 GSCHEM_TYPE_LOG_DOCKABLE
,
930 "title", _("Status"),
931 "settings-name", "log",
932 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
,
933 "initial-width", 640,
934 "initial-height", 480,
935 "gschem-toplevel", w_current
,
938 w_current
->messages_dockable
= g_object_new (
939 GSCHEM_TYPE_MESSAGES_DOCKABLE
,
940 "title", _("Messages"),
941 "settings-name", "messages",
942 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
,
943 "initial-width", 800,
944 "initial-height", 320,
945 "gschem-toplevel", w_current
,
948 w_current
->find_text_dockable
= g_object_new (
949 GSCHEM_TYPE_FIND_TEXT_DOCKABLE
,
950 "title", _("Search results"),
951 "settings-name", "find-text",
952 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
,
953 "initial-width", 500,
954 "initial-height", 300,
955 "gschem-toplevel", w_current
,
957 g_signal_connect (w_current
->find_text_dockable
,
959 G_CALLBACK (&x_window_select_text
),
962 w_current
->patch_dockable
= g_object_new (
963 GSCHEM_TYPE_PATCH_DOCKABLE
,
965 "settings-name", "patch",
966 "initial-state", GSCHEM_DOCKABLE_STATE_HIDDEN
,
967 "initial-width", 500,
968 "initial-height", 300,
969 "gschem-toplevel", w_current
,
972 w_current
->pagesel_dockable
= g_object_new (
973 GSCHEM_TYPE_PAGESEL_DOCKABLE
,
975 "settings-name", "pagesel",
976 "initial-state", GSCHEM_DOCKABLE_STATE_HIDDEN
,
977 "initial-width", 515,
978 "initial-height", 180,
979 "gschem-toplevel", w_current
,
982 gschem_dockable_initialize_toplevel (w_current
);
986 if (default_third_button
== POPUP_ENABLED
) {
987 right_button_text
= _("Menu/Cancel");
989 right_button_text
= _("Pan/Cancel");
992 w_current
->bottom_widget
= GTK_WIDGET (g_object_new (GSCHEM_TYPE_BOTTOM_WIDGET
,
993 "grid-mode", gschem_options_get_grid_mode (w_current
->options
),
994 "grid-size", gschem_options_get_snap_size (w_current
->options
), /* x_grid_query_drawn_spacing (w_current), -- occurs before the page is set */
995 "left-button-text", _("Pick"),
996 "middle-button-text", _("none"),
997 "right-button-text", right_button_text
,
998 "snap-mode", gschem_options_get_snap_mode (w_current
->options
),
999 "snap-size", gschem_options_get_snap_size (w_current
->options
),
1000 "status-text", _("Select Mode"),
1003 i_update_middle_button (w_current
, NULL
, NULL
);
1005 gtk_box_pack_start (GTK_BOX (main_box
), w_current
->bottom_widget
, FALSE
, FALSE
, 0);
1007 x_window_restore_geometry (w_current
);
1008 g_signal_connect (G_OBJECT (w_current
->main_window
), "window-state-event",
1009 G_CALLBACK (x_window_state_event
), w_current
);
1011 gtk_widget_show_all (w_current
->main_window
);
1013 /* hide unused notebooks */
1014 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (w_current
->left_notebook
)) == 0)
1015 gtk_widget_hide (w_current
->left_notebook
);
1016 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (w_current
->bottom_notebook
)) == 0)
1017 gtk_widget_hide (w_current
->bottom_notebook
);
1018 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (w_current
->right_notebook
)) == 0)
1019 gtk_widget_hide (w_current
->right_notebook
);
1022 /*! \todo Finish function documentation!!!
1024 * \par Function Description
1027 void x_window_close(GschemToplevel
*w_current
)
1029 gboolean last_window
= FALSE
;
1031 /* If we're closing whilst inside an action, re-wind the
1032 * page contents back to their state before we started */
1033 if (w_current
->inside_action
) {
1034 i_cancel (w_current
);
1037 /* last chance to save possible unsaved pages */
1038 if (!x_dialog_close_window (w_current
)) {
1039 /* user somehow cancelled the close */
1043 x_clipboard_finish (w_current
);
1046 o_conn_print_hash(w_current
->page_current
->conn_table
);
1049 w_current
->dont_invalidate
= TRUE
;
1051 /* save window geometry */
1052 x_window_save_geometry (w_current
);
1054 /* close all the dialog boxes */
1055 if (w_current
->sowindow
)
1056 gtk_widget_destroy(w_current
->sowindow
);
1058 if (w_current
->tiwindow
)
1059 gtk_widget_destroy(w_current
->tiwindow
);
1061 if (w_current
->aawindow
)
1062 gtk_widget_destroy(w_current
->aawindow
);
1064 if (w_current
->aewindow
)
1065 gtk_widget_destroy(w_current
->aewindow
);
1067 if (w_current
->hkwindow
)
1068 gtk_widget_destroy(w_current
->hkwindow
);
1070 if (w_current
->sewindow
)
1071 gtk_widget_destroy(w_current
->sewindow
);
1073 /* save dock window geometry, close dock windows, disconnect signals */
1074 gschem_dockable_cleanup_toplevel (w_current
);
1076 g_clear_object (&w_current
->compselect_dockable
);
1077 g_clear_object (&w_current
->object_properties_dockable
);
1078 g_clear_object (&w_current
->text_properties_dockable
);
1079 g_clear_object (&w_current
->multiattrib_dockable
);
1080 g_clear_object (&w_current
->options_dockable
);
1081 g_clear_object (&w_current
->log_dockable
);
1082 g_clear_object (&w_current
->messages_dockable
);
1083 g_clear_object (&w_current
->find_text_dockable
);
1084 g_clear_object (&w_current
->patch_dockable
);
1085 g_clear_object (&w_current
->pagesel_dockable
);
1087 if (g_list_length (global_window_list
) == 1) {
1088 /* no more window after this one, remember to quit */
1092 /* stuff that has to be done before we free w_current */
1094 /* close the log file */
1096 /* free the buffers */
1097 o_buffer_free (w_current
);
1100 /* Allow Scheme value for this window to be garbage-collected */
1101 if (!SCM_UNBNDP (w_current
->smob
)) {
1102 SCM_SET_SMOB_DATA (w_current
->smob
, NULL
);
1103 scm_gc_unprotect_object (w_current
->smob
);
1104 w_current
->smob
= SCM_UNDEFINED
;
1107 /* finally close the main window */
1108 gtk_widget_destroy(w_current
->main_window
);
1110 global_window_list
= g_list_remove (global_window_list
, w_current
);
1111 gschem_toplevel_free (w_current
);
1113 /* just closed last window, so quit */
1119 /*! \todo Finish function documentation!!!
1121 * \par Function Description
1124 void x_window_close_all(GschemToplevel
*w_current
)
1126 GschemToplevel
*current
;
1127 GList
*list_copy
, *iter
;
1129 iter
= list_copy
= g_list_copy (global_window_list
);
1130 while (iter
!= NULL
) {
1131 current
= (GschemToplevel
*)iter
->data
;
1132 iter
= g_list_next (iter
);
1133 x_window_close (current
);
1135 g_list_free (list_copy
);
1138 /*! \brief Changes the current page.
1139 * \par Function Description
1140 * This function displays the specified page <B>page</B> in the
1141 * window attached to <B>toplevel</B>.
1143 * It changes the <B>toplevel</B>'s current page to <B>page</B>,
1144 * draws it and updates the user interface.
1146 * <B>page</B> has to be in the list of PAGEs attached to <B>toplevel</B>.
1148 * \param [in] w_current The toplevel environment.
1149 * \param [in] page The page to become current page.
1152 x_window_set_current_page (GschemToplevel
*w_current
, PAGE
*page
)
1154 GschemPageView
*page_view
= gschem_toplevel_get_current_page_view (w_current
);
1155 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
1158 g_return_if_fail (page_view
!= NULL
);
1159 g_return_if_fail (toplevel
!= NULL
);
1160 g_return_if_fail (page
!= NULL
);
1162 g_warn_if_fail (page_view
->page
== toplevel
->page_current
||
1163 page_view
->page
== NULL
);
1165 if (page
== toplevel
->page_current
&& page_view
->page
!= NULL
)
1169 o_redraw_cleanstates (w_current
);
1171 gschem_page_view_set_page (page_view
, page
);
1173 gschem_action_set_sensitive (action_page_revert
,
1174 page
->is_untitled
== FALSE
&&
1175 g_file_test (page
->page_filename
,
1176 G_FILE_TEST_EXISTS
|
1177 G_FILE_TEST_IS_REGULAR
),
1180 o_undo_update_actions (w_current
, page
);
1182 iter
= g_list_find (geda_list_get_glist (toplevel
->pages
), page
);
1183 gschem_action_set_sensitive (action_page_prev
,
1184 w_current
->enforce_hierarchy
1185 ? s_hierarchy_find_prev_page (
1186 toplevel
->pages
, page
) != NULL
1187 : iter
!= NULL
&& iter
->prev
!= NULL
,
1189 gschem_action_set_sensitive (action_page_next
,
1190 w_current
->enforce_hierarchy
1191 ? s_hierarchy_find_next_page(
1192 toplevel
->pages
, page
) != NULL
1193 : iter
!= NULL
&& iter
->next
!= NULL
,
1195 gschem_action_set_sensitive (action_hierarchy_up
, page
->up
>= 0, w_current
);
1197 i_update_menus (w_current
);
1198 /* i_set_filename (w_current, page->page_filename); */
1200 x_window_update_file_change_notification (w_current
, page
);
1201 x_window_update_patch_change_notification (w_current
, page
);
1203 x_pagesel_update (w_current
);
1204 x_multiattrib_update (w_current
);
1205 x_messages_page_changed (w_current
);
1208 /*! \brief Raise the main window to the front.
1210 * This is mostly equivalent to
1211 * gtk_window_present (GTK_WINDOW (w_current->main_window));
1213 * One of the two actions that \c gtk_window_present performs on an
1214 * already-visible window (\c gdk_window_show) is triggering a bug
1215 * with toolbar icon drawing, the other (\c gdk_window_focus) is the
1216 * one we actually want. In order to work around that bug, just call
1217 * \c gdk_window_focus directly.
1219 * \param [in] w_current the toplevel environment
1221 void x_window_present (GschemToplevel
*w_current
)
1223 //gdk_window_show (w_current->main_window->window); /* the culprit */
1225 #ifdef GDK_WINDOWING_X11
1226 GdkDisplay
*display
= gtk_widget_get_display (w_current
->main_window
);
1227 guint32 timestamp
= gdk_x11_display_get_user_time (display
);
1229 guint32 timestamp
= gtk_get_current_event_time ();
1232 gdk_window_focus (w_current
->main_window
->window
, timestamp
);
1235 /*! \brief Setup default icon for GTK windows
1237 * \par Function Description
1238 * Sets the default window icon by name, to be found in the current icon
1239 * theme. The name used is \#defined above as GSCHEM_THEME_ICON_NAME.
1241 void x_window_set_default_icon( void )
1243 gtk_window_set_default_icon_name( GSCHEM_THEME_ICON_NAME
);
1246 /*! \brief Setup icon search paths.
1247 * \par Function Description
1248 * Add the icons installed by gschem to the search path for the
1249 * default icon theme, so that they can be automatically found by GTK.
1252 x_window_init_icons (void)
1256 g_return_if_fail (s_path_sys_data () != NULL
);
1258 icon_path
= g_build_filename (s_path_sys_data (), "icons", NULL
);
1259 gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
1264 /*! \brief Creates a new X window.
1266 * \par Function description
1268 * Creates and initializes new GschemToplevel object and then sets
1269 * and setups its libgeda \a toplevel.
1271 * \param toplevel The libgeda TOPLEVEL object.
1272 * \return Pointer to the new GschemToplevel object.
1274 GschemToplevel
* x_window_new (TOPLEVEL
*toplevel
)
1276 GschemToplevel
*w_current
;
1278 w_current
= gschem_toplevel_new ();
1279 gschem_toplevel_set_toplevel (w_current
,
1280 (toplevel
!= NULL
) ? toplevel
: s_toplevel_new ());
1282 gschem_toplevel_get_toplevel (w_current
)->load_newer_backup_func
= x_fileselect_load_backup
;
1283 gschem_toplevel_get_toplevel (w_current
)->load_newer_backup_data
= w_current
;
1285 o_text_set_rendered_bounds_func (gschem_toplevel_get_toplevel (w_current
),
1286 o_text_get_rendered_bounds
, w_current
);
1288 /* Damage notifications should invalidate the object on screen */
1289 o_add_change_notify (gschem_toplevel_get_toplevel (w_current
),
1290 (ChangeNotifyFunc
) o_invalidate
,
1291 (ChangeNotifyFunc
) o_invalidate
, w_current
);
1293 x_window_setup (w_current
);