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
23 #include <gdk/gdkkeysyms.h>
27 PROP_GSCHEM_TOPLEVEL
= 1,
39 static gpointer parent_class
= NULL
;
41 static void class_init (GschemDockableClass
*class);
42 static void instance_init (GschemDockable
*dockable
);
43 static void constructed (GObject
*object
);
44 static void dispose (GObject
*object
);
45 static void finalize (GObject
*object
);
46 static void set_property (GObject
*object
, guint property_id
,
47 const GValue
*value
, GParamSpec
*pspec
);
48 static void get_property (GObject
*object
, guint property_id
,
49 GValue
*value
, GParamSpec
*pspec
);
51 static GtkWidget
*real_create_widget (GschemDockable
*dockable
);
52 static void real_post_present (GschemDockable
*dockable
);
53 static void real_cancel (GschemDockable
*dockable
);
54 static void real_save_internal_geometry (GschemDockable
*dockable
,
55 EdaConfig
*cfg
, gchar
*group_name
);
56 static void real_restore_internal_geometry (GschemDockable
*dockable
,
57 EdaConfig
*cfg
, gchar
*group_name
);
59 static const gchar
*get_notebook_group_name (
60 GschemToplevel
*w_current
, GtkNotebook
*notebook
);
61 static GschemDockable
*get_dockable_by_widget (
62 GschemToplevel
*w_current
, GtkWidget
*widget
);
63 static GschemDockable
*get_dockable_by_settings_name (
64 GschemToplevel
*w_current
, const gchar
*settings_name
);
66 static void save_internal_geometry (GschemDockable
*dockable
);
67 static void save_window_geometry (GschemDockable
*dockable
);
68 static void save_state (GschemDockable
*dockable
);
69 static void save_page_order (GschemToplevel
*w_current
,
70 GtkNotebook
*notebook
);
71 static void save_current_page (GschemToplevel
*w_current
,
72 GtkNotebook
*notebook
,
73 GschemDockable
*dockable
);
74 static void restore_internal_geometry (GschemDockable
*dockable
);
75 static void restore_window_geometry (GschemDockable
*dockable
);
76 static void restore_state (GschemDockable
*dockable
);
77 static void restore_page_order (GschemToplevel
*w_current
,
78 GtkNotebook
*notebook
);
79 static void restore_current_page (GschemToplevel
*w_current
,
80 GtkNotebook
*notebook
);
81 static void restore_detached_dockables (GschemToplevel
*w_current
);
83 static void create_widget (GschemDockable
*dockable
);
84 static void create_window (GschemDockable
*dockable
);
85 static void create_menu (GschemDockable
*dockable
);
86 static void update_menu_items (GschemDockable
*dockable
);
87 static void present_in_notebook (GschemDockable
*dockable
);
89 static void connect_notebook_signals (GschemToplevel
*w_current
,
93 callback_after_window_key_press_event (GtkWidget
*widget
,
95 GschemDockable
*dockable
);
97 callback_window_delete_event (GtkWidget
*widget
,
99 GschemDockable
*dockable
);
101 callback_hide_button_clicked (GtkWidget
*button
,
102 GschemDockable
*dockable
);
104 callback_cancel_button_clicked (GtkWidget
*button
,
105 GschemDockable
*dockable
);
107 callback_help_button_clicked (GtkWidget
*button
,
108 GschemDockable
*dockable
);
110 callback_dock_item_toggled (GtkWidget
*check_menu_item
,
111 GschemDockable
*dockable
);
113 callback_menu_item_activate (GtkWidget
*menu_item
,
114 GschemDockable
*dockable
);
116 callback_event_box_button_press_event (GtkWidget
*widget
,
117 GdkEventButton
*event
,
118 GschemDockable
*dockable
);
121 callback_main_window_focus_in_event (GtkWidget
*widget
,
123 GschemToplevel
*w_current
);
125 callback_notebook_page_added (GtkWidget
*notebook
,
128 GschemToplevel
*w_current
);
130 callback_notebook_page_added_removed_reordered (GtkWidget
*notebook
,
133 GschemToplevel
*w_current
);
135 callback_notebook_switch_page (GtkWidget
*notebook
,
138 GschemToplevel
*w_current
);
140 callback_notebook_create_window (GtkWidget
*notebook
,
143 GschemToplevel
*w_current
);
145 callback_notebook_key_press_event (GtkWidget
*notebook
,
147 GschemToplevel
*w_current
);
149 callback_notebook_button_press_event (GtkWidget
*notebook
,
150 GdkEventButton
*event
,
151 GschemToplevel
*w_current
);
155 gschem_dockable_state_get_type ()
157 static GType type
= 0;
160 static const GEnumValue values
[] = {
161 { GSCHEM_DOCKABLE_STATE_HIDDEN
,
162 "GSCHEM_DOCKABLE_STATE_HIDDEN", "hidden" },
163 { GSCHEM_DOCKABLE_STATE_DIALOG
,
164 "GSCHEM_DOCKABLE_STATE_DIALOG", "dialog" },
165 { GSCHEM_DOCKABLE_STATE_WINDOW
,
166 "GSCHEM_DOCKABLE_STATE_WINDOW", "window" },
167 { GSCHEM_DOCKABLE_STATE_DOCKED_LEFT
,
168 "GSCHEM_DOCKABLE_STATE_DOCKED_LEFT", "docked-left" },
169 { GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
,
170 "GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM", "docked-bottom" },
171 { GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
,
172 "GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT", "docked-right" },
176 type
= g_enum_register_static ("GschemDockableState", values
);
184 gschem_dockable_get_type ()
186 static GType type
= 0;
189 static const GTypeInfo info
= {
190 sizeof (GschemDockableClass
),
191 NULL
, /* base_init */
192 NULL
, /* base_finalize */
193 (GClassInitFunc
) class_init
,
194 NULL
, /* class_finalize */
195 NULL
, /* class_data */
196 sizeof (GschemDockable
),
198 (GInstanceInitFunc
) instance_init
,
199 NULL
/* value_table */
202 type
= g_type_register_static (G_TYPE_OBJECT
,
205 G_TYPE_FLAG_ABSTRACT
);
213 class_init (GschemDockableClass
*class)
215 GObjectClass
*gobject_class
= G_OBJECT_CLASS (class);
217 class->create_widget
= real_create_widget
;
218 class->post_present
= real_post_present
;
219 class->cancel
= real_cancel
;
220 class->save_internal_geometry
= real_save_internal_geometry
;
221 class->restore_internal_geometry
= real_restore_internal_geometry
;
223 gobject_class
->constructed
= constructed
;
224 gobject_class
->dispose
= dispose
;
225 gobject_class
->finalize
= finalize
;
226 gobject_class
->set_property
= set_property
;
227 gobject_class
->get_property
= get_property
;
229 parent_class
= g_type_class_peek_parent (class);
231 g_object_class_install_property (
232 gobject_class
, PROP_GSCHEM_TOPLEVEL
,
233 g_param_spec_pointer ("gschem-toplevel",
236 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
238 g_object_class_install_property (
239 gobject_class
, PROP_TITLE
,
240 g_param_spec_string ("title",
244 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
245 g_object_class_install_property (
246 gobject_class
, PROP_SETTINGS_NAME
,
247 g_param_spec_string ("settings-name",
251 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
252 g_object_class_install_property (
253 gobject_class
, PROP_CANCELLABLE
,
254 g_param_spec_boolean ("cancellable",
258 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
259 g_object_class_install_property (
260 gobject_class
, PROP_HELP_PAGE
,
261 g_param_spec_string ("help-page",
265 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
267 g_object_class_install_property (
268 gobject_class
, PROP_INITIAL_STATE
,
269 g_param_spec_enum ("initial-state",
272 GSCHEM_TYPE_DOCKABLE_STATE
,
273 GSCHEM_DOCKABLE_STATE_WINDOW
,
274 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
275 g_object_class_install_property (
276 gobject_class
, PROP_INITIAL_WIDTH
,
277 g_param_spec_int ("initial-width",
283 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
284 g_object_class_install_property (
285 gobject_class
, PROP_INITIAL_HEIGHT
,
286 g_param_spec_int ("initial-height",
292 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
293 g_object_class_install_property (
294 gobject_class
, PROP_INITIAL_WIN_POS
,
295 g_param_spec_enum ("initial-window-position",
298 GTK_TYPE_WINDOW_POSITION
,
300 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
302 g_object_class_install_property (
303 gobject_class
, PROP_STATE
,
304 g_param_spec_enum ("state",
307 GSCHEM_TYPE_DOCKABLE_STATE
,
308 GSCHEM_DOCKABLE_STATE_HIDDEN
,
314 instance_init (GschemDockable
*dockable
)
316 dockable
->w_current
= NULL
;
318 dockable
->title
= NULL
;
319 dockable
->settings_name
= NULL
;
320 dockable
->group_name
= NULL
;
321 dockable
->cancellable
= FALSE
;
322 dockable
->help_page
= NULL
;
324 dockable
->initial_state
= GSCHEM_DOCKABLE_STATE_HIDDEN
;
325 dockable
->initial_width
= -1;
326 dockable
->initial_height
= -1;
327 dockable
->initial_position
= GTK_WIN_POS_NONE
;
329 dockable
->widget
= NULL
;
330 dockable
->window
= NULL
;
331 dockable
->vbox
= NULL
;
332 dockable
->action_area
= NULL
;
333 dockable
->hide_button
= NULL
;
334 dockable
->cancel_button
= NULL
;
335 dockable
->help_button
= NULL
;
337 dockable
->dock_left_item
= NULL
;
338 dockable
->dock_bottom_item
= NULL
;
339 dockable
->dock_right_item
= NULL
;
341 dockable
->menu
= NULL
;
342 dockable
->detach_item
= NULL
;
343 dockable
->move_left_item
= NULL
;
344 dockable
->move_bottom_item
= NULL
;
345 dockable
->move_right_item
= NULL
;
346 dockable
->close_item
= NULL
;
351 constructed (GObject
*object
)
353 G_OBJECT_CLASS (parent_class
)->constructed (object
);
355 GschemDockable
*dockable
= GSCHEM_DOCKABLE (object
);
356 g_return_if_fail (dockable
->w_current
!= NULL
);
358 dockable
->w_current
->dockables
= g_list_append (
359 dockable
->w_current
->dockables
, dockable
);
361 dockable
->dock_left_item
=
362 gtk_check_menu_item_new_with_label (dockable
->title
);
363 gtk_widget_show (dockable
->dock_left_item
);
364 dockable
->dock_bottom_item
=
365 gtk_check_menu_item_new_with_label (dockable
->title
);
366 gtk_widget_show (dockable
->dock_bottom_item
);
367 dockable
->dock_right_item
=
368 gtk_check_menu_item_new_with_label (dockable
->title
);
369 gtk_widget_show (dockable
->dock_right_item
);
371 restore_state (dockable
);
373 g_signal_connect (dockable
->dock_left_item
, "toggled",
374 G_CALLBACK (callback_dock_item_toggled
), dockable
);
375 g_signal_connect (dockable
->dock_bottom_item
, "toggled",
376 G_CALLBACK (callback_dock_item_toggled
), dockable
);
377 g_signal_connect (dockable
->dock_right_item
, "toggled",
378 G_CALLBACK (callback_dock_item_toggled
), dockable
);
383 dispose (GObject
*object
)
385 GschemDockable
*dockable
= GSCHEM_DOCKABLE (object
);
387 g_clear_object (&dockable
->widget
);
388 g_clear_object (&dockable
->menu
);
390 G_OBJECT_CLASS (parent_class
)->dispose (object
);
395 finalize (GObject
*object
)
397 GschemDockable
*dockable
= GSCHEM_DOCKABLE (object
);
399 g_free (dockable
->title
);
400 g_free (dockable
->settings_name
);
401 g_free (dockable
->group_name
);
402 g_free (dockable
->help_page
);
404 G_OBJECT_CLASS (parent_class
)->finalize (object
);
409 set_property (GObject
*object
, guint property_id
,
410 const GValue
*value
, GParamSpec
*pspec
)
412 GschemDockable
*dockable
= GSCHEM_DOCKABLE (object
);
414 switch (property_id
) {
415 /* Properties specified as G_PARAM_CONSTRUCT[_ONLY] are set during
416 * construction--the instance isn't fully initialized at that time.
417 * Don't do any setup logic here. */
419 case PROP_GSCHEM_TOPLEVEL
:
420 dockable
->w_current
= GSCHEM_TOPLEVEL (g_value_get_pointer (value
));
424 g_free (dockable
->title
);
425 dockable
->title
= g_strdup (g_value_get_string (value
));
427 case PROP_SETTINGS_NAME
:
428 g_free (dockable
->settings_name
);
429 g_free (dockable
->group_name
);
430 dockable
->settings_name
= g_strdup (g_value_get_string (value
));
431 dockable
->group_name
= g_strdup_printf ("gschem.dialog-geometry.%s",
432 dockable
->settings_name
);
434 case PROP_CANCELLABLE
:
435 dockable
->cancellable
= g_value_get_boolean (value
);
438 g_free (dockable
->help_page
);
439 dockable
->help_page
= g_strdup (g_value_get_string (value
));
442 case PROP_INITIAL_STATE
:
443 dockable
->initial_state
= g_value_get_enum (value
);
445 case PROP_INITIAL_WIDTH
:
446 dockable
->initial_width
= g_value_get_int (value
);
448 case PROP_INITIAL_HEIGHT
:
449 dockable
->initial_height
= g_value_get_int (value
);
451 case PROP_INITIAL_WIN_POS
:
452 dockable
->initial_position
= g_value_get_enum (value
);
455 /* Properties not specified as G_PARAM_CONSTRUCT[_ONLY] will only
456 * be set after the object has been fully initialized. */
459 gschem_dockable_set_state (dockable
, g_value_get_enum (value
));
463 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
469 get_property (GObject
*object
, guint property_id
,
470 GValue
*value
, GParamSpec
*pspec
)
472 GschemDockable
*dockable
= GSCHEM_DOCKABLE (object
);
474 switch (property_id
) {
475 case PROP_GSCHEM_TOPLEVEL
:
476 g_value_set_pointer (value
, dockable
->w_current
);
479 g_value_set_string (value
, dockable
->title
);
481 case PROP_SETTINGS_NAME
:
482 g_value_set_string (value
, dockable
->settings_name
);
484 case PROP_CANCELLABLE
:
485 g_value_set_boolean (value
, dockable
->cancellable
);
488 g_value_set_string (value
, dockable
->help_page
);
490 case PROP_INITIAL_STATE
:
491 g_value_set_enum (value
, dockable
->initial_state
);
493 case PROP_INITIAL_WIDTH
:
494 g_value_set_int (value
, dockable
->initial_width
);
496 case PROP_INITIAL_HEIGHT
:
497 g_value_set_int (value
, dockable
->initial_height
);
499 case PROP_INITIAL_WIN_POS
:
500 g_value_set_enum (value
, dockable
->initial_position
);
503 g_value_set_enum (value
, gschem_dockable_get_state (dockable
));
506 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
512 real_create_widget (GschemDockable
*dockable
)
514 g_assert_not_reached ();
519 real_post_present (GschemDockable
*dockable
)
521 /* default action: none */
526 real_cancel (GschemDockable
*dockable
)
528 /* default action: ignore */
533 real_save_internal_geometry (GschemDockable
*dockable
,
534 EdaConfig
*cfg
, gchar
*group_name
)
536 /* override if dockable has internal geometry */
541 real_restore_internal_geometry (GschemDockable
*dockable
,
542 EdaConfig
*cfg
, gchar
*group_name
)
544 /* override if dockable has internal geometry */
548 /******************************************************************************/
552 get_notebook_group_name (GschemToplevel
*w_current
, GtkNotebook
*notebook
)
554 if (GTK_WIDGET (notebook
) == w_current
->left_notebook
)
555 return "gschem.dock-geometry.left";
556 if (GTK_WIDGET (notebook
) == w_current
->bottom_notebook
)
557 return "gschem.dock-geometry.bottom";
558 if (GTK_WIDGET (notebook
) == w_current
->right_notebook
)
559 return "gschem.dock-geometry.right";
560 g_assert_not_reached ();
564 static GschemDockable
*
565 get_dockable_by_widget (GschemToplevel
*w_current
, GtkWidget
*widget
)
567 g_return_val_if_fail (widget
!= NULL
, NULL
);
569 GValue value
= G_VALUE_INIT
;
570 g_value_init (&value
, G_TYPE_POINTER
);
571 g_object_get_property (G_OBJECT (widget
), "user-data", &value
);
572 return GSCHEM_DOCKABLE (g_value_get_pointer (&value
));
576 static GschemDockable
*
577 get_dockable_by_settings_name (GschemToplevel
*w_current
,
578 const gchar
*settings_name
)
580 g_return_val_if_fail (settings_name
!= NULL
, NULL
);
582 for (GList
*l
= w_current
->dockables
; l
!= NULL
; l
= l
->next
) {
583 GschemDockable
*dockable
= GSCHEM_DOCKABLE (l
->data
);
584 if (strcmp (settings_name
, dockable
->settings_name
) == 0)
588 return NULL
; /* unknown dockable name */
592 /*! \brief Save current internal geometry of a dockable */
594 save_internal_geometry (GschemDockable
*dockable
)
596 EdaConfig
*cfg
= eda_config_get_user_context ();
597 g_return_if_fail (cfg
!= NULL
);
598 g_return_if_fail (dockable
->widget
!= NULL
);
600 GSCHEM_DOCKABLE_GET_CLASS (dockable
)
601 ->save_internal_geometry (dockable
, cfg
, dockable
->group_name
);
605 /*! \brief Save current window position and size of a detached dockable */
607 save_window_geometry (GschemDockable
*dockable
)
609 EdaConfig
*cfg
= eda_config_get_user_context ();
610 g_return_if_fail (cfg
!= NULL
);
611 g_return_if_fail (dockable
->window
!= NULL
);
613 gint x
, y
, width
, height
;
614 gtk_window_get_position (GTK_WINDOW (dockable
->window
), &x
, &y
);
615 gtk_window_get_size (GTK_WINDOW (dockable
->window
), &width
, &height
);
617 eda_config_set_int (cfg
, dockable
->group_name
, "x", x
);
618 eda_config_set_int (cfg
, dockable
->group_name
, "y", y
);
619 eda_config_set_int (cfg
, dockable
->group_name
, "width", width
);
620 eda_config_set_int (cfg
, dockable
->group_name
, "height", height
);
624 /*! \brief Save current state of a dockable */
626 save_state (GschemDockable
*dockable
)
628 EdaConfig
*cfg
= eda_config_get_user_context ();
629 g_return_if_fail (cfg
!= NULL
);
631 GschemDockableState state
= gschem_dockable_get_state (dockable
);
633 state
== GSCHEM_DOCKABLE_STATE_WINDOW
? "detached" :
634 state
== GSCHEM_DOCKABLE_STATE_DOCKED_LEFT
? "docked-left" :
635 state
== GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
? "docked-bottom" :
636 state
== GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
? "docked-right" : "hidden";
638 eda_config_set_string (cfg
, dockable
->group_name
, "state", value
);
643 save_page_order (GschemToplevel
*w_current
,
644 GtkNotebook
*notebook
)
646 EdaConfig
*cfg
= eda_config_get_user_context ();
647 g_return_if_fail (cfg
!= NULL
);
649 gint page_count
= gtk_notebook_get_n_pages (notebook
);
651 /* write new page order to configuration */
652 const gchar
**list
= g_new (const gchar
*, page_count
);
654 for (gint page_num
= 0; page_num
< page_count
; page_num
++) {
655 GtkWidget
*widget
= gtk_notebook_get_nth_page (notebook
, page_num
);
656 GschemDockable
*dockable
= get_dockable_by_widget (w_current
, widget
);
657 g_return_if_fail (dockable
!= NULL
);
658 list
[page_num
] = dockable
->settings_name
;
661 eda_config_set_string_list (
662 cfg
, get_notebook_group_name (w_current
, notebook
),
663 "page-order", list
, page_count
);
667 /* clear current page key if notebook is empty */
669 eda_config_set_string (
670 cfg
, get_notebook_group_name (w_current
, notebook
),
676 save_current_page (GschemToplevel
*w_current
,
677 GtkNotebook
*notebook
,
678 GschemDockable
*dockable
)
680 EdaConfig
*cfg
= eda_config_get_user_context ();
681 g_return_if_fail (cfg
!= NULL
);
683 eda_config_set_string (
684 cfg
, get_notebook_group_name (w_current
, notebook
),
685 "current-page", dockable
->settings_name
);
689 /*! \brief Restore last internal geometry of a dockable */
691 restore_internal_geometry (GschemDockable
*dockable
)
693 EdaConfig
*cfg
= eda_config_get_user_context ();
694 g_return_if_fail (cfg
!= NULL
);
695 g_return_if_fail (dockable
->widget
!= NULL
);
697 GSCHEM_DOCKABLE_GET_CLASS (dockable
)
698 ->restore_internal_geometry (dockable
, cfg
, dockable
->group_name
);
702 /*! \brief Restore last window position and size of a detached dockable */
704 restore_window_geometry (GschemDockable
*dockable
)
706 EdaConfig
*cfg
= eda_config_get_user_context ();
707 g_return_if_fail (cfg
!= NULL
);
708 g_return_if_fail (dockable
->window
!= NULL
);
710 if (!eda_config_has_group (cfg
, dockable
->group_name
))
711 gtk_window_set_position (GTK_WINDOW (dockable
->window
),
712 dockable
->initial_position
);
714 gint x
, y
, width
, height
;
715 x
= eda_config_get_int (cfg
, dockable
->group_name
, "x", NULL
);
716 y
= eda_config_get_int (cfg
, dockable
->group_name
, "y", NULL
);
717 width
= eda_config_get_int (cfg
, dockable
->group_name
, "width", NULL
);
718 height
= eda_config_get_int (cfg
, dockable
->group_name
, "height", NULL
);
720 gtk_window_move (GTK_WINDOW (dockable
->window
), x
, y
);
721 if (width
> 0 && height
> 0)
722 gtk_window_resize (GTK_WINDOW (dockable
->window
), width
, height
);
727 /*! \brief Restore last state of a dockable (if it was docked) */
729 restore_state (GschemDockable
*dockable
)
731 EdaConfig
*cfg
= eda_config_get_user_context ();
732 g_return_if_fail (cfg
!= NULL
);
734 gchar
*state
= eda_config_get_string (
735 cfg
, dockable
->group_name
, "state", NULL
);
738 if (dockable
->initial_state
!= GSCHEM_DOCKABLE_STATE_WINDOW
)
739 gschem_dockable_set_state (dockable
, dockable
->initial_state
);
740 } else if (strcmp (state
, "detached") == 0)
741 /* detached docks are restored later */;
742 else if (strcmp (state
, "docked-left") == 0)
743 gschem_dockable_set_state (dockable
, GSCHEM_DOCKABLE_STATE_DOCKED_LEFT
);
744 else if (strcmp (state
, "docked-bottom") == 0)
745 gschem_dockable_set_state (dockable
, GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
);
746 else if (strcmp (state
, "docked-right") == 0)
747 gschem_dockable_set_state (dockable
, GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
);
754 restore_page_order (GschemToplevel
*w_current
,
755 GtkNotebook
*notebook
)
757 EdaConfig
*cfg
= eda_config_get_user_context ();
758 g_return_if_fail (cfg
!= NULL
);
761 gsize page_count
= 0;
764 list
= eda_config_get_string_list (
765 cfg
, get_notebook_group_name (w_current
, notebook
),
766 "page-order", &page_count
, NULL
);
768 for (page_num
= 0; page_num
< page_count
; page_num
++) {
769 GschemDockable
*dockable
=
770 get_dockable_by_settings_name (w_current
, list
[page_num
]);
771 if (dockable
!= NULL
&& dockable
->widget
!= NULL
)
772 gtk_notebook_reorder_child (notebook
, dockable
->widget
, page_num
);
780 restore_current_page (GschemToplevel
*w_current
,
781 GtkNotebook
*notebook
)
783 EdaConfig
*cfg
= eda_config_get_user_context ();
784 g_return_if_fail (cfg
!= NULL
);
786 gchar
*current_page
= eda_config_get_string (
787 cfg
, get_notebook_group_name (w_current
, notebook
),
788 "current-page", NULL
);
790 GschemDockable
*dockable
= NULL
;
791 if (current_page
!= NULL
&& *current_page
!= '\0')
792 dockable
= get_dockable_by_settings_name (w_current
, current_page
);
794 g_free (current_page
);
795 if (dockable
== NULL
|| dockable
->widget
== NULL
)
798 gint page_num
= gtk_notebook_page_num (notebook
, dockable
->widget
);
802 /* non-dockable tabs aren't necessarily visible at this point */
803 gtk_widget_show (dockable
->widget
);
805 gtk_notebook_set_current_page (notebook
, page_num
);
810 restore_detached_dockables (GschemToplevel
*w_current
)
812 EdaConfig
*cfg
= eda_config_get_user_context ();
813 g_return_if_fail (cfg
!= NULL
);
815 for (GList
*l
= w_current
->dockables
; l
!= NULL
; l
= l
->next
) {
816 GschemDockable
*dockable
= GSCHEM_DOCKABLE (l
->data
);
817 gchar
*state
= eda_config_get_string (
818 cfg
, dockable
->group_name
, "state", NULL
);
820 if (state
!= NULL
? strcmp (state
, "detached") == 0 :
821 dockable
->initial_state
== GSCHEM_DOCKABLE_STATE_WINDOW
)
822 gschem_dockable_detach (dockable
, FALSE
);
827 /* open up log window on startup */
828 if (w_current
->log_window
== MAP_ON_STARTUP
)
829 switch (gschem_dockable_get_state (w_current
->log_dockable
)) {
830 case GSCHEM_DOCKABLE_STATE_HIDDEN
:
831 /* For whatever reason, this only works if the action area is
832 * hidden while showing the log window. Otherwise, scrolling
833 * down to the bottom of the log will cause drawing the main
834 * window toolbar icons to break [sic]; but only if the log
835 * window height is about the length of the log or smaller.
837 * I suspect this may somehow be connected to widget size
838 * allocation, but I'm giving up on debugging this now and
839 * just accept that it may flicker a bit. */
841 gschem_dockable_detach (w_current
->log_dockable
, FALSE
);
842 gtk_widget_show (w_current
->log_dockable
->action_area
);
845 case GSCHEM_DOCKABLE_STATE_DIALOG
:
846 case GSCHEM_DOCKABLE_STATE_WINDOW
:
847 gtk_window_present (GTK_WINDOW (w_current
->log_dockable
->window
));
850 case GSCHEM_DOCKABLE_STATE_DOCKED_LEFT
:
851 case GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
:
852 case GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
:
853 present_in_notebook (w_current
->log_dockable
);
856 else if (w_current
->log_dockable
->widget
== NULL
)
857 /* create the widget so the log window can auto-show if necessary */
858 create_widget (w_current
->log_dockable
);
862 /******************************************************************************/
866 create_widget (GschemDockable
*dockable
)
868 g_return_if_fail (dockable
->widget
== NULL
);
871 GSCHEM_DOCKABLE_GET_CLASS (dockable
)->create_widget (dockable
);
872 g_object_ref_sink (dockable
->widget
);
874 /* GtkNotebook doesn't allow storing a pointer along with a widget,
875 * so store the dockable in the user-data property of the widget */
877 GValue value
= G_VALUE_INIT
;
878 g_value_init (&value
, G_TYPE_POINTER
);
879 g_value_set_pointer (&value
, dockable
);
880 g_object_set_property (G_OBJECT (dockable
->widget
), "user-data", &value
);
885 create_window (GschemDockable
*dockable
)
887 g_return_if_fail (dockable
->window
== NULL
);
889 dockable
->window
= g_object_new (GTK_TYPE_WINDOW
,
890 "title", dockable
->title
,
891 "default-width", dockable
->initial_width
,
892 "default-height", dockable
->initial_height
,
895 gtk_window_set_transient_for (GTK_WINDOW (dockable
->window
),
896 GTK_WINDOW (dockable
->w_current
->main_window
));
897 gtk_window_set_type_hint (GTK_WINDOW (dockable
->window
),
898 GDK_WINDOW_TYPE_HINT_DIALOG
);
900 g_signal_connect_after (dockable
->window
,
902 G_CALLBACK (callback_after_window_key_press_event
),
904 g_signal_connect (dockable
->window
,
906 G_CALLBACK (callback_window_delete_event
),
910 /* create containers */
912 dockable
->vbox
= g_object_new (GTK_TYPE_VBOX
,
916 gtk_container_add (GTK_CONTAINER (dockable
->window
), dockable
->vbox
);
917 gtk_widget_show (dockable
->vbox
);
919 dockable
->action_area
= g_object_new (GTK_TYPE_HBUTTON_BOX
,
922 "layout-style", GTK_BUTTONBOX_END
,
924 gtk_box_pack_end (GTK_BOX (dockable
->vbox
),
925 dockable
->action_area
,
927 gtk_widget_show (dockable
->action_area
);
932 if (dockable
->cancellable
) {
933 dockable
->cancel_button
= gtk_button_new_from_stock (GTK_STOCK_CANCEL
);
934 gtk_widget_set_can_default (dockable
->cancel_button
, TRUE
);
935 gtk_widget_show (dockable
->cancel_button
);
936 g_signal_connect (dockable
->cancel_button
, "clicked",
937 G_CALLBACK (callback_cancel_button_clicked
), dockable
);
938 gtk_box_pack_end (GTK_BOX (dockable
->action_area
),
939 dockable
->cancel_button
,
943 dockable
->hide_button
= gtk_button_new_from_stock (
944 dockable
->cancellable
? GTK_STOCK_OK
: GTK_STOCK_CLOSE
);
945 gtk_widget_set_can_default (dockable
->hide_button
, TRUE
);
946 gtk_widget_show (dockable
->hide_button
);
947 g_signal_connect (dockable
->hide_button
, "clicked",
948 G_CALLBACK (callback_hide_button_clicked
), dockable
);
949 gtk_box_pack_end (GTK_BOX (dockable
->action_area
),
950 dockable
->hide_button
,
953 if (dockable
->help_page
!= NULL
) {
954 dockable
->help_button
= gtk_button_new_from_stock (GTK_STOCK_HELP
);
955 gtk_widget_set_can_default (dockable
->help_button
, TRUE
);
956 gtk_widget_show (dockable
->help_button
);
957 g_signal_connect (dockable
->help_button
, "clicked",
958 G_CALLBACK (callback_help_button_clicked
), dockable
);
959 gtk_box_pack_end (GTK_BOX (dockable
->action_area
),
960 dockable
->help_button
,
962 gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (dockable
->action_area
),
963 dockable
->help_button
, TRUE
);
966 GdkScreen
*screen
= gtk_widget_get_screen (dockable
->window
);
967 if (gtk_alternative_dialog_button_order (screen
)) {
968 gtk_box_reorder_child (GTK_BOX (dockable
->action_area
),
969 dockable
->hide_button
, 0);
970 if (dockable
->cancel_button
!= NULL
)
971 gtk_box_reorder_child (GTK_BOX (dockable
->action_area
),
972 dockable
->cancel_button
, 1);
973 if (dockable
->help_button
!= NULL
)
974 gtk_box_reorder_child (GTK_BOX (dockable
->action_area
),
975 dockable
->help_button
, 2);
978 gtk_widget_grab_default (dockable
->hide_button
);
983 create_menu (GschemDockable
*dockable
)
985 g_return_if_fail (dockable
->menu
== NULL
);
987 dockable
->menu
= gtk_menu_new ();
988 g_object_ref_sink (dockable
->menu
);
990 dockable
->detach_item
= gtk_menu_item_new_with_mnemonic (_("_Detach"));
991 g_signal_connect (dockable
->detach_item
, "activate",
992 G_CALLBACK (callback_menu_item_activate
), dockable
);
993 gtk_menu_shell_append (GTK_MENU_SHELL (dockable
->menu
),
994 dockable
->detach_item
);
996 gtk_menu_shell_append (GTK_MENU_SHELL (dockable
->menu
),
997 gtk_separator_menu_item_new ());
999 dockable
->move_left_item
=
1000 gtk_menu_item_new_with_mnemonic (_("Move to _left dock"));
1001 g_signal_connect (dockable
->move_left_item
, "activate",
1002 G_CALLBACK (callback_menu_item_activate
), dockable
);
1003 gtk_menu_shell_append (GTK_MENU_SHELL (dockable
->menu
),
1004 dockable
->move_left_item
);
1006 dockable
->move_bottom_item
=
1007 gtk_menu_item_new_with_mnemonic (_("Move to _bottom dock"));
1008 g_signal_connect (dockable
->move_bottom_item
, "activate",
1009 G_CALLBACK (callback_menu_item_activate
), dockable
);
1010 gtk_menu_shell_append (GTK_MENU_SHELL (dockable
->menu
),
1011 dockable
->move_bottom_item
);
1013 dockable
->move_right_item
=
1014 gtk_menu_item_new_with_mnemonic (_("Move to _right dock"));
1015 g_signal_connect (dockable
->move_right_item
, "activate",
1016 G_CALLBACK (callback_menu_item_activate
), dockable
);
1017 gtk_menu_shell_append (GTK_MENU_SHELL (dockable
->menu
),
1018 dockable
->move_right_item
);
1020 gtk_menu_shell_append (GTK_MENU_SHELL (dockable
->menu
),
1021 gtk_separator_menu_item_new ());
1023 dockable
->close_item
= gtk_image_menu_item_new_from_stock (GTK_STOCK_CLOSE
,
1025 g_signal_connect (dockable
->close_item
, "activate",
1026 G_CALLBACK (callback_menu_item_activate
), dockable
);
1027 gtk_menu_shell_append (GTK_MENU_SHELL (dockable
->menu
),
1028 dockable
->close_item
);
1030 gtk_widget_show_all (dockable
->menu
);
1035 update_menu_items (GschemDockable
*dockable
)
1037 GschemDockableState state
= gschem_dockable_get_state (dockable
);
1039 gtk_check_menu_item_set_active (
1040 GTK_CHECK_MENU_ITEM (dockable
->dock_left_item
),
1041 state
== GSCHEM_DOCKABLE_STATE_DOCKED_LEFT
);
1042 gtk_check_menu_item_set_active (
1043 GTK_CHECK_MENU_ITEM (dockable
->dock_bottom_item
),
1044 state
== GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
);
1045 gtk_check_menu_item_set_active (
1046 GTK_CHECK_MENU_ITEM (dockable
->dock_right_item
),
1047 state
== GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
);
1052 present_in_notebook (GschemDockable
*dockable
)
1057 g_return_if_fail (dockable
->widget
!= NULL
);
1059 parent
= gtk_widget_get_parent (dockable
->widget
);
1060 g_return_if_fail (GTK_IS_NOTEBOOK (parent
));
1062 i
= gtk_notebook_page_num (GTK_NOTEBOOK (parent
), dockable
->widget
);
1063 g_return_if_fail (i
!= -1);
1065 gtk_notebook_set_current_page (GTK_NOTEBOOK (parent
), i
);
1067 x_window_present (dockable
->w_current
);
1068 gtk_widget_grab_focus (dockable
->widget
);
1073 gschem_dockable_hide (GschemDockable
*dockable
)
1075 g_return_if_fail (GSCHEM_IS_DOCKABLE (dockable
));
1077 GtkWidget
*parent
= dockable
->widget
== NULL
? NULL
:
1078 gtk_widget_get_parent (dockable
->widget
);
1080 if (parent
== NULL
||
1081 (dockable
->window
!= NULL
&& parent
== dockable
->vbox
&&
1082 !gtk_widget_get_visible (dockable
->window
)))
1083 /* already hidden, no action required */
1086 if (dockable
->window
!= NULL
&& parent
== dockable
->vbox
) {
1088 save_internal_geometry (dockable
);
1089 save_window_geometry (dockable
);
1090 gtk_widget_hide (dockable
->window
);
1092 /* remove from notebook */
1093 save_internal_geometry (dockable
);
1094 gtk_container_remove (GTK_CONTAINER (parent
), dockable
->widget
);
1097 update_menu_items (dockable
);
1098 save_state (dockable
);
1103 gschem_dockable_detach (GschemDockable
*dockable
, gboolean show_action_area
)
1105 g_return_if_fail (GSCHEM_IS_DOCKABLE (dockable
));
1107 if (dockable
->widget
== NULL
)
1108 create_widget (dockable
);
1110 if (dockable
->window
== NULL
)
1111 create_window (dockable
);
1113 GtkWidget
*parent
= gtk_widget_get_parent (dockable
->widget
);
1115 if (parent
== NULL
) {
1116 /* freshly created or was removed from notebook */
1118 gtk_box_pack_start (GTK_BOX (dockable
->vbox
),
1122 if (show_action_area
)
1123 gtk_widget_show (dockable
->action_area
);
1125 gtk_widget_hide (dockable
->action_area
);
1127 restore_window_geometry (dockable
);
1128 restore_internal_geometry (dockable
);
1130 /* detached docks are only restored after the main window is visible */
1131 g_assert (gtk_widget_get_visible (dockable
->w_current
->main_window
));
1133 gtk_window_present (GTK_WINDOW (dockable
->window
));
1134 save_state (dockable
);
1136 } else if (dockable
->window
!= NULL
&& parent
== dockable
->vbox
&&
1137 !gtk_widget_get_visible (dockable
->window
)) {
1138 /* already in window, but window is currently hidden */
1140 if (show_action_area
)
1141 gtk_widget_show (dockable
->action_area
);
1143 gtk_widget_hide (dockable
->action_area
);
1145 restore_window_geometry (dockable
);
1146 restore_internal_geometry (dockable
);
1148 gtk_window_present (GTK_WINDOW (dockable
->window
));
1149 save_state (dockable
);
1151 } else if (dockable
->window
!= NULL
&& parent
== dockable
->vbox
) {
1152 /* already in window, and window is currently visible
1153 just show/hide action area as appropriate */
1155 if (show_action_area
&& !gtk_widget_get_visible (dockable
->action_area
)) {
1156 gtk_widget_show (dockable
->action_area
);
1157 save_state (dockable
);
1159 if (!show_action_area
&& gtk_widget_get_visible (dockable
->action_area
)) {
1160 gtk_widget_hide (dockable
->action_area
);
1161 save_state (dockable
);
1165 /* currently docked */
1167 g_assert (GTK_IS_NOTEBOOK (parent
));
1168 save_internal_geometry (dockable
);
1169 gtk_container_remove (GTK_CONTAINER (parent
), dockable
->widget
);
1171 gtk_box_pack_start (GTK_BOX (dockable
->vbox
),
1175 if (show_action_area
)
1176 gtk_widget_show (dockable
->action_area
);
1178 gtk_widget_hide (dockable
->action_area
);
1180 restore_window_geometry (dockable
);
1181 restore_internal_geometry (dockable
);
1183 update_menu_items (dockable
);
1185 gtk_window_present (GTK_WINDOW (dockable
->window
));
1186 save_state (dockable
);
1192 gschem_dockable_attach_to_notebook (GschemDockable
*dockable
,
1193 GtkWidget
*notebook
)
1195 g_return_if_fail (GSCHEM_IS_DOCKABLE (dockable
));
1196 g_return_if_fail (notebook
== dockable
->w_current
->left_notebook
||
1197 notebook
== dockable
->w_current
->bottom_notebook
||
1198 notebook
== dockable
->w_current
->right_notebook
);
1199 g_return_if_fail (GTK_IS_NOTEBOOK (notebook
));
1201 if (dockable
->widget
== NULL
)
1202 create_widget (dockable
);
1204 GtkWidget
*parent
= gtk_widget_get_parent (dockable
->widget
);
1206 if (parent
== NULL
) {
1207 /* hidden and not attached to window */
1208 } else if (dockable
->window
!= NULL
&& parent
== dockable
->vbox
) {
1209 /* attached to window (hidden or visible) */
1210 if (gtk_widget_get_visible (dockable
->window
)) {
1211 save_internal_geometry (dockable
);
1212 save_window_geometry (dockable
);
1213 gtk_widget_hide (dockable
->window
);
1215 gtk_container_remove (GTK_CONTAINER (parent
), dockable
->widget
);
1217 if (parent
== notebook
)
1218 /* already in requested notebook, nothing to do */
1221 g_assert (GTK_IS_NOTEBOOK (parent
));
1222 save_internal_geometry (dockable
);
1223 gtk_container_remove (GTK_CONTAINER (parent
), dockable
->widget
);
1226 g_assert (gtk_widget_get_parent (dockable
->widget
) == NULL
);
1228 /* add widget to notebook */
1230 GtkWidget
*event_box
= gtk_event_box_new ();
1231 gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box
), FALSE
);
1232 g_signal_connect (event_box
,
1233 "button-press-event",
1234 G_CALLBACK (callback_event_box_button_press_event
),
1237 GtkWidget
*label
= gtk_label_new (dockable
->title
);
1238 gtk_container_add (GTK_CONTAINER (event_box
), label
);
1239 gtk_widget_show (label
);
1241 gtk_notebook_append_page (GTK_NOTEBOOK (notebook
),
1244 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook
),
1245 dockable
->widget
, TRUE
);
1246 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook
),
1247 dockable
->widget
, TRUE
);
1249 restore_internal_geometry (dockable
);
1250 update_menu_items (dockable
);
1252 /* don't present when restoring state on startup */
1253 if (gtk_widget_get_visible (dockable
->w_current
->main_window
)) {
1254 present_in_notebook (dockable
);
1255 save_state (dockable
);
1261 gschem_dockable_set_state (GschemDockable
*dockable
, GschemDockableState state
)
1263 g_return_if_fail (GSCHEM_IS_DOCKABLE (dockable
));
1266 case GSCHEM_DOCKABLE_STATE_HIDDEN
:
1267 gschem_dockable_hide (dockable
);
1269 case GSCHEM_DOCKABLE_STATE_DIALOG
:
1270 gschem_dockable_detach (dockable
, TRUE
);
1272 case GSCHEM_DOCKABLE_STATE_WINDOW
:
1273 gschem_dockable_detach (dockable
, FALSE
);
1275 case GSCHEM_DOCKABLE_STATE_DOCKED_LEFT
:
1276 gschem_dockable_attach_to_notebook (
1277 dockable
, dockable
->w_current
->left_notebook
);
1279 case GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
:
1280 gschem_dockable_attach_to_notebook (
1281 dockable
, dockable
->w_current
->bottom_notebook
);
1283 case GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
:
1284 gschem_dockable_attach_to_notebook (
1285 dockable
, dockable
->w_current
->right_notebook
);
1288 g_assert_not_reached ();
1294 gschem_dockable_get_state (GschemDockable
*dockable
)
1296 g_return_val_if_fail (GSCHEM_IS_DOCKABLE (dockable
),
1297 GSCHEM_DOCKABLE_STATE_HIDDEN
);
1299 if (dockable
->widget
== NULL
)
1300 return GSCHEM_DOCKABLE_STATE_HIDDEN
;
1302 GtkWidget
*parent
= gtk_widget_get_parent (dockable
->widget
);
1304 return GSCHEM_DOCKABLE_STATE_HIDDEN
;
1306 if (dockable
->window
!= NULL
&& parent
== dockable
->vbox
) {
1307 if (!gtk_widget_get_visible (dockable
->window
))
1308 return GSCHEM_DOCKABLE_STATE_HIDDEN
;
1309 if (!gtk_widget_get_visible (dockable
->action_area
))
1310 return GSCHEM_DOCKABLE_STATE_WINDOW
;
1311 return GSCHEM_DOCKABLE_STATE_DIALOG
;
1314 if (parent
== dockable
->w_current
->left_notebook
)
1315 return GSCHEM_DOCKABLE_STATE_DOCKED_LEFT
;
1316 if (parent
== dockable
->w_current
->bottom_notebook
)
1317 return GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
;
1318 if (parent
== dockable
->w_current
->right_notebook
)
1319 return GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
;
1321 g_assert_not_reached ();
1326 gschem_dockable_present (GschemDockable
*dockable
)
1328 g_return_if_fail (GSCHEM_IS_DOCKABLE (dockable
));
1330 switch (gschem_dockable_get_state (dockable
)) {
1331 case GSCHEM_DOCKABLE_STATE_HIDDEN
:
1332 gschem_dockable_detach (dockable
, TRUE
);
1334 case GSCHEM_DOCKABLE_STATE_DIALOG
:
1335 case GSCHEM_DOCKABLE_STATE_WINDOW
:
1336 gtk_window_present (GTK_WINDOW (dockable
->window
));
1338 case GSCHEM_DOCKABLE_STATE_DOCKED_LEFT
:
1339 case GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
:
1340 case GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
:
1341 present_in_notebook (dockable
);
1344 g_assert_not_reached ();
1347 GSCHEM_DOCKABLE_GET_CLASS (dockable
)->post_present (dockable
);
1351 /******************************************************************************/
1355 connect_notebook_signals (GschemToplevel
*w_current
, GtkWidget
*notebook
)
1358 notebook
, "create-window",
1359 G_CALLBACK (callback_notebook_create_window
), w_current
);
1361 notebook
, "page-added",
1362 G_CALLBACK (callback_notebook_page_added
), w_current
);
1364 notebook
, "page-added",
1365 G_CALLBACK (callback_notebook_page_added_removed_reordered
), w_current
);
1367 notebook
, "page-removed",
1368 G_CALLBACK (callback_notebook_page_added_removed_reordered
), w_current
);
1370 notebook
, "page-reordered",
1371 G_CALLBACK (callback_notebook_page_added_removed_reordered
), w_current
);
1373 notebook
, "switch-page",
1374 G_CALLBACK (callback_notebook_switch_page
), w_current
);
1376 notebook
, "key-press-event",
1377 G_CALLBACK (callback_notebook_key_press_event
), w_current
);
1379 notebook
, "button-press-event",
1380 G_CALLBACK (callback_notebook_button_press_event
), w_current
);
1385 gschem_dockable_initialize_toplevel (GschemToplevel
*w_current
)
1387 /* restore saved page order and last opened page */
1388 restore_page_order (w_current
, GTK_NOTEBOOK (w_current
->left_notebook
));
1389 restore_current_page (w_current
, GTK_NOTEBOOK (w_current
->left_notebook
));
1391 restore_page_order (w_current
, GTK_NOTEBOOK (w_current
->bottom_notebook
));
1392 restore_current_page (w_current
, GTK_NOTEBOOK (w_current
->bottom_notebook
));
1394 restore_page_order (w_current
, GTK_NOTEBOOK (w_current
->right_notebook
));
1395 restore_current_page (w_current
, GTK_NOTEBOOK (w_current
->right_notebook
));
1397 /* connect signals */
1398 connect_notebook_signals (w_current
, w_current
->left_notebook
);
1399 connect_notebook_signals (w_current
, w_current
->bottom_notebook
);
1400 connect_notebook_signals (w_current
, w_current
->right_notebook
);
1403 G_OBJECT (w_current
->main_window
), "focus-in-event",
1404 G_CALLBACK (callback_main_window_focus_in_event
), w_current
);
1406 /* populate docking area menus */
1407 for (GList
*l
= w_current
->dockables
; l
!= NULL
; l
= l
->next
) {
1408 gtk_menu_shell_append (GTK_MENU_SHELL (w_current
->left_docking_area_menu
),
1409 GSCHEM_DOCKABLE (l
->data
)->dock_left_item
);
1410 gtk_menu_shell_append (GTK_MENU_SHELL (w_current
->bottom_docking_area_menu
),
1411 GSCHEM_DOCKABLE (l
->data
)->dock_bottom_item
);
1412 gtk_menu_shell_append (GTK_MENU_SHELL (w_current
->right_docking_area_menu
),
1413 GSCHEM_DOCKABLE (l
->data
)->dock_right_item
);
1419 gschem_dockable_cleanup_toplevel (GschemToplevel
*w_current
)
1421 /* disconnect notebook signals */
1422 g_signal_handlers_disconnect_by_data (w_current
->left_notebook
, w_current
);
1423 g_signal_handlers_disconnect_by_data (w_current
->bottom_notebook
, w_current
);
1424 g_signal_handlers_disconnect_by_data (w_current
->right_notebook
, w_current
);
1426 /* destroy dock windows */
1427 for (GList
*l
= w_current
->dockables
; l
!= NULL
; l
= l
->next
) {
1428 GschemDockable
*dockable
= GSCHEM_DOCKABLE (l
->data
);
1430 /* if the dockable is visible, save geometry */
1431 switch (gschem_dockable_get_state (dockable
)) {
1432 case GSCHEM_DOCKABLE_STATE_HIDDEN
:
1435 case GSCHEM_DOCKABLE_STATE_DIALOG
:
1436 case GSCHEM_DOCKABLE_STATE_WINDOW
:
1437 save_internal_geometry (dockable
);
1438 save_window_geometry (dockable
);
1440 case GSCHEM_DOCKABLE_STATE_DOCKED_LEFT
:
1441 case GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
:
1442 case GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
:
1443 save_internal_geometry (dockable
);
1447 if (dockable
->window
!= NULL
) {
1448 gtk_widget_destroy (dockable
->window
);
1449 dockable
->window
= NULL
;
1452 if (dockable
->widget
!= NULL
) {
1453 gtk_widget_destroy (dockable
->widget
);
1454 dockable
->widget
= NULL
;
1460 /******************************************************************************/
1464 callback_after_window_key_press_event (GtkWidget
*widget
,
1466 GschemDockable
*dockable
)
1468 if ((event
->keyval
== GDK_KEY_Return
||
1469 event
->keyval
== GDK_KEY_ISO_Enter
||
1470 event
->keyval
== GDK_KEY_KP_Enter
) &&
1471 (event
->state
& gtk_accelerator_get_default_mod_mask ()) == 0) {
1472 if (gschem_dockable_get_state (dockable
) == GSCHEM_DOCKABLE_STATE_DIALOG
)
1473 gschem_dockable_hide (dockable
);
1475 gtk_widget_grab_focus (dockable
->w_current
->drawing_area
);
1476 x_window_present (dockable
->w_current
);
1481 if (event
->keyval
== GDK_KEY_Escape
&&
1482 (event
->state
& gtk_accelerator_get_default_mod_mask ()) == 0) {
1483 if (gschem_dockable_get_state (dockable
) == GSCHEM_DOCKABLE_STATE_DIALOG
)
1484 gschem_dockable_hide (dockable
);
1486 gtk_widget_grab_focus (dockable
->w_current
->drawing_area
);
1487 x_window_present (dockable
->w_current
);
1490 if (dockable
->cancellable
)
1491 GSCHEM_DOCKABLE_GET_CLASS (dockable
)->cancel (dockable
);
1500 callback_window_delete_event (GtkWidget
*widget
,
1502 GschemDockable
*dockable
)
1504 GschemDockableState state
= gschem_dockable_get_state (dockable
);
1505 g_return_val_if_fail (state
== GSCHEM_DOCKABLE_STATE_DIALOG
||
1506 state
== GSCHEM_DOCKABLE_STATE_WINDOW
, FALSE
);
1508 gschem_dockable_hide (dockable
);
1510 if (state
== GSCHEM_DOCKABLE_STATE_DIALOG
&& dockable
->cancellable
)
1511 GSCHEM_DOCKABLE_GET_CLASS (dockable
)->cancel (dockable
);
1518 callback_hide_button_clicked (GtkWidget
*button
,
1519 GschemDockable
*dockable
)
1521 gschem_dockable_hide (dockable
);
1526 callback_cancel_button_clicked (GtkWidget
*button
,
1527 GschemDockable
*dockable
)
1529 gschem_dockable_hide (dockable
);
1531 if (dockable
->cancellable
)
1532 GSCHEM_DOCKABLE_GET_CLASS (dockable
)->cancel (dockable
);
1537 callback_help_button_clicked (GtkWidget
*button
,
1538 GschemDockable
*dockable
)
1540 g_return_if_fail (dockable
->help_page
!= NULL
);
1542 scm_dynwind_begin (0);
1543 g_dynwind_window (dockable
->w_current
);
1544 g_scm_eval_protected (scm_list_2 (
1546 scm_c_public_variable ("gschem gschemdoc",
1548 scm_from_utf8_string (dockable
->help_page
)),
1555 callback_dock_item_toggled (GtkWidget
*check_menu_item
,
1556 GschemDockable
*dockable
)
1558 gboolean active
= gtk_check_menu_item_get_active (
1559 GTK_CHECK_MENU_ITEM (check_menu_item
));
1561 GschemDockableState current_state
= gschem_dockable_get_state (dockable
);
1562 GschemDockableState target_state
;
1564 if (check_menu_item
== dockable
->dock_left_item
)
1565 target_state
= GSCHEM_DOCKABLE_STATE_DOCKED_LEFT
;
1566 else if (check_menu_item
== dockable
->dock_bottom_item
)
1567 target_state
= GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
;
1568 else if (check_menu_item
== dockable
->dock_right_item
)
1569 target_state
= GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
;
1571 g_assert_not_reached ();
1573 if (active
&& current_state
!= target_state
)
1574 gschem_dockable_set_state (dockable
, target_state
);
1575 else if (!active
&& current_state
== target_state
)
1576 gschem_dockable_hide (dockable
);
1581 callback_menu_item_activate (GtkWidget
*menu_item
,
1582 GschemDockable
*dockable
)
1584 if (menu_item
== dockable
->detach_item
)
1585 gschem_dockable_set_state (dockable
, GSCHEM_DOCKABLE_STATE_WINDOW
);
1586 else if (menu_item
== dockable
->move_left_item
)
1587 gschem_dockable_set_state (dockable
, GSCHEM_DOCKABLE_STATE_DOCKED_LEFT
);
1588 else if (menu_item
== dockable
->move_bottom_item
)
1589 gschem_dockable_set_state (dockable
, GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
);
1590 else if (menu_item
== dockable
->move_right_item
)
1591 gschem_dockable_set_state (dockable
, GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
);
1592 else if (menu_item
== dockable
->close_item
)
1593 gschem_dockable_set_state (dockable
, GSCHEM_DOCKABLE_STATE_HIDDEN
);
1595 g_assert_not_reached ();
1600 callback_event_box_button_press_event (GtkWidget
*widget
,
1601 GdkEventButton
*event
,
1602 GschemDockable
*dockable
)
1604 if (event
->button
== 2 && event
->type
== GDK_BUTTON_PRESS
) {
1605 gschem_dockable_hide (dockable
);
1609 if (event
->button
== 3 && event
->type
== GDK_BUTTON_PRESS
) {
1610 if (dockable
->menu
== NULL
)
1611 create_menu (dockable
);
1613 GschemDockableState state
= gschem_dockable_get_state (dockable
);
1614 gtk_widget_set_sensitive (dockable
->detach_item
,
1615 state
!= GSCHEM_DOCKABLE_STATE_WINDOW
);
1616 gtk_widget_set_sensitive (dockable
->move_left_item
,
1617 state
!= GSCHEM_DOCKABLE_STATE_DOCKED_LEFT
);
1618 gtk_widget_set_sensitive (dockable
->move_bottom_item
,
1619 state
!= GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
);
1620 gtk_widget_set_sensitive (dockable
->move_right_item
,
1621 state
!= GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
);
1622 gtk_widget_set_sensitive (dockable
->close_item
,
1623 state
!= GSCHEM_DOCKABLE_STATE_HIDDEN
);
1625 gtk_menu_popup (GTK_MENU (dockable
->menu
), NULL
, NULL
, NULL
, NULL
,
1626 event
->button
, event
->time
);
1635 callback_main_window_focus_in_event (GtkWidget
*widget
,
1637 GschemToplevel
*w_current
)
1639 static gboolean initialized
= FALSE
;
1641 for (GList
*l
= w_current
->dockables
; l
!= NULL
; l
= l
->next
) {
1642 GschemDockable
*dockable
= GSCHEM_DOCKABLE (l
->data
);
1643 if (gschem_dockable_get_state (dockable
) == GSCHEM_DOCKABLE_STATE_DIALOG
)
1644 gschem_dockable_set_state (dockable
, GSCHEM_DOCKABLE_STATE_WINDOW
);
1649 restore_detached_dockables (w_current
);
1657 callback_notebook_page_added (GtkWidget
*notebook
,
1660 GschemToplevel
*w_current
)
1662 GschemDockable
*dockable
= get_dockable_by_widget (w_current
, child
);
1663 g_return_if_fail (dockable
!= NULL
);
1665 update_menu_items (dockable
);
1666 save_state (dockable
);
1671 callback_notebook_page_added_removed_reordered (GtkWidget
*notebook
,
1674 GschemToplevel
*w_current
)
1676 save_page_order (w_current
, GTK_NOTEBOOK (notebook
));
1678 /* show or hide notebook as appropriate */
1679 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook
)) == 0)
1680 gtk_widget_hide (notebook
);
1682 gtk_widget_show (notebook
);
1687 callback_notebook_switch_page (GtkWidget
*notebook
,
1690 GschemToplevel
*w_current
)
1692 GschemDockable
*dockable
= get_dockable_by_widget (w_current
, arg1
);
1693 g_return_if_fail (dockable
!= NULL
);
1695 save_current_page (w_current
, GTK_NOTEBOOK (notebook
), dockable
);
1699 static GtkNotebook
*
1700 callback_notebook_create_window (GtkWidget
*notebook
,
1703 GschemToplevel
*w_current
)
1705 GschemDockable
*dockable
= get_dockable_by_widget (w_current
, page
);
1706 g_return_val_if_fail (dockable
!= NULL
, NULL
);
1708 /* This is kind of a hack: Write the desired window position to the
1709 configuration so it is restored when detaching */
1711 EdaConfig
*cfg
= eda_config_get_user_context ();
1713 eda_config_set_int (cfg
, dockable
->group_name
, "x", x
);
1714 eda_config_set_int (cfg
, dockable
->group_name
, "y", y
);
1717 gschem_dockable_detach (dockable
, FALSE
);
1723 callback_notebook_key_press_event (GtkWidget
*notebook
,
1725 GschemToplevel
*w_current
)
1727 gint page_num
= gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook
));
1728 GtkWidget
*widget
= gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook
),
1730 GschemDockable
*dockable
= get_dockable_by_widget (w_current
, widget
);
1731 g_return_val_if_fail (dockable
!= NULL
, FALSE
);
1733 if ((event
->keyval
== GDK_KEY_Return
||
1734 event
->keyval
== GDK_KEY_ISO_Enter
||
1735 event
->keyval
== GDK_KEY_KP_Enter
) &&
1736 (event
->state
& gtk_accelerator_get_default_mod_mask ()) == 0) {
1737 gtk_widget_grab_focus (w_current
->drawing_area
);
1741 if (event
->keyval
== GDK_KEY_Escape
&&
1742 (event
->state
& gtk_accelerator_get_default_mod_mask ()) == 0) {
1743 gtk_widget_grab_focus (w_current
->drawing_area
);
1744 if (GSCHEM_DOCKABLE_GET_CLASS (dockable
)->cancel
!= NULL
)
1745 GSCHEM_DOCKABLE_GET_CLASS (dockable
)->cancel (dockable
);
1754 callback_notebook_button_press_event (GtkWidget
*notebook
,
1755 GdkEventButton
*event
,
1756 GschemToplevel
*w_current
)
1758 if (event
->button
!= 3 || event
->type
!= GDK_BUTTON_PRESS
)
1762 gdk_window_get_user_data (event
->window
, &data
);
1763 if (data
!= notebook
)
1766 GtkWidget
*menu
= notebook
== w_current
->left_notebook
?
1767 w_current
->left_docking_area_menu
:
1768 notebook
== w_current
->bottom_notebook
?
1769 w_current
->bottom_docking_area_menu
:
1770 notebook
== w_current
->right_notebook
?
1771 w_current
->right_docking_area_menu
: NULL
;
1772 g_return_val_if_fail (menu
!= NULL
, FALSE
);
1773 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
,
1774 event
->button
, event
->time
);