Commit 9501fc2c authored by Matthias Clasen's avatar Matthias Clasen

Merge branch 'nested-popover-menu' into 'master'

Nested popover menus

See merge request !1076
parents 75472914 1203dc50
Pipeline #113451 passed with stages
in 23 minutes and 7 seconds
......@@ -1905,11 +1905,11 @@ microphone-sensitivity-medium-symbolic</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="togglesmenuitem">
<property name="label">Checks &amp; Radios</property>
<object class="GtkMenuItem" id="checksmenuitem">
<property name="label">_Checks</property>
<property name="use-underline">1</property>
<child type="submenu">
<object class="GtkMenu" id="togglessubmenu">
<object class="GtkMenu" id="checkssubmenu">
<child>
<object class="GtkCheckMenuItem" id="checkmenuitem1">
<property name="label">_Check</property>
......@@ -1953,9 +1953,16 @@ microphone-sensitivity-medium-symbolic</property>
<property name="use-underline">1</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="separatormenuitem"/>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem" id="radiosmenuitem">
<property name="label">_Radios</property>
<property name="use-underline">1</property>
<child type="submenu">
<object class="GtkMenu" id="radiossubmenu">
<child>
<object class="GtkRadioMenuItem" id="radiomenuitem1">
<property name="label">_Radio</property>
......@@ -2007,6 +2014,7 @@ microphone-sensitivity-medium-symbolic</property>
</child>
</object>
</child>
FOO
<child>
<object class="GtkMenuItem" id="menuitem3">
<property name="label" translatable="yes">View</property>
......@@ -3940,7 +3948,7 @@ bad things might happen.</property>
</section>
<section>
<submenu>
<attribute name="label" translatable="yes">Checks &amp; Radios</attribute>
<attribute name="label" translatable="yes">C_hecks</attribute>
<section>
<item>
<attribute name="label" translatable="yes">Check</attribute>
......@@ -3964,6 +3972,9 @@ bad things might happen.</property>
<attribute name="hidden-when">action-missing</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">_Radios</attribute>
<section>
<item>
<attribute name="label" translatable="yes">Radio</attribute>
......
......@@ -1787,6 +1787,8 @@ gtk_map_list_model_get_type
GtkMenu
gtk_menu_new
gtk_menu_new_from_model
GtkPopoverMenuFlags
gtk_menu_new_from_model_full
gtk_menu_reorder_child
gtk_menu_popup_at_rect
gtk_menu_popup_at_widget
......
......@@ -38,18 +38,19 @@ typedef GtkBoxClass GtkMenuSectionBoxClass;
struct _GtkMenuSectionBox
{
GtkBox parent_instance;
GtkMenuSectionBox *toplevel;
GtkMenuTracker *tracker;
GtkBox *item_box;
GtkWidget *separator;
guint separator_sync_idle;
gboolean iconic;
gboolean inline_buttons;
gboolean circular;
gint depth;
GtkSizeGroup *indicators;
GtkBox parent_instance;
GtkMenuSectionBox *toplevel;
GtkMenuTracker *tracker;
GtkBox *item_box;
GtkWidget *separator;
guint separator_sync_idle;
gboolean iconic;
gboolean inline_buttons;
gboolean circular;
gint depth;
GtkPopoverMenuFlags flags;
GtkSizeGroup *indicators;
};
typedef struct
......@@ -295,22 +296,43 @@ gtk_menu_section_box_insert_func (GtkMenuTrackerItem *item,
}
else if (gtk_menu_tracker_item_get_has_link (item, G_MENU_LINK_SUBMENU))
{
GtkWidget *stack = NULL;
GtkWidget *parent = NULL;
gchar *name;
if (box->flags & GTK_POPOVER_MENU_NESTED)
{
GMenuModel *model;
GtkWidget *submenu;
widget = g_object_new (GTK_TYPE_MODEL_BUTTON,
"menu-name", gtk_menu_tracker_item_get_label (item),
"indicator-size-group", box->indicators,
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);
model = _gtk_menu_tracker_item_get_link (item, G_MENU_LINK_SUBMENU);
get_ancestors (GTK_WIDGET (box->toplevel), GTK_TYPE_STACK, &stack, &parent);
g_object_get (gtk_stack_get_page (GTK_STACK (stack), parent), "name", &name, NULL);
gtk_menu_section_box_new_submenu (item, box->toplevel, widget, name);
g_free (name);
submenu = gtk_popover_menu_new_from_model_full (NULL, model, box->flags);
gtk_popover_set_has_arrow (GTK_POPOVER (submenu), FALSE);
gtk_widget_set_valign (submenu, GTK_ALIGN_START);
widget = g_object_new (GTK_TYPE_MODEL_BUTTON,
"popover", submenu,
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);
}
else
{
GtkWidget *stack = NULL;
GtkWidget *parent = NULL;
gchar *name;
widget = g_object_new (GTK_TYPE_MODEL_BUTTON,
"menu-name", gtk_menu_tracker_item_get_label (item),
"indicator-size-group", box->indicators,
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);
get_ancestors (GTK_WIDGET (box->toplevel), GTK_TYPE_STACK, &stack, &parent);
g_object_get (gtk_stack_get_page (GTK_STACK (stack), parent), "name", &name, NULL);
gtk_menu_section_box_new_submenu (item, box->toplevel, widget, name);
g_free (name);
}
}
else
{
......@@ -453,13 +475,15 @@ update_popover_position_cb (GObject *source,
}
void
gtk_menu_section_box_new_toplevel (GtkPopoverMenu *popover,
GMenuModel *model)
gtk_menu_section_box_new_toplevel (GtkPopoverMenu *popover,
GMenuModel *model,
GtkPopoverMenuFlags flags)
{
GtkMenuSectionBox *box;
box = g_object_new (GTK_TYPE_MENU_SECTION_BOX, NULL);
box->indicators = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
box->flags = flags;
gtk_popover_menu_add_submenu (popover, GTK_WIDGET (box), "main");
......@@ -482,6 +506,7 @@ gtk_menu_section_box_new_submenu (GtkMenuTrackerItem *item,
box = g_object_new (GTK_TYPE_MENU_SECTION_BOX, NULL);
box->indicators = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
box->flags = toplevel->flags;
button = g_object_new (GTK_TYPE_MODEL_BUTTON,
"menu-name", name,
......@@ -521,6 +546,7 @@ gtk_menu_section_box_new_section (GtkMenuTrackerItem *item,
box->indicators = g_object_ref (parent->indicators);
box->toplevel = parent->toplevel;
box->depth = parent->depth + 1;
box->flags = parent->flags;
label = gtk_menu_tracker_item_get_label (item);
hint = gtk_menu_tracker_item_get_display_hint (item);
......
......@@ -41,8 +41,9 @@ G_BEGIN_DECLS
typedef struct _GtkMenuSectionBox GtkMenuSectionBox;
GType gtk_menu_section_box_get_type (void) G_GNUC_CONST;
void gtk_menu_section_box_new_toplevel (GtkPopoverMenu *popover,
GMenuModel *model);
void gtk_menu_section_box_new_toplevel (GtkPopoverMenu *popover,
GMenuModel *model,
GtkPopoverMenuFlags flags);
G_END_DECLS
......
......@@ -43,6 +43,7 @@
#include "gtkactionable.h"
#include "gtkeventcontrollermotion.h"
#include "gtkeventcontrollerkey.h"
#include "gtknative.h"
/**
* SECTION:gtkmodelbutton
......@@ -162,6 +163,7 @@ struct _GtkModelButton
GtkWidget *start_indicator;
GtkWidget *end_box;
GtkWidget *end_indicator;
GtkWidget *popover;
gboolean active;
gboolean centered;
gboolean iconic;
......@@ -169,6 +171,7 @@ struct _GtkModelButton
GtkButtonRole role;
GtkSizeGroup *indicators;
char *accel;
guint open_timeout;
};
typedef GtkButtonClass GtkModelButtonClass;
......@@ -184,6 +187,7 @@ enum
PROP_USE_MARKUP,
PROP_ACTIVE,
PROP_MENU_NAME,
PROP_POPOVER,
PROP_ICONIC,
PROP_ACCEL,
PROP_INDICATOR_SIZE_GROUP,
......@@ -275,7 +279,8 @@ gtk_model_button_update_state (GtkModelButton *button)
case GTK_BUTTON_ROLE_NORMAL:
start_type = GTK_CSS_IMAGE_BUILTIN_NONE;
if (button->menu_name != NULL)
if (button->menu_name != NULL ||
button->popover != NULL)
end_type = GTK_CSS_IMAGE_BUILTIN_ARROW_RIGHT;
else
end_type = GTK_CSS_IMAGE_BUILTIN_NONE;
......@@ -344,7 +349,7 @@ update_node_name (GtkModelButton *button)
case GTK_BUTTON_ROLE_NORMAL:
a11y_role = ATK_ROLE_PUSH_BUTTON;
start_name = I_("none");
if (button->menu_name)
if (button->menu_name || button->popover)
end_name = I_("arrow");
else
end_name = I_("none");
......@@ -519,6 +524,28 @@ gtk_model_button_set_iconic (GtkModelButton *button,
g_object_notify_by_pspec (G_OBJECT (button), properties[PROP_ICONIC]);
}
static void
gtk_model_button_set_popover (GtkModelButton *button,
GtkWidget *popover)
{
if (button->popover)
gtk_popover_set_relative_to (GTK_POPOVER (button->popover), NULL);
button->popover = popover;
if (button->popover)
{
gtk_popover_set_relative_to (GTK_POPOVER (button->popover), GTK_WIDGET (button));
gtk_popover_set_position (GTK_POPOVER (button->popover), GTK_POS_RIGHT);
}
update_node_name (button);
gtk_model_button_update_state (button);
gtk_widget_queue_resize (GTK_WIDGET (button));
g_object_notify_by_pspec (G_OBJECT (button), properties[PROP_POPOVER]);
}
static void
update_accel (GtkModelButton *button,
const char *accel)
......@@ -591,6 +618,10 @@ gtk_model_button_get_property (GObject *object,
g_value_set_string (value, button->menu_name);
break;
case PROP_POPOVER:
g_value_set_object (value, button->popover);
break;
case PROP_ICONIC:
g_value_set_boolean (value, button->iconic);
break;
......@@ -643,6 +674,10 @@ gtk_model_button_set_property (GObject *object,
gtk_model_button_set_menu_name (button, g_value_get_string (value));
break;
case PROP_POPOVER:
gtk_model_button_set_popover (button, (GtkWidget *)g_value_get_object (value));
break;
case PROP_ICONIC:
gtk_model_button_set_iconic (button, g_value_get_boolean (value));
break;
......@@ -783,7 +818,9 @@ gtk_model_button_size_allocate (GtkWidget *widget,
int height,
int baseline)
{
if (GTK_MODEL_BUTTON (widget)->iconic)
GtkModelButton *button = GTK_MODEL_BUTTON (widget);
if (button->iconic)
{
GTK_WIDGET_CLASS (gtk_model_button_parent_class)->size_allocate (widget,
width,
......@@ -792,14 +829,12 @@ gtk_model_button_size_allocate (GtkWidget *widget,
}
else
{
GtkModelButton *button;
GtkAllocation child_allocation;
GtkWidget *child;
int start_width, start_height;
int end_width, end_height;
int min;
button = GTK_MODEL_BUTTON (widget);
child = gtk_bin_get_child (GTK_BIN (widget));
gtk_widget_measure (button->start_box,
......@@ -860,6 +895,9 @@ gtk_model_button_size_allocate (GtkWidget *widget,
gtk_widget_size_allocate (child, &child_allocation, baseline);
}
}
if (button->popover)
gtk_native_check_resize (GTK_NATIVE (button->popover));
}
static void
......@@ -888,8 +926,14 @@ close_menu (GtkModelButton *button)
GtkWidget *popover;
popover = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_POPOVER);
if (popover != NULL)
gtk_popover_popdown (GTK_POPOVER (popover));
while (popover != NULL)
{
gtk_popover_popdown (GTK_POPOVER (popover));
if (GTK_IS_POPOVER_MENU (popover))
popover = gtk_popover_menu_get_parent_menu (GTK_POPOVER_MENU (popover));
else
popover = NULL;
}
}
static void
......@@ -901,6 +945,17 @@ gtk_model_button_clicked (GtkButton *button)
{
switch_menu (model_button);
}
else if (model_button->popover != NULL)
{
GtkPopoverMenu *menu;
GtkWidget *submenu;
menu = (GtkPopoverMenu *)gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_POPOVER_MENU);
submenu = model_button->popover;
gtk_popover_popup (GTK_POPOVER (submenu));
gtk_popover_menu_set_open_submenu (menu, submenu);
gtk_popover_menu_set_parent_menu (GTK_POPOVER_MENU (submenu), GTK_WIDGET (menu));
}
else if (model_button->role == GTK_BUTTON_ROLE_NORMAL)
{
close_menu (model_button);
......@@ -915,6 +970,10 @@ gtk_model_button_finalize (GObject *object)
gtk_widget_unparent (button->start_box);
gtk_widget_unparent (button->end_box);
g_free (button->accel);
g_clear_pointer (&button->popover, gtk_widget_unparent);
if (button->open_timeout)
g_source_remove (button->open_timeout);
G_OBJECT_CLASS (gtk_model_button_parent_class)->finalize (object);
}
......@@ -979,6 +1038,20 @@ gtk_model_button_focus (GtkWidget *widget,
switch_menu (button);
return TRUE;
}
else if (direction == GTK_DIR_RIGHT &&
button->role == GTK_BUTTON_ROLE_NORMAL &&
button->popover != NULL)
{
GtkPopoverMenu *menu;
GtkWidget *submenu;
menu = GTK_POPOVER_MENU (gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_POPOVER_MENU));
submenu = button->popover;
gtk_popover_popup (GTK_POPOVER (submenu));
gtk_popover_menu_set_open_submenu (menu, submenu);
gtk_popover_menu_set_parent_menu (GTK_POPOVER_MENU (submenu), GTK_WIDGET (menu));
return TRUE;
}
}
else
{
......@@ -1080,8 +1153,7 @@ gtk_model_button_class_init (GtkModelButtonClass *class)
/**
* GtkModelButton:menu-name:
*
* The name of a submenu to open when the button is activated.
* If this is set, the button should not have an action associated with it.
* The name of a submenu to open when the button is activated. * If this is set, the button should not have an action associated with it.
*/
properties[PROP_MENU_NAME] =
g_param_spec_string ("menu-name",
......@@ -1090,6 +1162,13 @@ gtk_model_button_class_init (GtkModelButtonClass *class)
NULL,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_POPOVER] =
g_param_spec_object ("popover",
P_("Popover"),
P_("Popover to open"),
GTK_TYPE_POPOVER,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GtkModelButton:iconic:
*
......@@ -1129,6 +1208,82 @@ gtk_model_button_class_init (GtkModelButtonClass *class)
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), I_("modelbutton"));
}
static void
close_submenus (GtkPopover *popover)
{
GtkPopoverMenu *menu;
if (GTK_IS_POPOVER_MENU (popover))
{
GtkWidget *submenu;
menu = GTK_POPOVER_MENU (popover);
submenu = gtk_popover_menu_get_open_submenu (menu);
if (submenu)
{
close_submenus (GTK_POPOVER (submenu));
gtk_popover_popdown (GTK_POPOVER (submenu));
gtk_popover_menu_set_open_submenu (menu, NULL);
}
}
}
static gboolean
open_submenu (gpointer data)
{
GtkModelButton *button = data;
GtkPopover *popover;
popover = (GtkPopover*)gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_POPOVER);
if (GTK_IS_POPOVER_MENU (popover))
{
gtk_popover_menu_set_active_item (GTK_POPOVER_MENU (popover), GTK_WIDGET (button));
if (button->popover)
{
GtkWidget *submenu = button->popover;
if (gtk_popover_menu_get_open_submenu (GTK_POPOVER_MENU (popover)) != submenu)
close_submenus (popover);
gtk_popover_popup (GTK_POPOVER (submenu));
gtk_popover_menu_set_open_submenu (GTK_POPOVER_MENU (popover), submenu);
gtk_popover_menu_set_parent_menu (GTK_POPOVER_MENU (submenu), GTK_WIDGET (popover));
}
}
button->open_timeout = 0;
return G_SOURCE_REMOVE;
}
#define OPEN_TIMEOUT 80
static void
start_open (GtkModelButton *button)
{
if (button->open_timeout)
g_source_remove (button->open_timeout);
if (button->popover &&
gtk_widget_get_visible (button->popover))
return;
button->open_timeout = g_timeout_add (OPEN_TIMEOUT, open_submenu, button);
g_source_set_name_by_id (button->open_timeout, "[gtk] open_submenu");
}
static void
stop_open (GtkModelButton *button)
{
if (button->open_timeout)
{
g_source_remove (button->open_timeout);
button->open_timeout = 0;
}
}
static void
enter_cb (GtkEventController *controller,
double x,
......@@ -1151,7 +1306,21 @@ enter_cb (GtkEventController *controller,
NULL);
if (popover && (is || contains))
gtk_popover_menu_set_active_item (GTK_POPOVER_MENU (popover), target);
{
if (gtk_popover_menu_get_open_submenu (GTK_POPOVER_MENU (popover)) != NULL)
start_open (GTK_MODEL_BUTTON (target));
else
open_submenu (target);
}
}
static void
motion_cb (GtkEventController *controller,
double x,
double y,
gpointer data)
{
start_open (GTK_MODEL_BUTTON (data));
}
static void
......@@ -1160,21 +1329,7 @@ leave_cb (GtkEventController *controller,
GdkNotifyType type,
gpointer data)
{
GtkWidget *target;
GtkWidget *popover;
gboolean is;
gboolean contains;
target = gtk_event_controller_get_widget (controller);
popover = gtk_widget_get_ancestor (target, GTK_TYPE_POPOVER_MENU);
g_object_get (controller,
"is-pointer-focus", &is,
"contains-pointer-focus", &contains,
NULL);
if (popover && !(is || contains))
gtk_popover_menu_set_active_item (GTK_POPOVER_MENU (popover), NULL);
stop_open (GTK_MODEL_BUTTON (data));
}
static void
......@@ -1231,8 +1386,9 @@ gtk_model_button_init (GtkModelButton *button)
update_node_ordering (button);
controller = gtk_event_controller_motion_new ();
g_signal_connect (controller, "enter", G_CALLBACK (enter_cb), NULL);
g_signal_connect (controller, "leave", G_CALLBACK (leave_cb), NULL);
g_signal_connect (controller, "enter", G_CALLBACK (enter_cb), button);
g_signal_connect (controller, "motion", G_CALLBACK (motion_cb), button);
g_signal_connect (controller, "leave", G_CALLBACK (leave_cb), button);
gtk_widget_add_controller (GTK_WIDGET (button), controller);
controller = gtk_event_controller_key_new ();
......
......@@ -107,6 +107,7 @@
#include "config.h"
#include "gtkpopoverprivate.h"
#include "gtkpopovermenuprivate.h"
#include "gtknative.h"
#include "gtkwidgetprivate.h"
#include "gtkeventcontrollerkey.h"
......@@ -246,14 +247,50 @@ move_to_rect (GtkPopover *popover)
switch (priv->position)
{
case GTK_POS_LEFT:
parent_anchor = GDK_GRAVITY_WEST;
surface_anchor = GDK_GRAVITY_EAST;
switch (gtk_widget_get_valign (GTK_WIDGET (popover)))
{
case GTK_ALIGN_START:
parent_anchor = GDK_GRAVITY_NORTH_WEST;
surface_anchor = GDK_GRAVITY_NORTH_EAST;
break;
case GTK_ALIGN_END:
parent_anchor = GDK_GRAVITY_SOUTH_WEST;
surface_anchor = GDK_GRAVITY_SOUTH_EAST;
break;
case GTK_ALIGN_FILL:
case GTK_ALIGN_CENTER:
case GTK_ALIGN_BASELINE:
default:
parent_anchor = GDK_GRAVITY_WEST;
surface_anchor = GDK_GRAVITY_EAST;
break;
}
anchor_hints = GDK_ANCHOR_FLIP_X | GDK_ANCHOR_SLIDE_Y;
break;
case GTK_POS_RIGHT:
parent_anchor = GDK_GRAVITY_EAST;
surface_anchor = GDK_GRAVITY_WEST;
switch (gtk_widget_get_valign (GTK_WIDGET (popover)))
{
case GTK_ALIGN_START:
parent_anchor = GDK_GRAVITY_NORTH_EAST;
surface_anchor = GDK_GRAVITY_NORTH_WEST;
break;
case GTK_ALIGN_END:
parent_anchor = GDK_GRAVITY_SOUTH_EAST;
surface_anchor = GDK_GRAVITY_SOUTH_WEST;
break;
case GTK_ALIGN_FILL:
case GTK_ALIGN_CENTER:
case GTK_ALIGN_BASELINE:
default:
parent_anchor = GDK_GRAVITY_EAST;
surface_anchor = GDK_GRAVITY_WEST;
break;
}
anchor_hints = GDK_ANCHOR_FLIP_X | GDK_ANCHOR_SLIDE_Y;
break;
......@@ -362,6 +399,19 @@ gtk_popover_focus_out (GtkWidget *widget)
{
}
static void
close_menu (GtkPopover *popover)
{
while (popover)
{
gtk_popover_popdown (popover);
if (GTK_IS_POPOVER_MENU (popover))
popover = (GtkPopover *)gtk_popover_menu_get_parent_menu (GTK_POPOVER_MENU (popover));
else
popover = NULL;
}
}
static gboolean
gtk_popover_key_pressed (GtkWidget *widget,
guint keyval,
......@@ -370,7 +420,7 @@ gtk_popover_key_pressed (GtkWidget *widget,
{
if (keyval == GDK_KEY_Escape)
{
gtk_popover_popdown (GTK_POPOVER (widget));
close_menu (GTK_POPOVER (widget));
return TRUE;
}
......
......@@ -29,9 +29,12 @@
#include "gtkpopoverprivate.h"
#include "gtkwidgetprivate.h"
#include "gtkeventcontrollerkey.h"
#include "gtkeventcontrollermotion.h"
#include "gtkmain.h"
#include "gtktypebuiltins.h"
#include "gtkbindings.h"
#include "gtkmodelbutton.h"
#include "gtkpopovermenubar.h"
/**
......@@ -124,6 +127,8 @@ struct _GtkPopoverMenu
GtkPopover parent_instance;
GtkWidget *active_item;
GtkWidget *open_submenu;
GtkWidget *parent_menu;
};
struct _GtkPopoverMenuClass
......@@ -137,6 +142,38 @@ enum {
G_DEFINE_TYPE (GtkPopoverMenu, gtk_popover_menu, GTK_TYPE_POPOVER)
GtkWidget *
gtk_popover_menu_get_parent_menu (GtkPopoverMenu *menu)
{
return menu->parent_menu;
}
void
gtk_popover_menu_set_parent_menu (GtkPopoverMenu *menu,
GtkWidget *parent)
{
menu->parent_menu = parent;
}
GtkWidget *
gtk_popover_menu_get_open_submenu (GtkPopoverMenu *menu)
{
return menu->open_submenu;
}
void
gtk_popover_menu_set_open_submenu (GtkPopoverMenu *menu,
GtkWidget *submenu)
{
menu->open_submenu = submenu;
}
GtkWidget *
gtk_popover_menu_get_active_item (GtkPopoverMenu *menu)
{
return menu->active_item;
}
void
gtk_popover_menu_set_active_item (GtkPopoverMenu *menu,
GtkWidget *item)
......@@ -150,8 +187,16 @@ gtk_popover_menu_set_active_item (GtkPopoverMenu *menu,
if (menu->active_item)
{
GtkWidget *popover;
gtk_widget_set_state_flags (menu->active_item, GTK_STATE_FLAG_SELECTED, FALSE);
gtk_widget_grab_focus (menu->active_item);
if (GTK_IS_MODEL_BUTTON (item))
g_object_get (item, "popover", &popover, NULL);
if (!popover || popover != menu->open_submenu)
gtk_widget_grab_focus (menu->active_item);
g_clear_object (&popover);
}
}
}
......@@ -168,14 +213,40 @@ static void
focus_out (GtkEventController *controller,
GdkCrossingMode mode,
GdkNotifyType detail,
GtkPopover *popover)
GtkPopoverMenu *menu)
{
gboolean contains_focus;
g_object_get (controller, "contains-focus", &contains_focus, NULL);
if (!contains_focus)
gtk_popover_popdown (popover);
{
if (menu->parent_menu &&