nss: upgrade to release 3.73
[LibreOffice.git] / vcl / unx / gtk3 / gtk3glomenu.cxx
blobca6887cb9d9589de85753cd57559fb7313e0bdd7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <unx/gtk/glomenu.h>
12 struct GLOMenu
14 GMenuModel const parent_instance;
16 GArray *items;
19 typedef GMenuModelClass GLOMenuClass;
21 #ifdef __GNUC__
22 #pragma GCC diagnostic push
23 #pragma GCC diagnostic ignored "-Wunused-function"
24 #if defined __clang__
25 #if __has_warning("-Wdeprecated-volatile")
26 #pragma clang diagnostic ignored "-Wdeprecated-volatile"
27 #endif
28 #endif
29 #endif
30 G_DEFINE_TYPE (GLOMenu, g_lo_menu, G_TYPE_MENU_MODEL);
31 #ifdef __GNUC__
32 #pragma GCC diagnostic pop
33 #endif
35 namespace {
37 struct item
39 GHashTable* attributes; // Item attributes.
40 GHashTable* links; // Item links.
45 static void
46 g_lo_menu_struct_item_init (struct item *menu_item)
48 menu_item->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, reinterpret_cast<GDestroyNotify>(g_variant_unref));
49 menu_item->links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
52 /* We treat attribute names the same as GSettings keys:
53 * - only lowercase ascii, digits and '-'
54 * - must start with lowercase
55 * - must not end with '-'
56 * - no consecutive '-'
57 * - not longer than 1024 chars
59 static bool
60 valid_attribute_name (const gchar *name)
62 gint i;
64 if (!g_ascii_islower (name[0]))
65 return false;
67 for (i = 1; name[i]; i++)
69 if (name[i] != '-' &&
70 !g_ascii_islower (name[i]) &&
71 !g_ascii_isdigit (name[i]))
72 return false;
74 if (name[i] == '-' && name[i + 1] == '-')
75 return false;
78 if (name[i - 1] == '-')
79 return false;
81 if (i > 1024)
82 return false;
84 return true;
88 * GLOMenu
91 static gboolean
92 g_lo_menu_is_mutable (GMenuModel*)
94 // Menu is always mutable.
95 return true;
98 static gint
99 g_lo_menu_get_n_items (GMenuModel *model)
101 g_return_val_if_fail (model != nullptr, 0);
102 GLOMenu *menu = G_LO_MENU (model);
103 g_return_val_if_fail (menu->items != nullptr, 0);
105 return menu->items->len;
108 gint
109 g_lo_menu_get_n_items_from_section (GLOMenu *menu,
110 gint section)
112 g_return_val_if_fail (0 <= section && section < static_cast<gint>(menu->items->len), 0);
114 GLOMenu *model = g_lo_menu_get_section (menu, section);
116 g_return_val_if_fail (model != nullptr, 0);
118 gint length = model->items->len;
120 g_object_unref (model);
122 return length;
125 static void
126 g_lo_menu_get_item_attributes (GMenuModel *model,
127 gint position,
128 GHashTable **table)
130 GLOMenu *menu = G_LO_MENU (model);
131 *table = g_hash_table_ref (g_array_index (menu->items, struct item, position).attributes);
134 static void
135 g_lo_menu_get_item_links (GMenuModel *model,
136 gint position,
137 GHashTable **table)
139 GLOMenu *menu = G_LO_MENU (model);
140 *table = g_hash_table_ref (g_array_index (menu->items, struct item, position).links);
143 void
144 g_lo_menu_insert (GLOMenu *menu,
145 gint position,
146 const gchar *label)
148 g_lo_menu_insert_section (menu, position, label, nullptr);
151 void
152 g_lo_menu_insert_in_section (GLOMenu *menu,
153 gint section,
154 gint position,
155 const gchar *label)
157 g_return_if_fail (G_IS_LO_MENU (menu));
158 g_return_if_fail (0 <= section && section < static_cast<gint>(menu->items->len));
160 GLOMenu *model = g_lo_menu_get_section (menu, section);
162 g_return_if_fail (model != nullptr);
164 g_lo_menu_insert (model, position, label);
166 g_object_unref (model);
169 GLOMenu *
170 g_lo_menu_new()
172 return G_LO_MENU( g_object_new (G_TYPE_LO_MENU, nullptr) );
175 static void
176 g_lo_menu_set_attribute_value (GLOMenu *menu,
177 gint position,
178 const gchar *attribute,
179 GVariant *value)
181 g_return_if_fail (G_IS_LO_MENU (menu));
182 g_return_if_fail (attribute != nullptr);
183 g_return_if_fail (valid_attribute_name (attribute));
185 if (position >= static_cast<gint>(menu->items->len))
186 return;
188 struct item menu_item = g_array_index (menu->items, struct item, position);
190 if (value != nullptr)
191 g_hash_table_insert (menu_item.attributes, g_strdup (attribute), g_variant_ref_sink (value));
192 else
193 g_hash_table_remove (menu_item.attributes, attribute);
196 static GVariant*
197 g_lo_menu_get_attribute_value_from_item_in_section (GLOMenu *menu,
198 gint section,
199 gint position,
200 const gchar *attribute,
201 const GVariantType *type)
203 GMenuModel *model = G_MENU_MODEL (g_lo_menu_get_section (menu, section));
205 g_return_val_if_fail (model != nullptr, nullptr);
207 GVariant *value = g_menu_model_get_item_attribute_value (model,
208 position,
209 attribute,
210 type);
212 g_object_unref (model);
214 return value;
217 void
218 g_lo_menu_set_label (GLOMenu *menu,
219 gint position,
220 const gchar *label)
222 g_return_if_fail (G_IS_LO_MENU (menu));
224 GVariant *value;
226 if (label != nullptr)
227 value = g_variant_new_string (label);
228 else
229 value = nullptr;
231 g_lo_menu_set_attribute_value (menu, position, G_MENU_ATTRIBUTE_LABEL, value);
234 void
235 g_lo_menu_set_icon (GLOMenu *menu,
236 gint position,
237 const GIcon *icon)
239 g_return_if_fail (G_IS_LO_MENU (menu));
241 GVariant *value;
243 if (icon != nullptr)
245 #if GLIB_CHECK_VERSION(2,38,0)
246 value = g_icon_serialize (const_cast<GIcon*>(icon));
247 #else
248 value = nullptr;
249 #endif
251 else
252 value = nullptr;
254 #ifndef G_MENU_ATTRIBUTE_ICON
255 # define G_MENU_ATTRIBUTE_ICON "icon"
256 #endif
258 g_lo_menu_set_attribute_value (menu, position, G_MENU_ATTRIBUTE_ICON, value);
259 if (value)
260 g_variant_unref (value);
263 void
264 g_lo_menu_set_label_to_item_in_section (GLOMenu *menu,
265 gint section,
266 gint position,
267 const gchar *label)
269 g_return_if_fail (G_IS_LO_MENU (menu));
271 GLOMenu *model = g_lo_menu_get_section (menu, section);
273 g_return_if_fail (model != nullptr);
275 g_lo_menu_set_label (model, position, label);
277 // Notify the update.
278 g_menu_model_items_changed (G_MENU_MODEL (model), position, 1, 1);
280 g_object_unref (model);
283 void
284 g_lo_menu_set_icon_to_item_in_section (GLOMenu *menu,
285 gint section,
286 gint position,
287 const GIcon *icon)
289 g_return_if_fail (G_IS_LO_MENU (menu));
291 GLOMenu *model = g_lo_menu_get_section (menu, section);
293 g_return_if_fail (model != nullptr);
295 g_lo_menu_set_icon (model, position, icon);
297 // Notify the update.
298 g_menu_model_items_changed (G_MENU_MODEL (model), position, 1, 1);
300 g_object_unref (model);
303 gchar *
304 g_lo_menu_get_label_from_item_in_section (GLOMenu *menu,
305 gint section,
306 gint position)
308 g_return_val_if_fail (G_IS_LO_MENU (menu), nullptr);
310 GVariant *label_value = g_lo_menu_get_attribute_value_from_item_in_section (menu,
311 section,
312 position,
313 G_MENU_ATTRIBUTE_LABEL,
314 G_VARIANT_TYPE_STRING);
316 gchar *label = nullptr;
318 if (label_value)
320 label = g_variant_dup_string (label_value, nullptr);
321 g_variant_unref (label_value);
324 return label;
327 void
328 g_lo_menu_set_action_and_target_value (GLOMenu *menu,
329 gint position,
330 const gchar *action,
331 GVariant *target_value)
333 g_return_if_fail (G_IS_LO_MENU (menu));
335 GVariant *action_value;
337 if (action != nullptr)
339 action_value = g_variant_new_string (action);
341 else
343 action_value = nullptr;
344 target_value = nullptr;
347 g_lo_menu_set_attribute_value (menu, position, G_MENU_ATTRIBUTE_ACTION, action_value);
348 g_lo_menu_set_attribute_value (menu, position, G_MENU_ATTRIBUTE_TARGET, target_value);
349 g_lo_menu_set_attribute_value (menu, position, G_LO_MENU_ATTRIBUTE_SUBMENU_ACTION, nullptr);
351 g_menu_model_items_changed (G_MENU_MODEL (menu), position, 1, 1);
354 void
355 g_lo_menu_set_action_and_target_value_to_item_in_section (GLOMenu *menu,
356 gint section,
357 gint position,
358 const gchar *command,
359 GVariant *target_value)
361 g_return_if_fail (G_IS_LO_MENU (menu));
363 GLOMenu *model = g_lo_menu_get_section (menu, section);
365 g_return_if_fail (model != nullptr);
367 g_lo_menu_set_action_and_target_value (model, position, command, target_value);
369 g_object_unref (model);
372 void
373 g_lo_menu_set_accelerator_to_item_in_section (GLOMenu *menu,
374 gint section,
375 gint position,
376 const gchar *accelerator)
378 g_return_if_fail (G_IS_LO_MENU (menu));
380 GLOMenu *model = g_lo_menu_get_section (menu, section);
382 g_return_if_fail (model != nullptr);
384 GVariant *value;
386 if (accelerator != nullptr)
387 value = g_variant_new_string (accelerator);
388 else
389 value = nullptr;
391 g_lo_menu_set_attribute_value (model, position, G_LO_MENU_ATTRIBUTE_ACCELERATOR, value);
393 // Notify the update.
394 g_menu_model_items_changed (G_MENU_MODEL (model), position, 1, 1);
396 g_object_unref (model);
399 gchar *
400 g_lo_menu_get_accelerator_from_item_in_section (GLOMenu *menu,
401 gint section,
402 gint position)
404 g_return_val_if_fail (G_IS_LO_MENU (menu), nullptr);
406 GVariant *accel_value = g_lo_menu_get_attribute_value_from_item_in_section (menu,
407 section,
408 position,
409 G_LO_MENU_ATTRIBUTE_ACCELERATOR,
410 G_VARIANT_TYPE_STRING);
412 gchar *accel = nullptr;
414 if (accel_value != nullptr)
416 accel = g_variant_dup_string (accel_value, nullptr);
417 g_variant_unref (accel_value);
420 return accel;
423 void
424 g_lo_menu_set_command_to_item_in_section (GLOMenu *menu,
425 gint section,
426 gint position,
427 const gchar *command)
429 g_return_if_fail (G_IS_LO_MENU (menu));
431 GLOMenu *model = g_lo_menu_get_section (menu, section);
433 g_return_if_fail (model != nullptr);
435 GVariant *value;
437 if (command != nullptr)
438 value = g_variant_new_string (command);
439 else
440 value = nullptr;
442 g_lo_menu_set_attribute_value (model, position, G_LO_MENU_ATTRIBUTE_COMMAND, value);
444 // Notify the update.
445 g_menu_model_items_changed (G_MENU_MODEL (model), position, 1, 1);
447 g_object_unref (model);
450 gchar *
451 g_lo_menu_get_command_from_item_in_section (GLOMenu *menu,
452 gint section,
453 gint position)
455 g_return_val_if_fail (G_IS_LO_MENU (menu), nullptr);
457 GVariant *command_value = g_lo_menu_get_attribute_value_from_item_in_section (menu,
458 section,
459 position,
460 G_LO_MENU_ATTRIBUTE_COMMAND,
461 G_VARIANT_TYPE_STRING);
463 gchar *command = nullptr;
465 if (command_value != nullptr)
467 command = g_variant_dup_string (command_value, nullptr);
468 g_variant_unref (command_value);
471 return command;
474 static void
475 g_lo_menu_set_link (GLOMenu *menu,
476 gint position,
477 const gchar *link,
478 GMenuModel *model)
480 g_return_if_fail (G_IS_LO_MENU (menu));
481 g_return_if_fail (link != nullptr);
482 g_return_if_fail (valid_attribute_name (link));
484 if (position < 0 || position >= static_cast<gint>(menu->items->len))
485 position = menu->items->len - 1;
487 struct item menu_item = g_array_index (menu->items, struct item, position);
489 if (model != nullptr)
490 g_hash_table_insert (menu_item.links, g_strdup (link), g_object_ref (model));
491 else
492 g_hash_table_remove (menu_item.links, link);
495 void
496 g_lo_menu_insert_section (GLOMenu *menu,
497 gint position,
498 const gchar *label,
499 GMenuModel *section)
501 g_return_if_fail (G_IS_LO_MENU (menu));
503 if (position < 0 || position > static_cast<gint>(menu->items->len))
504 position = menu->items->len;
506 struct item menu_item;
508 g_lo_menu_struct_item_init(&menu_item);
510 g_array_insert_val (menu->items, position, menu_item);
512 g_lo_menu_set_label (menu, position, label);
513 g_lo_menu_set_link (menu, position, G_MENU_LINK_SECTION, section);
515 g_menu_model_items_changed (G_MENU_MODEL (menu), position, 0, 1);
518 void
519 g_lo_menu_new_section (GLOMenu *menu,
520 gint position,
521 const gchar *label)
523 GMenuModel *section = G_MENU_MODEL (g_lo_menu_new());
525 g_lo_menu_insert_section (menu, position, label, section);
527 g_object_unref (section);
530 GLOMenu *
531 g_lo_menu_get_section (GLOMenu *menu,
532 gint section)
534 g_return_val_if_fail (G_IS_LO_MENU (menu), nullptr);
536 return G_LO_MENU (G_MENU_MODEL_CLASS (g_lo_menu_parent_class)
537 ->get_item_link (G_MENU_MODEL (menu), section, G_MENU_LINK_SECTION));
540 void
541 g_lo_menu_new_submenu_in_item_in_section (GLOMenu *menu,
542 gint section,
543 gint position)
545 g_return_if_fail (G_IS_LO_MENU (menu));
546 g_return_if_fail (0 <= section && section < static_cast<gint>(menu->items->len));
548 GLOMenu* model = g_lo_menu_get_section (menu, section);
550 g_return_if_fail (model != nullptr);
552 if (0 <= position && position < static_cast<gint>(model->items->len)) {
553 GMenuModel* submenu = G_MENU_MODEL (g_lo_menu_new());
555 g_lo_menu_set_link (model, position, G_MENU_LINK_SUBMENU, submenu);
557 g_object_unref (submenu);
559 g_menu_model_items_changed (G_MENU_MODEL (model), position, 1, 1);
561 g_object_unref (model);
565 GLOMenu *
566 g_lo_menu_get_submenu_from_item_in_section (GLOMenu *menu,
567 gint section,
568 gint position)
570 g_return_val_if_fail (G_IS_LO_MENU (menu), nullptr);
571 g_return_val_if_fail (0 <= section && section < static_cast<gint>(menu->items->len), nullptr);
573 GLOMenu *model = g_lo_menu_get_section (menu, section);
575 g_return_val_if_fail (model != nullptr, nullptr);
577 GLOMenu *submenu = nullptr;
579 if (0 <= position && position < static_cast<gint>(model->items->len))
580 submenu = G_LO_MENU (G_MENU_MODEL_CLASS (g_lo_menu_parent_class)
581 ->get_item_link (G_MENU_MODEL (model), position, G_MENU_LINK_SUBMENU));
582 //submenu = g_menu_model_get_item_link (G_MENU_MODEL (model), position, G_MENU_LINK_SUBMENU);
584 g_object_unref (model);
586 return submenu;
589 void
590 g_lo_menu_set_submenu_action_to_item_in_section (GLOMenu *menu,
591 gint section,
592 gint position,
593 const gchar *action)
595 g_return_if_fail (G_IS_LO_MENU (menu));
597 GMenuModel *model = G_MENU_MODEL (g_lo_menu_get_section (menu, section));
599 g_return_if_fail (model != nullptr);
601 GVariant *value;
603 if (action != nullptr)
604 value = g_variant_new_string (action);
605 else
606 value = nullptr;
608 g_lo_menu_set_attribute_value (G_LO_MENU (model), position, G_LO_MENU_ATTRIBUTE_SUBMENU_ACTION, value);
610 // Notify the update.
611 g_menu_model_items_changed (model, position, 1, 1);
613 g_object_unref (model);
616 static void
617 g_lo_menu_clear_item (struct item *menu_item)
619 if (menu_item->attributes != nullptr)
620 g_hash_table_unref (menu_item->attributes);
621 if (menu_item->links != nullptr)
622 g_hash_table_unref (menu_item->links);
625 void
626 g_lo_menu_remove (GLOMenu *menu,
627 gint position)
629 g_return_if_fail (G_IS_LO_MENU (menu));
630 g_return_if_fail (0 <= position && position < static_cast<gint>(menu->items->len));
632 g_lo_menu_clear_item (&g_array_index (menu->items, struct item, position));
633 g_array_remove_index (menu->items, position);
634 g_menu_model_items_changed (G_MENU_MODEL (menu), position, 1, 0);
637 void
638 g_lo_menu_remove_from_section (GLOMenu *menu,
639 gint section,
640 gint position)
642 g_return_if_fail (G_IS_LO_MENU (menu));
643 g_return_if_fail (0 <= section && section < static_cast<gint>(menu->items->len));
645 GLOMenu *model = g_lo_menu_get_section (menu, section);
647 g_return_if_fail (model != nullptr);
649 g_lo_menu_remove (model, position);
651 g_object_unref (model);
654 static void
655 g_lo_menu_finalize (GObject *object)
657 GLOMenu *menu = G_LO_MENU (object);
658 struct item *items;
659 gint n_items;
660 gint i;
662 n_items = menu->items->len;
663 items = reinterpret_cast<struct item *>(g_array_free (menu->items, FALSE));
664 for (i = 0; i < n_items; i++)
665 g_lo_menu_clear_item (&items[i]);
666 g_free (items);
668 G_OBJECT_CLASS (g_lo_menu_parent_class)
669 ->finalize (object);
672 static void
673 g_lo_menu_init (GLOMenu *menu)
675 menu->items = g_array_new (FALSE, FALSE, sizeof (struct item));
678 static void
679 g_lo_menu_class_init (GLOMenuClass *klass)
681 GMenuModelClass *model_class = G_MENU_MODEL_CLASS (klass);
682 GObjectClass *object_class = G_OBJECT_CLASS (klass);
684 object_class->finalize = g_lo_menu_finalize;
686 model_class->is_mutable = g_lo_menu_is_mutable;
687 model_class->get_n_items = g_lo_menu_get_n_items;
688 model_class->get_item_attributes = g_lo_menu_get_item_attributes;
689 model_class->get_item_links = g_lo_menu_get_item_links;
692 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */