1 --- gtk+-2.6.4/gtk/gtkwidget.c 2005-02-24 18:44:02.000000000 +0200
2 +++ gtk+-2.6.4/gtk/gtkwidget.c 2005-04-06 16:19:38.386702696 +0300
10 #include "gtkcontainer.h"
11 #include "gtkaccelmap.h"
13 #include "gtkwindow.h"
14 #include "gtkbindings.h"
15 #include "gtkprivate.h"
16 +#include "gtktreeview.h"
17 +#include "gtkentry.h"
18 +#include "gtktextview.h"
19 +#include "gtkimcontext.h"
22 #include "gdk/gdkprivate.h" /* Used in gtk_reset_shapes_recurse to avoid copy */
23 #include <gobject/gvaluecollector.h>
25 #include "gtkaccessible.h"
26 #include "gtktooltips.h"
27 #include "gtkinvisible.h"
28 +#include "gtkscrollbar.h" /* Following are needed for special focus changes */
29 +#include "gtktoolbar.h"
31 +#include "gtkmenuitem.h"
32 +#include "gtktogglebutton.h"
33 +#include "gtkcomboboxentry.h"
34 +#include "gtktogglebutton.h"
35 +#include "gtkcomboboxentry.h"
37 #define WIDGET_CLASS(w) GTK_WIDGET_GET_CLASS (w)
38 #define INIT_PATH_SIZE (512)
40 +#define GTK_TAP_THRESHOLD 30
41 +#define GTK_TAP_MENU_THRESHOLD 20
42 +#define GTK_TAP_AND_HOLD_TIMER_COUNTER 11
43 +#define GTK_TAP_AND_HOLD_TIMER_INTERVAL 100
45 +typedef struct _GtkWidgetPrivate GtkWidgetPrivate;
47 +#define GTK_WIDGET_GET_PRIVATE(obj) ( G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
48 + GTK_TYPE_WIDGET, GtkWidgetPrivate) )
50 +#define TAP_AND_HOLD_ANIMATION 1
56 ACCEL_CLOSURES_CHANGED,
68 PROP_EXTENSION_EVENTS,
74 typedef struct _GtkStateData GtkStateData;
79 +struct _GtkWidgetPrivate
85 + GtkStateType type_on_press;
86 + GdkEvent *fake_event;
87 + GtkMenuPositionFunc func;
91 + gint button_pressed : 1;
92 + gint signals_connected : 1;
93 + GtkWidgetTapAndHoldFlags flags;
97 +#ifdef TAP_AND_HOLD_ANIMATION
98 + GdkPixbufAnimation *anim;
99 + GdkPixbufAnimationIter *iter;
100 + guint width, height;
105 +/* --- Tap And Hold --- */
106 +static gboolean gtk_widget_tap_and_hold_button_press_with_events( GtkWidget *widget,
107 + GdkEvent *event, GtkWidgetPrivate *priv );
108 +static gboolean gtk_widget_tap_and_hold_button_release_with_events( GtkWidget *widget,
109 + GdkEvent *event, GtkWidgetPrivate *priv );
110 +static gboolean gtk_widget_tap_and_hold_leave_notify_with_events( GtkWidget *widget,
111 + GdkEvent *event, GtkWidgetPrivate *priv );
112 +static gboolean gtk_widget_tap_and_hold_timeout_with_events( GtkWidget *widget );
113 +static gboolean gtk_widget_tap_and_hold_timeout( GtkWidget *widget );
114 +static gboolean gtk_widget_tap_and_hold_button_press( GtkWidget *widget,
115 + GdkEvent *event, GtkWidgetPrivate *priv );
116 +static gboolean gtk_widget_tap_and_hold_button_release( GtkWidget *widget,
117 + GdkEvent *event, GtkWidgetPrivate *priv );
118 +static gboolean gtk_widget_tap_and_hold_leave_notify( GtkWidget *widget,
119 + GdkEvent *event, GtkWidgetPrivate *priv );
120 +static void gtk_widget_tap_and_hold_setup_real( GtkWidget *widget,
121 + GtkWidget *menu, GtkCallback func, GtkWidgetTapAndHoldFlags flags );
122 +static void gtk_widget_real_tap_and_hold(GtkWidget *widget);
123 /* --- prototypes --- */
124 static void gtk_widget_class_init (GtkWidgetClass *klass);
125 static void gtk_widget_init (GtkWidget *widget);
130 +/*Hildon focus handling*/
131 +static void gtk_widget_set_focus_handling( GtkWidget *widget, gboolean state );
133 +static gboolean gtk_widget_enter_notify_event( GtkWidget *widget, GdkEventCrossing *event );
134 +static gboolean gtk_widget_leave_notify_event( GtkWidget *widget, GdkEventCrossing *event );
135 +static gint gtk_widget_button_release_event( GtkWidget *widget, GdkEventButton *event );
136 +static gint gtk_widget_button_press_event( GtkWidget *widget, GdkEventButton *event );
138 /* --- variables --- */
139 static gpointer parent_class = NULL;
141 static GtkTextDirection gtk_default_direction = GTK_TEXT_DIR_LTR;
142 static GParamSpecPool *style_property_spec_pool = NULL;
144 +static gboolean on_same_widget = FALSE; /*Hildon focus handling*/
145 +static gboolean mouse_pressed = FALSE; /*Hildon focus handling*/
147 static GQuark quark_property_parser = 0;
148 static GQuark quark_aux_info = 0;
149 static GQuark quark_accel_path = 0;
151 klass->drag_data_received = NULL;
152 klass->screen_changed = NULL;
153 klass->can_activate_accel = gtk_widget_real_can_activate_accel;
154 + klass->tap_and_hold_setup = gtk_widget_tap_and_hold_setup_real;
155 + klass->insensitive_press = NULL;
156 + klass->tap_and_hold = gtk_widget_real_tap_and_hold;
158 klass->show_help = gtk_widget_real_show_help;
162 klass->no_expose_event = NULL;
164 + g_type_class_add_private( klass, sizeof(GtkWidgetPrivate) );
166 + g_object_class_install_property (gobject_class,
168 + g_param_spec_int ("tap_and_hold_state",
169 + P_("Tap and hold State type"),
170 + P_("Sets the state to be used to the tap and hold functionality. The default is GTK_STATE_NORMAL"),
172 + 4, /*4 == Last state in GTK+-2.0*/
174 + G_PARAM_READWRITE));
176 g_object_class_install_property (gobject_class,
178 g_param_spec_string ("name",
179 @@ -1389,6 +1487,31 @@
180 _gtk_marshal_BOOLEAN__UINT,
181 G_TYPE_BOOLEAN, 1, G_TYPE_UINT);
183 + widget_signals[INSENSITIVE_PRESS] =
184 + g_signal_new ("insensitive_press",
185 + G_TYPE_FROM_CLASS (gobject_class),
186 + G_SIGNAL_RUN_FIRST,
187 + G_STRUCT_OFFSET (GtkWidgetClass, insensitive_press),
189 + _gtk_marshal_VOID__VOID,
192 + widget_signals[TAP_AND_HOLD] =
193 + g_signal_new("tap-and-hold", G_TYPE_FROM_CLASS(gobject_class),
195 + G_STRUCT_OFFSET(GtkWidgetClass, tap_and_hold),
197 + _gtk_marshal_VOID__VOID,
200 + widget_signals[TAP_AND_HOLD_SETUP] =
201 + g_signal_new("tap-and-hold-setup", G_TYPE_FROM_CLASS(gobject_class),
203 + G_STRUCT_OFFSET(GtkWidgetClass, tap_and_hold_setup),
204 + NULL, NULL, /*FIXME -- OBJECT_POINTER_FLAGS*/
205 + _gtk_marshal_VOID__OBJECT_UINT_FLAGS,
206 + G_TYPE_NONE, 3, G_TYPE_OBJECT, G_TYPE_POINTER, G_TYPE_UINT);
208 binding_set = gtk_binding_set_by_class (klass);
209 gtk_binding_entry_add_signal (binding_set, GDK_F10, GDK_SHIFT_MASK,
211 @@ -1418,7 +1541,12 @@
212 P_("Whether to draw the focus indicator inside widgets"),
216 + gtk_widget_class_install_style_property (klass,
217 + g_param_spec_boolean ("hildon-focus-handling",
218 + P_("Hildon focus handling"),
219 + P_("Whether the widget is using the hildon like focus handling or not"),
221 + G_PARAM_READABLE));
222 gtk_widget_class_install_style_property (klass,
223 g_param_spec_int ("focus-line-width",
224 P_("Focus linewidth"),
225 @@ -1543,6 +1671,8 @@
226 case PROP_NO_SHOW_ALL:
227 gtk_widget_set_no_show_all (widget, g_value_get_boolean (value));
229 + case PROP_TAP_AND_HOLD:
230 + GTK_WIDGET_GET_PRIVATE(widget)->type_on_press = g_value_get_int(value);
234 @@ -1637,16 +1767,45 @@
235 case PROP_NO_SHOW_ALL:
236 g_value_set_boolean (value, gtk_widget_get_no_show_all (widget));
238 + case PROP_TAP_AND_HOLD:
239 + g_value_set_int (value,
240 + (int)GTK_WIDGET_GET_PRIVATE(widget)->type_on_press);
242 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
247 +static void gtk_widget_set_focus_handling( GtkWidget *widget, gboolean state )
249 + GtkWidgetPrivate *priv;
250 + priv = GTK_WIDGET_GET_PRIVATE (widget);
252 + if( state && GTK_WIDGET_CAN_FOCUS(widget) )
254 + if (!priv->state_set)
256 + g_signal_connect( G_OBJECT(widget), "button-press-event",
257 + G_CALLBACK(gtk_widget_button_press_event), NULL );
258 + g_signal_connect( G_OBJECT(widget), "button-release-event",
259 + G_CALLBACK(gtk_widget_button_release_event), NULL );
260 + g_signal_connect( G_OBJECT(widget), "enter-notify-event",
261 + G_CALLBACK(gtk_widget_enter_notify_event), NULL );
262 + g_signal_connect( G_OBJECT(widget), "leave-notify-event",
263 + G_CALLBACK(gtk_widget_leave_notify_event), NULL );
264 + priv->state_set = TRUE;
270 gtk_widget_init (GtkWidget *widget)
272 + GtkWidgetPrivate *priv;
273 GTK_PRIVATE_FLAGS (widget) = PRIVATE_GTK_CHILD_VISIBLE;
275 + priv = GTK_WIDGET_GET_PRIVATE(widget);
277 widget->state = GTK_STATE_NORMAL;
278 widget->saved_state = GTK_STATE_NORMAL;
280 @@ -1659,6 +1818,18 @@
281 widget->window = NULL;
282 widget->parent = NULL;
284 + priv->fake_event = NULL;
285 + priv->timer_id = 0;
287 + priv->run_press = TRUE;
288 + priv->signals_connected = FALSE;
289 + priv->x = priv->y = 0;
291 + priv->timer_counter = 0;
293 + priv->state_set = FALSE;
294 + priv->interval = GTK_TAP_AND_HOLD_TIMER_INTERVAL;
296 GTK_WIDGET_SET_FLAGS (widget,
298 GTK_PARENT_SENSITIVE |
299 @@ -1670,6 +1841,7 @@
300 GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED);
302 widget->style = gtk_widget_get_default_style ();
304 g_object_ref (widget->style);
307 @@ -2153,6 +2325,7 @@
309 if ((GTK_WIDGET_FLAGS (widget) & GTK_NO_SHOW_ALL) != 0)
313 class = GTK_WIDGET_GET_CLASS (widget);
315 @@ -3400,6 +3573,127 @@
320 + * gtk_widget_button_press_event
321 + * @widget: a #GtkWidget
322 + * @event: a #GtkEventKey
325 +static gboolean gtk_widget_button_press_event(GtkWidget *widget, GdkEventButton *event )
327 + if( !mouse_pressed /*&& !GTK_IS_TREE_VIEW(widget) && !GTK_IS_ENTRY(widget)*/ )
329 + GtkWidget *toplevel;
330 + toplevel = gtk_widget_get_toplevel (widget);
331 + if (GTK_IS_WINDOW (toplevel))
333 + mouse_pressed = TRUE;
335 + if( /*!gtk_window_get_prev_focus_widget(GTK_WINDOW(toplevel)) &&*/
336 + GTK_IS_WIDGET(GTK_WINDOW(toplevel)->focus_widget) )
337 + gtk_window_set_prev_focus_widget( GTK_WINDOW(toplevel),
338 + GTK_WINDOW(toplevel)->focus_widget );
345 + * gtk_widget_button_release_event
346 + * @widget: a #GtkWidget
347 + * @event: a #GtkEventKey
350 +static gboolean gtk_widget_button_release_event(GtkWidget *widget, GdkEventButton *event )
352 + if( mouse_pressed /*&& !GTK_IS_ENTRY(widget)*/ )
354 + GtkWidget *toplevel;
355 + GtkWidget *event_widget;
356 + event_widget = gtk_get_event_widget( (GdkEvent*) event );
357 + toplevel = gtk_widget_get_toplevel (widget);
359 + mouse_pressed = FALSE;
360 + on_same_widget = TRUE;
362 + if (GTK_IS_WINDOW (toplevel))
364 + if( !on_same_widget && GTK_IS_WIDGET(GTK_WINDOW(toplevel)->focus_widget) )
365 + gtk_window_set_prev_focus_widget( GTK_WINDOW(toplevel), GTK_WINDOW(toplevel)->focus_widget );
367 + gtk_window_set_prev_focus_widget( GTK_WINDOW(toplevel), event_widget );
374 + * gtk_widget_enter_notify_event
375 + * @widget: a #GtkWidget
376 + * @event: a #GtkEventCrossing
379 +static gboolean gtk_widget_enter_notify_event( GtkWidget *widget, GdkEventCrossing *event )
381 + GtkWidget *toplevel;
382 + GtkWidget *event_widget;
383 + /*if( GTK_IS_ENTRY(widget) )
386 + toplevel = gtk_widget_get_toplevel (widget);
387 + event_widget = gtk_get_event_widget ( (GdkEvent*) event );
389 + if(mouse_pressed && !on_same_widget && gtk_window_get_prev_focus_widget( GTK_WINDOW(toplevel) ) == event_widget)
391 +/* GtkWidget *temp;*/
392 + on_same_widget = TRUE;
394 +/* temp = gtk_window_get_prev_focus_widget( GTK_WINDOW(toplevel) );*/
395 + if( GTK_IS_WIDGET(GTK_WINDOW(toplevel)->focus_widget) )
397 + gtk_window_set_prev_focus_widget( GTK_WINDOW(toplevel), GTK_WINDOW(toplevel)->focus_widget );
398 + if( GTK_WIDGET_CAN_FOCUS(event_widget) )
399 + gtk_widget_grab_focus( event_widget );
401 + gtk_widget_activate( event_widget );
409 + * gtk_widget_leave_notify_event
410 + * @widget: a #GtkWidget
411 + * @event: a #GtkEventCrossing
414 +static gboolean gtk_widget_leave_notify_event( GtkWidget *widget, GdkEventCrossing *event )
416 + if( mouse_pressed && on_same_widget /*&& !GTK_IS_ENTRY(widget)*/ )
418 + GtkWidget *event_widget;
419 + GtkWidget *toplevel;
421 + toplevel = gtk_widget_get_toplevel( widget );
422 + event_widget = gtk_get_event_widget( (GdkEvent*) event );
423 + on_same_widget = FALSE;
425 + temp = gtk_window_get_prev_focus_widget( GTK_WINDOW(toplevel) );
426 + if( GTK_IS_WIDGET(temp) &&
427 + gtk_window_has_toplevel_focus(GTK_WINDOW(toplevel)) )
429 + gtk_window_set_prev_focus_widget( GTK_WINDOW(toplevel), event_widget );
430 + if( GTK_WIDGET_CAN_FOCUS(temp) )
431 + gtk_widget_grab_focus( temp );
433 + gtk_widget_activate( temp );
440 #define WIDGET_REALIZED_FOR_EVENT(widget, event) \
441 (event->type == GDK_FOCUS_CHANGE || GTK_WIDGET_REALIZED(widget))
443 @@ -3947,11 +4241,14 @@
445 gtk_widget_real_grab_focus (GtkWidget *focus_widget)
447 - if (GTK_WIDGET_CAN_FOCUS (focus_widget))
448 + if (GTK_WIDGET_CAN_FOCUS (focus_widget) &&
449 + GTK_WIDGET_VISIBLE (focus_widget))
451 + static GtkIMContext *last_context = NULL;
455 + GtkIMContext *context;
457 /* clear the current focus setting, break if the current widget
458 * is the focus widget's parent, since containers above that will
459 * be set by the next loop.
460 @@ -3972,6 +4269,53 @@
465 + /* Focus change stuff (previously in modified im context) */
466 + if (GTK_IS_ENTRY (widget))
467 + context = GTK_ENTRY (widget)->im_context;
468 + else if (GTK_IS_TEXT_VIEW (widget))
469 + context = GTK_TEXT_VIEW (widget)->im_context;
473 + if (context || last_context)
475 + gboolean is_combo, is_inside_toolbar;
478 + parent = gtk_widget_get_parent (focus_widget);
479 + is_combo = GTK_IS_TOGGLE_BUTTON (focus_widget) &&
480 + (GTK_IS_COMBO_BOX_ENTRY (parent) ||
481 + GTK_IS_COMBO_BOX (parent));
482 + is_inside_toolbar =
483 + gtk_widget_get_ancestor (focus_widget,
484 + GTK_TYPE_TOOLBAR) != NULL;
486 + if (focus_widget == NULL ||
487 + !GTK_IS_ENTRY (focus_widget) &&
488 + !GTK_IS_TEXT_VIEW (focus_widget) &&
489 + !GTK_IS_SCROLLBAR (focus_widget) &&
490 + !GTK_IS_MENU_ITEM (focus_widget) &&
491 + !GTK_IS_MENU (focus_widget) &&
492 + !is_inside_toolbar &&
495 + /* we can't hide IM without IM context. it's possible to move
496 + * focus to widget which doesn't have IM context, but which
497 + * doesn't want IM to be hidden either. So, we have this
498 + * static last_context variable which is used... */
499 + gtk_im_context_hide (context != NULL
500 + ? context : last_context);
505 + if (last_context != NULL)
506 + g_object_unref (last_context);
507 + last_context = context;
508 + g_object_ref (last_context);
514 @@ -4462,9 +4806,13 @@
516 g_return_if_fail (GTK_IS_WIDGET (widget));
518 - if (!GTK_WIDGET_USER_STYLE (widget) &&
519 - !GTK_WIDGET_RC_STYLE (widget))
520 + if (!GTK_WIDGET_USER_STYLE (widget) && !GTK_WIDGET_RC_STYLE (widget))
522 + gboolean hfh = FALSE;
523 gtk_widget_reset_rc_style (widget);
524 + gtk_widget_style_get( widget, "hildon-focus-handling", &hfh, NULL );
525 + gtk_widget_set_focus_handling( widget, hfh );
529 /* Look up the RC style for this widget, unsetting any user style that
530 @@ -6396,7 +6744,7 @@
532 if (!GTK_WIDGET_DIRECTION_SET (widget))
533 gtk_widget_emit_direction_changed (widget, old_dir);
536 if (GTK_IS_CONTAINER (widget))
537 gtk_container_forall (GTK_CONTAINER (widget),
538 gtk_widget_set_default_direction_recurse,
539 @@ -6405,6 +6753,13 @@
540 g_object_unref (widget);
544 +void gtk_widget_set_direction_recursive(GtkWidget * widget, GtkTextDirection dir )
546 + gtk_widget_set_default_direction_recurse( widget, GUINT_TO_POINTER(dir) );
551 * gtk_widget_set_default_direction:
552 * @dir: the new default direction. This cannot be
553 @@ -6422,7 +6777,7 @@
555 GList *toplevels, *tmp_list;
556 GtkTextDirection old_dir = gtk_default_direction;
559 gtk_default_direction = dir;
561 tmp_list = toplevels = gtk_window_list_toplevels ();
562 @@ -6497,6 +6852,7 @@
563 gtk_widget_finalize (GObject *object)
565 GtkWidget *widget = GTK_WIDGET (object);
566 + GtkWidgetPrivate *priv = GTK_WIDGET_GET_PRIVATE(object);
567 GtkWidgetAuxInfo *aux_info;
569 GdkExtensionMode *mode;
570 @@ -6507,6 +6863,12 @@
571 g_object_unref (widget->style);
572 widget->style = NULL;
574 + if (priv->timer_id)
576 + g_source_remove (priv->timer_id);
577 + priv->timer_id = 0;
581 g_free (widget->name);
583 @@ -6526,6 +6888,12 @@
585 g_object_unref (accessible);
587 + if (GTK_IS_MENU(priv->menu))
588 + gtk_widget_destroy (priv->menu);
590 + if (priv->fake_event)
591 + gdk_event_free (priv->fake_event);
593 G_OBJECT_CLASS (parent_class)->finalize (object);
596 @@ -7577,3 +7945,450 @@
598 g_object_notify (G_OBJECT (widget), "no_show_all");
601 +void gtk_widget_insensitive_press ( GtkWidget *widget )
603 + g_return_if_fail (GTK_IS_WIDGET (widget));
605 + g_signal_emit(widget, widget_signals[INSENSITIVE_PRESS], 0);
610 +#ifdef TAP_AND_HOLD_ANIMATION
612 +init_tap_and_hold_animation( GtkWidgetPrivate *priv )
617 + g_get_current_time( &time );
618 + priv->iter = gdk_pixbuf_animation_get_iter( priv->anim, &time );
619 + priv->interval = gdk_pixbuf_animation_iter_get_delay_time( priv->iter );
624 +timeout_tap_and_hold_animation( GtkWidgetPrivate *priv )
633 + screen = gdk_screen_get_default();
634 + g_get_current_time( &time );
636 + pic = gdk_pixbuf_animation_iter_get_pixbuf( priv->iter );
637 + cursor = gdk_cursor_new_from_pixbuf( gdk_display_get_default(), pic,
638 + priv->width, priv->height );
640 + gdk_window_set_cursor( priv->fake_event->button.window, cursor );
642 + gdk_pixbuf_animation_iter_advance( priv->iter, &time );
647 +stop_tap_and_hold_animation( GtkWidgetPrivate *priv )
651 + gdk_window_set_cursor( priv->fake_event->button.window, NULL );
658 +void tap_and_hold_remove_timer( GtkWidgetPrivate *priv )
660 + if (priv->timer_id)
662 + g_source_remove (priv->timer_id);
663 + priv->timer_id = 0;
664 + #ifdef TAP_AND_HOLD_ANIMATION
665 + stop_tap_and_hold_animation( priv );
671 + * gtk_widget_tap_and_hold_setup:
673 + * @widget : A @GtkWidget
674 + * @menu : A @GtkWidget
675 + * @func : A @GtkCallback
676 + * @flags : A @GtkWidgetTapAndHoldFlags
678 + * Setups the tap and hold functionality to the @widget.
679 + * The @menu is shown when the functionality is activated.
680 + * If the @menu is wanted to be positioned in a different way than the
681 + * gtk+ default, the menuposition @func can be passed as a third parameter.
682 + * Fourth parameter, @flags are explaned with detail in the documentation.
684 +void gtk_widget_tap_and_hold_setup (GtkWidget *widget, GtkWidget *menu,
685 + GtkCallback func, GtkWidgetTapAndHoldFlags flags)
687 + /*GtkWidgetClass *klass = GTK_WIDGET_GET_CLASS(widget);*/
688 + g_return_if_fail( GTK_IS_WIDGET(widget));
689 + g_return_if_fail(menu == NULL || GTK_IS_MENU(menu));
690 + g_signal_emit( widget, widget_signals[TAP_AND_HOLD_SETUP], 0, menu, func,
694 +static void gtk_widget_tap_and_hold_setup_real (GtkWidget *widget,
695 + GtkWidget *menu, GtkCallback func, GtkWidgetTapAndHoldFlags flags)
697 + #ifdef TAP_AND_HOLD_ANIMATION
698 + GtkStyle *style = NULL;
699 + GError *error = NULL;
701 + GtkWidgetPrivate *priv;
702 + g_return_if_fail (GTK_IS_WIDGET(widget));
703 + g_return_if_fail (menu == NULL || GTK_IS_MENU(menu));
704 + priv = GTK_WIDGET_GET_PRIVATE (widget);
706 + if (priv->signals_connected)
709 + _gtk_menu_enable_context_menu_behavior (menu);
712 + priv->func = (GtkMenuPositionFunc)func;
713 + priv->signals_connected = TRUE;
714 + priv->timer_counter = 0;
715 + priv->flags = flags;
717 + if (flags & GTK_TAP_AND_HOLD_PASS_PRESS)
719 + g_signal_connect( widget, "button-press-event",
720 + G_CALLBACK(gtk_widget_tap_and_hold_button_press_with_events), priv );
721 + g_signal_connect( widget, "button-release-event",
722 + G_CALLBACK(gtk_widget_tap_and_hold_button_release_with_events), priv );
723 + g_signal_connect( widget, "leave-notify-event",
724 + G_CALLBACK(gtk_widget_tap_and_hold_leave_notify_with_events), priv );
728 + g_signal_connect( widget, "button-press-event",
729 + G_CALLBACK(gtk_widget_tap_and_hold_button_press), priv );
730 + g_signal_connect( widget, "button-release-event",
731 + G_CALLBACK(gtk_widget_tap_and_hold_button_release), priv );
732 + g_signal_connect( widget, "leave-notify-event",
733 + G_CALLBACK(gtk_widget_tap_and_hold_leave_notify), priv );
736 +#ifdef TAP_AND_HOLD_ANIMATION
738 + style = gtk_rc_get_style_by_paths(gtk_settings_get_default(),
739 + "gtk-tap-and-hold-animation",
740 + NULL, G_TYPE_NONE);
745 + priv->anim = gdk_pixbuf_animation_new_from_file(
746 + (gchar*)style->rc_style->bg_pixmap_name[0], &error );
748 + priv->width = gdk_pixbuf_animation_get_width( priv->anim )/2;
749 + priv->height = gdk_pixbuf_animation_get_height( priv->anim )/2;
754 +static void gtk_widget_real_tap_and_hold(GtkWidget *widget)
756 + GtkWidgetPrivate *priv = GTK_WIDGET_GET_PRIVATE (widget);
758 + if (GTK_IS_MENU(priv->menu))
759 + gtk_menu_popup( GTK_MENU(priv->menu), NULL, NULL,
760 + (GtkMenuPositionFunc)priv->func,
761 + widget, 1, gdk_x11_get_server_time(widget->window) );
764 +static gboolean gtk_widget_tap_and_hold_timeout (GtkWidget *widget)
766 + GtkWidgetPrivate *priv= GTK_WIDGET_GET_PRIVATE(widget);
767 + gboolean return_value;
770 + #ifdef TAP_AND_HOLD_ANIMATION
771 + timeout_tap_and_hold_animation( priv );
774 + if( priv->timer_counter )
775 + priv->timer_counter--;
777 + priv->timer_id = 0;
779 + gdk_display_get_pointer( gdk_x11_lookup_xdisplay(
780 + GDK_WINDOW_XDISPLAY(priv->fake_event->button.window) ),
781 + NULL, &x, &y, NULL );
783 + if ((abs(x - priv->x) > GTK_TAP_THRESHOLD) ||
784 + (abs(y - priv->y) > GTK_TAP_THRESHOLD))
786 + if (priv->stype != priv->type_on_press)
787 + gtk_widget_set_state( widget, priv->stype );
788 + priv->timer_counter = 0;
789 + priv->timer_id = 0;
790 + priv->x = priv->y = 0;
791 + priv->run_press = FALSE;
792 + g_signal_emit_by_name (G_OBJECT(widget), "button-press-event",
793 + priv->fake_event, &return_value);
796 + if (!priv->timer_id)
798 + if (priv->stype != priv->type_on_press)
799 + gtk_widget_set_state( widget, priv->stype );
800 + #ifdef TAP_AND_HOLD_ANIMATION
801 + stop_tap_and_hold_animation( priv );
803 + g_signal_emit(widget, widget_signals[TAP_AND_HOLD], 0);
811 +static gboolean gtk_widget_tap_and_hold_button_press (GtkWidget *widget,
812 + GdkEvent *event, GtkWidgetPrivate *priv)
814 + if (!priv->run_press || event->button.button != 1)
816 + priv->run_press = TRUE;
820 + if (event->button.type == GDK_2BUTTON_PRESS)
823 + if (priv->fake_event)
824 + gdk_event_free (priv->fake_event);
825 + priv->fake_event = gdk_event_copy(event);
827 + if (!priv->timer_id)
829 + priv->stype = GTK_WIDGET_STATE(widget);
830 + if (priv->stype != priv->type_on_press)
831 + gtk_widget_set_state( widget, priv->type_on_press );
832 + gdk_display_get_pointer(
833 + gdk_x11_lookup_xdisplay( GDK_WINDOW_XDISPLAY(event->button.window) ),
834 + NULL, &priv->x, &priv->y, NULL );
835 + priv->timer_counter = GTK_TAP_AND_HOLD_TIMER_COUNTER;
837 + #ifdef TAP_AND_HOLD_ANIMATION
838 + init_tap_and_hold_animation( priv );
840 + priv->timer_id = g_timeout_add( priv->interval,
841 + (GSourceFunc)gtk_widget_tap_and_hold_timeout, widget );
846 +static gboolean gtk_widget_tap_and_hold_button_release (GtkWidget *widget,
847 + GdkEvent *event, GtkWidgetPrivate *priv)
849 + gboolean return_value;
851 + if (!priv->run_press || event->button.button != 1 || !priv->timer_id ||
852 + event->button.type == GDK_2BUTTON_PRESS)
855 + g_source_remove (priv->timer_id);
856 + priv->timer_id = 0;
857 + priv->x = priv->y = priv->timer_counter = 0;
858 + if (priv->stype != priv->type_on_press)
859 + gtk_widget_set_state (widget, priv->stype);
861 + #ifdef TAP_AND_HOLD_ANIMATION
862 + stop_tap_and_hold_animation( priv );
865 + if (priv->flags & GTK_TAP_AND_HOLD_NO_SIGNALS)
868 + priv->run_press = FALSE;
870 + g_signal_emit_by_name (G_OBJECT(widget), "button-press-event",
871 + priv->fake_event, &return_value);
876 +static gboolean gtk_widget_tap_and_hold_leave_notify (GtkWidget *widget,
877 + GdkEvent *event, GtkWidgetPrivate *priv)
879 + gboolean return_value;
880 + if (!priv->timer_id)
883 + g_source_remove (priv->timer_id);
884 + priv->timer_id = 0;
885 + priv->x = priv->y = priv->timer_counter = 0;
886 + if (priv->stype != priv->type_on_press)
887 + gtk_widget_set_state (widget, priv->stype);
889 + #ifdef TAP_AND_HOLD_ANIMATION
890 + stop_tap_and_hold_animation( priv );
892 + priv->run_press = FALSE;
893 + g_signal_emit_by_name (G_OBJECT(widget), "button-press-event",
894 + priv->fake_event, &return_value);
900 +gtk_widget_tap_and_hold_timeout_with_events (GtkWidget *widget)
903 + GtkWidgetPrivate *priv= GTK_WIDGET_GET_PRIVATE(widget);
905 + g_return_val_if_fail (priv->fake_event, FALSE);
907 + #ifdef TAP_AND_HOLD_ANIMATION
908 + timeout_tap_and_hold_animation( priv );
911 + gdk_display_get_pointer( gdk_x11_lookup_xdisplay(
912 + GDK_WINDOW_XDISPLAY(priv->fake_event->button.window) ),
913 + NULL, &x, &y, NULL );
915 + if( priv->timer_counter )
917 + priv->timer_counter--;
918 + if ((abs(x - priv->x) > GTK_TAP_THRESHOLD) ||
919 + (abs(y - priv->y) > GTK_TAP_THRESHOLD))
921 + #ifdef TAP_AND_HOLD_ANIMATION
922 + stop_tap_and_hold_animation( priv );
924 + tap_and_hold_remove_timer( priv );
929 + if (!((abs(x - priv->x) > GTK_TAP_THRESHOLD) ||
930 + (abs(y - priv->y) > GTK_TAP_THRESHOLD)))
932 + gboolean return_value;
933 + priv->fake_event->button.type = GDK_BUTTON_RELEASE;
934 + priv->fake_event->button.x = x;
935 + priv->fake_event->button.y = y;
936 + g_signal_emit_by_name (G_OBJECT(widget), "button-release-event",
937 + priv->fake_event, &return_value);
938 + #ifdef TAP_AND_HOLD_ANIMATION
939 + stop_tap_and_hold_animation( priv );
941 + g_signal_emit(widget, widget_signals[TAP_AND_HOLD], 0);
942 + priv->timer_id = 0;
945 + gdk_event_free(priv->fake_event);
946 + priv->fake_event = NULL;
950 + if (priv->timer_id)
952 + g_source_remove (priv->timer_id);
953 + priv->timer_id = 0;
959 +static gboolean gtk_widget_tap_and_hold_button_press_with_events(
960 + GtkWidget *widget, GdkEvent *event, GtkWidgetPrivate *priv)
962 + if( priv->timer_id || event->button.type == GDK_2BUTTON_PRESS)
965 + if (priv->fake_event)
966 + gdk_event_free (priv->fake_event);
967 + priv->fake_event = gdk_event_copy (event);
969 + gdk_display_get_pointer(
970 + gdk_x11_lookup_xdisplay(GDK_WINDOW_XDISPLAY(event->button.window)),
971 + NULL, &priv->x, &priv->y, NULL);
972 + #ifdef TAP_AND_HOLD_ANIMATION
973 + init_tap_and_hold_animation( priv );
975 + priv->timer_counter = GTK_TAP_AND_HOLD_TIMER_COUNTER;
976 + priv->timer_id = g_timeout_add(priv->interval,
977 + (GSourceFunc)gtk_widget_tap_and_hold_timeout_with_events,
982 +static gboolean gtk_widget_tap_and_hold_button_release_with_events(
983 + GtkWidget *widget, GdkEvent *event, GtkWidgetPrivate *priv)
985 + tap_and_hold_remove_timer( priv );
989 +static gboolean gtk_widget_tap_and_hold_leave_notify_with_events(
990 + GtkWidget *widget, GdkEvent *event, GtkWidgetPrivate *priv)
992 + tap_and_hold_remove_timer( priv );
997 + * gtk_widget_tap_and_hold_menu_position_top:
998 + * @menu: a #GtkMenu
999 + * @x: x cordinate to be returned
1000 + * @y: y cordinate to be returned
1001 + * @push_in: If going off screen, push it pack on the screen
1002 + * @widget: a #GtkWidget
1004 + * Pre-made menu positioning function.
1005 + * It positiones the @menu over the @widget.
1008 +void gtk_widget_tap_and_hold_menu_position_top( GtkWidget *menu,
1009 + gint *x, gint *y, gboolean *push_in, GtkWidget *widget )
1012 + * This function positiones the menu above widgets.
1013 + * This is a modified version of the position function
1014 + * gtk_combo_box_position_over.
1017 + GtkRequisition requisition;
1018 + gint screen_width = 0;
1019 + gint menu_xpos = 0;
1020 + gint menu_ypos = 0;
1021 + gint w_xpos = 0, w_ypos = 0;
1023 + gtk_widget_size_request( menu, &requisition );
1025 + topw = gtk_widget_get_toplevel(widget);
1026 + gdk_window_get_origin( topw->window, &w_xpos, &w_ypos );
1028 + menu_xpos += widget->allocation.x + w_xpos;
1029 + menu_ypos += widget->allocation.y + w_ypos - requisition.height;
1031 + if( gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL )
1032 + menu_xpos = menu_xpos + widget->allocation.width - requisition.width;
1034 + screen_width = gdk_screen_get_width( gtk_widget_get_screen(widget) );
1036 + if( menu_xpos < w_xpos )
1037 + menu_xpos = w_xpos;
1038 + else if( (menu_xpos + requisition.width) > screen_width )
1039 + menu_xpos -= ( (menu_xpos + requisition.width) - screen_width );
1040 + if( menu_ypos < w_ypos )
1041 + menu_ypos = w_ypos;