stack switcher: Support switching during DND

GtkNotebook will switch pages if you hover over a tab
during DND. The same makes sense in GtkStackSwitcher,
so implement it here.
This commit is contained in:
Matthias Clasen 2016-03-13 00:11:52 -05:00
parent fff323df09
commit 9a21ff3cd2

View File

@ -21,6 +21,7 @@
#include "gtkstackswitcher.h"
#include "gtkradiobutton.h"
#include "gtklabel.h"
#include "gtkdnd.h"
#include "gtkorientable.h"
#include "gtkprivate.h"
#include "gtkintl.h"
@ -53,6 +54,8 @@
* stack pages.
*/
#define TIMEOUT_EXPAND 500
typedef struct _GtkStackSwitcherPrivate GtkStackSwitcherPrivate;
struct _GtkStackSwitcherPrivate
{
@ -60,6 +63,8 @@ struct _GtkStackSwitcherPrivate
GHashTable *buttons;
gint icon_size;
gboolean in_child_changed;
GtkWidget *switch_button;
guint switch_timer;
};
enum {
@ -76,6 +81,8 @@ gtk_stack_switcher_init (GtkStackSwitcher *switcher)
GtkStyleContext *context;
GtkStackSwitcherPrivate *priv;
gtk_widget_set_has_window (GTK_WIDGET (switcher), FALSE);
priv = gtk_stack_switcher_get_instance_private (switcher);
priv->icon_size = GTK_ICON_SIZE_MENU;
@ -87,6 +94,9 @@ gtk_stack_switcher_init (GtkStackSwitcher *switcher)
gtk_style_context_add_class (context, GTK_STYLE_CLASS_LINKED);
gtk_orientable_set_orientation (GTK_ORIENTABLE (switcher), GTK_ORIENTATION_HORIZONTAL);
gtk_drag_dest_set (GTK_WIDGET (switcher), 0, NULL, 0, 0);
gtk_drag_dest_set_track_motion (GTK_WIDGET (switcher), TRUE);
}
static void
@ -241,6 +251,102 @@ on_needs_attention_updated (GtkWidget *widget,
update_button (self, widget, button);
}
static void
remove_switch_timer (GtkStackSwitcher *self)
{
GtkStackSwitcherPrivate *priv;
priv = gtk_stack_switcher_get_instance_private (self);
if (priv->switch_timer)
{
g_source_remove (priv->switch_timer);
priv->switch_timer = 0;
}
}
static gboolean
gtk_stack_switcher_switch_timeout (gpointer data)
{
GtkStackSwitcher *self = data;
GtkStackSwitcherPrivate *priv;
GtkWidget *button;
priv = gtk_stack_switcher_get_instance_private (self);
priv->switch_timer = 0;
button = priv->switch_button;
priv->switch_button = NULL;
if (button)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
return G_SOURCE_REMOVE;
}
static gboolean
gtk_stack_switcher_drag_motion (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
guint time)
{
GtkStackSwitcher *self = GTK_STACK_SWITCHER (widget);
GtkStackSwitcherPrivate *priv;
GtkAllocation allocation;
GtkWidget *button;
GHashTableIter iter;
gpointer value;
gboolean retval = FALSE;
gtk_widget_get_allocation (widget, &allocation);
priv = gtk_stack_switcher_get_instance_private (self);
x += allocation.x;
y += allocation.y;
button = NULL;
g_hash_table_iter_init (&iter, priv->buttons);
while (g_hash_table_iter_next (&iter, NULL, &value))
{
gtk_widget_get_allocation (GTK_WIDGET (value), &allocation);
if (x >= allocation.x && x <= allocation.x + allocation.width &&
y >= allocation.y && y <= allocation.y + allocation.height)
{
button = GTK_WIDGET (value);
retval = TRUE;
break;
}
}
if (button != priv->switch_button)
remove_switch_timer (self);
priv->switch_button = button;
if (button && !priv->switch_timer)
{
priv->switch_timer = gdk_threads_add_timeout (TIMEOUT_EXPAND,
gtk_stack_switcher_switch_timeout,
self);
g_source_set_name_by_id (priv->switch_timer, "[gtk+] gtk_stack_switcher_switch_timeout");
}
return retval;
}
static void
gtk_stack_switcher_drag_leave (GtkWidget *widget,
GdkDragContext *context,
guint time)
{
GtkStackSwitcher *self = GTK_STACK_SWITCHER (widget);
remove_switch_timer (self);
}
static void
add_child (GtkWidget *widget,
GtkStackSwitcher *self)
@ -252,6 +358,7 @@ add_child (GtkWidget *widget,
priv = gtk_stack_switcher_get_instance_private (self);
button = gtk_radio_button_new (NULL);
gtk_widget_set_focus_on_click (button, FALSE);
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE);
@ -530,6 +637,7 @@ gtk_stack_switcher_dispose (GObject *object)
{
GtkStackSwitcher *switcher = GTK_STACK_SWITCHER (object);
remove_switch_timer (switcher);
gtk_stack_switcher_set_stack (switcher, NULL);
G_OBJECT_CLASS (gtk_stack_switcher_parent_class)->dispose (object);
@ -559,6 +667,8 @@ gtk_stack_switcher_class_init (GtkStackSwitcherClass *class)
object_class->dispose = gtk_stack_switcher_dispose;
object_class->finalize = gtk_stack_switcher_finalize;
widget_class->drag_motion = gtk_stack_switcher_drag_motion;
widget_class->drag_leave = gtk_stack_switcher_drag_leave;
/**
* GtkStackSwitcher:icon-size:
*