X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkrange.c;h=8339e52b70c195a829185fd0ddad7217012e3d79;hb=a89d420270d1a856e072ed87c365b0176f102e6c;hp=0d32f0bb02af1d3bb997c76b39badbbf453491ad;hpb=bad24bc1192e7ac546cc8ffd33cdcadefab14de9;p=~andy%2Fgtk diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c index 0d32f0bb0..8339e52b7 100644 --- a/gtk/gtkrange.c +++ b/gtk/gtkrange.c @@ -13,9 +13,7 @@ * 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, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -30,18 +28,19 @@ #include #include +#include "gtkrange.h" + +#include "gtkadjustment.h" +#include "gtkcolorscaleprivate.h" +#include "gtkintl.h" #include "gtkmain.h" #include "gtkmarshalers.h" #include "gtkorientableprivate.h" -#include "gtkrange.h" +#include "gtkprivate.h" #include "gtkscale.h" -#include "gtkcolorscaleprivate.h" #include "gtkscrollbar.h" -#include "gtkwindow.h" -#include "gtkprivate.h" -#include "gtkintl.h" -#include "gtkmain.h" #include "gtktypebuiltins.h" +#include "gtkwindow.h" #include "a11y/gtkrangeaccessible.h" /** @@ -117,8 +116,6 @@ struct _GtkRangePrivate gint slider_start; /* Slider range along the long dimension, in widget->window coords */ gint slider_end; - guint repaint_id; - /* Steppers are: < > ---- < > * a b c d */ @@ -141,6 +138,9 @@ struct _GtkRangePrivate /* The range has an origin, should be drawn differently. Used by GtkScale */ guint has_origin : 1; + /* Whether we're doing fine adjustment */ + guint zoom : 1; + /* Fill level */ guint show_fill_level : 1; guint restrict_to_fill_level : 1; @@ -1500,10 +1500,6 @@ gtk_range_destroy (GtkWidget *widget) gtk_range_remove_step_timer (range); - if (priv->repaint_id) - g_source_remove (priv->repaint_id); - priv->repaint_id = 0; - if (priv->adjustment) { g_signal_handlers_disconnect_by_func (priv->adjustment, @@ -1730,9 +1726,11 @@ gtk_range_realize (GtkWidget *widget) attributes.wclass = GDK_INPUT_ONLY; attributes.event_mask = gtk_widget_get_events (widget); attributes.event_mask |= (GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_SCROLL_MASK | + GDK_SMOOTH_SCROLL_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); @@ -1740,7 +1738,7 @@ gtk_range_realize (GtkWidget *widget) priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); - gdk_window_set_user_data (priv->event_window, range); + gtk_widget_register_window (widget, priv->event_window); } static void @@ -1751,7 +1749,7 @@ gtk_range_unrealize (GtkWidget *widget) gtk_range_remove_step_timer (range); - gdk_window_set_user_data (priv->event_window, NULL); + gtk_widget_unregister_window (widget, priv->event_window); gdk_window_destroy (priv->event_window); priv->event_window = NULL; @@ -2009,15 +2007,12 @@ gtk_range_draw (GtkWidget *widget, GtkStateFlags widget_state; gint focus_line_width = 0; gint focus_padding = 0; - gboolean touchscreen; gboolean draw_trough = TRUE; gboolean draw_slider = TRUE; GtkStyleContext *context; + GtkBorder margin; context = gtk_widget_get_style_context (widget); - g_object_get (gtk_widget_get_settings (widget), - "gtk-touchscreen-mode", &touchscreen, - NULL); if (GTK_IS_SCALE (widget) && gtk_adjustment_get_upper (priv->adjustment) == gtk_adjustment_get_lower (priv->adjustment)) @@ -2037,11 +2032,6 @@ gtk_range_draw (GtkWidget *widget, "focus-padding", &focus_padding, NULL); - /* we're now exposing, so there's no need to force early repaints */ - if (priv->repaint_id) - g_source_remove (priv->repaint_id); - priv->repaint_id = 0; - gtk_range_calc_marks (range); gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment)); @@ -2118,10 +2108,16 @@ gtk_range_draw (GtkWidget *widget, gtk_style_context_save (context); gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH); + gtk_style_context_get_margin (context, widget_state, &margin); + + x += margin.left; + y += margin.top; + width -= margin.left + margin.right; + height -= margin.top + margin.bottom; if (draw_trough) { - if (!priv->has_origin) + if (!priv->has_origin || !draw_slider) { gtk_render_background (context, cr, x, y, width, height); @@ -2247,13 +2243,6 @@ gtk_range_draw (GtkWidget *widget, fill_y += priv->trough.height - fill_height; } -#if 0 - if (fill_level < gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_page_size (priv->adjustment)) - fill_detail = "trough-fill-level-full"; - else - fill_detail = "trough-fill-level"; -#endif - gtk_render_activity (context, cr, fill_x, fill_y, fill_width, fill_height); @@ -2279,7 +2268,7 @@ gtk_range_draw (GtkWidget *widget, state &= ~(GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_ACTIVE); - if (!touchscreen && priv->mouse_location == MOUSE_SLIDER && !(state & GTK_STATE_FLAG_INSENSITIVE)) + if (priv->mouse_location == MOUSE_SLIDER && !(state & GTK_STATE_FLAG_INSENSITIVE)) state |= GTK_STATE_FLAG_PRELIGHT; if (priv->grab_location == MOUSE_SLIDER) @@ -2309,28 +2298,28 @@ gtk_range_draw (GtkWidget *widget, draw_stepper (range, STEPPER_A, cr, priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT, priv->grab_location == MOUSE_STEPPER_A, - !touchscreen && priv->mouse_location == MOUSE_STEPPER_A, + priv->mouse_location == MOUSE_STEPPER_A, widget_state); if (priv->has_stepper_b) draw_stepper (range, STEPPER_B, cr, priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT, priv->grab_location == MOUSE_STEPPER_B, - !touchscreen && priv->mouse_location == MOUSE_STEPPER_B, + priv->mouse_location == MOUSE_STEPPER_B, widget_state); if (priv->has_stepper_c) draw_stepper (range, STEPPER_C, cr, priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT, priv->grab_location == MOUSE_STEPPER_C, - !touchscreen && priv->mouse_location == MOUSE_STEPPER_C, + priv->mouse_location == MOUSE_STEPPER_C, widget_state); if (priv->has_stepper_d) draw_stepper (range, STEPPER_D, cr, priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT, priv->grab_location == MOUSE_STEPPER_D, - !touchscreen && priv->mouse_location == MOUSE_STEPPER_D, + priv->mouse_location == MOUSE_STEPPER_D, widget_state); return FALSE; @@ -2347,15 +2336,11 @@ range_grab_add (GtkRange *range, if (device == priv->grab_device) return; - if (priv->grab_device != NULL) - { - g_warning ("GtkRange already had a grab device, releasing device grab"); - gtk_device_grab_remove (GTK_WIDGET (range), priv->grab_device); - } - - /* we don't actually gdk_grab, since a button is down */ - gtk_device_grab_add (GTK_WIDGET (range), device, TRUE); - + /* Don't perform any GDK/GTK+ grab here. Since a button + * is down, there's an ongoing implicit grab on + * priv->event_window, which pretty much guarantees this + * is the only widget receiving the pointer events. + */ priv->grab_location = location; priv->grab_button = button; priv->grab_device = device; @@ -2372,9 +2357,10 @@ range_grab_remove (GtkRange *range) if (priv->grab_device) { - gtk_device_grab_remove (GTK_WIDGET (range), - priv->grab_device); + GdkDevice *grab_device = priv->grab_device; + priv->grab_device = NULL; + gtk_device_grab_remove (GTK_WIDGET (range), grab_device); } location = priv->grab_location; @@ -2384,6 +2370,8 @@ range_grab_remove (GtkRange *range) if (gtk_range_update_mouse_location (range) || location != MOUSE_OUTSIDE) gtk_widget_queue_draw (GTK_WIDGET (range)); + + priv->zoom = FALSE; } static GtkScrollType @@ -2450,7 +2438,7 @@ range_get_scroll_for_grab (GtkRange *range) static gdouble coord_to_value (GtkRange *range, - gint coord) + gdouble coord) { GtkRangePrivate *priv = range->priv; gdouble frac; @@ -2532,7 +2520,10 @@ gtk_range_button_press (GtkWidget *widget, { GtkRange *range = GTK_RANGE (widget); GtkRangePrivate *priv = range->priv; - GdkDevice *device; + GdkDevice *device, *source_device; + GdkInputSource source; + gboolean primary_warps; + gint page_increment_button, warp_button; if (!gtk_widget_has_focus (widget)) gtk_widget_grab_focus (widget); @@ -2542,12 +2533,29 @@ gtk_range_button_press (GtkWidget *widget, return FALSE; device = gdk_event_get_device ((GdkEvent *) event); + source_device = gdk_event_get_source_device ((GdkEvent *) event); + source = gdk_device_get_source (source_device); + priv->mouse_x = event->x; priv->mouse_y = event->y; if (gtk_range_update_mouse_location (range)) gtk_widget_queue_draw (widget); + g_object_get (gtk_widget_get_settings (widget), + "gtk-primary-button-warps-slider", &primary_warps, + NULL); + if (primary_warps) + { + warp_button = GDK_BUTTON_PRIMARY; + page_increment_button = GDK_BUTTON_SECONDARY; + } + else + { + warp_button = GDK_BUTTON_MIDDLE; + page_increment_button = GDK_BUTTON_PRIMARY; + } + if (priv->mouse_location == MOUSE_SLIDER && gdk_event_triggers_context_menu ((GdkEvent *)event)) { @@ -2558,23 +2566,24 @@ gtk_range_button_press (GtkWidget *widget, return TRUE; } - if (priv->mouse_location == MOUSE_TROUGH && - event->button == GDK_BUTTON_PRIMARY) + if (source != GDK_SOURCE_TOUCHSCREEN && + priv->mouse_location == MOUSE_TROUGH && + event->button == page_increment_button) { - /* button 1 steps by page increment, as with button 2 on a stepper + /* button 2 steps by page increment, as with button 2 on a stepper */ GtkScrollType scroll; gdouble click_value; - + click_value = coord_to_value (range, priv->orientation == GTK_ORIENTATION_VERTICAL ? event->y : event->x); priv->trough_click_forward = click_value > gtk_adjustment_get_value (priv->adjustment); range_grab_add (range, device, MOUSE_TROUGH, event->button); - + scroll = range_get_scroll_for_grab (range); - + gtk_range_add_step_timer (range, scroll); return TRUE; @@ -2609,17 +2618,17 @@ gtk_range_button_press (GtkWidget *widget, return TRUE; } else if ((priv->mouse_location == MOUSE_TROUGH && - event->button == GDK_BUTTON_MIDDLE) || + (source == GDK_SOURCE_TOUCHSCREEN || + event->button == warp_button)) || priv->mouse_location == MOUSE_SLIDER) { gboolean need_value_update = FALSE; /* Any button can be used to drag the slider, but you can start - * dragging the slider with a trough click using button 2; - * On button 2 press, we warp the slider to mouse position, - * then begin the slider drag. + * dragging the slider with a trough click using button 1; + * we warp the slider to mouse position, then begin the slider drag. */ - if (event->button == GDK_BUTTON_MIDDLE) + if (priv->mouse_location != MOUSE_SLIDER) { gdouble slider_low_value, slider_high_value, new_value; @@ -2647,6 +2656,12 @@ gtk_range_button_press (GtkWidget *widget, */ need_value_update = TRUE; } + else + { + /* Shift-click in the slider = fine adjustment */ + if (event->state & GDK_SHIFT_MASK) + priv->zoom = TRUE; + } if (priv->orientation == GTK_ORIENTATION_VERTICAL) { @@ -2679,13 +2694,14 @@ update_slider_position (GtkRange *range, gint mouse_y) { GtkRangePrivate *priv = range->priv; - gint delta; - gint c; + gdouble delta; + gdouble c; gdouble new_value; gboolean handled; gdouble next_value; gdouble mark_value; gdouble mark_delta; + gdouble zoom; gint i; if (priv->orientation == GTK_ORIENTATION_VERTICAL) @@ -2693,11 +2709,25 @@ update_slider_position (GtkRange *range, else delta = mouse_x - priv->slide_initial_coordinate; - c = priv->slide_initial_slider_position + delta; + if (priv->zoom) + { + zoom = MIN(1.0, (priv->orientation == GTK_ORIENTATION_VERTICAL ? + priv->trough.height : priv->trough.width) / + (gtk_adjustment_get_upper (priv->adjustment) - + gtk_adjustment_get_lower (priv->adjustment) - + gtk_adjustment_get_page_size (priv->adjustment))); + /* the above is ineffective for scales, so just set a zoom factor */ + if (zoom == 1.0) + zoom = 0.25; + } + else + zoom = 1.0; + + c = priv->slide_initial_slider_position + zoom * delta; new_value = coord_to_value (range, c); next_value = coord_to_value (range, c + 1); - mark_delta = fabs (next_value - new_value); + mark_delta = fabs (next_value - new_value); for (i = 0; i < priv->n_marks; i++) { @@ -2711,13 +2741,13 @@ update_slider_position (GtkRange *range, break; } } - } + } g_signal_emit (range, signals[CHANGE_VALUE], 0, GTK_SCROLL_JUMP, new_value, &handled); } -static void +static void stop_scrolling (GtkRange *range) { range_grab_remove (range); @@ -2738,7 +2768,7 @@ gtk_range_grab_broken (GtkWidget *widget, priv->grab_location != MOUSE_OUTSIDE) { if (priv->grab_location == MOUSE_SLIDER) - update_slider_position (range, priv->mouse_x, priv->mouse_y); + update_slider_position (range, priv->mouse_x, priv->mouse_y); stop_scrolling (range); @@ -2789,37 +2819,57 @@ gtk_range_button_release (GtkWidget *widget, /** * _gtk_range_get_wheel_delta: * @range: a #GtkRange - * @direction: A #GdkScrollDirection - * + * @event: A #GdkEventScroll + * * Returns a good step value for the mouse wheel. - * - * Return value: A good step value for the mouse wheel. - * + * + * Return value: A good step value for the mouse wheel. + * * Since: 2.4 **/ gdouble -_gtk_range_get_wheel_delta (GtkRange *range, - GdkScrollDirection direction) +_gtk_range_get_wheel_delta (GtkRange *range, + GdkEventScroll *event) { GtkRangePrivate *priv = range->priv; GtkAdjustment *adjustment = priv->adjustment; + gdouble dx, dy; gdouble delta; + gdouble page_size; + gdouble page_increment; + gdouble scroll_unit; + + page_size = gtk_adjustment_get_page_size (adjustment); + page_increment = gtk_adjustment_get_page_increment (adjustment); if (GTK_IS_SCROLLBAR (range)) - delta = pow (gtk_adjustment_get_page_size (adjustment), 2.0 / 3.0); + scroll_unit = pow (page_size, 2.0 / 3.0); else - delta = gtk_adjustment_get_step_increment (adjustment) * 2; - - if (direction == GDK_SCROLL_UP || - direction == GDK_SCROLL_LEFT) - delta = - delta; - + scroll_unit = page_increment; + + if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &dx, &dy)) + { + if (dx != 0 && + gtk_orientable_get_orientation (GTK_ORIENTABLE (range)) == GTK_ORIENTATION_HORIZONTAL) + delta = dx * scroll_unit; + else + delta = dy * scroll_unit; + } + else + { + if (event->direction == GDK_SCROLL_UP || + event->direction == GDK_SCROLL_LEFT) + delta = - scroll_unit; + else + delta = scroll_unit; + } + if (priv->inverted) delta = - delta; return delta; } - + static gboolean gtk_range_scroll_event (GtkWidget *widget, GdkEventScroll *event) @@ -2832,7 +2882,7 @@ gtk_range_scroll_event (GtkWidget *widget, gdouble delta; gboolean handled; - delta = _gtk_range_get_wheel_delta (range, event->direction); + delta = _gtk_range_get_wheel_delta (range, event); g_signal_emit (range, signals[CHANGE_VALUE], 0, GTK_SCROLL_JUMP, gtk_adjustment_get_value (priv->adjustment) + delta, @@ -2965,20 +3015,6 @@ gtk_range_adjustment_changed (GtkAdjustment *adjustment, */ } -static gboolean -force_repaint (gpointer data) -{ - GtkRange *range = GTK_RANGE (data); - GtkRangePrivate *priv = range->priv; - GtkWidget *widget = GTK_WIDGET (range); - - priv->repaint_id = 0; - if (gtk_widget_is_drawable (widget)) - gdk_window_process_updates (gtk_widget_get_window (widget), FALSE); - - return FALSE; -} - static void gtk_range_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data) @@ -2995,11 +3031,6 @@ gtk_range_adjustment_value_changed (GtkAdjustment *adjustment, (GTK_IS_SCALE (range) && gtk_scale_get_draw_value (GTK_SCALE (range)))) { gtk_widget_queue_draw (GTK_WIDGET (range)); - /* setup a timer to ensure the range isn't lagging too much behind the scroll position */ - if (!priv->repaint_id) - priv->repaint_id = gdk_threads_add_timeout_full (GDK_PRIORITY_EVENTS, - 181, force_repaint, - range, NULL); } /* Note that we don't round off to priv->round_digits here. @@ -3568,13 +3599,15 @@ gtk_range_calc_layout (GtkRange *range, GtkRangePrivate *priv = range->priv; gint slider_width, stepper_size, focus_width, trough_border, stepper_spacing; gint slider_length; - GtkBorder border; + GtkBorder border, trough_margin; gint n_steppers; gboolean has_steppers_ab; gboolean has_steppers_cd; gboolean trough_under_steppers; GdkRectangle range_rect; GtkWidget *widget; + GtkStyleContext *context; + GtkStateFlags state; if (!priv->need_recalc) return; @@ -3590,6 +3623,13 @@ gtk_range_calc_layout (GtkRange *range, */ widget = GTK_WIDGET (range); + context = gtk_widget_get_style_context (widget); + + state = gtk_widget_get_state_flags (widget); + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH); + gtk_style_context_get_margin (context, state, &trough_margin); + gtk_style_context_restore (context); gtk_range_get_props (range, &slider_width, &stepper_size, @@ -3858,7 +3898,6 @@ gtk_range_calc_layout (GtkRange *range, */ priv->trough.x = priv->stepper_b.x + priv->stepper_b.width + stepper_spacing * has_steppers_ab; priv->trough.y = range_rect.y; - priv->trough.width = priv->stepper_c.x - priv->trough.x - stepper_spacing * has_steppers_cd; priv->trough.height = range_rect.height;