Take page as input and take advantage of s_visit_page.
[geda-gaf/berndj.git] / gschem / src / gschem_dialog.c
blob73a54b202ef72a32eb48d0a2beb966ebd977dfa9
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2007 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., 59 Temple Place, Suite 330, Boston, MA 02111 USA
21 #include <config.h>
22 #include <glib.h>
24 #include <glib-object.h>
25 #include <glib/gstdio.h>
27 #include "gschem.h"
28 #include <gdk/gdkkeysyms.h>
30 #ifdef HAVE_LIBDMALLOC
31 #include <dmalloc.h>
32 #endif
35 #include "../include/gschem_dialog.h"
37 /* Signal marshaller based on generated code from glib-genmarshal */
38 static void
39 gschem_marshal_VOID__POINTER_STRING (GClosure *closure,
40 GValue *return_value,
41 guint n_param_values,
42 const GValue *param_values,
43 gpointer invocation_hint,
44 gpointer marshal_data)
46 typedef void (*GMarshalFunc_VOID__POINTER_STRING) (gpointer data1,
47 gpointer arg_1,
48 gpointer arg_2,
49 gpointer data2);
50 register GMarshalFunc_VOID__POINTER_STRING callback;
51 register GCClosure *cc = (GCClosure*) closure;
52 register gpointer data1, data2;
54 g_return_if_fail (n_param_values == 3);
56 if (G_CCLOSURE_SWAP_DATA (closure)) {
57 data1 = closure->data;
58 data2 = g_value_peek_pointer (param_values + 0);
59 } else {
60 data1 = g_value_peek_pointer (param_values + 0);
61 data2 = closure->data;
63 callback = (GMarshalFunc_VOID__POINTER_STRING) (marshal_data ? marshal_data : cc->callback);
65 callback (data1,
66 g_value_get_pointer (param_values + 1),
67 (gchar*)g_value_get_string (param_values + 2),
68 data2);
70 /* End section based on generated code from glib-genmashal */
73 enum {
74 PROP_SETTINGS_NAME = 1,
75 PROP_GSCHEM_TOPLEVEL
79 enum {
80 GEOMETRY_SAVE,
81 GEOMETRY_RESTORE,
82 LAST_SIGNAL
85 static guint gschem_dialog_signals[ LAST_SIGNAL ] = { 0 };
86 static GObjectClass *gschem_dialog_parent_class = NULL;
88 static GKeyFile *dialog_geometry = NULL;
90 #define DIALOG_GEOMETRY_STORE "gschem-dialog-geometry"
93 /*! \brief Save all geometry data into a file.
95 * \par Function Description
96 * This is called at program exit to save all window geometry data into a file
98 * \param [in] user_data unused
100 static void save_geometry_to_file(gpointer user_data)
102 gchar *data, *file;
104 g_assert( dialog_geometry != NULL );
106 data = g_key_file_to_data(dialog_geometry, NULL, NULL);
107 file = g_build_filename(g_get_home_dir (), ".gEDA", DIALOG_GEOMETRY_STORE,
108 NULL);
109 g_file_set_contents(file, data, -1, NULL);
110 g_free(data);
111 g_free(file);
115 /*! \brief GschemDialog "geometry_save" class method handler
117 * \par Function Description
118 * Save the dialog's current position and size to the passed GKeyFile
120 * \param [in] dialog The GschemDialog to save the position and size of.
121 * \param [in] key_file The GKeyFile to save the geometry data to.
122 * \param [in] group_name The group name in the key file to store the data under.
124 static void geometry_save (GschemDialog *dialog, GKeyFile *key_file, gchar* group_name)
126 gint x, y, width, height;
128 gtk_window_get_position (GTK_WINDOW (dialog), &x, &y);
129 gtk_window_get_size (GTK_WINDOW (dialog), &width, &height);
131 g_key_file_set_integer (key_file, group_name, "x", x);
132 g_key_file_set_integer (key_file, group_name, "y", y);
133 g_key_file_set_integer (key_file, group_name, "width", width );
134 g_key_file_set_integer (key_file, group_name, "height", height);
138 /*! \brief GschemDialog "geometry_restore" class method handler
140 * \par Function Description
141 * Restore dialog's last position and size from the passed GKeyFile
143 * \param [in] dialog The GschemDialog to restore the position and size of.
144 * \param [in] key_file The GKeyFile to load the geometry data from.
145 * \param [in] group_name The group name in the key file to find the data under.
147 static void geometry_restore (GschemDialog *dialog, GKeyFile *key_file, gchar* group_name)
149 gint x, y, width, height;
151 x = g_key_file_get_integer (key_file, group_name, "x", NULL);
152 y = g_key_file_get_integer (key_file, group_name, "y", NULL);
153 width = g_key_file_get_integer (key_file, group_name, "width", NULL);
154 height = g_key_file_get_integer (key_file, group_name, "height", NULL);
156 gtk_window_move (GTK_WINDOW (dialog), x, y);
157 gtk_window_resize (GTK_WINDOW (dialog), width, height);
161 /*! \brief Setup the GKeyFile for saving / restoring geometry
163 * \par Function Description
164 * Check if the GKeyFile for saving / restoring geometry is open.
165 * If it doesn't exist, we create it here, and also install a hook
166 * to ensure its contents are saved at program exit.
168 static void setup_keyfile ()
170 if (dialog_geometry != NULL)
171 return;
173 gchar *file = g_build_filename (g_get_home_dir (), ".gEDA",
174 DIALOG_GEOMETRY_STORE, NULL);
176 dialog_geometry = g_key_file_new();
178 /* Remember to save data on program exit */
179 gschem_atexit(save_geometry_to_file, NULL);
181 if (!g_file_test (file, G_FILE_TEST_EXISTS)) {
182 gchar *dir = g_build_filename (g_get_home_dir (), ".gEDA", NULL);
183 g_mkdir (dir, S_IRWXU | S_IRWXG);
184 g_free (dir);
186 g_file_set_contents (file, "", -1, NULL);
189 if (!g_key_file_load_from_file (dialog_geometry, file, G_KEY_FILE_NONE, NULL)) {
190 /* error opening key file, create an empty one and try again */
191 g_file_set_contents (file, "", -1, NULL);
192 if ( !g_key_file_load_from_file (dialog_geometry, file, G_KEY_FILE_NONE, NULL)) {
193 g_free (file);
194 return;
197 g_free (file);
201 /*! \brief GtkWidget show signal handler
203 * \par Function Description
204 * Just before the dialog widget is shown, call the hook
205 * to restore its previously saved position and size.
207 * \param [in] widget The GtkWidget being shown.
209 static void show_handler (GtkWidget *widget)
211 gchar *group_name;
212 GschemDialog *dialog = GSCHEM_DIALOG( widget );
214 group_name = dialog->settings_name;
215 if (group_name != NULL) {
217 setup_keyfile ();
218 g_assert( dialog_geometry != NULL );
219 if (g_key_file_has_group (dialog_geometry, group_name)) {
220 g_signal_emit (dialog, gschem_dialog_signals[ GEOMETRY_RESTORE ], 0,
221 dialog_geometry, group_name);
225 /* Let GTK show the window */
226 GTK_WIDGET_CLASS (gschem_dialog_parent_class)->show (widget);
230 /*! \brief GtkWidget unmap signal handler
232 * \par Function Description
233 * Just before the dialog widget is unmapped, call the hook
234 * to save its current position and size.
236 * This typically happens when you call gtk_widget_destroy().
238 * \param [in] widget The GtkWidget being unmapped.
240 static void unmap_handler (GtkWidget *widget)
242 gchar *group_name;
243 GschemDialog *dialog = GSCHEM_DIALOG (widget);
245 group_name = dialog->settings_name;
246 if (group_name != NULL) {
248 g_assert( dialog_geometry != NULL );
249 g_signal_emit (dialog, gschem_dialog_signals[ GEOMETRY_SAVE ], 0,
250 dialog_geometry, group_name);
253 /* Let GTK unmap the window */
254 GTK_WIDGET_CLASS (gschem_dialog_parent_class)->unmap (widget);
258 /*! \brief GObject finalise handler
260 * \par Function Description
261 * Just before the GschemDialog GObject is finalized, free our
262 * allocated data, and then chain up to the parent's finalize handler.
264 * \param [in] widget The GObject being finalized.
266 static void gschem_dialog_finalize (GObject *object)
268 GschemDialog *dialog = GSCHEM_DIALOG (object);
270 g_free (dialog->settings_name);
272 G_OBJECT_CLASS (gschem_dialog_parent_class)->finalize (object);
276 /*! \brief GObject property setter function
278 * \par Function Description
279 * Setter function for GschemDialog's GObject properties,
280 * "settings-name" and "toplevel".
282 * \param [in] object The GObject whose properties we are setting
283 * \param [in] property_id The numeric id. under which the property was
284 * registered with g_object_class_install_property()
285 * \param [in] value The GValue the property is being set from
286 * \param [in] pspec A GParamSpec describing the property being set
288 static void gschem_dialog_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
290 GschemDialog *dialog = GSCHEM_DIALOG (object);
292 switch(property_id) {
293 case PROP_SETTINGS_NAME:
294 g_free (dialog->settings_name);
295 dialog->settings_name = g_strdup (g_value_get_string (value));
296 break;
297 case PROP_GSCHEM_TOPLEVEL:
298 dialog->w_current = (GSCHEM_TOPLEVEL*)g_value_get_pointer (value);
299 break;
300 default:
301 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
307 /*! \brief GObject property getter function
309 * \par Function Description
310 * Getter function for GschemDialog's GObject properties,
311 * "settings-name" and "toplevel".
313 * \param [in] object The GObject whose properties we are getting
314 * \param [in] property_id The numeric id. under which the property was
315 * registered with g_object_class_install_property()
316 * \param [out] value The GValue in which to return the value of the property
317 * \param [in] pspec A GParamSpec describing the property being got
319 static void gschem_dialog_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
321 GschemDialog *dialog = GSCHEM_DIALOG (object);
323 switch(property_id) {
324 case PROP_SETTINGS_NAME:
325 g_value_set_string (value, dialog->settings_name);
326 break;
327 case PROP_GSCHEM_TOPLEVEL:
328 g_value_set_pointer (value, (gpointer)dialog->w_current);
329 break;
330 default:
331 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
337 /*! \brief GType class initialiser for GschemDialog
339 * \par Function Description
340 * GType class initialiser for GschemDialog. We override our parent
341 * virtual class methods as needed and register our GObject properties.
343 * \param [in] klass The GschemDialogClass we are initialising
345 static void gschem_dialog_class_init (GschemDialogClass *klass)
347 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
348 GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
350 klass->geometry_save = geometry_save;
351 klass->geometry_restore = geometry_restore;
353 gtkwidget_class->show = show_handler;
354 gtkwidget_class->unmap = unmap_handler;
356 gobject_class->finalize = gschem_dialog_finalize;
357 gobject_class->set_property = gschem_dialog_set_property;
358 gobject_class->get_property = gschem_dialog_get_property;
360 gschem_dialog_parent_class = g_type_class_peek_parent (klass);
362 gschem_dialog_signals[ GEOMETRY_SAVE ] =
363 g_signal_new ("geometry-save",
364 G_OBJECT_CLASS_TYPE( gobject_class ),
365 G_SIGNAL_RUN_FIRST, /*signal_flags */
366 G_STRUCT_OFFSET( GschemDialogClass, geometry_save ),
367 NULL, /* accumulator */
368 NULL, /* accu_data */
369 gschem_marshal_VOID__POINTER_STRING,
370 G_TYPE_NONE,
371 2, /* n_params */
372 G_TYPE_POINTER,
373 G_TYPE_STRING
376 gschem_dialog_signals[ GEOMETRY_RESTORE ] =
377 g_signal_new ("geometry-restore",
378 G_OBJECT_CLASS_TYPE( gobject_class ),
379 G_SIGNAL_RUN_FIRST, /*signal_flags */
380 G_STRUCT_OFFSET( GschemDialogClass, geometry_restore ),
381 NULL, /* accumulator */
382 NULL, /* accu_data */
383 gschem_marshal_VOID__POINTER_STRING,
384 G_TYPE_NONE,
385 2, /* n_params */
386 G_TYPE_POINTER,
387 G_TYPE_STRING
390 g_object_class_install_property (
391 gobject_class, PROP_SETTINGS_NAME,
392 g_param_spec_string ("settings-name",
395 NULL,
396 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
397 g_object_class_install_property (
398 gobject_class, PROP_GSCHEM_TOPLEVEL,
399 g_param_spec_pointer ("gschem-toplevel",
402 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
406 /*! \brief Function to retrieve GschemDialog's GType identifier.
408 * \par Function Description
409 * Function to retrieve GschemDialog's GType identifier.
410 * Upon first call, this registers the GschemDialog in the GType system.
411 * Subsequently it returns the saved value from its first execution.
413 * \return the GType identifier associated with GschemDialog.
415 GType gschem_dialog_get_type ()
417 static GType gschem_dialog_type = 0;
419 if (!gschem_dialog_type) {
420 static const GTypeInfo gschem_dialog_info = {
421 sizeof(GschemDialogClass),
422 NULL, /* base_init */
423 NULL, /* base_finalize */
424 (GClassInitFunc) gschem_dialog_class_init,
425 NULL, /* class_finalize */
426 NULL, /* class_data */
427 sizeof(GschemDialog),
428 0, /* n_preallocs */
429 NULL, /* instance_init */
432 gschem_dialog_type = g_type_register_static (GTK_TYPE_DIALOG,
433 "GschemDialog",
434 &gschem_dialog_info, 0);
437 return gschem_dialog_type;
441 /*! \brief Internal GTK function modified from GTK+-2.4.14 gtkdialog.c
442 * to support gschem_dialog_new_with_buttons(...)
444 * \par Function Description
445 * Convenience function which adds buttons to a pre-existing GtkDialog
447 * \param [in] dialog The GtkDialog buttons are being added to
448 * \param [in] first_button_text The text string for the first button
449 * \param [in] args The va_list containging the remaining button strings
451 static void gschem_dialog_add_buttons_valist (GtkDialog *dialog,
452 const gchar *first_button_text,
453 va_list args)
455 const gchar* text;
456 gint response_id;
458 g_return_if_fail (GTK_IS_DIALOG (dialog));
460 if (first_button_text == NULL)
461 return;
463 text = first_button_text;
464 response_id = va_arg (args, gint);
466 while (text != NULL)
468 gtk_dialog_add_button (dialog, text, response_id);
470 text = va_arg (args, gchar*);
471 if (text == NULL)
472 break;
473 response_id = va_arg (args, int);
478 /*! \brief Internal GTK function modified from GTK+-2.4.14 gtkdialog.c
479 * to support gschem_dialog_new_with_buttons(...)
481 * \par Function Description
482 * Convenience function which creates a blank GschemDialog with various options.
484 * \param [in] title The title text of the dialog
485 * \param [in] parent The GtkWindow which will parent this dialog
486 * \param [in] flags The GtkDialogFlags to use when setting up the dialog
487 * \param [in] settings_name The name gschem should use to store this dialog's settings
488 * \param [in] w_current The GSCHEM_TOPLEVEL object this dialog is associated with
490 * \return The GschemDialog created.
492 static GtkWidget* gschem_dialog_new_empty (const gchar *title,
493 GtkWindow *parent,
494 GtkDialogFlags flags,
495 const gchar *settings_name,
496 GSCHEM_TOPLEVEL *w_current)
498 GschemDialog *dialog;
500 dialog = g_object_new (GSCHEM_TYPE_DIALOG,
501 "settings-name", settings_name,
502 "gschem-toplevel", w_current,
503 NULL);
505 if (title)
506 gtk_window_set_title (GTK_WINDOW (dialog), title);
508 if (parent)
509 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
511 if (flags & GTK_DIALOG_MODAL)
512 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
514 if (flags & GTK_DIALOG_DESTROY_WITH_PARENT)
515 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
517 if (flags & GTK_DIALOG_NO_SEPARATOR)
518 gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
520 return GTK_WIDGET (dialog);
524 /*! \brief GTK function modified from GTK+-2.4.14 gtkdialog.c
525 * to provide a GschemDialog equivelant of the convenience function
526 * gtk_dialog_new_with_buttons(...)
528 * \par Function Description
529 * Convenience function which creates a GschemDialog with buttons and options.
531 * \param [in] title The title text of the dialog
532 * \param [in] parent The GtkWindow which will parent this dialog
533 * \param [in] flags The GtkDialogFlags to use when setting up the dialog
534 * \param [in] settings_name The name gschem should use to store this dialog's settings
535 * \param [in] w_current The GSCHEM_TOPLEVEL object this dialog is associated with
536 * \param [in] first_button_text The text string for the first button
537 * \param [in] ... A variable number of arguments with the remaining button strings
539 * \return The GschemDialog created.
541 GtkWidget* gschem_dialog_new_with_buttons (const gchar *title, GtkWindow *parent, GtkDialogFlags flags,
542 const gchar *settings_name, GSCHEM_TOPLEVEL *w_current,
543 const gchar *first_button_text, ...)
545 GschemDialog *dialog;
546 va_list args;
548 dialog = GSCHEM_DIALOG (gschem_dialog_new_empty (title, parent, flags, settings_name, w_current));
550 va_start (args, first_button_text);
552 gschem_dialog_add_buttons_valist (GTK_DIALOG (dialog),
553 first_button_text,
554 args);
556 va_end (args);
558 return GTK_WIDGET (dialog);