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