forked from AuroraMiddleware/gtk
popover: Implement auto mnemonics
Unfortunately, this involves copying a bunch of code from gtkwindow.c. The only difference here is that we add a private method to turn this off, which will be used by GtkPopoverMenu to implement its own auto mnemonics.
This commit is contained in:
parent
fc0b0b14a8
commit
642503afb4
154
gtk/gtkpopover.c
154
gtk/gtkpopover.c
@ -102,6 +102,7 @@
|
||||
#include "gtknative.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkeventcontrollerkey.h"
|
||||
#include "gtkeventcontrollerfocus.h"
|
||||
#include "gtkcssnodeprivate.h"
|
||||
#include "gtkbinlayout.h"
|
||||
#include "gtkenums.h"
|
||||
@ -130,6 +131,8 @@
|
||||
#include "wayland/gdkwayland.h"
|
||||
#endif
|
||||
|
||||
#define MNEMONICS_DELAY 300 /* ms */
|
||||
|
||||
#define TAIL_GAP_WIDTH 24
|
||||
#define TAIL_HEIGHT 12
|
||||
|
||||
@ -147,6 +150,9 @@ typedef struct {
|
||||
gboolean autohide;
|
||||
gboolean has_arrow;
|
||||
gboolean mnemonics_visible;
|
||||
gboolean disable_auto_mnemonics;
|
||||
|
||||
guint mnemonics_display_timeout_id;
|
||||
|
||||
GtkWidget *contents_widget;
|
||||
GtkCssNode *arrow_node;
|
||||
@ -579,18 +585,137 @@ close_menu (GtkPopover *popover)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_popover_has_mnemonic_modifier_pressed (GtkPopover *popover)
|
||||
{
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
GList *seats, *s;
|
||||
gboolean retval = FALSE;
|
||||
|
||||
seats = gdk_display_list_seats (gtk_widget_get_display (GTK_WIDGET (popover)));
|
||||
|
||||
for (s = seats; s; s = s->next)
|
||||
{
|
||||
GdkDevice *dev = gdk_seat_get_pointer (s->data);
|
||||
GdkModifierType mask;
|
||||
|
||||
gdk_device_get_state (dev, priv->surface, NULL, &mask);
|
||||
if ((mask & gtk_accelerator_get_default_mod_mask ()) == GDK_MOD1_MASK)
|
||||
{
|
||||
retval = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free (seats);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
schedule_mnemonics_visible_cb (gpointer data)
|
||||
{
|
||||
GtkPopover *popover = data;
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
priv->mnemonics_display_timeout_id = 0;
|
||||
|
||||
gtk_popover_set_mnemonics_visible (popover, TRUE);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_popover_schedule_mnemonics_visible (GtkPopover *popover)
|
||||
{
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
if (priv->mnemonics_display_timeout_id)
|
||||
return;
|
||||
|
||||
priv->mnemonics_display_timeout_id =
|
||||
g_timeout_add (MNEMONICS_DELAY, schedule_mnemonics_visible_cb, popover);
|
||||
g_source_set_name_by_id (priv->mnemonics_display_timeout_id, "[gtk] popover_schedule_mnemonics_visible_cb");
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_popover_focus_in (GtkWidget *widget)
|
||||
{
|
||||
GtkPopover *popover = GTK_POPOVER (widget);
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
if (priv->disable_auto_mnemonics)
|
||||
return;
|
||||
|
||||
if (gtk_widget_get_visible (widget))
|
||||
{
|
||||
if (gtk_popover_has_mnemonic_modifier_pressed (popover))
|
||||
gtk_popover_schedule_mnemonics_visible (popover);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_popover_focus_out (GtkWidget *widget)
|
||||
{
|
||||
GtkPopover *popover = GTK_POPOVER (widget);
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
if (priv->disable_auto_mnemonics)
|
||||
return;
|
||||
|
||||
gtk_popover_set_mnemonics_visible (popover, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
update_mnemonics_visible (GtkPopover *popover,
|
||||
guint keyval,
|
||||
GdkModifierType state,
|
||||
gboolean visible)
|
||||
{
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
if (priv->disable_auto_mnemonics)
|
||||
return;
|
||||
|
||||
if ((keyval == GDK_KEY_Alt_L || keyval == GDK_KEY_Alt_R) &&
|
||||
((state & (gtk_accelerator_get_default_mod_mask ()) & ~(GDK_MOD1_MASK)) == 0))
|
||||
{
|
||||
if (visible)
|
||||
gtk_popover_schedule_mnemonics_visible (popover);
|
||||
else
|
||||
gtk_popover_set_mnemonics_visible (popover, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_popover_key_pressed (GtkWidget *widget,
|
||||
guint keyval,
|
||||
guint keycode,
|
||||
GdkModifierType state)
|
||||
{
|
||||
GtkPopover *popover = GTK_POPOVER (widget);
|
||||
|
||||
if (keyval == GDK_KEY_Escape)
|
||||
{
|
||||
close_menu (GTK_POPOVER (widget));
|
||||
close_menu (popover);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
update_mnemonics_visible (popover, keyval, state, TRUE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_popover_key_released (GtkWidget *widget,
|
||||
guint keyval,
|
||||
guint keycode,
|
||||
GdkModifierType state)
|
||||
{
|
||||
GtkPopover *popover = GTK_POPOVER (widget);
|
||||
|
||||
update_mnemonics_visible (popover, keyval, state, FALSE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -709,8 +834,14 @@ gtk_popover_init (GtkPopover *popover)
|
||||
|
||||
controller = gtk_event_controller_key_new ();
|
||||
g_signal_connect_swapped (controller, "key-pressed", G_CALLBACK (gtk_popover_key_pressed), popover);
|
||||
g_signal_connect_swapped (controller, "key-released", G_CALLBACK (gtk_popover_key_released), popover);
|
||||
gtk_widget_add_controller (GTK_WIDGET (popover), controller);
|
||||
|
||||
controller = gtk_event_controller_focus_new ();
|
||||
g_signal_connect_swapped (controller, "enter", G_CALLBACK (gtk_popover_focus_in), popover);
|
||||
g_signal_connect_swapped (controller, "leave", G_CALLBACK (gtk_popover_focus_out), popover);
|
||||
gtk_widget_add_controller (widget, controller);
|
||||
|
||||
priv->arrow_node = gtk_css_node_new ();
|
||||
gtk_css_node_set_name (priv->arrow_node, g_quark_from_static_string ("arrow"));
|
||||
gtk_css_node_set_parent (priv->arrow_node, gtk_widget_get_css_node (widget));
|
||||
@ -797,6 +928,7 @@ gtk_popover_show (GtkWidget *widget)
|
||||
static void
|
||||
gtk_popover_hide (GtkWidget *widget)
|
||||
{
|
||||
gtk_popover_set_mnemonics_visible (GTK_POPOVER (widget), FALSE);
|
||||
_gtk_widget_set_visible_flag (widget, FALSE);
|
||||
gtk_widget_unmap (widget);
|
||||
g_signal_emit (widget, signals[CLOSED], 0);
|
||||
@ -899,6 +1031,12 @@ gtk_popover_finalize (GObject *object)
|
||||
|
||||
g_clear_pointer (&priv->layout, gdk_popup_layout_unref);
|
||||
|
||||
if (priv->mnemonics_display_timeout_id)
|
||||
{
|
||||
g_source_remove (priv->mnemonics_display_timeout_id);
|
||||
priv->mnemonics_display_timeout_id = 0;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (gtk_popover_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@ -1938,6 +2076,12 @@ gtk_popover_set_mnemonics_visible (GtkPopover *popover,
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_MNEMONICS_VISIBLE]);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (popover));
|
||||
|
||||
if (priv->mnemonics_display_timeout_id)
|
||||
{
|
||||
g_source_remove (priv->mnemonics_display_timeout_id);
|
||||
priv->mnemonics_display_timeout_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1957,3 +2101,11 @@ gtk_popover_get_mnemonics_visible (GtkPopover *popover)
|
||||
|
||||
return priv->mnemonics_visible;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_popover_disable_auto_mnemonics (GtkPopover *popover)
|
||||
{
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
priv->disable_auto_mnemonics = TRUE;
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ G_BEGIN_DECLS
|
||||
|
||||
GtkWidget *gtk_popover_get_contents_widget (GtkPopover *popover);
|
||||
|
||||
void gtk_popover_disable_auto_mnemonics (GtkPopover *popover);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_POPOVER_PRIVATE_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user