Remove extra debug message
[geda-gaf.git] / gschem / src / x_window.c
blob1dd3df3fa2b5eebc9479da4d1d3b77984ddee071
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
20 #include <config.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <sys/stat.h>
26 #include "gdk/gdk.h"
27 #ifdef GDK_WINDOWING_X11
28 #include "gdk/gdkx.h"
29 #endif
31 #include "gschem.h"
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!!!
48 * \brief
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);
68 /* X related stuff */
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),
79 w_current);
82 /*! \todo Finish function documentation!!!
83 * \brief
84 * \par Function Description
87 void x_window_create_drawing(GtkWidget *scrolled, GschemToplevel *w_current)
89 /* drawing next */
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
110 * area.
112 * \param [in] w_current The toplevel environment.
114 void x_window_setup_draw_events(GschemToplevel *w_current)
116 struct event_reg_t {
117 gchar *detailed_signal;
118 GCallback c_handler;
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) },
133 { NULL, NULL } };
134 struct event_reg_t main_window_events[] = {
135 { "enter_notify_event", G_CALLBACK(x_event_enter) },
136 { NULL, NULL } };
137 struct event_reg_t *tmp;
139 /* is the configure event type missing here? hack */
140 gtk_widget_set_events (w_current->drawing_area,
141 GDK_EXPOSURE_MASK |
142 GDK_POINTER_MOTION_MASK |
143 GDK_BUTTON_PRESS_MASK |
144 GDK_ENTER_NOTIFY_MASK |
145 GDK_KEY_PRESS_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,
151 tmp->c_handler,
152 w_current);
155 for (tmp = main_window_events; tmp->detailed_signal != NULL; tmp++) {
156 g_signal_connect (w_current->main_window,
157 tmp->detailed_signal,
158 tmp->c_handler,
159 w_current);
164 static void
165 x_window_find_text (GtkWidget *widget, gint response, GschemToplevel *w_current)
167 gint close = FALSE;
168 int count;
170 g_return_if_fail (w_current != NULL);
171 g_return_if_fail (w_current->toplevel != NULL);
173 switch (response) {
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)));
181 if (count > 0) {
182 gschem_dockable_present (w_current->find_text_dockable);
183 close = TRUE;
185 break;
187 case GTK_RESPONSE_CANCEL:
188 case GTK_RESPONSE_DELETE_EVENT:
189 close = TRUE;
190 break;
192 default:
193 printf("x_window_find_text(): strange signal %d\n", response);
196 if (close) {
197 gtk_widget_grab_focus (w_current->drawing_area);
198 gtk_widget_hide (GTK_WIDGET (widget));
204 static void
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));
221 static void
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));
238 static void
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);
250 scm_dynwind_end ();
253 gtk_widget_grab_focus (w_current->drawing_area);
254 gtk_widget_hide (GTK_WIDGET (widget));
257 static void
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);
263 OBJECT *page_obj;
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);
274 static gboolean
275 x_window_state_event (GtkWidget *widget,
276 GdkEventWindowState *event,
277 gpointer user_data)
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 */
290 static void
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;
299 if (menu == NULL)
300 /* not a submenu */
301 continue;
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 */
306 continue;
308 gint coords[4];
309 gsize length = 0;
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]);
317 length = 4;
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);
328 static void
329 x_window_save_geometry (GschemToplevel *w_current)
331 gchar *window_state;
332 GtkAllocation allocation;
334 /* save window geometry */
335 window_state = eda_config_get_string (eda_config_get_user_context (),
336 "gschem.window-geometry",
337 "state", NULL);
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);
374 static void
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;
383 if (menu == NULL)
384 /* not a submenu */
385 continue;
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 */
390 continue;
392 gsize length = 0;
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]);
406 g_free(coords);
408 x_window_restore_menu_geometry (GTK_MENU_SHELL (menu), w_current);
412 static gboolean
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);
423 return FALSE;
426 static void
427 x_window_restore_geometry (GschemToplevel *w_current)
429 gint width, height, dock_size;
430 gchar *window_state;
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) {
438 width = 1200;
439 height = 900;
441 g_object_set (w_current->main_window,
442 "default-width", width,
443 "default-height", height,
444 NULL);
446 /* restore main window state */
447 window_state = eda_config_get_string (eda_config_get_user_context (),
448 "gschem.window-geometry",
449 "state", NULL);
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);
463 if (dock_size <= 0)
464 dock_size = 300;
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);
469 if (dock_size <= 0)
470 dock_size = 150;
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);
475 if (dock_size <= 0)
476 dock_size = 300;
477 gtk_widget_set_size_request (w_current->right_notebook, dock_size, 0);
481 /*! \todo Finish function documentation!!!
482 * \brief
483 * \par Function Description
485 * \note
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
489 * signal to the app
491 static gboolean
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 */
503 /* do */
504 return TRUE;
508 void
509 x_window_update_file_change_notification (GschemToplevel *w_current,
510 PAGE *page)
512 if (page->is_untitled) {
513 g_object_set (w_current->file_change_notification,
514 "gschem-page", page,
515 "path", NULL,
516 NULL);
517 return;
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"),
524 basename,
525 page->CHANGED
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"),
530 basename,
531 page->CHANGED
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,
535 "gschem-page", page,
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
542 : GTK_STOCK_OPEN,
543 "button-label", page->CHANGED
544 ? _("_Revert")
545 : page->exists_on_disk ? _("_Reload")
546 : _("_Open"),
547 "markup", markup,
548 NULL);
549 g_free (markup);
550 g_free (basename);
553 static void
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);
559 else {
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);
567 void
568 x_window_update_patch_change_notification (GschemToplevel *w_current,
569 PAGE *page)
571 gchar *patch_filename = x_patch_guess_filename (page);
572 gchar *basename, *markup;
574 if (patch_filename == NULL) {
575 basename = NULL;
576 markup = NULL;
577 } else {
578 struct stat buf;
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?"),
584 basename);
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?"),
589 basename);
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?"),
594 basename);
595 else
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?"),
599 basename);
602 g_object_set (w_current->patch_change_notification,
603 "gschem-page", page,
604 "path", patch_filename,
605 "has-known-mtime", page->patch_seen_on_disk,
606 "known-mtime", &page->patch_mtime,
607 "button-label", _("_Import"),
608 "markup", markup,
609 NULL);
610 g_free (markup);
611 g_free (basename);
612 g_free (patch_filename);
615 static void
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);
623 } else {
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!!!
632 * \brief
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;
643 GtkWidget *scrolled;
644 GtkAdjustment *hadjustment;
645 GtkAdjustment *vadjustment;
646 char *right_button_text;
647 GtkWidget *left_hpaned, *right_hpaned;
648 GtkWidget *vpaned;
649 GtkWidget *work_box;
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,
658 * see below
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);
685 } else {
686 gtk_box_pack_start (GTK_BOX (main_box), w_current->menubar,
687 FALSE, FALSE, 0);
690 gschem_action_set_sensitive (action_view_menubar, w_current->menubar != NULL,
691 w_current);
692 gschem_action_set_active (action_view_menubar, w_current->menubar != NULL,
693 w_current);
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);
705 } else {
706 gtk_box_pack_start (GTK_BOX (main_box), w_current->toolbar,
707 FALSE, FALSE, 0);
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,
713 w_current);
714 gschem_action_set_active (action_view_toolbar,
715 w_current->toolbars && w_current->toolbar != NULL,
716 w_current);
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,
724 FALSE,
725 TRUE);
726 gtk_notebook_set_group_name (GTK_NOTEBOOK (w_current->left_notebook),
727 "gschem-dock");
729 right_hpaned = gtk_hpaned_new ();
730 gtk_paned_pack2 (GTK_PANED (left_hpaned),
731 right_hpaned,
732 TRUE,
733 TRUE);
735 w_current->right_notebook = gtk_notebook_new ();
736 gtk_paned_pack2 (GTK_PANED (right_hpaned),
737 w_current->right_notebook,
738 FALSE,
739 TRUE);
740 gtk_notebook_set_group_name (GTK_NOTEBOOK (w_current->right_notebook),
741 "gschem-dock");
743 vpaned = gtk_vpaned_new ();
744 gtk_paned_pack1 (GTK_PANED (right_hpaned),
745 vpaned,
746 TRUE,
747 TRUE);
749 w_current->bottom_notebook = gtk_notebook_new ();
750 gtk_paned_pack2 (GTK_PANED (vpaned),
751 w_current->bottom_notebook,
752 FALSE,
753 TRUE);
754 gtk_notebook_set_group_name (GTK_NOTEBOOK (w_current->bottom_notebook),
755 "gschem-dock");
757 work_box = gtk_vbox_new (FALSE, 0);
758 gtk_paned_pack1 (GTK_PANED (vpaned),
759 work_box,
760 TRUE,
761 TRUE);
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,
767 NULL);
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,
772 FALSE, FALSE, 0);
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,
778 NULL);
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,
783 FALSE, FALSE, 0);
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,
791 toplevel->init_left,
792 toplevel->init_right,
793 100.0,
794 100.0,
795 10.0));
797 vadjustment = GTK_ADJUSTMENT (gtk_adjustment_new (toplevel->init_bottom,
798 0.0,
799 toplevel->init_bottom - toplevel->init_top,
800 100.0,
801 100.0,
802 10.0));
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,
812 w_current);
814 /* find text box */
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,
819 FALSE,
820 FALSE,
823 g_signal_connect (w_current->find_text_widget,
824 "response",
825 G_CALLBACK (&x_window_find_text),
826 w_current);
828 /* hide text box */
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:"),
832 NULL));
834 gtk_box_pack_start (GTK_BOX (work_box),
835 w_current->hide_text_widget,
836 FALSE,
837 FALSE,
840 g_signal_connect (w_current->hide_text_widget,
841 "response",
842 G_CALLBACK (&x_window_hide_text),
843 w_current);
845 /* show text box */
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:"),
849 NULL));
851 gtk_box_pack_start (GTK_BOX (work_box),
852 w_current->show_text_widget,
853 FALSE,
854 FALSE,
857 g_signal_connect (w_current->show_text_widget,
858 "response",
859 G_CALLBACK (&x_window_show_text),
860 w_current);
862 /* macro box */
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,
867 FALSE,
868 FALSE,
871 g_signal_connect (w_current->macro_widget,
872 "response",
873 G_CALLBACK (&x_window_invoke_macro),
874 w_current);
877 w_current->compselect_dockable = g_object_new (
878 GSCHEM_TYPE_COMPSELECT_DOCKABLE,
879 "title", _("Library"),
880 "settings-name", "compselect",
881 "cancellable", TRUE,
882 "initial-state", GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT,
883 "initial-width", 500,
884 "initial-height", 600,
885 "gschem-toplevel", w_current,
886 NULL);
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,
896 NULL);
898 w_current->text_properties_dockable = g_object_new (
899 GSCHEM_TYPE_TEXT_PROPERTIES_DOCKABLE,
900 "title", _("Text"),
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,
906 NULL);
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,
916 NULL);
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,
926 NULL);
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,
936 NULL);
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,
946 NULL);
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,
956 NULL);
957 g_signal_connect (w_current->find_text_dockable,
958 "select-object",
959 G_CALLBACK (&x_window_select_text),
960 w_current);
962 w_current->patch_dockable = g_object_new (
963 GSCHEM_TYPE_PATCH_DOCKABLE,
964 "title", _("Patch"),
965 "settings-name", "patch",
966 "initial-state", GSCHEM_DOCKABLE_STATE_HIDDEN,
967 "initial-width", 500,
968 "initial-height", 300,
969 "gschem-toplevel", w_current,
970 NULL);
972 w_current->pagesel_dockable = g_object_new (
973 GSCHEM_TYPE_PAGESEL_DOCKABLE,
974 "title", _("Pages"),
975 "settings-name", "pagesel",
976 "initial-state", GSCHEM_DOCKABLE_STATE_HIDDEN,
977 "initial-width", 515,
978 "initial-height", 180,
979 "gschem-toplevel", w_current,
980 NULL);
982 gschem_dockable_initialize_toplevel (w_current);
985 /* bottom box */
986 if (default_third_button == POPUP_ENABLED) {
987 right_button_text = _("Menu/Cancel");
988 } else {
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"),
1001 NULL));
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!!!
1023 * \brief
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 */
1040 return;
1043 x_clipboard_finish (w_current);
1045 #if DEBUG
1046 o_conn_print_hash(w_current->page_current->conn_table);
1047 #endif
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 */
1089 last_window = TRUE;
1092 /* stuff that has to be done before we free w_current */
1093 if (last_window) {
1094 /* close the log file */
1095 s_log_close ();
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 */
1114 if (last_window) {
1115 gschem_quit();
1119 /*! \todo Finish function documentation!!!
1120 * \brief
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.
1151 void
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);
1156 GList *iter;
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)
1166 /* nothing to do */
1167 return;
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),
1178 w_current);
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,
1188 w_current);
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,
1194 w_current);
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);
1228 #else
1229 guint32 timestamp = gtk_get_current_event_time ();
1230 #endif
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.
1251 void
1252 x_window_init_icons (void)
1254 gchar *icon_path;
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 (),
1260 icon_path);
1261 g_free (icon_path);
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);
1295 return w_current;