Merge master into gtk3.
[pspp] / src / ui / gui / pspp-sheet-view.c
index d83665acf20c1583325dc045d3664ccf0db9c489..ccdbd10e9919b5d61cbc059bd6d4c7284c66e277 100644 (file)
@@ -135,6 +135,8 @@ enum {
   PROP_MODEL,
   PROP_HADJUSTMENT,
   PROP_VADJUSTMENT,
+  PROP_HSCROLL_POLICY,
+  PROP_VSCROLL_POLICY,
   PROP_HEADERS_VISIBLE,
   PROP_HEADERS_CLICKABLE,
   PROP_REORDERABLE,
@@ -171,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,
@@ -295,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,
@@ -451,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)
@@ -481,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;
@@ -531,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,
@@ -754,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
@@ -773,6 +797,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class)
                  G_TYPE_NONE, 2,
                  GTK_TYPE_ADJUSTMENT,
                  GTK_TYPE_ADJUSTMENT);
+#endif
 
   /**
    * PsppSheetView::row-activated:
@@ -1094,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
@@ -1117,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:
@@ -1205,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;
@@ -3792,21 +3834,24 @@ 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;
 
+      /* 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_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);
-      
+      cairo_move_to (cr, x + 0.5, min_y);
+      cairo_line_to (cr, x + 0.5, max_y - min_y);
       cairo_stroke (cr);
     }
 }
@@ -3819,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;
@@ -3850,14 +3895,13 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
   gboolean row_ending_details;
   gboolean draw_vgrid_lines, draw_hgrid_lines;
   gint min_y, max_y;
-  cairo_t *cr = gdk_cairo_create (event->window);
+
   GdkRectangle Zarea;
   GtkAllocation allocation;
   gtk_widget_get_allocation (widget, &allocation);
 
   Zarea.x =      0;
   Zarea.y =      0;
-  Zarea.width =  gdk_window_get_width (event->window);
   Zarea.height = allocation.height;
 
   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
@@ -4218,7 +4262,7 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
 #endif
                }
 
-             if (y_offset + max_height >= Zarea.height - 0.5)
+             if (y_offset + max_height <= Zarea.height - 0.5)
                {
 #if GTK3_TRANSITION
                  gdk_draw_line (event->window,
@@ -4302,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),
-                                &Zarea,
                                 widget,
                                 (is_first
                                  ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
@@ -4315,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),
-                                &Zarea,
                                 widget,
                                 "treeview-drop-indicator",
                                 0, BACKGROUND_FIRST_PIXEL (tree_view, node)
@@ -4370,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,
-                            &Zarea,
                             widget,
                             (is_first
                              ? (is_last ? "treeview" : "treeview-left" )
@@ -4381,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,
-                            &Zarea,
                             widget,
                             "treeview",
                             0, tmp_y,
@@ -4440,19 +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);
-  cairo_t *cr = gdk_cairo_create (event->window);
-
-  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
@@ -4464,12 +4509,12 @@ 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;
@@ -4480,10 +4525,11 @@ pspp_sheet_view_expose (GtkWidget      *widget,
                           GTK_SHADOW_NONE,
                           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)
        {
@@ -4493,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;
@@ -4509,16 +4555,21 @@ pspp_sheet_view_expose (GtkWidget      *widget,
       pspp_sheet_view_draw_vertical_grid_lines (tree_view,
                                                cr,
                                                n_visible_columns,
-                                               event->area.y,
-                                               event->area.height);
+                                               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
@@ -7729,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;
 
@@ -9179,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;
 }
 
@@ -9205,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;
 }
 
@@ -9231,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");
 }