[nautilus/wip/ernestask/gtk4-continued: 17/144] canvas: Use custom event objects for event synthesis



commit 9b6b318b4913f24f9cc8e9e1fb0ea60f3860ac5d
Author: Ernestas Kulik <ernestask gnome org>
Date:   Mon Jun 4 09:26:30 2018 +0300

    canvas: Use custom event objects for event synthesis
    
    Since GdkEvent is now closed off and doesn’t exactly allow synthesizing
    events outside GTK+, a mechanism for life support is required. This
    commit adds a new event type to use in the canvas view.
    
    Additionally, this commit replaces button event handling with a gesture.

 eel/eel-canvas.c                | 381 +++++++++++++++---------------------
 eel/eel-canvas.h                |  16 +-
 eel/eel-event.c                 | 199 +++++++++++++++++++
 eel/eel-event.h                 |  59 ++++++
 eel/meson.build                 |   2 +
 src/nautilus-canvas-container.c | 419 ++++++++++++++++++++++------------------
 src/nautilus-canvas-item.c      | 123 +++++++-----
 src/nautilus-canvas-private.h   |   5 +-
 src/nautilus-canvas-view.c      |  31 ++-
 9 files changed, 745 insertions(+), 490 deletions(-)
---
diff --git a/eel/eel-canvas.c b/eel/eel-canvas.c
index 154dbd6b2..06deef763 100644
--- a/eel/eel-canvas.c
+++ b/eel/eel-canvas.c
@@ -93,7 +93,7 @@ enum
 static void eel_canvas_item_class_init (EelCanvasItemClass *klass);
 static void eel_canvas_item_init (EelCanvasItem *item);
 static int  emit_event (EelCanvas *canvas,
-                        GdkEvent  *event);
+                        EelEvent  *event);
 
 static guint item_signals[ITEM_LAST_SIGNAL];
 
@@ -1069,36 +1069,11 @@ is_descendant (EelCanvasItem *item,
 static void
 eel_canvas_item_grab_focus (EelCanvasItem *item)
 {
-    EelCanvasItem *focused_item;
-    GdkEvent ev;
-
     g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
     g_return_if_fail (gtk_widget_get_can_focus (GTK_WIDGET (item->canvas)));
 
-    focused_item = item->canvas->focused_item;
-
-    if (focused_item)
-    {
-        ev.focus_change.type = GDK_FOCUS_CHANGE;
-        ev.focus_change.window = gtk_layout_get_bin_window (GTK_LAYOUT (item->canvas));
-        ev.focus_change.send_event = FALSE;
-        ev.focus_change.in = FALSE;
-
-        emit_event (item->canvas, &ev);
-    }
-
     item->canvas->focused_item = item;
     gtk_widget_grab_focus (GTK_WIDGET (item->canvas));
-
-    if (focused_item)
-    {
-        ev.focus_change.type = GDK_FOCUS_CHANGE;
-        ev.focus_change.window = gtk_layout_get_bin_window (GTK_LAYOUT (item->canvas));
-        ev.focus_change.send_event = FALSE;
-        ev.focus_change.in = TRUE;
-
-        emit_event (item->canvas, &ev);
-    }
 }
 
 
@@ -1916,8 +1891,6 @@ static void eel_canvas_realize (GtkWidget *widget);
 static void eel_canvas_unrealize (GtkWidget *widget);
 static void eel_canvas_size_allocate (GtkWidget     *widget,
                                       GtkAllocation *allocation);
-static gint eel_canvas_button (GtkWidget      *widget,
-                               GdkEventButton *event);
 static gint eel_canvas_motion (GtkWidget      *widget,
                                GdkEventMotion *event);
 static gint eel_canvas_draw (GtkWidget *widget,
@@ -1926,10 +1899,6 @@ static gint eel_canvas_key (GtkWidget   *widget,
                             GdkEventKey *event);
 static gint eel_canvas_crossing (GtkWidget        *widget,
                                  GdkEventCrossing *event);
-static gint eel_canvas_focus_in (GtkWidget     *widget,
-                                 GdkEventFocus *event);
-static gint eel_canvas_focus_out (GtkWidget     *widget,
-                                  GdkEventFocus *event);
 static void eel_canvas_request_update_real (EelCanvas *canvas);
 static GtkLayoutClass *canvas_parent_class;
 
@@ -2002,6 +1971,18 @@ eel_canvas_set_property (GObject      *object,
     }
 }
 
+static void
+eel_canvas_dispose (GObject *object)
+{
+    EelCanvas *canvas;
+
+    canvas = EEL_CANVAS (object);
+
+    g_clear_object (&canvas->pick_event);
+
+    G_OBJECT_CLASS (canvas_parent_class)->dispose (object);
+}
+
 static void
 eel_canvas_accessible_adjustment_changed (GtkAdjustment *adjustment,
                                           gpointer       data)
@@ -2129,6 +2110,7 @@ eel_canvas_class_init (EelCanvasClass *klass)
 
     gobject_class->set_property = eel_canvas_set_property;
     gobject_class->get_property = eel_canvas_get_property;
+    gobject_class->dispose = eel_canvas_dispose;
 
     widget_class->destroy = eel_canvas_destroy;
     widget_class->map = eel_canvas_map;
@@ -2136,16 +2118,12 @@ eel_canvas_class_init (EelCanvasClass *klass)
     widget_class->realize = eel_canvas_realize;
     widget_class->unrealize = eel_canvas_unrealize;
     widget_class->size_allocate = eel_canvas_size_allocate;
-    widget_class->button_press_event = eel_canvas_button;
-    widget_class->button_release_event = eel_canvas_button;
     widget_class->motion_notify_event = eel_canvas_motion;
     widget_class->draw = eel_canvas_draw;
     widget_class->key_press_event = eel_canvas_key;
     widget_class->key_release_event = eel_canvas_key;
     widget_class->enter_notify_event = eel_canvas_crossing;
     widget_class->leave_notify_event = eel_canvas_crossing;
-    widget_class->focus_in_event = eel_canvas_focus_in;
-    widget_class->focus_out_event = eel_canvas_focus_out;
 
     klass->request_update = eel_canvas_request_update_real;
 
@@ -2166,23 +2144,27 @@ panic_root_destroyed (GtkWidget *object,
 static void
 eel_canvas_init (EelCanvas *canvas)
 {
+    GtkWidget *widget;
     guint width, height;
-    gtk_widget_set_can_focus (GTK_WIDGET (canvas), TRUE);
 
-    gtk_widget_set_redraw_on_allocate (GTK_WIDGET (canvas), FALSE);
+    widget = GTK_WIDGET (canvas);
+
+    gtk_widget_set_can_focus (widget, TRUE);
+    gtk_widget_set_redraw_on_allocate (widget, FALSE);
 
     canvas->scroll_x1 = 0.0;
     canvas->scroll_y1 = 0.0;
-    gtk_layout_get_size (GTK_LAYOUT (canvas),
-                         &width, &height);
+
+    gtk_layout_get_size (GTK_LAYOUT (canvas), &width, &height);
+
     canvas->scroll_x2 = width;
     canvas->scroll_y2 = height;
 
     canvas->pixels_per_unit = 1.0;
 
-    canvas->pick_event.type = GDK_LEAVE_NOTIFY;
-    canvas->pick_event.crossing.x = 0;
-    canvas->pick_event.crossing.y = 0;
+    canvas->pick_event = eel_event_new ();
+
+    eel_event_set_event_type (canvas->pick_event, GDK_LEAVE_NOTIFY);
 
     gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (canvas), NULL);
     gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (canvas), NULL);
@@ -2366,8 +2348,7 @@ eel_canvas_realize (GtkWidget *widget)
                             | GDK_KEY_PRESS_MASK
                             | GDK_KEY_RELEASE_MASK
                             | GDK_ENTER_NOTIFY_MASK
-                            | GDK_LEAVE_NOTIFY_MASK
-                            | GDK_FOCUS_CHANGE_MASK));
+                            | GDK_LEAVE_NOTIFY_MASK));
 
     /* Create our own temporary pixmap gc and realize all the items */
 
@@ -2570,13 +2551,18 @@ eel_canvas_size_allocate (GtkWidget     *widget,
 
 static int
 emit_event (EelCanvas *canvas,
-            GdkEvent  *event)
+            EelEvent  *event)
 {
-    GdkEvent ev;
+    GdkEventType event_type;
+    g_autoptr (EelEvent) ev = NULL;
     gint finished;
     EelCanvasItem *item;
     EelCanvasItem *parent;
     guint mask;
+    gdouble world_x;
+    gdouble world_y;
+
+    event_type = eel_event_get_event_type (event);
 
     /* Could be an old pick event */
     if (!gtk_widget_get_realized (GTK_WIDGET (canvas)))
@@ -2594,7 +2580,7 @@ emit_event (EelCanvas *canvas,
 
     if (canvas->grabbed_item)
     {
-        switch (event->type)
+        switch (eel_event_get_event_type (event))
         {
             case GDK_ENTER_NOTIFY:
             {
@@ -2653,49 +2639,20 @@ emit_event (EelCanvas *canvas,
         }
     }
 
-    /* Convert to world coordinates -- we have two cases because of diferent
-     * offsets of the fields in the event structures.
-     */
-
-    ev = *event;
-
-    switch (ev.type)
-    {
-        case GDK_ENTER_NOTIFY:
-        case GDK_LEAVE_NOTIFY:
-        {
-            eel_canvas_window_to_world (canvas,
-                                        ev.crossing.x, ev.crossing.y,
-                                        &ev.crossing.x, &ev.crossing.y);
-        }
-        break;
+    ev = eel_event_copy (event);
 
-        case GDK_MOTION_NOTIFY:
-        case GDK_BUTTON_PRESS:
-        case GDK_2BUTTON_PRESS:
-        case GDK_3BUTTON_PRESS:
-        case GDK_BUTTON_RELEASE:
-        {
-            eel_canvas_window_to_world (canvas,
-                                        ev.motion.x, ev.motion.y,
-                                        &ev.motion.x, &ev.motion.y);
-        }
-        break;
+    eel_event_get_coords (ev, &world_x, &world_y);
+    eel_canvas_window_to_world (canvas, world_x, world_y, &world_x, &world_y);
 
-        default:
-        {
-        }
-        break;
-    }
+    eel_event_set_coords (ev, world_x, world_y);
 
     /* Choose where we send the event */
 
     item = canvas->current_item;
 
     if (canvas->focused_item
-        && ((event->type == GDK_KEY_PRESS) ||
-            (event->type == GDK_KEY_RELEASE) ||
-            (event->type == GDK_FOCUS_CHANGE)))
+        && ((event_type == GDK_KEY_PRESS) ||
+            (event_type == GDK_KEY_RELEASE)))
     {
         item = canvas->focused_item;
     }
@@ -2711,9 +2668,11 @@ emit_event (EelCanvas *canvas,
     {
         g_object_ref (item);
 
-        g_signal_emit (
-            G_OBJECT (item), item_signals[ITEM_EVENT], 0,
-            &ev, &finished);
+        g_signal_emit (item,
+                       item_signals[ITEM_EVENT],
+                       0,
+                       ev,
+                       &finished);
 
         parent = item->parent;
         g_object_unref (item);
@@ -2729,13 +2688,13 @@ emit_event (EelCanvas *canvas,
  */
 static int
 pick_current_item (EelCanvas *canvas,
-                   GdkEvent  *event)
+                   EelEvent  *event)
 {
+    GdkEventType event_type;
     int button_down;
-    double x, y;
-    int cx, cy;
     int retval;
 
+    event_type = eel_event_get_event_type (event);
     retval = FALSE;
 
     /* If a button is down, we'll perform enter and leave events on the
@@ -2757,39 +2716,23 @@ pick_current_item (EelCanvas *canvas,
      * re-pick the current item if the current one gets deleted.  Also,
      * synthesize an enter event.
      */
-    if (event != &canvas->pick_event)
+    if (event != canvas->pick_event)
     {
-        if ((event->type == GDK_MOTION_NOTIFY) || (event->type == GDK_BUTTON_RELEASE))
+        if (event_type == GDK_MOTION_NOTIFY || event_type == GDK_BUTTON_RELEASE)
         {
-            /* these fields have the same offsets in both types of events */
-
-            canvas->pick_event.crossing.type = GDK_ENTER_NOTIFY;
-            canvas->pick_event.crossing.window = event->motion.window;
-            canvas->pick_event.crossing.send_event = event->motion.send_event;
-            canvas->pick_event.crossing.subwindow = NULL;
-            canvas->pick_event.crossing.x = event->motion.x;
-            canvas->pick_event.crossing.y = event->motion.y;
-            canvas->pick_event.crossing.mode = GDK_CROSSING_NORMAL;
-            canvas->pick_event.crossing.detail = GDK_NOTIFY_NONLINEAR;
-            canvas->pick_event.crossing.focus = FALSE;
-            canvas->pick_event.crossing.state = event->motion.state;
-
-            /* these fields don't have the same offsets in both types of events */
-
-            if (event->type == GDK_MOTION_NOTIFY)
-            {
-                canvas->pick_event.crossing.x_root = event->motion.x_root;
-                canvas->pick_event.crossing.y_root = event->motion.y_root;
-            }
-            else
-            {
-                canvas->pick_event.crossing.x_root = event->button.x_root;
-                canvas->pick_event.crossing.y_root = event->button.y_root;
-            }
+            gdouble x;
+            gdouble y;
+
+            eel_event_get_coords (event, &x, &y);
+
+            eel_event_set_coords (canvas->pick_event, x, y);
+            eel_event_set_event_type (canvas->pick_event, GDK_ENTER_NOTIFY);
+            eel_event_set_state (canvas->pick_event, eel_event_get_state (event));
         }
         else
         {
-            canvas->pick_event = *event;
+            g_clear_object (&canvas->pick_event);
+            canvas->pick_event = g_object_ref (event);
         }
     }
 
@@ -2802,20 +2745,14 @@ pick_current_item (EelCanvas *canvas,
 
     /* LeaveNotify means that there is no current item, so we don't look for one */
 
-    if (canvas->pick_event.type != GDK_LEAVE_NOTIFY)
+    if (eel_event_get_event_type (canvas->pick_event) != GDK_LEAVE_NOTIFY)
     {
-        /* these fields don't have the same offsets in both types of events */
+        gdouble x;
+        gdouble y;
+        gint cx;
+        gint cy;
 
-        if (canvas->pick_event.type == GDK_ENTER_NOTIFY)
-        {
-            x = canvas->pick_event.crossing.x;
-            y = canvas->pick_event.crossing.y;
-        }
-        else
-        {
-            x = canvas->pick_event.motion.x;
-            y = canvas->pick_event.motion.y;
-        }
+        eel_event_get_coords (canvas->pick_event, &x, &y);
 
         /* canvas pixel coords */
 
@@ -2851,15 +2788,14 @@ pick_current_item (EelCanvas *canvas,
         && (canvas->current_item != NULL)
         && !canvas->left_grabbed_item)
     {
-        GdkEvent new_event;
+        g_autoptr (EelEvent) new_event = NULL;
+
+        new_event = eel_event_copy (canvas->pick_event);
 
-        new_event = canvas->pick_event;
-        new_event.type = GDK_LEAVE_NOTIFY;
+        eel_event_set_event_type (new_event, GDK_LEAVE_NOTIFY);
 
-        new_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
-        new_event.crossing.subwindow = NULL;
         canvas->in_repick = TRUE;
-        retval = emit_event (canvas, &new_event);
+        retval = emit_event (canvas, new_event);
         canvas->in_repick = FALSE;
     }
 
@@ -2879,36 +2815,39 @@ pick_current_item (EelCanvas *canvas,
 
     if (canvas->current_item != NULL)
     {
-        GdkEvent new_event;
+        g_autoptr (EelEvent) new_event = NULL;
 
-        new_event = canvas->pick_event;
-        new_event.type = GDK_ENTER_NOTIFY;
-        new_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
-        new_event.crossing.subwindow = NULL;
-        retval = emit_event (canvas, &new_event);
+        new_event = eel_event_copy (canvas->pick_event);
+
+        eel_event_set_event_type (new_event, GDK_ENTER_NOTIFY);
+
+        retval = emit_event (canvas, new_event);
     }
 
     return retval;
 }
 
-/* Button event handler for the canvas */
-static gint
-eel_canvas_button (GtkWidget      *widget,
-                   GdkEventButton *event)
+gboolean
+eel_canvas_handle_event (EelCanvas *canvas,
+                         EelEvent  *event)
 {
-    EelCanvas *canvas;
-    int mask;
-    int retval;
+    guint button;
+    GdkWindow *event_window;
+    GdkWindow *bin_window;
+    GdkEventType event_type;
+    gint mask;
+    gboolean handled = FALSE;
 
-    g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE);
+    g_return_val_if_fail (EEL_IS_CANVAS (canvas), FALSE);
     g_return_val_if_fail (event != NULL, FALSE);
 
-    retval = FALSE;
-
-    canvas = EEL_CANVAS (widget);
+    button = eel_event_get_button (event);
+    event_window = eel_event_get_window (event);
+    bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (canvas));
+    event_type = eel_event_get_event_type (event);
 
     /* Don't handle extra mouse button events */
-    if (event->button > 5)
+    if (button > 5)
     {
         return FALSE;
     }
@@ -2917,12 +2856,12 @@ eel_canvas_button (GtkWidget      *widget,
      * dispatch normally regardless of the event's window if an item has
      * has a pointer grab in effect
      */
-    if (!canvas->grabbed_item && event->window != gtk_layout_get_bin_window (GTK_LAYOUT (canvas)))
+    if (canvas->grabbed_item == NULL && event_window != bin_window)
     {
-        return retval;
+        return FALSE;
     }
 
-    switch (event->button)
+    switch (button)
     {
         case 1:
         {
@@ -2958,7 +2897,7 @@ eel_canvas_button (GtkWidget      *widget,
             mask = 0;
     }
 
-    switch (event->type)
+    switch (event_type)
     {
         case GDK_BUTTON_PRESS:
         case GDK_2BUTTON_PRESS:
@@ -2967,12 +2906,17 @@ eel_canvas_button (GtkWidget      *widget,
             /* Pick the current item as if the button were not pressed, and
              * then process the event.
              */
-            event->state ^= mask;
-            canvas->state = event->state;
-            pick_current_item (canvas, (GdkEvent *) event);
-            event->state ^= mask;
-            canvas->state = event->state;
-            retval = emit_event (canvas, (GdkEvent *) event);
+            canvas->state = eel_event_get_state (event);
+
+            canvas->state ^= mask;
+            eel_event_set_state (event, canvas->state);
+
+            pick_current_item (canvas, event);
+
+            canvas->state ^= mask;
+            eel_event_set_state (event, canvas->state);
+
+            handled = emit_event (canvas, event);
         }
         break;
 
@@ -2981,12 +2925,16 @@ eel_canvas_button (GtkWidget      *widget,
             /* Process the event as if the button were pressed, then repick
              * after the button has been released
              */
-            canvas->state = event->state;
-            retval = emit_event (canvas, (GdkEvent *) event);
-            event->state ^= mask;
-            canvas->state = event->state;
-            pick_current_item (canvas, (GdkEvent *) event);
-            event->state ^= mask;
+            canvas->state = eel_event_get_state (event);
+
+            handled = emit_event (canvas, event);
+
+            canvas->state ^= mask;
+            eel_event_set_state (event, canvas->state);
+
+            pick_current_item (canvas, event);
+
+            eel_event_set_state (event, canvas->state ^ mask);
         }
         break;
 
@@ -2994,54 +2942,65 @@ eel_canvas_button (GtkWidget      *widget,
             g_assert_not_reached ();
     }
 
-    return retval;
+    return handled;
 }
 
 /* Motion event handler for the canvas */
 static gint
 eel_canvas_motion (GtkWidget      *widget,
-                   GdkEventMotion *event)
+                   GdkEventMotion *gdk_event)
 {
     EelCanvas *canvas;
+    g_autoptr (EelEvent) event = NULL;
+    GdkWindow *event_window;
+    GdkWindow *bin_window;
 
     g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE);
-    g_return_val_if_fail (event != NULL, FALSE);
+    g_return_val_if_fail (gdk_event != NULL, FALSE);
 
     canvas = EEL_CANVAS (widget);
+    event = eel_event_new_from_gdk_event ((GdkEvent *) gdk_event);
+    event_window = eel_event_get_window (event);
+    bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (canvas));
 
-    if (event->window != gtk_layout_get_bin_window (GTK_LAYOUT (canvas)))
+    if (event_window != bin_window)
     {
         return FALSE;
     }
 
-    canvas->state = event->state;
-    pick_current_item (canvas, (GdkEvent *) event);
-    return emit_event (canvas, (GdkEvent *) event);
+    canvas->state = eel_event_get_state (event);
+
+    pick_current_item (canvas, event);
+
+    return emit_event (canvas, event);
 }
 
 /* Key event handler for the canvas */
 static gint
 eel_canvas_key (GtkWidget   *widget,
-                GdkEventKey *event)
+                GdkEventKey *gdk_event)
 {
     EelCanvas *canvas;
+    g_autoptr (EelEvent) event = NULL;
 
     g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE);
-    g_return_val_if_fail (event != NULL, FALSE);
+    g_return_val_if_fail (gdk_event != NULL, FALSE);
 
     canvas = EEL_CANVAS (widget);
+    event = eel_event_new_from_gdk_event ((GdkEvent *) gdk_event);
 
-    if (emit_event (canvas, (GdkEvent *) event))
+    if (emit_event (canvas, event))
     {
         return TRUE;
     }
-    if (event->type == GDK_KEY_RELEASE)
+
+    if (gdk_event_get_event_type ((GdkEvent *) gdk_event) == GDK_KEY_RELEASE)
     {
-        return GTK_WIDGET_CLASS (canvas_parent_class)->key_release_event (widget, event);
+        return GTK_WIDGET_CLASS (canvas_parent_class)->key_release_event (widget, gdk_event);
     }
     else
     {
-        return GTK_WIDGET_CLASS (canvas_parent_class)->key_press_event (widget, event);
+        return GTK_WIDGET_CLASS (canvas_parent_class)->key_press_event (widget, gdk_event);
     }
 }
 
@@ -3049,63 +3008,31 @@ eel_canvas_key (GtkWidget   *widget,
 /* Crossing event handler for the canvas */
 static gint
 eel_canvas_crossing (GtkWidget        *widget,
-                     GdkEventCrossing *event)
+                     GdkEventCrossing *gdk_event)
 {
     EelCanvas *canvas;
+    g_autoptr (EelEvent) event = NULL;
+    GdkWindow *event_window;
+    GdkWindow *bin_window;
 
     g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE);
-    g_return_val_if_fail (event != NULL, FALSE);
+    g_return_val_if_fail (gdk_event != NULL, FALSE);
 
     canvas = EEL_CANVAS (widget);
+    event = eel_event_new_from_gdk_event ((GdkEvent *) gdk_event);
+    event_window = eel_event_get_window (event);
+    bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (canvas));
 
-    if (event->window != gtk_layout_get_bin_window (GTK_LAYOUT (canvas)))
+    if (event_window != bin_window)
     {
         return FALSE;
     }
 
-    canvas->state = event->state;
-    return pick_current_item (canvas, (GdkEvent *) event);
-}
-
-/* Focus in handler for the canvas */
-static gint
-eel_canvas_focus_in (GtkWidget     *widget,
-                     GdkEventFocus *event)
-{
-    EelCanvas *canvas;
-
-    canvas = EEL_CANVAS (widget);
-
-    if (canvas->focused_item)
-    {
-        return emit_event (canvas, (GdkEvent *) event);
-    }
-    else
-    {
-        return FALSE;
-    }
-}
-
-/* Focus out handler for the canvas */
-static gint
-eel_canvas_focus_out (GtkWidget     *widget,
-                      GdkEventFocus *event)
-{
-    EelCanvas *canvas;
-
-    canvas = EEL_CANVAS (widget);
+    canvas->state = eel_event_get_state (event);
 
-    if (canvas->focused_item)
-    {
-        return emit_event (canvas, (GdkEvent *) event);
-    }
-    else
-    {
-        return FALSE;
-    }
+    return pick_current_item (canvas, event);
 }
 
-
 static cairo_region_t *
 eel_cairo_get_clip_region (cairo_t *cr)
 {
@@ -3248,7 +3175,7 @@ update_again:
     while (canvas->need_repick)
     {
         canvas->need_repick = FALSE;
-        pick_current_item (canvas, &canvas->pick_event);
+        pick_current_item (canvas, canvas->pick_event);
     }
 
     /* it is possible that during picking we emitted an event in which
@@ -4129,7 +4056,7 @@ eel_canvas_item_class_init (EelCanvasItemClass *klass)
                       boolean_handled_accumulator, NULL,
                       g_cclosure_marshal_generic,
                       G_TYPE_BOOLEAN, 1,
-                      GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+                      EEL_TYPE_EVENT);
 
     item_signals[ITEM_DESTROY] =
         g_signal_new ("destroy",
diff --git a/eel/eel-canvas.h b/eel/eel-canvas.h
index 62e50a857..d81477eca 100644
--- a/eel/eel-canvas.h
+++ b/eel/eel-canvas.h
@@ -39,6 +39,8 @@
 #include <gdk/gdk.h>
 #include <stdarg.h>
 
+#include "eel-event.h"
+
 G_BEGIN_DECLS
 
 
@@ -172,10 +174,7 @@ struct _EelCanvasItemClass {
        /* Signal: an event ocurred for an item of this type.  The (x, y)
         * coordinates are in the canvas world coordinate system.
         */
-       gboolean (* event)                (EelCanvasItem *item, GdkEvent *event);
-
-       /* Reserved for future expansion */
-       gpointer spare_vmethods [4];
+       gboolean (* event) (EelCanvasItem  *item, EelEvent *event);
 };
 
 
@@ -342,7 +341,7 @@ struct _EelCanvas {
        EelCanvasItem *focused_item;
 
        /* Event on which selection of current item is based */
-       GdkEvent pick_event;
+       EelEvent *pick_event;
 
        /* Scrolling region */
        double scroll_x1, scroll_y1;
@@ -361,7 +360,7 @@ struct _EelCanvas {
        int zoom_xofs, zoom_yofs;
 
        /* Last known modifier state, for deferred repick when a button is down */
-       int state;
+       GdkModifierType state;
 
        /* Event mask specified when grabbing an item */
        guint grabbed_event_mask;
@@ -465,6 +464,9 @@ void eel_canvas_window_to_world (EelCanvas *canvas,
 void eel_canvas_world_to_window (EelCanvas *canvas,
                                 double worldx, double worldy, double *winx, double *winy);
 
+gboolean eel_canvas_handle_event (EelCanvas *canvas,
+                                  EelEvent  *event);
+
 /* Accessible implementation */
 GType eel_canvas_accessible_get_type (void);
 
@@ -494,4 +496,4 @@ struct _EelCanvasItemAccessibleClass
        GtkAccessibleClass parent_class;
 };
 
-G_END_DECLS
\ No newline at end of file
+G_END_DECLS
diff --git a/eel/eel-event.c b/eel/eel-event.c
new file mode 100644
index 000000000..13582692d
--- /dev/null
+++ b/eel/eel-event.c
@@ -0,0 +1,199 @@
+/* Copyright (C) 2018 Ernestas Kulik <ernestask gnome org>
+ *
+ * This file is part of Nautilus.
+ *
+ * Nautilus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Nautilus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Nautilus.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "eel-event.h"
+
+struct _EelEvent
+{
+    GObject parent_instance;
+
+    GdkEventType type;
+
+    GdkWindow *window;
+
+    gdouble x;
+    gdouble y;
+
+    guint button;
+
+    GdkModifierType state;
+
+    guint32 time;
+};
+
+G_DEFINE_TYPE (EelEvent, eel_event, G_TYPE_OBJECT)
+
+static void
+eel_event_init (EelEvent *self)
+{
+    self->type = GDK_NOTHING;
+    self->window = NULL;
+    self->x = 0.0;
+    self->y = 0.0;
+    self->button = 0;
+    self->state = 0;
+    self->time = 0;
+}
+
+static void
+eel_event_class_init (EelEventClass *klass)
+{
+}
+
+GdkEventType
+eel_event_get_event_type (EelEvent *self)
+{
+    g_return_val_if_fail (EEL_IS_EVENT (self), GDK_NOTHING);
+
+    return self->type;
+}
+
+void
+eel_event_set_event_type (EelEvent     *self,
+                          GdkEventType  type)
+{
+    g_return_if_fail (EEL_IS_EVENT (self));
+    g_return_if_fail (type >= GDK_NOTHING && type < GDK_EVENT_LAST);
+
+    self->type = type;
+}
+
+GdkWindow *
+eel_event_get_window (EelEvent *self)
+{
+    g_return_val_if_fail (EEL_IS_EVENT (self), NULL);
+
+    return self->window;
+}
+
+void
+eel_event_set_window (EelEvent  *self,
+                      GdkWindow *window)
+{
+    g_return_if_fail (EEL_IS_EVENT (self));
+    g_return_if_fail (GDK_IS_WINDOW (window));
+
+    self->window = window;
+}
+
+void
+eel_event_get_coords (EelEvent *self,
+                      gdouble  *x,
+                      gdouble  *y)
+{
+    g_return_if_fail (EEL_IS_EVENT (self));
+
+    if (x != NULL)
+    {
+        *x = self->x;
+    }
+    if (y != NULL)
+    {
+        *y = self->y;
+    }
+}
+
+void
+eel_event_set_coords (EelEvent *self,
+                      gdouble   x,
+                      gdouble   y)
+{
+    g_return_if_fail (EEL_IS_EVENT (self));
+
+    self->x = x;
+    self->y = y;
+}
+
+guint
+eel_event_get_button (EelEvent *self)
+{
+    g_return_val_if_fail (EEL_IS_EVENT (self), 0);
+
+    return self->button;
+}
+
+GdkModifierType
+eel_event_get_state (EelEvent *self)
+{
+    g_return_val_if_fail (EEL_IS_EVENT (self), 0);
+
+    return self->state;
+}
+
+void
+eel_event_set_state (EelEvent        *self,
+                     GdkModifierType  state)
+{
+    g_return_if_fail (EEL_IS_EVENT (self));
+
+    self->state = state;
+}
+
+guint32
+eel_event_get_time (EelEvent *self)
+{
+    g_return_val_if_fail (EEL_IS_EVENT (self), 0);
+
+    return self->time;
+}
+
+EelEvent *
+eel_event_copy (EelEvent *self)
+{
+    EelEvent *event;
+
+    g_return_val_if_fail (EEL_IS_EVENT (self), NULL);
+
+    event = eel_event_new ();
+
+    event->type = self->type;
+    event->window = self->window;
+    event->x = self->x;
+    event->y = self->y;
+    event->button = self->button;
+    event->state = self->state;
+    event->time = self->time;
+
+    return event;
+}
+
+EelEvent *
+eel_event_new (void)
+{
+    return g_object_new (EEL_TYPE_EVENT, NULL);
+}
+
+EelEvent *
+eel_event_new_from_gdk_event (const GdkEvent *gdk_event)
+{
+    EelEvent *event;
+
+    g_return_val_if_fail (gdk_event != NULL, NULL);
+
+    event = eel_event_new ();
+
+    event->type = gdk_event_get_event_type (gdk_event);
+    event->window = gdk_event_get_window (gdk_event);
+    event->time = gdk_event_get_time (gdk_event);
+
+    gdk_event_get_coords (gdk_event, &event->x, &event->y);
+    gdk_event_get_button (gdk_event, &event->button);
+    gdk_event_get_state (gdk_event, &event->state);
+
+    return event;
+}
diff --git a/eel/eel-event.h b/eel/eel-event.h
new file mode 100644
index 000000000..26dc3c458
--- /dev/null
+++ b/eel/eel-event.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2018 Ernestas Kulik <ernestask gnome org>
+ *
+ * This file is part of Nautilus.
+ *
+ * Nautilus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Nautilus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Nautilus.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define EEL_TYPE_EVENT (eel_event_get_type ())
+
+G_DECLARE_FINAL_TYPE (EelEvent, eel_event, EEL, EVENT, GObject)
+
+GdkEventType     eel_event_get_event_type     (EelEvent        *event);
+void             eel_event_set_event_type     (EelEvent        *event,
+                                               GdkEventType     type);
+
+GdkWindow       *eel_event_get_window         (EelEvent        *event);
+void             eel_event_set_window         (EelEvent        *event,
+                                               GdkWindow       *window);
+
+void             eel_event_get_coords         (EelEvent        *event,
+                                               gdouble         *x,
+                                               gdouble         *y);
+void             eel_event_set_coords         (EelEvent        *event,
+                                               gdouble          x,
+                                               gdouble          y);
+
+guint            eel_event_get_button         (EelEvent        *event);
+void             eel_event_set_button         (EelEvent        *event,
+                                               guint            button);
+
+GdkModifierType  eel_event_get_state          (EelEvent        *event);
+void             eel_event_set_state          (EelEvent        *event,
+                                               GdkModifierType  state);
+
+guint32          eel_event_get_time           (EelEvent        *event);
+
+EelEvent        *eel_event_copy               (EelEvent        *event);
+
+EelEvent        *eel_event_new                (void);
+EelEvent        *eel_event_new_from_gdk_event (const GdkEvent  *gdk_event);
+
+G_END_DECLS
diff --git a/eel/meson.build b/eel/meson.build
index 5437bdc4c..c646f9e6f 100644
--- a/eel/meson.build
+++ b/eel/meson.build
@@ -5,6 +5,8 @@ libeel_2_sources = [
   'eel-canvas.c',
   'eel-debug.h',
   'eel-debug.c',
+  'eel-event.c',
+  'eel-event.h',
   'eel-glib-extensions.h',
   'eel-graphic-effects.h',
   'eel-graphic-effects.c',
diff --git a/src/nautilus-canvas-container.c b/src/nautilus-canvas-container.c
index 598db03d3..94d4d09d3 100644
--- a/src/nautilus-canvas-container.c
+++ b/src/nautilus-canvas-container.c
@@ -124,7 +124,8 @@ static GType         nautilus_canvas_container_accessible_get_type (void);
 static void          preview_selected_items (NautilusCanvasContainer *container);
 static void          activate_selected_items (NautilusCanvasContainer *container);
 static void          activate_selected_items_alternate (NautilusCanvasContainer *container,
-                                                        NautilusCanvasIcon      *icon);
+                                                        NautilusCanvasIcon      *icon,
+                                                        EelEvent                *event);
 static NautilusCanvasIcon *get_first_selected_icon (NautilusCanvasContainer *container);
 static NautilusCanvasIcon *get_nth_selected_icon (NautilusCanvasContainer *container,
                                                   int                      index);
@@ -189,7 +190,6 @@ enum
     ACTIVATE_PREVIEWER,
     BAND_SELECT_STARTED,
     BAND_SELECT_ENDED,
-    BUTTON_PRESS,
     CAN_ACCEPT_ITEM,
     CONTEXT_CLICK_BACKGROUND,
     CONTEXT_CLICK_SELECTION,
@@ -1433,9 +1433,13 @@ redo_layout (NautilusCanvasContainer *container)
 /* Container-level icon handling functions.  */
 
 static gboolean
-button_event_modifies_selection (GdkEventButton *event)
+button_event_modifies_selection (EelEvent *event)
 {
-    return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0;
+    GdkModifierType state;
+
+    state = eel_event_get_state (event);
+
+    return (state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0;
 }
 
 /* invalidate the cached label sizes for all the icons */
@@ -1723,11 +1727,13 @@ rubberband_timeout_callback (gpointer data)
 
 static void
 stop_rubberbanding (NautilusCanvasContainer *container,
-                    GdkEventButton          *event);
+                    const GdkEvent          *event);
 
 static void
 start_rubberbanding (NautilusCanvasContainer *container,
-                     GdkEventButton          *event)
+                     gdouble                  x,
+                     gdouble                  y,
+                     const GdkEvent          *event)
 {
     AtkObject *accessible;
     NautilusCanvasContainerDetails *details;
@@ -1747,7 +1753,7 @@ start_rubberbanding (NautilusCanvasContainer *container,
     g_signal_emit (container,
                    signals[BAND_SELECT_STARTED], 0);
 
-    band_info->device = event->device;
+    band_info->device = gdk_event_get_device (event);
 
     for (p = details->icons; p != NULL; p = p->next)
     {
@@ -1755,9 +1761,12 @@ start_rubberbanding (NautilusCanvasContainer *container,
         icon->was_selected_before_rubberband = icon->is_selected;
     }
 
-    eel_canvas_window_to_world
-        (EEL_CANVAS (container), event->x, event->y,
-        &band_info->start_x, &band_info->start_y);
+    x += gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container)));
+    y += gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container)));
+
+    eel_canvas_window_to_world (EEL_CANVAS (container),
+                                x, y,
+                                &band_info->start_x, &band_info->start_y);
 
     band_info->selection_rectangle = eel_canvas_item_new
                                          (eel_canvas_root
@@ -1774,8 +1783,8 @@ start_rubberbanding (NautilusCanvasContainer *container,
     atk_object_set_name (accessible, "selection");
     atk_object_set_description (accessible, _("The selection rectangle"));
 
-    band_info->prev_x = event->x - gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE 
(container)));
-    band_info->prev_y = event->y - gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE 
(container)));
+    band_info->prev_x = x - gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE 
(container)));
+    band_info->prev_y = y - gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE 
(container)));
 
     band_info->active = TRUE;
 
@@ -1792,12 +1801,12 @@ start_rubberbanding (NautilusCanvasContainer *container,
                            | GDK_BUTTON_RELEASE_MASK
                            | GDK_SCROLL_MASK),
                           NULL,
-                          (GdkEvent *) event);
+                          event);
 }
 
 static void
 stop_rubberbanding (NautilusCanvasContainer *container,
-                    GdkEventButton          *event)
+                    const GdkEvent          *event)
 {
     NautilusCanvasRubberbandInfo *band_info;
     GList *icons;
@@ -1805,7 +1814,7 @@ stop_rubberbanding (NautilusCanvasContainer *container,
 
     band_info = &container->details->rubberband_info;
 
-    if (event != NULL && event->device != band_info->device)
+    if (event != NULL && gdk_event_get_device (event) != band_info->device)
     {
         return;
     }
@@ -2528,6 +2537,10 @@ keyboard_move_to (NautilusCanvasContainer *container,
                   NautilusCanvasIcon      *from,
                   GdkEventKey             *event)
 {
+    GdkModifierType state;
+
+    gdk_event_get_state ((GdkEvent *) event, &state);
+
     if (icon == NULL)
     {
         return;
@@ -2535,15 +2548,11 @@ keyboard_move_to (NautilusCanvasContainer *container,
 
     set_focus (container, icon, TRUE);
 
-    if (event != NULL &&
-        (event->state & GDK_CONTROL_MASK) != 0 &&
-        (event->state & GDK_SHIFT_MASK) == 0)
+    if ((state & GDK_CONTROL_MASK) != 0 && (state & GDK_SHIFT_MASK) == 0)
     {
         clear_keyboard_rubberband_start (container);
     }
-    else if (event != NULL &&
-             (event->state & GDK_CONTROL_MASK) != 0 &&
-             (event->state & GDK_SHIFT_MASK) != 0)
+    else if ((state & GDK_CONTROL_MASK) != 0 && (state & GDK_SHIFT_MASK) != 0)
     {
         /* Do rubberband selection */
         EelDRect rect;
@@ -2560,9 +2569,7 @@ keyboard_move_to (NautilusCanvasContainer *container,
             rubberband_select (container, &rect);
         }
     }
-    else if (event != NULL &&
-             (event->state & GDK_CONTROL_MASK) == 0 &&
-             (event->state & GDK_SHIFT_MASK) != 0)
+    else if ((state & GDK_CONTROL_MASK) == 0 && (state & GDK_SHIFT_MASK) != 0)
     {
         /* Select range */
         NautilusCanvasIcon *start_icon;
@@ -2761,8 +2768,11 @@ keyboard_arrow_key (NautilusCanvasContainer *container,
 static gboolean
 is_rectangle_selection_event (GdkEventKey *event)
 {
-    return (event->state & GDK_CONTROL_MASK) != 0 &&
-           (event->state & GDK_SHIFT_MASK) != 0;
+    GdkModifierType state;
+
+    gdk_event_get_state ((GdkEvent *) event, &state);
+
+    return (state & GDK_CONTROL_MASK) != 0 && (state & GDK_SHIFT_MASK) != 0;
 }
 
 static void
@@ -2871,19 +2881,20 @@ keyboard_up (NautilusCanvasContainer *container,
 
 static void
 keyboard_space (NautilusCanvasContainer *container,
-                GdkEventKey             *event)
+                GdkEventKey             *gdk_event)
 {
+    g_autoptr (EelEvent) event = NULL;
+    GdkModifierType state;
     NautilusCanvasIcon *icon;
 
-    if (!has_selection (container) &&
-        container->details->focus != NULL)
+    event = eel_event_new_from_gdk_event ((GdkEvent *) gdk_event);
+    state = eel_event_get_state (event);
+
+    if (!has_selection (container) && container->details->focus != NULL)
     {
-        keyboard_move_to (container,
-                          container->details->focus,
-                          NULL, NULL);
+        keyboard_move_to (container, container->details->focus, NULL, NULL);
     }
-    else if ((event->state & GDK_CONTROL_MASK) != 0 &&
-             (event->state & GDK_SHIFT_MASK) == 0)
+    else if ((state & GDK_CONTROL_MASK) != 0 && (state & GDK_SHIFT_MASK) == 0)
     {
         /* Control-space toggles the selection state of the current icon. */
         if (container->details->focus != NULL)
@@ -2914,9 +2925,9 @@ keyboard_space (NautilusCanvasContainer *container,
             }
         }
     }
-    else if ((event->state & GDK_SHIFT_MASK) != 0)
+    else if ((state & GDK_SHIFT_MASK) != 0)
     {
-        activate_selected_items_alternate (container, NULL);
+        activate_selected_items_alternate (container, NULL, event);
     }
     else
     {
@@ -3211,29 +3222,43 @@ style_updated (GtkWidget *widget)
     }
 }
 
-static gboolean
-button_press_event (GtkWidget      *widget,
-                    GdkEventButton *event)
+static void
+on_multi_press_gesture_pressed (GtkGestureMultiPress *gesture,
+                                gint                  n_press,
+                                gdouble               x,
+                                gdouble               y,
+                                gpointer              user_data)
 {
+    GtkWidget *widget;
     NautilusCanvasContainer *container;
+    GdkEventSequence *sequence;
+    const GdkEvent *gdk_event;
+    guint button;
+    EelEvent *event;
     gboolean selection_changed;
-    gboolean return_value;
     gboolean clicked_on_icon;
 
+    widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
     container = NAUTILUS_CANVAS_CONTAINER (widget);
-    container->details->button_down_time = event->time;
+    sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
+    gdk_event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
+    button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+    event = eel_event_new_from_gdk_event (gdk_event);
+
+    container->details->button_down_time = gdk_event_get_time (gdk_event);
 
     /* Forget about the old keyboard selection now that we've started mousing. */
     clear_keyboard_rubberband_start (container);
 
-    if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS)
+    if (n_press >= 2)
     {
         /* We use our own double-click detection. */
-        return TRUE;
+        eel_canvas_handle_event (EEL_CANVAS (widget), event);
+        return;
     }
 
     /* Invoke the canvas event handler and see if an item picks up the event. */
-    clicked_on_icon = GTK_WIDGET_CLASS (nautilus_canvas_container_parent_class)->button_press_event (widget, 
event);
+    clicked_on_icon = eel_canvas_handle_event (EEL_CANVAS (widget), event);
 
     if (!gtk_widget_has_focus (widget))
     {
@@ -3242,13 +3267,12 @@ button_press_event (GtkWidget      *widget,
 
     if (clicked_on_icon)
     {
-        return TRUE;
+        return;
     }
 
     clear_focus (container);
 
-    if (event->button == DRAG_BUTTON &&
-        event->type == GDK_BUTTON_PRESS)
+    if (button == DRAG_BUTTON)
     {
         /* Clear the last click icon for double click */
         container->details->double_click_icon[1] = container->details->double_click_icon[0];
@@ -3256,7 +3280,7 @@ button_press_event (GtkWidget      *widget,
     }
 
     /* Button 1 does rubber banding. */
-    if (event->button == RUBBERBAND_BUTTON)
+    if (button == RUBBERBAND_BUTTON)
     {
         if (!button_event_modifies_selection (event))
         {
@@ -3268,63 +3292,58 @@ button_press_event (GtkWidget      *widget,
             }
         }
 
-        start_rubberbanding (container, event);
-        return TRUE;
+        start_rubberbanding (container, x, y, gdk_event);
+        return;
     }
 
     /* Prevent multi-button weirdness such as bug 6181 */
     if (container->details->rubberband_info.active)
     {
-        return TRUE;
+        return;
     }
 
     /* Button 2 may be passed to the window manager. */
-    if (event->button == MIDDLE_BUTTON)
+    if (button == MIDDLE_BUTTON)
     {
         selection_changed = unselect_all (container);
         if (selection_changed)
         {
             g_signal_emit (container, signals[SELECTION_CHANGED], 0);
         }
-        g_signal_emit (widget, signals[MIDDLE_CLICK], 0, event);
-        return TRUE;
+        g_signal_emit (widget, signals[MIDDLE_CLICK], 0, gdk_event);
+        return;
     }
 
     /* Button 3 does a contextual menu. */
-    if (event->button == CONTEXTUAL_MENU_BUTTON)
+    if (button == CONTEXTUAL_MENU_BUTTON)
     {
         selection_changed = unselect_all (container);
         if (selection_changed)
         {
             g_signal_emit (container, signals[SELECTION_CHANGED], 0);
         }
-        g_signal_emit (widget, signals[CONTEXT_CLICK_BACKGROUND], 0, event);
-        return TRUE;
+        g_signal_emit (widget, signals[CONTEXT_CLICK_BACKGROUND], 0, gdk_event);
+        return;
     }
-
-    /* Otherwise, we emit a button_press message. */
-    g_signal_emit (widget,
-                   signals[BUTTON_PRESS], 0, event,
-                   &return_value);
-    return return_value;
 }
 
 static void
 nautilus_canvas_container_did_not_drag (NautilusCanvasContainer *container,
-                                        GdkEventButton          *event)
+                                        EelEvent                *event)
 {
     NautilusCanvasContainerDetails *details;
-    gboolean selection_changed;
+    GdkModifierType state;
+    guint button;
     static gint64 last_click_time = 0;
     static gint click_count = 0;
-    gint double_click_time;
-    gint64 current_time;
 
     details = container->details;
+    state = eel_event_get_state (event);
+    button = eel_event_get_button (event);
 
     if (details->icon_selected_on_button_down &&
-        ((event->state & GDK_CONTROL_MASK) != 0 ||
-         (event->state & GDK_SHIFT_MASK) == 0))
+        ((state & GDK_CONTROL_MASK) != 0 ||
+         (state & GDK_SHIFT_MASK) == 0))
     {
         if (button_event_modifies_selection (event))
         {
@@ -3335,22 +3354,26 @@ nautilus_canvas_container_did_not_drag (NautilusCanvasContainer *container,
         }
         else
         {
+            gboolean selection_changed;
+
             details->range_selection_base_icon = details->drag_icon;
             selection_changed = select_one_unselect_others
                                     (container, details->drag_icon);
 
             if (selection_changed)
             {
-                g_signal_emit (container,
-                               signals[SELECTION_CHANGED], 0);
+                g_signal_emit (container, signals[SELECTION_CHANGED], 0);
             }
         }
     }
 
     if (details->drag_icon != NULL &&
-        (details->single_click_mode ||
-         event->button == MIDDLE_BUTTON))
+        (details->single_click_mode || button == MIDDLE_BUTTON))
     {
+        gint double_click_time;
+        gint64 current_time;
+        guint32 event_time;
+
         /* Determine click count */
         g_object_get (G_OBJECT (gtk_widget_get_settings (GTK_WIDGET (container))),
                       "gtk-double-click-time", &double_click_time,
@@ -3372,9 +3395,10 @@ nautilus_canvas_container_did_not_drag (NautilusCanvasContainer *container,
          * the selection or pressing for a very long time, or double clicking.
          */
 
+        event_time = eel_event_get_time (event);
 
         if (click_count == 0 &&
-            event->time - details->button_down_time < MAX_CLICK_TIME &&
+            event_time - details->button_down_time < MAX_CLICK_TIME &&
             !button_event_modifies_selection (event))
         {
             /* It's a tricky UI issue whether this should activate
@@ -3385,9 +3409,9 @@ nautilus_canvas_container_did_not_drag (NautilusCanvasContainer *container,
              * NautilusList goes the other way because its "links" seem
              * much more link-like.
              */
-            if (event->button == MIDDLE_BUTTON)
+            if (button == MIDDLE_BUTTON)
             {
-                activate_selected_items_alternate (container, NULL);
+                activate_selected_items_alternate (container, NULL, event);
             }
             else
             {
@@ -3441,53 +3465,56 @@ clear_drag_state (NautilusCanvasContainer *container)
     container->details->drag_state = DRAG_STATE_INITIAL;
 }
 
-static gboolean
-button_release_event (GtkWidget      *widget,
-                      GdkEventButton *event)
+static void
+on_multi_press_gesture_released (GtkGestureMultiPress *gesture,
+                                 gint                  n_press,
+                                 gdouble               x,
+                                 gdouble               y,
+                                 gpointer              user_data)
 {
+    GtkWidget *widget;
     NautilusCanvasContainer *container;
     NautilusCanvasContainerDetails *details;
+    guint button;
+    GdkEventSequence *sequence;
+    const GdkEvent *gdk_event;
+    g_autoptr (EelEvent) event = NULL;
 
+    widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
     container = NAUTILUS_CANVAS_CONTAINER (widget);
     details = container->details;
+    button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+    sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
+    gdk_event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
+    event = eel_event_new_from_gdk_event (gdk_event);
 
-    if (event->button == RUBBERBAND_BUTTON && details->rubberband_info.active)
+    if (button == RUBBERBAND_BUTTON && details->rubberband_info.active)
     {
-        stop_rubberbanding (container, event);
-        return TRUE;
+        stop_rubberbanding (container, gdk_event);
+        return;
     }
 
-    if (event->button == details->drag_button)
+    if (button == details->drag_button)
     {
         details->drag_button = 0;
 
-        switch (details->drag_state)
+        if (details->drag_state == DRAG_STATE_MOVE_OR_COPY)
         {
-            case DRAG_STATE_MOVE_OR_COPY:
+            if (!details->drag_started)
             {
-                if (!details->drag_started)
-                {
-                    nautilus_canvas_container_did_not_drag (container, event);
-                }
-                else
-                {
-                    nautilus_canvas_dnd_end_drag (container);
-                    DEBUG ("Ending drag from canvas container");
-                }
+                nautilus_canvas_container_did_not_drag (container, event);
             }
-            break;
-
-            default:
+            else
             {
+                nautilus_canvas_dnd_end_drag (container);
+                DEBUG ("Ending drag from canvas container");
             }
-            break;
         }
 
         clear_drag_state (container);
-        return TRUE;
     }
 
-    return GTK_WIDGET_CLASS (nautilus_canvas_container_parent_class)->button_release_event (widget, event);
+    eel_canvas_handle_event (EEL_CANVAS (widget), event);
 }
 
 static int
@@ -3509,13 +3536,19 @@ motion_notify_event (GtkWidget      *widget,
         {
             case DRAG_STATE_MOVE_OR_COPY:
             {
+                gdouble x;
+                gdouble y;
+
                 if (details->drag_started)
                 {
                     break;
                 }
 
-                eel_canvas_window_to_world
-                    (EEL_CANVAS (container), event->x, event->y, &world_x, &world_y);
+                gdk_event_get_coords ((GdkEvent *) event, &x, &y);
+
+                eel_canvas_window_to_world (EEL_CANVAS (container),
+                                            x, y,
+                                            &world_x, &world_y);
 
                 if (gtk_drag_check_threshold (widget,
                                               details->drag_x,
@@ -3592,11 +3625,16 @@ key_press_event (GtkWidget   *widget,
 {
     NautilusCanvasContainer *container;
     gboolean handled;
+    guint keyval;
+    GdkModifierType state;
 
     container = NAUTILUS_CANVAS_CONTAINER (widget);
     handled = FALSE;
 
-    switch (event->keyval)
+    gdk_event_get_keyval ((GdkEvent *) event, &keyval);
+    gdk_event_get_state ((GdkEvent *) event, &state);
+
+    switch (keyval)
     {
         case GDK_KEY_Home:
         case GDK_KEY_KP_Home:
@@ -3618,7 +3656,7 @@ key_press_event (GtkWidget   *widget,
         case GDK_KEY_KP_Left:
         {
             /* Don't eat Alt-Left, as that is used for history browsing */
-            if ((event->state & GDK_MOD1_MASK) == 0)
+            if ((state & GDK_MOD1_MASK) == 0)
             {
                 keyboard_left (container, event);
                 handled = TRUE;
@@ -3630,7 +3668,7 @@ key_press_event (GtkWidget   *widget,
         case GDK_KEY_KP_Up:
         {
             /* Don't eat Alt-Up, as that is used for alt-shift-Up */
-            if ((event->state & GDK_MOD1_MASK) == 0)
+            if ((state & GDK_MOD1_MASK) == 0)
             {
                 keyboard_up (container, event);
                 handled = TRUE;
@@ -3642,7 +3680,7 @@ key_press_event (GtkWidget   *widget,
         case GDK_KEY_KP_Right:
         {
             /* Don't eat Alt-Right, as that is used for history browsing */
-            if ((event->state & GDK_MOD1_MASK) == 0)
+            if ((state & GDK_MOD1_MASK) == 0)
             {
                 keyboard_right (container, event);
                 handled = TRUE;
@@ -3654,7 +3692,7 @@ key_press_event (GtkWidget   *widget,
         case GDK_KEY_KP_Down:
         {
             /* Don't eat Alt-Down, as that is used for Open */
-            if ((event->state & GDK_MOD1_MASK) == 0)
+            if ((state & GDK_MOD1_MASK) == 0)
             {
                 keyboard_down (container, event);
                 handled = TRUE;
@@ -3675,7 +3713,7 @@ key_press_event (GtkWidget   *widget,
              * background popup even if something is selected.
              * The other cases are handled by the "popup-menu" GtkWidget signal.
              */
-            if (event->state & GDK_CONTROL_MASK)
+            if (state & GDK_CONTROL_MASK)
             {
                 handled = handle_popups (container, (GdkEvent *) event,
                                          "context_click_background");
@@ -3686,7 +3724,7 @@ key_press_event (GtkWidget   *widget,
         case GDK_KEY_v:
         {
             /* Eat Control + v to not enable type ahead */
-            if ((event->state & GDK_CONTROL_MASK) != 0)
+            if ((state & GDK_CONTROL_MASK) != 0)
             {
                 handled = TRUE;
             }
@@ -3780,16 +3818,6 @@ nautilus_canvas_container_class_init (NautilusCanvasContainerClass *class)
                         NULL, NULL,
                         g_cclosure_marshal_VOID__VOID,
                         G_TYPE_NONE, 0);
-    signals[BUTTON_PRESS]
-        = g_signal_new ("button-press",
-                        G_TYPE_FROM_CLASS (class),
-                        G_SIGNAL_RUN_LAST,
-                        G_STRUCT_OFFSET (NautilusCanvasContainerClass,
-                                         button_press),
-                        NULL, NULL,
-                        g_cclosure_marshal_generic,
-                        G_TYPE_BOOLEAN, 1,
-                        GDK_TYPE_EVENT);
     signals[ACTIVATE]
         = g_signal_new ("activate",
                         G_TYPE_FROM_CLASS (class),
@@ -3807,9 +3835,10 @@ nautilus_canvas_container_class_init (NautilusCanvasContainerClass *class)
                         G_STRUCT_OFFSET (NautilusCanvasContainerClass,
                                          activate_alternate),
                         NULL, NULL,
-                        g_cclosure_marshal_VOID__POINTER,
-                        G_TYPE_NONE, 1,
-                        G_TYPE_POINTER);
+                        g_cclosure_marshal_generic,
+                        G_TYPE_NONE, 2,
+                        G_TYPE_POINTER,
+                        EEL_TYPE_EVENT);
     signals[ACTIVATE_PREVIEWER]
         = g_signal_new ("activate-previewer",
                         G_TYPE_FROM_CLASS (class),
@@ -4029,8 +4058,6 @@ nautilus_canvas_container_class_init (NautilusCanvasContainerClass *class)
     widget_class->get_preferred_height = get_prefered_height;
     widget_class->realize = realize;
     widget_class->unrealize = unrealize;
-    widget_class->button_press_event = button_press_event;
-    widget_class->button_release_event = button_release_event;
     widget_class->motion_notify_event = motion_notify_event;
     widget_class->key_press_event = key_press_event;
     widget_class->style_updated = style_updated;
@@ -4184,6 +4211,20 @@ nautilus_canvas_container_init (NautilusCanvasContainer *container)
 
         setup_prefs = TRUE;
     }
+
+    details->multi_press_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (container));
+
+#if 0
+    gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (details->multi_press_gesture),
+                                                GTK_PHASE_CAPTURE);
+#endif
+    gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (details->multi_press_gesture),
+                                   0);
+
+    g_signal_connect (details->multi_press_gesture, "pressed",
+                      G_CALLBACK (on_multi_press_gesture_pressed), NULL);
+    g_signal_connect (details->multi_press_gesture, "released",
+                      G_CALLBACK (on_multi_press_gesture_released), NULL);
 }
 
 typedef struct
@@ -4195,11 +4236,14 @@ typedef struct
 static gboolean
 handle_canvas_double_click (NautilusCanvasContainer *container,
                             NautilusCanvasIcon      *icon,
-                            GdkEventButton          *event)
+                            EelEvent                *event)
 {
     NautilusCanvasContainerDetails *details;
+    guint button;
+
+    button = eel_event_get_button (event);
 
-    if (event->button != DRAG_BUTTON)
+    if (button != DRAG_BUTTON)
     {
         return FALSE;
     }
@@ -4232,33 +4276,37 @@ handle_canvas_double_click (NautilusCanvasContainer *container,
 static gboolean
 handle_canvas_button_press (NautilusCanvasContainer *container,
                             NautilusCanvasIcon      *icon,
-                            GdkEventButton          *event)
+                            EelEvent                *event)
 {
     NautilusCanvasContainerDetails *details;
+    GdkEventType event_type;
+    guint button;
+    GdkModifierType state;
 
     details = container->details;
-
-    if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS)
+    event_type = eel_event_get_event_type (event);
+    if (event_type == GDK_2BUTTON_PRESS || event_type == GDK_3BUTTON_PRESS)
     {
         return TRUE;
     }
+    button = eel_event_get_button (event);
+    state = eel_event_get_state (event);
 
-    if (event->button != DRAG_BUTTON
-        && event->button != CONTEXTUAL_MENU_BUTTON
-        && event->button != DRAG_MENU_BUTTON)
+    if (button != DRAG_BUTTON
+        && button != CONTEXTUAL_MENU_BUTTON
+        && button != DRAG_MENU_BUTTON)
     {
         return TRUE;
     }
 
-    if ((event->button == DRAG_BUTTON) &&
-        event->type == GDK_BUTTON_PRESS)
+    if (button == DRAG_BUTTON && event_type == GDK_BUTTON_PRESS)
     {
         /* The next double click has to be on this icon */
         details->double_click_icon[1] = details->double_click_icon[0];
         details->double_click_icon[0] = icon;
 
         details->double_click_button[1] = details->double_click_button[0];
-        details->double_click_button[0] = event->button;
+        details->double_click_button[0] = button;
     }
 
     if (handle_canvas_double_click (container, icon, event))
@@ -4269,13 +4317,13 @@ handle_canvas_button_press (NautilusCanvasContainer *container,
         return TRUE;
     }
 
-    if (event->button == DRAG_BUTTON
-        || event->button == DRAG_MENU_BUTTON)
+    if (button == DRAG_BUTTON || button == DRAG_MENU_BUTTON)
     {
-        details->drag_button = event->button;
+        details->drag_button = button;
         details->drag_icon = icon;
-        details->drag_x = event->x;
-        details->drag_y = event->y;
+
+        eel_event_get_coords (event, &details->drag_x, &details->drag_y);
+
         details->drag_state = DRAG_STATE_MOVE_OR_COPY;
         details->drag_started = FALSE;
     }
@@ -4285,8 +4333,8 @@ handle_canvas_button_press (NautilusCanvasContainer *container,
      */
     details->icon_selected_on_button_down = icon->is_selected;
 
-    if ((event->button == DRAG_BUTTON || event->button == MIDDLE_BUTTON) &&
-        (event->state & GDK_SHIFT_MASK) != 0)
+    if ((button == DRAG_BUTTON || button == MIDDLE_BUTTON) &&
+        (state & GDK_SHIFT_MASK) != 0)
     {
         NautilusCanvasIcon *start_icon;
 
@@ -4299,7 +4347,7 @@ handle_canvas_button_press (NautilusCanvasContainer *container,
             details->range_selection_base_icon = icon;
         }
         if (select_range (container, start_icon, icon,
-                          (event->state & GDK_CONTROL_MASK) == 0))
+                          (state & GDK_CONTROL_MASK) == 0))
         {
             g_signal_emit (container,
                            signals[SELECTION_CHANGED], 0);
@@ -4324,13 +4372,14 @@ handle_canvas_button_press (NautilusCanvasContainer *container,
         }
     }
 
-    if (event->button == CONTEXTUAL_MENU_BUTTON)
+    if (button == CONTEXTUAL_MENU_BUTTON)
     {
         clear_drag_state (container);
 
         g_signal_emit (container,
                        signals[CONTEXT_CLICK_SELECTION], 0,
-                       event);
+                       /* Handlers expect a GdkEvent, not EelEvent. */
+                       gtk_get_current_event ());
     }
 
 
@@ -4339,65 +4388,55 @@ handle_canvas_button_press (NautilusCanvasContainer *container,
 
 static int
 item_event_callback (EelCanvasItem *item,
-                     GdkEvent      *event,
+                     EelEvent      *event,
                      gpointer       data)
 {
     NautilusCanvasContainer *container;
     NautilusCanvasIcon *icon;
-    GdkEventButton *event_button;
+    GdkEventType event_type;
 
     container = NAUTILUS_CANVAS_CONTAINER (data);
-
     icon = NAUTILUS_CANVAS_ITEM (item)->user_data;
+
     g_assert (icon != NULL);
 
-    event_button = &event->button;
+    event_type = eel_event_get_event_type (event);
+    if (event_type == GDK_MOTION_NOTIFY)
+    {
+        return GDK_EVENT_PROPAGATE;
+    }
+    if (event_type == GDK_BUTTON_PRESS)
+    {
+        container->details->double_clicked = FALSE;
 
-    switch (event->type)
+        return handle_canvas_button_press (container, icon, event);
+    }
+    if (event_type == GDK_BUTTON_RELEASE)
     {
-        case GDK_MOTION_NOTIFY:
-        {
-            return FALSE;
-        }
+        guint button;
 
-        case GDK_BUTTON_PRESS:
+        button = eel_event_get_button (event);
+        if (button == DRAG_BUTTON && container->details->double_clicked)
         {
-            container->details->double_clicked = FALSE;
-            if (handle_canvas_button_press (container, icon, event_button))
+            GdkModifierType state;
+
+            state = eel_event_get_state (event);
+
+            if (!button_event_modifies_selection (event))
             {
-                /* Stop the event from being passed along further. Returning
-                 * TRUE ain't enough.
-                 */
-                return TRUE;
+                activate_selected_items (container);
             }
-            return FALSE;
-        }
-
-        case GDK_BUTTON_RELEASE:
-        {
-            if (event_button->button == DRAG_BUTTON
-                && container->details->double_clicked)
+            else if ((state & GDK_CONTROL_MASK) == 0 &&
+                     (state & GDK_SHIFT_MASK) != 0)
             {
-                if (!button_event_modifies_selection (event_button))
-                {
-                    activate_selected_items (container);
-                }
-                else if ((event_button->state & GDK_CONTROL_MASK) == 0 &&
-                         (event_button->state & GDK_SHIFT_MASK) != 0)
-                {
-                    activate_selected_items_alternate (container, icon);
-                }
+                activate_selected_items_alternate (container, icon, event);
             }
-            /* fall through */
         }
-
-        default:
-        {
-            container->details->double_clicked = FALSE;
-            return FALSE;
-        }
-        break;
     }
+
+    container->details->double_clicked = FALSE;
+
+    return GDK_EVENT_PROPAGATE;
 }
 
 GtkWidget *
@@ -4752,9 +4791,10 @@ preview_selected_items (NautilusCanvasContainer *container)
 
 static void
 activate_selected_items_alternate (NautilusCanvasContainer *container,
-                                   NautilusCanvasIcon      *icon)
+                                   NautilusCanvasIcon      *icon,
+                                   EelEvent                *event)
 {
-    GList *selection;
+    g_autoptr (GList) selection = NULL;
 
     g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container));
 
@@ -4766,13 +4806,14 @@ activate_selected_items_alternate (NautilusCanvasContainer *container,
     {
         selection = nautilus_canvas_container_get_selection (container);
     }
+
     if (selection != NULL)
     {
         g_signal_emit (container,
                        signals[ACTIVATE_ALTERNATE], 0,
-                       selection);
+                       selection,
+                       event);
     }
-    g_list_free (selection);
 }
 
 static NautilusIconInfo *
diff --git a/src/nautilus-canvas-item.c b/src/nautilus-canvas-item.c
index 42181e8c4..94f505b1c 100644
--- a/src/nautilus-canvas-item.c
+++ b/src/nautilus-canvas-item.c
@@ -1455,68 +1455,91 @@ get_label_layout (PangoLayout        **layout_cache,
 
 /* handle events */
 
-static int
-nautilus_canvas_item_event (EelCanvasItem *item,
-                            GdkEvent      *event)
+static gboolean
+nautilus_canvas_item_enter_notify_event (EelCanvasItem *item,
+                                         EelEvent      *event)
 {
     NautilusCanvasItem *canvas_item;
-    GdkCursor *cursor;
-    GdkWindow *cursor_window;
 
     canvas_item = NAUTILUS_CANVAS_ITEM (item);
-    cursor_window = ((GdkEventAny *) event)->window;
 
-    switch (event->type)
+    if (!canvas_item->details->is_prelit)
     {
-        case GDK_ENTER_NOTIFY:
+        canvas_item->details->is_prelit = TRUE;
+        nautilus_canvas_item_invalidate_label_size (canvas_item);
+        eel_canvas_item_request_update (item);
+        eel_canvas_item_send_behind (item,
+                                     NAUTILUS_CANVAS_CONTAINER 
(item->canvas)->details->rubberband_info.selection_rectangle);
+
+        /* show a hand cursor */
+        if (in_single_click_mode ())
         {
-            if (!canvas_item->details->is_prelit)
-            {
-                canvas_item->details->is_prelit = TRUE;
-                nautilus_canvas_item_invalidate_label_size (canvas_item);
-                eel_canvas_item_request_update (item);
-                eel_canvas_item_send_behind (item,
-                                             NAUTILUS_CANVAS_CONTAINER 
(item->canvas)->details->rubberband_info.selection_rectangle);
-
-                /* show a hand cursor */
-                if (in_single_click_mode ())
-                {
-                    cursor = gdk_cursor_new_for_display (gdk_display_get_default (),
-                                                         GDK_HAND2);
-                    gdk_window_set_cursor (cursor_window, cursor);
-                    g_object_unref (cursor);
+            GdkDisplay *display;
+            g_autoptr (GdkCursor) cursor = NULL;
+            GdkWindow *window;
 
-                    canvas_item->details->cursor_window = g_object_ref (cursor_window);
-                }
-            }
-            return TRUE;
-        }
+            display = gdk_display_get_default ();
+            cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
+            window = eel_event_get_window (event);
 
-        case GDK_LEAVE_NOTIFY:
-        {
-            if (canvas_item->details->is_prelit
-                || canvas_item->details->is_highlighted_for_drop)
-            {
-                /* When leaving, turn of the prelight state and the
-                 * higlighted for drop. The latter gets turned on
-                 * by the drag&drop motion callback.
-                 */
-                canvas_item->details->is_prelit = FALSE;
-                canvas_item->details->is_highlighted_for_drop = FALSE;
-                nautilus_canvas_item_invalidate_label_size (canvas_item);
-                eel_canvas_item_request_update (item);
-
-                /* show default cursor */
-                gdk_window_set_cursor (cursor_window, NULL);
-                g_clear_object (&canvas_item->details->cursor_window);
-            }
-            return TRUE;
+            gdk_window_set_cursor (window, cursor);
+
+            canvas_item->details->cursor_window = g_object_ref (window);
         }
+    }
 
-        default:
-            /* Don't eat up other events; canvas container might use them. */
-            return FALSE;
+    return GDK_EVENT_STOP;
+}
+
+static gboolean
+nautilus_canvas_item_leave_notify_event (EelCanvasItem *item,
+                                         EelEvent      *event)
+{
+    NautilusCanvasItem *canvas_item;
+
+    canvas_item = NAUTILUS_CANVAS_ITEM (item);
+
+    if (canvas_item->details->is_prelit
+        || canvas_item->details->is_highlighted_for_drop)
+    {
+        GdkWindow *window;
+
+        window = eel_event_get_window (event);
+
+        /* When leaving, turn of the prelight state and the
+         * higlighted for drop. The latter gets turned on
+         * by the drag&drop motion callback.
+         */
+        canvas_item->details->is_prelit = FALSE;
+        canvas_item->details->is_highlighted_for_drop = FALSE;
+        nautilus_canvas_item_invalidate_label_size (canvas_item);
+        eel_canvas_item_request_update (item);
+
+        /* show default cursor */
+        gdk_window_set_cursor (window, NULL);
+        g_clear_object (&canvas_item->details->cursor_window);
     }
+
+    return GDK_EVENT_STOP;
+}
+
+static gboolean
+nautilus_canvas_item_event (EelCanvasItem *item,
+                            EelEvent      *event)
+{
+    GdkEventType event_type;
+
+    event_type = eel_event_get_event_type (event);
+    if (event_type == GDK_ENTER_NOTIFY)
+    {
+        return nautilus_canvas_item_enter_notify_event (item, event);
+    }
+    if (event_type == GDK_LEAVE_NOTIFY)
+    {
+        return nautilus_canvas_item_leave_notify_event (item, event);
+    }
+
+    return GDK_EVENT_PROPAGATE;
 }
 
 static gboolean
diff --git a/src/nautilus-canvas-private.h b/src/nautilus-canvas-private.h
index e60e86299..2e19e4e27 100644
--- a/src/nautilus-canvas-private.h
+++ b/src/nautilus-canvas-private.h
@@ -151,7 +151,8 @@ struct NautilusCanvasContainerDetails {
        /* Drag state. Valid only if drag_button is non-zero. */
        guint drag_button;
        NautilusCanvasIcon *drag_icon;
-       int drag_x, drag_y;
+       gdouble drag_x;
+    gdouble drag_y;
        DragState drag_state;
        gboolean drag_started;
 
@@ -202,6 +203,8 @@ struct NautilusCanvasContainerDetails {
        eel_boolean_bit is_populating_container : 1;
        eel_boolean_bit needs_resort : 1;
        eel_boolean_bit selection_needs_resort : 1;
+
+    GtkGesture *multi_press_gesture;
 };
 
 /* Private functions shared by mutiple files. */
diff --git a/src/nautilus-canvas-view.c b/src/nautilus-canvas-view.c
index 6674433d2..11e2551fb 100644
--- a/src/nautilus-canvas-view.c
+++ b/src/nautilus-canvas-view.c
@@ -1054,36 +1054,35 @@ canvas_container_activate_previewer_callback (NautilusCanvasContainer *container
 static void
 canvas_container_activate_alternate_callback (NautilusCanvasContainer *container,
                                               GList                   *file_list,
+                                              EelEvent                *event,
                                               NautilusCanvasView      *canvas_view)
 {
-    GdkEvent *event;
-    GdkEventButton *button_event;
-    GdkEventKey *key_event;
-    gboolean open_in_tab, open_in_window;
+    GdkEventType event_type;
+    GdkModifierType state;
+    gboolean open_in_tab;
+    gboolean open_in_window;
     NautilusWindowOpenFlags flags;
 
     g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
     g_assert (container == get_canvas_container (canvas_view));
 
-    flags = 0;
-    event = gtk_get_current_event ();
+    event_type = eel_event_get_event_type (event);
+    state = eel_event_get_state (event);
     open_in_tab = FALSE;
     open_in_window = FALSE;
+    flags = 0;
 
-    if (event->type == GDK_BUTTON_PRESS ||
-        event->type == GDK_BUTTON_RELEASE ||
-        event->type == GDK_2BUTTON_PRESS ||
-        event->type == GDK_3BUTTON_PRESS)
+    if (event_type == GDK_BUTTON_PRESS ||
+        event_type == GDK_BUTTON_RELEASE ||
+        event_type == GDK_2BUTTON_PRESS ||
+        event_type == GDK_3BUTTON_PRESS)
     {
-        button_event = (GdkEventButton *) event;
-        open_in_window = ((button_event->state & GDK_SHIFT_MASK) != 0);
+        open_in_window = (state & GDK_SHIFT_MASK) != 0;
         open_in_tab = !open_in_window;
     }
-    else if (event->type == GDK_KEY_PRESS ||
-             event->type == GDK_KEY_RELEASE)
+    else if (event_type == GDK_KEY_PRESS || event_type == GDK_KEY_RELEASE)
     {
-        key_event = (GdkEventKey *) event;
-        open_in_tab = ((key_event->state & GDK_SHIFT_MASK) != 0);
+        open_in_tab = (state & GDK_SHIFT_MASK) != 0;
     }
 
     if (open_in_tab)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]