1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
3  *
4  * gimpcontrollerinfo.c
5  * Copyright (C) 2004-2005 Michael Natterer <mitch@gimp.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <string.h>
24 
25 #include <gegl.h>
26 #include <gtk/gtk.h>
27 
28 #include "libgimpconfig/gimpconfig.h"
29 #include "libgimpwidgets/gimpwidgets.h"
30 
31 #define GIMP_ENABLE_CONTROLLER_UNDER_CONSTRUCTION
32 #include "libgimpwidgets/gimpcontroller.h"
33 
34 #include "widgets-types.h"
35 
36 #include "core/gimpmarshal.h"
37 
38 #include "gimpcontrollerinfo.h"
39 
40 #include "gimp-intl.h"
41 
42 
43 enum
44 {
45   PROP_0,
46   PROP_ENABLED,
47   PROP_DEBUG_EVENTS,
48   PROP_CONTROLLER,
49   PROP_MAPPING
50 };
51 
52 enum
53 {
54   EVENT_MAPPED,
55   LAST_SIGNAL
56 };
57 
58 
59 static void     gimp_controller_info_config_iface_init (GimpConfigInterface *iface);
60 
61 static void     gimp_controller_info_finalize     (GObject          *object);
62 static void     gimp_controller_info_set_property (GObject          *object,
63                                                    guint             property_id,
64                                                    const GValue     *value,
65                                                    GParamSpec       *pspec);
66 static void     gimp_controller_info_get_property (GObject          *object,
67                                                    guint             property_id,
68                                                    GValue           *value,
69                                                    GParamSpec       *pspec);
70 
71 static gboolean gimp_controller_info_serialize_property   (GimpConfig       *config,
72                                                            guint             property_id,
73                                                            const GValue     *value,
74                                                            GParamSpec       *pspec,
75                                                            GimpConfigWriter *writer);
76 static gboolean gimp_controller_info_deserialize_property (GimpConfig       *config,
77                                                            guint             property_id,
78                                                            GValue           *value,
79                                                            GParamSpec       *pspec,
80                                                            GScanner         *scanner,
81                                                            GTokenType       *expected);
82 
83 static gboolean gimp_controller_info_event (GimpController            *controller,
84                                             const GimpControllerEvent *event,
85                                             GimpControllerInfo        *info);
86 
87 
88 G_DEFINE_TYPE_WITH_CODE (GimpControllerInfo, gimp_controller_info,
89                          GIMP_TYPE_VIEWABLE,
90                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG,
91                                                 gimp_controller_info_config_iface_init))
92 
93 #define parent_class gimp_controller_info_parent_class
94 
95 static guint info_signals[LAST_SIGNAL] = { 0 };
96 
97 
98 static void
gimp_controller_info_class_init(GimpControllerInfoClass * klass)99 gimp_controller_info_class_init (GimpControllerInfoClass *klass)
100 {
101   GObjectClass      *object_class   = G_OBJECT_CLASS (klass);
102   GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
103 
104   object_class->finalize            = gimp_controller_info_finalize;
105   object_class->set_property        = gimp_controller_info_set_property;
106   object_class->get_property        = gimp_controller_info_get_property;
107 
108   viewable_class->default_icon_name = GIMP_ICON_CONTROLLER;
109 
110   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_ENABLED,
111                             "enabled",
112                             _("Enabled"),
113                             NULL,
114                             TRUE,
115                             GIMP_PARAM_STATIC_STRINGS);
116 
117   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_DEBUG_EVENTS,
118                             "debug-events",
119                             _("Debug events"),
120                             NULL,
121                             FALSE,
122                             GIMP_PARAM_STATIC_STRINGS);
123 
124   GIMP_CONFIG_PROP_OBJECT (object_class, PROP_CONTROLLER,
125                            "controller",
126                            "Controller",
127                            NULL,
128                            GIMP_TYPE_CONTROLLER,
129                            GIMP_PARAM_STATIC_STRINGS);
130 
131   GIMP_CONFIG_PROP_BOXED (object_class, PROP_MAPPING,
132                           "mapping",
133                           "Mapping",
134                           NULL,
135                           G_TYPE_HASH_TABLE,
136                           GIMP_PARAM_STATIC_STRINGS);
137 
138   info_signals[EVENT_MAPPED] =
139     g_signal_new ("event-mapped",
140                   G_TYPE_FROM_CLASS (klass),
141                   G_SIGNAL_RUN_LAST,
142                   G_STRUCT_OFFSET (GimpControllerInfoClass, event_mapped),
143                   g_signal_accumulator_true_handled, NULL,
144                   gimp_marshal_BOOLEAN__OBJECT_POINTER_STRING,
145                   G_TYPE_BOOLEAN, 3,
146                   G_TYPE_OBJECT,
147                   G_TYPE_POINTER,
148                   G_TYPE_STRING);
149 }
150 
151 static void
gimp_controller_info_init(GimpControllerInfo * info)152 gimp_controller_info_init (GimpControllerInfo *info)
153 {
154   info->controller = NULL;
155   info->mapping    = g_hash_table_new_full (g_str_hash,
156                                             g_str_equal,
157                                             (GDestroyNotify) g_free,
158                                             (GDestroyNotify) g_free);
159 }
160 
161 static void
gimp_controller_info_config_iface_init(GimpConfigInterface * iface)162 gimp_controller_info_config_iface_init (GimpConfigInterface *iface)
163 {
164   iface->serialize_property   = gimp_controller_info_serialize_property;
165   iface->deserialize_property = gimp_controller_info_deserialize_property;
166 }
167 
168 static void
gimp_controller_info_finalize(GObject * object)169 gimp_controller_info_finalize (GObject *object)
170 {
171   GimpControllerInfo *info = GIMP_CONTROLLER_INFO (object);
172 
173   g_clear_object (&info->controller);
174   g_clear_pointer (&info->mapping, g_hash_table_unref);
175 
176   G_OBJECT_CLASS (parent_class)->finalize (object);
177 }
178 
179 static void
gimp_controller_info_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)180 gimp_controller_info_set_property (GObject      *object,
181                                    guint         property_id,
182                                    const GValue *value,
183                                    GParamSpec   *pspec)
184 {
185   GimpControllerInfo *info = GIMP_CONTROLLER_INFO (object);
186 
187   switch (property_id)
188     {
189     case PROP_ENABLED:
190       info->enabled = g_value_get_boolean (value);
191       break;
192     case PROP_DEBUG_EVENTS:
193       info->debug_events = g_value_get_boolean (value);
194       break;
195     case PROP_CONTROLLER:
196       if (info->controller)
197         {
198           g_signal_handlers_disconnect_by_func (info->controller,
199                                                 gimp_controller_info_event,
200                                                 info);
201           g_object_unref (info->controller);
202         }
203 
204       info->controller = g_value_dup_object (value);
205 
206       if (info->controller)
207         {
208           GimpControllerClass *controller_class;
209 
210           g_signal_connect_object (info->controller, "event",
211                                    G_CALLBACK (gimp_controller_info_event),
212                                    G_OBJECT (info),
213                                    0);
214 
215           controller_class = GIMP_CONTROLLER_GET_CLASS (info->controller);
216           gimp_viewable_set_icon_name (GIMP_VIEWABLE (info),
217                                        controller_class->icon_name);
218         }
219       break;
220     case PROP_MAPPING:
221       if (info->mapping)
222         g_hash_table_unref (info->mapping);
223       info->mapping = g_value_dup_boxed (value);
224       break;
225 
226     default:
227       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
228       break;
229     }
230 }
231 
232 static void
gimp_controller_info_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)233 gimp_controller_info_get_property (GObject    *object,
234                                    guint       property_id,
235                                    GValue     *value,
236                                    GParamSpec *pspec)
237 {
238   GimpControllerInfo *info = GIMP_CONTROLLER_INFO (object);
239 
240   switch (property_id)
241     {
242     case PROP_ENABLED:
243       g_value_set_boolean (value, info->enabled);
244       break;
245     case PROP_DEBUG_EVENTS:
246       g_value_set_boolean (value, info->debug_events);
247       break;
248     case PROP_CONTROLLER:
249       g_value_set_object (value, info->controller);
250       break;
251     case PROP_MAPPING:
252       g_value_set_boxed (value, info->mapping);
253       break;
254 
255     default:
256       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
257       break;
258     }
259 }
260 
261 static void
gimp_controller_info_serialize_mapping(gpointer key,gpointer value,gpointer data)262 gimp_controller_info_serialize_mapping (gpointer key,
263                                         gpointer value,
264                                         gpointer data)
265 {
266   const gchar      *event_name  = key;
267   const gchar      *action_name = value;
268   GimpConfigWriter *writer      = data;
269 
270   gimp_config_writer_open (writer, "map");
271   gimp_config_writer_string (writer, event_name);
272   gimp_config_writer_string (writer, action_name);
273   gimp_config_writer_close (writer);
274 }
275 
276 static gboolean
gimp_controller_info_serialize_property(GimpConfig * config,guint property_id,const GValue * value,GParamSpec * pspec,GimpConfigWriter * writer)277 gimp_controller_info_serialize_property (GimpConfig       *config,
278                                          guint             property_id,
279                                          const GValue     *value,
280                                          GParamSpec       *pspec,
281                                          GimpConfigWriter *writer)
282 {
283   GHashTable *mapping;
284 
285   if (property_id != PROP_MAPPING)
286     return FALSE;
287 
288   mapping = g_value_get_boxed (value);
289 
290   if (mapping)
291     {
292       gimp_config_writer_open (writer, pspec->name);
293 
294       g_hash_table_foreach (mapping,
295                             (GHFunc) gimp_controller_info_serialize_mapping,
296                             writer);
297 
298       gimp_config_writer_close (writer);
299     }
300 
301   return TRUE;
302 }
303 
304 static gboolean
gimp_controller_info_deserialize_property(GimpConfig * config,guint property_id,GValue * value,GParamSpec * pspec,GScanner * scanner,GTokenType * expected)305 gimp_controller_info_deserialize_property (GimpConfig *config,
306                                            guint       property_id,
307                                            GValue     *value,
308                                            GParamSpec *pspec,
309                                            GScanner   *scanner,
310                                            GTokenType *expected)
311 {
312   GHashTable *mapping;
313   GTokenType  token;
314 
315   if (property_id != PROP_MAPPING)
316     return FALSE;
317 
318   mapping = g_hash_table_new_full (g_str_hash,
319                                    g_str_equal,
320                                    (GDestroyNotify) g_free,
321                                    (GDestroyNotify) g_free);
322 
323   token = G_TOKEN_LEFT_PAREN;
324 
325   while (g_scanner_peek_next_token (scanner) == token)
326     {
327       token = g_scanner_get_next_token (scanner);
328 
329       switch (token)
330         {
331         case G_TOKEN_LEFT_PAREN:
332           token = G_TOKEN_IDENTIFIER;
333           break;
334 
335         case G_TOKEN_IDENTIFIER:
336           if (! strcmp (scanner->value.v_identifier, "map"))
337             {
338               gchar *event_name;
339               gchar *action_name;
340 
341               token = G_TOKEN_STRING;
342               if (! gimp_scanner_parse_string (scanner, &event_name))
343                 goto error;
344 
345               token = G_TOKEN_STRING;
346               if (! gimp_scanner_parse_string (scanner, &action_name))
347                 goto error;
348 
349               g_hash_table_insert (mapping, event_name, action_name);
350             }
351           token = G_TOKEN_RIGHT_PAREN;
352           break;
353 
354         case G_TOKEN_RIGHT_PAREN:
355           token = G_TOKEN_LEFT_PAREN;
356           break;
357 
358         default:
359           break;
360         }
361     }
362 
363   if (token == G_TOKEN_LEFT_PAREN)
364     {
365       token = G_TOKEN_RIGHT_PAREN;
366 
367       if (g_scanner_peek_next_token (scanner) == token)
368         {
369           g_value_take_boxed (value, mapping);
370         }
371       else
372         {
373           goto error;
374         }
375     }
376   else
377     {
378     error:
379       g_hash_table_unref (mapping);
380 
381       *expected = token;
382     }
383 
384   return TRUE;
385 }
386 
387 
388 /*  public functions  */
389 
390 GimpControllerInfo *
gimp_controller_info_new(GType type)391 gimp_controller_info_new (GType type)
392 {
393   GimpControllerClass *controller_class;
394   GimpController      *controller;
395   GimpControllerInfo  *info;
396 
397   g_return_val_if_fail (g_type_is_a (type, GIMP_TYPE_CONTROLLER), NULL);
398 
399   controller_class = g_type_class_ref (type);
400 
401   controller = gimp_controller_new (type);
402   info = g_object_new (GIMP_TYPE_CONTROLLER_INFO,
403                        "name",       controller_class->name,
404                        "controller", controller,
405                        NULL);
406   g_object_unref (controller);
407 
408   g_type_class_unref (controller_class);
409 
410   return info;
411 }
412 
413 void
gimp_controller_info_set_enabled(GimpControllerInfo * info,gboolean enabled)414 gimp_controller_info_set_enabled (GimpControllerInfo *info,
415                                   gboolean            enabled)
416 {
417   g_return_if_fail (GIMP_IS_CONTROLLER_INFO (info));
418 
419   if (enabled != info->enabled)
420     g_object_set (info, "enabled", enabled, NULL);
421 }
422 
423 gboolean
gimp_controller_info_get_enabled(GimpControllerInfo * info)424 gimp_controller_info_get_enabled (GimpControllerInfo *info)
425 {
426   g_return_val_if_fail (GIMP_IS_CONTROLLER_INFO (info), FALSE);
427 
428   return info->enabled;
429 }
430 
431 void
gimp_controller_info_set_event_snooper(GimpControllerInfo * info,GimpControllerEventSnooper snooper,gpointer snooper_data)432 gimp_controller_info_set_event_snooper (GimpControllerInfo         *info,
433                                         GimpControllerEventSnooper  snooper,
434                                         gpointer                    snooper_data)
435 {
436   g_return_if_fail (GIMP_IS_CONTROLLER_INFO (info));
437 
438   info->snooper      = snooper;
439   info->snooper_data = snooper_data;
440 }
441 
442 
443 /*  private functions  */
444 
445 static gboolean
gimp_controller_info_event(GimpController * controller,const GimpControllerEvent * event,GimpControllerInfo * info)446 gimp_controller_info_event (GimpController            *controller,
447                             const GimpControllerEvent *event,
448                             GimpControllerInfo        *info)
449 {
450   const gchar *event_name;
451   const gchar *event_blurb;
452   const gchar *action_name = NULL;
453 
454   event_name = gimp_controller_get_event_name (controller,
455                                                event->any.event_id);
456   event_blurb = gimp_controller_get_event_blurb (controller,
457                                                  event->any.event_id);
458 
459   if (info->debug_events)
460     {
461       g_print ("Received '%s' (class '%s')\n"
462                "    controller event '%s (%s)'\n",
463                controller->name, GIMP_CONTROLLER_GET_CLASS (controller)->name,
464                event_name, event_blurb);
465 
466       switch (event->any.type)
467         {
468         case GIMP_CONTROLLER_EVENT_TRIGGER:
469           g_print ("    (trigger event)\n");
470           break;
471 
472         case GIMP_CONTROLLER_EVENT_VALUE:
473           if (G_VALUE_HOLDS_DOUBLE (&event->value.value))
474             g_print ("    (value event, value = %f)\n",
475                      g_value_get_double (&event->value.value));
476           else
477             g_print ("    (value event, unhandled type '%s')\n",
478                      g_type_name (event->value.value.g_type));
479           break;
480         }
481     }
482 
483   if (info->snooper)
484     {
485       if (info->snooper (info, controller, event, info->snooper_data))
486         {
487           if (info->debug_events)
488             g_print ("    intercepted by event snooper\n\n");
489 
490           return TRUE;
491         }
492     }
493 
494   if (! info->enabled)
495     {
496       if (info->debug_events)
497         g_print ("    ignoring because controller is disabled\n\n");
498 
499       return FALSE;
500     }
501 
502   if (info->mapping)
503     action_name = g_hash_table_lookup (info->mapping, event_name);
504 
505   if (action_name)
506     {
507       gboolean retval = FALSE;
508 
509       if (info->debug_events)
510         g_print ("    maps to action '%s'\n", action_name);
511 
512       g_signal_emit (info, info_signals[EVENT_MAPPED], 0,
513                      controller, event, action_name, &retval);
514 
515       if (info->debug_events)
516         {
517           if (retval)
518             g_print ("    action was found\n\n");
519           else
520             g_print ("    action NOT found\n\n");
521         }
522 
523       return retval;
524     }
525   else
526     {
527       if (info->debug_events)
528         g_print ("    doesn't map to action\n\n");
529     }
530 
531   return FALSE;
532 }
533