1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
13 #include <unx/gtk/gtksalmenu.hxx>
15 #ifdef ENABLE_GMENU_INTEGRATION
17 #include <unx/gtk/glomenu.h>
21 GMenuModel parent_instance
;
26 typedef GMenuModelClass GLOMenuClass
;
29 #pragma GCC diagnostic push
30 #pragma GCC diagnostic ignored "-Wunused-function"
32 G_DEFINE_TYPE (GLOMenu
, g_lo_menu
, G_TYPE_MENU_MODEL
);
34 #pragma GCC diagnostic pop
39 GHashTable
* attributes
; // Item attributes.
40 GHashTable
* links
; // Item links.
44 g_lo_menu_struct_item_init (struct item
*menu_item
)
46 menu_item
->attributes
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, reinterpret_cast<GDestroyNotify
>(g_variant_unref
));
47 menu_item
->links
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_object_unref
);
50 /* We treat attribute names the same as GSettings keys:
51 * - only lowercase ascii, digits and '-'
52 * - must start with lowercase
53 * - must not end with '-'
54 * - no consecutive '-'
55 * - not longer than 1024 chars
58 valid_attribute_name (const gchar
*name
)
62 if (!g_ascii_islower (name
[0]))
65 for (i
= 1; name
[i
]; i
++)
68 !g_ascii_islower (name
[i
]) &&
69 !g_ascii_isdigit (name
[i
]))
72 if (name
[i
] == '-' && name
[i
+ 1] == '-')
76 if (name
[i
- 1] == '-')
90 g_lo_menu_is_mutable (GMenuModel
*)
92 // Menu is always mutable.
97 g_lo_menu_get_n_items (GMenuModel
*model
)
99 g_return_val_if_fail (model
!= NULL
, 0);
100 GLOMenu
*menu
= G_LO_MENU (model
);
101 g_return_val_if_fail (menu
->items
!= NULL
, 0);
103 return menu
->items
->len
;
107 g_lo_menu_get_n_items_from_section (GLOMenu
*menu
,
110 g_return_val_if_fail (0 <= section
&& section
< (gint
) menu
->items
->len
, 0);
112 GLOMenu
*model
= g_lo_menu_get_section (menu
, section
);
114 g_return_val_if_fail (model
!= NULL
, 0);
116 gint length
= model
->items
->len
;
118 g_object_unref (model
);
124 g_lo_menu_get_item_attributes (GMenuModel
*model
,
128 GLOMenu
*menu
= G_LO_MENU (model
);
129 *table
= g_hash_table_ref (g_array_index (menu
->items
, struct item
, position
).attributes
);
133 g_lo_menu_get_item_links (GMenuModel
*model
,
137 GLOMenu
*menu
= G_LO_MENU (model
);
138 *table
= g_hash_table_ref (g_array_index (menu
->items
, struct item
, position
).links
);
142 g_lo_menu_insert (GLOMenu
*menu
,
146 g_lo_menu_insert_section (menu
, position
, label
, NULL
);
150 g_lo_menu_insert_in_section (GLOMenu
*menu
,
155 g_return_if_fail (G_IS_LO_MENU (menu
));
156 g_return_if_fail (0 <= section
&& section
< (gint
) menu
->items
->len
);
158 GLOMenu
*model
= g_lo_menu_get_section (menu
, section
);
160 g_return_if_fail (model
!= NULL
);
162 g_lo_menu_insert (model
, position
, label
);
164 g_object_unref (model
);
170 return G_LO_MENU( g_object_new (G_TYPE_LO_MENU
, NULL
) );
174 g_lo_menu_set_attribute_value (GLOMenu
*menu
,
176 const gchar
*attribute
,
179 g_return_if_fail (G_IS_LO_MENU (menu
));
180 g_return_if_fail (attribute
!= NULL
);
181 g_return_if_fail (valid_attribute_name (attribute
));
183 if (position
>= (gint
) menu
->items
->len
)
186 struct item menu_item
= g_array_index (menu
->items
, struct item
, position
);
189 g_hash_table_insert (menu_item
.attributes
, g_strdup (attribute
), g_variant_ref_sink (value
));
191 g_hash_table_remove (menu_item
.attributes
, attribute
);
195 g_lo_menu_get_attribute_value_from_item_in_section (GLOMenu
*menu
,
198 const gchar
*attribute
,
199 const GVariantType
*type
)
201 GMenuModel
*model
= G_MENU_MODEL (g_lo_menu_get_section (menu
, section
));
203 g_return_val_if_fail (model
!= NULL
, NULL
);
205 GVariant
*value
= g_menu_model_get_item_attribute_value (model
,
210 g_object_unref (model
);
216 g_lo_menu_set_label (GLOMenu
*menu
,
220 g_return_if_fail (G_IS_LO_MENU (menu
));
225 value
= g_variant_new_string (label
);
229 g_lo_menu_set_attribute_value (menu
, position
, G_MENU_ATTRIBUTE_LABEL
, value
);
233 g_lo_menu_set_label_to_item_in_section (GLOMenu
*menu
,
238 g_return_if_fail (G_IS_LO_MENU (menu
));
240 GLOMenu
*model
= g_lo_menu_get_section (menu
, section
);
242 g_return_if_fail (model
!= NULL
);
244 g_lo_menu_set_label (model
, position
, label
);
246 // Notify the update.
247 g_menu_model_items_changed (G_MENU_MODEL (model
), position
, 1, 1);
249 g_object_unref (model
);
253 g_lo_menu_get_label_from_item_in_section (GLOMenu
*menu
,
257 g_return_val_if_fail (G_IS_LO_MENU (menu
), NULL
);
259 GVariant
*label_value
= g_lo_menu_get_attribute_value_from_item_in_section (menu
,
262 G_MENU_ATTRIBUTE_LABEL
,
263 G_VARIANT_TYPE_STRING
);
269 label
= g_variant_dup_string (label_value
, NULL
);
270 g_variant_unref (label_value
);
277 g_lo_menu_set_action_and_target_value (GLOMenu
*menu
,
280 GVariant
*target_value
)
282 g_return_if_fail (G_IS_LO_MENU (menu
));
284 GVariant
*action_value
;
288 action_value
= g_variant_new_string (action
);
296 g_lo_menu_set_attribute_value (menu
, position
, G_MENU_ATTRIBUTE_ACTION
, action_value
);
297 g_lo_menu_set_attribute_value (menu
, position
, G_MENU_ATTRIBUTE_TARGET
, target_value
);
299 g_menu_model_items_changed (G_MENU_MODEL (menu
), position
, 1, 1);
303 g_lo_menu_set_action_and_target_value_to_item_in_section (GLOMenu
*menu
,
306 const gchar
*command
,
307 GVariant
*target_value
)
309 g_return_if_fail (G_IS_LO_MENU (menu
));
311 GLOMenu
*model
= g_lo_menu_get_section (menu
, section
);
313 g_return_if_fail (model
!= NULL
);
315 g_lo_menu_set_action_and_target_value (model
, position
, command
, target_value
);
317 g_object_unref (model
);
321 g_lo_menu_set_accelerator_to_item_in_section (GLOMenu
*menu
,
324 const gchar
*accelerator
)
326 g_return_if_fail (G_IS_LO_MENU (menu
));
328 GLOMenu
*model
= g_lo_menu_get_section (menu
, section
);
330 g_return_if_fail (model
!= NULL
);
334 if (accelerator
!= NULL
)
335 value
= g_variant_new_string (accelerator
);
339 g_lo_menu_set_attribute_value (model
, position
, G_LO_MENU_ATTRIBUTE_ACCELERATOR
, value
);
341 // Notify the update.
342 g_menu_model_items_changed (G_MENU_MODEL (model
), position
, 1, 1);
344 g_object_unref (model
);
348 g_lo_menu_get_accelerator_from_item_in_section (GLOMenu
*menu
,
352 g_return_val_if_fail (G_IS_LO_MENU (menu
), NULL
);
354 GVariant
*accel_value
= g_lo_menu_get_attribute_value_from_item_in_section (menu
,
357 G_LO_MENU_ATTRIBUTE_ACCELERATOR
,
358 G_VARIANT_TYPE_STRING
);
362 if (accel_value
!= NULL
)
364 accel
= g_variant_dup_string (accel_value
, NULL
);
365 g_variant_unref (accel_value
);
372 g_lo_menu_set_command_to_item_in_section (GLOMenu
*menu
,
375 const gchar
*command
)
377 g_return_if_fail (G_IS_LO_MENU (menu
));
379 GLOMenu
*model
= g_lo_menu_get_section (menu
, section
);
381 g_return_if_fail (model
!= NULL
);
386 value
= g_variant_new_string (command
);
390 g_lo_menu_set_attribute_value (model
, position
, G_LO_MENU_ATTRIBUTE_COMMAND
, value
);
392 // Notify the update.
393 g_menu_model_items_changed (G_MENU_MODEL (model
), position
, 1, 1);
395 g_object_unref (model
);
399 g_lo_menu_get_command_from_item_in_section (GLOMenu
*menu
,
403 g_return_val_if_fail (G_IS_LO_MENU (menu
), NULL
);
405 GVariant
*command_value
= g_lo_menu_get_attribute_value_from_item_in_section (menu
,
408 G_LO_MENU_ATTRIBUTE_COMMAND
,
409 G_VARIANT_TYPE_STRING
);
411 gchar
*command
= NULL
;
413 if (command_value
!= NULL
)
415 command
= g_variant_dup_string (command_value
, NULL
);
416 g_variant_unref (command_value
);
423 g_lo_menu_set_link (GLOMenu
*menu
,
428 g_return_if_fail (G_IS_LO_MENU (menu
));
429 g_return_if_fail (link
!= NULL
);
430 g_return_if_fail (valid_attribute_name (link
));
432 if (position
< 0 || position
>= (gint
) menu
->items
->len
)
433 position
= menu
->items
->len
- 1;
435 struct item menu_item
= g_array_index (menu
->items
, struct item
, position
);
438 g_hash_table_insert (menu_item
.links
, g_strdup (link
), g_object_ref (model
));
440 g_hash_table_remove (menu_item
.links
, link
);
444 g_lo_menu_insert_section (GLOMenu
*menu
,
449 g_return_if_fail (G_IS_LO_MENU (menu
));
451 if (position
< 0 || position
> (gint
) menu
->items
->len
)
452 position
= menu
->items
->len
;
454 struct item menu_item
;
456 g_lo_menu_struct_item_init(&menu_item
);
458 g_array_insert_val (menu
->items
, position
, menu_item
);
460 g_lo_menu_set_label (menu
, position
, label
);
461 g_lo_menu_set_link (menu
, position
, G_MENU_LINK_SECTION
, section
);
463 g_menu_model_items_changed (G_MENU_MODEL (menu
), position
, 0, 1);
467 g_lo_menu_new_section (GLOMenu
*menu
,
471 GMenuModel
*section
= G_MENU_MODEL (g_lo_menu_new());
473 g_lo_menu_insert_section (menu
, position
, label
, section
);
475 g_object_unref (section
);
479 g_lo_menu_get_section (GLOMenu
*menu
,
482 g_return_val_if_fail (G_IS_LO_MENU (menu
), NULL
);
484 return G_LO_MENU (G_MENU_MODEL_CLASS (g_lo_menu_parent_class
)
485 ->get_item_link (G_MENU_MODEL (menu
), section
, G_MENU_LINK_SECTION
));
489 g_lo_menu_new_submenu_in_item_in_section (GLOMenu
*menu
,
493 g_return_if_fail (G_IS_LO_MENU (menu
));
494 g_return_if_fail (0 <= section
&& section
< (gint
) menu
->items
->len
);
496 GLOMenu
* model
= g_lo_menu_get_section (menu
, section
);
498 g_return_if_fail (model
!= NULL
);
500 if (0 <= position
&& position
< (gint
) model
->items
->len
) {
501 GMenuModel
* submenu
= G_MENU_MODEL (g_lo_menu_new());
503 g_lo_menu_set_link (model
, position
, G_MENU_LINK_SUBMENU
, submenu
);
505 g_object_unref (submenu
);
507 g_menu_model_items_changed (G_MENU_MODEL (model
), position
, 1, 1);
509 g_object_unref (model
);
514 g_lo_menu_set_submenu_to_item_in_section (GLOMenu
*menu
,
519 g_return_if_fail (G_IS_LO_MENU (menu
));
520 g_return_if_fail (0 <= section
&& section
< (gint
) menu
->items
->len
);
522 GLOMenu
*model
= g_lo_menu_get_section (menu
, section
);
524 g_return_if_fail (model
!= NULL
);
526 g_lo_menu_set_link (model
, position
, G_MENU_LINK_SUBMENU
, submenu
);
528 // Notify the update.
529 g_menu_model_items_changed (G_MENU_MODEL (model
), position
, 1, 1);
531 g_object_unref (model
);
535 g_lo_menu_get_submenu_from_item_in_section (GLOMenu
*menu
,
539 g_return_val_if_fail (G_IS_LO_MENU (menu
), NULL
);
540 g_return_val_if_fail (0 <= section
&& section
< (gint
) menu
->items
->len
, NULL
);
542 GLOMenu
*model
= g_lo_menu_get_section (menu
, section
);
544 g_return_val_if_fail (model
!= NULL
, NULL
);
546 GLOMenu
*submenu
= NULL
;
548 if (0 <= position
&& position
< (gint
) model
->items
->len
)
549 submenu
= G_LO_MENU (G_MENU_MODEL_CLASS (g_lo_menu_parent_class
)
550 ->get_item_link (G_MENU_MODEL (model
), position
, G_MENU_LINK_SUBMENU
));
551 //submenu = g_menu_model_get_item_link (G_MENU_MODEL (model), position, G_MENU_LINK_SUBMENU);
553 g_object_unref (model
);
559 g_lo_menu_set_submenu_action_to_item_in_section (GLOMenu
*menu
,
564 g_return_if_fail (G_IS_LO_MENU (menu
));
566 GMenuModel
*model
= G_MENU_MODEL (g_lo_menu_get_section (menu
, section
));
568 g_return_if_fail (model
!= NULL
);
573 value
= g_variant_new_string (action
);
577 g_lo_menu_set_attribute_value (G_LO_MENU (model
), position
, G_LO_MENU_ATTRIBUTE_SUBMENU_ACTION
, value
);
579 // Notify the update.
580 g_menu_model_items_changed (model
, position
, 1, 1);
582 g_object_unref (model
);
586 g_lo_menu_clear_item (struct item
*menu_item
)
588 if (menu_item
->attributes
!= NULL
)
589 g_hash_table_unref (menu_item
->attributes
);
590 if (menu_item
->links
!= NULL
)
591 g_hash_table_unref (menu_item
->links
);
595 g_lo_menu_remove (GLOMenu
*menu
,
598 g_return_if_fail (G_IS_LO_MENU (menu
));
599 g_return_if_fail (0 <= position
&& position
< (gint
) menu
->items
->len
);
601 g_lo_menu_clear_item (&g_array_index (menu
->items
, struct item
, position
));
602 g_array_remove_index (menu
->items
, position
);
603 g_menu_model_items_changed (G_MENU_MODEL (menu
), position
, 1, 0);
607 g_lo_menu_remove_from_section (GLOMenu
*menu
,
611 g_return_if_fail (G_IS_LO_MENU (menu
));
612 g_return_if_fail (0 <= section
&& section
< (gint
) menu
->items
->len
);
614 GLOMenu
*model
= g_lo_menu_get_section (menu
, section
);
616 g_return_if_fail (model
!= NULL
);
618 g_lo_menu_remove (model
, position
);
620 g_object_unref (model
);
624 g_lo_menu_finalize (GObject
*object
)
626 GLOMenu
*menu
= G_LO_MENU (object
);
631 n_items
= menu
->items
->len
;
632 items
= reinterpret_cast<struct item
*>(g_array_free (menu
->items
, FALSE
));
633 for (i
= 0; i
< n_items
; i
++)
634 g_lo_menu_clear_item (&items
[i
]);
637 G_OBJECT_CLASS (g_lo_menu_parent_class
)
642 g_lo_menu_init (GLOMenu
*menu
)
644 menu
->items
= g_array_new (FALSE
, FALSE
, sizeof (struct item
));
648 g_lo_menu_class_init (GLOMenuClass
*klass
)
650 GMenuModelClass
*model_class
= G_MENU_MODEL_CLASS (klass
);
651 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
653 object_class
->finalize
= g_lo_menu_finalize
;
655 model_class
->is_mutable
= g_lo_menu_is_mutable
;
656 model_class
->get_n_items
= g_lo_menu_get_n_items
;
657 model_class
->get_item_attributes
= g_lo_menu_get_item_attributes
;
658 model_class
->get_item_links
= g_lo_menu_get_item_links
;
663 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */