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