Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / unx / gtk / window / glomenu.cxx
blobcaa314351287fd811e5366f74649748c51858f88
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 <stdio.h>
11 #include <string.h>
13 #include <unx/gtk/gtksalmenu.hxx>
15 #ifdef ENABLE_GMENU_INTEGRATION
17 #include <unx/gtk/glomenu.h>
19 struct _GLOMenu
21 GMenuModel parent_instance;
23 GArray *items;
26 typedef GMenuModelClass GLOMenuClass;
28 #ifdef __GNUC__
29 #pragma GCC diagnostic push
30 #pragma GCC diagnostic ignored "-Wunused-function"
31 #endif
32 G_DEFINE_TYPE (GLOMenu, g_lo_menu, G_TYPE_MENU_MODEL);
33 #ifdef __GNUC__
34 #pragma GCC diagnostic pop
35 #endif
37 struct item
39 GHashTable* attributes; // Item attributes.
40 GHashTable* links; // Item links.
43 static void
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
57 static gboolean
58 valid_attribute_name (const gchar *name)
60 gint i;
62 if (!g_ascii_islower (name[0]))
63 return FALSE;
65 for (i = 1; name[i]; i++)
67 if (name[i] != '-' &&
68 !g_ascii_islower (name[i]) &&
69 !g_ascii_isdigit (name[i]))
70 return FALSE;
72 if (name[i] == '-' && name[i + 1] == '-')
73 return FALSE;
76 if (name[i - 1] == '-')
77 return FALSE;
79 if (i > 1024)
80 return FALSE;
82 return TRUE;
86 * GLOMenu
89 static gboolean
90 g_lo_menu_is_mutable (GMenuModel*)
92 // Menu is always mutable.
93 return TRUE;
96 static gint
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;
106 gint
107 g_lo_menu_get_n_items_from_section (GLOMenu *menu,
108 gint section)
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);
120 return length;
123 static void
124 g_lo_menu_get_item_attributes (GMenuModel *model,
125 gint position,
126 GHashTable **table)
128 GLOMenu *menu = G_LO_MENU (model);
129 *table = g_hash_table_ref (g_array_index (menu->items, struct item, position).attributes);
132 static void
133 g_lo_menu_get_item_links (GMenuModel *model,
134 gint position,
135 GHashTable **table)
137 GLOMenu *menu = G_LO_MENU (model);
138 *table = g_hash_table_ref (g_array_index (menu->items, struct item, position).links);
141 void
142 g_lo_menu_insert (GLOMenu *menu,
143 gint position,
144 const gchar *label)
146 g_lo_menu_insert_section (menu, position, label, NULL);
149 void
150 g_lo_menu_insert_in_section (GLOMenu *menu,
151 gint section,
152 gint position,
153 const gchar *label)
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);
167 GLOMenu *
168 g_lo_menu_new()
170 return G_LO_MENU( g_object_new (G_TYPE_LO_MENU, NULL) );
173 void
174 g_lo_menu_set_attribute_value (GLOMenu *menu,
175 gint position,
176 const gchar *attribute,
177 GVariant *value)
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)
184 return;
186 struct item menu_item = g_array_index (menu->items, struct item, position);
188 if (value != NULL)
189 g_hash_table_insert (menu_item.attributes, g_strdup (attribute), g_variant_ref_sink (value));
190 else
191 g_hash_table_remove (menu_item.attributes, attribute);
194 GVariant*
195 g_lo_menu_get_attribute_value_from_item_in_section (GLOMenu *menu,
196 gint section,
197 gint position,
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,
206 position,
207 attribute,
208 type);
210 g_object_unref (model);
212 return value;
215 void
216 g_lo_menu_set_label (GLOMenu *menu,
217 gint position,
218 const gchar *label)
220 g_return_if_fail (G_IS_LO_MENU (menu));
222 GVariant *value;
224 if (label != NULL)
225 value = g_variant_new_string (label);
226 else
227 value = NULL;
229 g_lo_menu_set_attribute_value (menu, position, G_MENU_ATTRIBUTE_LABEL, value);
232 void
233 g_lo_menu_set_label_to_item_in_section (GLOMenu *menu,
234 gint section,
235 gint position,
236 const gchar *label)
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);
252 gchar *
253 g_lo_menu_get_label_from_item_in_section (GLOMenu *menu,
254 gint section,
255 gint position)
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,
260 section,
261 position,
262 G_MENU_ATTRIBUTE_LABEL,
263 G_VARIANT_TYPE_STRING);
265 gchar *label = NULL;
267 if (label_value)
269 label = g_variant_dup_string (label_value, NULL);
270 g_variant_unref (label_value);
273 return label;
276 void
277 g_lo_menu_set_action_and_target_value (GLOMenu *menu,
278 gint position,
279 const gchar *action,
280 GVariant *target_value)
282 g_return_if_fail (G_IS_LO_MENU (menu));
284 GVariant *action_value;
286 if (action != NULL)
288 action_value = g_variant_new_string (action);
290 else
292 action_value = NULL;
293 target_value = NULL;
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);
302 void
303 g_lo_menu_set_action_and_target_value_to_item_in_section (GLOMenu *menu,
304 gint section,
305 gint position,
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);
320 void
321 g_lo_menu_set_accelerator_to_item_in_section (GLOMenu *menu,
322 gint section,
323 gint position,
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);
332 GVariant *value;
334 if (accelerator != NULL)
335 value = g_variant_new_string (accelerator);
336 else
337 value = NULL;
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);
347 gchar *
348 g_lo_menu_get_accelerator_from_item_in_section (GLOMenu *menu,
349 gint section,
350 gint position)
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,
355 section,
356 position,
357 G_LO_MENU_ATTRIBUTE_ACCELERATOR,
358 G_VARIANT_TYPE_STRING);
360 gchar *accel = NULL;
362 if (accel_value != NULL)
364 accel = g_variant_dup_string (accel_value, NULL);
365 g_variant_unref (accel_value);
368 return accel;
371 void
372 g_lo_menu_set_command_to_item_in_section (GLOMenu *menu,
373 gint section,
374 gint position,
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);
383 GVariant *value;
385 if (command != NULL)
386 value = g_variant_new_string (command);
387 else
388 value = NULL;
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);
398 gchar *
399 g_lo_menu_get_command_from_item_in_section (GLOMenu *menu,
400 gint section,
401 gint position)
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,
406 section,
407 position,
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);
419 return command;
422 void
423 g_lo_menu_set_link (GLOMenu *menu,
424 gint position,
425 const gchar *link,
426 GMenuModel *model)
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);
437 if (model != NULL)
438 g_hash_table_insert (menu_item.links, g_strdup (link), g_object_ref (model));
439 else
440 g_hash_table_remove (menu_item.links, link);
443 void
444 g_lo_menu_insert_section (GLOMenu *menu,
445 gint position,
446 const gchar *label,
447 GMenuModel *section)
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);
466 void
467 g_lo_menu_new_section (GLOMenu *menu,
468 gint position,
469 const gchar *label)
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);
478 GLOMenu *
479 g_lo_menu_get_section (GLOMenu *menu,
480 gint section)
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));
488 void
489 g_lo_menu_new_submenu_in_item_in_section (GLOMenu *menu,
490 gint section,
491 gint position)
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);
513 void
514 g_lo_menu_set_submenu_to_item_in_section (GLOMenu *menu,
515 gint section,
516 gint position,
517 GMenuModel *submenu)
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);
534 GLOMenu *
535 g_lo_menu_get_submenu_from_item_in_section (GLOMenu *menu,
536 gint section,
537 gint position)
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);
555 return submenu;
558 void
559 g_lo_menu_set_submenu_action_to_item_in_section (GLOMenu *menu,
560 gint section,
561 gint position,
562 const gchar *action)
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);
570 GVariant *value;
572 if (action != NULL)
573 value = g_variant_new_string (action);
574 else
575 value = NULL;
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);
585 static void
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);
594 void
595 g_lo_menu_remove (GLOMenu *menu,
596 gint position)
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);
606 void
607 g_lo_menu_remove_from_section (GLOMenu *menu,
608 gint section,
609 gint position)
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);
623 static void
624 g_lo_menu_finalize (GObject *object)
626 GLOMenu *menu = G_LO_MENU (object);
627 struct item *items;
628 gint n_items;
629 gint i;
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]);
635 g_free (items);
637 G_OBJECT_CLASS (g_lo_menu_parent_class)
638 ->finalize (object);
641 static void
642 g_lo_menu_init (GLOMenu *menu)
644 menu->items = g_array_new (FALSE, FALSE, sizeof (struct item));
647 static void
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;
661 #endif
663 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */