forked from AuroraMiddleware/gtk
GtkScaleButton: Use a popover
This works better than the contortions we're currently doing with an undecorated dialog, and grabs. https://bugzilla.gnome.org/show_bug.cgi?id=723181
This commit is contained in:
parent
e9fb8ad1f7
commit
c46b1c2a05
@ -31,9 +31,6 @@
|
||||
# include "gtkprinteroptionwidget.h"
|
||||
#endif
|
||||
|
||||
/* Some forward declarations of internal types */
|
||||
GType _gtk_scale_button_scale_get_type (void);
|
||||
|
||||
/* This function is referred to in gtk/glade/gtk-private-widgets.xml
|
||||
* and is used to ensure the private types for use in Glade while
|
||||
* editing UI files that define GTK+'s various composite widget classes.
|
||||
@ -45,7 +42,6 @@ gtk_glade_catalog_init (const gchar *catalog_name)
|
||||
g_type_ensure (GTK_TYPE_COLOR_SWATCH);
|
||||
g_type_ensure (GTK_TYPE_COLOR_PLANE);
|
||||
g_type_ensure (GTK_TYPE_COLOR_SCALE);
|
||||
g_type_ensure (_gtk_scale_button_scale_get_type ());
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
g_type_ensure (GTK_TYPE_PRINTER_OPTION_WIDGET);
|
||||
|
@ -3,6 +3,7 @@
|
||||
* Copyright (C) 2006, 2007 Christian Persch
|
||||
* Copyright (C) 2006 Jan Arne Petersen
|
||||
* Copyright (C) 2005-2007 Red Hat, Inc.
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* - Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||
@ -48,6 +49,7 @@
|
||||
#include "gtkmain.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtkorientable.h"
|
||||
#include "gtkpopover.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkscale.h"
|
||||
#include "gtkbox.h"
|
||||
@ -99,21 +101,15 @@ struct _GtkScaleButtonPrivate
|
||||
GtkWidget *box;
|
||||
GtkWidget *scale;
|
||||
GtkWidget *image;
|
||||
GtkWidget *active_button;
|
||||
|
||||
GtkIconSize size;
|
||||
GtkOrientation orientation;
|
||||
|
||||
guint click_id;
|
||||
gint click_timeout;
|
||||
guint timeout : 1;
|
||||
gdouble direction;
|
||||
guint32 pop_time;
|
||||
|
||||
gchar **icon_list;
|
||||
|
||||
GdkDevice *grab_pointer;
|
||||
GdkDevice *grab_keyboard;
|
||||
|
||||
GtkAdjustment *adjustment; /* needed because it must be settable in init() */
|
||||
};
|
||||
|
||||
@ -134,37 +130,22 @@ static void gtk_scale_button_set_orientation_private (GtkScaleButton *button,
|
||||
GtkOrientation orientation);
|
||||
static gboolean gtk_scale_button_scroll (GtkWidget *widget,
|
||||
GdkEventScroll *event);
|
||||
static void gtk_scale_button_screen_changed (GtkWidget *widget,
|
||||
GdkScreen *previous_screen);
|
||||
static gboolean gtk_scale_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event);
|
||||
static gboolean gtk_scale_button_key_release (GtkWidget *widget,
|
||||
GdkEventKey *event);
|
||||
static void gtk_scale_button_clicked (GtkButton *button);
|
||||
static void gtk_scale_button_popup (GtkWidget *widget);
|
||||
static void gtk_scale_button_popdown (GtkWidget *widget);
|
||||
static gboolean cb_dock_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event,
|
||||
gpointer user_data);
|
||||
static gboolean cb_dock_key_release (GtkWidget *widget,
|
||||
GdkEventKey *event,
|
||||
gpointer user_data);
|
||||
static gboolean cb_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event,
|
||||
gpointer user_data);
|
||||
static gboolean cb_button_release (GtkWidget *widget,
|
||||
GdkEventButton *event,
|
||||
gpointer user_data);
|
||||
static void cb_dock_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed,
|
||||
gpointer user_data);
|
||||
static gboolean cb_dock_grab_broken_event (GtkWidget *widget,
|
||||
gboolean was_grabbed,
|
||||
gpointer user_data);
|
||||
static void cb_scale_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed,
|
||||
gpointer user_data);
|
||||
static void gtk_scale_button_update_icon (GtkScaleButton *button);
|
||||
static void gtk_scale_button_scale_value_changed(GtkRange *range);
|
||||
static void cb_button_clicked (GtkWidget *button,
|
||||
gpointer user_data);
|
||||
static void gtk_scale_button_update_icon (GtkScaleButton *button);
|
||||
static void cb_scale_value_changed (GtkRange *range,
|
||||
gpointer user_data);
|
||||
static void cb_popup_mapped (GtkWidget *popup,
|
||||
gpointer user_data);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkScaleButton, gtk_scale_button, GTK_TYPE_BUTTON,
|
||||
G_ADD_PRIVATE (GtkScaleButton)
|
||||
@ -173,26 +154,12 @@ G_DEFINE_TYPE_WITH_CODE (GtkScaleButton, gtk_scale_button, GTK_TYPE_BUTTON,
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0, };
|
||||
|
||||
/*
|
||||
* ScaleButtonScale forward declarations
|
||||
*/
|
||||
#define GTK_TYPE_SCALE_BUTTON_SCALE (_gtk_scale_button_scale_get_type ())
|
||||
#define GTK_SCALE_BUTTON_SCALE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SCALE_BUTTON_SCALE, GtkScaleButtonScale))
|
||||
#define GTK_IS_SCALE_BUTTON_SCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SCALE_BUTTON_SCALE))
|
||||
GType _gtk_scale_button_scale_get_type (void);
|
||||
|
||||
typedef struct _GtkScaleButtonScale
|
||||
{
|
||||
GtkScale parent_instance;
|
||||
GtkScaleButton *button;
|
||||
} GtkScaleButtonScale;
|
||||
|
||||
|
||||
static void
|
||||
gtk_scale_button_class_init (GtkScaleButtonClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass);
|
||||
GtkBindingSet *binding_set;
|
||||
|
||||
gobject_class->constructor = gtk_scale_button_constructor;
|
||||
@ -201,10 +168,9 @@ gtk_scale_button_class_init (GtkScaleButtonClass *klass)
|
||||
gobject_class->set_property = gtk_scale_button_set_property;
|
||||
gobject_class->get_property = gtk_scale_button_get_property;
|
||||
|
||||
widget_class->button_press_event = gtk_scale_button_press;
|
||||
widget_class->key_release_event = gtk_scale_button_key_release;
|
||||
widget_class->scroll_event = gtk_scale_button_scroll;
|
||||
widget_class->screen_changed = gtk_scale_button_screen_changed;
|
||||
|
||||
button_class->clicked = gtk_scale_button_clicked;
|
||||
|
||||
/**
|
||||
* GtkScaleButton:orientation:
|
||||
@ -368,13 +334,11 @@ gtk_scale_button_class_init (GtkScaleButtonClass *klass)
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkScaleButton, image);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkScaleButton, adjustment);
|
||||
|
||||
gtk_widget_class_bind_template_callback (widget_class, cb_dock_button_press);
|
||||
gtk_widget_class_bind_template_callback (widget_class, cb_dock_key_release);
|
||||
gtk_widget_class_bind_template_callback (widget_class, cb_dock_grab_notify);
|
||||
gtk_widget_class_bind_template_callback (widget_class, cb_dock_grab_broken_event);
|
||||
gtk_widget_class_bind_template_callback (widget_class, cb_button_press);
|
||||
gtk_widget_class_bind_template_callback (widget_class, cb_button_release);
|
||||
gtk_widget_class_bind_template_callback (widget_class, cb_scale_grab_notify);
|
||||
gtk_widget_class_bind_template_callback (widget_class, cb_button_clicked);
|
||||
gtk_widget_class_bind_template_callback (widget_class, cb_scale_value_changed);
|
||||
gtk_widget_class_bind_template_callback (widget_class, cb_popup_mapped);
|
||||
|
||||
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_SCALE_BUTTON_ACCESSIBLE);
|
||||
}
|
||||
@ -386,18 +350,11 @@ gtk_scale_button_init (GtkScaleButton *button)
|
||||
|
||||
button->priv = priv = gtk_scale_button_get_instance_private (button);
|
||||
|
||||
priv->timeout = FALSE;
|
||||
priv->click_id = 0;
|
||||
priv->click_timeout = CLICK_TIMEOUT;
|
||||
priv->orientation = GTK_ORIENTATION_VERTICAL;
|
||||
|
||||
g_type_ensure (GTK_TYPE_SCALE_BUTTON_SCALE);
|
||||
gtk_widget_init_template (GTK_WIDGET (button));
|
||||
|
||||
/* Assign GtkScaleButtonScale pointer back to 'button',
|
||||
* since there's no property for that we can't do it in the template
|
||||
*/
|
||||
GTK_SCALE_BUTTON_SCALE (priv->scale)->button = button;
|
||||
gtk_popover_set_relative_to (GTK_POPOVER (priv->dock), GTK_WIDGET (button));
|
||||
|
||||
/* Need a local reference to the adjustment */
|
||||
g_object_ref (priv->adjustment);
|
||||
@ -805,11 +762,6 @@ gtk_scale_button_set_orientation_private (GtkScaleButton *button,
|
||||
gtk_range_set_inverted (GTK_RANGE (priv->scale), FALSE);
|
||||
}
|
||||
|
||||
/* FIXME: without this, the popup window appears as a square
|
||||
* after changing the orientation
|
||||
*/
|
||||
gtk_window_resize (GTK_WINDOW (priv->dock), 1, 1);
|
||||
|
||||
g_object_notify (G_OBJECT (button), "orientation");
|
||||
}
|
||||
}
|
||||
@ -852,361 +804,84 @@ gtk_scale_button_scroll (GtkWidget *widget,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_scale_button_screen_changed (GtkWidget *widget,
|
||||
GdkScreen *previous_screen)
|
||||
{
|
||||
GtkScaleButton *button = (GtkScaleButton *) widget;
|
||||
GtkScaleButtonPrivate *priv;
|
||||
GdkScreen *screen;
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
if (gtk_widget_has_screen (widget) == FALSE)
|
||||
return;
|
||||
|
||||
priv = button->priv;
|
||||
|
||||
screen = gtk_widget_get_screen (widget);
|
||||
g_value_init (&value, G_TYPE_INT);
|
||||
if (gdk_screen_get_setting (screen,
|
||||
"gtk-double-click-time",
|
||||
&value) == FALSE)
|
||||
{
|
||||
priv->click_timeout = CLICK_TIMEOUT;
|
||||
return;
|
||||
}
|
||||
|
||||
priv->click_timeout = g_value_get_int (&value);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_scale_popup (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
guint32 time)
|
||||
gtk_scale_popup (GtkWidget *widget)
|
||||
{
|
||||
GtkAllocation allocation, dock_allocation, scale_allocation;
|
||||
GtkScaleButton *button;
|
||||
GtkScaleButtonPrivate *priv;
|
||||
GtkAdjustment *adjustment;
|
||||
gint x, y, m, dx, dy, sx, sy, startoff;
|
||||
gint min_slider_size;
|
||||
gdouble v;
|
||||
GdkScreen *screen;
|
||||
gboolean is_moved;
|
||||
GdkDevice *device, *keyboard, *pointer;
|
||||
GtkScaleButton *button = GTK_SCALE_BUTTON (widget);
|
||||
GtkScaleButtonPrivate *priv = button->priv;
|
||||
|
||||
is_moved = FALSE;
|
||||
button = GTK_SCALE_BUTTON (widget);
|
||||
priv = button->priv;
|
||||
adjustment = priv->adjustment;
|
||||
|
||||
screen = gtk_widget_get_screen (widget);
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
|
||||
/* position roughly */
|
||||
gtk_window_set_screen (GTK_WINDOW (priv->dock), screen);
|
||||
|
||||
gdk_window_get_origin (gtk_widget_get_window (widget),
|
||||
&x, &y);
|
||||
x += allocation.x;
|
||||
y += allocation.y;
|
||||
|
||||
gtk_window_set_transient_for (GTK_WINDOW (priv->dock),
|
||||
GTK_WINDOW (gtk_widget_get_toplevel (widget)));
|
||||
|
||||
if (priv->orientation == GTK_ORIENTATION_VERTICAL)
|
||||
gtk_window_move (GTK_WINDOW (priv->dock), x, y - (SCALE_SIZE / 2));
|
||||
else
|
||||
gtk_window_move (GTK_WINDOW (priv->dock), x - (SCALE_SIZE / 2), y);
|
||||
|
||||
gtk_widget_show_all (priv->dock);
|
||||
|
||||
gdk_window_get_origin (gtk_widget_get_window (priv->dock),
|
||||
&dx, &dy);
|
||||
gtk_widget_get_allocation (priv->dock, &dock_allocation);
|
||||
dx += dock_allocation.x;
|
||||
dy += dock_allocation.y;
|
||||
|
||||
|
||||
gdk_window_get_origin (gtk_widget_get_window (priv->scale),
|
||||
&sx, &sy);
|
||||
gtk_widget_get_allocation (priv->scale, &scale_allocation);
|
||||
sx += scale_allocation.x;
|
||||
sy += scale_allocation.y;
|
||||
|
||||
priv->timeout = TRUE;
|
||||
|
||||
/* position (needs widget to be shown already) */
|
||||
v = gtk_scale_button_get_value (button) / (gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_lower (adjustment));
|
||||
min_slider_size = gtk_range_get_min_slider_size (GTK_RANGE (priv->scale));
|
||||
|
||||
if (priv->orientation == GTK_ORIENTATION_VERTICAL)
|
||||
{
|
||||
startoff = sy - dy;
|
||||
|
||||
x += (allocation.width - dock_allocation.width) / 2;
|
||||
y -= startoff;
|
||||
y -= min_slider_size / 2;
|
||||
m = scale_allocation.height - min_slider_size;
|
||||
y -= m * (1.0 - v);
|
||||
}
|
||||
else
|
||||
{
|
||||
startoff = sx - dx;
|
||||
|
||||
x -= startoff;
|
||||
y += (allocation.height - dock_allocation.height) / 2;
|
||||
x -= min_slider_size / 2;
|
||||
m = scale_allocation.width - min_slider_size;
|
||||
x -= m * v;
|
||||
}
|
||||
|
||||
/* Make sure the dock stays inside the monitor */
|
||||
if (event->type == GDK_BUTTON_PRESS)
|
||||
{
|
||||
GtkAllocation d_allocation;
|
||||
int monitor;
|
||||
GdkEventButton *button_event = (GdkEventButton *) event;
|
||||
GdkRectangle rect;
|
||||
GtkWidget *d;
|
||||
|
||||
d = GTK_WIDGET (priv->dock);
|
||||
monitor = gdk_screen_get_monitor_at_point (screen,
|
||||
button_event->x_root,
|
||||
button_event->y_root);
|
||||
gdk_screen_get_monitor_workarea (screen, monitor, &rect);
|
||||
|
||||
if (priv->orientation == GTK_ORIENTATION_VERTICAL)
|
||||
y += button_event->y;
|
||||
else
|
||||
x += button_event->x;
|
||||
|
||||
/* Move the dock, but set is_moved so we
|
||||
* don't forward the first click later on,
|
||||
* as it could make the scale go to the bottom */
|
||||
gtk_widget_get_allocation (d, &d_allocation);
|
||||
if (y < rect.y)
|
||||
{
|
||||
y = rect.y;
|
||||
is_moved = TRUE;
|
||||
}
|
||||
else if (y + d_allocation.height > rect.height + rect.y)
|
||||
{
|
||||
y = rect.y + rect.height - d_allocation.height;
|
||||
is_moved = TRUE;
|
||||
}
|
||||
|
||||
if (x < rect.x)
|
||||
{
|
||||
x = rect.x;
|
||||
is_moved = TRUE;
|
||||
}
|
||||
else if (x + d_allocation.width > rect.width + rect.x)
|
||||
{
|
||||
x = rect.x + rect.width - d_allocation.width;
|
||||
is_moved = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_window_move (GTK_WINDOW (priv->dock), x, y);
|
||||
|
||||
if (event->type == GDK_BUTTON_PRESS)
|
||||
GTK_WIDGET_CLASS (gtk_scale_button_parent_class)->button_press_event (widget, (GdkEventButton *) event);
|
||||
|
||||
device = gdk_event_get_device (event);
|
||||
|
||||
if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
|
||||
{
|
||||
keyboard = device;
|
||||
pointer = gdk_device_get_associated_device (device);
|
||||
}
|
||||
else
|
||||
{
|
||||
pointer = device;
|
||||
keyboard = gdk_device_get_associated_device (device);
|
||||
}
|
||||
|
||||
/* grab focus */
|
||||
gtk_device_grab_add (priv->dock, pointer, TRUE);
|
||||
|
||||
if (gdk_device_grab (pointer, gtk_widget_get_window (priv->dock),
|
||||
GDK_OWNERSHIP_WINDOW, TRUE,
|
||||
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
|
||||
GDK_POINTER_MOTION_MASK, NULL, time) != GDK_GRAB_SUCCESS)
|
||||
{
|
||||
gtk_device_grab_remove (priv->dock, pointer);
|
||||
gtk_widget_hide (priv->dock);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (gdk_device_grab (keyboard, gtk_widget_get_window (priv->dock),
|
||||
GDK_OWNERSHIP_WINDOW, TRUE,
|
||||
GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
|
||||
NULL, time) != GDK_GRAB_SUCCESS)
|
||||
{
|
||||
gdk_device_ungrab (pointer, time);
|
||||
gtk_device_grab_remove (priv->dock, pointer);
|
||||
gtk_widget_hide (priv->dock);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gtk_widget_grab_focus (priv->dock);
|
||||
priv->grab_keyboard = keyboard;
|
||||
priv->grab_pointer = pointer;
|
||||
|
||||
if (event->type == GDK_BUTTON_PRESS && !is_moved)
|
||||
{
|
||||
GdkEventButton *e;
|
||||
GdkEventButton *button_event = (GdkEventButton *) event;
|
||||
|
||||
/* forward event to the slider */
|
||||
e = (GdkEventButton *) gdk_event_copy ((GdkEvent *) event);
|
||||
e->window = gtk_widget_get_window (priv->scale);
|
||||
|
||||
/* position: the X position isn't relevant, halfway will work just fine.
|
||||
* The vertical position should be *exactly* in the middle of the slider
|
||||
* of the scale; if we don't do that correctly, it'll move from its current
|
||||
* position, which means a position change on-click, which is bad.
|
||||
*/
|
||||
gtk_widget_get_allocation (priv->scale, &scale_allocation);
|
||||
if (priv->orientation == GTK_ORIENTATION_VERTICAL)
|
||||
{
|
||||
e->x = scale_allocation.width / 2;
|
||||
m = scale_allocation.height - min_slider_size;
|
||||
e->y = ((1.0 - v) * m) + min_slider_size / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
e->y = scale_allocation.height / 2;
|
||||
m = scale_allocation.width - min_slider_size;
|
||||
e->x = (v * m) + min_slider_size / 2;
|
||||
}
|
||||
|
||||
gtk_widget_event (priv->scale, (GdkEvent *) e);
|
||||
e->window = button_event->window;
|
||||
gdk_event_free ((GdkEvent *) e);
|
||||
}
|
||||
|
||||
gtk_widget_grab_focus (priv->scale);
|
||||
|
||||
priv->pop_time = time;
|
||||
gtk_widget_show (priv->dock);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_scale_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
static void
|
||||
gtk_scale_button_popdown (GtkWidget *widget)
|
||||
{
|
||||
return gtk_scale_popup (widget, (GdkEvent *) event, event->time);
|
||||
GtkScaleButton *button = GTK_SCALE_BUTTON (widget);
|
||||
GtkScaleButtonPrivate *priv = button->priv;
|
||||
|
||||
gtk_widget_hide (priv->dock);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_scale_button_clicked (GtkButton *button)
|
||||
{
|
||||
gtk_scale_popup (GTK_WIDGET (button));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_scale_button_popup (GtkWidget *widget)
|
||||
{
|
||||
GdkEvent *ev;
|
||||
|
||||
/* This is a callback for a keybinding signal,
|
||||
* current event should be the key event that
|
||||
* triggered it.
|
||||
*/
|
||||
ev = gtk_get_current_event ();
|
||||
|
||||
if (ev->type != GDK_KEY_PRESS &&
|
||||
ev->type != GDK_KEY_RELEASE)
|
||||
{
|
||||
gdk_event_free (ev);
|
||||
ev = gdk_event_new (GDK_KEY_RELEASE);
|
||||
ev->key.time = GDK_CURRENT_TIME;
|
||||
}
|
||||
|
||||
gtk_scale_popup (widget, ev, ev->key.time);
|
||||
gdk_event_free (ev);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_scale_button_key_release (GtkWidget *widget,
|
||||
GdkEventKey *event)
|
||||
{
|
||||
return gtk_bindings_activate_event (G_OBJECT (widget), event);
|
||||
}
|
||||
|
||||
/* This is called when the grab is broken for
|
||||
* either the dock, or the scale itself */
|
||||
static void
|
||||
gtk_scale_button_grab_notify (GtkScaleButton *button,
|
||||
gboolean was_grabbed)
|
||||
{
|
||||
GtkScaleButtonPrivate *priv;
|
||||
GtkWidget *toplevel, *grab_widget;
|
||||
GtkWindowGroup *group;
|
||||
|
||||
priv = button->priv;
|
||||
|
||||
if (!priv->grab_pointer ||
|
||||
!gtk_widget_device_is_shadowed (GTK_WIDGET (button), priv->grab_pointer))
|
||||
return;
|
||||
|
||||
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
|
||||
|
||||
if (GTK_IS_WINDOW (toplevel))
|
||||
group = gtk_window_get_group (GTK_WINDOW (toplevel));
|
||||
else
|
||||
group = gtk_window_get_group (NULL);
|
||||
|
||||
grab_widget = gtk_window_group_get_current_device_grab (group, priv->grab_pointer);
|
||||
|
||||
if (grab_widget &&
|
||||
gtk_widget_is_ancestor (grab_widget, priv->dock))
|
||||
return;
|
||||
|
||||
gdk_device_ungrab (priv->grab_keyboard, GDK_CURRENT_TIME);
|
||||
gdk_device_ungrab (priv->grab_pointer, GDK_CURRENT_TIME);
|
||||
gtk_device_grab_remove (priv->dock, priv->grab_pointer);
|
||||
|
||||
priv->grab_keyboard = NULL;
|
||||
priv->grab_pointer = NULL;
|
||||
|
||||
/* hide again */
|
||||
gtk_widget_hide (priv->dock);
|
||||
priv->timeout = FALSE;
|
||||
gtk_scale_popup (widget);
|
||||
}
|
||||
|
||||
/*
|
||||
* +/- button callbacks.
|
||||
*/
|
||||
|
||||
static gboolean
|
||||
cb_button_timeout (gpointer user_data)
|
||||
button_click (GtkScaleButton *button,
|
||||
GtkWidget *active)
|
||||
{
|
||||
GtkScaleButton *button;
|
||||
GtkScaleButtonPrivate *priv;
|
||||
GtkAdjustment *adjustment;
|
||||
GtkScaleButtonPrivate *priv = button->priv;
|
||||
GtkAdjustment *adjustment = priv->adjustment;
|
||||
gboolean can_continue = TRUE;
|
||||
gdouble val;
|
||||
gboolean res = TRUE;
|
||||
|
||||
button = GTK_SCALE_BUTTON (user_data);
|
||||
priv = button->priv;
|
||||
|
||||
if (priv->click_id == 0)
|
||||
return FALSE;
|
||||
|
||||
adjustment = priv->adjustment;
|
||||
|
||||
val = gtk_scale_button_get_value (button);
|
||||
val += priv->direction;
|
||||
|
||||
if (active == priv->plus_button)
|
||||
val += gtk_adjustment_get_page_increment (adjustment);
|
||||
else
|
||||
val -= gtk_adjustment_get_page_increment (adjustment);
|
||||
|
||||
if (val <= gtk_adjustment_get_lower (adjustment))
|
||||
{
|
||||
res = FALSE;
|
||||
can_continue = FALSE;
|
||||
val = gtk_adjustment_get_lower (adjustment);
|
||||
}
|
||||
else if (val > gtk_adjustment_get_upper (adjustment))
|
||||
{
|
||||
res = FALSE;
|
||||
can_continue = FALSE;
|
||||
val = gtk_adjustment_get_upper (adjustment);
|
||||
}
|
||||
|
||||
gtk_scale_button_set_value (button, val);
|
||||
|
||||
return can_continue;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cb_button_timeout (gpointer user_data)
|
||||
{
|
||||
GtkScaleButton *button = GTK_SCALE_BUTTON (user_data);
|
||||
GtkScaleButtonPrivate *priv = button->priv;
|
||||
gboolean res;
|
||||
|
||||
if (priv->click_id == 0)
|
||||
return G_SOURCE_REMOVE;
|
||||
|
||||
res = button_click (button, priv->active_button);
|
||||
if (!res)
|
||||
{
|
||||
g_source_remove (priv->click_id);
|
||||
@ -1221,23 +896,19 @@ cb_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkScaleButton *button;
|
||||
GtkScaleButtonPrivate *priv;
|
||||
GtkAdjustment *adjustment;
|
||||
|
||||
button = GTK_SCALE_BUTTON (user_data);
|
||||
priv = button->priv;
|
||||
adjustment = priv->adjustment;
|
||||
GtkScaleButton *button = GTK_SCALE_BUTTON (user_data);
|
||||
GtkScaleButtonPrivate *priv = button->priv;
|
||||
gint double_click_time;
|
||||
|
||||
if (priv->click_id != 0)
|
||||
g_source_remove (priv->click_id);
|
||||
|
||||
if (widget == priv->plus_button)
|
||||
priv->direction = fabs (gtk_adjustment_get_page_increment (adjustment));
|
||||
else
|
||||
priv->direction = - fabs (gtk_adjustment_get_page_increment (adjustment));
|
||||
priv->active_button = widget;
|
||||
|
||||
priv->click_id = gdk_threads_add_timeout (priv->click_timeout,
|
||||
g_object_get (gtk_widget_get_settings (widget),
|
||||
"gtk-double-click-time", &double_click_time,
|
||||
NULL);
|
||||
priv->click_id = gdk_threads_add_timeout (double_click_time,
|
||||
cb_button_timeout,
|
||||
button);
|
||||
g_source_set_name_by_id (priv->click_id, "[gtk+] cb_button_timeout");
|
||||
@ -1251,11 +922,8 @@ cb_button_release (GtkWidget *widget,
|
||||
GdkEventButton *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkScaleButton *button;
|
||||
GtkScaleButtonPrivate *priv;
|
||||
|
||||
button = GTK_SCALE_BUTTON (user_data);
|
||||
priv = button->priv;
|
||||
GtkScaleButton *button = GTK_SCALE_BUTTON (user_data);
|
||||
GtkScaleButtonPrivate *priv = button->priv;
|
||||
|
||||
if (priv->click_id != 0)
|
||||
{
|
||||
@ -1267,231 +935,27 @@ cb_button_release (GtkWidget *widget,
|
||||
}
|
||||
|
||||
static void
|
||||
cb_dock_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkScaleButton *button = (GtkScaleButton *) user_data;
|
||||
|
||||
gtk_scale_button_grab_notify (button, was_grabbed);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cb_dock_grab_broken_event (GtkWidget *widget,
|
||||
gboolean was_grabbed,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkScaleButton *button = (GtkScaleButton *) user_data;
|
||||
|
||||
gtk_scale_button_grab_notify (button, FALSE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Scale callbacks */
|
||||
|
||||
static void
|
||||
gtk_scale_button_release_grab (GtkScaleButton *button,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GdkEventButton *e;
|
||||
GtkScaleButtonPrivate *priv;
|
||||
|
||||
priv = button->priv;
|
||||
|
||||
/* ungrab focus */
|
||||
gdk_device_ungrab (priv->grab_keyboard, event->time);
|
||||
gdk_device_ungrab (priv->grab_pointer, event->time);
|
||||
gtk_device_grab_remove (priv->dock, priv->grab_pointer);
|
||||
|
||||
priv->grab_keyboard = NULL;
|
||||
priv->grab_pointer = NULL;
|
||||
|
||||
/* hide again */
|
||||
gtk_widget_hide (priv->dock);
|
||||
priv->timeout = FALSE;
|
||||
|
||||
e = (GdkEventButton *) gdk_event_copy ((GdkEvent *) event);
|
||||
e->window = gtk_widget_get_window (GTK_WIDGET (button));
|
||||
e->type = GDK_BUTTON_RELEASE;
|
||||
gtk_widget_event (GTK_WIDGET (button), (GdkEvent *) e);
|
||||
e->window = event->window;
|
||||
gdk_event_free ((GdkEvent *) e);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cb_dock_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event,
|
||||
gpointer user_data)
|
||||
cb_button_clicked (GtkWidget *widget,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkScaleButton *button = GTK_SCALE_BUTTON (user_data);
|
||||
GtkScaleButtonPrivate *priv = button->priv;
|
||||
|
||||
if (event->type == GDK_BUTTON_PRESS)
|
||||
{
|
||||
gtk_scale_button_release_grab (button, event);
|
||||
return TRUE;
|
||||
}
|
||||
if (priv->click_id != 0)
|
||||
return;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_scale_button_popdown (GtkWidget *widget)
|
||||
{
|
||||
GtkScaleButton *button;
|
||||
GtkScaleButtonPrivate *priv;
|
||||
|
||||
button = GTK_SCALE_BUTTON (widget);
|
||||
priv = button->priv;
|
||||
|
||||
/* ungrab focus */
|
||||
gdk_device_ungrab (priv->grab_keyboard, GDK_CURRENT_TIME);
|
||||
gdk_device_ungrab (priv->grab_pointer, GDK_CURRENT_TIME);
|
||||
gtk_device_grab_remove (priv->dock, priv->grab_pointer);
|
||||
|
||||
priv->grab_keyboard = NULL;
|
||||
priv->grab_pointer = NULL;
|
||||
|
||||
/* hide again */
|
||||
gtk_widget_hide (priv->dock);
|
||||
priv->timeout = FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cb_dock_key_release (GtkWidget *widget,
|
||||
GdkEventKey *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (event->keyval == GDK_KEY_Escape)
|
||||
{
|
||||
gtk_scale_button_popdown (GTK_WIDGET (user_data));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!gtk_bindings_activate_event (G_OBJECT (widget), event))
|
||||
{
|
||||
/* The popup hasn't managed the event, pass onto the button */
|
||||
gtk_bindings_activate_event (G_OBJECT (user_data), event);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
cb_scale_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkScaleButton *button = (GtkScaleButton *) user_data;
|
||||
|
||||
gtk_scale_button_grab_notify (button, was_grabbed);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scale stuff.
|
||||
*/
|
||||
typedef struct _GtkScaleButtonScaleClass
|
||||
{
|
||||
GtkScaleClass parent_class;
|
||||
} GtkScaleButtonScaleClass;
|
||||
|
||||
static gboolean gtk_scale_button_scale_press (GtkWidget *widget,
|
||||
GdkEventButton *event);
|
||||
static gboolean gtk_scale_button_scale_release (GtkWidget *widget,
|
||||
GdkEventButton *event);
|
||||
|
||||
G_DEFINE_TYPE (GtkScaleButtonScale, _gtk_scale_button_scale, GTK_TYPE_SCALE)
|
||||
|
||||
static void
|
||||
_gtk_scale_button_scale_class_init (GtkScaleButtonScaleClass *klass)
|
||||
{
|
||||
GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
|
||||
GtkRangeClass *gtkrange_class = GTK_RANGE_CLASS (klass);
|
||||
|
||||
gtkwidget_class->button_press_event = gtk_scale_button_scale_press;
|
||||
gtkwidget_class->button_release_event = gtk_scale_button_scale_release;
|
||||
gtkrange_class->value_changed = gtk_scale_button_scale_value_changed;
|
||||
}
|
||||
|
||||
static void
|
||||
_gtk_scale_button_scale_init (GtkScaleButtonScale *scale)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_scale_button_scale_press (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GtkScaleButtonPrivate *priv;
|
||||
|
||||
/* Avoid a crash when using a GtkScaleButtonScale without a GtkScaleButton,
|
||||
* this can happen while editing gtkscalebutton.ui in Glade
|
||||
*/
|
||||
if (!GTK_SCALE_BUTTON_SCALE (widget)->button)
|
||||
return GTK_WIDGET_CLASS (_gtk_scale_button_scale_parent_class)->button_release_event (widget, event);
|
||||
|
||||
priv = GTK_SCALE_BUTTON_SCALE (widget)->button->priv;
|
||||
|
||||
/* the scale will grab input; if we have input grabbed, all goes
|
||||
* horribly wrong, so let's not do that.
|
||||
*/
|
||||
gtk_device_grab_remove (priv->dock, event->device);
|
||||
|
||||
return GTK_WIDGET_CLASS (_gtk_scale_button_scale_parent_class)->button_press_event (widget, event);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_scale_button_scale_release (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GtkScaleButton *button = GTK_SCALE_BUTTON_SCALE (widget)->button;
|
||||
gboolean res;
|
||||
|
||||
/* Avoid a crash when using a GtkScaleButtonScale without a GtkScaleButton,
|
||||
* this can happen while editing gtkscalebutton.ui in Glade
|
||||
*/
|
||||
if (!button)
|
||||
return GTK_WIDGET_CLASS (_gtk_scale_button_scale_parent_class)->button_release_event (widget, event);
|
||||
|
||||
if (button->priv->timeout)
|
||||
{
|
||||
/* if we did a quick click, leave the window open; else, hide it */
|
||||
if (event->time > button->priv->pop_time + button->priv->click_timeout)
|
||||
{
|
||||
|
||||
gtk_scale_button_release_grab (button, event);
|
||||
GTK_WIDGET_CLASS (_gtk_scale_button_scale_parent_class)->button_release_event (widget, event);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
button->priv->timeout = FALSE;
|
||||
}
|
||||
|
||||
res = GTK_WIDGET_CLASS (_gtk_scale_button_scale_parent_class)->button_release_event (widget, event);
|
||||
|
||||
/* the scale will release input; right after that, we *have to* grab
|
||||
* it back so we can catch out-of-scale clicks and hide the popup,
|
||||
* so I basically want a g_signal_connect_after_always(), but I can't
|
||||
* find that, so we do this complex 'first-call-parent-then-do-actual-
|
||||
* action' thingy...
|
||||
*/
|
||||
gtk_device_grab_add (button->priv->dock, event->device, TRUE);
|
||||
|
||||
return res;
|
||||
button_click (button, widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_scale_button_update_icon (GtkScaleButton *button)
|
||||
{
|
||||
GtkScaleButtonPrivate *priv;
|
||||
GtkScaleButtonPrivate *priv = button->priv;
|
||||
GtkAdjustment *adjustment;
|
||||
gdouble value;
|
||||
const gchar *name;
|
||||
guint num_icons;
|
||||
|
||||
priv = button->priv;
|
||||
|
||||
if (!priv->icon_list || priv->icon_list[0] == '\0')
|
||||
{
|
||||
gtk_image_set_from_icon_name (GTK_IMAGE (priv->image),
|
||||
@ -1545,8 +1009,7 @@ gtk_scale_button_update_icon (GtkScaleButton *button)
|
||||
gdouble step;
|
||||
guint i;
|
||||
|
||||
step = (gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_lower (adjustment)) / (num_icons - 2);
|
||||
i = (guint) ((value - gtk_adjustment_get_lower (adjustment)) / step) + 2;
|
||||
step = (gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_lower (adjustment)) / (num_icons - 2); i = (guint) ((value - gtk_adjustment_get_lower (adjustment)) / step) + 2;
|
||||
g_assert (i < num_icons);
|
||||
name = priv->icon_list[i];
|
||||
}
|
||||
@ -1557,17 +1020,12 @@ gtk_scale_button_update_icon (GtkScaleButton *button)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_scale_button_scale_value_changed (GtkRange *range)
|
||||
cb_scale_value_changed (GtkRange *range,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkScaleButton *button = GTK_SCALE_BUTTON_SCALE (range)->button;
|
||||
GtkScaleButton *button = user_data;
|
||||
gdouble value;
|
||||
|
||||
/* Avoid a crash when using a GtkScaleButtonScale without a GtkScaleButton,
|
||||
* this can happen while editing gtkscalebutton.ui in Glade
|
||||
*/
|
||||
if (!button)
|
||||
return;
|
||||
|
||||
value = gtk_range_get_value (range);
|
||||
|
||||
gtk_scale_button_update_icon (button);
|
||||
@ -1575,3 +1033,13 @@ gtk_scale_button_scale_value_changed (GtkRange *range)
|
||||
g_signal_emit (button, signals[VALUE_CHANGED], 0, value);
|
||||
g_object_notify (G_OBJECT (button), "value");
|
||||
}
|
||||
|
||||
static void
|
||||
cb_popup_mapped (GtkWidget *popup,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkScaleButton *button = user_data;
|
||||
GtkScaleButtonPrivate *priv = button->priv;
|
||||
|
||||
gtk_widget_grab_focus (priv->scale);
|
||||
}
|
||||
|
@ -20,80 +20,88 @@
|
||||
<property name="step_increment">2</property>
|
||||
<property name="page_increment">20</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="dock">
|
||||
<property name="name">gtk-scalebutton-popup-window</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="type">popup</property>
|
||||
<property name="decorated">False</property>
|
||||
<signal name="button-press-event" handler="cb_dock_button_press" swapped="no"/>
|
||||
<signal name="grab-broken-event" handler="cb_dock_grab_broken_event" swapped="no"/>
|
||||
<signal name="grab-notify" handler="cb_dock_grab_notify" swapped="no"/>
|
||||
<signal name="key-release-event" handler="cb_dock_key_release" swapped="no"/>
|
||||
<object class="GtkPopover" id="dock">
|
||||
<signal name="map" handler="cb_popup_mapped" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkFrame" id="frame1">
|
||||
<object class="GtkBox" id="box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">out</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="margin">4</property>
|
||||
<property name="spacing">4</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="box">
|
||||
<object class="GtkButton" id="plus_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="relief">none</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
<class name="image-button"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkButton" id="plus_button">
|
||||
<property name="label">+</property>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="relief">none</property>
|
||||
<signal name="button-press-event" handler="cb_button_press" swapped="no"/>
|
||||
<signal name="button-release-event" handler="cb_button_release" swapped="no"/>
|
||||
<property name="icon-name">list-add-symbolic</property>
|
||||
<property name="icon-size">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScaleButtonScale" id="scale">
|
||||
<property name="height_request">100</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="adjustment">adjustment</property>
|
||||
<property name="inverted">True</property>
|
||||
<property name="round_digits">1</property>
|
||||
<property name="draw_value">False</property>
|
||||
<signal name="grab-notify" handler="cb_scale_grab_notify" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="minus_button">
|
||||
<property name="label">-</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="relief">none</property>
|
||||
<signal name="button-press-event" handler="cb_button_press" swapped="no"/>
|
||||
<signal name="button-release-event" handler="cb_button_release" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<signal name="button-press-event" handler="cb_button_press" swapped="no"/>
|
||||
<signal name="button-release-event" handler="cb_button_release" swapped="no"/>
|
||||
<signal name="clicked" handler="cb_button_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
<child>
|
||||
<object class="GtkScale" id="scale">
|
||||
<property name="height_request">100</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="adjustment">adjustment</property>
|
||||
<property name="inverted">True</property>
|
||||
<property name="round_digits">1</property>
|
||||
<property name="draw_value">False</property>
|
||||
<signal name="value-changed" handler="cb_scale_value_changed" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="minus_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="relief">none</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
<class name="image-button"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="icon-name">list-remove-symbolic</property>
|
||||
<property name="icon-size">0</property>
|
||||
</object>
|
||||
</child>
|
||||
<signal name="button-press-event" handler="cb_button_press" swapped="no"/>
|
||||
<signal name="button-release-event" handler="cb_button_release" swapped="no"/>
|
||||
<signal name="clicked" handler="cb_button_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
Loading…
Reference in New Issue
Block a user