15817
|
1 #include "gntbindable.h"
|
|
2 #include "gntstyle.h"
|
|
3 #include "gnt.h"
|
|
4 #include "gntutils.h"
|
|
5
|
|
6 static GObjectClass *parent_class = NULL;
|
|
7
|
|
8 static void
|
|
9 gnt_bindable_class_init(GntBindableClass *klass)
|
|
10 {
|
|
11 parent_class = g_type_class_peek_parent(klass);
|
|
12
|
|
13 klass->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
|
|
14 (GDestroyNotify)gnt_bindable_action_free);
|
|
15 klass->bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
|
|
16 (GDestroyNotify)gnt_bindable_action_param_free);
|
|
17
|
|
18 gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass));
|
|
19 GNTDEBUG;
|
|
20 }
|
|
21
|
|
22 static gpointer
|
|
23 bindable_clone(GntBindableAction *action)
|
|
24 {
|
|
25 GntBindableAction *ret = g_new0(GntBindableAction, 1);
|
|
26 ret->name = g_strdup(action->name);
|
|
27 ret->u = action->u;
|
|
28 return ret;
|
|
29 }
|
|
30
|
|
31 static gpointer
|
|
32 binding_clone(GntBindableActionParam *param)
|
|
33 {
|
|
34 GntBindableActionParam *p = g_new0(GntBindableActionParam, 1);
|
|
35 p->list = g_list_copy(param->list);
|
|
36 p->action = param->action;
|
|
37 return p;
|
|
38 }
|
|
39
|
|
40 static void
|
|
41 duplicate_hashes(GntBindableClass *klass)
|
|
42 {
|
|
43 /* Duplicate the bindings from parent class */
|
|
44 if (klass->actions) {
|
|
45 klass->actions = g_hash_table_duplicate(klass->actions, g_str_hash,
|
|
46 g_str_equal, g_free, (GDestroyNotify)gnt_bindable_action_free,
|
|
47 (GDupFunc)g_strdup, (GDupFunc)bindable_clone);
|
|
48 klass->bindings = g_hash_table_duplicate(klass->bindings, g_str_hash,
|
|
49 g_str_equal, g_free, (GDestroyNotify)gnt_bindable_action_param_free,
|
|
50 (GDupFunc)g_strdup, (GDupFunc)binding_clone);
|
|
51 } else {
|
|
52 klass->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
|
|
53 (GDestroyNotify)gnt_bindable_action_free);
|
|
54 klass->bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
|
|
55 (GDestroyNotify)gnt_bindable_action_param_free);
|
|
56 }
|
|
57
|
|
58 GNTDEBUG;
|
|
59 }
|
|
60
|
|
61 /******************************************************************************
|
|
62 * GntBindable API
|
|
63 *****************************************************************************/
|
|
64 GType
|
|
65 gnt_bindable_get_gtype(void)
|
|
66 {
|
|
67 static GType type = 0;
|
|
68
|
|
69 if(type == 0) {
|
|
70 static const GTypeInfo info = {
|
|
71 sizeof(GntBindableClass),
|
|
72 (GBaseInitFunc)duplicate_hashes, /* base_init */
|
|
73 NULL, /* base_finalize */
|
|
74 (GClassInitFunc)gnt_bindable_class_init,
|
|
75 NULL,
|
|
76 NULL, /* class_data */
|
|
77 sizeof(GntBindable),
|
|
78 0, /* n_preallocs */
|
|
79 NULL, /* instance_init */
|
|
80 NULL /* value_table */
|
|
81 };
|
|
82
|
|
83 type = g_type_register_static(G_TYPE_OBJECT,
|
|
84 "GntBindable",
|
|
85 &info, G_TYPE_FLAG_ABSTRACT);
|
|
86 }
|
|
87
|
|
88 return type;
|
|
89 }
|
|
90
|
|
91 /**
|
|
92 * Key Remaps
|
|
93 */
|
|
94 const char *
|
|
95 gnt_bindable_remap_keys(GntBindable *bindable, const char *text)
|
|
96 {
|
|
97 const char *remap = NULL;
|
|
98 GType type = G_OBJECT_TYPE(bindable);
|
|
99 GntBindableClass *klass = GNT_BINDABLE_CLASS(GNT_BINDABLE_GET_CLASS(bindable));
|
|
100
|
|
101 if (klass->remaps == NULL)
|
|
102 {
|
|
103 klass->remaps = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
|
|
104 gnt_styles_get_keyremaps(type, klass->remaps);
|
|
105 }
|
|
106
|
|
107 remap = g_hash_table_lookup(klass->remaps, text);
|
|
108
|
|
109 return (remap ? remap : text);
|
|
110 }
|
|
111
|
|
112 /**
|
|
113 * Actions and Bindings
|
|
114 */
|
|
115 gboolean
|
|
116 gnt_bindable_perform_action_named(GntBindable *bindable, const char *name, ...)
|
|
117 {
|
|
118 GntBindableClass *klass = GNT_BINDABLE_CLASS(GNT_BINDABLE_GET_CLASS(bindable));
|
|
119 GList *list = NULL;
|
|
120 va_list args;
|
|
121 GntBindableAction *action;
|
|
122 void *p;
|
|
123
|
|
124 va_start(args, name);
|
|
125 while ((p = va_arg(args, void *)) != NULL)
|
|
126 list = g_list_append(list, p);
|
|
127 va_end(args);
|
|
128
|
|
129 action = g_hash_table_lookup(klass->actions, name);
|
|
130 if (action && action->u.action) {
|
|
131 return action->u.action(bindable, list);
|
|
132 }
|
|
133 return FALSE;
|
|
134 }
|
|
135
|
|
136 gboolean
|
|
137 gnt_bindable_perform_action_key(GntBindable *bindable, const char *keys)
|
|
138 {
|
|
139 GntBindableClass *klass = GNT_BINDABLE_CLASS(GNT_BINDABLE_GET_CLASS(bindable));
|
|
140 GntBindableActionParam *param = g_hash_table_lookup(klass->bindings, keys);
|
|
141
|
|
142 if (param && param->action) {
|
|
143 if (param->list)
|
|
144 return param->action->u.action(bindable, param->list);
|
|
145 else
|
|
146 return param->action->u.action_noparam(bindable);
|
|
147 }
|
|
148 return FALSE;
|
|
149 }
|
|
150
|
|
151 static void
|
|
152 register_binding(GntBindableClass *klass, const char *name, const char *trigger, GList *list)
|
|
153 {
|
|
154 GntBindableActionParam *param;
|
|
155 GntBindableAction *action;
|
|
156
|
|
157 if (name == NULL || *name == '\0') {
|
|
158 g_hash_table_remove(klass->bindings, (char*)trigger);
|
|
159 gnt_keys_del_combination(trigger);
|
|
160 return;
|
|
161 }
|
|
162
|
|
163 action = g_hash_table_lookup(klass->actions, name);
|
|
164 if (!action) {
|
|
165 g_printerr("GntWidget: Invalid action name %s for %s\n",
|
|
166 name, g_type_name(G_OBJECT_CLASS_TYPE(klass)));
|
|
167 if (list)
|
|
168 g_list_free(list);
|
|
169 return;
|
|
170 }
|
|
171
|
|
172 param = g_new0(GntBindableActionParam, 1);
|
|
173 param->action = action;
|
|
174 param->list = list;
|
|
175 g_hash_table_replace(klass->bindings, g_strdup(trigger), param);
|
|
176 gnt_keys_add_combination(trigger);
|
|
177 }
|
|
178
|
|
179 void gnt_bindable_register_binding(GntBindableClass *klass, const char *name,
|
|
180 const char *trigger, ...)
|
|
181 {
|
|
182 GList *list = NULL;
|
|
183 va_list args;
|
|
184 void *data;
|
|
185
|
|
186 va_start(args, trigger);
|
|
187 while ((data = va_arg(args, void *))) {
|
|
188 list = g_list_append(list, data);
|
|
189 }
|
|
190 va_end(args);
|
|
191
|
|
192 register_binding(klass, name, trigger, list);
|
|
193 }
|
|
194
|
|
195 void gnt_bindable_class_register_action(GntBindableClass *klass, const char *name,
|
|
196 GntBindableActionCallback callback, const char *trigger, ...)
|
|
197 {
|
|
198 void *data;
|
|
199 va_list args;
|
|
200 GntBindableAction *action = g_new0(GntBindableAction, 1);
|
|
201 GList *list;
|
|
202
|
|
203 action->name = g_strdup(name);
|
|
204 action->u.action = callback;
|
|
205
|
|
206 g_hash_table_replace(klass->actions, g_strdup(name), action);
|
|
207
|
|
208 if (trigger && *trigger) {
|
|
209 list = NULL;
|
|
210 va_start(args, trigger);
|
|
211 while ((data = va_arg(args, void *))) {
|
|
212 list = g_list_append(list, data);
|
|
213 }
|
|
214 va_end(args);
|
|
215
|
|
216 register_binding(klass, name, trigger, list);
|
|
217 }
|
|
218 }
|
|
219
|
|
220 void gnt_bindable_action_free(GntBindableAction *action)
|
|
221 {
|
|
222 g_free(action->name);
|
|
223 g_free(action);
|
|
224 }
|
|
225
|
|
226 void gnt_bindable_action_param_free(GntBindableActionParam *param)
|
|
227 {
|
|
228 g_list_free(param->list); /* XXX: There may be a leak here for string parameters */
|
|
229 g_free(param);
|
|
230 }
|
|
231
|
|
232
|