added gimp_config_diff() which returns the difference beween two
2002-11-25 Michael Natterer <mitch@gimp.org> * app/config/gimpconfig-utils.[ch]: added gimp_config_diff() which returns the difference beween two GimpConfig objects as a GList of GParamSpecs. * app/config/gimpconfig-params.c (gimp_param_color_cmp): compare the colors as integers to get rid of rounding foobar. * app/config/gimpconfig-serialize.c: use gimp_config_diff(). * app/display/gimpdisplayshell-handlers.c: only need to call gimp_display_shell_scale_setup() on resolution change if the display is not in dot-for-dot mode. * app/display/gimpdisplayshell.c: changed a separator in the padding color menu. * app/gui/dialogs.c: made the prefs dialog a singleton again. * app/gui/preferences-dialog.c: Should be fully functional again: Apply GIMP_PARAM_CONFIRM properties on "OK". Save gimprc on "OK". Parse a temporaty GimpRc on dialog creation to get the current GIMP_PARAM_RESTART values. Use gimp_config_diff() for all config comparisons.
This commit is contained in:

committed by
Michael Natterer

parent
91f2f3b10d
commit
1229d8c84c
26
ChangeLog
26
ChangeLog
@ -1,3 +1,29 @@
|
|||||||
|
2002-11-25 Michael Natterer <mitch@gimp.org>
|
||||||
|
|
||||||
|
* app/config/gimpconfig-utils.[ch]: added gimp_config_diff()
|
||||||
|
which returns the difference beween two GimpConfig objects
|
||||||
|
as a GList of GParamSpecs.
|
||||||
|
|
||||||
|
* app/config/gimpconfig-params.c (gimp_param_color_cmp): compare
|
||||||
|
the colors as integers to get rid of rounding foobar.
|
||||||
|
|
||||||
|
* app/config/gimpconfig-serialize.c: use gimp_config_diff().
|
||||||
|
|
||||||
|
* app/display/gimpdisplayshell-handlers.c: only need to call
|
||||||
|
gimp_display_shell_scale_setup() on resolution change if the
|
||||||
|
display is not in dot-for-dot mode.
|
||||||
|
|
||||||
|
* app/display/gimpdisplayshell.c: changed a separator in the
|
||||||
|
padding color menu.
|
||||||
|
|
||||||
|
* app/gui/dialogs.c: made the prefs dialog a singleton again.
|
||||||
|
|
||||||
|
* app/gui/preferences-dialog.c: Should be fully functional again:
|
||||||
|
Apply GIMP_PARAM_CONFIRM properties on "OK". Save gimprc on "OK".
|
||||||
|
Parse a temporaty GimpRc on dialog creation to get the current
|
||||||
|
GIMP_PARAM_RESTART values. Use gimp_config_diff() for all config
|
||||||
|
comparisons.
|
||||||
|
|
||||||
2002-11-25 Manish Singh <yosh@gimp.org>
|
2002-11-25 Manish Singh <yosh@gimp.org>
|
||||||
|
|
||||||
* libgimpbase/gimpwire.c: using a union like that may not be
|
* libgimpbase/gimpwire.c: using a union like that may not be
|
||||||
|
@ -147,13 +147,20 @@ gimp_param_color_values_cmp (GParamSpec *pspec,
|
|||||||
return color1 != NULL;
|
return color1 != NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gdouble intensity1 = gimp_rgb_intensity (color1);
|
guint32 int1, int2;
|
||||||
gdouble intensity2 = gimp_rgb_intensity (color2);
|
|
||||||
|
|
||||||
if (intensity1 < intensity2)
|
gimp_rgba_get_uchar (color1,
|
||||||
return -1;
|
((guchar *) &int1) + 0,
|
||||||
else
|
((guchar *) &int1) + 1,
|
||||||
return intensity1 > intensity2;
|
((guchar *) &int1) + 2,
|
||||||
|
((guchar *) &int1) + 3);
|
||||||
|
gimp_rgba_get_uchar (color2,
|
||||||
|
((guchar *) &int2) + 0,
|
||||||
|
((guchar *) &int2) + 1,
|
||||||
|
((guchar *) &int2) + 2,
|
||||||
|
((guchar *) &int2) + 3);
|
||||||
|
|
||||||
|
return int1 - int2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,12 +139,11 @@ gimp_config_serialize_changed_properties (GObject *new,
|
|||||||
gint fd,
|
gint fd,
|
||||||
gint indent_level)
|
gint indent_level)
|
||||||
{
|
{
|
||||||
GObjectClass *klass;
|
GObjectClass *klass;
|
||||||
GParamSpec **property_specs;
|
GList *diff;
|
||||||
guint n_property_specs;
|
GList *list;
|
||||||
guint i;
|
GString *str;
|
||||||
GString *str;
|
gboolean property_written = FALSE;
|
||||||
gboolean property_written = FALSE;
|
|
||||||
|
|
||||||
g_return_val_if_fail (G_IS_OBJECT (new), FALSE);
|
g_return_val_if_fail (G_IS_OBJECT (new), FALSE);
|
||||||
g_return_val_if_fail (G_IS_OBJECT (old), FALSE);
|
g_return_val_if_fail (G_IS_OBJECT (old), FALSE);
|
||||||
@ -153,64 +152,54 @@ gimp_config_serialize_changed_properties (GObject *new,
|
|||||||
|
|
||||||
klass = G_OBJECT_GET_CLASS (new);
|
klass = G_OBJECT_GET_CLASS (new);
|
||||||
|
|
||||||
property_specs = g_object_class_list_properties (klass, &n_property_specs);
|
diff = gimp_config_diff (new, old, GIMP_PARAM_SERIALIZE);
|
||||||
|
|
||||||
if (!property_specs)
|
if (! diff)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
str = g_string_new (NULL);
|
str = g_string_new (NULL);
|
||||||
|
|
||||||
for (i = 0; i < n_property_specs; i++)
|
for (list = diff; list; list = g_list_next (list))
|
||||||
{
|
{
|
||||||
GParamSpec *prop_spec;
|
GParamSpec *prop_spec;
|
||||||
GValue new_value = { 0, };
|
GValue new_value = { 0, };
|
||||||
GValue old_value = { 0, };
|
|
||||||
|
|
||||||
prop_spec = property_specs[i];
|
prop_spec = (GParamSpec *) list->data;
|
||||||
|
|
||||||
if (! (prop_spec->flags & GIMP_PARAM_SERIALIZE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
g_value_init (&new_value, prop_spec->value_type);
|
g_value_init (&new_value, prop_spec->value_type);
|
||||||
g_value_init (&old_value, prop_spec->value_type);
|
|
||||||
|
|
||||||
g_object_get_property (new, prop_spec->name, &new_value);
|
g_object_get_property (new, prop_spec->name, &new_value);
|
||||||
g_object_get_property (old, prop_spec->name, &old_value);
|
|
||||||
|
|
||||||
if (g_param_values_cmp (prop_spec, &new_value, &old_value) != 0)
|
if (property_written)
|
||||||
{
|
g_string_assign (str, "\n");
|
||||||
if (property_written)
|
else
|
||||||
g_string_assign (str, "\n");
|
g_string_assign (str, "");
|
||||||
else
|
|
||||||
g_string_assign (str, "");
|
|
||||||
|
|
||||||
gimp_config_string_indent (str, indent_level);
|
gimp_config_string_indent (str, indent_level);
|
||||||
|
|
||||||
g_string_append_printf (str, "(%s ", prop_spec->name);
|
g_string_append_printf (str, "(%s ", prop_spec->name);
|
||||||
|
|
||||||
if (gimp_config_serialize_value (&new_value, str, TRUE))
|
if (gimp_config_serialize_value (&new_value, str, TRUE))
|
||||||
{
|
{
|
||||||
g_string_append (str, ")\n");
|
g_string_append (str, ")\n");
|
||||||
property_written = TRUE;
|
property_written = TRUE;
|
||||||
|
|
||||||
if (write (fd, str->str, str->len) == -1)
|
if (write (fd, str->str, str->len) == -1)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
else if (prop_spec->value_type != G_TYPE_STRING)
|
else if (prop_spec->value_type != G_TYPE_STRING)
|
||||||
{
|
{
|
||||||
g_warning ("couldn't serialize property %s::%s of type %s",
|
g_warning ("couldn't serialize property %s::%s of type %s",
|
||||||
g_type_name (G_TYPE_FROM_INSTANCE (new)),
|
g_type_name (G_TYPE_FROM_INSTANCE (new)),
|
||||||
prop_spec->name,
|
prop_spec->name,
|
||||||
g_type_name (prop_spec->value_type));
|
g_type_name (prop_spec->value_type));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_value_unset (&new_value);
|
g_value_unset (&new_value);
|
||||||
g_value_unset (&old_value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (property_specs);
|
|
||||||
g_string_free (str, TRUE);
|
g_string_free (str, TRUE);
|
||||||
|
g_list_free (diff);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,50 @@
|
|||||||
#include "gimpconfig-utils.h"
|
#include "gimpconfig-utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
GList *
|
||||||
|
gimp_config_diff (GObject *a,
|
||||||
|
GObject *b,
|
||||||
|
GParamFlags flags)
|
||||||
|
{
|
||||||
|
GParamSpec **param_specs;
|
||||||
|
guint n_param_specs;
|
||||||
|
gint i;
|
||||||
|
GList *list = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (G_IS_OBJECT (a), FALSE);
|
||||||
|
g_return_val_if_fail (G_IS_OBJECT (b), FALSE);
|
||||||
|
g_return_val_if_fail (G_TYPE_FROM_INSTANCE (a) == G_TYPE_FROM_INSTANCE (b),
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
param_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a),
|
||||||
|
&n_param_specs);
|
||||||
|
|
||||||
|
for (i = 0; i < n_param_specs; i++)
|
||||||
|
{
|
||||||
|
if (! flags || ((param_specs[i]->flags & flags) == flags))
|
||||||
|
{
|
||||||
|
GValue a_value = { 0, };
|
||||||
|
GValue b_value = { 0, };
|
||||||
|
|
||||||
|
g_value_init (&a_value, param_specs[i]->value_type);
|
||||||
|
g_value_init (&b_value, param_specs[i]->value_type);
|
||||||
|
|
||||||
|
g_object_get_property (a, param_specs[i]->name, &a_value);
|
||||||
|
g_object_get_property (b, param_specs[i]->name, &b_value);
|
||||||
|
|
||||||
|
if (g_param_values_cmp (param_specs[i], &a_value, &b_value))
|
||||||
|
list = g_list_prepend (list, param_specs[i]);
|
||||||
|
|
||||||
|
g_value_unset (&a_value);
|
||||||
|
g_value_unset (&b_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (param_specs);
|
||||||
|
|
||||||
|
return g_list_reverse (list);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gimp_config_copy_properties (GObject *src,
|
gimp_config_copy_properties (GObject *src,
|
||||||
GObject *dest)
|
GObject *dest)
|
||||||
@ -64,7 +108,11 @@ gimp_config_copy_properties (GObject *src,
|
|||||||
|
|
||||||
g_object_get_property (src, prop_spec->name, &value);
|
g_object_get_property (src, prop_spec->name, &value);
|
||||||
g_object_set_property (dest, prop_spec->name, &value);
|
g_object_set_property (dest, prop_spec->name, &value);
|
||||||
|
|
||||||
|
g_value_unset (&value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free (property_specs);
|
||||||
}
|
}
|
||||||
|
|
||||||
gchar *
|
gchar *
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
#define __GIMP_CONFIG_UTILS_H__
|
#define __GIMP_CONFIG_UTILS_H__
|
||||||
|
|
||||||
|
|
||||||
|
GList * gimp_config_diff (GObject *a,
|
||||||
|
GObject *b,
|
||||||
|
GParamFlags flags);
|
||||||
void gimp_config_copy_properties (GObject *src,
|
void gimp_config_copy_properties (GObject *src,
|
||||||
GObject *dest);
|
GObject *dest);
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ GimpDialogFactory *global_toolbox_factory = NULL;
|
|||||||
static const GimpDialogFactoryEntry toplevel_entries[] =
|
static const GimpDialogFactoryEntry toplevel_entries[] =
|
||||||
{
|
{
|
||||||
{ "gimp-device-status-dialog", dialogs_device_status_get, 32, TRUE, TRUE, FALSE, TRUE },
|
{ "gimp-device-status-dialog", dialogs_device_status_get, 32, TRUE, TRUE, FALSE, TRUE },
|
||||||
{ "gimp-preferences-dialog", dialogs_preferences_get, 32, FALSE, FALSE, FALSE, TRUE },
|
{ "gimp-preferences-dialog", dialogs_preferences_get, 32, TRUE, FALSE, FALSE, TRUE },
|
||||||
{ "gimp-module-browser-dialog", dialogs_module_browser_get, 32, TRUE, FALSE, FALSE, TRUE },
|
{ "gimp-module-browser-dialog", dialogs_module_browser_get, 32, TRUE, FALSE, FALSE, TRUE },
|
||||||
{ "gimp-undo-history-dialog", dialogs_undo_history_get, 32, FALSE, FALSE, FALSE, TRUE },
|
{ "gimp-undo-history-dialog", dialogs_undo_history_get, 32, FALSE, FALSE, FALSE, TRUE },
|
||||||
{ "gimp-display-filters-dialog", dialogs_display_filters_get, 32, FALSE, FALSE, FALSE, TRUE },
|
{ "gimp-display-filters-dialog", dialogs_display_filters_get, 32, FALSE, FALSE, FALSE, TRUE },
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "config/gimpconfig.h"
|
#include "config/gimpconfig.h"
|
||||||
#include "config/gimpconfig-params.h"
|
#include "config/gimpconfig-params.h"
|
||||||
|
#include "config/gimpconfig-utils.h"
|
||||||
#include "config/gimprc.h"
|
#include "config/gimprc.h"
|
||||||
|
|
||||||
#include "core/gimp.h"
|
#include "core/gimp.h"
|
||||||
@ -46,10 +47,7 @@
|
|||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
|
||||||
/* gimprc will be parsed with a buffer size of 1024,
|
#define MAX_COMMENT_LENGTH 512 /* arbitrary */
|
||||||
* so don't set this too large
|
|
||||||
*/
|
|
||||||
#define MAX_COMMENT_LENGTH 512
|
|
||||||
|
|
||||||
|
|
||||||
/* preferences local functions */
|
/* preferences local functions */
|
||||||
@ -76,11 +74,82 @@ static void prefs_resolution_calibrate_callback (GtkWidget *widget,
|
|||||||
static void prefs_input_dialog_able_callback (GtkWidget *widget,
|
static void prefs_input_dialog_able_callback (GtkWidget *widget,
|
||||||
GdkDevice *device,
|
GdkDevice *device,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
static void prefs_restart_notification (void);
|
|
||||||
|
|
||||||
|
|
||||||
/* public function */
|
/* public function */
|
||||||
|
|
||||||
|
GtkWidget *
|
||||||
|
preferences_dialog_create (Gimp *gimp)
|
||||||
|
{
|
||||||
|
GtkWidget *prefs_dialog;
|
||||||
|
GObject *config;
|
||||||
|
GObject *config_copy;
|
||||||
|
GObject *config_orig;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
|
||||||
|
|
||||||
|
config = G_OBJECT (gimp->config);
|
||||||
|
config_copy = gimp_config_duplicate (config);
|
||||||
|
config_orig = gimp_config_duplicate (config);
|
||||||
|
|
||||||
|
/* read the saved gimprc to get GIMP_PARAM_RESTART values */
|
||||||
|
{
|
||||||
|
GimpRc *gimprc;
|
||||||
|
GObject *config_saved;
|
||||||
|
GList *diff;
|
||||||
|
GList *list;
|
||||||
|
|
||||||
|
gimprc = gimp_rc_new (GIMP_RC (config)->system_gimprc,
|
||||||
|
GIMP_RC (config)->user_gimprc);
|
||||||
|
config_saved = G_OBJECT (gimprc);
|
||||||
|
|
||||||
|
diff = gimp_config_diff (config_saved, config_copy, GIMP_PARAM_RESTART);
|
||||||
|
|
||||||
|
for (list = diff; list; list = g_list_next (list))
|
||||||
|
{
|
||||||
|
GParamSpec *param_spec;
|
||||||
|
GValue value = { 0, };
|
||||||
|
|
||||||
|
param_spec = (GParamSpec *) list->data;
|
||||||
|
|
||||||
|
g_value_init (&value, param_spec->value_type);
|
||||||
|
|
||||||
|
g_object_get_property (config_saved, param_spec->name, &value);
|
||||||
|
g_object_set_property (config_copy, param_spec->name, &value);
|
||||||
|
|
||||||
|
g_value_unset (&value);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free (diff);
|
||||||
|
g_object_unref (gimprc);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_signal_connect_object (config, "notify",
|
||||||
|
G_CALLBACK (prefs_config_notify),
|
||||||
|
config_copy, 0);
|
||||||
|
g_signal_connect_object (config_copy, "notify",
|
||||||
|
G_CALLBACK (prefs_config_copy_notify),
|
||||||
|
config, 0);
|
||||||
|
|
||||||
|
prefs_dialog = prefs_dialog_new (gimp, config_copy);
|
||||||
|
|
||||||
|
g_object_weak_ref (G_OBJECT (prefs_dialog),
|
||||||
|
(GWeakNotify) g_object_unref,
|
||||||
|
config_copy);
|
||||||
|
g_object_weak_ref (G_OBJECT (prefs_dialog),
|
||||||
|
(GWeakNotify) g_object_unref,
|
||||||
|
config_orig);
|
||||||
|
|
||||||
|
g_object_set_data (G_OBJECT (prefs_dialog), "gimp", gimp);
|
||||||
|
g_object_set_data (G_OBJECT (prefs_dialog), "config-copy", config_copy);
|
||||||
|
g_object_set_data (G_OBJECT (prefs_dialog), "config-orig", config_orig);
|
||||||
|
|
||||||
|
return prefs_dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* private functions */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
prefs_config_notify (GObject *config,
|
prefs_config_notify (GObject *config,
|
||||||
GParamSpec *param_spec,
|
GParamSpec *param_spec,
|
||||||
@ -161,111 +230,14 @@ prefs_config_copy_notify (GObject *config_copy,
|
|||||||
g_value_unset (&global_value);
|
g_value_unset (&global_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkWidget *
|
|
||||||
preferences_dialog_create (Gimp *gimp)
|
|
||||||
{
|
|
||||||
GtkWidget *prefs_dialog;
|
|
||||||
GObject *config;
|
|
||||||
GObject *config_copy;
|
|
||||||
GObject *config_orig;
|
|
||||||
|
|
||||||
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
|
|
||||||
|
|
||||||
config = G_OBJECT (gimp->config);
|
|
||||||
config_copy = gimp_config_duplicate (config);
|
|
||||||
config_orig = gimp_config_duplicate (config);
|
|
||||||
|
|
||||||
g_signal_connect_object (config, "notify",
|
|
||||||
G_CALLBACK (prefs_config_notify),
|
|
||||||
config_copy, 0);
|
|
||||||
g_signal_connect_object (config_copy, "notify",
|
|
||||||
G_CALLBACK (prefs_config_copy_notify),
|
|
||||||
config, 0);
|
|
||||||
|
|
||||||
prefs_dialog = prefs_dialog_new (gimp, config_copy);
|
|
||||||
|
|
||||||
g_object_weak_ref (G_OBJECT (prefs_dialog),
|
|
||||||
(GWeakNotify) g_object_unref,
|
|
||||||
config_copy);
|
|
||||||
g_object_weak_ref (G_OBJECT (prefs_dialog),
|
|
||||||
(GWeakNotify) g_object_unref,
|
|
||||||
config_orig);
|
|
||||||
|
|
||||||
g_object_set_data (G_OBJECT (prefs_dialog), "gimp", gimp);
|
|
||||||
g_object_set_data (G_OBJECT (prefs_dialog), "config-copy", config_copy);
|
|
||||||
g_object_set_data (G_OBJECT (prefs_dialog), "config-orig", config_orig);
|
|
||||||
|
|
||||||
return prefs_dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* private functions */
|
|
||||||
|
|
||||||
static void
|
|
||||||
prefs_restart_notification_save_callback (GtkWidget *widget,
|
|
||||||
gpointer data)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
prefs_save_callback (widget, prefs_dialog);
|
|
||||||
gtk_widget_destroy (GTK_WIDGET (data));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The user pressed OK and not Save, but has changed some settings that
|
|
||||||
* only take effect after he restarts the GIMP. Allow him to save the
|
|
||||||
* settings.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
prefs_restart_notification (void)
|
|
||||||
{
|
|
||||||
GtkWidget *dialog;
|
|
||||||
GtkWidget *hbox;
|
|
||||||
GtkWidget *label;
|
|
||||||
|
|
||||||
dialog = gimp_dialog_new (_("Save Preferences ?"), "gimp_message",
|
|
||||||
gimp_standard_help_func,
|
|
||||||
"dialogs/preferences/preferences.html",
|
|
||||||
GTK_WIN_POS_MOUSE,
|
|
||||||
FALSE, FALSE, FALSE,
|
|
||||||
|
|
||||||
GTK_STOCK_CLOSE, gtk_widget_destroy,
|
|
||||||
NULL, 1, NULL, FALSE, TRUE,
|
|
||||||
|
|
||||||
GTK_STOCK_SAVE,
|
|
||||||
prefs_restart_notification_save_callback,
|
|
||||||
NULL, NULL, NULL, TRUE, FALSE,
|
|
||||||
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (dialog), "destroy",
|
|
||||||
G_CALLBACK (gtk_main_quit),
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
hbox = gtk_hbox_new (FALSE, 4);
|
|
||||||
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE, FALSE, 4);
|
|
||||||
gtk_widget_show (hbox);
|
|
||||||
|
|
||||||
label = gtk_label_new (_("At least one of the changes you made will only\n"
|
|
||||||
"take effect after you restart the GIMP.\n\n"
|
|
||||||
"You may choose 'Save' now to make your changes\n"
|
|
||||||
"permanent, so you can restart GIMP or hit 'Close'\n"
|
|
||||||
"and the critical parts of your changes will not\n"
|
|
||||||
"be applied."));
|
|
||||||
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
|
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 4);
|
|
||||||
gtk_widget_show (label);
|
|
||||||
|
|
||||||
gtk_widget_show (dialog);
|
|
||||||
|
|
||||||
gtk_main ();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
prefs_cancel_callback (GtkWidget *widget,
|
prefs_cancel_callback (GtkWidget *widget,
|
||||||
GtkWidget *dialog)
|
GtkWidget *dialog)
|
||||||
{
|
{
|
||||||
Gimp *gimp;
|
Gimp *gimp;
|
||||||
GObject *config_orig;
|
GObject *config_orig;
|
||||||
|
GList *diff;
|
||||||
|
GList *list;
|
||||||
|
|
||||||
gimp = g_object_get_data (G_OBJECT (dialog), "gimp");
|
gimp = g_object_get_data (G_OBJECT (dialog), "gimp");
|
||||||
config_orig = g_object_get_data (G_OBJECT (dialog), "config-orig");
|
config_orig = g_object_get_data (G_OBJECT (dialog), "config-orig");
|
||||||
@ -274,49 +246,34 @@ prefs_cancel_callback (GtkWidget *widget,
|
|||||||
|
|
||||||
gtk_widget_destroy (dialog); /* destroys config_copy */
|
gtk_widget_destroy (dialog); /* destroys config_copy */
|
||||||
|
|
||||||
if (! gimp_config_is_equal_to (G_OBJECT (gimp->config), config_orig))
|
diff = gimp_config_diff (G_OBJECT (gimp->config), config_orig,
|
||||||
|
GIMP_PARAM_SERIALIZE);
|
||||||
|
|
||||||
|
g_object_freeze_notify (G_OBJECT (gimp->config));
|
||||||
|
|
||||||
|
for (list = diff; list; list = g_list_next (list))
|
||||||
{
|
{
|
||||||
GParamSpec **param_specs;
|
GParamSpec *param_spec;
|
||||||
guint n_param_specs;
|
GValue value = { 0, };
|
||||||
gint i;
|
|
||||||
|
|
||||||
param_specs =
|
param_spec = (GParamSpec *) list->data;
|
||||||
g_object_class_list_properties (G_OBJECT_GET_CLASS (config_orig),
|
|
||||||
&n_param_specs);
|
|
||||||
|
|
||||||
g_object_freeze_notify (G_OBJECT (gimp->config));
|
g_value_init (&value, param_spec->value_type);
|
||||||
|
|
||||||
for (i = 0; i < n_param_specs; i++)
|
g_object_get_property (config_orig,
|
||||||
{
|
param_spec->name,
|
||||||
GValue global_value = { 0, };
|
&value);
|
||||||
GValue orig_value = { 0, };
|
g_object_set_property (G_OBJECT (gimp->config),
|
||||||
|
param_spec->name,
|
||||||
|
&value);
|
||||||
|
|
||||||
g_value_init (&global_value, param_specs[i]->value_type);
|
g_value_unset (&value);
|
||||||
g_value_init (&orig_value, param_specs[i]->value_type);
|
|
||||||
|
|
||||||
g_object_get_property (G_OBJECT (gimp->config),
|
|
||||||
param_specs[i]->name,
|
|
||||||
&global_value);
|
|
||||||
g_object_get_property (config_orig,
|
|
||||||
param_specs[i]->name,
|
|
||||||
&orig_value);
|
|
||||||
|
|
||||||
if (g_param_values_cmp (param_specs[i], &global_value, &orig_value))
|
|
||||||
{
|
|
||||||
g_object_set_property (G_OBJECT (gimp->config),
|
|
||||||
param_specs[i]->name,
|
|
||||||
&orig_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_value_unset (&global_value);
|
|
||||||
g_value_unset (&orig_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_object_thaw_notify (G_OBJECT (gimp->config));
|
|
||||||
|
|
||||||
g_free (param_specs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_object_thaw_notify (G_OBJECT (gimp->config));
|
||||||
|
|
||||||
|
g_list_free (diff);
|
||||||
|
|
||||||
g_object_unref (config_orig);
|
g_object_unref (config_orig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,97 +282,73 @@ prefs_ok_callback (GtkWidget *widget,
|
|||||||
GtkWidget *dialog)
|
GtkWidget *dialog)
|
||||||
{
|
{
|
||||||
Gimp *gimp;
|
Gimp *gimp;
|
||||||
GObject *config_orig;
|
|
||||||
GObject *config_copy;
|
GObject *config_copy;
|
||||||
|
GList *restart_diff;
|
||||||
|
GList *confirm_diff;
|
||||||
|
GList *list;
|
||||||
|
|
||||||
gimp = g_object_get_data (G_OBJECT (dialog), "gimp");
|
gimp = g_object_get_data (G_OBJECT (dialog), "gimp");
|
||||||
config_orig = g_object_get_data (G_OBJECT (dialog), "config-orig");
|
|
||||||
config_copy = g_object_get_data (G_OBJECT (dialog), "config-copy");
|
config_copy = g_object_get_data (G_OBJECT (dialog), "config-copy");
|
||||||
|
|
||||||
g_object_ref (config_orig);
|
|
||||||
g_object_ref (config_copy);
|
g_object_ref (config_copy);
|
||||||
|
|
||||||
gtk_widget_destroy (dialog);
|
gtk_widget_destroy (dialog);
|
||||||
|
|
||||||
if (! gimp_config_is_equal_to (config_copy, config_orig))
|
restart_diff = gimp_config_diff (G_OBJECT (gimp->config), config_copy,
|
||||||
|
GIMP_PARAM_RESTART);
|
||||||
|
confirm_diff = gimp_config_diff (G_OBJECT (gimp->config), config_copy,
|
||||||
|
GIMP_PARAM_CONFIRM);
|
||||||
|
|
||||||
|
g_object_freeze_notify (G_OBJECT (gimp->config));
|
||||||
|
|
||||||
|
for (list = confirm_diff; list; list = g_list_next (list))
|
||||||
{
|
{
|
||||||
if (gimp_config_is_equal_to (G_OBJECT (gimp->config), config_copy))
|
GParamSpec *param_spec;
|
||||||
{
|
GValue value = { 0, };
|
||||||
g_message ("You have not changed any value that needs "
|
|
||||||
"restart or confirmation.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GParamSpec **param_specs;
|
|
||||||
guint n_param_specs;
|
|
||||||
GList *restart_list = NULL;
|
|
||||||
GList *confirm_list = NULL;
|
|
||||||
gint i;
|
|
||||||
|
|
||||||
param_specs =
|
param_spec = (GParamSpec *) list->data;
|
||||||
g_object_class_list_properties (G_OBJECT_GET_CLASS (config_copy),
|
|
||||||
&n_param_specs);
|
|
||||||
|
|
||||||
for (i = 0; i < n_param_specs; i++)
|
g_value_init (&value, param_spec->value_type);
|
||||||
{
|
|
||||||
GValue global_value = { 0, };
|
|
||||||
GValue copy_value = { 0, };
|
|
||||||
|
|
||||||
g_value_init (&global_value, param_specs[i]->value_type);
|
g_object_get_property (config_copy,
|
||||||
g_value_init (©_value, param_specs[i]->value_type);
|
param_spec->name,
|
||||||
|
&value);
|
||||||
|
g_object_set_property (G_OBJECT (gimp->config),
|
||||||
|
param_spec->name,
|
||||||
|
&value);
|
||||||
|
|
||||||
g_object_get_property (G_OBJECT (gimp->config),
|
g_value_unset (&value);
|
||||||
param_specs[i]->name,
|
|
||||||
&global_value);
|
|
||||||
g_object_get_property (config_copy,
|
|
||||||
param_specs[i]->name,
|
|
||||||
©_value);
|
|
||||||
|
|
||||||
if (g_param_values_cmp (param_specs[i],
|
|
||||||
&global_value, ©_value))
|
|
||||||
{
|
|
||||||
if (param_specs[i]->flags & GIMP_PARAM_RESTART)
|
|
||||||
{
|
|
||||||
restart_list = g_list_prepend (restart_list,
|
|
||||||
param_specs[i]);
|
|
||||||
}
|
|
||||||
else if (param_specs[i]->flags & GIMP_PARAM_CONFIRM)
|
|
||||||
{
|
|
||||||
confirm_list = g_list_prepend (confirm_list,
|
|
||||||
param_specs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_value_unset (&global_value);
|
|
||||||
g_value_unset (©_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (restart_list && confirm_list)
|
|
||||||
{
|
|
||||||
g_message ("You have changed %d values which need restart\n"
|
|
||||||
"and %d values which need confirmation.",
|
|
||||||
g_list_length (restart_list),
|
|
||||||
g_list_length (confirm_list));
|
|
||||||
}
|
|
||||||
else if (restart_list)
|
|
||||||
{
|
|
||||||
g_message ("You have changed %d values which need restart.",
|
|
||||||
g_list_length (restart_list));
|
|
||||||
}
|
|
||||||
else if (confirm_list)
|
|
||||||
{
|
|
||||||
g_message ("You have changed %d values which need confirmation.",
|
|
||||||
g_list_length (confirm_list));
|
|
||||||
}
|
|
||||||
|
|
||||||
g_list_free (restart_list);
|
|
||||||
g_list_free (confirm_list);
|
|
||||||
|
|
||||||
g_free (param_specs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_unref (config_orig);
|
g_object_thaw_notify (G_OBJECT (gimp->config));
|
||||||
|
|
||||||
|
if (restart_diff)
|
||||||
|
{
|
||||||
|
GString *string;
|
||||||
|
|
||||||
|
string = g_string_new (_("You will have to restart GIMP for\n"
|
||||||
|
"the following changes to take effect:"));
|
||||||
|
g_string_append (string, "\n\n");
|
||||||
|
|
||||||
|
for (list = restart_diff; list; list = g_list_next (list))
|
||||||
|
{
|
||||||
|
GParamSpec *param_spec;
|
||||||
|
|
||||||
|
param_spec = (GParamSpec *) list->data;
|
||||||
|
|
||||||
|
g_string_append_printf (string, "%s\n", param_spec->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_message (string->str);
|
||||||
|
|
||||||
|
g_string_free (string, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free (confirm_diff);
|
||||||
|
g_list_free (restart_diff);
|
||||||
|
|
||||||
|
gimp_rc_save (GIMP_RC (config_copy));
|
||||||
|
|
||||||
g_object_unref (config_copy);
|
g_object_unref (config_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -646,7 +646,6 @@ gimp_display_shell_new (GimpDisplay *gdisp,
|
|||||||
{
|
{
|
||||||
static GtkItemFactoryEntry menu_items[] =
|
static GtkItemFactoryEntry menu_items[] =
|
||||||
{
|
{
|
||||||
{ "/---", NULL, NULL, 0, "<Separator>"},
|
|
||||||
{ N_("/From Theme"), NULL,
|
{ N_("/From Theme"), NULL,
|
||||||
gimp_display_shell_color_button_menu_callback,
|
gimp_display_shell_color_button_menu_callback,
|
||||||
GIMP_DISPLAY_PADDING_MODE_DEFAULT, NULL },
|
GIMP_DISPLAY_PADDING_MODE_DEFAULT, NULL },
|
||||||
@ -656,6 +655,7 @@ gimp_display_shell_new (GimpDisplay *gdisp,
|
|||||||
{ N_("/Dark Check Color"), NULL,
|
{ N_("/Dark Check Color"), NULL,
|
||||||
gimp_display_shell_color_button_menu_callback,
|
gimp_display_shell_color_button_menu_callback,
|
||||||
GIMP_DISPLAY_PADDING_MODE_DARK_CHECK, NULL },
|
GIMP_DISPLAY_PADDING_MODE_DARK_CHECK, NULL },
|
||||||
|
{ "/---", NULL, NULL, 0, "<Separator>"},
|
||||||
{ N_("/Select Custom Color..."), NULL,
|
{ N_("/Select Custom Color..."), NULL,
|
||||||
gimp_display_shell_color_button_menu_callback,
|
gimp_display_shell_color_button_menu_callback,
|
||||||
GIMP_DISPLAY_PADDING_MODE_CUSTOM, NULL },
|
GIMP_DISPLAY_PADDING_MODE_CUSTOM, NULL },
|
||||||
|
@ -302,7 +302,8 @@ static void
|
|||||||
gimp_display_shell_resolution_changed_handler (GimpImage *gimage,
|
gimp_display_shell_resolution_changed_handler (GimpImage *gimage,
|
||||||
GimpDisplayShell *shell)
|
GimpDisplayShell *shell)
|
||||||
{
|
{
|
||||||
gimp_display_shell_scale_setup (shell);
|
if (! shell->dot_for_dot)
|
||||||
|
gimp_display_shell_scale_setup (shell);
|
||||||
|
|
||||||
gimp_statusbar_resize_cursor (GIMP_STATUSBAR (shell->statusbar));
|
gimp_statusbar_resize_cursor (GIMP_STATUSBAR (shell->statusbar));
|
||||||
}
|
}
|
||||||
@ -311,6 +312,7 @@ static void
|
|||||||
gimp_display_shell_unit_changed_handler (GimpImage *gimage,
|
gimp_display_shell_unit_changed_handler (GimpImage *gimage,
|
||||||
GimpDisplayShell *shell)
|
GimpDisplayShell *shell)
|
||||||
{
|
{
|
||||||
|
if (! shell->dot_for_dot)
|
||||||
gimp_display_shell_scale_setup (shell);
|
gimp_display_shell_scale_setup (shell);
|
||||||
|
|
||||||
gimp_statusbar_resize_cursor (GIMP_STATUSBAR (shell->statusbar));
|
gimp_statusbar_resize_cursor (GIMP_STATUSBAR (shell->statusbar));
|
||||||
@ -419,9 +421,10 @@ gimp_display_shell_monitor_res_notify_handler (GObject *config,
|
|||||||
shell->monitor_xres = GIMP_DISPLAY_CONFIG (config)->monitor_xres;
|
shell->monitor_xres = GIMP_DISPLAY_CONFIG (config)->monitor_xres;
|
||||||
shell->monitor_yres = GIMP_DISPLAY_CONFIG (config)->monitor_yres;
|
shell->monitor_yres = GIMP_DISPLAY_CONFIG (config)->monitor_yres;
|
||||||
|
|
||||||
#ifdef __GNUC__
|
if (! shell->dot_for_dot)
|
||||||
#warning FIXME: update displays on monitor resolution change
|
gimp_display_shell_scale_setup (shell);
|
||||||
#endif
|
|
||||||
|
gimp_statusbar_resize_cursor (GIMP_STATUSBAR (shell->statusbar));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -646,7 +646,6 @@ gimp_display_shell_new (GimpDisplay *gdisp,
|
|||||||
{
|
{
|
||||||
static GtkItemFactoryEntry menu_items[] =
|
static GtkItemFactoryEntry menu_items[] =
|
||||||
{
|
{
|
||||||
{ "/---", NULL, NULL, 0, "<Separator>"},
|
|
||||||
{ N_("/From Theme"), NULL,
|
{ N_("/From Theme"), NULL,
|
||||||
gimp_display_shell_color_button_menu_callback,
|
gimp_display_shell_color_button_menu_callback,
|
||||||
GIMP_DISPLAY_PADDING_MODE_DEFAULT, NULL },
|
GIMP_DISPLAY_PADDING_MODE_DEFAULT, NULL },
|
||||||
@ -656,6 +655,7 @@ gimp_display_shell_new (GimpDisplay *gdisp,
|
|||||||
{ N_("/Dark Check Color"), NULL,
|
{ N_("/Dark Check Color"), NULL,
|
||||||
gimp_display_shell_color_button_menu_callback,
|
gimp_display_shell_color_button_menu_callback,
|
||||||
GIMP_DISPLAY_PADDING_MODE_DARK_CHECK, NULL },
|
GIMP_DISPLAY_PADDING_MODE_DARK_CHECK, NULL },
|
||||||
|
{ "/---", NULL, NULL, 0, "<Separator>"},
|
||||||
{ N_("/Select Custom Color..."), NULL,
|
{ N_("/Select Custom Color..."), NULL,
|
||||||
gimp_display_shell_color_button_menu_callback,
|
gimp_display_shell_color_button_menu_callback,
|
||||||
GIMP_DISPLAY_PADDING_MODE_CUSTOM, NULL },
|
GIMP_DISPLAY_PADDING_MODE_CUSTOM, NULL },
|
||||||
|
@ -40,7 +40,7 @@ GimpDialogFactory *global_toolbox_factory = NULL;
|
|||||||
static const GimpDialogFactoryEntry toplevel_entries[] =
|
static const GimpDialogFactoryEntry toplevel_entries[] =
|
||||||
{
|
{
|
||||||
{ "gimp-device-status-dialog", dialogs_device_status_get, 32, TRUE, TRUE, FALSE, TRUE },
|
{ "gimp-device-status-dialog", dialogs_device_status_get, 32, TRUE, TRUE, FALSE, TRUE },
|
||||||
{ "gimp-preferences-dialog", dialogs_preferences_get, 32, FALSE, FALSE, FALSE, TRUE },
|
{ "gimp-preferences-dialog", dialogs_preferences_get, 32, TRUE, FALSE, FALSE, TRUE },
|
||||||
{ "gimp-module-browser-dialog", dialogs_module_browser_get, 32, TRUE, FALSE, FALSE, TRUE },
|
{ "gimp-module-browser-dialog", dialogs_module_browser_get, 32, TRUE, FALSE, FALSE, TRUE },
|
||||||
{ "gimp-undo-history-dialog", dialogs_undo_history_get, 32, FALSE, FALSE, FALSE, TRUE },
|
{ "gimp-undo-history-dialog", dialogs_undo_history_get, 32, FALSE, FALSE, FALSE, TRUE },
|
||||||
{ "gimp-display-filters-dialog", dialogs_display_filters_get, 32, FALSE, FALSE, FALSE, TRUE },
|
{ "gimp-display-filters-dialog", dialogs_display_filters_get, 32, FALSE, FALSE, FALSE, TRUE },
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "config/gimpconfig.h"
|
#include "config/gimpconfig.h"
|
||||||
#include "config/gimpconfig-params.h"
|
#include "config/gimpconfig-params.h"
|
||||||
|
#include "config/gimpconfig-utils.h"
|
||||||
#include "config/gimprc.h"
|
#include "config/gimprc.h"
|
||||||
|
|
||||||
#include "core/gimp.h"
|
#include "core/gimp.h"
|
||||||
@ -46,10 +47,7 @@
|
|||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
|
||||||
/* gimprc will be parsed with a buffer size of 1024,
|
#define MAX_COMMENT_LENGTH 512 /* arbitrary */
|
||||||
* so don't set this too large
|
|
||||||
*/
|
|
||||||
#define MAX_COMMENT_LENGTH 512
|
|
||||||
|
|
||||||
|
|
||||||
/* preferences local functions */
|
/* preferences local functions */
|
||||||
@ -76,11 +74,82 @@ static void prefs_resolution_calibrate_callback (GtkWidget *widget,
|
|||||||
static void prefs_input_dialog_able_callback (GtkWidget *widget,
|
static void prefs_input_dialog_able_callback (GtkWidget *widget,
|
||||||
GdkDevice *device,
|
GdkDevice *device,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
static void prefs_restart_notification (void);
|
|
||||||
|
|
||||||
|
|
||||||
/* public function */
|
/* public function */
|
||||||
|
|
||||||
|
GtkWidget *
|
||||||
|
preferences_dialog_create (Gimp *gimp)
|
||||||
|
{
|
||||||
|
GtkWidget *prefs_dialog;
|
||||||
|
GObject *config;
|
||||||
|
GObject *config_copy;
|
||||||
|
GObject *config_orig;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
|
||||||
|
|
||||||
|
config = G_OBJECT (gimp->config);
|
||||||
|
config_copy = gimp_config_duplicate (config);
|
||||||
|
config_orig = gimp_config_duplicate (config);
|
||||||
|
|
||||||
|
/* read the saved gimprc to get GIMP_PARAM_RESTART values */
|
||||||
|
{
|
||||||
|
GimpRc *gimprc;
|
||||||
|
GObject *config_saved;
|
||||||
|
GList *diff;
|
||||||
|
GList *list;
|
||||||
|
|
||||||
|
gimprc = gimp_rc_new (GIMP_RC (config)->system_gimprc,
|
||||||
|
GIMP_RC (config)->user_gimprc);
|
||||||
|
config_saved = G_OBJECT (gimprc);
|
||||||
|
|
||||||
|
diff = gimp_config_diff (config_saved, config_copy, GIMP_PARAM_RESTART);
|
||||||
|
|
||||||
|
for (list = diff; list; list = g_list_next (list))
|
||||||
|
{
|
||||||
|
GParamSpec *param_spec;
|
||||||
|
GValue value = { 0, };
|
||||||
|
|
||||||
|
param_spec = (GParamSpec *) list->data;
|
||||||
|
|
||||||
|
g_value_init (&value, param_spec->value_type);
|
||||||
|
|
||||||
|
g_object_get_property (config_saved, param_spec->name, &value);
|
||||||
|
g_object_set_property (config_copy, param_spec->name, &value);
|
||||||
|
|
||||||
|
g_value_unset (&value);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free (diff);
|
||||||
|
g_object_unref (gimprc);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_signal_connect_object (config, "notify",
|
||||||
|
G_CALLBACK (prefs_config_notify),
|
||||||
|
config_copy, 0);
|
||||||
|
g_signal_connect_object (config_copy, "notify",
|
||||||
|
G_CALLBACK (prefs_config_copy_notify),
|
||||||
|
config, 0);
|
||||||
|
|
||||||
|
prefs_dialog = prefs_dialog_new (gimp, config_copy);
|
||||||
|
|
||||||
|
g_object_weak_ref (G_OBJECT (prefs_dialog),
|
||||||
|
(GWeakNotify) g_object_unref,
|
||||||
|
config_copy);
|
||||||
|
g_object_weak_ref (G_OBJECT (prefs_dialog),
|
||||||
|
(GWeakNotify) g_object_unref,
|
||||||
|
config_orig);
|
||||||
|
|
||||||
|
g_object_set_data (G_OBJECT (prefs_dialog), "gimp", gimp);
|
||||||
|
g_object_set_data (G_OBJECT (prefs_dialog), "config-copy", config_copy);
|
||||||
|
g_object_set_data (G_OBJECT (prefs_dialog), "config-orig", config_orig);
|
||||||
|
|
||||||
|
return prefs_dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* private functions */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
prefs_config_notify (GObject *config,
|
prefs_config_notify (GObject *config,
|
||||||
GParamSpec *param_spec,
|
GParamSpec *param_spec,
|
||||||
@ -161,111 +230,14 @@ prefs_config_copy_notify (GObject *config_copy,
|
|||||||
g_value_unset (&global_value);
|
g_value_unset (&global_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkWidget *
|
|
||||||
preferences_dialog_create (Gimp *gimp)
|
|
||||||
{
|
|
||||||
GtkWidget *prefs_dialog;
|
|
||||||
GObject *config;
|
|
||||||
GObject *config_copy;
|
|
||||||
GObject *config_orig;
|
|
||||||
|
|
||||||
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
|
|
||||||
|
|
||||||
config = G_OBJECT (gimp->config);
|
|
||||||
config_copy = gimp_config_duplicate (config);
|
|
||||||
config_orig = gimp_config_duplicate (config);
|
|
||||||
|
|
||||||
g_signal_connect_object (config, "notify",
|
|
||||||
G_CALLBACK (prefs_config_notify),
|
|
||||||
config_copy, 0);
|
|
||||||
g_signal_connect_object (config_copy, "notify",
|
|
||||||
G_CALLBACK (prefs_config_copy_notify),
|
|
||||||
config, 0);
|
|
||||||
|
|
||||||
prefs_dialog = prefs_dialog_new (gimp, config_copy);
|
|
||||||
|
|
||||||
g_object_weak_ref (G_OBJECT (prefs_dialog),
|
|
||||||
(GWeakNotify) g_object_unref,
|
|
||||||
config_copy);
|
|
||||||
g_object_weak_ref (G_OBJECT (prefs_dialog),
|
|
||||||
(GWeakNotify) g_object_unref,
|
|
||||||
config_orig);
|
|
||||||
|
|
||||||
g_object_set_data (G_OBJECT (prefs_dialog), "gimp", gimp);
|
|
||||||
g_object_set_data (G_OBJECT (prefs_dialog), "config-copy", config_copy);
|
|
||||||
g_object_set_data (G_OBJECT (prefs_dialog), "config-orig", config_orig);
|
|
||||||
|
|
||||||
return prefs_dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* private functions */
|
|
||||||
|
|
||||||
static void
|
|
||||||
prefs_restart_notification_save_callback (GtkWidget *widget,
|
|
||||||
gpointer data)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
prefs_save_callback (widget, prefs_dialog);
|
|
||||||
gtk_widget_destroy (GTK_WIDGET (data));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The user pressed OK and not Save, but has changed some settings that
|
|
||||||
* only take effect after he restarts the GIMP. Allow him to save the
|
|
||||||
* settings.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
prefs_restart_notification (void)
|
|
||||||
{
|
|
||||||
GtkWidget *dialog;
|
|
||||||
GtkWidget *hbox;
|
|
||||||
GtkWidget *label;
|
|
||||||
|
|
||||||
dialog = gimp_dialog_new (_("Save Preferences ?"), "gimp_message",
|
|
||||||
gimp_standard_help_func,
|
|
||||||
"dialogs/preferences/preferences.html",
|
|
||||||
GTK_WIN_POS_MOUSE,
|
|
||||||
FALSE, FALSE, FALSE,
|
|
||||||
|
|
||||||
GTK_STOCK_CLOSE, gtk_widget_destroy,
|
|
||||||
NULL, 1, NULL, FALSE, TRUE,
|
|
||||||
|
|
||||||
GTK_STOCK_SAVE,
|
|
||||||
prefs_restart_notification_save_callback,
|
|
||||||
NULL, NULL, NULL, TRUE, FALSE,
|
|
||||||
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (dialog), "destroy",
|
|
||||||
G_CALLBACK (gtk_main_quit),
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
hbox = gtk_hbox_new (FALSE, 4);
|
|
||||||
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE, FALSE, 4);
|
|
||||||
gtk_widget_show (hbox);
|
|
||||||
|
|
||||||
label = gtk_label_new (_("At least one of the changes you made will only\n"
|
|
||||||
"take effect after you restart the GIMP.\n\n"
|
|
||||||
"You may choose 'Save' now to make your changes\n"
|
|
||||||
"permanent, so you can restart GIMP or hit 'Close'\n"
|
|
||||||
"and the critical parts of your changes will not\n"
|
|
||||||
"be applied."));
|
|
||||||
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
|
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 4);
|
|
||||||
gtk_widget_show (label);
|
|
||||||
|
|
||||||
gtk_widget_show (dialog);
|
|
||||||
|
|
||||||
gtk_main ();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
prefs_cancel_callback (GtkWidget *widget,
|
prefs_cancel_callback (GtkWidget *widget,
|
||||||
GtkWidget *dialog)
|
GtkWidget *dialog)
|
||||||
{
|
{
|
||||||
Gimp *gimp;
|
Gimp *gimp;
|
||||||
GObject *config_orig;
|
GObject *config_orig;
|
||||||
|
GList *diff;
|
||||||
|
GList *list;
|
||||||
|
|
||||||
gimp = g_object_get_data (G_OBJECT (dialog), "gimp");
|
gimp = g_object_get_data (G_OBJECT (dialog), "gimp");
|
||||||
config_orig = g_object_get_data (G_OBJECT (dialog), "config-orig");
|
config_orig = g_object_get_data (G_OBJECT (dialog), "config-orig");
|
||||||
@ -274,49 +246,34 @@ prefs_cancel_callback (GtkWidget *widget,
|
|||||||
|
|
||||||
gtk_widget_destroy (dialog); /* destroys config_copy */
|
gtk_widget_destroy (dialog); /* destroys config_copy */
|
||||||
|
|
||||||
if (! gimp_config_is_equal_to (G_OBJECT (gimp->config), config_orig))
|
diff = gimp_config_diff (G_OBJECT (gimp->config), config_orig,
|
||||||
|
GIMP_PARAM_SERIALIZE);
|
||||||
|
|
||||||
|
g_object_freeze_notify (G_OBJECT (gimp->config));
|
||||||
|
|
||||||
|
for (list = diff; list; list = g_list_next (list))
|
||||||
{
|
{
|
||||||
GParamSpec **param_specs;
|
GParamSpec *param_spec;
|
||||||
guint n_param_specs;
|
GValue value = { 0, };
|
||||||
gint i;
|
|
||||||
|
|
||||||
param_specs =
|
param_spec = (GParamSpec *) list->data;
|
||||||
g_object_class_list_properties (G_OBJECT_GET_CLASS (config_orig),
|
|
||||||
&n_param_specs);
|
|
||||||
|
|
||||||
g_object_freeze_notify (G_OBJECT (gimp->config));
|
g_value_init (&value, param_spec->value_type);
|
||||||
|
|
||||||
for (i = 0; i < n_param_specs; i++)
|
g_object_get_property (config_orig,
|
||||||
{
|
param_spec->name,
|
||||||
GValue global_value = { 0, };
|
&value);
|
||||||
GValue orig_value = { 0, };
|
g_object_set_property (G_OBJECT (gimp->config),
|
||||||
|
param_spec->name,
|
||||||
|
&value);
|
||||||
|
|
||||||
g_value_init (&global_value, param_specs[i]->value_type);
|
g_value_unset (&value);
|
||||||
g_value_init (&orig_value, param_specs[i]->value_type);
|
|
||||||
|
|
||||||
g_object_get_property (G_OBJECT (gimp->config),
|
|
||||||
param_specs[i]->name,
|
|
||||||
&global_value);
|
|
||||||
g_object_get_property (config_orig,
|
|
||||||
param_specs[i]->name,
|
|
||||||
&orig_value);
|
|
||||||
|
|
||||||
if (g_param_values_cmp (param_specs[i], &global_value, &orig_value))
|
|
||||||
{
|
|
||||||
g_object_set_property (G_OBJECT (gimp->config),
|
|
||||||
param_specs[i]->name,
|
|
||||||
&orig_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_value_unset (&global_value);
|
|
||||||
g_value_unset (&orig_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_object_thaw_notify (G_OBJECT (gimp->config));
|
|
||||||
|
|
||||||
g_free (param_specs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_object_thaw_notify (G_OBJECT (gimp->config));
|
||||||
|
|
||||||
|
g_list_free (diff);
|
||||||
|
|
||||||
g_object_unref (config_orig);
|
g_object_unref (config_orig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,97 +282,73 @@ prefs_ok_callback (GtkWidget *widget,
|
|||||||
GtkWidget *dialog)
|
GtkWidget *dialog)
|
||||||
{
|
{
|
||||||
Gimp *gimp;
|
Gimp *gimp;
|
||||||
GObject *config_orig;
|
|
||||||
GObject *config_copy;
|
GObject *config_copy;
|
||||||
|
GList *restart_diff;
|
||||||
|
GList *confirm_diff;
|
||||||
|
GList *list;
|
||||||
|
|
||||||
gimp = g_object_get_data (G_OBJECT (dialog), "gimp");
|
gimp = g_object_get_data (G_OBJECT (dialog), "gimp");
|
||||||
config_orig = g_object_get_data (G_OBJECT (dialog), "config-orig");
|
|
||||||
config_copy = g_object_get_data (G_OBJECT (dialog), "config-copy");
|
config_copy = g_object_get_data (G_OBJECT (dialog), "config-copy");
|
||||||
|
|
||||||
g_object_ref (config_orig);
|
|
||||||
g_object_ref (config_copy);
|
g_object_ref (config_copy);
|
||||||
|
|
||||||
gtk_widget_destroy (dialog);
|
gtk_widget_destroy (dialog);
|
||||||
|
|
||||||
if (! gimp_config_is_equal_to (config_copy, config_orig))
|
restart_diff = gimp_config_diff (G_OBJECT (gimp->config), config_copy,
|
||||||
|
GIMP_PARAM_RESTART);
|
||||||
|
confirm_diff = gimp_config_diff (G_OBJECT (gimp->config), config_copy,
|
||||||
|
GIMP_PARAM_CONFIRM);
|
||||||
|
|
||||||
|
g_object_freeze_notify (G_OBJECT (gimp->config));
|
||||||
|
|
||||||
|
for (list = confirm_diff; list; list = g_list_next (list))
|
||||||
{
|
{
|
||||||
if (gimp_config_is_equal_to (G_OBJECT (gimp->config), config_copy))
|
GParamSpec *param_spec;
|
||||||
{
|
GValue value = { 0, };
|
||||||
g_message ("You have not changed any value that needs "
|
|
||||||
"restart or confirmation.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GParamSpec **param_specs;
|
|
||||||
guint n_param_specs;
|
|
||||||
GList *restart_list = NULL;
|
|
||||||
GList *confirm_list = NULL;
|
|
||||||
gint i;
|
|
||||||
|
|
||||||
param_specs =
|
param_spec = (GParamSpec *) list->data;
|
||||||
g_object_class_list_properties (G_OBJECT_GET_CLASS (config_copy),
|
|
||||||
&n_param_specs);
|
|
||||||
|
|
||||||
for (i = 0; i < n_param_specs; i++)
|
g_value_init (&value, param_spec->value_type);
|
||||||
{
|
|
||||||
GValue global_value = { 0, };
|
|
||||||
GValue copy_value = { 0, };
|
|
||||||
|
|
||||||
g_value_init (&global_value, param_specs[i]->value_type);
|
g_object_get_property (config_copy,
|
||||||
g_value_init (©_value, param_specs[i]->value_type);
|
param_spec->name,
|
||||||
|
&value);
|
||||||
|
g_object_set_property (G_OBJECT (gimp->config),
|
||||||
|
param_spec->name,
|
||||||
|
&value);
|
||||||
|
|
||||||
g_object_get_property (G_OBJECT (gimp->config),
|
g_value_unset (&value);
|
||||||
param_specs[i]->name,
|
|
||||||
&global_value);
|
|
||||||
g_object_get_property (config_copy,
|
|
||||||
param_specs[i]->name,
|
|
||||||
©_value);
|
|
||||||
|
|
||||||
if (g_param_values_cmp (param_specs[i],
|
|
||||||
&global_value, ©_value))
|
|
||||||
{
|
|
||||||
if (param_specs[i]->flags & GIMP_PARAM_RESTART)
|
|
||||||
{
|
|
||||||
restart_list = g_list_prepend (restart_list,
|
|
||||||
param_specs[i]);
|
|
||||||
}
|
|
||||||
else if (param_specs[i]->flags & GIMP_PARAM_CONFIRM)
|
|
||||||
{
|
|
||||||
confirm_list = g_list_prepend (confirm_list,
|
|
||||||
param_specs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_value_unset (&global_value);
|
|
||||||
g_value_unset (©_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (restart_list && confirm_list)
|
|
||||||
{
|
|
||||||
g_message ("You have changed %d values which need restart\n"
|
|
||||||
"and %d values which need confirmation.",
|
|
||||||
g_list_length (restart_list),
|
|
||||||
g_list_length (confirm_list));
|
|
||||||
}
|
|
||||||
else if (restart_list)
|
|
||||||
{
|
|
||||||
g_message ("You have changed %d values which need restart.",
|
|
||||||
g_list_length (restart_list));
|
|
||||||
}
|
|
||||||
else if (confirm_list)
|
|
||||||
{
|
|
||||||
g_message ("You have changed %d values which need confirmation.",
|
|
||||||
g_list_length (confirm_list));
|
|
||||||
}
|
|
||||||
|
|
||||||
g_list_free (restart_list);
|
|
||||||
g_list_free (confirm_list);
|
|
||||||
|
|
||||||
g_free (param_specs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_unref (config_orig);
|
g_object_thaw_notify (G_OBJECT (gimp->config));
|
||||||
|
|
||||||
|
if (restart_diff)
|
||||||
|
{
|
||||||
|
GString *string;
|
||||||
|
|
||||||
|
string = g_string_new (_("You will have to restart GIMP for\n"
|
||||||
|
"the following changes to take effect:"));
|
||||||
|
g_string_append (string, "\n\n");
|
||||||
|
|
||||||
|
for (list = restart_diff; list; list = g_list_next (list))
|
||||||
|
{
|
||||||
|
GParamSpec *param_spec;
|
||||||
|
|
||||||
|
param_spec = (GParamSpec *) list->data;
|
||||||
|
|
||||||
|
g_string_append_printf (string, "%s\n", param_spec->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_message (string->str);
|
||||||
|
|
||||||
|
g_string_free (string, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free (confirm_diff);
|
||||||
|
g_list_free (restart_diff);
|
||||||
|
|
||||||
|
gimp_rc_save (GIMP_RC (config_copy));
|
||||||
|
|
||||||
g_object_unref (config_copy);
|
g_object_unref (config_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,12 +139,11 @@ gimp_config_serialize_changed_properties (GObject *new,
|
|||||||
gint fd,
|
gint fd,
|
||||||
gint indent_level)
|
gint indent_level)
|
||||||
{
|
{
|
||||||
GObjectClass *klass;
|
GObjectClass *klass;
|
||||||
GParamSpec **property_specs;
|
GList *diff;
|
||||||
guint n_property_specs;
|
GList *list;
|
||||||
guint i;
|
GString *str;
|
||||||
GString *str;
|
gboolean property_written = FALSE;
|
||||||
gboolean property_written = FALSE;
|
|
||||||
|
|
||||||
g_return_val_if_fail (G_IS_OBJECT (new), FALSE);
|
g_return_val_if_fail (G_IS_OBJECT (new), FALSE);
|
||||||
g_return_val_if_fail (G_IS_OBJECT (old), FALSE);
|
g_return_val_if_fail (G_IS_OBJECT (old), FALSE);
|
||||||
@ -153,64 +152,54 @@ gimp_config_serialize_changed_properties (GObject *new,
|
|||||||
|
|
||||||
klass = G_OBJECT_GET_CLASS (new);
|
klass = G_OBJECT_GET_CLASS (new);
|
||||||
|
|
||||||
property_specs = g_object_class_list_properties (klass, &n_property_specs);
|
diff = gimp_config_diff (new, old, GIMP_PARAM_SERIALIZE);
|
||||||
|
|
||||||
if (!property_specs)
|
if (! diff)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
str = g_string_new (NULL);
|
str = g_string_new (NULL);
|
||||||
|
|
||||||
for (i = 0; i < n_property_specs; i++)
|
for (list = diff; list; list = g_list_next (list))
|
||||||
{
|
{
|
||||||
GParamSpec *prop_spec;
|
GParamSpec *prop_spec;
|
||||||
GValue new_value = { 0, };
|
GValue new_value = { 0, };
|
||||||
GValue old_value = { 0, };
|
|
||||||
|
|
||||||
prop_spec = property_specs[i];
|
prop_spec = (GParamSpec *) list->data;
|
||||||
|
|
||||||
if (! (prop_spec->flags & GIMP_PARAM_SERIALIZE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
g_value_init (&new_value, prop_spec->value_type);
|
g_value_init (&new_value, prop_spec->value_type);
|
||||||
g_value_init (&old_value, prop_spec->value_type);
|
|
||||||
|
|
||||||
g_object_get_property (new, prop_spec->name, &new_value);
|
g_object_get_property (new, prop_spec->name, &new_value);
|
||||||
g_object_get_property (old, prop_spec->name, &old_value);
|
|
||||||
|
|
||||||
if (g_param_values_cmp (prop_spec, &new_value, &old_value) != 0)
|
if (property_written)
|
||||||
{
|
g_string_assign (str, "\n");
|
||||||
if (property_written)
|
else
|
||||||
g_string_assign (str, "\n");
|
g_string_assign (str, "");
|
||||||
else
|
|
||||||
g_string_assign (str, "");
|
|
||||||
|
|
||||||
gimp_config_string_indent (str, indent_level);
|
gimp_config_string_indent (str, indent_level);
|
||||||
|
|
||||||
g_string_append_printf (str, "(%s ", prop_spec->name);
|
g_string_append_printf (str, "(%s ", prop_spec->name);
|
||||||
|
|
||||||
if (gimp_config_serialize_value (&new_value, str, TRUE))
|
if (gimp_config_serialize_value (&new_value, str, TRUE))
|
||||||
{
|
{
|
||||||
g_string_append (str, ")\n");
|
g_string_append (str, ")\n");
|
||||||
property_written = TRUE;
|
property_written = TRUE;
|
||||||
|
|
||||||
if (write (fd, str->str, str->len) == -1)
|
if (write (fd, str->str, str->len) == -1)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
else if (prop_spec->value_type != G_TYPE_STRING)
|
else if (prop_spec->value_type != G_TYPE_STRING)
|
||||||
{
|
{
|
||||||
g_warning ("couldn't serialize property %s::%s of type %s",
|
g_warning ("couldn't serialize property %s::%s of type %s",
|
||||||
g_type_name (G_TYPE_FROM_INSTANCE (new)),
|
g_type_name (G_TYPE_FROM_INSTANCE (new)),
|
||||||
prop_spec->name,
|
prop_spec->name,
|
||||||
g_type_name (prop_spec->value_type));
|
g_type_name (prop_spec->value_type));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_value_unset (&new_value);
|
g_value_unset (&new_value);
|
||||||
g_value_unset (&old_value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (property_specs);
|
|
||||||
g_string_free (str, TRUE);
|
g_string_free (str, TRUE);
|
||||||
|
g_list_free (diff);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,50 @@
|
|||||||
#include "gimpconfig-utils.h"
|
#include "gimpconfig-utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
GList *
|
||||||
|
gimp_config_diff (GObject *a,
|
||||||
|
GObject *b,
|
||||||
|
GParamFlags flags)
|
||||||
|
{
|
||||||
|
GParamSpec **param_specs;
|
||||||
|
guint n_param_specs;
|
||||||
|
gint i;
|
||||||
|
GList *list = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (G_IS_OBJECT (a), FALSE);
|
||||||
|
g_return_val_if_fail (G_IS_OBJECT (b), FALSE);
|
||||||
|
g_return_val_if_fail (G_TYPE_FROM_INSTANCE (a) == G_TYPE_FROM_INSTANCE (b),
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
param_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a),
|
||||||
|
&n_param_specs);
|
||||||
|
|
||||||
|
for (i = 0; i < n_param_specs; i++)
|
||||||
|
{
|
||||||
|
if (! flags || ((param_specs[i]->flags & flags) == flags))
|
||||||
|
{
|
||||||
|
GValue a_value = { 0, };
|
||||||
|
GValue b_value = { 0, };
|
||||||
|
|
||||||
|
g_value_init (&a_value, param_specs[i]->value_type);
|
||||||
|
g_value_init (&b_value, param_specs[i]->value_type);
|
||||||
|
|
||||||
|
g_object_get_property (a, param_specs[i]->name, &a_value);
|
||||||
|
g_object_get_property (b, param_specs[i]->name, &b_value);
|
||||||
|
|
||||||
|
if (g_param_values_cmp (param_specs[i], &a_value, &b_value))
|
||||||
|
list = g_list_prepend (list, param_specs[i]);
|
||||||
|
|
||||||
|
g_value_unset (&a_value);
|
||||||
|
g_value_unset (&b_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (param_specs);
|
||||||
|
|
||||||
|
return g_list_reverse (list);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gimp_config_copy_properties (GObject *src,
|
gimp_config_copy_properties (GObject *src,
|
||||||
GObject *dest)
|
GObject *dest)
|
||||||
@ -64,7 +108,11 @@ gimp_config_copy_properties (GObject *src,
|
|||||||
|
|
||||||
g_object_get_property (src, prop_spec->name, &value);
|
g_object_get_property (src, prop_spec->name, &value);
|
||||||
g_object_set_property (dest, prop_spec->name, &value);
|
g_object_set_property (dest, prop_spec->name, &value);
|
||||||
|
|
||||||
|
g_value_unset (&value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free (property_specs);
|
||||||
}
|
}
|
||||||
|
|
||||||
gchar *
|
gchar *
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
#define __GIMP_CONFIG_UTILS_H__
|
#define __GIMP_CONFIG_UTILS_H__
|
||||||
|
|
||||||
|
|
||||||
|
GList * gimp_config_diff (GObject *a,
|
||||||
|
GObject *b,
|
||||||
|
GParamFlags flags);
|
||||||
void gimp_config_copy_properties (GObject *src,
|
void gimp_config_copy_properties (GObject *src,
|
||||||
GObject *dest);
|
GObject *dest);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user