diff --git a/ChangeLog b/ChangeLog index a74d95edd9..26128a0be7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +2004-06-16 Michael Natterer + + * libgimpwidgets/gimpcontroller.[ch]: added #define + GIMP_CONTROLLER_PARAM_SERIALIZE. Made all properties serializable. + + * modules/controller_linux_input.c: made "device-name" + serializable. + + * app/config/gimpconfig-params.h: added macro + GIMP_CONFIG_INSTALL_PROP_POINTER() which needs to be handled + by custom (de)serialize_property() implementations. + + * app/config/gimpconfig-deserialize.c + * app/config/gimpconfig-serialize.c: made object (de)serialization + work for object properties which are *not* GIMP_PARAM_AGGREGATE. + Write/parse the exact type of the object to create to enable this. + + * app/core/gimpmarshal.list: new marshaller for GimpControllerInfo. + + * app/widgets/gimpcontrollerinfo.[ch]: implement GimpConfigInterface + and add "controller" and "mapping" properties. Add "event-mapped" + signal which carries the action_name. + + * app/widgets/gimpcontrollers.c: removed all deserialization code + and simply (de)serialize the controller container. Install a + container handler for "event-mapped" and do the action_name -> + action mapping in the callback. + + * etc/controllerrc: regenerated with new syntax. Delete your old one! + 2004-06-16 Sven Neumann * app/widgets/gimpcontrollerwheel.c diff --git a/app/config/gimpconfig-deserialize.c b/app/config/gimpconfig-deserialize.c index 7670af4513..8f6b916532 100644 --- a/app/config/gimpconfig-deserialize.c +++ b/app/config/gimpconfig-deserialize.c @@ -666,7 +666,33 @@ gimp_config_deserialize_object (GValue *value, prop_object = g_value_get_object (value); if (! prop_object) - return G_TOKEN_RIGHT_PAREN; + { + /* if the object property is not GIMP_PARAM_AGGREGATE, read + * the type of the object and create it + */ + if (! (prop_spec->flags & GIMP_PARAM_AGGREGATE)) + { + gchar *type_name; + GType type; + + if (! gimp_scanner_parse_string (scanner, &type_name)) + return G_TOKEN_STRING; + + type = g_type_from_name (type_name); + g_free (type_name); + + if (! g_type_is_a (type, prop_spec->value_type)) + return G_TOKEN_STRING; + + prop_object = g_object_new (type, NULL); + + g_value_take_object (value, prop_object); + } + else + { + return G_TOKEN_RIGHT_PAREN; + } + } config_iface = GIMP_CONFIG_GET_INTERFACE (prop_object); diff --git a/app/config/gimpconfig-params.h b/app/config/gimpconfig-params.h index 42dd689fd7..6b315f5090 100644 --- a/app/config/gimpconfig-params.h +++ b/app/config/gimpconfig-params.h @@ -223,7 +223,7 @@ GParamSpec * gimp_param_spec_unit (const gchar *name, flags | GIMP_CONFIG_PARAM_FLAGS)) -/* object properties are _not_ G_PARAM_CONSTRUCT */ +/* object and pointer properties are _not_ G_PARAM_CONSTRUCT */ #define GIMP_CONFIG_INSTALL_PROP_OBJECT(class, id,\ name, blurb, object_type, flags)\ @@ -233,5 +233,12 @@ GParamSpec * gimp_param_spec_unit (const gchar *name, flags |\ G_PARAM_READWRITE | GIMP_PARAM_SERIALIZE)) +#define GIMP_CONFIG_INSTALL_PROP_POINTER(class, id,\ + name, blurb, flags)\ + g_object_class_install_property (class, id,\ + g_param_spec_pointer (name, NULL, blurb,\ + flags |\ + G_PARAM_READWRITE | GIMP_PARAM_SERIALIZE)) + #endif /* __GIMP_CONFIG_PARAMS_H__ */ diff --git a/app/config/gimpconfig-serialize.c b/app/config/gimpconfig-serialize.c index bc53d34917..09f5ba97a5 100644 --- a/app/config/gimpconfig-serialize.c +++ b/app/config/gimpconfig-serialize.c @@ -257,8 +257,7 @@ gimp_config_serialize_property (GimpConfig *config, if (! success) { - if (G_VALUE_HOLDS_OBJECT (&value) && - (param_spec->flags & GIMP_PARAM_AGGREGATE)) + if (G_VALUE_HOLDS_OBJECT (&value)) { GimpConfigInterface *config_iface = NULL; GimpConfig *prop_object; @@ -274,6 +273,17 @@ gimp_config_serialize_property (GimpConfig *config, { gimp_config_writer_open (writer, param_spec->name); + /* if the object property is not GIMP_PARAM_AGGREGATE, + * deserializing will need to know the exact type + * in order to create the object + */ + if (! (param_spec->flags & GIMP_PARAM_AGGREGATE)) + { + GType object_type = G_TYPE_FROM_INSTANCE (prop_object); + + gimp_config_writer_string (writer, g_type_name (object_type)); + } + success = config_iface->serialize (prop_object, writer, NULL); if (success) diff --git a/app/core/gimpmarshal.list b/app/core/gimpmarshal.list index 788d8006e7..a10ee2aece 100644 --- a/app/core/gimpmarshal.list +++ b/app/core/gimpmarshal.list @@ -25,6 +25,7 @@ BOOLEAN: BOOLEAN BOOLEAN: ENUM, INT BOOLEAN: OBJECT, POINTER +BOOLEAN: OBJECT, POINTER, STRING VOID: BOXED VOID: DOUBLE diff --git a/app/widgets/gimpcontrollerinfo.c b/app/widgets/gimpcontrollerinfo.c index 596c605430..02a0fe35bd 100644 --- a/app/widgets/gimpcontrollerinfo.c +++ b/app/widgets/gimpcontrollerinfo.c @@ -22,33 +22,77 @@ #include "config.h" +#include + #include #include "libgimpwidgets/gimpwidgets.h" +#include "libgimpwidgets/gimpcontroller.h" #include "widgets-types.h" +#include "config/gimpconfig.h" +#include "config/gimpconfig-params.h" +#include "config/gimpconfigwriter.h" +#include "config/gimpscanner.h" + +#include "core/gimpmarshal.h" + #include "gimpcontrollerinfo.h" #include "gimp-intl.h" -static void gimp_controller_info_class_init (GimpControllerInfoClass *klass); -static void gimp_controller_info_init (GimpControllerInfo *info); +enum +{ + PROP_0, + PROP_CONTROLLER, + PROP_MAPPING +}; -static void gimp_controller_info_finalize (GObject *object); -static void gimp_controller_info_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec); -static void gimp_controller_info_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec); +enum +{ + EVENT_MAPPED, + LAST_SIGNAL +}; + + +static void gimp_controller_info_class_init (GimpControllerInfoClass *klass); +static void gimp_controller_info_init (GimpControllerInfo *info); + +static void gimp_controller_info_config_iface_init (GimpConfigInterface *config_iface); + +static void gimp_controller_info_finalize (GObject *object); +static void gimp_controller_info_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_controller_info_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static gboolean gimp_controller_info_serialize_property (GimpConfig *config, + guint property_id, + const GValue *value, + GParamSpec *pspec, + GimpConfigWriter *writer); +static gboolean gimp_controller_info_deserialize_property (GimpConfig *config, + guint property_id, + GValue *value, + GParamSpec *pspec, + GScanner *scanner, + GTokenType *expected); + +static gboolean gimp_controller_info_event (GimpController *controller, + const GimpControllerEvent *event, + GimpControllerInfo *info); static GimpObjectClass *parent_class = NULL; +static guint info_signals[LAST_SIGNAL] = { 0 }; + GType gimp_controller_info_get_type (void) @@ -69,15 +113,40 @@ gimp_controller_info_get_type (void) 0, /* n_preallocs */ (GInstanceInitFunc) gimp_controller_info_init, }; + static const GInterfaceInfo config_iface_info = + { + (GInterfaceInitFunc) gimp_controller_info_config_iface_init, + NULL, /* iface_finalize */ + NULL /* iface_data */ + }; controller_type = g_type_register_static (GIMP_TYPE_OBJECT, "GimpControllerInfo", &controller_info, 0); + + g_type_add_interface_static (controller_type, GIMP_TYPE_CONFIG, + &config_iface_info); } return controller_type; } +gboolean +gimp_controller_info_boolean_handled_accumulator (GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer dummy) +{ + gboolean continue_emission; + gboolean signal_handled; + + signal_handled = g_value_get_boolean (handler_return); + g_value_set_boolean (return_accu, signal_handled); + continue_emission = ! signal_handled; + + return continue_emission; +} + static void gimp_controller_info_class_init (GimpControllerInfoClass *klass) { @@ -88,16 +157,40 @@ gimp_controller_info_class_init (GimpControllerInfoClass *klass) object_class->finalize = gimp_controller_info_finalize; object_class->set_property = gimp_controller_info_set_property; object_class->get_property = gimp_controller_info_get_property; + + GIMP_CONFIG_INSTALL_PROP_OBJECT (object_class, PROP_CONTROLLER, + "controller", NULL, + GIMP_TYPE_CONTROLLER, + 0); + GIMP_CONFIG_INSTALL_PROP_POINTER (object_class, PROP_MAPPING, + "mapping", NULL, + 0); + + info_signals[EVENT_MAPPED] = + g_signal_new ("event-mapped", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GimpControllerInfoClass, event_mapped), + gimp_controller_info_boolean_handled_accumulator, NULL, + gimp_marshal_BOOLEAN__OBJECT_POINTER_STRING, + G_TYPE_BOOLEAN, 3, + G_TYPE_OBJECT, + G_TYPE_POINTER, + G_TYPE_STRING); } static void gimp_controller_info_init (GimpControllerInfo *info) { info->controller = NULL; - info->mapping = g_hash_table_new_full (g_str_hash, - g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_object_unref); + info->mapping = NULL; +} + +static void +gimp_controller_info_config_iface_init (GimpConfigInterface *config_iface) +{ + config_iface->serialize_property = gimp_controller_info_serialize_property; + config_iface->deserialize_property = gimp_controller_info_deserialize_property; } static void @@ -124,6 +217,31 @@ gimp_controller_info_set_property (GObject *object, switch (property_id) { + case PROP_CONTROLLER: + if (info->controller) + { + g_signal_handlers_disconnect_by_func (info->controller, + gimp_controller_info_event, + info); + g_object_unref (info->controller); + } + + info->controller = (GimpController *) g_value_dup_object (value); + + if (info->controller) + { + g_signal_connect_object (info->controller, "event", + G_CALLBACK (gimp_controller_info_event), + G_OBJECT (info), + 0); + } + break; + case PROP_MAPPING: + if (info->mapping) + g_hash_table_destroy (info->mapping); + info->mapping = g_value_get_pointer (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -140,8 +258,185 @@ gimp_controller_info_get_property (GObject *object, switch (property_id) { + case PROP_CONTROLLER: + g_value_set_object (value, info->controller); + break; + case PROP_MAPPING: + g_value_set_pointer (value, info->mapping); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } + +static void +gimp_controller_info_serialize_mapping (gpointer key, + gpointer value, + gpointer data) +{ + const gchar *event_name = key; + const gchar *action_name = value; + GimpConfigWriter *writer = data; + + gimp_config_writer_open (writer, "map"); + gimp_config_writer_string (writer, event_name); + gimp_config_writer_string (writer, action_name); + gimp_config_writer_close (writer); +} + +static gboolean +gimp_controller_info_serialize_property (GimpConfig *config, + guint property_id, + const GValue *value, + GParamSpec *pspec, + GimpConfigWriter *writer) +{ + GHashTable *mapping; + + if (property_id != PROP_MAPPING) + return FALSE; + + mapping = g_value_get_pointer (value); + + gimp_config_writer_open (writer, pspec->name); + + g_hash_table_foreach (mapping, + (GHFunc) gimp_controller_info_serialize_mapping, + writer); + + gimp_config_writer_close (writer); + + return TRUE; +} + +static gboolean +gimp_controller_info_deserialize_property (GimpConfig *config, + guint property_id, + GValue *value, + GParamSpec *pspec, + GScanner *scanner, + GTokenType *expected) +{ + GHashTable *mapping = NULL; + GTokenType token; + + if (property_id != PROP_MAPPING) + return FALSE; + + mapping = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_free); + + token = G_TOKEN_LEFT_PAREN; + + while (g_scanner_peek_next_token (scanner) == token) + { + token = g_scanner_get_next_token (scanner); + + switch (token) + { + case G_TOKEN_LEFT_PAREN: + token = G_TOKEN_IDENTIFIER; + break; + + case G_TOKEN_IDENTIFIER: + if (! strcmp (scanner->value.v_identifier, "map")) + { + gchar *event_name; + gchar *action_name; + + token = G_TOKEN_STRING; + if (! gimp_scanner_parse_string (scanner, &event_name)) + goto error; + + token = G_TOKEN_STRING; + if (! gimp_scanner_parse_string (scanner, &action_name)) + goto error; + + g_hash_table_insert (mapping, event_name, action_name); + } + token = G_TOKEN_RIGHT_PAREN; + break; + + case G_TOKEN_RIGHT_PAREN: + token = G_TOKEN_LEFT_PAREN; + break; + + default: + break; + } + } + + if (token == G_TOKEN_LEFT_PAREN) + { + token = G_TOKEN_RIGHT_PAREN; + + if (g_scanner_peek_next_token (scanner) == token) + { + g_value_set_pointer (value, mapping); + } + else + { + goto error; + } + } + else + { + error: + if (mapping) + g_hash_table_destroy (mapping); + + *expected = token; + } + + return TRUE; +} + +static gboolean +gimp_controller_info_event (GimpController *controller, + const GimpControllerEvent *event, + GimpControllerInfo *info) +{ + const gchar *class_name; + const gchar *event_name; + const gchar *event_blurb; + const gchar *action_name; + + class_name = GIMP_CONTROLLER_GET_CLASS (controller)->name; + + event_name = gimp_controller_get_event_name (controller, event->any.event_id); + event_blurb = gimp_controller_get_event_blurb (controller, event->any.event_id); + + g_print ("Received '%s' (class '%s')\n" + " controller event '%s (%s)'\n", + controller->name, class_name, + event_name, event_blurb); + + action_name = g_hash_table_lookup (info->mapping, event_name); + + if (action_name) + { + gboolean retval = FALSE; + + g_print (" maps to action '%s'\n", action_name); + + g_signal_emit (info, info_signals[EVENT_MAPPED], 0, + controller, event, action_name, &retval); + + if (retval) + g_print (" action was found\n\n"); + else + g_print (" action NOT found\n\n"); + + return retval; + } + else + { + g_print (" doesn't map to action\n\n"); + } + + return FALSE; +} diff --git a/app/widgets/gimpcontrollerinfo.h b/app/widgets/gimpcontrollerinfo.h index d34d67f8c8..dfa184fa17 100644 --- a/app/widgets/gimpcontrollerinfo.h +++ b/app/widgets/gimpcontrollerinfo.h @@ -48,6 +48,11 @@ struct _GimpControllerInfo struct _GimpControllerInfoClass { GimpObjectClass parent_class; + + gboolean (* event_mapped) (GimpControllerInfo *info, + GimpController *controller, + const GimpControllerEvent *event, + const gchar *action_name); }; diff --git a/app/widgets/gimpcontrollers.c b/app/widgets/gimpcontrollers.c index 0b7b9e1291..961062cf32 100644 --- a/app/widgets/gimpcontrollers.c +++ b/app/widgets/gimpcontrollers.c @@ -22,16 +22,19 @@ #include "libgimpbase/gimpbase.h" #include "libgimpwidgets/gimpwidgets.h" +#include "libgimpwidgets/gimpcontroller.h" #include "widgets-types.h" #include "config/gimpconfig.h" +#include "config/gimpconfig-error.h" #include "config/gimpconfig-params.h" #include "config/gimpconfig-utils.h" #include "config/gimpconfigwriter.h" #include "config/gimpscanner.h" #include "core/gimp.h" +#include "core/gimplist.h" #include "gimpcontrollerinfo.h" #include "gimpcontrollers.h" @@ -48,7 +51,8 @@ typedef struct _GimpControllerManager GimpControllerManager; struct _GimpControllerManager { - GList *controllers; + GimpContainer *controllers; + GQuark event_mapped_id; GimpController *wheel; GimpUIManager *ui_manager; }; @@ -59,12 +63,11 @@ struct _GimpControllerManager static GimpControllerManager * gimp_controller_manager_get (Gimp *gimp); static void gimp_controller_manager_free (GimpControllerManager *manager); -static gboolean gimp_controller_info_event (GimpController *controller, - const GimpControllerEvent *event, - GimpControllerInfo *info); - -static GTokenType gimp_controller_deserialize (GimpControllerManager *manager, - GScanner *scanner); +static gboolean gimp_controllers_event_mapped (GimpControllerInfo *info, + GimpController *controller, + const GimpControllerEvent *event, + const gchar *action_name, + GimpControllerManager *manager); /* public functions */ @@ -83,6 +86,13 @@ gimp_controllers_init (Gimp *gimp) GIMP_CONTROLLER_MANAGER_DATA_KEY, manager, (GDestroyNotify) gimp_controller_manager_free); + manager->controllers = gimp_list_new (GIMP_TYPE_CONTROLLER_INFO, TRUE); + + manager->event_mapped_id = + gimp_container_add_handler (manager->controllers, "event-mapped", + G_CALLBACK (gimp_controllers_event_mapped), + manager); + /* EEEEEEK */ { static const GInterfaceInfo config_iface_info = @@ -110,21 +120,12 @@ gimp_controllers_exit (Gimp *gimp) g_type_class_unref (g_type_class_peek (GIMP_TYPE_CONTROLLER_WHEEL)); } -enum -{ - CONTROLLER, - CONTROLLER_OPTIONS, - CONTROLLER_MAPPING -}; - void gimp_controllers_restore (Gimp *gimp, GimpUIManager *ui_manager) { GimpControllerManager *manager; gchar *filename; - GScanner *scanner; - GTokenType token; GError *error = NULL; g_return_if_fail (GIMP_IS_GIMP (gimp)); @@ -139,81 +140,46 @@ gimp_controllers_restore (Gimp *gimp, filename = gimp_personal_rc_file ("controllerrc"); - scanner = gimp_scanner_new_file (filename, &error); - - if (! scanner) + if (! gimp_config_deserialize_file (GIMP_CONFIG (manager->controllers), + filename, NULL, &error)) { - g_clear_error (&error); - g_free (filename); - return; - } - - g_scanner_scope_add_symbol (scanner, 0, "controller", - GINT_TO_POINTER (CONTROLLER)); - g_scanner_scope_add_symbol (scanner, CONTROLLER, "options", - GINT_TO_POINTER (CONTROLLER_OPTIONS)); - g_scanner_scope_add_symbol (scanner, CONTROLLER, "mapping", - GINT_TO_POINTER (CONTROLLER_MAPPING)); - - token = G_TOKEN_LEFT_PAREN; - - while (g_scanner_peek_next_token (scanner) == token) - { - token = g_scanner_get_next_token (scanner); - - switch (token) + if (error->code == GIMP_CONFIG_ERROR_OPEN_ENOENT) { - case G_TOKEN_LEFT_PAREN: - token = G_TOKEN_SYMBOL; - break; + g_clear_error (&error); + g_free (filename); - case G_TOKEN_SYMBOL: - if (scanner->value.v_symbol == GINT_TO_POINTER (CONTROLLER)) + filename = g_build_filename (gimp_sysconf_directory (), + "controllerrc", NULL); + + if (! gimp_config_deserialize_file (GIMP_CONFIG (manager->controllers), + filename, NULL, &error)) { - g_scanner_set_scope (scanner, CONTROLLER); - token = gimp_controller_deserialize (manager, scanner); - - if (token == G_TOKEN_RIGHT_PAREN) - g_scanner_set_scope (scanner, 0); - else - break; + g_message (error->message); } - token = G_TOKEN_RIGHT_PAREN; - break; - - case G_TOKEN_RIGHT_PAREN: - token = G_TOKEN_LEFT_PAREN; - break; - - default: /* do nothing */ - break; } - } + else + { + g_message (error->message); + } - if (token != G_TOKEN_LEFT_PAREN) - { - g_scanner_get_next_token (scanner); - g_scanner_unexp_token (scanner, token, NULL, NULL, NULL, - _("fatal parse error"), TRUE); - } - - if (error) - { - g_message (error->message); g_clear_error (&error); - - gimp_config_file_backup_on_error (filename, "controllerrc", NULL); } - gimp_scanner_destroy (scanner); - g_free (filename); + gimp_list_reverse (GIMP_LIST (manager->controllers)); - manager->controllers = g_list_reverse (manager->controllers); + g_free (filename); } void gimp_controllers_save (Gimp *gimp) { + const gchar *header = + "GIMP controllerrc\n" + "\n" + "This file will be entirely rewritten every time you quit the gimp."; + const gchar *footer = + "end of controllerrc"; + GimpControllerManager *manager; gchar *filename; GError *error = NULL; @@ -225,6 +191,16 @@ gimp_controllers_save (Gimp *gimp) g_return_if_fail (manager != NULL); filename = gimp_personal_rc_file ("controllerrc"); + + if (! gimp_config_serialize_to_file (GIMP_CONFIG (manager->controllers), + filename, + header, footer, NULL, + &error)) + { + g_message (error->message); + g_error_free (error); + } + g_free (filename); } @@ -253,203 +229,38 @@ gimp_controller_manager_get (Gimp *gimp) static void gimp_controller_manager_free (GimpControllerManager *manager) { - g_list_foreach (manager->controllers, (GFunc) g_object_unref, NULL); - g_list_free (manager->controllers); + gimp_container_remove_handler (manager->controllers, + manager->event_mapped_id); + g_object_unref (manager->controllers); g_object_unref (manager->ui_manager); g_free (manager); } -static GTokenType -gimp_controller_deserialize (GimpControllerManager *manager, - GScanner *scanner) -{ - GimpControllerInfo *info = NULL; - GTokenType token; - gchar *controller_name; - GType controller_type; - - token = G_TOKEN_STRING; - - if (! gimp_scanner_parse_string (scanner, &controller_name)) - goto error; - - controller_type = g_type_from_name (controller_name); - g_free (controller_name); - - if (! g_type_is_a (controller_type, GIMP_TYPE_CONTROLLER)) - goto error; - - info = g_object_new (GIMP_TYPE_CONTROLLER_INFO, NULL); - - info->controller = gimp_controller_new (controller_type); - - /* EEEEEK */ - { - GParamSpec **props; - gint n_props; - gint i; - - props = g_object_class_list_properties (g_type_class_peek (controller_type), - &n_props); - - for (i = 0; i < n_props; i++) - props[i]->flags |= GIMP_PARAM_SERIALIZE; - - g_free (props); - } - - token = G_TOKEN_LEFT_PAREN; - - while (g_scanner_peek_next_token (scanner) == token) - { - token = g_scanner_get_next_token (scanner); - - switch (token) - { - case G_TOKEN_LEFT_PAREN: - token = G_TOKEN_SYMBOL; - break; - - case G_TOKEN_SYMBOL: - switch (GPOINTER_TO_INT (scanner->value.v_symbol)) - { - case CONTROLLER_OPTIONS: - { - GimpConfigInterface *config_iface; - - config_iface = GIMP_CONFIG_GET_INTERFACE (info->controller); - - if (! config_iface->deserialize (GIMP_CONFIG (info->controller), - scanner, - 1, - FALSE)) - { - goto error; - } - } - break; - - case CONTROLLER_MAPPING: - { - GtkAction *action = NULL; - GList *list; - gchar *event_name; - gchar *action_name; - - token = G_TOKEN_INT; - if (! gimp_scanner_parse_string (scanner, &event_name)) - goto error; - - token = G_TOKEN_STRING; - if (! gimp_scanner_parse_string (scanner, &action_name)) - goto error; - - for (list = gtk_ui_manager_get_action_groups (GTK_UI_MANAGER (manager->ui_manager)); - list; - list = g_list_next (list)) - { - GtkActionGroup *group = list->data; - - action = gtk_action_group_get_action (group, action_name); - - if (action) - break; - } - - if (action) - { - g_hash_table_insert (info->mapping, event_name, - g_object_ref (action)); - } - else - { - g_free (event_name); - g_printerr ("%s: action '%s' not found\n", - G_STRFUNC, action_name); - } - - g_free (action_name); - } - break; - - default: - break; - } - token = G_TOKEN_RIGHT_PAREN; - break; - - case G_TOKEN_RIGHT_PAREN: - token = G_TOKEN_LEFT_PAREN; - break; - - default: - break; - } - } - - if (token == G_TOKEN_LEFT_PAREN) - { - token = G_TOKEN_RIGHT_PAREN; - - if (g_scanner_peek_next_token (scanner) == token) - { - g_signal_connect (info->controller, "event", - G_CALLBACK (gimp_controller_info_event), - info); - - if (GIMP_IS_CONTROLLER_WHEEL (info->controller)) - manager->wheel = info->controller; - - manager->controllers = g_list_prepend (manager->controllers, info); - } - else - { - goto error; - } - } - else - { - error: - if (info) - g_object_unref (info); - } - - return token; -} - static gboolean -gimp_controller_info_event (GimpController *controller, - const GimpControllerEvent *event, - GimpControllerInfo *info) +gimp_controllers_event_mapped (GimpControllerInfo *info, + GimpController *controller, + const GimpControllerEvent *event, + const gchar *action_name, + GimpControllerManager *manager) { - GtkAction *action; - const gchar *class_name; - const gchar *event_name; - const gchar *event_blurb; + GList *list; - class_name = GIMP_CONTROLLER_GET_CLASS (controller)->name; - - event_name = gimp_controller_get_event_name (controller, event->any.event_id); - event_blurb = gimp_controller_get_event_blurb (controller, event->any.event_id); - - g_print ("Received '%s' (class '%s')\n" - " controller event '%s (%s)'\n", - controller->name, class_name, - event_name, event_blurb); - - action = g_hash_table_lookup (info->mapping, event_name); - - if (action) + for (list = gtk_ui_manager_get_action_groups (GTK_UI_MANAGER (manager->ui_manager)); + list; + list = g_list_next (list)) { - g_print (" handled by action '%s'\n\n", gtk_action_get_name (action)); - gtk_action_activate (action); - return TRUE; - } - else - { - g_print (" not handled\n\n"); + GtkActionGroup *group = list->data; + GtkAction *action; + + action = gtk_action_group_get_action (group, action_name); + + if (action) + { + gtk_action_activate (action); + return TRUE; + } } return FALSE; diff --git a/etc/controllerrc b/etc/controllerrc index 9fb70b0b3a..2e84946955 100644 --- a/etc/controllerrc +++ b/etc/controllerrc @@ -1,30 +1,37 @@ # GIMP controllerrc +# +# This file will be entirely rewritten every time you quit the gimp. -(controller "GimpControllerWheel" - (options - (name "Main Mouse Wheel")) - (mapping "scroll-up-shift-control-alt" "context-font-next") - (mapping "scroll-up-control-alt" "context-gradient-next") - (mapping "scroll-up-shift-alt" "context-pattern-next") - (mapping "scroll-up-shift-control" "context-brush-next") - (mapping "scroll-up-alt" "context-opacity-increase-skip") - (mapping "scroll-down-shift-control-alt" "context-font-previous") - (mapping "scroll-down-control-alt" "context-gradient-previous") - (mapping "scroll-down-shift-alt" "context-pattern-previous") - (mapping "scroll-down-shift-control" "context-brush-previous") - (mapping "scroll-down-alt" "context-opacity-decrease-skip")) +(GimpControllerInfo "Main Mouse Wheel" + (controller "GimpControllerWheel" + (name "Main Mouse Wheel") + (enabled yes)) + (mapping + (map "scroll-down-alt" "context-opacity-decrease-skip") + (map "scroll-down-control-alt" "context-gradient-previous") + (map "scroll-down-shift-alt" "context-pattern-previous") + (map "scroll-down-shift-control" "context-brush-previous") + (map "scroll-down-shift-control-alt" "context-font-previous") + (map "scroll-up-alt" "context-opacity-increase-skip") + (map "scroll-up-control-alt" "context-gradient-next") + (map "scroll-up-shift-alt" "context-pattern-next") + (map "scroll-up-shift-control" "context-brush-next") + (map "scroll-up-shift-control-alt" "context-font-next"))) +(GimpControllerInfo "ShuttlePRO" + (controller "ControllerLinuxInput" + (name "ShuttlePRO") + (enabled yes) + (device "/dev/input/event2")) + (mapping + (map "button-0" "tools-rect-select") + (map "button-1" "tools-ellipse-select") + (map "button-2" "tools-bucket-fill") + (map "button-3" "tools-blend") + (map "button-4" "tools-pencil") + (map "button-5" "tools-paintbrush") + (map "button-6" "tools-eraser") + (map "button-7" "tools-airbrush") + (map "wheel-turn-left" "context-brush-radius-decrease") + (map "wheel-turn-right" "context-brush-radius-increase"))) -(controller "ControllerLinuxInput" - (options - (name "ShuttlePRO") - (device "/dev/input/event2")) - (mapping "button-0" "tools-rect-select") - (mapping "button-1" "tools-ellipse-select") - (mapping "button-2" "tools-bucket-fill") - (mapping "button-3" "tools-blend") - (mapping "button-4" "tools-pencil") - (mapping "button-5" "tools-paintbrush") - (mapping "button-6" "tools-eraser") - (mapping "button-7" "tools-airbrush") - (mapping "wheel-turn-left" "context-brush-radius-decrease") - (mapping "wheel-turn-right" "context-brush-radius-increase")) +# end of controllerrc diff --git a/libgimpconfig/gimpconfig-deserialize.c b/libgimpconfig/gimpconfig-deserialize.c index 7670af4513..8f6b916532 100644 --- a/libgimpconfig/gimpconfig-deserialize.c +++ b/libgimpconfig/gimpconfig-deserialize.c @@ -666,7 +666,33 @@ gimp_config_deserialize_object (GValue *value, prop_object = g_value_get_object (value); if (! prop_object) - return G_TOKEN_RIGHT_PAREN; + { + /* if the object property is not GIMP_PARAM_AGGREGATE, read + * the type of the object and create it + */ + if (! (prop_spec->flags & GIMP_PARAM_AGGREGATE)) + { + gchar *type_name; + GType type; + + if (! gimp_scanner_parse_string (scanner, &type_name)) + return G_TOKEN_STRING; + + type = g_type_from_name (type_name); + g_free (type_name); + + if (! g_type_is_a (type, prop_spec->value_type)) + return G_TOKEN_STRING; + + prop_object = g_object_new (type, NULL); + + g_value_take_object (value, prop_object); + } + else + { + return G_TOKEN_RIGHT_PAREN; + } + } config_iface = GIMP_CONFIG_GET_INTERFACE (prop_object); diff --git a/libgimpconfig/gimpconfig-params.h b/libgimpconfig/gimpconfig-params.h index 42dd689fd7..6b315f5090 100644 --- a/libgimpconfig/gimpconfig-params.h +++ b/libgimpconfig/gimpconfig-params.h @@ -223,7 +223,7 @@ GParamSpec * gimp_param_spec_unit (const gchar *name, flags | GIMP_CONFIG_PARAM_FLAGS)) -/* object properties are _not_ G_PARAM_CONSTRUCT */ +/* object and pointer properties are _not_ G_PARAM_CONSTRUCT */ #define GIMP_CONFIG_INSTALL_PROP_OBJECT(class, id,\ name, blurb, object_type, flags)\ @@ -233,5 +233,12 @@ GParamSpec * gimp_param_spec_unit (const gchar *name, flags |\ G_PARAM_READWRITE | GIMP_PARAM_SERIALIZE)) +#define GIMP_CONFIG_INSTALL_PROP_POINTER(class, id,\ + name, blurb, flags)\ + g_object_class_install_property (class, id,\ + g_param_spec_pointer (name, NULL, blurb,\ + flags |\ + G_PARAM_READWRITE | GIMP_PARAM_SERIALIZE)) + #endif /* __GIMP_CONFIG_PARAMS_H__ */ diff --git a/libgimpconfig/gimpconfig-serialize.c b/libgimpconfig/gimpconfig-serialize.c index bc53d34917..09f5ba97a5 100644 --- a/libgimpconfig/gimpconfig-serialize.c +++ b/libgimpconfig/gimpconfig-serialize.c @@ -257,8 +257,7 @@ gimp_config_serialize_property (GimpConfig *config, if (! success) { - if (G_VALUE_HOLDS_OBJECT (&value) && - (param_spec->flags & GIMP_PARAM_AGGREGATE)) + if (G_VALUE_HOLDS_OBJECT (&value)) { GimpConfigInterface *config_iface = NULL; GimpConfig *prop_object; @@ -274,6 +273,17 @@ gimp_config_serialize_property (GimpConfig *config, { gimp_config_writer_open (writer, param_spec->name); + /* if the object property is not GIMP_PARAM_AGGREGATE, + * deserializing will need to know the exact type + * in order to create the object + */ + if (! (param_spec->flags & GIMP_PARAM_AGGREGATE)) + { + GType object_type = G_TYPE_FROM_INSTANCE (prop_object); + + gimp_config_writer_string (writer, g_type_name (object_type)); + } + success = config_iface->serialize (prop_object, writer, NULL); if (success) diff --git a/libgimpwidgets/gimpcontroller.c b/libgimpwidgets/gimpcontroller.c index 38676812f2..dc118ba969 100644 --- a/libgimpwidgets/gimpcontroller.c +++ b/libgimpwidgets/gimpcontroller.c @@ -120,12 +120,14 @@ gimp_controller_class_init (GimpControllerClass *klass) g_param_spec_string ("name", NULL, NULL, "Unnamed Controller", G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); + G_PARAM_CONSTRUCT | + GIMP_CONTROLLER_PARAM_SERIALIZE)); g_object_class_install_property (object_class, PROP_ENABLED, g_param_spec_boolean ("enabled", NULL, NULL, TRUE, G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); + G_PARAM_CONSTRUCT | + GIMP_CONTROLLER_PARAM_SERIALIZE)); controller_signals[EVENT] = g_signal_new ("event", diff --git a/libgimpwidgets/gimpcontroller.h b/libgimpwidgets/gimpcontroller.h index 638e3476f9..27a01a2624 100644 --- a/libgimpwidgets/gimpcontroller.h +++ b/libgimpwidgets/gimpcontroller.h @@ -27,6 +27,10 @@ G_BEGIN_DECLS /* For information look at the html documentation */ + +#define GIMP_CONTROLLER_PARAM_SERIALIZE (1 << (0 + G_PARAM_USER_SHIFT)) + + typedef enum { GIMP_CONTROLLER_EVENT_TRIGGER, diff --git a/modules/controller_linux_input.c b/modules/controller_linux_input.c index 33389226a5..2466d48b3f 100644 --- a/modules/controller_linux_input.c +++ b/modules/controller_linux_input.c @@ -211,7 +211,8 @@ linux_input_class_init (ControllerLinuxInputClass *klass) g_param_spec_string ("device", NULL, NULL, NULL, G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); + G_PARAM_CONSTRUCT | + GIMP_CONTROLLER_PARAM_SERIALIZE)); controller_class->name = _("Linux Input Events");