gschem
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * gschem - gEDA Schematic Capture 00003 * Copyright (C) 1998-2010 Ales Hvezda 00004 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details) 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 #include <config.h> 00022 #include <glib.h> 00023 00024 #include <glib-object.h> 00025 #include <glib/gstdio.h> 00026 00027 #include "gschem.h" 00028 #include <gdk/gdkkeysyms.h> 00029 00030 #ifdef HAVE_LIBDMALLOC 00031 #include <dmalloc.h> 00032 #endif 00033 00034 00035 #include "../include/gschem_dialog.h" 00036 00037 /* Signal marshaller based on generated code from glib-genmarshal */ 00038 static void 00039 gschem_marshal_VOID__POINTER_STRING (GClosure *closure, 00040 GValue *return_value, 00041 guint n_param_values, 00042 const GValue *param_values, 00043 gpointer invocation_hint, 00044 gpointer marshal_data) 00045 { 00046 typedef void (*GMarshalFunc_VOID__POINTER_STRING) (gpointer data1, 00047 gpointer arg_1, 00048 gpointer arg_2, 00049 gpointer data2); 00050 register GMarshalFunc_VOID__POINTER_STRING callback; 00051 register GCClosure *cc = (GCClosure*) closure; 00052 register gpointer data1, data2; 00053 00054 g_return_if_fail (n_param_values == 3); 00055 00056 if (G_CCLOSURE_SWAP_DATA (closure)) { 00057 data1 = closure->data; 00058 data2 = g_value_peek_pointer (param_values + 0); 00059 } else { 00060 data1 = g_value_peek_pointer (param_values + 0); 00061 data2 = closure->data; 00062 } 00063 callback = (GMarshalFunc_VOID__POINTER_STRING) (marshal_data ? marshal_data : cc->callback); 00064 00065 callback (data1, 00066 g_value_get_pointer (param_values + 1), 00067 (gchar*)g_value_get_string (param_values + 2), 00068 data2); 00069 } 00070 /* End section based on generated code from glib-genmashal */ 00071 00072 00073 enum { 00074 PROP_SETTINGS_NAME = 1, 00075 PROP_GSCHEM_TOPLEVEL 00076 }; 00077 00078 00079 enum { 00080 GEOMETRY_SAVE, 00081 GEOMETRY_RESTORE, 00082 LAST_SIGNAL 00083 }; 00084 00085 static guint gschem_dialog_signals[ LAST_SIGNAL ] = { 0 }; 00086 static GObjectClass *gschem_dialog_parent_class = NULL; 00087 00088 static GKeyFile *dialog_geometry = NULL; 00089 00090 #define DIALOG_GEOMETRY_STORE "gschem-dialog-geometry" 00091 00092 00100 static void save_geometry_to_file(gpointer user_data) 00101 { 00102 gchar *data, *file; 00103 00104 g_assert( dialog_geometry != NULL ); 00105 00106 data = g_key_file_to_data(dialog_geometry, NULL, NULL); 00107 file = g_build_filename(s_path_user_config (), DIALOG_GEOMETRY_STORE, 00108 NULL); 00109 g_file_set_contents(file, data, -1, NULL); 00110 g_free(data); 00111 g_free(file); 00112 } 00113 00114 00124 static void geometry_save (GschemDialog *dialog, GKeyFile *key_file, gchar* group_name) 00125 { 00126 gint x, y, width, height; 00127 00128 gtk_window_get_position (GTK_WINDOW (dialog), &x, &y); 00129 gtk_window_get_size (GTK_WINDOW (dialog), &width, &height); 00130 00131 g_key_file_set_integer (key_file, group_name, "x", x); 00132 g_key_file_set_integer (key_file, group_name, "y", y); 00133 g_key_file_set_integer (key_file, group_name, "width", width ); 00134 g_key_file_set_integer (key_file, group_name, "height", height); 00135 } 00136 00137 00147 static void geometry_restore (GschemDialog *dialog, GKeyFile *key_file, gchar* group_name) 00148 { 00149 gint x, y, width, height; 00150 00151 x = g_key_file_get_integer (key_file, group_name, "x", NULL); 00152 y = g_key_file_get_integer (key_file, group_name, "y", NULL); 00153 width = g_key_file_get_integer (key_file, group_name, "width", NULL); 00154 height = g_key_file_get_integer (key_file, group_name, "height", NULL); 00155 00156 gtk_window_move (GTK_WINDOW (dialog), x, y); 00157 gtk_window_resize (GTK_WINDOW (dialog), width, height); 00158 } 00159 00160 00168 static void setup_keyfile () 00169 { 00170 if (dialog_geometry != NULL) 00171 return; 00172 00173 gchar *file = g_build_filename (s_path_user_config (), 00174 DIALOG_GEOMETRY_STORE, NULL); 00175 00176 dialog_geometry = g_key_file_new(); 00177 00178 /* Remember to save data on program exit */ 00179 gschem_atexit(save_geometry_to_file, NULL); 00180 00181 if (!g_file_test (file, G_FILE_TEST_EXISTS)) { 00182 g_mkdir (s_path_user_config (), S_IRWXU | S_IRWXG); 00183 00184 g_file_set_contents (file, "", -1, NULL); 00185 } 00186 00187 if (!g_key_file_load_from_file (dialog_geometry, file, G_KEY_FILE_NONE, NULL)) { 00188 /* error opening key file, create an empty one and try again */ 00189 g_file_set_contents (file, "", -1, NULL); 00190 if ( !g_key_file_load_from_file (dialog_geometry, file, G_KEY_FILE_NONE, NULL)) { 00191 g_free (file); 00192 return; 00193 } 00194 } 00195 g_free (file); 00196 } 00197 00198 00207 static void show_handler (GtkWidget *widget) 00208 { 00209 gchar *group_name; 00210 GschemDialog *dialog = GSCHEM_DIALOG( widget ); 00211 00212 group_name = dialog->settings_name; 00213 if (group_name != NULL) { 00214 00215 setup_keyfile (); 00216 g_assert( dialog_geometry != NULL ); 00217 if (g_key_file_has_group (dialog_geometry, group_name)) { 00218 g_signal_emit (dialog, gschem_dialog_signals[ GEOMETRY_RESTORE ], 0, 00219 dialog_geometry, group_name); 00220 } 00221 } 00222 00223 /* Let GTK show the window */ 00224 GTK_WIDGET_CLASS (gschem_dialog_parent_class)->show (widget); 00225 } 00226 00227 00238 static void unmap_handler (GtkWidget *widget) 00239 { 00240 gchar *group_name; 00241 GschemDialog *dialog = GSCHEM_DIALOG (widget); 00242 00243 group_name = dialog->settings_name; 00244 if (group_name != NULL) { 00245 00246 g_assert( dialog_geometry != NULL ); 00247 g_signal_emit (dialog, gschem_dialog_signals[ GEOMETRY_SAVE ], 0, 00248 dialog_geometry, group_name); 00249 } 00250 00251 /* Let GTK unmap the window */ 00252 GTK_WIDGET_CLASS (gschem_dialog_parent_class)->unmap (widget); 00253 } 00254 00255 00264 static void gschem_dialog_finalize (GObject *object) 00265 { 00266 GschemDialog *dialog = GSCHEM_DIALOG (object); 00267 00268 g_free (dialog->settings_name); 00269 00270 G_OBJECT_CLASS (gschem_dialog_parent_class)->finalize (object); 00271 } 00272 00273 00286 static void gschem_dialog_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) 00287 { 00288 GschemDialog *dialog = GSCHEM_DIALOG (object); 00289 00290 switch(property_id) { 00291 case PROP_SETTINGS_NAME: 00292 g_free (dialog->settings_name); 00293 dialog->settings_name = g_strdup (g_value_get_string (value)); 00294 break; 00295 case PROP_GSCHEM_TOPLEVEL: 00296 dialog->w_current = (GSCHEM_TOPLEVEL*)g_value_get_pointer (value); 00297 break; 00298 default: 00299 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 00300 } 00301 00302 } 00303 00304 00317 static void gschem_dialog_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) 00318 { 00319 GschemDialog *dialog = GSCHEM_DIALOG (object); 00320 00321 switch(property_id) { 00322 case PROP_SETTINGS_NAME: 00323 g_value_set_string (value, dialog->settings_name); 00324 break; 00325 case PROP_GSCHEM_TOPLEVEL: 00326 g_value_set_pointer (value, (gpointer)dialog->w_current); 00327 break; 00328 default: 00329 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 00330 } 00331 00332 } 00333 00334 00343 static void gschem_dialog_class_init (GschemDialogClass *klass) 00344 { 00345 GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 00346 GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass); 00347 00348 klass->geometry_save = geometry_save; 00349 klass->geometry_restore = geometry_restore; 00350 00351 gtkwidget_class->show = show_handler; 00352 gtkwidget_class->unmap = unmap_handler; 00353 00354 gobject_class->finalize = gschem_dialog_finalize; 00355 gobject_class->set_property = gschem_dialog_set_property; 00356 gobject_class->get_property = gschem_dialog_get_property; 00357 00358 gschem_dialog_parent_class = g_type_class_peek_parent (klass); 00359 00360 gschem_dialog_signals[ GEOMETRY_SAVE ] = 00361 g_signal_new ("geometry-save", 00362 G_OBJECT_CLASS_TYPE( gobject_class ), 00363 G_SIGNAL_RUN_FIRST, /*signal_flags */ 00364 G_STRUCT_OFFSET( GschemDialogClass, geometry_save ), 00365 NULL, /* accumulator */ 00366 NULL, /* accu_data */ 00367 gschem_marshal_VOID__POINTER_STRING, 00368 G_TYPE_NONE, 00369 2, /* n_params */ 00370 G_TYPE_POINTER, 00371 G_TYPE_STRING 00372 ); 00373 00374 gschem_dialog_signals[ GEOMETRY_RESTORE ] = 00375 g_signal_new ("geometry-restore", 00376 G_OBJECT_CLASS_TYPE( gobject_class ), 00377 G_SIGNAL_RUN_FIRST, /*signal_flags */ 00378 G_STRUCT_OFFSET( GschemDialogClass, geometry_restore ), 00379 NULL, /* accumulator */ 00380 NULL, /* accu_data */ 00381 gschem_marshal_VOID__POINTER_STRING, 00382 G_TYPE_NONE, 00383 2, /* n_params */ 00384 G_TYPE_POINTER, 00385 G_TYPE_STRING 00386 ); 00387 00388 g_object_class_install_property ( 00389 gobject_class, PROP_SETTINGS_NAME, 00390 g_param_spec_string ("settings-name", 00391 "", 00392 "", 00393 NULL, 00394 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); 00395 g_object_class_install_property ( 00396 gobject_class, PROP_GSCHEM_TOPLEVEL, 00397 g_param_spec_pointer ("gschem-toplevel", 00398 "", 00399 "", 00400 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); 00401 } 00402 00403 00413 GType gschem_dialog_get_type () 00414 { 00415 static GType gschem_dialog_type = 0; 00416 00417 if (!gschem_dialog_type) { 00418 static const GTypeInfo gschem_dialog_info = { 00419 sizeof(GschemDialogClass), 00420 NULL, /* base_init */ 00421 NULL, /* base_finalize */ 00422 (GClassInitFunc) gschem_dialog_class_init, 00423 NULL, /* class_finalize */ 00424 NULL, /* class_data */ 00425 sizeof(GschemDialog), 00426 0, /* n_preallocs */ 00427 NULL, /* instance_init */ 00428 }; 00429 00430 gschem_dialog_type = g_type_register_static (GTK_TYPE_DIALOG, 00431 "GschemDialog", 00432 &gschem_dialog_info, 0); 00433 } 00434 00435 return gschem_dialog_type; 00436 } 00437 00438 00449 static void gschem_dialog_add_buttons_valist (GtkDialog *dialog, 00450 const gchar *first_button_text, 00451 va_list args) 00452 { 00453 const gchar* text; 00454 gint response_id; 00455 00456 g_return_if_fail (GTK_IS_DIALOG (dialog)); 00457 00458 if (first_button_text == NULL) 00459 return; 00460 00461 text = first_button_text; 00462 response_id = va_arg (args, gint); 00463 00464 while (text != NULL) 00465 { 00466 gtk_dialog_add_button (dialog, text, response_id); 00467 00468 text = va_arg (args, gchar*); 00469 if (text == NULL) 00470 break; 00471 response_id = va_arg (args, int); 00472 } 00473 } 00474 00475 00490 static GtkWidget* gschem_dialog_new_empty (const gchar *title, 00491 GtkWindow *parent, 00492 GtkDialogFlags flags, 00493 const gchar *settings_name, 00494 GSCHEM_TOPLEVEL *w_current) 00495 { 00496 GschemDialog *dialog; 00497 00498 dialog = g_object_new (GSCHEM_TYPE_DIALOG, 00499 "settings-name", settings_name, 00500 "gschem-toplevel", w_current, 00501 NULL); 00502 00503 if (title) 00504 gtk_window_set_title (GTK_WINDOW (dialog), title); 00505 00506 if (parent) 00507 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); 00508 00509 if (flags & GTK_DIALOG_MODAL) 00510 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); 00511 00512 if (flags & GTK_DIALOG_DESTROY_WITH_PARENT) 00513 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); 00514 00515 if (flags & GTK_DIALOG_NO_SEPARATOR) 00516 gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); 00517 00518 return GTK_WIDGET (dialog); 00519 } 00520 00521 00539 GtkWidget* gschem_dialog_new_with_buttons (const gchar *title, GtkWindow *parent, GtkDialogFlags flags, 00540 const gchar *settings_name, GSCHEM_TOPLEVEL *w_current, 00541 const gchar *first_button_text, ...) 00542 { 00543 GschemDialog *dialog; 00544 va_list args; 00545 00546 dialog = GSCHEM_DIALOG (gschem_dialog_new_empty (title, parent, flags, settings_name, w_current)); 00547 00548 va_start (args, first_button_text); 00549 00550 gschem_dialog_add_buttons_valist (GTK_DIALOG (dialog), 00551 first_button_text, 00552 args); 00553 00554 va_end (args); 00555 00556 return GTK_WIDGET (dialog); 00557 } 00558