Compare commits
10 Commits
main
...
wip/desrt/
Author | SHA1 | Date | |
---|---|---|---|
|
92d891e6ed | ||
|
e66872474f | ||
|
891b6fbb84 | ||
|
aab6c15cb1 | ||
|
36c1f1941f | ||
|
50e64e5978 | ||
|
b82ef4ecc7 | ||
|
4408bfe1da | ||
|
1299192411 | ||
|
b79deb86cd |
@@ -511,6 +511,7 @@ gtk_private_h_sources = \
|
||||
gtkmenubuttonprivate.h \
|
||||
gtkmenuprivate.h \
|
||||
gtkmenuitemprivate.h \
|
||||
gtkmenusectionbox.h \
|
||||
gtkmenushellprivate.h \
|
||||
gtkmenutracker.h \
|
||||
gtkmenutrackeritem.h \
|
||||
@@ -789,6 +790,7 @@ gtk_base_c_sources = \
|
||||
gtkmenubar.c \
|
||||
gtkmenubutton.c \
|
||||
gtkmenuitem.c \
|
||||
gtkmenusectionbox.c \
|
||||
gtkmenushell.c \
|
||||
gtkmenutracker.c \
|
||||
gtkmenutrackeritem.c \
|
||||
|
424
gtk/gtkmenusectionbox.c
Normal file
424
gtk/gtkmenusectionbox.c
Normal file
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Copyright © 2014 Canonical Limited
|
||||
* Copyright © 2013 Carlos Garnacho
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the licence, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkmenusectionbox.h"
|
||||
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtklabel.h"
|
||||
#include "gtkmenutracker.h"
|
||||
#include "gtkmodelbutton.h"
|
||||
#include "gtkseparator.h"
|
||||
#include "gtksizegroup.h"
|
||||
#include "gtkstack.h"
|
||||
#include "gtkstylecontext.h"
|
||||
#include "gtkpopover.h"
|
||||
#include "gtkorientable.h"
|
||||
|
||||
typedef GtkBoxClass GtkMenuSectionBoxClass;
|
||||
|
||||
struct _GtkMenuSectionBox
|
||||
{
|
||||
GtkBox parent_instance;
|
||||
|
||||
GtkSizeGroup *size_group;
|
||||
GtkMenuSectionBox *toplevel;
|
||||
GtkMenuTracker *tracker;
|
||||
GtkBox *item_box;
|
||||
GtkWidget *separator;
|
||||
guint separator_sync_idle;
|
||||
gboolean iconic;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkMenuSectionBox, gtk_menu_section_box, GTK_TYPE_BOX)
|
||||
|
||||
void gtk_menu_section_box_sync_separators (GtkMenuSectionBox *box,
|
||||
gint *n_items);
|
||||
void gtk_menu_section_box_new_submenu (GtkMenuTrackerItem *item,
|
||||
GtkMenuSectionBox *toplevel,
|
||||
GtkWidget *focus);
|
||||
GtkWidget * gtk_menu_section_box_new_section (GtkMenuTrackerItem *item,
|
||||
GtkMenuSectionBox *toplevel);
|
||||
|
||||
static void
|
||||
gtk_menu_section_box_sync_item (GtkWidget *widget,
|
||||
gpointer user_data)
|
||||
{
|
||||
gint *n_items = user_data;
|
||||
|
||||
if (GTK_IS_MENU_SECTION_BOX (widget))
|
||||
gtk_menu_section_box_sync_separators (GTK_MENU_SECTION_BOX (widget), n_items);
|
||||
else
|
||||
(*n_items)++;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_menu_section_box_sync_separators (GtkMenuSectionBox *box,
|
||||
gint *n_items)
|
||||
{
|
||||
gboolean should_have_separator;
|
||||
gint n_items_before = *n_items;
|
||||
|
||||
gtk_container_foreach (GTK_CONTAINER (box->item_box), gtk_menu_section_box_sync_item, n_items);
|
||||
|
||||
should_have_separator = n_items_before > 0 && *n_items > n_items_before;
|
||||
|
||||
if (box->separator == NULL)
|
||||
return;
|
||||
|
||||
if (should_have_separator == (gtk_widget_get_parent (box->separator) != NULL))
|
||||
return;
|
||||
|
||||
if (should_have_separator)
|
||||
gtk_box_pack_start (GTK_BOX (box), box->separator, FALSE, FALSE, 0);
|
||||
else
|
||||
gtk_container_remove (GTK_CONTAINER (box), box->separator);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_menu_section_box_handle_sync_separators (gpointer user_data)
|
||||
{
|
||||
GtkMenuSectionBox *box = user_data;
|
||||
gint n_items = 0;
|
||||
|
||||
gtk_menu_section_box_sync_separators (box, &n_items);
|
||||
|
||||
box->separator_sync_idle = 0;
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_section_box_schedule_separator_sync (GtkMenuSectionBox *box)
|
||||
{
|
||||
box = box->toplevel;
|
||||
|
||||
if (!box->separator_sync_idle)
|
||||
box->separator_sync_idle = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE, /* before resize... */
|
||||
gtk_menu_section_box_handle_sync_separators,
|
||||
box, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_popover_item_activate (GtkWidget *button,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkMenuTrackerItem *item = user_data;
|
||||
|
||||
gtk_menu_tracker_item_activated (item);
|
||||
|
||||
if (gtk_menu_tracker_item_get_role (item) == GTK_MENU_TRACKER_ITEM_ROLE_NORMAL)
|
||||
gtk_widget_hide (gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_section_box_remove_func (gint position,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkMenuSectionBox *box = user_data;
|
||||
GList *children;
|
||||
|
||||
children = gtk_container_get_children (GTK_CONTAINER (box->item_box));
|
||||
gtk_widget_destroy (g_list_nth_data (children, position));
|
||||
g_list_free (children);
|
||||
|
||||
gtk_menu_section_box_schedule_separator_sync (box);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_ancestors (GtkWidget *widget,
|
||||
GType widget_type,
|
||||
GtkWidget **ancestor,
|
||||
GtkWidget **below)
|
||||
{
|
||||
GtkWidget *a, *b;
|
||||
|
||||
a = NULL;
|
||||
b = widget;
|
||||
while (b != NULL)
|
||||
{
|
||||
a = gtk_widget_get_parent (b);
|
||||
if (!a)
|
||||
return FALSE;
|
||||
if (g_type_is_a (G_OBJECT_TYPE (a), widget_type))
|
||||
break;
|
||||
b = a;
|
||||
}
|
||||
|
||||
*below = b;
|
||||
*ancestor = a;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
close_submenu (GtkWidget *button,
|
||||
gpointer data)
|
||||
{
|
||||
GtkMenuTrackerItem *item = data;
|
||||
GtkWidget *stack;
|
||||
GtkWidget *parent;
|
||||
GtkWidget *focus;
|
||||
|
||||
if (gtk_menu_tracker_item_get_should_request_show (item))
|
||||
gtk_menu_tracker_item_request_submenu_shown (item, FALSE);
|
||||
|
||||
focus = GTK_WIDGET (g_object_get_data (G_OBJECT (button), "focus"));
|
||||
get_ancestors (focus, GTK_TYPE_STACK, &stack, &parent);
|
||||
gtk_stack_set_visible_child (GTK_STACK (stack), parent);
|
||||
gtk_widget_grab_focus (focus);
|
||||
}
|
||||
|
||||
static void
|
||||
open_submenu (GtkWidget *button,
|
||||
gpointer data)
|
||||
{
|
||||
GtkMenuTrackerItem *item = data;
|
||||
GtkWidget *stack;
|
||||
GtkWidget *child;
|
||||
GtkWidget *focus;
|
||||
|
||||
if (gtk_menu_tracker_item_get_should_request_show (item))
|
||||
gtk_menu_tracker_item_request_submenu_shown (item, TRUE);
|
||||
|
||||
focus = GTK_WIDGET (g_object_get_data (G_OBJECT (button), "focus"));
|
||||
get_ancestors (focus, GTK_TYPE_STACK, &stack, &child);
|
||||
gtk_stack_set_visible_child (GTK_STACK (stack), child);
|
||||
gtk_widget_grab_focus (focus);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_section_box_insert_func (GtkMenuTrackerItem *item,
|
||||
gint position,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkMenuSectionBox *box = user_data;
|
||||
GtkWidget *widget;
|
||||
|
||||
if (gtk_menu_tracker_item_get_is_separator (item))
|
||||
{
|
||||
widget = gtk_menu_section_box_new_section (item, box->toplevel);
|
||||
}
|
||||
else if (gtk_menu_tracker_item_get_has_link (item, G_MENU_LINK_SUBMENU))
|
||||
{
|
||||
widget = g_object_new (GTK_TYPE_MODEL_BUTTON, "has-submenu", TRUE, NULL);
|
||||
g_object_bind_property (item, "label", widget, "text", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "icon", widget, "icon", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "sensitive", widget, "sensitive", G_BINDING_SYNC_CREATE);
|
||||
gtk_menu_section_box_new_submenu (item, box->toplevel, widget);
|
||||
gtk_widget_show (widget);
|
||||
}
|
||||
else
|
||||
{
|
||||
widget = gtk_model_button_new ();
|
||||
|
||||
g_object_bind_property (item, "label", widget, "text", G_BINDING_SYNC_CREATE);
|
||||
|
||||
if (box->iconic)
|
||||
{
|
||||
g_object_bind_property (item, "verb-icon", widget, "icon", G_BINDING_SYNC_CREATE);
|
||||
g_object_set (widget, "iconic", TRUE, "centered", TRUE, NULL);
|
||||
}
|
||||
else
|
||||
g_object_bind_property (item, "icon", widget, "icon", G_BINDING_SYNC_CREATE);
|
||||
|
||||
g_object_bind_property (item, "sensitive", widget, "sensitive", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "role", widget, "action-role", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "toggled", widget, "toggled", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "accel", widget, "accel", G_BINDING_SYNC_CREATE);
|
||||
|
||||
g_signal_connect (widget, "clicked", G_CALLBACK (gtk_popover_item_activate), item);
|
||||
}
|
||||
|
||||
gtk_widget_show (widget);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (widget), "GtkMenuTrackerItem", g_object_ref (item), g_object_unref);
|
||||
|
||||
gtk_widget_set_halign (widget, GTK_ALIGN_FILL);
|
||||
gtk_container_add (GTK_CONTAINER (box->item_box), widget);
|
||||
gtk_box_reorder_child (GTK_BOX (box->item_box), widget, position);
|
||||
|
||||
gtk_menu_section_box_schedule_separator_sync (box);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_section_box_init (GtkMenuSectionBox *box)
|
||||
{
|
||||
GtkWidget *item_box;
|
||||
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (box), GTK_ORIENTATION_VERTICAL);
|
||||
|
||||
box->toplevel = box;
|
||||
|
||||
item_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
box->item_box = GTK_BOX (item_box);
|
||||
gtk_box_pack_end (GTK_BOX (box), item_box, FALSE, FALSE, 0);
|
||||
gtk_widget_set_halign (GTK_WIDGET (item_box), GTK_ALIGN_FILL);
|
||||
gtk_widget_show (item_box);
|
||||
|
||||
gtk_widget_set_halign (GTK_WIDGET (box), GTK_ALIGN_FILL);
|
||||
g_object_set (box, "margin", 10, NULL);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_section_box_dispose (GObject *object)
|
||||
{
|
||||
GtkMenuSectionBox *box = GTK_MENU_SECTION_BOX (object);
|
||||
|
||||
g_print ("disposed %p\n", object);
|
||||
|
||||
if (box->separator_sync_idle)
|
||||
{
|
||||
g_source_remove (box->separator_sync_idle);
|
||||
box->separator_sync_idle = 0;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (gtk_menu_section_box_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_section_box_class_init (GtkMenuSectionBoxClass *class)
|
||||
{
|
||||
G_OBJECT_CLASS (class)->dispose = gtk_menu_section_box_dispose;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_menu_section_box_new_toplevel (GtkStack *stack,
|
||||
GMenuModel *model,
|
||||
const gchar *action_namespace)
|
||||
{
|
||||
GtkMenuSectionBox *box;
|
||||
|
||||
box = g_object_new (GTK_TYPE_MENU_SECTION_BOX, NULL);
|
||||
box->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
|
||||
gtk_size_group_add_widget (box->size_group, GTK_WIDGET (box));
|
||||
gtk_stack_add_named (stack, GTK_WIDGET (box), "main");
|
||||
|
||||
box->tracker = gtk_menu_tracker_new (GTK_ACTION_OBSERVABLE (_gtk_widget_get_action_muxer (GTK_WIDGET (box))),
|
||||
model, TRUE, FALSE, action_namespace,
|
||||
gtk_menu_section_box_insert_func,
|
||||
gtk_menu_section_box_remove_func, box);
|
||||
|
||||
gtk_widget_show (GTK_WIDGET (box));
|
||||
}
|
||||
|
||||
void
|
||||
gtk_menu_section_box_new_submenu (GtkMenuTrackerItem *item,
|
||||
GtkMenuSectionBox *toplevel,
|
||||
GtkWidget *focus)
|
||||
{
|
||||
GtkMenuSectionBox *box;
|
||||
GtkWidget *button;
|
||||
|
||||
box = g_object_new (GTK_TYPE_MENU_SECTION_BOX, NULL);
|
||||
box->size_group = g_object_ref (toplevel->size_group);
|
||||
gtk_size_group_add_widget (box->size_group, GTK_WIDGET (box));
|
||||
|
||||
button = g_object_new (GTK_TYPE_MODEL_BUTTON,
|
||||
"has-submenu", TRUE,
|
||||
"inverted", TRUE,
|
||||
"centered", TRUE,
|
||||
NULL);
|
||||
g_object_bind_property (item, "label", button, "text", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "icon", button, "icon", G_BINDING_SYNC_CREATE);
|
||||
|
||||
g_object_set_data (G_OBJECT (button), "focus", focus);
|
||||
g_object_set_data (G_OBJECT (focus), "focus", button);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
|
||||
gtk_widget_show (button);
|
||||
|
||||
g_signal_connect (focus, "clicked", G_CALLBACK (open_submenu), item);
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (close_submenu), item);
|
||||
|
||||
gtk_stack_add_named (GTK_STACK (gtk_widget_get_ancestor (GTK_WIDGET (toplevel), GTK_TYPE_STACK)),
|
||||
GTK_WIDGET (box), gtk_menu_tracker_item_get_label (item));
|
||||
gtk_widget_show (GTK_WIDGET (box));
|
||||
|
||||
box->tracker = gtk_menu_tracker_new_for_item_link (item, G_MENU_LINK_SUBMENU, FALSE,
|
||||
gtk_menu_section_box_insert_func,
|
||||
gtk_menu_section_box_remove_func,
|
||||
box);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_menu_section_box_new_section (GtkMenuTrackerItem *item,
|
||||
GtkMenuSectionBox *toplevel)
|
||||
{
|
||||
GtkMenuSectionBox *box;
|
||||
GtkWidget *separator;
|
||||
const gchar *label;
|
||||
const gchar *hint;
|
||||
|
||||
box = g_object_new (GTK_TYPE_MENU_SECTION_BOX, NULL);
|
||||
box->size_group = g_object_ref (toplevel->size_group);
|
||||
box->toplevel = toplevel;
|
||||
|
||||
separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
|
||||
label = gtk_menu_tracker_item_get_label (item);
|
||||
hint = gtk_menu_tracker_item_get_display_hint (item);
|
||||
|
||||
if (hint && g_str_equal (hint, "iconic"))
|
||||
{
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (box->item_box), GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (box->item_box)), GTK_STYLE_CLASS_LINKED);
|
||||
box->iconic = TRUE;
|
||||
}
|
||||
|
||||
if (label != NULL)
|
||||
{
|
||||
GtkWidget *title;
|
||||
|
||||
title = gtk_label_new (label);
|
||||
g_object_bind_property (item, "label", title, "label", G_BINDING_SYNC_CREATE);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (title), GTK_STYLE_CLASS_SEPARATOR);
|
||||
gtk_widget_set_halign (title, GTK_ALIGN_START);
|
||||
box->separator = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
g_object_set (box->separator,
|
||||
"margin-start", 12,
|
||||
"margin-end", 12,
|
||||
"margin-top", 6,
|
||||
"margin-bottom", 3,
|
||||
NULL);
|
||||
gtk_container_add (GTK_CONTAINER (box->separator), title);
|
||||
gtk_container_add (GTK_CONTAINER (box->separator), separator);
|
||||
gtk_widget_show_all (box->separator);
|
||||
}
|
||||
else
|
||||
{
|
||||
box->separator = separator;
|
||||
g_object_set (box->separator,
|
||||
"margin-start", 12,
|
||||
"margin-end", 12,
|
||||
"margin-top", 3,
|
||||
"margin-bottom", 3,
|
||||
NULL);
|
||||
gtk_widget_show (box->separator);
|
||||
}
|
||||
|
||||
box->tracker = gtk_menu_tracker_new_for_item_link (item, G_MENU_LINK_SECTION, FALSE,
|
||||
gtk_menu_section_box_insert_func,
|
||||
gtk_menu_section_box_remove_func,
|
||||
box);
|
||||
|
||||
return GTK_WIDGET (box);
|
||||
}
|
49
gtk/gtkmenusectionbox.h
Normal file
49
gtk/gtkmenusectionbox.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright © 2014 Codethink Limited
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the licence, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_MENU_SECTION_BOX_H__
|
||||
#define __GTK_MENU_SECTION_BOX_H__
|
||||
|
||||
#include <gtk/gtkmenutrackeritem.h>
|
||||
#include <gtk/gtkstack.h>
|
||||
#include <gtk/gtkbox.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_MENU_SECTION_BOX (gtk_menu_section_box_get_type ())
|
||||
#define GTK_MENU_SECTION_BOX(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
|
||||
GTK_TYPE_MENU_SECTION_BOX, GtkMenuSectionBox))
|
||||
#define GTK_MENU_SECTION_BOX_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
|
||||
GTK_TYPE_MENU_SECTION_BOX, GtkMenuSectionBoxClass))
|
||||
#define GTK_IS_MENU_SECTION_BOX(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
|
||||
GTK_TYPE_MENU_SECTION_BOX))
|
||||
#define GTK_IS_MENU_SECTION_BOX_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \
|
||||
GTK_TYPE_MENU_SECTION_BOX))
|
||||
#define GTK_MENU_SECTION_BOX_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \
|
||||
GTK_TYPE_MENU_SECTION_BOX, GtkMenuSectionBoxClass))
|
||||
|
||||
typedef struct _GtkMenuSectionBox GtkMenuSectionBox;
|
||||
|
||||
void gtk_menu_section_box_new_toplevel (GtkStack *stack,
|
||||
GMenuModel *model,
|
||||
const gchar *action_namespace);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_MENU_SECTION_BOX_H__ */
|
@@ -2057,7 +2057,7 @@ gtk_menu_shell_tracker_insert_func (GtkMenuTrackerItem *item,
|
||||
|
||||
gtk_widget_show (widget);
|
||||
}
|
||||
else if (gtk_menu_tracker_item_get_has_submenu (item))
|
||||
else if (gtk_menu_tracker_item_get_has_link (item, G_MENU_LINK_SUBMENU))
|
||||
{
|
||||
GtkMenuShell *submenu;
|
||||
|
||||
@@ -2070,10 +2070,11 @@ gtk_menu_shell_tracker_insert_func (GtkMenuTrackerItem *item,
|
||||
* prevent arbitrary recursion depth. We could also do it
|
||||
* lazy...
|
||||
*/
|
||||
submenu->priv->tracker = gtk_menu_tracker_new_for_item_submenu (item,
|
||||
gtk_menu_shell_tracker_insert_func,
|
||||
gtk_menu_shell_tracker_remove_func,
|
||||
submenu);
|
||||
submenu->priv->tracker = gtk_menu_tracker_new_for_item_link (item,
|
||||
G_MENU_LINK_SUBMENU, TRUE,
|
||||
gtk_menu_shell_tracker_insert_func,
|
||||
gtk_menu_shell_tracker_remove_func,
|
||||
submenu);
|
||||
gtk_menu_item_set_submenu (GTK_MENU_ITEM (widget), GTK_WIDGET (submenu));
|
||||
|
||||
if (gtk_menu_tracker_item_get_should_request_show (item))
|
||||
@@ -2185,7 +2186,7 @@ gtk_menu_shell_bind_model (GtkMenuShell *menu_shell,
|
||||
|
||||
if (model)
|
||||
menu_shell->priv->tracker = gtk_menu_tracker_new (GTK_ACTION_OBSERVABLE (muxer),
|
||||
model, with_separators, action_namespace,
|
||||
model, with_separators, FALSE, action_namespace,
|
||||
gtk_menu_shell_tracker_insert_func,
|
||||
gtk_menu_shell_tracker_remove_func,
|
||||
menu_shell);
|
||||
|
@@ -60,6 +60,7 @@ typedef struct _GtkMenuTrackerSection GtkMenuTrackerSection;
|
||||
struct _GtkMenuTracker
|
||||
{
|
||||
GtkActionObservable *observable;
|
||||
gboolean merge_sections;
|
||||
GtkMenuTrackerInsertFunc insert_func;
|
||||
GtkMenuTrackerRemoveFunc remove_func;
|
||||
gpointer user_data;
|
||||
@@ -308,7 +309,8 @@ gtk_menu_tracker_add_items (GtkMenuTracker *tracker,
|
||||
|
||||
submenu = g_menu_model_get_item_link (model, position + n_items, G_MENU_LINK_SECTION);
|
||||
g_assert (submenu != model);
|
||||
if (submenu != NULL)
|
||||
|
||||
if (submenu != NULL && tracker->merge_sections)
|
||||
{
|
||||
GtkMenuTrackerSection *subsection;
|
||||
gchar *action_namespace = NULL;
|
||||
@@ -340,7 +342,7 @@ gtk_menu_tracker_add_items (GtkMenuTracker *tracker,
|
||||
GtkMenuTrackerItem *item;
|
||||
|
||||
item = _gtk_menu_tracker_item_new (tracker->observable, model, position + n_items,
|
||||
section->action_namespace, FALSE);
|
||||
section->action_namespace, submenu != NULL);
|
||||
|
||||
/* In the case that the item may disappear we handle that by
|
||||
* treating the item that we just created as being its own
|
||||
@@ -367,19 +369,19 @@ gtk_menu_tracker_add_items (GtkMenuTracker *tracker,
|
||||
* case that we want to show a separator, but we will never do
|
||||
* that because separators are not shown for this fake section.
|
||||
*/
|
||||
if (_gtk_menu_tracker_item_may_disappear (item))
|
||||
if (gtk_menu_tracker_item_may_disappear (item))
|
||||
{
|
||||
GtkMenuTrackerSection *fake_section;
|
||||
|
||||
fake_section = g_slice_new0 (GtkMenuTrackerSection);
|
||||
fake_section->is_fake = TRUE;
|
||||
fake_section->model = g_object_ref (item);
|
||||
fake_section->handler = g_signal_connect (item, "visibility-changed",
|
||||
fake_section->handler = g_signal_connect (item, "notify::is-visible",
|
||||
G_CALLBACK (gtk_menu_tracker_item_visibility_changed),
|
||||
tracker);
|
||||
*change_point = g_slist_prepend (*change_point, fake_section);
|
||||
|
||||
if (_gtk_menu_tracker_item_is_visible (item))
|
||||
if (gtk_menu_tracker_item_get_is_visible (item))
|
||||
{
|
||||
(* tracker->insert_func) (item, offset, tracker->user_data);
|
||||
fake_section->items = g_slist_prepend (NULL, NULL);
|
||||
@@ -540,6 +542,7 @@ GtkMenuTracker *
|
||||
gtk_menu_tracker_new (GtkActionObservable *observable,
|
||||
GMenuModel *model,
|
||||
gboolean with_separators,
|
||||
gboolean merge_sections,
|
||||
const gchar *action_namespace,
|
||||
GtkMenuTrackerInsertFunc insert_func,
|
||||
GtkMenuTrackerRemoveFunc remove_func,
|
||||
@@ -548,6 +551,7 @@ gtk_menu_tracker_new (GtkActionObservable *observable,
|
||||
GtkMenuTracker *tracker;
|
||||
|
||||
tracker = g_slice_new (GtkMenuTracker);
|
||||
tracker->merge_sections = merge_sections;
|
||||
tracker->observable = g_object_ref (observable);
|
||||
tracker->insert_func = insert_func;
|
||||
tracker->remove_func = remove_func;
|
||||
@@ -560,20 +564,22 @@ gtk_menu_tracker_new (GtkActionObservable *observable,
|
||||
}
|
||||
|
||||
GtkMenuTracker *
|
||||
gtk_menu_tracker_new_for_item_submenu (GtkMenuTrackerItem *item,
|
||||
GtkMenuTrackerInsertFunc insert_func,
|
||||
GtkMenuTrackerRemoveFunc remove_func,
|
||||
gpointer user_data)
|
||||
gtk_menu_tracker_new_for_item_link (GtkMenuTrackerItem *item,
|
||||
const gchar *link_name,
|
||||
gboolean merge_sections,
|
||||
GtkMenuTrackerInsertFunc insert_func,
|
||||
GtkMenuTrackerRemoveFunc remove_func,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkMenuTracker *tracker;
|
||||
GMenuModel *submenu;
|
||||
gchar *namespace;
|
||||
|
||||
submenu = _gtk_menu_tracker_item_get_submenu (item);
|
||||
namespace = _gtk_menu_tracker_item_get_submenu_namespace (item);
|
||||
submenu = _gtk_menu_tracker_item_get_link (item, link_name);
|
||||
namespace = _gtk_menu_tracker_item_get_link_namespace (item);
|
||||
|
||||
tracker = gtk_menu_tracker_new (_gtk_menu_tracker_item_get_observable (item), submenu,
|
||||
TRUE, namespace, insert_func, remove_func, user_data);
|
||||
TRUE, merge_sections, namespace, insert_func, remove_func, user_data);
|
||||
|
||||
g_object_unref (submenu);
|
||||
g_free (namespace);
|
||||
|
@@ -35,12 +35,15 @@ typedef void (* GtkMenuTrackerRemoveFunc) (gint
|
||||
GtkMenuTracker * gtk_menu_tracker_new (GtkActionObservable *observer,
|
||||
GMenuModel *model,
|
||||
gboolean with_separators,
|
||||
gboolean merge_sections,
|
||||
const gchar *action_namespace,
|
||||
GtkMenuTrackerInsertFunc insert_func,
|
||||
GtkMenuTrackerRemoveFunc remove_func,
|
||||
gpointer user_data);
|
||||
|
||||
GtkMenuTracker * gtk_menu_tracker_new_for_item_submenu (GtkMenuTrackerItem *item,
|
||||
GtkMenuTracker * gtk_menu_tracker_new_for_item_link (GtkMenuTrackerItem *item,
|
||||
const gchar *link_name,
|
||||
gboolean merge_sections,
|
||||
GtkMenuTrackerInsertFunc insert_func,
|
||||
GtkMenuTrackerRemoveFunc remove_func,
|
||||
gpointer user_data);
|
||||
|
@@ -106,20 +106,19 @@ struct _GtkMenuTrackerItem
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_IS_SEPARATOR,
|
||||
PROP_HAS_SUBMENU,
|
||||
PROP_LABEL,
|
||||
PROP_ICON,
|
||||
PROP_VERB_ICON,
|
||||
PROP_SENSITIVE,
|
||||
PROP_VISIBLE,
|
||||
PROP_ROLE,
|
||||
PROP_TOGGLED,
|
||||
PROP_ACCEL,
|
||||
PROP_SUBMENU_SHOWN,
|
||||
PROP_IS_VISIBLE,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *gtk_menu_tracker_item_pspecs[N_PROPS];
|
||||
static guint gtk_menu_tracker_visibility_changed_signal;
|
||||
|
||||
static void gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface);
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkMenuTrackerItem, gtk_menu_tracker_item, G_TYPE_OBJECT,
|
||||
@@ -161,21 +160,18 @@ gtk_menu_tracker_item_get_property (GObject *object,
|
||||
case PROP_IS_SEPARATOR:
|
||||
g_value_set_boolean (value, gtk_menu_tracker_item_get_is_separator (self));
|
||||
break;
|
||||
case PROP_HAS_SUBMENU:
|
||||
g_value_set_boolean (value, gtk_menu_tracker_item_get_has_submenu (self));
|
||||
break;
|
||||
case PROP_LABEL:
|
||||
g_value_set_string (value, gtk_menu_tracker_item_get_label (self));
|
||||
break;
|
||||
case PROP_ICON:
|
||||
g_value_set_object (value, gtk_menu_tracker_item_get_icon (self));
|
||||
break;
|
||||
case PROP_VERB_ICON:
|
||||
g_value_set_object (value, gtk_menu_tracker_item_get_verb_icon (self));
|
||||
break;
|
||||
case PROP_SENSITIVE:
|
||||
g_value_set_boolean (value, gtk_menu_tracker_item_get_sensitive (self));
|
||||
break;
|
||||
case PROP_VISIBLE:
|
||||
g_value_set_boolean (value, gtk_menu_tracker_item_get_visible (self));
|
||||
break;
|
||||
case PROP_ROLE:
|
||||
g_value_set_enum (value, gtk_menu_tracker_item_get_role (self));
|
||||
break;
|
||||
@@ -188,6 +184,9 @@ gtk_menu_tracker_item_get_property (GObject *object,
|
||||
case PROP_SUBMENU_SHOWN:
|
||||
g_value_set_boolean (value, gtk_menu_tracker_item_get_submenu_shown (self));
|
||||
break;
|
||||
case PROP_IS_VISIBLE:
|
||||
g_value_set_boolean (value, gtk_menu_tracker_item_get_is_visible (self));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -222,16 +221,14 @@ gtk_menu_tracker_item_class_init (GtkMenuTrackerItemClass *class)
|
||||
|
||||
gtk_menu_tracker_item_pspecs[PROP_IS_SEPARATOR] =
|
||||
g_param_spec_boolean ("is-separator", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
gtk_menu_tracker_item_pspecs[PROP_HAS_SUBMENU] =
|
||||
g_param_spec_boolean ("has-submenu", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
gtk_menu_tracker_item_pspecs[PROP_LABEL] =
|
||||
g_param_spec_string ("label", "", "", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
gtk_menu_tracker_item_pspecs[PROP_ICON] =
|
||||
g_param_spec_object ("icon", "", "", G_TYPE_ICON, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
gtk_menu_tracker_item_pspecs[PROP_VERB_ICON] =
|
||||
g_param_spec_object ("verb-icon", "", "", G_TYPE_ICON, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
gtk_menu_tracker_item_pspecs[PROP_SENSITIVE] =
|
||||
g_param_spec_boolean ("sensitive", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
gtk_menu_tracker_item_pspecs[PROP_VISIBLE] =
|
||||
g_param_spec_boolean ("visible", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
gtk_menu_tracker_item_pspecs[PROP_ROLE] =
|
||||
g_param_spec_enum ("role", "", "",
|
||||
GTK_TYPE_MENU_TRACKER_ITEM_ROLE, GTK_MENU_TRACKER_ITEM_ROLE_NORMAL,
|
||||
@@ -242,13 +239,10 @@ gtk_menu_tracker_item_class_init (GtkMenuTrackerItemClass *class)
|
||||
g_param_spec_string ("accel", "", "", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
gtk_menu_tracker_item_pspecs[PROP_SUBMENU_SHOWN] =
|
||||
g_param_spec_boolean ("submenu-shown", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
gtk_menu_tracker_item_pspecs[PROP_IS_VISIBLE] =
|
||||
g_param_spec_boolean ("is-visible", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
||||
|
||||
g_object_class_install_properties (class, N_PROPS, gtk_menu_tracker_item_pspecs);
|
||||
|
||||
gtk_menu_tracker_visibility_changed_signal = g_signal_new ("visibility-changed", GTK_TYPE_MENU_TRACKER_ITEM,
|
||||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE,
|
||||
1, G_TYPE_BOOLEAN);
|
||||
}
|
||||
|
||||
/* This syncs up the visibility for the hidden-when='' case. We call it
|
||||
@@ -282,7 +276,7 @@ gtk_menu_tracker_item_update_visibility (GtkMenuTrackerItem *self)
|
||||
if (visible != self->is_visible)
|
||||
{
|
||||
self->is_visible = visible;
|
||||
g_signal_emit (self, gtk_menu_tracker_visibility_changed_signal, 0, visible);
|
||||
g_object_notify (G_OBJECT (self), "is-visible");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,11 +559,12 @@ gtk_menu_tracker_item_get_is_separator (GtkMenuTrackerItem *self)
|
||||
* for #GtkMenuTrackerItem.
|
||||
*/
|
||||
gboolean
|
||||
gtk_menu_tracker_item_get_has_submenu (GtkMenuTrackerItem *self)
|
||||
gtk_menu_tracker_item_get_has_link (GtkMenuTrackerItem *self,
|
||||
const gchar *link_name)
|
||||
{
|
||||
GMenuModel *link;
|
||||
|
||||
link = g_menu_item_get_link (self->item, G_MENU_LINK_SUBMENU);
|
||||
link = g_menu_item_get_link (self->item, link_name);
|
||||
|
||||
if (link)
|
||||
{
|
||||
@@ -612,18 +607,34 @@ gtk_menu_tracker_item_get_icon (GtkMenuTrackerItem *self)
|
||||
return icon;
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gtk_menu_tracker_item_get_verb_icon:
|
||||
*
|
||||
* Returns: (transfer full):
|
||||
*/
|
||||
GIcon *
|
||||
gtk_menu_tracker_item_get_verb_icon (GtkMenuTrackerItem *self)
|
||||
{
|
||||
GVariant *icon_data;
|
||||
GIcon *icon;
|
||||
|
||||
icon_data = g_menu_item_get_attribute_value (self->item, "verb-icon", NULL);
|
||||
|
||||
if (icon_data == NULL)
|
||||
return NULL;
|
||||
|
||||
icon = g_icon_deserialize (icon_data);
|
||||
g_variant_unref (icon_data);
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_menu_tracker_item_get_sensitive (GtkMenuTrackerItem *self)
|
||||
{
|
||||
return self->sensitive;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_menu_tracker_item_get_visible (GtkMenuTrackerItem *self)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GtkMenuTrackerItemRole
|
||||
gtk_menu_tracker_item_get_role (GtkMenuTrackerItem *self)
|
||||
{
|
||||
@@ -663,14 +674,25 @@ gtk_menu_tracker_item_get_special (GtkMenuTrackerItem *self)
|
||||
return special;
|
||||
}
|
||||
|
||||
GMenuModel *
|
||||
_gtk_menu_tracker_item_get_submenu (GtkMenuTrackerItem *self)
|
||||
const gchar *
|
||||
gtk_menu_tracker_item_get_display_hint (GtkMenuTrackerItem *self)
|
||||
{
|
||||
return g_menu_item_get_link (self->item, "submenu");
|
||||
const gchar *display_hint = NULL;
|
||||
|
||||
g_menu_item_get_attribute (self->item, "display-hint", "&s", &display_hint);
|
||||
|
||||
return display_hint;
|
||||
}
|
||||
|
||||
GMenuModel *
|
||||
_gtk_menu_tracker_item_get_link (GtkMenuTrackerItem *self,
|
||||
const gchar *link_name)
|
||||
{
|
||||
return g_menu_item_get_link (self->item, link_name);
|
||||
}
|
||||
|
||||
gchar *
|
||||
_gtk_menu_tracker_item_get_submenu_namespace (GtkMenuTrackerItem *self)
|
||||
_gtk_menu_tracker_item_get_link_namespace (GtkMenuTrackerItem *self)
|
||||
{
|
||||
const gchar *namespace;
|
||||
|
||||
@@ -890,14 +912,29 @@ gtk_menu_tracker_item_request_submenu_shown (GtkMenuTrackerItem *self,
|
||||
gtk_menu_tracker_item_set_submenu_shown (self, shown);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_menu_tracker_item_get_is_visible:
|
||||
* @self: A #GtkMenuTrackerItem instance
|
||||
*
|
||||
* Don't use this unless you're tracking items for yourself -- normally
|
||||
* the tracker will emit add/remove automatically when this changes.
|
||||
*
|
||||
* Returns: if the item should currently be shown
|
||||
*/
|
||||
gboolean
|
||||
_gtk_menu_tracker_item_is_visible (GtkMenuTrackerItem *self)
|
||||
gtk_menu_tracker_item_get_is_visible (GtkMenuTrackerItem *self)
|
||||
{
|
||||
return self->is_visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_menu_tracker_item_may_disappear:
|
||||
* @self: A #GtkMenuTrackerItem instance
|
||||
*
|
||||
* Returns: if the item may disappear (ie: is-visible property may change)
|
||||
*/
|
||||
gboolean
|
||||
_gtk_menu_tracker_item_may_disappear (GtkMenuTrackerItem *self)
|
||||
gtk_menu_tracker_item_may_disappear (GtkMenuTrackerItem *self)
|
||||
{
|
||||
return self->hidden_when != HIDDEN_NEVER;
|
||||
}
|
||||
|
@@ -50,19 +50,22 @@ GtkMenuTrackerItem * _gtk_menu_tracker_item_new (GtkActi
|
||||
|
||||
const gchar * gtk_menu_tracker_item_get_special (GtkMenuTrackerItem *self);
|
||||
|
||||
const gchar * gtk_menu_tracker_item_get_display_hint (GtkMenuTrackerItem *self);
|
||||
|
||||
GtkActionObservable * _gtk_menu_tracker_item_get_observable (GtkMenuTrackerItem *self);
|
||||
|
||||
gboolean gtk_menu_tracker_item_get_is_separator (GtkMenuTrackerItem *self);
|
||||
|
||||
gboolean gtk_menu_tracker_item_get_has_submenu (GtkMenuTrackerItem *self);
|
||||
gboolean gtk_menu_tracker_item_get_has_link (GtkMenuTrackerItem *self,
|
||||
const gchar *link_name);
|
||||
|
||||
const gchar * gtk_menu_tracker_item_get_label (GtkMenuTrackerItem *self);
|
||||
|
||||
GIcon * gtk_menu_tracker_item_get_icon (GtkMenuTrackerItem *self);
|
||||
|
||||
gboolean gtk_menu_tracker_item_get_sensitive (GtkMenuTrackerItem *self);
|
||||
GIcon * gtk_menu_tracker_item_get_verb_icon (GtkMenuTrackerItem *self);
|
||||
|
||||
gboolean gtk_menu_tracker_item_get_visible (GtkMenuTrackerItem *self);
|
||||
gboolean gtk_menu_tracker_item_get_sensitive (GtkMenuTrackerItem *self);
|
||||
|
||||
GtkMenuTrackerItemRole gtk_menu_tracker_item_get_role (GtkMenuTrackerItem *self);
|
||||
|
||||
@@ -70,13 +73,14 @@ gboolean gtk_menu_tracker_item_get_toggled (GtkMenu
|
||||
|
||||
const gchar * gtk_menu_tracker_item_get_accel (GtkMenuTrackerItem *self);
|
||||
|
||||
GMenuModel * _gtk_menu_tracker_item_get_submenu (GtkMenuTrackerItem *self);
|
||||
GMenuModel * _gtk_menu_tracker_item_get_link (GtkMenuTrackerItem *self,
|
||||
const gchar *link_name);
|
||||
|
||||
gchar * _gtk_menu_tracker_item_get_submenu_namespace (GtkMenuTrackerItem *self);
|
||||
gchar * _gtk_menu_tracker_item_get_link_namespace (GtkMenuTrackerItem *self);
|
||||
|
||||
gboolean _gtk_menu_tracker_item_may_disappear (GtkMenuTrackerItem *self);
|
||||
gboolean gtk_menu_tracker_item_may_disappear (GtkMenuTrackerItem *self);
|
||||
|
||||
gboolean _gtk_menu_tracker_item_is_visible (GtkMenuTrackerItem *self);
|
||||
gboolean gtk_menu_tracker_item_get_is_visible (GtkMenuTrackerItem *self);
|
||||
|
||||
gboolean gtk_menu_tracker_item_get_should_request_show (GtkMenuTrackerItem *self);
|
||||
|
||||
|
@@ -41,6 +41,7 @@ struct _GtkModelButton
|
||||
gboolean has_submenu;
|
||||
gboolean centered;
|
||||
gboolean inverted;
|
||||
gboolean iconic;
|
||||
GtkMenuTrackerItemRole role;
|
||||
};
|
||||
|
||||
@@ -58,7 +59,8 @@ enum
|
||||
PROP_ACCEL,
|
||||
PROP_HAS_SUBMENU,
|
||||
PROP_INVERTED,
|
||||
PROP_CENTERED
|
||||
PROP_CENTERED,
|
||||
PROP_ICONIC
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -96,21 +98,33 @@ gtk_model_button_set_action_role (GtkModelButton *button,
|
||||
atk_object_set_role (accessible, a11y_role);
|
||||
}
|
||||
|
||||
static void
|
||||
update_visibility (GtkModelButton *button)
|
||||
{
|
||||
gboolean has_icon;
|
||||
gboolean has_text;
|
||||
|
||||
has_icon = gtk_image_get_storage_type (GTK_IMAGE (button->image)) != GTK_IMAGE_EMPTY;
|
||||
has_text = gtk_label_get_text (GTK_LABEL (button->label))[0] != '\0';
|
||||
|
||||
gtk_widget_set_visible (button->image, has_icon);
|
||||
gtk_widget_set_visible (button->label, has_text && (!button->iconic || !has_icon));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_model_button_set_icon (GtkModelButton *button,
|
||||
GIcon *icon)
|
||||
{
|
||||
gtk_image_set_from_gicon (GTK_IMAGE (button->image), icon, GTK_ICON_SIZE_MENU);
|
||||
gtk_widget_set_visible (button->image, icon != NULL);
|
||||
update_visibility (button);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_model_button_set_text (GtkModelButton *button,
|
||||
const gchar *text)
|
||||
{
|
||||
if (text != NULL)
|
||||
gtk_label_set_text_with_mnemonic (GTK_LABEL (button->label), text);
|
||||
gtk_widget_set_visible (button->label, text != NULL);
|
||||
gtk_label_set_text_with_mnemonic (GTK_LABEL (button->label), text);
|
||||
update_visibility (button);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -153,6 +167,28 @@ gtk_model_button_set_centered (GtkModelButton *button,
|
||||
gtk_widget_queue_draw (GTK_WIDGET (button));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_model_button_set_iconic (GtkModelButton *button,
|
||||
gboolean iconic)
|
||||
{
|
||||
button->iconic = iconic;
|
||||
if (iconic)
|
||||
{
|
||||
gtk_style_context_remove_class (gtk_widget_get_style_context (GTK_WIDGET (button)),
|
||||
GTK_STYLE_CLASS_MENUITEM);
|
||||
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NORMAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (button)),
|
||||
GTK_STYLE_CLASS_MENUITEM);
|
||||
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
|
||||
}
|
||||
|
||||
update_visibility (button);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (button));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_model_button_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
@@ -195,6 +231,10 @@ gtk_model_button_set_property (GObject *object,
|
||||
gtk_model_button_set_centered (button, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_ICONIC:
|
||||
gtk_model_button_set_iconic (button, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
@@ -223,7 +263,10 @@ gtk_model_button_get_full_border (GtkModelButton *button,
|
||||
border->top = border_width + focus_width + focus_pad;
|
||||
border->bottom = border_width + focus_width + focus_pad;
|
||||
|
||||
*indicator = indicator_size + 2 * indicator_spacing;
|
||||
if (button->iconic)
|
||||
*indicator = 0;
|
||||
else
|
||||
*indicator = indicator_size + 2 * indicator_spacing;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -540,12 +583,22 @@ gtk_model_button_draw (GtkWidget *widget,
|
||||
gint focus_width, focus_pad;
|
||||
gint baseline;
|
||||
|
||||
state = get_button_state (model_button);
|
||||
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
gtk_style_context_save (context);
|
||||
gtk_style_context_set_state (context, state);
|
||||
|
||||
if (model_button->iconic)
|
||||
{
|
||||
GTK_WIDGET_CLASS (gtk_model_button_parent_class)->draw (widget, cr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
width = gtk_widget_get_allocated_width (widget);
|
||||
height = gtk_widget_get_allocated_height (widget);
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
baseline = gtk_widget_get_allocated_baseline (widget);
|
||||
state = get_button_state (model_button);
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"focus-line-width", &focus_width,
|
||||
@@ -566,9 +619,6 @@ gtk_model_button_draw (GtkWidget *widget,
|
||||
y = CLAMP (baseline - indicator_size * button->priv->baseline_align,
|
||||
0, height - indicator_size);
|
||||
|
||||
gtk_style_context_save (context);
|
||||
gtk_style_context_set_state (context, state);
|
||||
|
||||
gtk_render_background (context, cr,
|
||||
border_width, border_width,
|
||||
width - 2 * border_width,
|
||||
@@ -614,12 +664,13 @@ gtk_model_button_draw (GtkWidget *widget,
|
||||
height - 2 * (border_width + focus_pad) - border.top - border.bottom);
|
||||
}
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
|
||||
child = gtk_bin_get_child (GTK_BIN (widget));
|
||||
if (child)
|
||||
gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
|
||||
|
||||
out:
|
||||
gtk_style_context_restore (context);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -640,30 +691,34 @@ gtk_model_button_class_init (GtkModelButtonClass *class)
|
||||
widget_class->draw = gtk_model_button_draw;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_ACTION_ROLE,
|
||||
g_param_spec_enum ("action-role", "action role", "action role",
|
||||
g_param_spec_enum ("action-role", "", "",
|
||||
GTK_TYPE_MENU_TRACKER_ITEM_ROLE,
|
||||
GTK_MENU_TRACKER_ITEM_ROLE_NORMAL,
|
||||
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (object_class, PROP_ICON,
|
||||
g_param_spec_object ("icon", "icon", "icon", G_TYPE_ICON,
|
||||
g_param_spec_object ("icon", "", "", G_TYPE_ICON,
|
||||
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (object_class, PROP_TEXT,
|
||||
g_param_spec_string ("text", "text", "text", NULL,
|
||||
g_param_spec_string ("text", "", "", NULL,
|
||||
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (object_class, PROP_TOGGLED,
|
||||
g_param_spec_boolean ("toggled", "toggled", "toggled", FALSE,
|
||||
g_param_spec_boolean ("toggled", "", "", FALSE,
|
||||
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (object_class, PROP_ACCEL,
|
||||
g_param_spec_string ("accel", "accel", "accel", NULL,
|
||||
g_param_spec_string ("accel", "", "", NULL,
|
||||
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (object_class, PROP_HAS_SUBMENU,
|
||||
g_param_spec_boolean ("has-submenu", "has-submenu", "has-submenu", FALSE,
|
||||
g_param_spec_boolean ("has-submenu", "", "", FALSE,
|
||||
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (object_class, PROP_INVERTED,
|
||||
g_param_spec_boolean ("inverted", "inverted", "inverted", FALSE,
|
||||
g_param_spec_boolean ("inverted", "", "", FALSE,
|
||||
|
||||
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (object_class, PROP_CENTERED,
|
||||
g_param_spec_boolean ("centered", "centered", "centered", FALSE,
|
||||
g_param_spec_boolean ("centered", "", "", FALSE,
|
||||
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (object_class, PROP_ICONIC,
|
||||
g_param_spec_boolean ("iconic", "", "", TRUE,
|
||||
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
gtk_widget_class_set_accessible_role (GTK_WIDGET_CLASS (class), ATK_ROLE_PUSH_BUTTON);
|
||||
|
284
gtk/gtkpopover.c
284
gtk/gtkpopover.c
@@ -37,6 +37,40 @@
|
||||
* is desired on a popover, gtk_popover_set_modal() may be called on it
|
||||
* to tweak its behavior.
|
||||
*
|
||||
* ## GtkPopover as menu replacement
|
||||
*
|
||||
* GtkPopover is often used to replace menus. To facilitate this, it
|
||||
* supports being populated from a #GMenuModel, using
|
||||
* gtk_popover_new_from_model(). In addition to all the regular menu
|
||||
* model features, this function supports rendering sections in the
|
||||
* model in a more compact form, as a row of icon buttons instead of
|
||||
* menu items.
|
||||
*
|
||||
* To use this rendering, set the ”display-hint” attribute
|
||||
* of the section to ”iconic” and set the icons of your items with
|
||||
* the ”verb-icon” attribute.
|
||||
*
|
||||
* |[
|
||||
* <section>
|
||||
* <attribute name="display-hint">iconic</attribute>
|
||||
* <item>
|
||||
* <attribute name="label">Cut</attribute>
|
||||
* <attribute name="action">app.cut</attribute>
|
||||
* <attribute name="verb-icon">edit-cut-symbolic</attribute>
|
||||
* </item>
|
||||
* <item>
|
||||
* <attribute name="label">Copy</attribute>
|
||||
* <attribute name="action">app.copy</attribute>
|
||||
* <attribute name="verb-icon">edit-copy-symbolic</attribute>
|
||||
* </item>
|
||||
* <item>
|
||||
* <attribute name="label">Paste</attribute>
|
||||
* <attribute name="action">app.paste</attribute>
|
||||
* <attribute name="verb-icon">edit-paste-symbolic</attribute>
|
||||
* </item>
|
||||
* </section>
|
||||
* ]|
|
||||
*
|
||||
* Since: 3.12
|
||||
*/
|
||||
|
||||
@@ -62,6 +96,7 @@
|
||||
#include "gtkstack.h"
|
||||
#include "gtksizegroup.h"
|
||||
#include "a11y/gtkpopoveraccessible.h"
|
||||
#include "gtkmenusectionbox.h"
|
||||
|
||||
#define TAIL_GAP_WIDTH 24
|
||||
#define TAIL_HEIGHT 12
|
||||
@@ -88,7 +123,6 @@ struct _GtkPopoverPrivate
|
||||
GtkScrollable *parent_scrollable;
|
||||
GtkAdjustment *vadj;
|
||||
GtkAdjustment *hadj;
|
||||
GtkMenuTracker *tracker;
|
||||
GdkRectangle pointing_to;
|
||||
guint hierarchy_changed_id;
|
||||
guint size_allocate_id;
|
||||
@@ -201,8 +235,6 @@ gtk_popover_dispose (GObject *object)
|
||||
GtkPopover *popover = GTK_POPOVER (object);
|
||||
GtkPopoverPrivate *priv = popover->priv;
|
||||
|
||||
g_clear_pointer (&priv->tracker, gtk_menu_tracker_free);
|
||||
|
||||
if (priv->window)
|
||||
_gtk_window_remove_popover (priv->window, GTK_WIDGET (object));
|
||||
|
||||
@@ -1895,221 +1927,6 @@ gtk_popover_get_modal (GtkPopover *popover)
|
||||
return popover->priv->modal;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_popover_tracker_remove_func (gint position,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkWidget *box = user_data;
|
||||
GList *children;
|
||||
GtkWidget *child;
|
||||
|
||||
g_assert (GTK_IS_BOX (box));
|
||||
|
||||
children = gtk_container_get_children (GTK_CONTAINER (box));
|
||||
child = g_list_nth_data (children, position);
|
||||
g_list_free (children);
|
||||
|
||||
gtk_widget_destroy (child);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_popover_item_activate (GtkWidget *button,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkMenuTrackerItem *item = user_data;
|
||||
|
||||
gtk_menu_tracker_item_activated (item);
|
||||
|
||||
if (gtk_menu_tracker_item_get_role (item) == GTK_MENU_TRACKER_ITEM_ROLE_NORMAL)
|
||||
gtk_widget_hide (gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_ancestors (GtkWidget *widget,
|
||||
GType widget_type,
|
||||
GtkWidget **ancestor,
|
||||
GtkWidget **below)
|
||||
{
|
||||
GtkWidget *a, *b;
|
||||
|
||||
a = NULL;
|
||||
b = widget;
|
||||
while (b != NULL)
|
||||
{
|
||||
a = gtk_widget_get_parent (b);
|
||||
if (!a)
|
||||
return FALSE;
|
||||
if (g_type_is_a (G_OBJECT_TYPE (a), widget_type))
|
||||
break;
|
||||
b = a;
|
||||
}
|
||||
|
||||
*below = b;
|
||||
*ancestor = a;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
close_submenu (GtkWidget *button,
|
||||
gpointer data)
|
||||
{
|
||||
GtkMenuTrackerItem *item = data;
|
||||
GtkWidget *stack;
|
||||
GtkWidget *parent;
|
||||
GtkWidget *focus;
|
||||
|
||||
if (gtk_menu_tracker_item_get_should_request_show (item))
|
||||
gtk_menu_tracker_item_request_submenu_shown (item, FALSE);
|
||||
|
||||
focus = GTK_WIDGET (g_object_get_data (G_OBJECT (button), "focus"));
|
||||
get_ancestors (focus, GTK_TYPE_STACK, &stack, &parent);
|
||||
gtk_stack_set_visible_child (GTK_STACK (stack), parent);
|
||||
gtk_widget_grab_focus (focus);
|
||||
}
|
||||
|
||||
static void
|
||||
open_submenu (GtkWidget *button,
|
||||
gpointer data)
|
||||
{
|
||||
GtkMenuTrackerItem *item = data;
|
||||
GtkWidget *stack;
|
||||
GtkWidget *child;
|
||||
GtkWidget *focus;
|
||||
|
||||
if (gtk_menu_tracker_item_get_should_request_show (item))
|
||||
gtk_menu_tracker_item_request_submenu_shown (item, TRUE);
|
||||
|
||||
focus = GTK_WIDGET (g_object_get_data (G_OBJECT (button), "focus"));
|
||||
get_ancestors (focus, GTK_TYPE_STACK, &stack, &child);
|
||||
gtk_stack_set_visible_child (GTK_STACK (stack), child);
|
||||
gtk_widget_grab_focus (focus);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_popover_tracker_insert_func (GtkMenuTrackerItem *item,
|
||||
gint position,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkWidget *box = user_data;
|
||||
GtkWidget *stack;
|
||||
GtkWidget *widget;
|
||||
GtkSizeGroup *group;
|
||||
|
||||
stack = gtk_widget_get_ancestor (box, GTK_TYPE_STACK);
|
||||
group = g_object_get_data (G_OBJECT (stack), "size-group");
|
||||
|
||||
if (gtk_menu_tracker_item_get_is_separator (item))
|
||||
{
|
||||
GtkWidget *separator;
|
||||
const gchar *label;
|
||||
|
||||
separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
|
||||
|
||||
label = gtk_menu_tracker_item_get_label (item);
|
||||
|
||||
if (label != NULL)
|
||||
{
|
||||
GtkWidget *title;
|
||||
|
||||
title = gtk_label_new (label);
|
||||
g_object_bind_property (item, "label", title, "label", G_BINDING_SYNC_CREATE);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (title), GTK_STYLE_CLASS_SEPARATOR);
|
||||
gtk_widget_set_halign (title, GTK_ALIGN_START);
|
||||
widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
g_object_set (widget,
|
||||
"margin-start", 12,
|
||||
"margin-end", 12,
|
||||
"margin-top", 6,
|
||||
"margin-bottom", 3,
|
||||
NULL);
|
||||
gtk_container_add (GTK_CONTAINER (widget), title);
|
||||
gtk_container_add (GTK_CONTAINER (widget), separator);
|
||||
gtk_widget_show_all (widget);
|
||||
}
|
||||
else
|
||||
{
|
||||
widget = separator;
|
||||
g_object_set (widget,
|
||||
"margin-start", 12,
|
||||
"margin-end", 12,
|
||||
"margin-top", 3,
|
||||
"margin-bottom", 3,
|
||||
NULL);
|
||||
gtk_widget_show (widget);
|
||||
}
|
||||
}
|
||||
else if (gtk_menu_tracker_item_get_has_submenu (item))
|
||||
{
|
||||
GtkMenuTracker *tracker;
|
||||
GtkWidget *child;
|
||||
GtkWidget *button;
|
||||
GtkWidget *content;
|
||||
|
||||
child = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
g_object_set (child, "margin", 10, NULL);
|
||||
|
||||
button = (GtkWidget *) g_object_new (GTK_TYPE_MODEL_BUTTON,
|
||||
"has-submenu", TRUE,
|
||||
"inverted", TRUE,
|
||||
"centered", TRUE,
|
||||
NULL);
|
||||
g_object_bind_property (item, "label", button, "text", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "icon", button, "icon", G_BINDING_SYNC_CREATE);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (child), button);
|
||||
gtk_widget_show_all (child);
|
||||
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (close_submenu), item);
|
||||
|
||||
gtk_stack_add_named (GTK_STACK (stack), child,
|
||||
gtk_menu_tracker_item_get_label (item));
|
||||
gtk_size_group_add_widget (group, child);
|
||||
|
||||
widget = (GtkWidget *) g_object_new (GTK_TYPE_MODEL_BUTTON,
|
||||
"has-submenu", TRUE,
|
||||
NULL);
|
||||
g_object_bind_property (item, "label", widget, "text", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "icon", widget, "icon", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "sensitive", widget, "sensitive", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "visible", widget, "visible", G_BINDING_SYNC_CREATE);
|
||||
gtk_widget_show (widget);
|
||||
|
||||
g_signal_connect (widget, "clicked", G_CALLBACK (open_submenu), item);
|
||||
|
||||
g_object_set_data (G_OBJECT (widget), "focus", button);
|
||||
g_object_set_data (G_OBJECT (button), "focus", widget);
|
||||
|
||||
content = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_halign (content, GTK_ALIGN_FILL);
|
||||
gtk_widget_show (content);
|
||||
gtk_container_add (GTK_CONTAINER (child), content);
|
||||
tracker = gtk_menu_tracker_new_for_item_submenu (item, gtk_popover_tracker_insert_func, gtk_popover_tracker_remove_func, content);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (widget), "submenutracker", tracker, (GDestroyNotify)gtk_menu_tracker_free);
|
||||
|
||||
gtk_widget_show (widget);
|
||||
}
|
||||
else
|
||||
{
|
||||
widget = gtk_model_button_new ();
|
||||
g_object_bind_property (item, "label", widget, "text", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "icon", widget, "icon", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "sensitive", widget, "sensitive", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "visible", widget, "visible", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "role", widget, "action-role", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "toggled", widget, "toggled", G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (item, "accel", widget, "accel", G_BINDING_SYNC_CREATE);
|
||||
|
||||
g_signal_connect (widget, "clicked", G_CALLBACK (gtk_popover_item_activate), item);
|
||||
}
|
||||
|
||||
g_object_set_data_full (G_OBJECT (widget), "GtkMenuTrackerItem", g_object_ref (item), g_object_unref);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (box), widget);
|
||||
gtk_box_reorder_child (GTK_BOX (box), widget, position);
|
||||
}
|
||||
|
||||
static void
|
||||
back_to_main (GtkWidget *popover)
|
||||
{
|
||||
@@ -2158,52 +1975,29 @@ gtk_popover_bind_model (GtkPopover *popover,
|
||||
GMenuModel *model,
|
||||
const gchar *action_namespace)
|
||||
{
|
||||
GtkActionMuxer *muxer;
|
||||
GtkWidget *child;
|
||||
GtkWidget *stack;
|
||||
GtkWidget *box;
|
||||
GtkPopoverPrivate *priv;
|
||||
GtkSizeGroup *group;
|
||||
|
||||
g_return_if_fail (GTK_IS_POPOVER (popover));
|
||||
g_return_if_fail (model == NULL || G_IS_MENU_MODEL (model));
|
||||
|
||||
priv = popover->priv;
|
||||
|
||||
muxer = _gtk_widget_get_action_muxer (GTK_WIDGET (popover));
|
||||
|
||||
g_clear_pointer (&priv->tracker, gtk_menu_tracker_free);
|
||||
|
||||
child = gtk_bin_get_child (GTK_BIN (popover));
|
||||
if (child)
|
||||
gtk_container_remove (GTK_CONTAINER (popover), child);
|
||||
|
||||
gtk_widget_destroy (child);
|
||||
|
||||
if (model)
|
||||
{
|
||||
stack = gtk_stack_new ();
|
||||
group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
|
||||
g_object_set_data_full (G_OBJECT (stack), "size-group", group, g_object_unref);
|
||||
gtk_stack_set_homogeneous (GTK_STACK (stack), FALSE);
|
||||
gtk_stack_set_transition_type (GTK_STACK (stack), GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT);
|
||||
gtk_widget_show (stack);
|
||||
gtk_container_add (GTK_CONTAINER (popover), stack);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
g_object_set (box, "margin", 10, NULL);
|
||||
gtk_widget_show (box);
|
||||
gtk_stack_add_named (GTK_STACK (stack), box, "main");
|
||||
gtk_size_group_add_widget (group, box);
|
||||
gtk_menu_section_box_new_toplevel (GTK_STACK (stack), model, action_namespace);
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (stack), "main");
|
||||
|
||||
g_signal_connect (popover, "unmap", G_CALLBACK (back_to_main), NULL);
|
||||
g_signal_connect (popover, "map", G_CALLBACK (back_to_main), NULL);
|
||||
|
||||
priv->tracker = gtk_menu_tracker_new (GTK_ACTION_OBSERVABLE (muxer),
|
||||
model,
|
||||
TRUE,
|
||||
action_namespace,
|
||||
gtk_popover_tracker_insert_func,
|
||||
gtk_popover_tracker_remove_func,
|
||||
box);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,23 @@
|
||||
<interface>
|
||||
<menu id="menu">
|
||||
<section>
|
||||
<attribute name="display-hint">iconic</attribute>
|
||||
<item>
|
||||
<attribute name="label">Cut</attribute>
|
||||
<attribute name="action">top.cut</attribute>
|
||||
<attribute name="verb-icon">edit-cut-symbolic</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Copy</attribute>
|
||||
<attribute name="action">top.copy</attribute>
|
||||
<attribute name="verb-icon">edit-copy-symbolic</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Paste</attribute>
|
||||
<attribute name="action">top.paste</attribute>
|
||||
<attribute name="verb-icon">edit-paste-symbolic</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label">No action</attribute>
|
||||
@@ -44,6 +62,21 @@
|
||||
<attribute name="label">Item 5b</attribute>
|
||||
<attribute name="action">top.action5</attribute>
|
||||
</item>
|
||||
<section>
|
||||
<attribute name="display-hint">iconic</attribute>
|
||||
<item>
|
||||
<attribute name="label">List</attribute>
|
||||
<attribute name="action">top.set-view</attribute>
|
||||
<attribute name="target">list</attribute>
|
||||
<attribute name="verb-icon">view-list-symbolic</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Grid</attribute>
|
||||
<attribute name="action">top.set-view</attribute>
|
||||
<attribute name="target">grid</attribute>
|
||||
<attribute name="verb-icon">view-grid-symbolic</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<item>
|
||||
<attribute name="label">Item 5c</attribute>
|
||||
<attribute name="action">top.action5</attribute>
|
||||
@@ -53,6 +86,29 @@
|
||||
<attribute name="action">top.action5</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<attribute name="display-hint">iconic</attribute>
|
||||
<attribute name="label">Format</attribute>
|
||||
<item>
|
||||
<attribute name="label">Bold</attribute>
|
||||
<attribute name="action">top.bold</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Italic</attribute>
|
||||
<attribute name="action">top.italic</attribute>
|
||||
<attribute name="verb-icon">format-text-italic-symbolic</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Strikethrough</attribute>
|
||||
<attribute name="action">top.strikethrough</attribute>
|
||||
<attribute name="verb-icon">format-text-strikethrough-symbolic</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Underline</attribute>
|
||||
<attribute name="action">top.underline</attribute>
|
||||
<attribute name="verb-icon">format-text-underline-symbolic</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<attribute name="label">6666</attribute>
|
||||
<item>
|
||||
|
@@ -9,6 +9,14 @@ activate (GSimpleAction *action,
|
||||
}
|
||||
|
||||
static GActionEntry entries[] = {
|
||||
{ "cut", activate, NULL, NULL, NULL },
|
||||
{ "copy", activate, NULL, NULL, NULL },
|
||||
{ "paste", activate, NULL, NULL, NULL },
|
||||
{ "bold", NULL, NULL, "false", NULL },
|
||||
{ "italic", NULL, NULL, "false", NULL },
|
||||
{ "strikethrough", NULL, NULL, "false", NULL },
|
||||
{ "underline", NULL, NULL, "false", NULL },
|
||||
{ "set-view", NULL, "s", "'list'", NULL },
|
||||
{ "action1", activate, NULL, NULL, NULL },
|
||||
{ "action2", NULL, NULL, "true", NULL },
|
||||
{ "action2a", NULL, NULL, "false", NULL },
|
||||
|
Reference in New Issue
Block a user