--- gtk+-2.6.4/gtk/gtkwidget.c	2005-02-24 18:44:02.000000000 +0200
+++ gtk+-2.6.4/gtk/gtkwidget.c	2005-04-06 16:19:38.386702696 +0300
@@ -28,6 +28,8 @@
 #include <stdarg.h>
 #include <string.h>
 #include <locale.h>
+#include <stdlib.h>
+#include <x11/gdkx.h>
 #include "gtkalias.h"
 #include "gtkcontainer.h"
 #include "gtkaccelmap.h"
@@ -44,6 +46,11 @@
 #include "gtkwindow.h"
 #include "gtkbindings.h"
 #include "gtkprivate.h"
+#include "gtktreeview.h"
+#include "gtkentry.h"
+#include "gtktextview.h"
+#include "gtkimcontext.h"
+#include "gtkmenu.h"
 #include "gdk/gdk.h"
 #include "gdk/gdkprivate.h" /* Used in gtk_reset_shapes_recurse to avoid copy */
 #include <gobject/gvaluecollector.h>
@@ -53,11 +60,30 @@
 #include "gtkaccessible.h"
 #include "gtktooltips.h"
 #include "gtkinvisible.h"
+#include "gtkscrollbar.h"   /* Following are needed for special focus changes */
+#include "gtktoolbar.h"
+#include "gtkmenu.h"
+#include "gtkmenuitem.h"
+#include "gtktogglebutton.h"
+#include "gtkcomboboxentry.h"
+#include "gtktogglebutton.h"
+#include "gtkcomboboxentry.h"
 
 #define WIDGET_CLASS(w)	 GTK_WIDGET_GET_CLASS (w)
 #define	INIT_PATH_SIZE	(512)
 
+#define GTK_TAP_THRESHOLD 30
+#define GTK_TAP_MENU_THRESHOLD 20
+#define GTK_TAP_AND_HOLD_TIMER_COUNTER 11
+#define GTK_TAP_AND_HOLD_TIMER_INTERVAL 100
 
+typedef struct _GtkWidgetPrivate GtkWidgetPrivate;
+
+#define GTK_WIDGET_GET_PRIVATE(obj) ( G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+                                      GTK_TYPE_WIDGET, GtkWidgetPrivate) )
+
+#define TAP_AND_HOLD_ANIMATION 1
+                                      
 enum {
   SHOW,
   HIDE,
@@ -120,6 +146,9 @@
   ACCEL_CLOSURES_CHANGED,
   SCREEN_CHANGED,
   CAN_ACTIVATE_ACCEL,
+	INSENSITIVE_PRESS,
+  TAP_AND_HOLD,
+  TAP_AND_HOLD_SETUP,
   LAST_SIGNAL
 };
 
@@ -142,7 +171,8 @@
   PROP_STYLE,
   PROP_EVENTS,
   PROP_EXTENSION_EVENTS,
-  PROP_NO_SHOW_ALL
+  PROP_NO_SHOW_ALL,
+  PROP_TAP_AND_HOLD
 };
 
 typedef	struct	_GtkStateData	 GtkStateData;
@@ -155,7 +185,50 @@
   guint		use_forall : 1;
 };
 
+struct _GtkWidgetPrivate
+{
+  GtkWidget *menu;
+  guint timer_id;
+
+  GtkStateType stype;
+  GtkStateType type_on_press;
+  GdkEvent *fake_event;
+  GtkMenuPositionFunc func;
+  gint x, y;
+  gint timer_counter;
+  gint run_press : 1;
+  gint button_pressed : 1;
+  gint signals_connected : 1;
+  GtkWidgetTapAndHoldFlags flags;
+  gboolean state_set;
+  guint interval;
+  
+#ifdef TAP_AND_HOLD_ANIMATION
+  GdkPixbufAnimation *anim;
+  GdkPixbufAnimationIter *iter;
+  guint width, height;
+#endif
+};
+
 
+/* --- Tap And Hold --- */
+static gboolean gtk_widget_tap_and_hold_button_press_with_events( GtkWidget *widget,
+                                     GdkEvent *event, GtkWidgetPrivate *priv );
+static gboolean gtk_widget_tap_and_hold_button_release_with_events( GtkWidget *widget,
+                                     GdkEvent *event, GtkWidgetPrivate *priv );
+static gboolean gtk_widget_tap_and_hold_leave_notify_with_events( GtkWidget *widget,
+                                     GdkEvent *event, GtkWidgetPrivate *priv );
+static gboolean gtk_widget_tap_and_hold_timeout_with_events( GtkWidget *widget );
+static gboolean gtk_widget_tap_and_hold_timeout( GtkWidget *widget );
+static gboolean gtk_widget_tap_and_hold_button_press( GtkWidget *widget,
+                                     GdkEvent *event, GtkWidgetPrivate *priv );
+static gboolean gtk_widget_tap_and_hold_button_release( GtkWidget *widget,
+                                     GdkEvent *event, GtkWidgetPrivate *priv );
+static gboolean gtk_widget_tap_and_hold_leave_notify( GtkWidget *widget,
+                                     GdkEvent *event, GtkWidgetPrivate *priv );
+static void gtk_widget_tap_and_hold_setup_real( GtkWidget *widget,
+            GtkWidget *menu, GtkCallback func, GtkWidgetTapAndHoldFlags flags );
+static void gtk_widget_real_tap_and_hold(GtkWidget *widget);
 /* --- prototypes --- */
 static void	gtk_widget_class_init		 (GtkWidgetClass    *klass);
 static void	gtk_widget_init			 (GtkWidget	    *widget);
@@ -228,6 +301,13 @@
 					   gint       width,
 					   gint       height);
 
+/*Hildon focus handling*/
+static void gtk_widget_set_focus_handling( GtkWidget *widget, gboolean state );
+
+static gboolean gtk_widget_enter_notify_event( GtkWidget *widget, GdkEventCrossing *event );
+static gboolean gtk_widget_leave_notify_event( GtkWidget *widget, GdkEventCrossing *event );
+static gint gtk_widget_button_release_event( GtkWidget *widget, GdkEventButton *event );
+static gint gtk_widget_button_press_event( GtkWidget *widget, GdkEventButton *event );
 
 /* --- variables --- */
 static gpointer         parent_class = NULL;
@@ -239,6 +319,9 @@
 static GtkTextDirection gtk_default_direction = GTK_TEXT_DIR_LTR;
 static GParamSpecPool  *style_property_spec_pool = NULL;
 
+static gboolean on_same_widget = FALSE; /*Hildon focus handling*/
+static gboolean mouse_pressed = FALSE; /*Hildon focus handling*/
+
 static GQuark		quark_property_parser = 0;
 static GQuark		quark_aux_info = 0;
 static GQuark		quark_accel_path = 0;
@@ -396,6 +479,9 @@
   klass->drag_data_received = NULL;
   klass->screen_changed = NULL;
   klass->can_activate_accel = gtk_widget_real_can_activate_accel;
+  klass->tap_and_hold_setup = gtk_widget_tap_and_hold_setup_real;
+  klass->insensitive_press = NULL;
+  klass->tap_and_hold = gtk_widget_real_tap_and_hold;
 
   klass->show_help = gtk_widget_real_show_help;
   
@@ -404,6 +490,18 @@
 
   klass->no_expose_event = NULL;
 
+  g_type_class_add_private( klass, sizeof(GtkWidgetPrivate) );
+
+  g_object_class_install_property (gobject_class,
+				   PROP_TAP_AND_HOLD,
+				   g_param_spec_int ("tap_and_hold_state",
+ 						     P_("Tap and hold State type"),
+ 						     P_("Sets the state to be used to the tap and hold functionality. The default is GTK_STATE_NORMAL"),
+ 						     0,
+ 						     4, /*4 == Last state in GTK+-2.0*/
+ 						     GTK_STATE_NORMAL,
+ 						     G_PARAM_READWRITE));
+
   g_object_class_install_property (gobject_class,
 				   PROP_NAME,
 				   g_param_spec_string ("name",
@@ -1389,6 +1487,31 @@
 		  _gtk_marshal_BOOLEAN__UINT,
                   G_TYPE_BOOLEAN, 1, G_TYPE_UINT);
 
+   widget_signals[INSENSITIVE_PRESS] =
+     g_signal_new ("insensitive_press",
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (GtkWidgetClass, insensitive_press),
+                  NULL, NULL,
+                  _gtk_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  widget_signals[TAP_AND_HOLD] =
+    g_signal_new("tap-and-hold", G_TYPE_FROM_CLASS(gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET(GtkWidgetClass, tap_and_hold),
+                  NULL, NULL,
+                  _gtk_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+                  
+  widget_signals[TAP_AND_HOLD_SETUP] =  
+    g_signal_new("tap-and-hold-setup", G_TYPE_FROM_CLASS(gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET(GtkWidgetClass, tap_and_hold_setup),
+                  NULL, NULL, /*FIXME -- OBJECT_POINTER_FLAGS*/
+                  _gtk_marshal_VOID__OBJECT_UINT_FLAGS,
+                  G_TYPE_NONE, 3, G_TYPE_OBJECT, G_TYPE_POINTER, G_TYPE_UINT);
+
   binding_set = gtk_binding_set_by_class (klass);
   gtk_binding_entry_add_signal (binding_set, GDK_F10, GDK_SHIFT_MASK,
                                 "popup_menu", 0);
@@ -1418,7 +1541,12 @@
 								 P_("Whether to draw the focus indicator inside widgets"),
 								 TRUE,
 								 G_PARAM_READABLE));
-
+  gtk_widget_class_install_style_property (klass,
+				   g_param_spec_boolean ("hildon-focus-handling",
+ 							 P_("Hildon focus handling"),
+ 							 P_("Whether the widget is using the hildon like focus handling or not"),
+ 							 FALSE,
+								 G_PARAM_READABLE));
   gtk_widget_class_install_style_property (klass,
 					   g_param_spec_int ("focus-line-width",
 							     P_("Focus linewidth"),
@@ -1543,6 +1671,8 @@
     case PROP_NO_SHOW_ALL:
       gtk_widget_set_no_show_all (widget, g_value_get_boolean (value));
       break;
+    case PROP_TAP_AND_HOLD:
+      GTK_WIDGET_GET_PRIVATE(widget)->type_on_press = g_value_get_int(value);
     default:
       break;
     }
@@ -1637,16 +1767,45 @@
     case PROP_NO_SHOW_ALL:
       g_value_set_boolean (value, gtk_widget_get_no_show_all (widget));
       break;
+    case PROP_TAP_AND_HOLD:
+      g_value_set_int (value,
+                       (int)GTK_WIDGET_GET_PRIVATE(widget)->type_on_press);
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
     }
 }
 
+static void gtk_widget_set_focus_handling( GtkWidget *widget, gboolean state )
+{
+      GtkWidgetPrivate *priv;
+      priv = GTK_WIDGET_GET_PRIVATE (widget);
+
+      if( state && GTK_WIDGET_CAN_FOCUS(widget) )
+      {
+         if (!priv->state_set)
+            {  
+               g_signal_connect( G_OBJECT(widget), "button-press-event",
+                                      G_CALLBACK(gtk_widget_button_press_event), NULL );
+               g_signal_connect( G_OBJECT(widget), "button-release-event",
+                                      G_CALLBACK(gtk_widget_button_release_event), NULL );
+               g_signal_connect( G_OBJECT(widget), "enter-notify-event",
+                                      G_CALLBACK(gtk_widget_enter_notify_event), NULL );
+               g_signal_connect( G_OBJECT(widget), "leave-notify-event",
+                                      G_CALLBACK(gtk_widget_leave_notify_event), NULL );
+               priv->state_set = TRUE;
+            }
+      }
+}
+
 static void
 gtk_widget_init (GtkWidget *widget)
 {
+  GtkWidgetPrivate *priv;
   GTK_PRIVATE_FLAGS (widget) = PRIVATE_GTK_CHILD_VISIBLE;
+
+  priv = GTK_WIDGET_GET_PRIVATE(widget);
+
   widget->state = GTK_STATE_NORMAL;
   widget->saved_state = GTK_STATE_NORMAL;
   widget->name = NULL;
@@ -1659,6 +1818,18 @@
   widget->window = NULL;
   widget->parent = NULL;
 
+  priv->fake_event = NULL;
+  priv->timer_id = 0;
+  priv->menu = NULL;
+  priv->run_press = TRUE;
+  priv->signals_connected = FALSE;
+  priv->x = priv->y = 0;
+  priv->func = NULL;
+  priv->timer_counter = 0;
+  priv->flags = 0x0;
+  priv->state_set = FALSE;
+  priv->interval = GTK_TAP_AND_HOLD_TIMER_INTERVAL;
+  
   GTK_WIDGET_SET_FLAGS (widget,
 			GTK_SENSITIVE |
 			GTK_PARENT_SENSITIVE |
@@ -1670,6 +1841,7 @@
   GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED);
 
   widget->style = gtk_widget_get_default_style ();
+
   g_object_ref (widget->style);
 }
 
@@ -2153,6 +2325,7 @@
 
   if ((GTK_WIDGET_FLAGS (widget) & GTK_NO_SHOW_ALL) != 0)
     return;
+ 
 
   class = GTK_WIDGET_GET_CLASS (widget);
 
@@ -3400,6 +3573,127 @@
   return FALSE;
 }
 
+/**
+ * gtk_widget_button_press_event
+ * @widget: a #GtkWidget
+ * @event: a #GtkEventKey
+ *
+**/
+static gboolean gtk_widget_button_press_event(GtkWidget *widget, GdkEventButton *event )
+{
+  if( !mouse_pressed /*&& !GTK_IS_TREE_VIEW(widget) && !GTK_IS_ENTRY(widget)*/ )
+  {
+   	GtkWidget *toplevel;
+   	toplevel = gtk_widget_get_toplevel (widget);
+     if (GTK_IS_WINDOW (toplevel))
+       {
+         mouse_pressed = TRUE;
+
+         if( /*!gtk_window_get_prev_focus_widget(GTK_WINDOW(toplevel)) &&*/
+             GTK_IS_WIDGET(GTK_WINDOW(toplevel)->focus_widget) )
+           gtk_window_set_prev_focus_widget( GTK_WINDOW(toplevel), 
+                                           GTK_WINDOW(toplevel)->focus_widget );
+     }
+  }
+  return FALSE;
+}
+
+/**
+ * gtk_widget_button_release_event
+ * @widget: a #GtkWidget
+ * @event: a #GtkEventKey
+ *
+**/
+static gboolean gtk_widget_button_release_event(GtkWidget   *widget, GdkEventButton *event )
+{
+  if( mouse_pressed /*&& !GTK_IS_ENTRY(widget)*/ )
+  {
+  	GtkWidget *toplevel;
+  	GtkWidget *event_widget;
+  	event_widget = gtk_get_event_widget( (GdkEvent*) event );
+  	toplevel = gtk_widget_get_toplevel (widget);
+
+  	mouse_pressed = FALSE;
+    on_same_widget = TRUE;
+
+        if (GTK_IS_WINDOW (toplevel))
+          {
+  	    if( !on_same_widget && GTK_IS_WIDGET(GTK_WINDOW(toplevel)->focus_widget) )
+  		gtk_window_set_prev_focus_widget( GTK_WINDOW(toplevel), GTK_WINDOW(toplevel)->focus_widget );
+            else
+  	      gtk_window_set_prev_focus_widget( GTK_WINDOW(toplevel), event_widget );
+          }
+  }
+	return FALSE;
+}
+
+/**
+ * gtk_widget_enter_notify_event
+ * @widget: a #GtkWidget
+ * @event: a #GtkEventCrossing
+ *
+**/
+static gboolean gtk_widget_enter_notify_event( GtkWidget *widget, GdkEventCrossing *event )
+{
+ 	GtkWidget *toplevel;
+ 	GtkWidget *event_widget;
+  /*if( GTK_IS_ENTRY(widget) )
+    return FALSE;*/
+
+ 	toplevel = gtk_widget_get_toplevel (widget);
+ 	event_widget = gtk_get_event_widget ( (GdkEvent*) event );
+
+  if(mouse_pressed && !on_same_widget && gtk_window_get_prev_focus_widget( GTK_WINDOW(toplevel) ) == event_widget)
+  {
+/*  	GtkWidget *temp;*/
+  	on_same_widget = TRUE;
+
+/*    temp = gtk_window_get_prev_focus_widget( GTK_WINDOW(toplevel) );*/
+    if( GTK_IS_WIDGET(GTK_WINDOW(toplevel)->focus_widget) )
+    {
+      gtk_window_set_prev_focus_widget( GTK_WINDOW(toplevel), GTK_WINDOW(toplevel)->focus_widget );
+      if( GTK_WIDGET_CAN_FOCUS(event_widget) )
+        gtk_widget_grab_focus( event_widget );
+      else
+        gtk_widget_activate( event_widget );
+    }
+  }
+	return FALSE;
+}
+
+
+/**
+ * gtk_widget_leave_notify_event
+ * @widget: a #GtkWidget
+ * @event: a #GtkEventCrossing
+ * 
+**/
+static gboolean gtk_widget_leave_notify_event( GtkWidget *widget, GdkEventCrossing *event )
+{
+  if( mouse_pressed && on_same_widget /*&& !GTK_IS_ENTRY(widget)*/ )
+  {
+  	GtkWidget *event_widget;
+  	GtkWidget *toplevel;
+  	GtkWidget *temp;
+  	toplevel = gtk_widget_get_toplevel( widget );
+  	event_widget = gtk_get_event_widget( (GdkEvent*) event );
+  	on_same_widget = FALSE;
+
+    temp = gtk_window_get_prev_focus_widget( GTK_WINDOW(toplevel) );
+    if( GTK_IS_WIDGET(temp) &&
+        gtk_window_has_toplevel_focus(GTK_WINDOW(toplevel)) )
+    {
+        gtk_window_set_prev_focus_widget( GTK_WINDOW(toplevel), event_widget );
+      if( GTK_WIDGET_CAN_FOCUS(temp) )
+        gtk_widget_grab_focus( temp );
+      else
+        gtk_widget_activate( temp );
+    }
+  }
+	return FALSE;
+}
+
+
 #define WIDGET_REALIZED_FOR_EVENT(widget, event) \
      (event->type == GDK_FOCUS_CHANGE || GTK_WIDGET_REALIZED(widget))
 
@@ -3947,11 +4241,14 @@
 static void
 gtk_widget_real_grab_focus (GtkWidget *focus_widget)
 {
-  if (GTK_WIDGET_CAN_FOCUS (focus_widget))
+  if (GTK_WIDGET_CAN_FOCUS (focus_widget) &&
+      GTK_WIDGET_VISIBLE (focus_widget))
     {
+      static GtkIMContext *last_context = NULL;
       GtkWidget *toplevel;
       GtkWidget *widget;
-      
+      GtkIMContext *context;
+
       /* clear the current focus setting, break if the current widget
        * is the focus widget's parent, since containers above that will
        * be set by the next loop.
@@ -3972,6 +4269,53 @@
 
 	      return;
 	    }
+
+          /* Focus change stuff (previously in modified im context) */
+          if (GTK_IS_ENTRY (widget))
+            context = GTK_ENTRY (widget)->im_context;
+          else if (GTK_IS_TEXT_VIEW (widget))
+            context = GTK_TEXT_VIEW (widget)->im_context;
+          else
+            context = NULL;
+
+          if (context || last_context)
+            {
+              gboolean is_combo, is_inside_toolbar;
+              GtkWidget *parent;
+
+              parent = gtk_widget_get_parent (focus_widget);
+              is_combo = GTK_IS_TOGGLE_BUTTON (focus_widget) &&
+                (GTK_IS_COMBO_BOX_ENTRY (parent) ||
+                 GTK_IS_COMBO_BOX (parent));
+              is_inside_toolbar =
+                gtk_widget_get_ancestor (focus_widget,
+                                         GTK_TYPE_TOOLBAR) != NULL;
+
+              if (focus_widget == NULL ||
+                  !GTK_IS_ENTRY (focus_widget) &&
+                  !GTK_IS_TEXT_VIEW (focus_widget) &&
+                  !GTK_IS_SCROLLBAR (focus_widget) &&
+                  !GTK_IS_MENU_ITEM (focus_widget) &&
+                  !GTK_IS_MENU (focus_widget) &&
+                  !is_inside_toolbar &&
+                  !is_combo)
+                {
+                  /* we can't hide IM without IM context. it's possible to move
+                   * focus to widget which doesn't have IM context, but which
+                   * doesn't want IM to be hidden either. So, we have this
+                   * static last_context variable which is used... */
+                  gtk_im_context_hide (context != NULL
+                                       ? context : last_context);
+                }
+
+              if (context)
+                {
+                  if (last_context != NULL)
+                    g_object_unref (last_context);
+                  last_context = context;
+                  g_object_ref (last_context);
+                }
+            }
 	  
 	  if (widget)
 	    {
@@ -4462,9 +4806,13 @@
 {
   g_return_if_fail (GTK_IS_WIDGET (widget));
 
-  if (!GTK_WIDGET_USER_STYLE (widget) &&
-      !GTK_WIDGET_RC_STYLE (widget))
+  if (!GTK_WIDGET_USER_STYLE (widget) && !GTK_WIDGET_RC_STYLE (widget))
+  {
+    gboolean hfh = FALSE;
     gtk_widget_reset_rc_style (widget);
+    gtk_widget_style_get( widget, "hildon-focus-handling", &hfh, NULL );
+    gtk_widget_set_focus_handling( widget, hfh );
+  }
 }
 
 /* Look up the RC style for this widget, unsetting any user style that
@@ -6396,7 +6744,7 @@
   
   if (!GTK_WIDGET_DIRECTION_SET (widget))
     gtk_widget_emit_direction_changed (widget, old_dir);
-  
+
   if (GTK_IS_CONTAINER (widget))
     gtk_container_forall (GTK_CONTAINER (widget),
 			  gtk_widget_set_default_direction_recurse,
@@ -6405,6 +6753,13 @@
   g_object_unref (widget);
 }
 
+/* Non static */
+void gtk_widget_set_direction_recursive(GtkWidget * widget,  GtkTextDirection dir )
+{
+  gtk_widget_set_default_direction_recurse( widget, GUINT_TO_POINTER(dir) );
+}
+               
+
 /**
  * gtk_widget_set_default_direction:
  * @dir: the new default direction. This cannot be
@@ -6422,7 +6777,7 @@
     {
       GList *toplevels, *tmp_list;
       GtkTextDirection old_dir = gtk_default_direction;
-      
+
       gtk_default_direction = dir;
 
       tmp_list = toplevels = gtk_window_list_toplevels ();
@@ -6497,6 +6852,7 @@
 gtk_widget_finalize (GObject *object)
 {
   GtkWidget *widget = GTK_WIDGET (object);
+  GtkWidgetPrivate *priv = GTK_WIDGET_GET_PRIVATE(object);
   GtkWidgetAuxInfo *aux_info;
   gint *events;
   GdkExtensionMode *mode;
@@ -6507,6 +6863,12 @@
   g_object_unref (widget->style);
   widget->style = NULL;
 
+  if (priv->timer_id)
+    {
+      g_source_remove (priv->timer_id);
+      priv->timer_id = 0;
+    }
+  
   if (widget->name)
     g_free (widget->name);
   
@@ -6526,6 +6888,12 @@
   if (accessible)
     g_object_unref (accessible);
 
+  if  (GTK_IS_MENU(priv->menu))
+    gtk_widget_destroy (priv->menu);
+
+  if (priv->fake_event)
+    gdk_event_free (priv->fake_event);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -7577,3 +7945,450 @@
   
   g_object_notify (G_OBJECT (widget), "no_show_all");
 }
+
+void gtk_widget_insensitive_press ( GtkWidget *widget )
+{
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  
+  g_signal_emit(widget, widget_signals[INSENSITIVE_PRESS], 0);
+}
+
+/*Tap And Hold*/
+
+#ifdef TAP_AND_HOLD_ANIMATION
+static void
+init_tap_and_hold_animation( GtkWidgetPrivate *priv )
+{
+  GTimeVal time;
+  if( priv->anim )
+  {
+    g_get_current_time( &time );
+    priv->iter = gdk_pixbuf_animation_get_iter( priv->anim, &time );
+    priv->interval = gdk_pixbuf_animation_iter_get_delay_time( priv->iter );
+  }
+}
+
+static void
+timeout_tap_and_hold_animation( GtkWidgetPrivate *priv )
+{
+  GdkScreen *screen;
+  GdkPixbuf *pic;
+  GdkCursor *cursor;
+  GTimeVal time;
+
+  if( priv->anim )
+  {
+    screen = gdk_screen_get_default();
+    g_get_current_time( &time );
+	
+    pic = gdk_pixbuf_animation_iter_get_pixbuf( priv->iter );
+    cursor = gdk_cursor_new_from_pixbuf( gdk_display_get_default(), pic,
+                                         priv->width, priv->height );
+
+    gdk_window_set_cursor( priv->fake_event->button.window, cursor );
+	
+    gdk_pixbuf_animation_iter_advance( priv->iter, &time );
+  }
+}
+
+static void
+stop_tap_and_hold_animation( GtkWidgetPrivate *priv )
+{
+  if( priv->anim )
+  {
+    gdk_window_set_cursor( priv->fake_event->button.window, NULL );
+  }
+}
+
+
+#endif
+
+void tap_and_hold_remove_timer( GtkWidgetPrivate *priv )
+{
+    if (priv->timer_id)
+    {
+      g_source_remove (priv->timer_id);
+      priv->timer_id = 0;
+      #ifdef TAP_AND_HOLD_ANIMATION
+      stop_tap_and_hold_animation( priv );
+      #endif
+    }
+}
+
+/**
+ * gtk_widget_tap_and_hold_setup:
+ *
+ * @widget : A @GtkWidget
+ * @menu : A @GtkWidget
+ * @func : A @GtkCallback
+ * @flags : A @GtkWidgetTapAndHoldFlags
+ *
+ * Setups the tap and hold functionality to the @widget.
+ * The @menu is shown when the functionality is activated.
+ * If the @menu is wanted to be positioned in a different way than the
+ * gtk+ default, the menuposition @func can be passed as a third parameter.
+ * Fourth parameter, @flags are explaned with detail in the documentation.
+ */
+void gtk_widget_tap_and_hold_setup (GtkWidget *widget, GtkWidget *menu,
+            GtkCallback func, GtkWidgetTapAndHoldFlags flags)
+{
+  /*GtkWidgetClass *klass = GTK_WIDGET_GET_CLASS(widget);*/
+  g_return_if_fail( GTK_IS_WIDGET(widget));
+  g_return_if_fail(menu == NULL || GTK_IS_MENU(menu));
+  g_signal_emit( widget, widget_signals[TAP_AND_HOLD_SETUP], 0, menu, func,
+                 flags );
+}
+
+static void gtk_widget_tap_and_hold_setup_real (GtkWidget *widget,
+         GtkWidget *menu, GtkCallback func, GtkWidgetTapAndHoldFlags flags)
+{
+  #ifdef TAP_AND_HOLD_ANIMATION
+  GtkStyle *style = NULL;
+  GError *error = NULL;
+  #endif
+  GtkWidgetPrivate *priv;
+  g_return_if_fail (GTK_IS_WIDGET(widget));
+  g_return_if_fail (menu == NULL || GTK_IS_MENU(menu));
+  priv = GTK_WIDGET_GET_PRIVATE (widget);
+
+  if (priv->signals_connected)
+    return;
+
+  _gtk_menu_enable_context_menu_behavior (menu);
+
+  priv->menu = menu;
+  priv->func = (GtkMenuPositionFunc)func;
+  priv->signals_connected = TRUE;
+  priv->timer_counter = 0;
+  priv->flags = flags;
+
+  if (flags & GTK_TAP_AND_HOLD_PASS_PRESS)
+    {
+      g_signal_connect( widget, "button-press-event",
+        G_CALLBACK(gtk_widget_tap_and_hold_button_press_with_events), priv );
+      g_signal_connect( widget, "button-release-event",
+        G_CALLBACK(gtk_widget_tap_and_hold_button_release_with_events), priv );
+      g_signal_connect( widget, "leave-notify-event",
+        G_CALLBACK(gtk_widget_tap_and_hold_leave_notify_with_events), priv );
+    }
+  else
+    {
+      g_signal_connect( widget, "button-press-event",
+                    G_CALLBACK(gtk_widget_tap_and_hold_button_press), priv );
+      g_signal_connect( widget, "button-release-event",
+                    G_CALLBACK(gtk_widget_tap_and_hold_button_release), priv );
+      g_signal_connect( widget, "leave-notify-event",
+                    G_CALLBACK(gtk_widget_tap_and_hold_leave_notify), priv );
+    }
+    
+#ifdef TAP_AND_HOLD_ANIMATION
+  priv->anim = NULL;
+  style = gtk_rc_get_style_by_paths(gtk_settings_get_default(),
+                                      "gtk-tap-and-hold-animation",
+                                      NULL, G_TYPE_NONE);
+
+  if( style )
+  {
+
+    priv->anim = gdk_pixbuf_animation_new_from_file(
+                        (gchar*)style->rc_style->bg_pixmap_name[0], &error );
+
+    priv->width = gdk_pixbuf_animation_get_width( priv->anim )/2;
+    priv->height = gdk_pixbuf_animation_get_height( priv->anim )/2;
+  }
+#endif
+}
+
+static void gtk_widget_real_tap_and_hold(GtkWidget *widget)
+{
+  GtkWidgetPrivate *priv = GTK_WIDGET_GET_PRIVATE (widget);
+
+  if (GTK_IS_MENU(priv->menu))
+    gtk_menu_popup( GTK_MENU(priv->menu), NULL, NULL,
+        (GtkMenuPositionFunc)priv->func,
+        widget, 1, gdk_x11_get_server_time(widget->window) );
+}
+
+static gboolean gtk_widget_tap_and_hold_timeout (GtkWidget *widget)
+{
+  GtkWidgetPrivate *priv= GTK_WIDGET_GET_PRIVATE(widget);
+  gboolean return_value;
+  gint x = 0, y = 0;
+
+  #ifdef TAP_AND_HOLD_ANIMATION
+  timeout_tap_and_hold_animation( priv  );
+  #endif
+  
+  if( priv->timer_counter )
+    priv->timer_counter--;
+  else
+    priv->timer_id = 0;
+
+  gdk_display_get_pointer( gdk_x11_lookup_xdisplay(
+      GDK_WINDOW_XDISPLAY(priv->fake_event->button.window) ),
+      NULL, &x, &y, NULL );
+
+  if ((abs(x - priv->x) > GTK_TAP_THRESHOLD) ||
+      (abs(y - priv->y) > GTK_TAP_THRESHOLD))
+    {
+      if (priv->stype != priv->type_on_press)
+        gtk_widget_set_state( widget, priv->stype );
+      priv->timer_counter = 0;
+      priv->timer_id = 0;
+      priv->x = priv->y = 0;
+      priv->run_press = FALSE;
+      g_signal_emit_by_name (G_OBJECT(widget), "button-press-event",
+                             priv->fake_event, &return_value);
+      return FALSE;
+   }
+  if (!priv->timer_id)
+    {
+      if (priv->stype != priv->type_on_press)
+        gtk_widget_set_state( widget, priv->stype );
+      #ifdef TAP_AND_HOLD_ANIMATION
+      stop_tap_and_hold_animation( priv );
+      #endif
+      g_signal_emit(widget, widget_signals[TAP_AND_HOLD], 0);
+      priv->x = x;
+      priv->y = y;
+      return FALSE;
+    }
+  return TRUE;
+}
+
+static gboolean gtk_widget_tap_and_hold_button_press (GtkWidget *widget,
+                                      GdkEvent *event, GtkWidgetPrivate *priv)
+{
+  if (!priv->run_press || event->button.button != 1)
+    {
+      priv->run_press = TRUE;
+      return FALSE;
+    }
+  
+  if (event->button.type == GDK_2BUTTON_PRESS)
+    return FALSE;
+
+  if (priv->fake_event)
+    gdk_event_free (priv->fake_event);
+  priv->fake_event = gdk_event_copy(event);
+  
+  if (!priv->timer_id)
+    {
+      priv->stype = GTK_WIDGET_STATE(widget);
+      if (priv->stype != priv->type_on_press)
+        gtk_widget_set_state( widget, priv->type_on_press );
+      gdk_display_get_pointer(
+         gdk_x11_lookup_xdisplay( GDK_WINDOW_XDISPLAY(event->button.window) ),
+         NULL, &priv->x, &priv->y, NULL );
+      priv->timer_counter = GTK_TAP_AND_HOLD_TIMER_COUNTER;
+      
+      #ifdef TAP_AND_HOLD_ANIMATION
+      init_tap_and_hold_animation( priv );
+      #endif
+      priv->timer_id = g_timeout_add( priv->interval,
+                        (GSourceFunc)gtk_widget_tap_and_hold_timeout, widget );
+    }
+return TRUE;
+}
+
+static gboolean gtk_widget_tap_and_hold_button_release (GtkWidget *widget,
+                                      GdkEvent *event, GtkWidgetPrivate *priv)
+{
+  gboolean return_value;
+
+  if (!priv->run_press || event->button.button != 1 || !priv->timer_id ||
+     event->button.type == GDK_2BUTTON_PRESS)
+    return FALSE;
+
+  g_source_remove (priv->timer_id);
+  priv->timer_id = 0;
+  priv->x = priv->y = priv->timer_counter = 0;
+  if (priv->stype != priv->type_on_press)
+    gtk_widget_set_state (widget, priv->stype);
+
+  #ifdef TAP_AND_HOLD_ANIMATION
+  stop_tap_and_hold_animation( priv );
+  #endif
+  
+  if (priv->flags & GTK_TAP_AND_HOLD_NO_SIGNALS)
+      return FALSE;
+
+  priv->run_press = FALSE;
+  
+  g_signal_emit_by_name (G_OBJECT(widget), "button-press-event",
+                         priv->fake_event, &return_value);
+
+return FALSE;
+}
+
+static gboolean gtk_widget_tap_and_hold_leave_notify (GtkWidget *widget,
+                                      GdkEvent *event, GtkWidgetPrivate *priv)
+{
+  gboolean return_value;
+  if (!priv->timer_id)
+    return FALSE;
+
+  g_source_remove (priv->timer_id);
+  priv->timer_id = 0;
+  priv->x = priv->y = priv->timer_counter = 0;
+  if (priv->stype != priv->type_on_press)
+    gtk_widget_set_state (widget, priv->stype);
+
+  #ifdef TAP_AND_HOLD_ANIMATION
+  stop_tap_and_hold_animation( priv );
+  #endif
+  priv->run_press = FALSE;
+  g_signal_emit_by_name (G_OBJECT(widget), "button-press-event",
+                         priv->fake_event, &return_value);
+
+return FALSE;
+}
+
+static gboolean
+gtk_widget_tap_and_hold_timeout_with_events (GtkWidget *widget)
+{
+  gint x, y;
+  GtkWidgetPrivate *priv= GTK_WIDGET_GET_PRIVATE(widget);
+
+  g_return_val_if_fail (priv->fake_event, FALSE);
+
+  #ifdef TAP_AND_HOLD_ANIMATION
+  timeout_tap_and_hold_animation( priv  );
+  #endif
+  
+  gdk_display_get_pointer( gdk_x11_lookup_xdisplay(
+      GDK_WINDOW_XDISPLAY(priv->fake_event->button.window) ),
+      NULL, &x, &y, NULL );
+  
+  if( priv->timer_counter )
+  {
+    priv->timer_counter--;
+    if ((abs(x - priv->x) > GTK_TAP_THRESHOLD) ||
+        (abs(y - priv->y) > GTK_TAP_THRESHOLD))
+     {
+       #ifdef TAP_AND_HOLD_ANIMATION
+       stop_tap_and_hold_animation( priv );
+       #endif
+       tap_and_hold_remove_timer( priv );
+     }
+    return TRUE;
+  }
+
+  if (!((abs(x - priv->x) > GTK_TAP_THRESHOLD) ||
+     (abs(y - priv->y) > GTK_TAP_THRESHOLD)))
+    {
+      gboolean return_value;
+      priv->fake_event->button.type = GDK_BUTTON_RELEASE;
+      priv->fake_event->button.x = x;
+      priv->fake_event->button.y = y;
+      g_signal_emit_by_name (G_OBJECT(widget), "button-release-event",
+                             priv->fake_event, &return_value);
+      #ifdef TAP_AND_HOLD_ANIMATION
+      stop_tap_and_hold_animation( priv );
+      #endif
+      g_signal_emit(widget, widget_signals[TAP_AND_HOLD], 0);
+      priv->timer_id = 0;
+      priv->x = x;
+      priv->y = y;
+      gdk_event_free(priv->fake_event);
+      priv->fake_event = NULL;
+    }
+ 
+    
+ if (priv->timer_id)
+    {
+      g_source_remove (priv->timer_id);
+      priv->timer_id = 0;
+    }
+
+  return FALSE;
+}
+
+static gboolean gtk_widget_tap_and_hold_button_press_with_events(
+                   GtkWidget *widget, GdkEvent *event, GtkWidgetPrivate *priv)
+{
+  if( priv->timer_id || event->button.type == GDK_2BUTTON_PRESS)
+    return FALSE;
+
+  if (priv->fake_event)
+    gdk_event_free (priv->fake_event);
+  priv->fake_event = gdk_event_copy (event);
+
+  gdk_display_get_pointer(
+         gdk_x11_lookup_xdisplay(GDK_WINDOW_XDISPLAY(event->button.window)),
+         NULL, &priv->x, &priv->y, NULL);
+  #ifdef TAP_AND_HOLD_ANIMATION
+  init_tap_and_hold_animation( priv );
+  #endif
+  priv->timer_counter = GTK_TAP_AND_HOLD_TIMER_COUNTER;
+  priv->timer_id = g_timeout_add(priv->interval,
+                    (GSourceFunc)gtk_widget_tap_and_hold_timeout_with_events, 
+                    widget);
+  return FALSE;
+}
+
+static gboolean gtk_widget_tap_and_hold_button_release_with_events(
+                   GtkWidget *widget, GdkEvent *event, GtkWidgetPrivate *priv)
+{
+  tap_and_hold_remove_timer( priv );
+  return FALSE;
+}
+
+static gboolean gtk_widget_tap_and_hold_leave_notify_with_events(
+                   GtkWidget *widget, GdkEvent *event, GtkWidgetPrivate *priv)
+{
+  tap_and_hold_remove_timer( priv );
+  return FALSE;
+}
+
+/**
+ * gtk_widget_tap_and_hold_menu_position_top:
+ * @menu: a #GtkMenu
+ * @x: x cordinate to be returned
+ * @y: y cordinate to be returned
+ * @push_in: If going off screen, push it pack on the screen
+ * @widget: a #GtkWidget
+ *
+ * Pre-made menu positioning function.
+ * It positiones the @menu over the @widget.
+ * 
+ **/
+void gtk_widget_tap_and_hold_menu_position_top( GtkWidget *menu,
+                       gint *x, gint *y, gboolean *push_in, GtkWidget *widget )
+{
+  /* 
+   * This function positiones the menu above widgets.
+   * This is a modified version of the position function 
+   * gtk_combo_box_position_over. 
+   */
+  GtkWidget *topw;
+  GtkRequisition requisition;
+  gint screen_width = 0;
+  gint menu_xpos = 0;
+  gint menu_ypos = 0;
+  gint w_xpos = 0, w_ypos = 0;
+
+  gtk_widget_size_request( menu, &requisition );
+
+  topw = gtk_widget_get_toplevel(widget);
+  gdk_window_get_origin( topw->window, &w_xpos, &w_ypos );
+
+  menu_xpos += widget->allocation.x + w_xpos;
+  menu_ypos += widget->allocation.y + w_ypos - requisition.height;
+
+  if( gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL )
+    menu_xpos = menu_xpos + widget->allocation.width - requisition.width;
+
+  screen_width = gdk_screen_get_width( gtk_widget_get_screen(widget) );
+
+  if( menu_xpos < w_xpos )
+    menu_xpos = w_xpos;
+  else if( (menu_xpos + requisition.width) > screen_width )
+    menu_xpos -= ( (menu_xpos + requisition.width) - screen_width );
+  if( menu_ypos < w_ypos )
+    menu_ypos = w_ypos;
+
+  *x = menu_xpos;
+  *y = menu_ypos;
+  *push_in = TRUE;
+}