Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : */
9 :
10 : #include <unx/gtk/gtksalmenu.hxx>
11 :
12 : #ifdef ENABLE_GMENU_INTEGRATION
13 :
14 : #include <unx/gtk/gloactiongroup.h>
15 : #include <unx/gtk/gtkinst.hxx>
16 : #include <unx/gtk/gtkframe.hxx>
17 :
18 :
19 : /*
20 : * GLOAction
21 : */
22 :
23 : #define G_TYPE_LO_ACTION (g_lo_action_get_type ())
24 : #define G_LO_ACTION(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
25 : G_TYPE_LO_ACTION, GLOAction))
26 :
27 : struct _GLOAction
28 : {
29 : GObject parent_instance;
30 :
31 : gint item_id; // Menu item ID.
32 : gboolean submenu; // TRUE if action is a submenu action.
33 : gboolean enabled; // TRUE if action is enabled.
34 : GVariantType* parameter_type; // A GVariantType with the action parameter type.
35 : GVariantType* state_type; // A GVariantType with item state type
36 : GVariant* state_hint; // A GVariant with state hints.
37 : GVariant* state; // A GVariant with current item state
38 : };
39 :
40 : typedef GObjectClass GLOActionClass;
41 : typedef struct _GLOAction GLOAction;
42 :
43 0 : G_DEFINE_TYPE (GLOAction, g_lo_action, G_TYPE_OBJECT);
44 :
45 : GLOAction*
46 0 : g_lo_action_new (void)
47 : {
48 0 : return G_LO_ACTION (g_object_new (G_TYPE_LO_ACTION, NULL));
49 : }
50 :
51 : static void
52 0 : g_lo_action_init (GLOAction *action)
53 : {
54 0 : action->item_id = -1;
55 0 : action->submenu = FALSE;
56 0 : action->enabled = TRUE;
57 0 : action->parameter_type = NULL;
58 0 : action->state_type = NULL;
59 0 : action->state_hint = NULL;
60 0 : action->state = NULL;
61 0 : }
62 :
63 : static void
64 0 : g_lo_action_finalize (GObject *object)
65 : {
66 0 : GLOAction* action = G_LO_ACTION(object);
67 :
68 0 : if (action->parameter_type)
69 0 : g_variant_type_free (action->parameter_type);
70 :
71 0 : if (action->state_type)
72 0 : g_variant_type_free (action->state_type);
73 :
74 0 : if (action->state_hint)
75 0 : g_variant_unref (action->state_hint);
76 :
77 0 : if (action->state)
78 0 : g_variant_unref (action->state);
79 :
80 0 : G_OBJECT_CLASS (g_lo_action_parent_class)->finalize (object);
81 0 : }
82 :
83 : static void
84 0 : g_lo_action_class_init (GLOActionClass *klass)
85 : {
86 0 : GObjectClass *object_class = G_OBJECT_CLASS(klass);
87 :
88 0 : object_class->finalize = g_lo_action_finalize;
89 0 : }
90 :
91 : /*
92 : * GLOActionGroup
93 : */
94 :
95 : struct _GLOActionGroupPrivate
96 : {
97 : GHashTable *table; /* string -> GLOAction */
98 : GtkSalFrame *frame; /* Frame to which GActionGroup is associated. */
99 : };
100 :
101 : static void g_lo_action_group_iface_init (GActionGroupInterface *);
102 :
103 0 : G_DEFINE_TYPE_WITH_CODE (GLOActionGroup,
104 : g_lo_action_group, G_TYPE_OBJECT,
105 : G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP,
106 : g_lo_action_group_iface_init));
107 :
108 : static gchar **
109 0 : g_lo_action_group_list_actions (GActionGroup *group)
110 : {
111 0 : GLOActionGroup *loGroup = G_LO_ACTION_GROUP (group);
112 : GHashTableIter iter;
113 0 : gint n, i = 0;
114 : gchar **keys;
115 : gpointer key;
116 :
117 0 : n = g_hash_table_size (loGroup->priv->table);
118 0 : keys = g_new (gchar *, n + 1);
119 :
120 0 : g_hash_table_iter_init (&iter, loGroup->priv->table);
121 0 : while (g_hash_table_iter_next (&iter, &key, NULL))
122 0 : keys[i++] = g_strdup ((gchar*) key);
123 0 : g_assert_cmpint (i, ==, n);
124 0 : keys[n] = NULL;
125 :
126 0 : return keys;
127 : }
128 :
129 : static gboolean
130 0 : g_lo_action_group_query_action (GActionGroup *group,
131 : const gchar *action_name,
132 : gboolean *enabled,
133 : const GVariantType **parameter_type,
134 : const GVariantType **state_type,
135 : GVariant **state_hint,
136 : GVariant **state)
137 : {
138 : //SAL_INFO("vcl.unity", "g_lo_action_group_query_action on " << group);
139 0 : GLOActionGroup *lo_group = G_LO_ACTION_GROUP (group);
140 : GLOAction* action;
141 :
142 0 : action = G_LO_ACTION (g_hash_table_lookup (lo_group->priv->table, action_name));
143 :
144 0 : if (action == NULL)
145 0 : return FALSE;
146 :
147 0 : if (enabled)
148 0 : *enabled = action->enabled;
149 :
150 0 : if (parameter_type)
151 0 : *parameter_type = action->parameter_type;
152 :
153 0 : if (state_type)
154 0 : *state_type = action->state_type;
155 :
156 0 : if (state_hint)
157 0 : *state_hint = (action->state_hint) ? g_variant_ref (action->state_hint) : NULL;
158 :
159 0 : if (state)
160 0 : *state = (action->state) ? g_variant_ref (action->state) : NULL;
161 :
162 0 : return TRUE;
163 : }
164 :
165 : static void
166 0 : g_lo_action_group_perform_submenu_action (GLOActionGroup *group,
167 : const gchar *action_name,
168 : GVariant *state)
169 : {
170 :
171 0 : GtkSalFrame* pFrame = group->priv->frame;
172 : SAL_INFO("vcl.unity", "g_lo_action_group_perform_submenu_action on " << group << " for frame " << pFrame);
173 :
174 0 : if (pFrame == NULL)
175 0 : return;
176 :
177 0 : GtkSalMenu* pSalMenu = static_cast<GtkSalMenu*> (pFrame->GetMenu());
178 : SAL_INFO("vcl.unity", "g_lo_action_group_perform_submenu_action on " << group << " for menu " << pSalMenu);
179 :
180 0 : if (pSalMenu != NULL) {
181 0 : gboolean bState = g_variant_get_boolean (state);
182 : SAL_INFO("vcl.unity", "g_lo_action_group_perform_submenu_action on " << group << " to " << bState);
183 :
184 0 : if (bState)
185 0 : pSalMenu->Activate();
186 : else
187 0 : pSalMenu->Deactivate (action_name);
188 : }
189 : }
190 :
191 : static void
192 0 : g_lo_action_group_change_state (GActionGroup *group,
193 : const gchar *action_name,
194 : GVariant *value)
195 : {
196 0 : g_return_if_fail (value != NULL);
197 :
198 0 : g_variant_ref_sink (value);
199 :
200 0 : if (action_name != NULL)
201 : {
202 0 : GLOActionGroup* lo_group = G_LO_ACTION_GROUP (group);
203 0 : GLOAction* action = G_LO_ACTION (g_hash_table_lookup (lo_group->priv->table, action_name));
204 :
205 0 : if (action != NULL)
206 : {
207 0 : if (action->submenu)
208 0 : g_lo_action_group_perform_submenu_action (lo_group, action_name, value);
209 : else
210 : {
211 0 : gboolean is_new = FALSE;
212 :
213 : /* If action already exists but has no state, it should be removed and added again. */
214 0 : if (action->state_type == NULL)
215 : {
216 0 : g_action_group_action_removed (G_ACTION_GROUP (group), action_name);
217 0 : action->state_type = g_variant_type_copy (g_variant_get_type(value));
218 0 : is_new = TRUE;
219 : }
220 :
221 0 : if (g_variant_is_of_type (value, action->state_type))
222 : {
223 0 : if (action->state)
224 0 : g_variant_unref(action->state);
225 :
226 0 : action->state = g_variant_ref (value);
227 :
228 0 : if (is_new)
229 0 : g_action_group_action_added (G_ACTION_GROUP (group), action_name);
230 : else
231 0 : g_action_group_action_state_changed (group, action_name, value);
232 : }
233 : }
234 : }
235 : }
236 :
237 0 : g_variant_unref (value);
238 : }
239 :
240 : static void
241 0 : g_lo_action_group_activate (GActionGroup *group,
242 : const gchar *action_name,
243 : GVariant *parameter)
244 : {
245 0 : GLOActionGroup *lo_group = G_LO_ACTION_GROUP (group);
246 0 : GtkSalFrame *pFrame = lo_group->priv->frame;
247 : SAL_INFO("vcl.unity", "g_lo_action_group_activate on group " << group << " for frame " << pFrame << " with parameter " << parameter);
248 :
249 0 : if ( parameter != NULL )
250 0 : g_action_group_change_action_state( group, action_name, parameter );
251 :
252 0 : if ( pFrame != NULL )
253 : {
254 0 : GtkSalMenu* pSalMenu = static_cast< GtkSalMenu* >( pFrame->GetMenu() );
255 : SAL_INFO("vcl.unity", "g_lo_action_group_activate for menu " << pSalMenu);
256 :
257 0 : if ( pSalMenu != NULL )
258 : {
259 0 : GLOAction* action = G_LO_ACTION (g_hash_table_lookup (lo_group->priv->table, action_name));
260 : SAL_INFO("vcl.unity", "g_lo_action_group_activate dispatching action " << action << " named " << action_name << " on menu " << pSalMenu);
261 0 : pSalMenu->DispatchCommand( action->item_id, action_name );
262 : }
263 : }
264 0 : }
265 :
266 : void
267 0 : g_lo_action_group_insert (GLOActionGroup *group,
268 : const gchar *action_name,
269 : gint item_id,
270 : gboolean submenu)
271 : {
272 0 : g_lo_action_group_insert_stateful (group, action_name, item_id, submenu, NULL, NULL, NULL, NULL);
273 0 : }
274 :
275 : void
276 0 : g_lo_action_group_insert_stateful (GLOActionGroup *group,
277 : const gchar *action_name,
278 : gint item_id,
279 : gboolean submenu,
280 : const GVariantType *parameter_type,
281 : const GVariantType *state_type,
282 : GVariant *state_hint,
283 : GVariant *state)
284 : {
285 0 : g_return_if_fail (G_IS_LO_ACTION_GROUP (group));
286 :
287 0 : GLOAction* old_action = G_LO_ACTION (g_hash_table_lookup (group->priv->table, action_name));
288 :
289 0 : if (old_action == NULL || old_action->item_id != item_id)
290 : {
291 0 : if (old_action != NULL)
292 0 : g_lo_action_group_remove (group, action_name);
293 : // g_action_group_action_removed (G_ACTION_GROUP (group), action_name);
294 :
295 0 : GLOAction* action = g_lo_action_new();
296 :
297 0 : g_hash_table_insert (group->priv->table, g_strdup (action_name), action);
298 :
299 0 : action->item_id = item_id;
300 0 : action->submenu = submenu;
301 :
302 0 : if (parameter_type)
303 0 : action->parameter_type = (GVariantType*) parameter_type;
304 :
305 0 : if (state_type)
306 0 : action->state_type = (GVariantType*) state_type;
307 :
308 0 : if (state_hint)
309 0 : action->state_hint = g_variant_ref_sink (state_hint);
310 :
311 0 : if (state)
312 0 : action->state = g_variant_ref_sink (state);
313 :
314 0 : g_action_group_action_added (G_ACTION_GROUP (group), action_name);
315 : }
316 : }
317 :
318 : static void
319 0 : g_lo_action_group_finalize (GObject *object)
320 : {
321 0 : GLOActionGroup *lo_group = G_LO_ACTION_GROUP (object);
322 :
323 0 : g_hash_table_unref (lo_group->priv->table);
324 :
325 0 : G_OBJECT_CLASS (g_lo_action_group_parent_class)->finalize (object);
326 0 : }
327 :
328 : static void
329 0 : g_lo_action_group_init (GLOActionGroup *group)
330 : {
331 : SAL_INFO("vcl.unity", "g_lo_action_group_init on " << group);
332 0 : group->priv = G_TYPE_INSTANCE_GET_PRIVATE (group,
333 : G_TYPE_LO_ACTION_GROUP,
334 0 : GLOActionGroupPrivate);
335 : group->priv->table = g_hash_table_new_full (g_str_hash, g_str_equal,
336 0 : g_free, g_object_unref);
337 0 : group->priv->frame = NULL;
338 0 : }
339 :
340 : static void
341 0 : g_lo_action_group_class_init (GLOActionGroupClass *klass)
342 : {
343 0 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
344 :
345 0 : object_class->finalize = g_lo_action_group_finalize;
346 :
347 0 : g_type_class_add_private (klass, sizeof (GLOActionGroupPrivate));
348 0 : }
349 :
350 : static void
351 0 : g_lo_action_group_iface_init (GActionGroupInterface *iface)
352 : {
353 0 : iface->list_actions = g_lo_action_group_list_actions;
354 0 : iface->query_action = g_lo_action_group_query_action;
355 0 : iface->change_action_state = g_lo_action_group_change_state;
356 0 : iface->activate_action = g_lo_action_group_activate;
357 0 : }
358 :
359 : GLOActionGroup *
360 0 : g_lo_action_group_new (gpointer frame)
361 : {
362 0 : GLOActionGroup* group = G_LO_ACTION_GROUP (g_object_new (G_TYPE_LO_ACTION_GROUP, NULL));
363 0 : group->priv->frame = static_cast< GtkSalFrame* > (frame);
364 :
365 0 : return group;
366 : }
367 :
368 : void
369 0 : g_lo_action_group_set_action_enabled (GLOActionGroup *group,
370 : const gchar *action_name,
371 : gboolean enabled)
372 : {
373 : SAL_INFO("vcl.unity", "g_lo_action_group_set_action_enabled on " << group);
374 0 : g_return_if_fail (G_IS_LO_ACTION_GROUP (group));
375 0 : g_return_if_fail (action_name != NULL);
376 :
377 0 : GLOAction* action = G_LO_ACTION (g_hash_table_lookup (group->priv->table, action_name));
378 :
379 0 : if (action == NULL)
380 0 : return;
381 :
382 0 : action->enabled = enabled;
383 :
384 0 : g_action_group_action_enabled_changed (G_ACTION_GROUP (group), action_name, enabled);
385 : }
386 :
387 : void
388 0 : g_lo_action_group_remove (GLOActionGroup *group,
389 : const gchar *action_name)
390 : {
391 : SAL_INFO("vcl.unity", "g_lo_action_group_remove on " << group);
392 0 : g_return_if_fail (G_IS_LO_ACTION_GROUP (group));
393 :
394 0 : if (action_name != NULL)
395 : {
396 0 : g_action_group_action_removed (G_ACTION_GROUP (group), action_name);
397 0 : g_hash_table_remove (group->priv->table, action_name);
398 : }
399 : }
400 :
401 : void
402 0 : g_lo_action_group_clear (GLOActionGroup *group)
403 : {
404 : SAL_INFO("vcl.unity", "g_lo_action_group_clear on " << group);
405 0 : g_return_if_fail (G_IS_LO_ACTION_GROUP (group));
406 :
407 0 : GList* keys = g_hash_table_get_keys (group->priv->table);
408 :
409 0 : for (GList* element = g_list_first (keys); element != NULL; element = g_list_next (element))
410 : {
411 0 : g_lo_action_group_remove (group, (gchar*) element->data);
412 : }
413 0 : }
414 :
415 : #endif
416 :
417 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|