Merge master into gtk3.
[pspp] / src / ui / gui / pspp-sheet-view.c
index ae5a179b5c87b83c5546548fa98e24ecb912caf6..ccdbd10e9919b5d61cbc059bd6d4c7284c66e277 100644 (file)
@@ -40,6 +40,7 @@
 #include <gtk/gtk.h>
 #include <gdk/gdk.h>
 #include <gdk/gdkkeysyms.h>
+#include <gdk/gdkkeysyms-compat.h>
 #include <string.h>
 
 #include "ui/gui/psppire-marshal.h"
@@ -134,6 +135,8 @@ enum {
   PROP_MODEL,
   PROP_HADJUSTMENT,
   PROP_VADJUSTMENT,
+  PROP_HSCROLL_POLICY,
+  PROP_VSCROLL_POLICY,
   PROP_HEADERS_VISIBLE,
   PROP_HEADERS_CLICKABLE,
   PROP_REORDERABLE,
@@ -170,8 +173,8 @@ static void     pspp_sheet_view_size_request         (GtkWidget        *widget,
                                                    GtkRequisition   *requisition);
 static void     pspp_sheet_view_size_allocate        (GtkWidget        *widget,
                                                    GtkAllocation    *allocation);
-static gboolean pspp_sheet_view_expose               (GtkWidget        *widget,
-                                                   GdkEventExpose   *event);
+static gboolean pspp_sheet_view_draw               (GtkWidget        *widget,
+                                                   cairo_t *cr);
 static gboolean pspp_sheet_view_key_press            (GtkWidget        *widget,
                                                    GdkEventKey      *event);
 static gboolean pspp_sheet_view_key_release          (GtkWidget        *widget,
@@ -294,6 +297,12 @@ static void     pspp_sheet_view_top_row_to_dy (PsppSheetView *tree_view);
 static void     invalidate_empty_focus      (PsppSheetView *tree_view);
 
 /* Internal functions */
+static GtkAdjustment *pspp_sheet_view_do_get_hadjustment (PsppSheetView *);
+static GtkAdjustment *pspp_sheet_view_do_get_vadjustment (PsppSheetView *);
+static void pspp_sheet_view_do_set_hadjustment (PsppSheetView   *tree_view,
+                                              GtkAdjustment *adjustment);
+static void pspp_sheet_view_do_set_vadjustment (PsppSheetView   *tree_view,
+                                              GtkAdjustment *adjustment);
 static void     pspp_sheet_view_add_move_binding               (GtkBindingSet      *binding_set,
                                                              guint               keyval,
                                                              guint               modmask,
@@ -450,7 +459,32 @@ static GtkBindingSet *edit_bindings;
 
 G_DEFINE_TYPE_WITH_CODE (PsppSheetView, pspp_sheet_view, GTK_TYPE_CONTAINER,
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
-                                               pspp_sheet_view_buildable_init))
+                                               pspp_sheet_view_buildable_init)
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
+
+static void
+pspp_sheet_view_get_preferred_width (GtkWidget *widget,
+                               gint      *minimal_width,
+                               gint      *natural_width)
+{
+  GtkRequisition requisition;
+
+  pspp_sheet_view_size_request (widget, &requisition);
+
+  *minimal_width = *natural_width = requisition.width;
+}
+
+static void
+pspp_sheet_view_get_preferred_height (GtkWidget *widget,
+                                gint      *minimal_height,
+                                gint      *natural_height)
+{
+  GtkRequisition requisition;
+
+  pspp_sheet_view_size_request (widget, &requisition);
+
+  *minimal_height = *natural_height = requisition.height;
+}
 
 static void
 pspp_sheet_view_class_init (PsppSheetViewClass *class)
@@ -480,14 +514,15 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class)
   widget_class->map = pspp_sheet_view_map;
   widget_class->realize = pspp_sheet_view_realize;
   widget_class->unrealize = pspp_sheet_view_unrealize;
-  widget_class->size_request = pspp_sheet_view_size_request;
+  widget_class->get_preferred_width = pspp_sheet_view_get_preferred_width;
+  widget_class->get_preferred_height = pspp_sheet_view_get_preferred_height;
   widget_class->size_allocate = pspp_sheet_view_size_allocate;
   widget_class->button_press_event = pspp_sheet_view_button_press;
   widget_class->button_release_event = pspp_sheet_view_button_release;
   widget_class->grab_broken_event = pspp_sheet_view_grab_broken;
   /*widget_class->configure_event = pspp_sheet_view_configure;*/
   widget_class->motion_notify_event = pspp_sheet_view_motion;
-  widget_class->expose_event = pspp_sheet_view_expose;
+  widget_class->draw = pspp_sheet_view_draw;
   widget_class->key_press_event = pspp_sheet_view_key_press;
   widget_class->key_release_event = pspp_sheet_view_key_release;
   widget_class->enter_notify_event = pspp_sheet_view_enter_notify;
@@ -530,21 +565,10 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class)
                                                        GTK_TYPE_TREE_MODEL,
                                                        GTK_PARAM_READWRITE));
 
-  g_object_class_install_property (o_class,
-                                   PROP_HADJUSTMENT,
-                                   g_param_spec_object ("hadjustment",
-                                                       P_("Horizontal Adjustment"),
-                                                        P_("Horizontal Adjustment for the widget"),
-                                                        GTK_TYPE_ADJUSTMENT,
-                                                        GTK_PARAM_READWRITE));
-
-  g_object_class_install_property (o_class,
-                                   PROP_VADJUSTMENT,
-                                   g_param_spec_object ("vadjustment",
-                                                       P_("Vertical Adjustment"),
-                                                        P_("Vertical Adjustment for the widget"),
-                                                        GTK_TYPE_ADJUSTMENT,
-                                                        GTK_PARAM_READWRITE));
+  g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
+  g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
+  g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
+  g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
 
   g_object_class_install_property (o_class,
                                    PROP_HEADERS_VISIBLE,
@@ -753,6 +777,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class)
                                                                GTK_PARAM_READABLE));
 
   /* Signals */
+#if GTK3_TRANSITION
   /**
    * PsppSheetView::set-scroll-adjustments
    * @horizontal: the horizontal #GtkAdjustment
@@ -772,6 +797,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class)
                  G_TYPE_NONE, 2,
                  GTK_TYPE_ADJUSTMENT,
                  GTK_TYPE_ADJUSTMENT);
+#endif
 
   /**
    * PsppSheetView::row-activated:
@@ -1093,6 +1119,9 @@ pspp_sheet_view_init (PsppSheetView *tree_view)
   tree_view->priv->button_style = NULL;
 
   tree_view->dispose_has_run = FALSE;
+
+  pspp_sheet_view_do_set_vadjustment (tree_view, NULL);
+  pspp_sheet_view_do_set_hadjustment (tree_view, NULL);
 }
 
 \f
@@ -1116,12 +1145,20 @@ pspp_sheet_view_set_property (GObject         *object,
       pspp_sheet_view_set_model (tree_view, g_value_get_object (value));
       break;
     case PROP_HADJUSTMENT:
-      pspp_sheet_view_set_hadjustment (tree_view, g_value_get_object (value));
+      pspp_sheet_view_do_set_hadjustment (tree_view, g_value_get_object (value));
       break;
     case PROP_VADJUSTMENT:
-      pspp_sheet_view_set_vadjustment (tree_view, g_value_get_object (value));
+      pspp_sheet_view_do_set_vadjustment (tree_view, g_value_get_object (value));
       break;
-    case PROP_HEADERS_VISIBLE:
+    case PROP_HSCROLL_POLICY:
+      tree_view->priv->hscroll_policy = g_value_get_enum (value);
+      gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+      break;
+    case PROP_VSCROLL_POLICY:
+      tree_view->priv->vscroll_policy = g_value_get_enum (value);
+      gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+      break;
+     case PROP_HEADERS_VISIBLE:
       pspp_sheet_view_set_headers_visible (tree_view, g_value_get_boolean (value));
       break;
     case PROP_HEADERS_CLICKABLE:
@@ -1204,6 +1241,12 @@ pspp_sheet_view_get_property (GObject    *object,
     case PROP_VADJUSTMENT:
       g_value_set_object (value, tree_view->priv->vadjustment);
       break;
+    case PROP_HSCROLL_POLICY:
+      g_value_set_enum (value, tree_view->priv->hscroll_policy);
+      break;
+    case PROP_VSCROLL_POLICY:
+      g_value_set_enum (value, tree_view->priv->vscroll_policy);
+      break;
     case PROP_HEADERS_VISIBLE:
       g_value_set_boolean (value, pspp_sheet_view_get_headers_visible (tree_view));
       break;
@@ -1476,10 +1519,9 @@ pspp_sheet_view_realize (GtkWidget *widget)
   attributes.height = allocation.height;
   attributes.wclass = GDK_INPUT_OUTPUT;
   attributes.visual = gtk_widget_get_visual (widget);
-  attributes.colormap = gtk_widget_get_colormap (widget);
   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
 
-  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
 
   gtk_widget_set_window (widget,
                         gdk_window_new (gtk_widget_get_parent_window (widget),
@@ -1524,7 +1566,6 @@ pspp_sheet_view_realize (GtkWidget *widget)
   /* Add them all up. */
   gtk_widget_set_style (widget,
                       gtk_style_attach (gtk_widget_get_style (widget), gtk_widget_get_window (widget)));
-  gdk_window_set_back_pixmap (gtk_widget_get_window (widget), NULL, FALSE);
   gdk_window_set_background (tree_view->priv->bin_window, &gtk_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
   gtk_style_set_background (gtk_widget_get_style (widget), tree_view->priv->header_window, GTK_STATE_NORMAL);
 
@@ -3524,14 +3565,16 @@ pspp_sheet_view_update_rubber_band_selection (PsppSheetView *tree_view)
   tree_view->priv->rubber_band_end_node = end_node;
 }
 
+#define GDK_RECTANGLE_PTR(X) ((GdkRectangle *)(X))
+
 static void
 pspp_sheet_view_update_rubber_band (PsppSheetView *tree_view)
 {
   gint x, y;
-  GdkRectangle old_area;
-  GdkRectangle new_area;
-  GdkRectangle common;
-  GdkRegion *invalid_region;
+  cairo_rectangle_int_t old_area;
+  cairo_rectangle_int_t new_area;
+  cairo_rectangle_int_t common;
+  cairo_region_t *invalid_region;
   PsppSheetViewColumn *column;
 
   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
@@ -3549,13 +3592,14 @@ pspp_sheet_view_update_rubber_band (PsppSheetView *tree_view)
   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
 
-  invalid_region = gdk_region_rectangle (&old_area);
-  gdk_region_union_with_rect (invalid_region, &new_area);
+  invalid_region = cairo_region_create_rectangle (&old_area);
+  cairo_region_union_rectangle (invalid_region, &new_area);
 
-  gdk_rectangle_intersect (&old_area, &new_area, &common);
+  gdk_rectangle_intersect (GDK_RECTANGLE_PTR (&old_area), 
+                          GDK_RECTANGLE_PTR (&new_area), GDK_RECTANGLE_PTR (&common));
   if (common.width > 2 && common.height > 2)
     {
-      GdkRegion *common_region;
+      cairo_region_t *common_region;
 
       /* make sure the border is invalidated */
       common.x += 1;
@@ -3563,15 +3607,26 @@ pspp_sheet_view_update_rubber_band (PsppSheetView *tree_view)
       common.width -= 2;
       common.height -= 2;
 
-      common_region = gdk_region_rectangle (&common);
+      common_region = cairo_region_create_rectangle (&common);
 
-      gdk_region_subtract (invalid_region, common_region);
-      gdk_region_destroy (common_region);
+      cairo_region_subtract (invalid_region, common_region);
+      cairo_region_destroy (common_region);
     }
 
-  gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
+#if GTK_MAJOR_VERSION == 3
+  gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);  
+#else
+  {
+    cairo_rectangle_int_t extents;
+    GdkRegion *ereg;
+    cairo_region_get_extents (invalid_region, &extents);
+    ereg = gdk_region_rectangle (GDK_RECTANGLE_PTR (&extents));
+    gdk_window_invalidate_region (tree_view->priv->bin_window, ereg, TRUE);
+    gdk_region_destroy (ereg);
+  }
+#endif
 
-  gdk_region_destroy (invalid_region);
+  cairo_region_destroy (invalid_region);
 
   tree_view->priv->rubber_band_x = x;
   tree_view->priv->rubber_band_y = y;
@@ -3587,6 +3642,7 @@ pspp_sheet_view_update_rubber_band (PsppSheetView *tree_view)
   pspp_sheet_view_update_rubber_band_selection (tree_view);
 }
 
+#if GTK3_TRANSITION
 static void
 pspp_sheet_view_paint_rubber_band (PsppSheetView  *tree_view,
                                GdkRectangle *area)
@@ -3631,6 +3687,8 @@ pspp_sheet_view_paint_rubber_band (PsppSheetView  *tree_view,
 
   cairo_destroy (cr);
 }
+#endif
+
 
 static gboolean
 pspp_sheet_view_motion_bin_window (GtkWidget      *widget,
@@ -3732,10 +3790,11 @@ invalidate_empty_focus (PsppSheetView *tree_view)
  * is empty.
  */
 static void
-draw_empty_focus (PsppSheetView *tree_view, GdkRectangle *clip_area)
+draw_empty_focus (PsppSheetView *tree_view)
 {
   GtkWidget *widget = GTK_WIDGET (tree_view);
   gint w, h;
+  cairo_t *cr = gdk_cairo_create (tree_view->priv->bin_window);
 
   if (!gtk_widget_has_focus (widget))
     return;
@@ -3748,20 +3807,20 @@ draw_empty_focus (PsppSheetView *tree_view, GdkRectangle *clip_area)
 
   if (w > 0 && h > 0)
     gtk_paint_focus (gtk_widget_get_style (widget),
-                    tree_view->priv->bin_window,
+                    cr,
                     gtk_widget_get_state (widget),
-                    clip_area,
                     widget,
                     NULL,
                     1, 1, w, h);
+  cairo_destroy (cr);
 }
 
 static void
 pspp_sheet_view_draw_vertical_grid_lines (PsppSheetView    *tree_view,
-                              GdkEventExpose *event,
-                                 gint            n_visible_columns,
-                                 gint min_y,
-                                 gint max_y)
+                                         cairo_t *cr,
+                                         gint n_visible_columns,
+                                         gint min_y,
+                                         gint max_y)
 {
   GList *list = tree_view->priv->columns;
   gint i = 0;
@@ -3775,36 +3834,25 @@ pspp_sheet_view_draw_vertical_grid_lines (PsppSheetView    *tree_view,
   for (list = tree_view->priv->columns; list; list = list->next, i++)
     {
       PsppSheetViewColumn *column = list->data;
-
-      /* We don't want a line for the last column */
-      if (i == n_visible_columns - 1)
-       break;
+      gint x;
 
       if (! column->visible)
        continue;
 
       current_x += column->width;
 
-      if (current_x - 1 >= event->area.x
-          && current_x - 1 < event->area.x + event->area.width)
-       {
-#if GTK3_TRANSITION
-         gdk_draw_line (event->window,
-                        tree_view->priv->grid_line_gc[GTK_WIDGET(tree_view)->state],
-                        current_x - 1, min_y,
-                        current_x - 1, max_y - min_y);
-#else
-
-         cairo_t *cr = gdk_cairo_create (event->window);       
-         cairo_set_line_width (cr, 1.0);
-         cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
-         cairo_move_to (cr, current_x - 0.5, min_y);
-         cairo_line_to (cr, current_x - 0.5 , max_y - min_y);
+      /* Generally the grid lines should fit within the column, but for the
+         last visible column we put it just past the end of the column.
+         (Otherwise horizontal grid lines sometimes stick out by one pixel.) */
+      x = current_x;
+      if (i != n_visible_columns - 1)
+        x--;
 
-         cairo_stroke (cr);
-         cairo_destroy (cr);
-#endif
-       }
+      cairo_set_line_width (cr, 1.0);
+      cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
+      cairo_move_to (cr, x + 0.5, min_y);
+      cairo_line_to (cr, x + 0.5, max_y - min_y);
+      cairo_stroke (cr);
     }
 }
 
@@ -3816,7 +3864,7 @@ pspp_sheet_view_draw_vertical_grid_lines (PsppSheetView    *tree_view,
  */
 static gboolean
 pspp_sheet_view_bin_expose (GtkWidget      *widget,
-                           GdkEventExpose *event)
+                           cairo_t *cr)
 {
   PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
   GtkTreePath *path;
@@ -3848,6 +3896,14 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
   gboolean draw_vgrid_lines, draw_hgrid_lines;
   gint min_y, max_y;
 
+  GdkRectangle Zarea;
+  GtkAllocation allocation;
+  gtk_widget_get_allocation (widget, &allocation);
+
+  Zarea.x =      0;
+  Zarea.y =      0;
+  Zarea.height = allocation.height;
+
   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
 
   gtk_widget_style_get (widget,
@@ -3860,17 +3916,19 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
 
   if (tree_view->priv->row_count == 0)
     {
-      draw_empty_focus (tree_view, &event->area);
+      draw_empty_focus (tree_view);
       return TRUE;
     }
 
+#if GTK3_TRANSITION
   /* clip event->area to the visible area */
-  if (event->area.height < 0.5)
+  if (Zarea.height < 0.5)
     return TRUE;
+#endif
 
   validate_visible_area (tree_view);
 
-  new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
+  new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, Zarea.y);
 
   if (new_y < 0)
     new_y = 0;
@@ -3885,10 +3943,9 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
   if (tree_view->priv->height < bin_window_height)
     {
       gtk_paint_flat_box (gtk_widget_get_style (widget),
-                          event->window,
+                          cr,
                           gtk_widget_get_state (widget),
                           GTK_SHADOW_NONE,
-                          &event->area,
                           widget,
                           "cell_even",
                           0, tree_view->priv->height,
@@ -3970,7 +4027,7 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
 
       cell_offset = 0;
 
-      background_area.y = y_offset + event->area.y;
+      background_area.y = y_offset + Zarea.y;
       background_area.height = max_height;
       max_y = background_area.y + max_height;
 
@@ -4021,12 +4078,14 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
           else
             selected_column = TRUE;
 
-         if (cell_offset > event->area.x + event->area.width ||
-             cell_offset + column->width < event->area.x)
+#if GTK3_TRANSITION
+         if (cell_offset > Zarea.x + Zarea.width ||
+             cell_offset + column->width < Zarea.x)
            {
              cell_offset += column->width;
              continue;
            }
+#endif
 
           if (selected && selected_column)
             flags |= GTK_CELL_RENDERER_SELECTED;
@@ -4076,11 +4135,13 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
              cell_area.height -= grid_line_width;
            }
 
+#if GTK3_TRANSITION
          if (gdk_region_rect_in (event->region, &background_area) == GDK_OVERLAP_RECTANGLE_OUT)
            {
              cell_offset += column->width;
              continue;
            }
+#endif
 
          pspp_sheet_view_column_cell_set_cell_data (column,
                                                      tree_view->priv->model,
@@ -4157,10 +4218,9 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
                g_snprintf (new_detail, 128, "%s_middle", detail);
 
              gtk_paint_flat_box (gtk_widget_get_style (widget),
-                                 event->window,
+                                 cr,
                                  state,
                                  GTK_SHADOW_NONE,
-                                 &event->area,
                                  widget,
                                  new_detail,
                                  background_area.x,
@@ -4171,10 +4231,9 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
          else
            {
              gtk_paint_flat_box (gtk_widget_get_style (widget),
-                                 event->window,
+                                 cr,
                                  state,
                                  GTK_SHADOW_NONE,
-                                 &event->area,
                                  widget,
                                  detail,
                                  background_area.x,
@@ -4185,7 +4244,6 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
 
          if (draw_hgrid_lines)
            {
-             cairo_t *cr = gdk_cairo_create (event->window);   
              cairo_set_line_width (cr, 1.0);
              cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
 
@@ -4204,7 +4262,7 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
 #endif
                }
 
-             if (y_offset + max_height >= event->area.height - 0.5)
+             if (y_offset + max_height <= Zarea.height - 0.5)
                {
 #if GTK3_TRANSITION
                  gdk_draw_line (event->window,
@@ -4220,14 +4278,12 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
 #endif
                }
              cairo_stroke (cr);
-             cairo_destroy (cr);
            }
 
           _pspp_sheet_view_column_cell_render (column,
-                                               event->window,
+                                               cr,
                                                &background_area,
                                                &cell_area,
-                                               &event->area,
                                                flags);
 
           if (node == cursor && has_special_cell &&
@@ -4237,28 +4293,26 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
               (column == tree_view->priv->edited_column)))
            {
              _pspp_sheet_view_column_cell_draw_focus (column,
-                                                    event->window,
+                                                      cr,
                                                     &background_area,
                                                     &cell_area,
-                                                    &event->area,
                                                     flags);
            }
 
          cell_offset += column->width;
        }
 
-      if (cell_offset < event->area.x)
+      if (cell_offset < Zarea.x)
         {
           gtk_paint_flat_box (gtk_widget_get_style (widget),
-                              event->window,
+                              cr,
                               GTK_STATE_NORMAL,
                               GTK_SHADOW_NONE,
-                              &event->area,
                               widget,
                               "base",
                               cell_offset,
                               background_area.y,
-                              event->area.x - cell_offset,
+                              Zarea.x - cell_offset,
                               background_area.height);
         }
 
@@ -4292,9 +4346,8 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
 
              if (row_ending_details)
                gtk_paint_focus (gtk_widget_get_style (widget),
-                                tree_view->priv->bin_window,
+                                cr,
                                 gtk_widget_get_state (widget),
-                                &event->area,
                                 widget,
                                 (is_first
                                  ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
@@ -4305,9 +4358,8 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
                               - focus_line_width + 1);
              else
                gtk_paint_focus (gtk_widget_get_style (widget),
-                                tree_view->priv->bin_window,
+                                cr,
                                 gtk_widget_get_state (widget),
-                                &event->area,
                                 widget,
                                 "treeview-drop-indicator",
                                 0, BACKGROUND_FIRST_PIXEL (tree_view, node)
@@ -4360,9 +4412,8 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
 
          if (row_ending_details)
            gtk_paint_focus (gtk_widget_get_style (widget),
-                            tree_view->priv->bin_window,
+                            cr,
                             focus_rect_state,
-                            &event->area,
                             widget,
                             (is_first
                              ? (is_last ? "treeview" : "treeview-left" )
@@ -4371,9 +4422,8 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
                             width, tmp_height);
          else
            gtk_paint_focus (gtk_widget_get_style (widget),
-                            tree_view->priv->bin_window,
+                            cr,
                             focus_rect_state,
-                            &event->area,
                             widget,
                             "treeview",
                             0, tmp_y,
@@ -4398,12 +4448,13 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
         }
       while (!done);
     }
-  while (y_offset < event->area.height);
+  while (y_offset < Zarea.height);
 
 done:
-  pspp_sheet_view_draw_vertical_grid_lines (tree_view, event, n_visible_columns,
+  pspp_sheet_view_draw_vertical_grid_lines (tree_view, cr, n_visible_columns,
                                    min_y, max_y);
 
+#if GTK3_TRANSITION
  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
    {
      GdkRectangle *rectangles;
@@ -4418,6 +4469,7 @@ done:
 
      g_free (rectangles);
    }
+#endif
 
   if (cursor_path)
     gtk_tree_path_free (cursor_path);
@@ -4428,18 +4480,24 @@ done:
   return FALSE;
 }
 
+
 static gboolean
-pspp_sheet_view_expose (GtkWidget      *widget,
-                        GdkEventExpose *event)
+pspp_sheet_view_draw (GtkWidget      *widget,
+                     cairo_t *cr)
 {
   PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
-  if (event->window == tree_view->priv->bin_window)
+  GtkAllocation allocation;
+  gtk_widget_get_allocation (widget, &allocation);
+  
+  if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
     {
       gboolean retval;
       GList *tmp_list;
 
-      retval = pspp_sheet_view_bin_expose (widget, event);
+      cairo_save (cr);
+      cairo_translate (cr, 0, gdk_window_get_height (tree_view->priv->header_window));
+      retval = pspp_sheet_view_bin_expose (widget, cr);
+      cairo_restore (cr);
 
       /* We can't just chain up to Container::expose as it will try to send the
        * event to the headers, so we handle propagating it to our children
@@ -4451,27 +4509,27 @@ pspp_sheet_view_expose (GtkWidget      *widget,
          PsppSheetViewChild *child = tmp_list->data;
          tmp_list = tmp_list->next;
 
-         gtk_container_propagate_expose (GTK_CONTAINER (tree_view), child->widget, event);
+         gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
        }
 
       return retval;
     }
-  else if (event->window == tree_view->priv->header_window)
+  else if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
     {
       gint n_visible_columns;
       GList *list;
 
       gtk_paint_flat_box (gtk_widget_get_style (widget),
-                          event->window,
+                          cr,
                           GTK_STATE_NORMAL,
                           GTK_SHADOW_NONE,
-                          &event->area,
                           widget,
                           "cell_odd",
-                          event->area.x,
-                          event->area.y,
-                          event->area.width,
-                          event->area.height);
+                         allocation.x,
+                         allocation.y,
+                         allocation.width,
+                         allocation.height
+                         );
 
       for (list = tree_view->priv->columns; list != NULL; list = list->next)
        {
@@ -4481,10 +4539,10 @@ pspp_sheet_view_expose (GtkWidget      *widget,
            continue;
 
           if (span_intersects (column->allocation.x, column->allocation.width,
-                               event->area.x, event->area.width)
+                              allocation.x, allocation.width)
               && column->button != NULL)
-            gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
-                                            column->button, event);
+            gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
+                                         column->button, cr);
        }
 
       n_visible_columns = 0;
@@ -4495,18 +4553,23 @@ pspp_sheet_view_expose (GtkWidget      *widget,
           n_visible_columns ++;
         }
       pspp_sheet_view_draw_vertical_grid_lines (tree_view,
-                                       event,
-                                       n_visible_columns,
-                                       event->area.y,
-                                       event->area.height);
+                                               cr,
+                                               n_visible_columns,
+                                               allocation.y,
+                                               allocation.height);
+
+      return TRUE;
     }
-  else if (event->window == tree_view->priv->drag_window)
+  else if (gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
     {
-      gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
-                                     tree_view->priv->drag_column->button,
-                                     event);
+      gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
+                                   tree_view->priv->drag_column->button,
+                                   cr);
+     
+      return TRUE;
     }
-  return TRUE;
+
+  return FALSE;
 }
 
 enum
@@ -6917,7 +6980,6 @@ pspp_sheet_view_style_set (GtkWidget *widget,
 
   if (gtk_widget_get_realized (widget))
     {
-      gdk_window_set_back_pixmap (gtk_widget_get_window (widget), NULL, FALSE);
       gdk_window_set_background (tree_view->priv->bin_window, &gtk_widget_get_style (widget)->base[gtk_widget_get_state (widget)]);
       gtk_style_set_background (gtk_widget_get_style (widget), tree_view->priv->header_window, GTK_STATE_NORMAL);
       pspp_sheet_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
@@ -7685,9 +7747,8 @@ _pspp_sheet_view_column_start_drag (PsppSheetView       *tree_view,
       attributes.width = column->allocation.width;
       attributes.height = column->allocation.height;
       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
-      attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
-      attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+      attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL ;
 
       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
                                                     &attributes,
@@ -7719,7 +7780,9 @@ _pspp_sheet_view_column_start_drag (PsppSheetView       *tree_view,
   send_event->button.axes = NULL;
   send_event->button.state = 0;
   send_event->button.button = 1;
-  send_event->button.device = gdk_display_get_core_pointer (display);
+  send_event->button.device = 
+    gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (display));
+
   send_event->button.x_root = 0;
   send_event->button.y_root = 0;
 
@@ -9169,9 +9232,12 @@ pspp_sheet_view_get_hadjustment (PsppSheetView *tree_view)
 {
   g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
 
-  if (tree_view->priv->hadjustment == NULL)
-    pspp_sheet_view_set_hadjustment (tree_view, NULL);
+  return pspp_sheet_view_do_get_hadjustment (tree_view);
+}
 
+static GtkAdjustment *
+pspp_sheet_view_do_get_hadjustment (PsppSheetView *tree_view)
+{
   return tree_view->priv->hadjustment;
 }
 
@@ -9195,23 +9261,60 @@ pspp_sheet_view_set_hadjustment (PsppSheetView   *tree_view,
   g_object_notify (G_OBJECT (tree_view), "hadjustment");
 }
 
+static void
+pspp_sheet_view_do_set_hadjustment (PsppSheetView   *tree_view,
+                                  GtkAdjustment *adjustment)
+{
+  PsppSheetViewPrivate *priv = tree_view->priv;
+
+  if (adjustment && priv->hadjustment == adjustment)
+    return;
+
+  if (priv->hadjustment != NULL)
+    {
+      g_signal_handlers_disconnect_by_func (priv->hadjustment,
+                                            pspp_sheet_view_adjustment_changed,
+                                            tree_view);
+      g_object_unref (priv->hadjustment);
+    }
+
+  if (adjustment == NULL)
+    adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
+                                     0.0, 0.0, 0.0);
+
+  g_signal_connect (adjustment, "value-changed",
+                    G_CALLBACK (pspp_sheet_view_adjustment_changed), tree_view);
+  priv->hadjustment = g_object_ref_sink (adjustment);
+  /* FIXME: Adjustment should probably be populated here with fresh values, but
+   * internal details are too complicated for me to decipher right now.
+   */
+  pspp_sheet_view_adjustment_changed (NULL, tree_view);
+
+  g_object_notify (G_OBJECT (tree_view), "hadjustment");
+}
+
 /**
  * pspp_sheet_view_get_vadjustment:
  * @tree_view: A #PsppSheetView
  *
  * Gets the #GtkAdjustment currently being used for the vertical aspect.
  *
- * Return value: A #GtkAdjustment object, or %NULL if none is currently being
- * used.
+ * Return value: (transfer none): A #GtkAdjustment object, or %NULL
+ *     if none is currently being used.
+ *
+ * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
  **/
 GtkAdjustment *
 pspp_sheet_view_get_vadjustment (PsppSheetView *tree_view)
 {
   g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
 
-  if (tree_view->priv->vadjustment == NULL)
-    pspp_sheet_view_set_vadjustment (tree_view, NULL);
+  return pspp_sheet_view_do_get_vadjustment (tree_view);
+}
 
+static GtkAdjustment *
+pspp_sheet_view_do_get_vadjustment (PsppSheetView *tree_view)
+{
   return tree_view->priv->vadjustment;
 }
 
@@ -9221,17 +9324,47 @@ pspp_sheet_view_get_vadjustment (PsppSheetView *tree_view)
  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
  *
  * Sets the #GtkAdjustment for the current vertical aspect.
+ *
+ * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
  **/
 void
 pspp_sheet_view_set_vadjustment (PsppSheetView   *tree_view,
-                              GtkAdjustment *adjustment)
+                               GtkAdjustment *adjustment)
 {
   g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
+  g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
 
-  pspp_sheet_view_set_adjustments (tree_view,
-                                tree_view->priv->hadjustment,
-                                adjustment);
+  pspp_sheet_view_do_set_vadjustment (tree_view, adjustment);
+}
+
+static void
+pspp_sheet_view_do_set_vadjustment (PsppSheetView   *tree_view,
+                                  GtkAdjustment *adjustment)
+{
+  PsppSheetViewPrivate *priv = tree_view->priv;
+
+  if (adjustment && priv->vadjustment == adjustment)
+    return;
 
+  if (priv->vadjustment != NULL)
+    {
+      g_signal_handlers_disconnect_by_func (priv->vadjustment,
+                                            pspp_sheet_view_adjustment_changed,
+                                            tree_view);
+      g_object_unref (priv->vadjustment);
+    }
+
+  if (adjustment == NULL)
+    adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
+                                     0.0, 0.0, 0.0);
+
+  g_signal_connect (adjustment, "value-changed",
+                    G_CALLBACK (pspp_sheet_view_adjustment_changed), tree_view);
+  priv->vadjustment = g_object_ref_sink (adjustment);
+  /* FIXME: Adjustment should probably be populated here with fresh values, but
+   * internal details are too complicated for me to decipher right now.
+   */
+  pspp_sheet_view_adjustment_changed (NULL, tree_view);
   g_object_notify (G_OBJECT (tree_view), "vadjustment");
 }
 
@@ -12519,7 +12652,7 @@ pspp_sheet_view_event (GtkWidget *widget,
   gtk_tree_path_free (path);
 
   handled = gtk_binding_set_activate (edit_bindings, keyval, event->state,
-                                      GTK_OBJECT (tree_view));
+                                      G_OBJECT (tree_view));
   if (handled)
     g_signal_stop_emission_by_name (widget, "event");
 
@@ -12788,7 +12921,6 @@ pspp_sheet_view_state_changed (GtkWidget      *widget,
   if (gtk_widget_get_realized (widget))
     {
       GtkStyle *style = gtk_widget_get_style (widget);
-      gdk_window_set_back_pixmap (gtk_widget_get_window (widget), NULL, FALSE);
       gdk_window_set_background (tree_view->priv->bin_window, &style->base[gtk_widget_get_state (widget)]);
     }