Updated copyright text/header in most source files.
[geda-gaf/peter-b.git] / gschem / src / gschem_dialog.c
blob2a6ece6d353c02f8e00c1ea10f99fb5b276f6464
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 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(s_path_user_config (), 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 (s_path_user_config (),
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 g_mkdir (s_path_user_config (), S_IRWXU | S_IRWXG);
184 g_file_set_contents (file, "", -1, NULL);
187 if (!g_key_file_load_from_file (dialog_geometry, file, G_KEY_FILE_NONE, NULL)) {
188 /* error opening key file, create an empty one and try again */
189 g_file_set_contents (file, "", -1, NULL);
190 if ( !g_key_file_load_from_file (dialog_geometry, file, G_KEY_FILE_NONE, NULL)) {
191 g_free (file);
192 return;
195 g_free (file);
199 /*! \brief GtkWidget show signal handler
201 * \par Function Description
202 * Just before the dialog widget is shown, call the hook
203 * to restore its previously saved position and size.
205 * \param [in] widget The GtkWidget being shown.
207 static void show_handler (GtkWidget *widget)
209 gchar *group_name;
210 GschemDialog *dialog = GSCHEM_DIALOG( widget );
212 group_name = dialog->settings_name;
213 if (group_name != NULL) {
215 setup_keyfile ();
216 g_assert( dialog_geometry != NULL );
217 if (g_key_file_has_group (dialog_geometry, group_name)) {
218 g_signal_emit (dialog, gschem_dialog_signals[ GEOMETRY_RESTORE ], 0,
219 dialog_geometry, group_name);
223 /* Let GTK show the window */
224 GTK_WIDGET_CLASS (gschem_dialog_parent_class)->show (widget);
228 /*! \brief GtkWidget unmap signal handler
230 * \par Function Description
231 * Just before the dialog widget is unmapped, call the hook
232 * to save its current position and size.
234 * This typically happens when you call gtk_widget_destroy().
236 * \param [in] widget The GtkWidget being unmapped.
238 static void unmap_handler (GtkWidget *widget)
240 gchar *group_name;
241 GschemDialog *dialog = GSCHEM_DIALOG (widget);
243 group_name = dialog->settings_name;
244 if (group_name != NULL) {
246 g_assert( dialog_geometry != NULL );
247 g_signal_emit (dialog, gschem_dialog_signals[ GEOMETRY_SAVE ], 0,
248 dialog_geometry, group_name);
251 /* Let GTK unmap the window */
252 GTK_WIDGET_CLASS (gschem_dialog_parent_class)->unmap (widget);
256 /*! \brief GObject finalise handler
258 * \par Function Description
259 * Just before the GschemDialog GObject is finalized, free our
260 * allocated data, and then chain up to the parent's finalize handler.
262 * \param [in] object The GObject being finalized.
264 static void gschem_dialog_finalize (GObject *object)
266 GschemDialog *dialog = GSCHEM_DIALOG (object);
268 g_free (dialog->settings_name);
270 G_OBJECT_CLASS (gschem_dialog_parent_class)->finalize (object);
274 /*! \brief GObject property setter function
276 * \par Function Description
277 * Setter function for GschemDialog's GObject properties,
278 * "settings-name" and "toplevel".
280 * \param [in] object The GObject whose properties we are setting
281 * \param [in] property_id The numeric id. under which the property was
282 * registered with g_object_class_install_property()
283 * \param [in] value The GValue the property is being set from
284 * \param [in] pspec A GParamSpec describing the property being set
286 static void gschem_dialog_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
288 GschemDialog *dialog = GSCHEM_DIALOG (object);
290 switch(property_id) {
291 case PROP_SETTINGS_NAME:
292 g_free (dialog->settings_name);
293 dialog->settings_name = g_strdup (g_value_get_string (value));
294 break;
295 case PROP_GSCHEM_TOPLEVEL:
296 dialog->w_current = (GSCHEM_TOPLEVEL*)g_value_get_pointer (value);
297 break;
298 default:
299 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
305 /*! \brief GObject property getter function
307 * \par Function Description
308 * Getter function for GschemDialog's GObject properties,
309 * "settings-name" and "toplevel".
311 * \param [in] object The GObject whose properties we are getting
312 * \param [in] property_id The numeric id. under which the property was
313 * registered with g_object_class_install_property()
314 * \param [out] value The GValue in which to return the value of the property
315 * \param [in] pspec A GParamSpec describing the property being got
317 static void gschem_dialog_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
319 GschemDialog *dialog = GSCHEM_DIALOG (object);
321 switch(property_id) {
322 case PROP_SETTINGS_NAME:
323 g_value_set_string (value, dialog->settings_name);
324 break;
325 case PROP_GSCHEM_TOPLEVEL:
326 g_value_set_pointer (value, (gpointer)dialog->w_current);
327 break;
328 default:
329 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
335 /*! \brief GType class initialiser for GschemDialog
337 * \par Function Description
338 * GType class initialiser for GschemDialog. We override our parent
339 * virtual class methods as needed and register our GObject properties.
341 * \param [in] klass The GschemDialogClass we are initialising
343 static void gschem_dialog_class_init (GschemDialogClass *klass)
345 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
346 GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
348 klass->geometry_save = geometry_save;
349 klass->geometry_restore = geometry_restore;
351 gtkwidget_class->show = show_handler;
352 gtkwidget_class->unmap = unmap_handler;
354 gobject_class->finalize = gschem_dialog_finalize;
355 gobject_class->set_property = gschem_dialog_set_property;
356 gobject_class->get_property = gschem_dialog_get_property;
358 gschem_dialog_parent_class = g_type_class_peek_parent (klass);
360 gschem_dialog_signals[ GEOMETRY_SAVE ] =
361 g_signal_new ("geometry-save",
362 G_OBJECT_CLASS_TYPE( gobject_class ),
363 G_SIGNAL_RUN_FIRST, /*signal_flags */
364 G_STRUCT_OFFSET( GschemDialogClass, geometry_save ),
365 NULL, /* accumulator */
366 NULL, /* accu_data */
367 gschem_marshal_VOID__POINTER_STRING,
368 G_TYPE_NONE,
369 2, /* n_params */
370 G_TYPE_POINTER,
371 G_TYPE_STRING
374 gschem_dialog_signals[ GEOMETRY_RESTORE ] =
375 g_signal_new ("geometry-restore",
376 G_OBJECT_CLASS_TYPE( gobject_class ),
377 G_SIGNAL_RUN_FIRST, /*signal_flags */
378 G_STRUCT_OFFSET( GschemDialogClass, geometry_restore ),
379 NULL, /* accumulator */
380 NULL, /* accu_data */
381 gschem_marshal_VOID__POINTER_STRING,
382 G_TYPE_NONE,
383 2, /* n_params */
384 G_TYPE_POINTER,
385 G_TYPE_STRING
388 g_object_class_install_property (
389 gobject_class, PROP_SETTINGS_NAME,
390 g_param_spec_string ("settings-name",
393 NULL,
394 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
395 g_object_class_install_property (
396 gobject_class, PROP_GSCHEM_TOPLEVEL,
397 g_param_spec_pointer ("gschem-toplevel",
400 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
404 /*! \brief Function to retrieve GschemDialog's GType identifier.
406 * \par Function Description
407 * Function to retrieve GschemDialog's GType identifier.
408 * Upon first call, this registers the GschemDialog in the GType system.
409 * Subsequently it returns the saved value from its first execution.
411 * \return the GType identifier associated with GschemDialog.
413 GType gschem_dialog_get_type ()
415 static GType gschem_dialog_type = 0;
417 if (!gschem_dialog_type) {
418 static const GTypeInfo gschem_dialog_info = {
419 sizeof(GschemDialogClass),
420 NULL, /* base_init */
421 NULL, /* base_finalize */
422 (GClassInitFunc) gschem_dialog_class_init,
423 NULL, /* class_finalize */
424 NULL, /* class_data */
425 sizeof(GschemDialog),
426 0, /* n_preallocs */
427 NULL, /* instance_init */
430 gschem_dialog_type = g_type_register_static (GTK_TYPE_DIALOG,
431 "GschemDialog",
432 &gschem_dialog_info, 0);
435 return gschem_dialog_type;
439 /*! \brief Internal GTK function modified from GTK+-2.4.14 gtkdialog.c
440 * to support gschem_dialog_new_with_buttons(...)
442 * \par Function Description
443 * Convenience function which adds buttons to a pre-existing GtkDialog
445 * \param [in] dialog The GtkDialog buttons are being added to
446 * \param [in] first_button_text The text string for the first button
447 * \param [in] args The va_list containging the remaining button strings
449 static void gschem_dialog_add_buttons_valist (GtkDialog *dialog,
450 const gchar *first_button_text,
451 va_list args)
453 const gchar* text;
454 gint response_id;
456 g_return_if_fail (GTK_IS_DIALOG (dialog));
458 if (first_button_text == NULL)
459 return;
461 text = first_button_text;
462 response_id = va_arg (args, gint);
464 while (text != NULL)
466 gtk_dialog_add_button (dialog, text, response_id);
468 text = va_arg (args, gchar*);
469 if (text == NULL)
470 break;
471 response_id = va_arg (args, int);
476 /*! \brief Internal GTK function modified from GTK+-2.4.14 gtkdialog.c
477 * to support gschem_dialog_new_with_buttons(...)
479 * \par Function Description
480 * Convenience function which creates a blank GschemDialog with various options.
482 * \param [in] title The title text of the dialog
483 * \param [in] parent The GtkWindow which will parent this dialog
484 * \param [in] flags The GtkDialogFlags to use when setting up the dialog
485 * \param [in] settings_name The name gschem should use to store this dialog's settings
486 * \param [in] w_current The GSCHEM_TOPLEVEL object this dialog is associated with
488 * \return The GschemDialog created.
490 static GtkWidget* gschem_dialog_new_empty (const gchar *title,
491 GtkWindow *parent,
492 GtkDialogFlags flags,
493 const gchar *settings_name,
494 GSCHEM_TOPLEVEL *w_current)
496 GschemDialog *dialog;
498 dialog = g_object_new (GSCHEM_TYPE_DIALOG,
499 "settings-name", settings_name,
500 "gschem-toplevel", w_current,
501 NULL);
503 if (title)
504 gtk_window_set_title (GTK_WINDOW (dialog), title);
506 if (parent)
507 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
509 if (flags & GTK_DIALOG_MODAL)
510 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
512 if (flags & GTK_DIALOG_DESTROY_WITH_PARENT)
513 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
515 if (flags & GTK_DIALOG_NO_SEPARATOR)
516 gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
518 return GTK_WIDGET (dialog);
522 /*! \brief GTK function modified from GTK+-2.4.14 gtkdialog.c
523 * to provide a GschemDialog equivelant of the convenience function
524 * gtk_dialog_new_with_buttons(...)
526 * \par Function Description
527 * Convenience function which creates a GschemDialog with buttons and options.
529 * \param [in] title The title text of the dialog
530 * \param [in] parent The GtkWindow which will parent this dialog
531 * \param [in] flags The GtkDialogFlags to use when setting up the dialog
532 * \param [in] settings_name The name gschem should use to store this dialog's settings
533 * \param [in] w_current The GSCHEM_TOPLEVEL object this dialog is associated with
534 * \param [in] first_button_text The text string for the first button
535 * \param [in] ... A variable number of arguments with the remaining button strings
537 * \return The GschemDialog created.
539 GtkWidget* gschem_dialog_new_with_buttons (const gchar *title, GtkWindow *parent, GtkDialogFlags flags,
540 const gchar *settings_name, GSCHEM_TOPLEVEL *w_current,
541 const gchar *first_button_text, ...)
543 GschemDialog *dialog;
544 va_list args;
546 dialog = GSCHEM_DIALOG (gschem_dialog_new_empty (title, parent, flags, settings_name, w_current));
548 va_start (args, first_button_text);
550 gschem_dialog_add_buttons_valist (GTK_DIALOG (dialog),
551 first_button_text,
552 args);
554 va_end (args);
556 return GTK_WIDGET (dialog);