static void build_button_bar (RBButtonBar *bar) { GtkWidget *waste; append_menu (bar, bar->priv->model, FALSE); waste = gtk_label_new (""); gtk_widget_set_hexpand (waste, TRUE); gtk_widget_show (waste); gtk_grid_attach (GTK_GRID (bar), waste, bar->priv->position++, 0, 1, 1); }
static gboolean append_menu (RBButtonBar *bar, GMenuModel *menu, gboolean need_separator) { int i; gulong id; id = g_signal_connect (menu, "items-changed", G_CALLBACK (items_changed_cb), bar); g_hash_table_insert (bar->priv->handlers, (gpointer)id, g_object_ref (menu)); for (i = 0; i < g_menu_model_get_n_items (menu); i++) { char *label_text; char *accel; GtkWidget *button; GtkWidget *label; GMenuModel *submenu; /* recurse into sections */ submenu = g_menu_model_get_item_link (menu, i, G_MENU_LINK_SECTION); if (submenu != NULL) { need_separator = append_menu (bar, submenu, TRUE); continue; } /* if this item and the previous item are in different sections, add * a separator between them. this may not be a good idea. */ if (need_separator) { GtkWidget *sep; if (bar->priv->position > 0) { sep = gtk_separator_new (GTK_ORIENTATION_VERTICAL); gtk_widget_show (sep); g_object_set (sep, "margin-start", 6, "margin-end", 6, NULL); gtk_grid_attach (GTK_GRID (bar), sep, bar->priv->position++, 0, 1, 1); } need_separator = FALSE; } button = NULL; /* submenus become menu buttons, normal items become buttons */ submenu = g_menu_model_get_item_link (menu, i, G_MENU_LINK_SUBMENU); if (submenu != NULL) { button = gtk_menu_button_new (); gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (button), submenu); g_object_set_data_full (G_OBJECT (button), "rb-menu-model", g_object_ref (submenu), (GDestroyNotify)g_object_unref); } else { GMenuAttributeIter *iter; const char *name; GVariant *value; char *str; guint signal_id; /* we can't do more than one of action and rb-property-bind * and rb-signal-bind, so just do whichever turns up first * in the iterator */ iter = g_menu_model_iterate_item_attributes (menu, i); while (g_menu_attribute_iter_get_next (iter, &name, &value)) { if (g_str_equal (name, "action")) { button = gtk_button_new (); g_variant_get (value, "s", &str, NULL); gtk_actionable_set_action_name (GTK_ACTIONABLE (button), str); /* action target too somehow? */ g_free (str); break; } else if (g_str_equal (name, "rb-property-bind")) { /* property has to be a boolean, can't do inverts, etc. etc. */ button = gtk_toggle_button_new (); g_variant_get (value, "s", &str, NULL); g_object_bind_property (bar->priv->target, str, button, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); g_free (str); break; } else if (g_str_equal (name, "rb-signal-bind")) { button = gtk_button_new (); g_variant_get (value, "s", &str, NULL); signal_id = g_signal_lookup (str, G_OBJECT_TYPE (bar->priv->target)); if (signal_id != 0) { g_object_set_data (G_OBJECT (button), "rb-signal-bind-id", GUINT_TO_POINTER (signal_id)); g_signal_connect (button, "clicked", G_CALLBACK (signal_button_clicked_cb), bar); } g_free (str); break; } } g_object_unref (iter); } if (button == NULL) { g_warning ("no idea what's going on here"); continue; } gtk_widget_set_hexpand (button, FALSE); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); label_text = NULL; g_menu_model_get_item_attribute (menu, i, "label", "s", &label_text); label = gtk_label_new (g_dgettext (NULL, label_text)); g_object_set (label, "margin-left", 6, "margin-right", 6, NULL); gtk_container_add (GTK_CONTAINER (button), label); if (g_menu_model_get_item_attribute (menu, i, "accel", "s", &accel)) { g_object_set_data_full (G_OBJECT (button), "rb-accel", accel, (GDestroyNotify) g_free); } gtk_widget_show_all (button); gtk_size_group_add_widget (bar->priv->size_group, button); gtk_grid_attach (GTK_GRID (bar), button, bar->priv->position++, 0, 1, 1); g_free (label_text); } return need_separator; }
/* Build a menu of the given bookmarks categorised by the given topics. * Shows categorisation using subdivisions, submenus, or a mix of both. */ static void append_menu (GString *string, const GPtrArray *topics, const GPtrArray *bookmarks, guint flags) { GPtrArray *uncovered; guint i, j; gboolean use_subdivis = flags & BUILD_SUBDIVIS; gboolean use_submenus = flags & BUILD_SUBMENUS; if (use_subdivis || use_submenus) { GPtrArray *subset, *covering, *subdivisions, *submenus, *unused; GArray *sizes = 0; EphyNode *topic; gint size, total; gboolean separate = FALSE; char name[EPHY_TOPIC_ACTION_NAME_BUFFER_SIZE]; /* Get the subtopics, uncovered bookmarks, and subtopic sizes. */ sizes = g_array_sized_new (FALSE, FALSE, sizeof(int), topics->len); uncovered = g_ptr_array_sized_new (bookmarks->len); covering = ephy_nodes_get_covering (topics, bookmarks, 0, uncovered, sizes); /* Preallocate arrays for submenus, subdivisions, and bookmark subsets. */ subdivisions = g_ptr_array_sized_new (topics->len); submenus = g_ptr_array_sized_new (topics->len); subset = g_ptr_array_sized_new (bookmarks->len); unused = g_ptr_array_sized_new (bookmarks->len); /* Get the total number of items in the menu. */ total = uncovered->len; for (i = 0; i < covering->len; i++) total += g_array_index (sizes, int, i); /* Seperate covering into list of submenus and subdivisions */ for (i = 0; i < covering->len; i++) { topic = g_ptr_array_index (covering, i); size = g_array_index (sizes, int, i); if (!use_submenus || (use_subdivis && (size < MIN_MENU_SIZE || total < MAX_MENU_SIZE))) { g_ptr_array_add (subdivisions, topic); } else { g_ptr_array_add (submenus, topic); total = total - size + 1; } } /* Sort the list of submenus and subdivisions. */ g_ptr_array_sort (submenus, ephy_bookmarks_compare_topic_pointers); g_ptr_array_sort (subdivisions, ephy_bookmarks_compare_topic_pointers); if (flags & BUILD_CHILD_SUBDIVIS) flags |= BUILD_SUBDIVIS; if (flags & BUILD_CHILD_SUBMENUS) flags |= BUILD_SUBMENUS; /* Create each of the submenus. */ for (i = 0; i < submenus->len; i++) { topic = g_ptr_array_index (submenus, i); ephy_nodes_get_covered (topic, bookmarks, subset); EPHY_TOPIC_ACTION_NAME_PRINTF (name, topic); g_string_append_printf (string, "<menu action=\"%s\">", name); append_menu (string, topics, subset, flags); g_string_append (string, "</menu>"); separate = TRUE; } /* Build a list of bookmarks which don't appear in any subdivision yet. */ for (i = 0; i < bookmarks->len; i++) { g_ptr_array_add (unused, g_ptr_array_index (bookmarks, i)); } /* Create each of the subdivisions. */ for (i = 0; i < subdivisions->len; i++) { topic = g_ptr_array_index (subdivisions, i); ephy_nodes_get_covered (topic, unused, subset); g_ptr_array_sort (subset, ephy_bookmarks_compare_bookmark_pointers); if (separate) g_string_append (string, "<separator/>"); append_bookmarks (string, subset); separate = TRUE; /* Record that each bookmark has been added. */ for (j = 0; j < subset->len; j++) { g_ptr_array_remove_fast (unused, g_ptr_array_index (subset, j)); } } g_array_free (sizes, TRUE); g_ptr_array_free (covering, TRUE); g_ptr_array_free (subdivisions, TRUE); g_ptr_array_free (submenus, TRUE); g_ptr_array_free (subset, TRUE); g_ptr_array_free (unused, TRUE); if (separate && uncovered->len) g_string_append (string, "<separator/>"); }