From b2f192faabe412adce79534e22efe9fb69ee40e2 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Fri, 21 Jul 2006 10:10:31 +0000 Subject: Rename /openembedded/ -> /meta/ git-svn-id: https://svn.o-hand.com/repos/poky/trunk@530 311d38ba-8fff-0310-9ca6-ca027cbcb966 --- .../gtk+/gtk+-2.6.4-1.osso7/gtktreeview.c.diff | 2253 ++++++++++++++++++++ 1 file changed, 2253 insertions(+) create mode 100644 meta/packages/gtk+/gtk+-2.6.4-1.osso7/gtktreeview.c.diff (limited to 'meta/packages/gtk+/gtk+-2.6.4-1.osso7/gtktreeview.c.diff') diff --git a/meta/packages/gtk+/gtk+-2.6.4-1.osso7/gtktreeview.c.diff b/meta/packages/gtk+/gtk+-2.6.4-1.osso7/gtktreeview.c.diff new file mode 100644 index 0000000000..87ccffa868 --- /dev/null +++ b/meta/packages/gtk+/gtk+-2.6.4-1.osso7/gtktreeview.c.diff @@ -0,0 +1,2253 @@ +--- gtk+-2.6.4/gtk/gtktreeview.c 2005-02-24 00:38:20.000000000 +0200 ++++ gtk+-2.6.4/gtk/gtktreeview.c 2005-04-06 16:19:38.274719720 +0300 +@@ -42,6 +42,7 @@ + #include "gtkentry.h" + #include "gtkframe.h" + #include "gtktreemodelsort.h" ++#include "gtkscrolledwindow.h" + + #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5) + #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2) +@@ -114,6 +115,7 @@ + EXPAND_COLLAPSE_CURSOR_ROW, + SELECT_CURSOR_PARENT, + START_INTERACTIVE_SEARCH, ++ ROW_INSENSITIVE, + LAST_SIGNAL + }; + +@@ -132,7 +134,10 @@ + PROP_SEARCH_COLUMN, + PROP_FIXED_HEIGHT_MODE, + PROP_HOVER_SELECTION, +- PROP_HOVER_EXPAND ++ PROP_HOVER_EXPAND, ++ PROP_DOTTED_LINES, ++ PROP_FORCE_LIST_KLUDGE, ++ PROP_ALLOW_CHECKBOX_MODE + }; + + static void gtk_tree_view_class_init (GtkTreeViewClass *klass); +@@ -338,8 +343,6 @@ + static void gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view, + GtkRBTree *tree, + GtkRBNode *node); +-static void gtk_tree_view_clamp_column_visible (GtkTreeView *tree_view, +- GtkTreeViewColumn *column); + static gboolean gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view, + GdkEventMotion *event); + static void gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view); +@@ -372,6 +375,18 @@ + gpointer data); + static gboolean expand_collapse_timeout (gpointer data); + static gboolean do_expand_collapse (GtkTreeView *tree_view); ++static void update_checkbox_mode (GObject *object, ++ GParamSpec *pspec, ++ gpointer data); ++static void set_dotted_lines (GtkTreeView *tree_view, ++ gboolean enable); ++static void selection_changed (GtkTreeSelection *selection, ++ gpointer data); ++static void check_if_can_focus (GtkTreeView *tree_view); ++static gint scroll_row_timeout (gpointer data); ++ ++static void add_scroll_timeout (GtkTreeView *tree_view); ++static void remove_scroll_timeout (GtkTreeView *tree_view); + + /* interactive search */ + static void gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view); +@@ -694,8 +709,54 @@ + FALSE, + G_PARAM_READWRITE)); + ++ /** ++ * GtkTreeView:dotted-lines: ++ * ++ * Enables or disables the dotted lines for hierarchical trees. ++ * Hildon patch. ++ */ ++ g_object_class_install_property (o_class, ++ PROP_DOTTED_LINES, ++ g_param_spec_boolean ("dotted_lines", ++ P_("Dotted Lines"), ++ P_("Whether to show or hide dotted lines for hierarchical trees"), ++ FALSE, ++ G_PARAM_READWRITE)); ++ ++ /** ++ * GtkTreeView:force-list-kludge: ++ * ++ * Hildon kludge for fixing file tree behaviour until a cleaner ++ * implementation is scheduled: if this property is set, then rows ++ * can be activated by tapping even if the underlying tree model is ++ * not technically a list. ++ */ ++ g_object_class_install_property (o_class, ++ PROP_FORCE_LIST_KLUDGE, ++ g_param_spec_boolean ("force_list_kludge", ++ P_("Force List Behaviour"), ++ P_("Whether to activate tapped focused items even if model was not a list"), ++ FALSE, ++ G_PARAM_READWRITE)); ++ ++ /** ++ * GtkTreeView:enable-checkbox-mode: ++ * ++ * Another Hildon kludge for allowing the existence of GtkTreeViews ++ * that have activatable columns but that still is not a Text Listbox ++ * in multiple selection with checkboxes mode. ++ */ ++ g_object_class_install_property (o_class, ++ PROP_ALLOW_CHECKBOX_MODE, ++ g_param_spec_boolean ("allow_checkbox_mode", ++ P_("Enable Checkbox Mode"), ++ P_("Whether to behave like a Listbox in a multiple selection with checkboxes mode, if checkboxes exist"), ++ TRUE, ++ G_PARAM_READWRITE)); ++ + /* Style properties */ + #define _TREE_VIEW_EXPANDER_SIZE 12 ++#define _TREE_VIEW_EXPANDER_INDENT 10 + #define _TREE_VIEW_VERTICAL_SEPARATOR 2 + #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2 + +@@ -709,6 +770,15 @@ + G_PARAM_READABLE)); + + gtk_widget_class_install_style_property (widget_class, ++ g_param_spec_int ("expander_indent", ++ P_("Expander intent"), ++ P_("Defines the expanders indent"), ++ 0, ++ G_MAXINT, ++ _TREE_VIEW_EXPANDER_INDENT, ++ G_PARAM_READABLE)); ++ ++ gtk_widget_class_install_style_property (widget_class, + g_param_spec_int ("vertical_separator", + P_("Vertical Separator Width"), + P_("Vertical space between cells. Must be an even number"), +@@ -754,6 +824,13 @@ + GDK_TYPE_COLOR, + G_PARAM_READABLE)); + ++ gtk_widget_class_install_style_property (widget_class, ++ g_param_spec_boolean ("passive_focus", ++ P_("Enables passive focus"), ++ P_("Used for tree view passive focus"), ++ TRUE, ++ G_PARAM_READABLE)); ++ + /* Signals */ + widget_class->set_scroll_adjustments_signal = + g_signal_new ("set_scroll_adjustments", +@@ -917,6 +994,16 @@ + _gtk_marshal_BOOLEAN__NONE, + G_TYPE_BOOLEAN, 0); + ++ tree_view_signals[ROW_INSENSITIVE] = ++ g_signal_new ("row_insensitive", ++ G_TYPE_FROM_CLASS (o_class), ++ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, ++ G_STRUCT_OFFSET (GtkTreeViewClass, row_insensitive), ++ NULL, NULL, ++ _gtk_marshal_VOID__OBJECT, ++ G_TYPE_NONE, 1, ++ GTK_TYPE_TREE_PATH); ++ + /* Key bindings */ + gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0, + GTK_MOVEMENT_DISPLAY_LINES, -1); +@@ -1004,12 +1091,13 @@ + + gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_row", 1, + G_TYPE_BOOLEAN, TRUE); ++ /* Hildon change: Enter shouldn't select + gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select_cursor_row", 1, + G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select_cursor_row", 1, + G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select_cursor_row", 1, +- G_TYPE_BOOLEAN, TRUE); ++ G_TYPE_BOOLEAN, TRUE);*/ + + /* expand and collapse rows */ + gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand_collapse_cursor_row", 3, +@@ -1123,19 +1211,31 @@ + gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start_interactive_search", 0); + + gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start_interactive_search", 0); ++ ++ /* Hildon addition: Add key bindings to Right and Left arrows */ ++ gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "expand_collapse_cursor_row", 3, ++ G_TYPE_BOOLEAN, FALSE, G_TYPE_BOOLEAN, TRUE, G_TYPE_BOOLEAN, FALSE); ++ gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3, ++ G_TYPE_BOOLEAN, FALSE, G_TYPE_BOOLEAN, TRUE, G_TYPE_BOOLEAN, TRUE); ++ gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "expand_collapse_cursor_row", 3, ++ G_TYPE_BOOLEAN, FALSE, G_TYPE_BOOLEAN, FALSE, G_TYPE_BOOLEAN, FALSE); ++ gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3, ++ G_TYPE_BOOLEAN, FALSE, G_TYPE_BOOLEAN, FALSE, G_TYPE_BOOLEAN, TRUE); + } + + static void + gtk_tree_view_init (GtkTreeView *tree_view) + { + tree_view->priv = g_new0 (GtkTreeViewPrivate, 1); +- GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS); ++ ++ /* Hildon: focus cannot be gained until at least one row is added */ ++ GTK_WIDGET_UNSET_FLAGS (tree_view, GTK_CAN_FOCUS); + + gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE); + ++ /* Hildon: Headers invisible by default */ + tree_view->priv->flags = GTK_TREE_VIEW_SHOW_EXPANDERS +- | GTK_TREE_VIEW_DRAW_KEYFOCUS +- | GTK_TREE_VIEW_HEADERS_VISIBLE; ++ | GTK_TREE_VIEW_DRAW_KEYFOCUS; + + /* We need some padding */ + tree_view->priv->dy = 0; +@@ -1165,6 +1265,26 @@ + + tree_view->priv->hover_selection = FALSE; + tree_view->priv->hover_expand = FALSE; ++ ++ tree_view->priv->ctrl_pressed = FALSE; ++ tree_view->priv->shift_pressed = FALSE; ++ ++ tree_view->priv->checkbox_mode = FALSE; ++ tree_view->priv->allow_checkbox_mode = TRUE; ++ tree_view->priv->pen_down = FALSE; ++ tree_view->priv->pen_drag_active = FALSE; ++ tree_view->priv->pen_drag_reverse = FALSE; ++ tree_view->priv->first_drag_row = NULL; ++ tree_view->priv->last_drag_row = NULL; ++ tree_view->priv->queued_expand_row = NULL; ++ tree_view->priv->queued_select_row = NULL; ++ tree_view->priv->pen_focus = TRUE; ++ ++ /* Hildon: cursor should follow when selection changes */ ++ g_signal_connect (tree_view->priv->selection, "changed", ++ G_CALLBACK (selection_changed), tree_view); ++ ++ gtk_widget_set_name (GTK_WIDGET (tree_view), "treeview"); + } + + +@@ -1223,6 +1343,27 @@ + case PROP_HOVER_EXPAND: + tree_view->priv->hover_expand = g_value_get_boolean (value); + break; ++ case PROP_DOTTED_LINES: ++ set_dotted_lines (tree_view, g_value_get_boolean (value)); ++ break; ++ case PROP_FORCE_LIST_KLUDGE: ++ tree_view->priv->force_list_kludge = g_value_get_boolean (value); ++ break; ++ case PROP_ALLOW_CHECKBOX_MODE: ++ if ((tree_view->priv->allow_checkbox_mode = g_value_get_boolean (value))) ++ { ++ gtk_widget_set_name (GTK_WIDGET(tree_view), "treeview"); ++ update_checkbox_mode (NULL, NULL, tree_view); ++ } ++ else ++ { ++ /* ugly hack - to ensure that checkboxes are independent of the ++ selection if !allow_checkbox_mode, we must be able to use ++ different theming in that case */ ++ gtk_widget_set_name (GTK_WIDGET(tree_view), "no_checkbox_mode"); ++ tree_view->priv->checkbox_mode = FALSE; ++ } ++ break; + default: + break; + } +@@ -1276,6 +1417,15 @@ + case PROP_HOVER_EXPAND: + g_value_set_boolean (value, tree_view->priv->hover_expand); + break; ++ case PROP_DOTTED_LINES: ++ g_value_set_boolean (value, tree_view->priv->dotted_lines); ++ break; ++ case PROP_FORCE_LIST_KLUDGE: ++ g_value_set_boolean (value, tree_view->priv->force_list_kludge); ++ break; ++ case PROP_ALLOW_CHECKBOX_MODE: ++ g_value_set_boolean (value, tree_view->priv->allow_checkbox_mode); ++ break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; +@@ -1376,6 +1526,27 @@ + tree_view->priv->destroy_count_data = NULL; + } + ++ if (tree_view->priv->first_drag_row) ++ { ++ gtk_tree_row_reference_free (tree_view->priv->first_drag_row); ++ tree_view->priv->first_drag_row = NULL; ++ } ++ if (tree_view->priv->last_drag_row) ++ { ++ gtk_tree_row_reference_free (tree_view->priv->last_drag_row); ++ tree_view->priv->last_drag_row = NULL; ++ } ++ if (tree_view->priv->queued_expand_row) ++ { ++ gtk_tree_row_reference_free (tree_view->priv->queued_expand_row); ++ tree_view->priv->queued_expand_row = NULL; ++ } ++ if (tree_view->priv->queued_select_row) ++ { ++ gtk_tree_row_reference_free (tree_view->priv->queued_select_row); ++ tree_view->priv->queued_select_row = NULL; ++ } ++ + gtk_tree_row_reference_free (tree_view->priv->cursor); + tree_view->priv->cursor = NULL; + +@@ -1494,6 +1665,8 @@ + gtk_tree_view_map_buttons (tree_view); + + gdk_window_show (widget->window); ++ ++ check_if_can_focus (tree_view); + } + + static void +@@ -1895,6 +2068,8 @@ + gint full_requested_width = 0; + gint number_of_expand_columns = 0; + gboolean rtl; ++ GtkWidget *scroll; ++ GtkPolicyType ptype; + + tree_view = GTK_TREE_VIEW (widget); + +@@ -1969,6 +2144,19 @@ + allocation.x = width; + column->width = real_requested_width; + ++ /* a dirty Hildon hack to force truncation if not enough space. This hack is applied ++ * only if we are NOT in a scrolled window with hscroll*/ ++ scroll = gtk_widget_get_ancestor(widget, GTK_TYPE_SCROLLED_WINDOW); ++ if ((!scroll || ++ (gtk_scrolled_window_get_policy (GTK_SCROLLED_WINDOW (scroll), &ptype, NULL), ptype == GTK_POLICY_NEVER)) ++ && (width + real_requested_width > widget->allocation.width)) ++ { ++ column->width = widget->allocation.width - width; ++ if (column->width < 1) ++ column->width = 1; ++ gtk_widget_queue_draw (widget); ++ } ++ + if (column->expand) + { + if (number_of_expand_columns == 1) +@@ -2153,6 +2341,23 @@ + GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS); + } + ++/* helper function for gtk_tree_view_button_press */ ++static void ++activate_callback (GtkTreeModel *model, ++ GtkTreePath *path, ++ GtkTreeIter *iter, ++ gpointer data) ++{ ++ GtkTreeView *tree_view = GTK_TREE_VIEW (data); ++ ++ /* Hildon: if the tree view has no active focus we don't activate ++ * the selected row */ ++ if ( !GTK_WIDGET_HAS_FOCUS (GTK_WIDGET(data)) ) ++ return; ++ ++ gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column); ++} ++ + static gboolean + gtk_tree_view_button_press (GtkWidget *widget, + GdkEventButton *event) +@@ -2166,6 +2371,7 @@ + gint vertical_separator; + gint horizontal_separator; + gboolean rtl; ++ gint expander_indent; + + g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); +@@ -2176,6 +2382,7 @@ + gtk_widget_style_get (widget, + "vertical_separator", &vertical_separator, + "horizontal_separator", &horizontal_separator, ++ "expander_indent", &expander_indent, + NULL); + + +@@ -2199,6 +2406,14 @@ + gint column_handled_click = FALSE; + gboolean row_double_click = FALSE; + gboolean rtl; ++ gboolean force_list_kludge; ++ GtkRBNode *cursor = NULL; ++ gboolean focus_grab = FALSE; ++ ++ if (!GTK_WIDGET_HAS_FOCUS (widget)) ++ focus_grab = TRUE; ++ ++ GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS); + + /* Empty tree? */ + if (tree_view->priv->tree == NULL) +@@ -2207,7 +2422,9 @@ + return TRUE; + } + +- /* are we in an arrow? */ ++ /* In Hildon we don't want to use the arrows */ ++#if 0 ++ /* are we in an arrow? */ + if (tree_view->priv->prelight_node && + GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)) + { +@@ -2226,6 +2443,7 @@ + grab_focus_and_unset_draw_keyfocus (tree_view); + return TRUE; + } ++#endif + + /* find the node that was clicked */ + new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y); +@@ -2247,6 +2465,65 @@ + background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node)); + background_area.x = 0; + ++ if (tree_view->priv->first_drag_row) ++ { ++ gtk_tree_row_reference_free (tree_view->priv->first_drag_row); ++ tree_view->priv->first_drag_row = NULL; ++ } ++ if (tree_view->priv->last_drag_row) ++ { ++ gtk_tree_row_reference_free (tree_view->priv->last_drag_row); ++ tree_view->priv->last_drag_row = NULL; ++ } ++ tree_view->priv->first_drag_row = ++ gtk_tree_row_reference_new (tree_view->priv->model, path); ++ tree_view->priv->last_drag_row = gtk_tree_row_reference_copy (tree_view->priv->first_drag_row); ++ ++ /* force_list_kludge allows pen dragging even if ++ GTK_TREE_MODEL_LIST_ONLY is not set (to fix file tree) */ ++ g_object_get (widget, "force_list_kludge", &force_list_kludge, NULL); ++ ++ /* Hildon: activate pen dragging, if listbox is not hierarchical and ++ the pen was not put down in a position that initiates drag'n'drop */ ++ if (!tree_view->priv->pen_down && ++ (force_list_kludge || ++ (gtk_tree_model_get_flags(tree_view->priv->model) ++ & GTK_TREE_MODEL_LIST_ONLY)) && ++ (tree_view->priv->checkbox_mode || ++ !gtk_tree_selection_path_is_selected(tree_view->priv->selection, path))) ++ { ++ gpointer drag_data; ++ ++ tree_view->priv->pen_down = TRUE; ++ tree_view->priv->pen_focus = TRUE; ++ ++ /* also block attached dnd signal handler */ ++ drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data"); ++ if (drag_data) ++ g_signal_handlers_block_matched (widget, ++ G_SIGNAL_MATCH_DATA, ++ 0, 0, NULL, NULL, ++ drag_data); ++ } ++ ++ /* For the Hildon buttonpress find out the previously selected row */ ++ GtkRBTree *cursor_tree = NULL; ++ GtkTreePath *cursor_path = NULL; ++ ++ if (tree_view->priv->cursor) ++ { ++ cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); ++ if (cursor_path) ++ { ++ _gtk_tree_view_find_node (tree_view, cursor_path, ++ &cursor_tree, &cursor); ++ gtk_tree_path_free (cursor_path); ++ } ++ } ++ ++ /* Hildon: in checkbox mode, dragging sets all checkboxes ++ to the same state as the first toggled checkbox */ ++ tree_view->priv->new_state = !gtk_tree_selection_path_is_selected(tree_view->priv->selection, path); + + /* Let the column have a chance at selecting it. */ + rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL); +@@ -2275,8 +2552,11 @@ + if (gtk_tree_view_is_expander_column (tree_view, column) && + TREE_VIEW_DRAW_EXPANDERS(tree_view)) + { +- cell_area.x += depth * tree_view->priv->expander_size; +- cell_area.width -= depth * tree_view->priv->expander_size; ++ gint adjust; ++ ++ adjust = depth * tree_view->priv->expander_size + (depth - 1) * expander_indent; ++ cell_area.x += adjust; ++ cell_area.width -= adjust; + } + break; + } +@@ -2364,15 +2644,19 @@ + */ + if (event->type == GDK_BUTTON_PRESS) + { ++ /* Hildon: ignore Ctrl and Shift */ ++#if 0 + if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK) + tree_view->priv->ctrl_pressed = TRUE; + if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) + tree_view->priv->shift_pressed = TRUE; ++#endif + + focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x); + if (focus_cell) + gtk_tree_view_column_focus_cell (column, focus_cell); + ++#if 0 + if (event->state & GDK_CONTROL_MASK) + { + gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE); +@@ -2387,6 +2671,86 @@ + { + gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE); + } ++#endif ++ if (tree_view->priv->checkbox_mode) ++ { ++ GtkRBTree *tree = NULL; ++ GtkRBNode *node = NULL; ++ ++ _gtk_tree_view_find_node (tree_view, path, &tree, &node); ++ ++ /* cursor cannot move to an insensitive row, so we ++ need to check here to avoid toggling the current ++ row by clicking on an insensitive row */ ++ if (_gtk_tree_selection_is_row_selectable (tree_view->priv->selection, ++ node, path)) ++ { ++ gtk_tree_view_real_set_cursor (tree_view, path, ++ FALSE, TRUE); ++ gtk_tree_view_real_toggle_cursor_row (tree_view); ++ } ++ else ++ /* Usually this would be emitted by real_set_cursor. ++ However in this case we never call it. */ ++ g_signal_emit (tree_view, tree_view_signals[ROW_INSENSITIVE], 0, path); ++ } ++ else ++ { ++ gboolean queue_row = TRUE; ++ gboolean force_list_kludge; ++ ++ /* force_list_kludge allows rows to be activated even if ++ GTK_TREE_MODEL_LIST_ONLY is not set (to fix file tree) */ ++ g_object_get (widget, "force_list_kludge", ++ &force_list_kludge, NULL); ++ if ((force_list_kludge || ++ (gtk_tree_model_get_flags (tree_view->priv->model) & ++ GTK_TREE_MODEL_LIST_ONLY)) && ++ gtk_tree_row_reference_valid (tree_view->priv->cursor)) ++ { ++ /* special case: text listbox without checkboxes ++ should activate selected rows when user taps ++ on cursor row, but not affect selection*/ ++ GtkTreePath *cursor_path = ++ gtk_tree_row_reference_get_path (tree_view->priv->cursor); ++ if (gtk_tree_path_compare (cursor_path, path) == 0) ++ { ++ gtk_tree_selection_selected_foreach (tree_view->priv->selection, ++ activate_callback, ++ tree_view); ++ queue_row = FALSE; ++ } ++ } ++ ++ if (queue_row && ++ (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE) && ++ gtk_tree_selection_path_is_selected (tree_view->priv->selection, path)) ++ { ++ GtkTreePath *old_cursor_path = NULL; ++ ++ /* we don't know if the user is selecting an item or performing ++ multiple item drag and drop until we know where button is released */ ++ if (tree_view->priv->queued_select_row) ++ gtk_tree_row_reference_free (tree_view->priv->queued_select_row); ++ tree_view->priv->queued_select_row = ++ gtk_tree_row_reference_new (tree_view->priv->model, path); ++ ++ /* however, move focus */ ++ if (tree_view->priv->cursor) ++ { ++ old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); ++ gtk_tree_row_reference_free (tree_view->priv->cursor); ++ } ++ tree_view->priv->cursor = gtk_tree_row_reference_new (tree_view->priv->model, ++ path); ++ gtk_tree_view_queue_draw_path (tree_view, path, NULL); ++ if (old_cursor_path) ++ gtk_tree_view_queue_draw_path (tree_view, old_cursor_path, NULL); ++ } ++ else ++ gtk_tree_view_real_set_cursor (tree_view, path, ++ queue_row, TRUE); ++ } + + tree_view->priv->ctrl_pressed = FALSE; + tree_view->priv->shift_pressed = FALSE; +@@ -2412,6 +2776,15 @@ + tree_view->priv->press_start_y = event->y; + } + ++ /* Hildon: if selected row is tapped -> the row gets activated and expands */ ++ if (!focus_grab) ++ { ++ /* ...although not until button is released */ ++ gtk_tree_row_reference_free (tree_view->priv->queued_expand_row); ++ tree_view->priv->queued_expand_row = ++ gtk_tree_row_reference_new (tree_view->priv->model, path); ++ } ++ + /* Test if a double click happened on the same row. */ + if (event->button == 1) + { +@@ -2433,6 +2806,8 @@ + } + } + ++ /* Hildon doesn't support double clicks */ ++#if 0 + if (row_double_click) + { + if (tree_view->priv->last_button_press) +@@ -2443,6 +2818,7 @@ + tree_view->priv->last_button_press_2 = NULL; + } + else ++#endif + { + if (tree_view->priv->last_button_press) + gtk_tree_row_reference_free (tree_view->priv->last_button_press); +@@ -2626,6 +3002,28 @@ + + tree_view = GTK_TREE_VIEW (widget); + ++ /* unblock attached dnd signal handler */ ++ if (tree_view->priv->pen_down) ++ { ++ gpointer drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data"); ++ if (drag_data) ++ g_signal_handlers_unblock_matched (widget, ++ G_SIGNAL_MATCH_DATA, ++ 0, 0, NULL, NULL, ++ drag_data); ++ } ++ ++ /* stop pen dragging */ ++ if (tree_view->priv->first_drag_row) ++ gtk_tree_row_reference_free (tree_view->priv->first_drag_row); ++ if (tree_view->priv->last_drag_row) ++ gtk_tree_row_reference_free (tree_view->priv->last_drag_row); ++ tree_view->priv->first_drag_row = NULL; ++ tree_view->priv->last_drag_row = NULL; ++ tree_view->priv->pen_down = FALSE; ++ tree_view->priv->pen_drag_active = FALSE; ++ remove_scroll_timeout (tree_view); ++ + if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG)) + return gtk_tree_view_button_release_drag_column (widget, event); + +@@ -2635,6 +3033,65 @@ + if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE)) + return gtk_tree_view_button_release_column_resize (widget, event); + ++ if (gtk_tree_row_reference_valid (tree_view->priv->queued_select_row)) ++ { ++ /* unselect other nodes - but only if not drag'n'dropping */ ++ if (event->window == tree_view->priv->bin_window) ++ gtk_tree_selection_unselect_all (tree_view->priv->selection); ++ ++ gtk_tree_view_real_set_cursor (tree_view, ++ gtk_tree_row_reference_get_path (tree_view->priv->queued_select_row), ++ FALSE, TRUE); ++ gtk_tree_row_reference_free (tree_view->priv->queued_select_row); ++ tree_view->priv->queued_select_row = NULL; ++ } ++ ++ /* for handling expand/collapse postponed from button_press (since we ++ don't want expand/collapse before tap on node has been completed) */ ++ if (gtk_tree_row_reference_valid (tree_view->priv->queued_expand_row) && ++ tree_view->priv->tree != NULL) ++ { ++ GtkTreePath *queued_expand_path; ++ GtkRBTree *tree; ++ GtkRBNode *node; ++ GtkRBNode *old_node; ++ gint y; ++ ++ queued_expand_path = ++ gtk_tree_row_reference_get_path (tree_view->priv->queued_expand_row); ++ ++ if (queued_expand_path) ++ { ++ /* must check that cursor hasn't moved elsewhere since button_press */ ++ y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->y); ++ _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node); ++ ++ _gtk_tree_view_find_node (tree_view, queued_expand_path, ++ &tree, &old_node); ++ ++ if (node && old_node == node) ++ { ++ if (node->children == NULL) ++ gtk_tree_view_real_expand_row (tree_view, ++ queued_expand_path, ++ tree, ++ node, ++ FALSE, TRUE); ++ else ++ gtk_tree_view_real_collapse_row (tree_view, ++ queued_expand_path, ++ tree, ++ node, ++ TRUE); ++ } ++ ++ gtk_tree_path_free (queued_expand_path); ++ } ++ ++ gtk_tree_row_reference_free( tree_view->priv->queued_expand_row); ++ tree_view->priv->queued_expand_row = NULL; ++ } ++ + if (tree_view->priv->button_pressed_node == NULL) + return FALSE; + +@@ -3311,6 +3768,7 @@ + GtkTreeView *tree_view; + GtkRBTree *tree; + GtkRBNode *node; ++ GtkTreePath *path, *last_drag_path, *current_path; + gint new_y; + + tree_view = (GtkTreeView *) widget; +@@ -3319,7 +3777,8 @@ + return FALSE; + + /* only check for an initiated drag when a button is pressed */ +- if (tree_view->priv->pressed_button >= 0) ++ /* Hildon: active pen drag overrides drag and drop */ ++ if (tree_view->priv->pressed_button >= 0 && !tree_view->priv->pen_down) + gtk_tree_view_maybe_begin_dragging_row (tree_view, event); + + new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y); +@@ -3328,6 +3787,99 @@ + + _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node); + ++ /* Hildon: pen dragging */ ++ if (tree_view->priv->pen_down && node != NULL && ++ tree_view->priv->queued_select_row == NULL && ++ gtk_tree_row_reference_valid (tree_view->priv->last_drag_row)) ++ { ++ gint direction; ++ ++ last_drag_path = gtk_tree_row_reference_get_path (tree_view->priv->last_drag_row); ++ path = _gtk_tree_view_find_path (tree_view, tree, node); ++ direction = gtk_tree_path_compare (path, last_drag_path); ++ ++ if (direction != 0) ++ { ++ current_path = gtk_tree_path_copy (last_drag_path); ++ ++ /* we must ensure that no row is skipped because stylus ++ is moving faster than motion events are generated */ ++ do { ++ if (direction > 0) ++ { ++ /* gtk_tree_path_next does not let us know when it failed */ ++ GtkTreeIter iter; ++ gtk_tree_model_get_iter (tree_view->priv->model, &iter, current_path); ++ if (!gtk_tree_model_iter_next (tree_view->priv->model, &iter)) ++ break; ++ ++ gtk_tree_path_next (current_path); ++ } ++ else if (!gtk_tree_path_prev (current_path)) ++ break; ++ ++ /* set cursor, and start scrolling */ ++ gtk_tree_view_real_set_cursor (tree_view, current_path, FALSE, FALSE); ++ add_scroll_timeout (tree_view); ++ ++ if (tree_view->priv->checkbox_mode) ++ { ++ /* always set to same state as the first tapped node */ ++ if (tree_view->priv->new_state) ++ gtk_tree_selection_select_path (tree_view->priv->selection, ++ current_path); ++ else ++ gtk_tree_selection_unselect_path (tree_view->priv->selection, ++ current_path); ++ } ++ else ++ { ++ if (gtk_tree_selection_path_is_selected (tree_view->priv->selection, ++ current_path)) ++ { ++ /* apparently we have reversed the pen drag direction */ ++ GtkTreePath *reverse_path; ++ gint reverse_direction; ++ ++ reverse_direction = gtk_tree_path_compare (current_path, ++ last_drag_path); ++ reverse_path = gtk_tree_path_copy (last_drag_path); ++ do { ++ gtk_tree_selection_unselect_path (tree_view->priv->selection, ++ reverse_path); ++ tree_view->priv->pen_drag_reverse = TRUE; ++ if (reverse_direction > 0) ++ { ++ GtkTreeIter iter; ++ gtk_tree_model_get_iter (tree_view->priv->model, &iter, reverse_path); ++ if (!gtk_tree_model_iter_next (tree_view->priv->model, &iter)) ++ break; ++ ++ gtk_tree_path_next (reverse_path); ++ } ++ else if (!gtk_tree_path_prev (reverse_path)) ++ break; ++ } while (gtk_tree_path_compare (reverse_path, current_path) != 0); ++ gtk_tree_path_free (reverse_path); ++ } ++ else ++ { ++ gtk_tree_selection_select_path (tree_view->priv->selection, ++ current_path); ++ tree_view->priv->pen_drag_reverse = FALSE; ++ } ++ } ++ } while (gtk_tree_path_compare(current_path, path) != 0); ++ gtk_tree_path_free (current_path); ++ ++ /* update last_drag_row */ ++ gtk_tree_row_reference_free (tree_view->priv->last_drag_row); ++ tree_view->priv->last_drag_row = ++ gtk_tree_row_reference_new (tree_view->priv->model, path); ++ gtk_tree_path_free (path); ++ } ++ } ++ + /* If we are currently pressing down a button, we don't want to prelight anything else. */ + if ((tree_view->priv->button_pressed_node != NULL) && + (tree_view->priv->button_pressed_node != node)) +@@ -3404,6 +3956,22 @@ + 1, 1, w, h); + } + ++/* Hildon: helper function for dotted slash drawing; ++ returns TRUE or FALSE, depending it there are ++ more nodes at current level */ ++static gboolean ++iter_has_next (GtkTreeModel *model, GtkTreeIter *iter) ++{ ++ GtkTreeIter *check_iter; ++ gboolean result; ++ ++ check_iter = gtk_tree_iter_copy(iter); ++ result = gtk_tree_model_iter_next (model, check_iter); ++ ++ gtk_tree_iter_free (check_iter); ++ return result; ++} ++ + /* Warning: Very scary function. + * Modify at your own risk + * +@@ -3433,16 +4001,25 @@ + guint flags; + gint highlight_x; + gint bin_window_width; +- GtkTreePath *cursor_path; +- GtkTreePath *drag_dest_path; ++ GtkTreePath *cursor_path = NULL; ++ GtkTreePath *drag_dest_path = NULL; + GList *last_column; + gint vertical_separator; + gint horizontal_separator; ++ gint expander_indent; + gint focus_line_width; + gboolean allow_rules; + gboolean has_special_cell; + gboolean rtl; + gint n_visible_columns; ++ gboolean dottedlines, passivefocus, res; ++ ++ /* Hildon: these variables are added for dotted slash drawing ++ (Hierarchical listbox) */ ++ gint i; ++ gint node_elements = 64; ++ gboolean *iter_value = NULL; ++ GtkTreeIter node_iter, parent_iter; + + g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE); + +@@ -3455,8 +4032,12 @@ + "vertical_separator", &vertical_separator, + "allow_rules", &allow_rules, + "focus-line-width", &focus_line_width, ++ "expander_indent", &expander_indent, ++ "passive_focus", &passivefocus, + NULL); + ++ g_object_get (widget, "dotted_lines", &dottedlines, NULL); ++ + if (tree_view->priv->tree == NULL) + { + draw_empty_focus (tree_view, &event->area); +@@ -3478,6 +4059,8 @@ + if (node == NULL) + return TRUE; + ++ iter_value = g_new (gboolean, node_elements); ++ + /* find the path for the node */ + path = _gtk_tree_view_find_path ((GtkTreeView *)widget, + tree, +@@ -3486,11 +4069,25 @@ + &iter, + path); + depth = gtk_tree_path_get_depth (path); ++ ++ node_iter = iter; ++ for (i = depth - 1; i >= 1; i--) ++ { ++ res = gtk_tree_model_iter_parent (tree_view->priv->model, &parent_iter, &node_iter); ++ /* Check, if we should grow array */ ++ if (i >= node_elements - 1) ++ { ++ node_elements *= 2; ++ iter_value = g_renew (gboolean, iter_value, node_elements); ++ if (!iter_value) ++ goto done; ++ } ++ iter_value[i] = iter_has_next (tree_view->priv->model, &parent_iter); ++ node_iter = parent_iter; ++ } ++ gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); + gtk_tree_path_free (path); + +- cursor_path = NULL; +- drag_dest_path = NULL; +- + if (tree_view->priv->cursor) + cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); + +@@ -3533,6 +4130,7 @@ + do + { + gboolean parity; ++ gboolean is_first = TRUE; + gboolean is_separator = FALSE; + + if (tree_view->priv->row_separator_func) +@@ -3570,6 +4168,7 @@ + GtkTreeViewColumn *column = list->data; + const gchar *detail = NULL; + GtkStateType state; ++ gboolean is_last = (rtl ? !list->prev : !list->next); + + if (!column->visible) + continue; +@@ -3660,31 +4259,152 @@ + else + state = GTK_STATE_NORMAL; + +- /* Draw background */ +- gtk_paint_flat_box (widget->style, +- event->window, +- state, +- GTK_SHADOW_NONE, +- &event->area, +- widget, +- detail, +- background_area.x, +- background_area.y, +- background_area.width, +- background_area.height); ++ if (tree_view->priv->pen_focus) ++ { ++ if (node != cursor || ++ (!GTK_WIDGET_HAS_FOCUS (widget) && !passivefocus)) ++ { ++ if ((flags & GTK_CELL_RENDERER_SELECTED) ++ && !tree_view->priv->checkbox_mode) ++ state = GTK_STATE_SELECTED; ++ else ++ state = GTK_STATE_NORMAL; ++ ++ /* Draw background */ ++ gtk_paint_flat_box (widget->style, ++ event->window, ++ state, ++ GTK_SHADOW_NONE, ++ &event->area, ++ widget, ++ detail, ++ background_area.x, ++ background_area.y, ++ background_area.width, ++ background_area.height); ++ } ++ else if ((flags & GTK_CELL_RENDERER_SELECTED) && ++ !tree_view->priv->checkbox_mode && ++ node != cursor) ++ { ++ gtk_paint_flat_box (widget->style, ++ event->window, ++ GTK_STATE_SELECTED, ++ GTK_SHADOW_NONE, ++ &event->area, ++ widget, ++ detail, ++ background_area.x, ++ background_area.y, ++ background_area.width, ++ background_area.height); ++ } ++ } ++ else ++ { ++ /* Draw background */ ++ gtk_paint_flat_box (widget->style, ++ event->window, ++ state, ++ GTK_SHADOW_NONE, ++ &event->area, ++ widget, ++ detail, ++ background_area.x, ++ background_area.y, ++ background_area.width, ++ background_area.height); ++ } ++ ++ /* Hildon change: drawing focus is moved here because it didn't work ++ properly before. Some changes where also made.*/ ++ /* draw the big row-spanning focus rectangle, if needed */ ++ if (node == cursor && ++ (!passivefocus || GTK_WIDGET_HAS_FOCUS (widget))) ++ { ++ gtk_paint_focus (widget->style, ++ event->window, ++ GTK_STATE_ACTIVE, ++ &event->area, ++ widget, ++ (is_first ++ ? (is_last ? "full" : "left") ++ : (is_last ? "right" : "middle")), ++ background_area.x - (is_first ? 0 : horizontal_separator / 2), ++ background_area.y - vertical_separator / 2, ++ background_area.width + (is_first ? 0 : (is_last ? horizontal_separator / 2 : horizontal_separator)), ++ background_area.height + vertical_separator); ++ ++ is_first = FALSE; ++ } ++ else if (node == cursor && passivefocus && ++ !GTK_WIDGET_HAS_FOCUS (widget)) ++ { ++ GtkStyle *style = gtk_rc_get_style_by_paths (gtk_widget_get_settings (widget), ++ "hildon-focus", ++ NULL, ++ G_TYPE_NONE); ++ gtk_style_attach (style, event->window); ++ ++ gtk_paint_focus (style, event->window, GTK_STATE_SELECTED, ++ &event->area, widget, ++ (is_first ++ ? (is_last ? "full" : "left") ++ : (is_last ? "right" : "middle")), ++ background_area.x - (is_first ? 0 : horizontal_separator / 2), ++ background_area.y - vertical_separator / 2, ++ background_area.width + (is_first ? 0 : (is_last ? horizontal_separator / 2 : horizontal_separator)), ++ background_area.height + vertical_separator); ++ ++ is_first = FALSE; ++ } ++ ++ if (node == cursor) ++ { ++ gint width, x_offset; ++ GtkStateType focus_rect_state; ++ focus_rect_state = ++ flags & GTK_CELL_RENDERER_FOCUSED ? GTK_STATE_ACTIVE : ++ (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT : ++ (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : ++ (flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED : ++ GTK_STATE_NORMAL))); ++ ++ gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, NULL); ++ gdk_drawable_get_size (tree_view->priv->bin_window, &width, NULL); ++ } + + if (gtk_tree_view_is_expander_column (tree_view, column) && + TREE_VIEW_DRAW_EXPANDERS(tree_view)) + { ++ gint px, px2, py, i; ++ ++ if (depth <= 1) ++ px = 0; ++ else ++ px = (depth - 1) * tree_view->priv->expander_size + ++ (depth - 2) * expander_indent; ++ ++ /* Hildonlike hack for making the indent look better. ++ * indent is added to all rows except the first one */ ++ + if (!rtl) +- cell_area.x += depth * tree_view->priv->expander_size; +- cell_area.width -= depth * tree_view->priv->expander_size; ++ cell_area.x += depth * tree_view->priv->expander_size + (depth-1) * expander_indent; ++ cell_area.width -= depth * tree_view->priv->expander_size + (depth-1) * expander_indent; + + /* If we have an expander column, the highlight underline + * starts with that column, so that it indicates which + * level of the tree we're dropping at. + */ + highlight_x = cell_area.x; ++ ++ if (!GTK_WIDGET_IS_SENSITIVE (widget)) ++ { ++ flags &= ~ (GTK_CELL_RENDERER_PRELIT + GTK_CELL_RENDERER_INSENSITIVE + ++ GTK_CELL_RENDERER_FOCUSED); ++ flags &= GTK_CELL_RENDERER_INSENSITIVE; ++ } ++ + if (is_separator) + gtk_paint_hline (widget->style, + event->window, +@@ -3702,6 +4422,48 @@ + &cell_area, + &event->area, + flags); ++ ++ /* Hildon dotted slash line drawing for Hierarchical Listbox ++ widget */ ++ if (dottedlines) ++ { ++ py = cell_area.y + cell_area.height / 2; ++ px2 = depth * tree_view->priv->expander_size + ++ (depth - 1) * expander_indent; ++ ++ gdk_gc_set_line_attributes (widget->style->fg_gc[GTK_WIDGET_STATE (widget)], ++ 1, GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_BEVEL); ++ ++ gdk_draw_line (tree_view->priv->bin_window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], ++ px, py, px2, py); ++ ++ if (depth > 1) ++ { ++ gdk_draw_line (tree_view->priv->bin_window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], ++ px, cell_area.y, px, py); ++ if (iter_has_next (tree_view->priv->model, &iter)) ++ { ++ gdk_draw_line (tree_view->priv->bin_window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], ++ px, py, px, cell_area.y + cell_area.height); ++ } ++ } ++ ++ if (node->children) ++ { ++ gdk_draw_line (tree_view->priv->bin_window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], ++ px2, py, px2, cell_area.y + cell_area.height); ++ } ++ for (i = depth - 1; i >= 2; i--) ++ { ++ if (iter_value[i]) ++ { ++ px = (i - 1)* tree_view->priv->expander_size + (i - 2) * expander_indent; ++ gdk_draw_line (tree_view->priv->bin_window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], ++ px, cell_area.y, px, cell_area.y + cell_area.height); ++ } ++ } ++ } ++ + if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT) + { + gint x, y; +@@ -3803,6 +4565,8 @@ + } + } + ++ /* Hildon: disabled this */ ++#if 0 + /* draw the big row-spanning focus rectangle, if needed */ + if (!has_special_cell && node == cursor && + GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) && +@@ -3830,6 +4594,7 @@ + width, + ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))); + } ++#endif + + y_offset += max_height; + if (node->children) +@@ -3847,6 +4612,17 @@ + has_child = gtk_tree_model_iter_children (tree_view->priv->model, + &iter, + &parent); ++ ++ /* Check if we need to grow array */ ++ if (depth >= node_elements - 1) ++ { ++ node_elements *= 2; ++ iter_value = g_renew (gboolean, iter_value, node_elements); ++ if (!iter_value) ++ goto done; ++ } ++ iter_value[depth] = iter_has_next (tree_view->priv->model, &parent); ++ + depth++; + + /* Sanity Check! */ +@@ -3897,6 +4673,9 @@ + if (drag_dest_path) + gtk_tree_path_free (drag_dest_path); + ++ if (iter_value) ++ g_free (iter_value); ++ + return FALSE; + } + +@@ -4179,6 +4958,63 @@ + + rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL); + ++ /* Special Hildon keyboard interactions */ ++ if (event->keyval == GDK_Escape) ++ gtk_tree_selection_unselect_all (tree_view->priv->selection); ++ ++ if (event->keyval == GDK_Return && ++ gtk_tree_row_reference_valid (tree_view->priv->cursor)) ++ { ++ gboolean force_list_kludge; ++ ++ g_object_get (widget, "force_list_kludge", &force_list_kludge, NULL); ++ if (force_list_kludge || ++ (gtk_tree_model_get_flags (tree_view->priv->model) & ++ GTK_TREE_MODEL_LIST_ONLY)) ++ { ++ /* text listbox */ ++ if (tree_view->priv->checkbox_mode) ++ { ++ /* multisel with checkboxes: select key toggles focused */ ++ gtk_tree_view_real_toggle_cursor_row (tree_view); ++ } ++ else ++ { ++ /* no checkboxes: select key activates focused */ ++ GtkTreePath *cursor_path = ++ gtk_tree_row_reference_get_path (tree_view->priv->cursor); ++ ++ gtk_tree_view_row_activated (tree_view, cursor_path, ++ tree_view->priv->focus_column); ++ ++ gtk_tree_path_free (cursor_path); ++ } ++ } ++ else ++ { ++ /* hierarchical listbox */ ++ GtkTreePath *cursor_path; ++ GtkRBTree *tree; ++ GtkRBNode *node; ++ ++ cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); ++ _gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node); ++ ++ if (node->children == NULL) ++ gtk_tree_view_real_expand_row (tree_view, ++ cursor_path, ++ tree, ++ node, ++ FALSE, TRUE); ++ else ++ gtk_tree_view_real_collapse_row (tree_view, ++ cursor_path, ++ tree, ++ node, ++ TRUE); ++ } ++ } ++ + if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG)) + { + if (event->keyval == GDK_Escape) +@@ -4420,6 +5256,7 @@ + + /* FIXME Is this function necessary? Can I get an enter_notify event + * w/o either an expose event or a mouse motion event? ++ * Hildon => it is necessary to make pen dragging work correctly + */ + static gboolean + gtk_tree_view_enter_notify (GtkWidget *widget, +@@ -4434,6 +5271,10 @@ + + tree_view = GTK_TREE_VIEW (widget); + ++ /* stop "automatic" pen dragging */ ++ tree_view->priv->pen_drag_active = FALSE; ++ remove_scroll_timeout (tree_view); ++ + /* Sanity check it */ + if (event->window != tree_view->priv->bin_window) + return FALSE; +@@ -4463,6 +5304,9 @@ + tree_view = GTK_TREE_VIEW (widget); + tree_view->priv->pressed_button = -1; + ++ if (tree_view->priv->pen_down && tree_view->priv->queued_select_row == NULL) ++ tree_view->priv->pen_drag_active = TRUE; ++ + if (event->mode == GDK_CROSSING_GRAB) + return TRUE; + +@@ -4535,6 +5379,7 @@ + gboolean retval = FALSE; + gboolean is_separator = FALSE; + gint focus_pad; ++ gint expander_indent; + + /* double check the row needs validating */ + if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) && +@@ -4551,6 +5396,7 @@ + gtk_widget_style_get (GTK_WIDGET (tree_view), + "focus-padding", &focus_pad, + "horizontal_separator", &horizontal_separator, ++ "expander_indent", &expander_indent, + NULL); + + for (list = tree_view->priv->columns; list; list = list->next) +@@ -4577,13 +5423,16 @@ + { + height = MAX (height, tmp_height); + height = MAX (height, tree_view->priv->expander_size); ++ ++ /* Hildon addition */ ++ height -= 1; + } + else + height = 2 + 2 * focus_pad; + + if (gtk_tree_view_is_expander_column (tree_view, column) && TREE_VIEW_DRAW_EXPANDERS (tree_view)) + { +- tmp_width = tmp_width + horizontal_separator + depth * (tree_view->priv->expander_size); ++ tmp_width = tmp_width + horizontal_separator + depth * (tree_view->priv->expander_size) + (depth - 1) * expander_indent; + } + else + tmp_width = tmp_width + horizontal_separator; +@@ -5585,6 +6434,16 @@ + #endif /* 0 */ + + static void ++add_scroll_timeout (GtkTreeView *tree_view) ++{ ++ if (tree_view->priv->scroll_timeout == 0) ++ { ++ tree_view->priv->scroll_timeout = ++ g_timeout_add (150, scroll_row_timeout, tree_view); ++ } ++} ++ ++static void + remove_scroll_timeout (GtkTreeView *tree_view) + { + if (tree_view->priv->scroll_timeout != 0) +@@ -6130,10 +6989,9 @@ + tree_view->priv->open_dest_timeout = + g_timeout_add (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view); + } +- else if (tree_view->priv->scroll_timeout == 0) ++ else + { +- tree_view->priv->scroll_timeout = +- g_timeout_add (150, scroll_row_timeout, tree_view); ++ add_scroll_timeout (tree_view); + } + + if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE)) +@@ -6901,8 +7759,6 @@ + GtkMovementStep step, + gint count) + { +- GdkModifierType state; +- + g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE); + g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS || + step == GTK_MOVEMENT_VISUAL_POSITIONS || +@@ -6919,6 +7775,8 @@ + GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS); + gtk_widget_grab_focus (GTK_WIDGET (tree_view)); + ++ /* Hildon: Ignore ctrl and shift */ ++#if 0 + if (gtk_get_current_event_state (&state)) + { + if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK) +@@ -6926,6 +7784,7 @@ + if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) + tree_view->priv->shift_pressed = TRUE; + } ++#endif + /* else we assume not pressed */ + + switch (step) +@@ -7092,6 +7951,27 @@ + done: + if (!tree_view->priv->fixed_height_mode) + install_presize_handler (tree_view); ++ ++ /* Hildon: has row now been dimmed? If so, unselect it */ ++ _gtk_tree_view_find_node (tree_view, path, &tree, &node); ++ if (!_gtk_tree_selection_is_row_selectable (tree_view->priv->selection, ++ node, ++ path)) ++ { ++ if (gtk_tree_path_compare (path, ++ gtk_tree_row_reference_get_path(tree_view->priv->cursor)) ++ == 0) ++ { ++ gtk_tree_row_reference_free (tree_view->priv->cursor); ++ tree_view->priv->cursor = NULL; ++ } ++ ++ gtk_tree_selection_unselect_path (tree_view->priv->selection, path); ++ gtk_tree_view_collapse_row (tree_view, path); ++ } ++ ++ check_if_can_focus (tree_view); ++ + if (free_path) + gtk_tree_path_free (path); + } +@@ -7196,6 +8076,11 @@ + install_presize_handler (tree_view); + if (free_path) + gtk_tree_path_free (path); ++ ++ /* Hildon: after a focusable row has been added, the ++ entire widget becomes focusable if it wasn't before */ ++ if ((GTK_WIDGET_FLAGS (tree_view) & GTK_CAN_FOCUS) == 0) ++ check_if_can_focus (tree_view); + } + + static void +@@ -7295,6 +8180,16 @@ + _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data); + } + ++static gboolean ++check_if_can_focus_idle (GtkTreeView *tree_view) ++{ ++ check_if_can_focus (tree_view); ++ ++ tree_view->priv->check_if_can_focus_idle_id = 0; ++ ++ return FALSE; ++} ++ + static void + gtk_tree_view_row_deleted (GtkTreeModel *model, + GtkTreePath *path, +@@ -7357,6 +8252,11 @@ + tree_view->priv->tree = NULL; + + _gtk_rbtree_remove (tree); ++ ++ /* Hildon: no nodes -> not focusable */ ++ /* FIXME this looks superfluos to me. check_if_can_focus is called ++ * at the end of this function .. -- Jorn */ ++ GTK_WIDGET_UNSET_FLAGS (tree_view, GTK_CAN_FOCUS); + } + else + { +@@ -7375,6 +8275,13 @@ + + if (selection_changed) + g_signal_emit_by_name (tree_view->priv->selection, "changed"); ++ ++ /* FIXME whacky hack to work around the treeview not being in a clean state ++ * when in a tree a row has been removed, but has_child_toggled not been ++ * called yet */ ++ if (tree_view->priv->check_if_can_focus_idle_id == 0) ++ tree_view->priv->check_if_can_focus_idle_id = ++ g_idle_add ((GSourceFunc) check_if_can_focus_idle, tree_view); + } + + static void +@@ -7508,6 +8415,7 @@ + GList *list; + GtkTreeViewColumn *tmp_column = NULL; + gint total_width; ++ gint expander_indent, depth; + gboolean indent_expanders; + gboolean rtl; + +@@ -7535,14 +8443,19 @@ + + gtk_widget_style_get (GTK_WIDGET (tree_view), + "indent_expanders", &indent_expanders, ++ "expander_indent", &expander_indent, + NULL); + ++ /* Hildonlike hack for making the indent look better. ++ * indent is added to all rows except the first one */ ++ depth = _gtk_rbtree_get_depth (tree); ++ + if (indent_expanders) + { + if (rtl) +- x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree); ++ x_offset -= tree_view->priv->expander_size * depth + (depth) * expander_indent; + else +- x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree); ++ x_offset += tree_view->priv->expander_size * depth + (depth) * expander_indent; + } + if (x1) + { +@@ -7617,9 +8530,11 @@ + gboolean retval = FALSE; + gint tmpheight; + gint horizontal_separator; ++ gint expander_indent; + + gtk_widget_style_get (GTK_WIDGET (tree_view), + "horizontal_separator", &horizontal_separator, ++ "expander_indent", &expander_indent, + NULL); + + if (height) +@@ -7657,7 +8572,7 @@ + if (gtk_tree_view_is_expander_column (tree_view, column) && + TREE_VIEW_DRAW_EXPANDERS (tree_view)) + { +- if (depth * tree_view->priv->expander_size + horizontal_separator + width > column->requested_width) ++ if ((depth - 1) *expander_indent + depth * tree_view->priv->expander_size + horizontal_separator + width > column->requested_width) + { + _gtk_tree_view_column_cell_set_dirty (column, TRUE); + retval = TRUE; +@@ -7747,6 +8662,7 @@ + } + } + ++#if 0 + static void + gtk_tree_view_clamp_column_visible (GtkTreeView *tree_view, + GtkTreeViewColumn *column) +@@ -7762,6 +8678,7 @@ + gtk_adjustment_set_value (tree_view->priv->hadjustment, + column->button->allocation.x); + } ++#endif + + /* This function could be more efficient. I'll optimize it if profiling seems + * to imply that it is important */ +@@ -8290,7 +9207,7 @@ + + area.x = x_offset; + area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator); +- area.width = expander_size + 2; ++ area.width = expander_size; + area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator)); + + if (node == tree_view->priv->button_pressed_node) +@@ -8397,7 +9314,10 @@ + GtkRBNode *cursor_node = NULL; + GtkRBTree *new_cursor_tree = NULL; + GtkRBNode *new_cursor_node = NULL; ++ GtkRBTree *old_cursor_tree; ++ GtkRBNode *old_cursor_node; + GtkTreePath *cursor_path = NULL; ++ GtkTreePath *new_cursor_path = NULL; + + if (! GTK_WIDGET_HAS_FOCUS (tree_view)) + return; +@@ -8415,12 +9335,30 @@ + if (cursor_tree == NULL) + /* FIXME: we lost the cursor; should we get the first? */ + return; +- if (count == -1) +- _gtk_rbtree_prev_full (cursor_tree, cursor_node, +- &new_cursor_tree, &new_cursor_node); +- else +- _gtk_rbtree_next_full (cursor_tree, cursor_node, +- &new_cursor_tree, &new_cursor_node); ++ ++ old_cursor_tree = cursor_tree; ++ old_cursor_node = cursor_node; ++ do { ++ if (count == -1) ++ _gtk_rbtree_prev_full (old_cursor_tree, old_cursor_node, ++ &new_cursor_tree, &new_cursor_node); ++ else ++ _gtk_rbtree_next_full (old_cursor_tree, old_cursor_node, ++ &new_cursor_tree, &new_cursor_node); ++ ++ if (new_cursor_node) ++ { ++ if (new_cursor_path) ++ gtk_tree_path_free (new_cursor_path); ++ ++ new_cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node); ++ old_cursor_tree = new_cursor_tree; ++ old_cursor_node = new_cursor_node; ++ } ++ } while (new_cursor_node && ++ !_gtk_tree_selection_is_row_selectable (tree_view->priv->selection, ++ new_cursor_node, ++ new_cursor_path)); + + /* + * If the list has only one item and multi-selection is set then select +@@ -8450,7 +9388,33 @@ + if (new_cursor_node) + { + cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node); +- gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE); ++ ++ if (tree_view->priv->checkbox_mode) ++ gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, TRUE); ++ else ++ gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE); ++ ++ if (tree_view->priv->pen_drag_active) ++ { ++ if (gtk_tree_path_compare (gtk_tree_row_reference_get_path (tree_view->priv->last_drag_row), ++ gtk_tree_row_reference_get_path (tree_view->priv->first_drag_row)) == 0) ++ tree_view->priv->pen_drag_reverse = FALSE; ++ ++ if (tree_view->priv->pen_drag_reverse) ++ { ++ gtk_tree_selection_select_path (tree_view->priv->selection, ++ cursor_path); ++ gtk_tree_selection_unselect_path (tree_view->priv->selection, ++ gtk_tree_row_reference_get_path (tree_view->priv->last_drag_row)); ++ } ++ ++ gtk_tree_row_reference_free (tree_view->priv->last_drag_row); ++ ++ tree_view->priv->last_drag_row = ++ gtk_tree_row_reference_new (tree_view->priv->model, ++ cursor_path); ++ } ++ + gtk_tree_path_free (cursor_path); + } + else +@@ -8467,6 +9431,8 @@ + { + GtkRBTree *cursor_tree = NULL; + GtkRBNode *cursor_node = NULL; ++ GtkRBTree *old_cursor_tree = NULL; ++ GtkRBNode *old_cursor_node = NULL; + GtkTreePath *cursor_path = NULL; + gint y; + gint vertical_separator; +@@ -8474,6 +9440,9 @@ + if (! GTK_WIDGET_HAS_FOCUS (tree_view)) + return; + ++ if (tree_view->priv->tree == NULL) ++ return; ++ + if (gtk_tree_row_reference_valid (tree_view->priv->cursor)) + cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); + else +@@ -8504,7 +9473,65 @@ + + _gtk_rbtree_find_offset (tree_view->priv->tree, y, &cursor_tree, &cursor_node); + cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node); +- g_return_if_fail (cursor_path != NULL); ++ ++ while (cursor_node && ++ !_gtk_tree_selection_is_row_selectable (tree_view->priv->selection, ++ cursor_node, ++ cursor_path)) ++ { ++ old_cursor_tree = cursor_tree; ++ old_cursor_node = cursor_node; ++ ++ if (count < 0) ++ _gtk_rbtree_prev_full (old_cursor_tree, old_cursor_node, ++ &cursor_tree, &cursor_node); ++ else ++ _gtk_rbtree_next_full (old_cursor_tree, old_cursor_node, ++ &cursor_tree, &cursor_node); ++ ++ if (cursor_path) ++ { ++ gtk_tree_path_free(cursor_path); ++ cursor_path = NULL; ++ } ++ ++ if (cursor_node) ++ cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node); ++ } ++ ++ if (cursor_path == NULL) ++ { ++ /* looks like we reached the end without finding a sensitive row, ++ so search backwards and try to find the last sensitive row as ++ the next best thing */ ++ _gtk_rbtree_find_offset (tree_view->priv->tree, y, &cursor_tree, &cursor_node); ++ cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node); ++ while (cursor_node && ++ !_gtk_tree_selection_is_row_selectable (tree_view->priv->selection, ++ cursor_node, ++ cursor_path)) ++ { ++ old_cursor_tree = cursor_tree; ++ old_cursor_node = cursor_node; ++ ++ if (count < 0) ++ _gtk_rbtree_next_full (old_cursor_tree, old_cursor_node, ++ &cursor_tree, &cursor_node); ++ else ++ _gtk_rbtree_prev_full (old_cursor_tree, old_cursor_node, ++ &cursor_tree, &cursor_node); ++ ++ if (cursor_path) ++ { ++ gtk_tree_path_free(cursor_path); ++ cursor_path = NULL; ++ } ++ ++ if (cursor_node) ++ cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node); ++ } ++ } ++ + gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE); + gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node); + gtk_tree_path_free (cursor_path); +@@ -8514,6 +9541,8 @@ + gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view, + gint count) + { ++ /* Hildon: cursor is always displayed on an entire row anyway */ ++#if 0 + GtkRBTree *cursor_tree = NULL; + GtkRBNode *cursor_node = NULL; + GtkTreePath *cursor_path = NULL; +@@ -8589,12 +9618,15 @@ + g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0); + } + gtk_tree_view_clamp_column_visible (tree_view, tree_view->priv->focus_column); ++#endif + } + + static void + gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view, + gint count) + { ++ /* Hildon: cursor is always displayed on an entire row anyway */ ++#if 0 + GtkRBTree *cursor_tree; + GtkRBNode *cursor_node; + GtkTreePath *path; +@@ -8631,6 +9663,7 @@ + path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node); + gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE); + gtk_tree_path_free (path); ++#endif + } + + static gboolean +@@ -8670,7 +9703,7 @@ + GtkTreePath *cursor_path = NULL; + GtkTreeSelectMode mode = 0; + +- if (! GTK_WIDGET_HAS_FOCUS (tree_view)) ++ if (! GTK_WIDGET_HAS_FOCUS (tree_view) && !tree_view->priv->checkbox_mode) + return FALSE; + + if (tree_view->priv->cursor) +@@ -8731,7 +9764,7 @@ + GtkRBNode *cursor_node = NULL; + GtkTreePath *cursor_path = NULL; + +- if (! GTK_WIDGET_HAS_FOCUS (tree_view)) ++ if (! GTK_WIDGET_HAS_FOCUS (tree_view) && !tree_view->priv->checkbox_mode) + return FALSE; + + cursor_path = NULL; +@@ -8774,6 +9807,7 @@ + GtkTreePath *cursor_path = NULL; + GtkRBTree *tree; + GtkRBNode *node; ++ gboolean hildon_row; + + if (! GTK_WIDGET_HAS_FOCUS (tree_view)) + return FALSE; +@@ -8796,10 +9830,32 @@ + && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL) + expand = !expand; + +- if (expand) +- gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE); ++ /* Keyboard Navigation: if we can't expand/collapse row, we should either move active focus ++ to child item (right arrow) or move active focus to the parent item (left arrow) */ ++ if (expand) ++ { ++ hildon_row = gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, ++ node, open_all, TRUE); ++ ++ if (!hildon_row || !node->children) ++ g_signal_emit_by_name (gtk_widget_get_ancestor (GTK_WIDGET (tree_view), ++ GTK_TYPE_WINDOW), ++ "move_focus", ++ GTK_DIR_TAB_FORWARD); ++ } + else +- gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE); ++ { ++ hildon_row = gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE); ++ ++ if (hildon_row == FALSE) ++ { ++ g_signal_emit_by_name (gtk_widget_get_ancestor (GTK_WIDGET(tree_view), ++ GTK_TYPE_WINDOW), ++ "move_focus", ++ GTK_DIR_TAB_BACKWARD); ++ gtk_tree_view_real_select_cursor_parent (tree_view); ++ } ++ } + + gtk_tree_path_free (cursor_path); + +@@ -9327,6 +10383,14 @@ + tree_view->priv->last_button_press_2 = NULL; + gtk_tree_row_reference_free (tree_view->priv->scroll_to_path); + tree_view->priv->scroll_to_path = NULL; ++ gtk_tree_row_reference_free (tree_view->priv->first_drag_row); ++ tree_view->priv->first_drag_row = NULL; ++ gtk_tree_row_reference_free (tree_view->priv->last_drag_row); ++ tree_view->priv->last_drag_row = NULL; ++ gtk_tree_row_reference_free (tree_view->priv->queued_expand_row); ++ tree_view->priv->queued_expand_row = NULL; ++ gtk_tree_row_reference_free (tree_view->priv->queued_select_row); ++ tree_view->priv->queued_select_row = NULL; + + tree_view->priv->scroll_to_column = NULL; + +@@ -9402,6 +10466,8 @@ + install_presize_handler (tree_view); + } + ++ check_if_can_focus (tree_view); ++ + g_object_notify (G_OBJECT (tree_view), "model"); + + if (GTK_WIDGET_REALIZED (tree_view)) +@@ -9744,6 +10810,10 @@ + G_CALLBACK (column_sizing_notify), + tree_view); + ++ g_signal_handlers_disconnect_by_func (column, ++ G_CALLBACK (update_checkbox_mode), ++ tree_view); ++ + _gtk_tree_view_column_unset_tree_view (column); + + tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column); +@@ -9773,6 +10843,8 @@ + g_object_unref (column); + g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0); + ++ update_checkbox_mode (NULL, NULL, tree_view); ++ + return tree_view->priv->n_columns; + } + +@@ -9815,6 +10887,9 @@ + g_signal_connect (column, "notify::sizing", + G_CALLBACK (column_sizing_notify), tree_view); + ++ g_signal_connect (column, "notify::visible", ++ G_CALLBACK (update_checkbox_mode), tree_view); ++ + tree_view->priv->columns = g_list_insert (tree_view->priv->columns, + column, position); + tree_view->priv->n_columns++; +@@ -9838,6 +10913,9 @@ + + g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0); + ++ update_checkbox_mode (NULL, NULL, tree_view); ++ check_if_can_focus (tree_view); ++ + return tree_view->priv->n_columns; + } + +@@ -10295,7 +11373,6 @@ + GtkTreeViewColumn *column) + { + g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); +- + g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column); + } + +@@ -10560,6 +11637,16 @@ + GtkTreeIter iter; + GtkTreeIter temp; + gboolean expand; ++ gint vertical_separator; ++ GtkTreePath *collapse_path; ++ GtkRBTree *tree2; ++ GtkRBNode *node2; ++ GtkTreePath *child_path = NULL; ++ GtkTreeIter parent_iter; ++ GtkTreeIter child_iter; ++ GdkRectangle visible_rect; ++ gint children, n; ++ guint total_height; + + remove_auto_expand_timeout (tree_view); + +@@ -10573,8 +11660,12 @@ + if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter)) + return FALSE; + ++ /* Hildon: insensitive rows cannot be expanded */ ++ if (!_gtk_tree_selection_is_row_selectable (tree_view->priv->selection, ++ node, path)) ++ return FALSE; + +- if (node->children && open_all) ++ if (node->children && open_all) + { + gboolean retval = FALSE; + GtkTreePath *tmp_path = gtk_tree_path_copy (path); +@@ -10603,6 +11694,37 @@ + return retval; + } + ++ /* Hildon: collapse other items in the same level */ ++ gtk_widget_style_get (GTK_WIDGET (tree_view), ++ "vertical_separator", &vertical_separator, NULL); ++ ++ /* find the first child */ ++ collapse_path = gtk_tree_path_copy (path); ++ while (gtk_tree_path_prev (collapse_path)) ++ ; ++ ++ do { ++ if (gtk_tree_path_compare (collapse_path, path) != 0) ++ { ++ _gtk_tree_view_find_node (tree_view, collapse_path, &tree2, &node2); ++ ++ if (tree2 == NULL) ++ /* end reached already */ ++ break; ++ ++ if (node2->children != NULL && ++ gtk_tree_view_real_collapse_row (tree_view, collapse_path, ++ tree2, node2, FALSE)) ++ /* no need to do anything else since only one row may ++ be expanded on any particular level at any time */ ++ break; ++ } ++ ++ gtk_tree_path_next (collapse_path); ++ } while (1); ++ ++ gtk_tree_path_free (collapse_path); ++ + g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand); + + if (expand) +@@ -10643,6 +11765,42 @@ + GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED); + } + ++ /* autoscroll if necessary */ ++ validate_visible_area (tree_view); ++ gtk_tree_model_get_iter (tree_view->priv->model, &parent_iter, path); ++ _gtk_tree_view_find_node (tree_view, path, &tree2, &node2); ++ validate_row (tree_view, tree2, node2, &parent_iter, path); ++ total_height = CELL_HEIGHT (node2, vertical_separator); ++ children = gtk_tree_model_iter_n_children (tree_view->priv->model, &parent_iter); ++ for (n = 0; n < children; n++) ++ { ++ gtk_tree_model_iter_nth_child (tree_view->priv->model, ++ &child_iter, &parent_iter, n); ++ ++ /* must free here so the path of last child is kept for later */ ++ if (child_path != NULL) ++ gtk_tree_path_free (child_path); ++ ++ child_path = gtk_tree_model_get_path (tree_view->priv->model, &child_iter); ++ _gtk_tree_view_find_node (tree_view, child_path, &tree2, &node2); ++ ++ if (CELL_HEIGHT (node2, 0) == 0) ++ validate_row (tree_view, tree2, node2, &child_iter, child_path); ++ ++ total_height += CELL_HEIGHT (node2, vertical_separator); ++ } ++ ++ gtk_tree_view_get_visible_rect (tree_view, &visible_rect); ++ ++ /* KNOWN BUG: If no autocollapse was performed earlier above, these calls ++ to gtk_tree_view_scroll_to_cell do nothing although they should. */ ++ if (total_height > visible_rect.height) ++ gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.0, 0.0); ++ else ++ gtk_tree_view_scroll_to_cell (tree_view, child_path, NULL, FALSE, 0.0, 0.0); ++ ++ gtk_tree_path_free (child_path); ++ + install_presize_handler (tree_view); + + g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path); +@@ -11070,6 +12228,16 @@ + GtkRBTree *tree = NULL; + GtkRBNode *node = NULL; + ++ _gtk_tree_view_find_node (tree_view, path, &tree, &node); ++ ++ /* Hildon: cursor cannot move to an insensitive row */ ++ if (!_gtk_tree_selection_is_row_selectable (tree_view->priv->selection, ++ node, path)) ++ { ++ g_signal_emit (tree_view, tree_view_signals[ROW_INSENSITIVE], 0, path); ++ return; ++ } ++ + if (gtk_tree_row_reference_valid (tree_view->priv->cursor)) + { + GtkTreePath *cursor_path; +@@ -11083,7 +12251,6 @@ + tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), + tree_view->priv->model, + path); +- _gtk_tree_view_find_node (tree_view, path, &tree, &node); + if (tree != NULL) + { + GtkRBTree *new_tree = NULL; +@@ -11093,7 +12260,8 @@ + { + GtkTreeSelectMode mode = 0; + +- if (tree_view->priv->ctrl_pressed) ++ if (tree_view->priv->ctrl_pressed || ++ tree_view->priv->pen_drag_active) + mode |= GTK_TREE_SELECT_MODE_TOGGLE; + if (tree_view->priv->shift_pressed) + mode |= GTK_TREE_SELECT_MODE_EXTEND; +@@ -11213,6 +12381,9 @@ + { + g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); + g_return_if_fail (path != NULL); ++ ++ tree_view->priv->pen_focus = FALSE; ++ + if (focus_column) + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (focus_column)); + if (focus_cell) +@@ -11414,6 +12585,7 @@ + GtkRBNode *node = NULL; + gint vertical_separator; + gint horizontal_separator; ++ gint expander_indent; + + g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); + g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column)); +@@ -11424,6 +12596,7 @@ + gtk_widget_style_get (GTK_WIDGET (tree_view), + "vertical_separator", &vertical_separator, + "horizontal_separator", &horizontal_separator, ++ "expander_indent", &expander_indent, + NULL); + + rect->x = 0; +@@ -11453,9 +12626,11 @@ + TREE_VIEW_DRAW_EXPANDERS (tree_view)) + { + gint depth = gtk_tree_path_get_depth (path) - 1; ++ gint adjust; + +- rect->x += depth * tree_view->priv->expander_size; +- rect->width -= depth * tree_view->priv->expander_size; ++ adjust = depth * tree_view->priv->expander_size + (depth - 1) * expander_indent; ++ rect->x += adjust; ++ rect->width -= adjust; + rect->width = MAX (rect->width, 0); + } + } +@@ -12077,8 +13252,13 @@ + if (gtk_tree_view_is_expander_column (tree_view, column) && + TREE_VIEW_DRAW_EXPANDERS(tree_view)) + { +- cell_area.x += depth * tree_view->priv->expander_size; +- cell_area.width -= depth * tree_view->priv->expander_size; ++ gint adjust, expander_indent; ++ ++ gtk_widget_style_get (widget, "expander_indent", &expander_indent, NULL); ++ ++ adjust = depth * tree_view->priv->expander_size + (depth - 1) * expander_indent; ++ cell_area.x += adjust; ++ cell_area.width -= adjust; + } + + if (gtk_tree_view_column_cell_is_visible (column)) +@@ -13062,3 +14242,138 @@ + tree_view->priv->pressed_button = -1; + } + ++/* Hildon addition: iterates through columns and cells, looks for ++ a cell with "activatable" attribute and sets or unsets ++ priv->checkbox_mode accordingly (except when checkbox mode ++ is disabled by unsetting allow_checkbox_mode). ++ */ ++static void ++update_checkbox_mode (GObject *object, GParamSpec *pspec, gpointer data) ++{ ++ GtkTreeView *tree_view = GTK_TREE_VIEW (data); ++ GList *columns = gtk_tree_view_get_columns (tree_view); ++ GList *list; ++ gboolean allow_checkbox_mode; ++ ++ g_object_get (GTK_WIDGET (data), ++ "allow_checkbox_mode", &allow_checkbox_mode, NULL); ++ g_return_if_fail (allow_checkbox_mode); ++ ++ for (list = columns; list; list = list->next) ++ { ++ GtkTreeViewColumn *col = GTK_TREE_VIEW_COLUMN (list->data); ++ if (gtk_tree_view_column_get_visible (col) && ++ _gtk_tree_view_column_has_activatable_cell (col)) ++ { ++ /* checkbox column found */ ++ tree_view->priv->checkbox_mode = TRUE; ++ g_list_free (columns); ++ return; ++ } ++ } ++ ++ /* no checkbox column was found */ ++ tree_view->priv->checkbox_mode = FALSE; ++ g_list_free (columns); ++} ++ ++static void ++set_dotted_lines (GtkTreeView *tree_view, gboolean enable) ++{ ++ if (enable != tree_view->priv->dotted_lines) ++ { ++ tree_view->priv->dotted_lines = enable; ++ gtk_widget_queue_draw (GTK_WIDGET (tree_view)); ++ } ++} ++ ++/* This function is used to ensure two things: ++ * - in single selection mode, focus will always equal selection ++ * - in multiple selection mode, focus is removed if cursor row is ++ * explicitly unselected ++ */ ++static void ++selection_changed (GtkTreeSelection *selection, gpointer data) ++{ ++ GtkTreeView *tree_view = GTK_TREE_VIEW(data); ++ GtkTreePath *cursor_path = NULL; ++ GtkTreeIter iter; ++ ++ /* if there are checkboxes, cursor row doesn't have to be selected */ ++ if (tree_view->priv->checkbox_mode) ++ return; ++ ++ if (gtk_tree_row_reference_valid (tree_view->priv->cursor)) ++ cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); ++ ++ if (cursor_path == NULL || ++ !gtk_tree_selection_path_is_selected (selection, cursor_path)) ++ { ++ GtkTreePath *selected_path; ++ GtkRBTree *tree = NULL; ++ GtkRBNode *node = NULL; ++ ++ if (gtk_tree_selection_get_mode (selection) != GTK_SELECTION_MULTIPLE && ++ gtk_tree_selection_get_selected (selection, NULL, &iter)) ++ { ++ selected_path = gtk_tree_model_get_path (tree_view->priv->model, ++ &iter); ++ gtk_tree_view_real_set_cursor (tree_view, selected_path, TRUE, TRUE); ++ _gtk_tree_view_find_node (tree_view, selected_path, &tree, &node); ++ gtk_tree_view_clamp_node_visible (tree_view, tree, node); ++ gtk_tree_path_free (selected_path); ++ gtk_widget_grab_focus (GTK_WIDGET (tree_view)); ++ } ++ else ++ { ++ gtk_tree_row_reference_free (tree_view->priv->cursor); ++ tree_view->priv->cursor = NULL; ++ } ++ } ++ ++ if (cursor_path) ++ gtk_tree_path_free (cursor_path); ++} ++ ++/* Helper function for ensuring that GtkTreeView is focusable ++ * if and only if it contains at least one sensitive top-level row. ++ * Should be called whenever the existence of a sensitive top-level row ++ * might have changed. ++ */ ++static void ++check_if_can_focus (GtkTreeView *tree_view) ++{ ++ GtkTreeModel *model = gtk_tree_view_get_model (tree_view); ++ GtkTreeIter iter; ++ ++ if (model == NULL || !GTK_WIDGET_MAPPED (tree_view)) ++ return; ++ ++ if (gtk_tree_model_get_iter_first (model, &iter) == FALSE) ++ { ++ GTK_WIDGET_UNSET_FLAGS (tree_view, GTK_CAN_FOCUS); ++ return; ++ } ++ ++ do { ++ GtkTreePath *path = gtk_tree_model_get_path (model, &iter); ++ GtkRBTree *tree; ++ GtkRBNode *node; ++ ++ _gtk_tree_view_find_node (tree_view, path, &tree, &node); ++ ++ if (_gtk_tree_selection_is_row_selectable (tree_view->priv->selection, ++ node, path)) ++ { ++ GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS); ++ if (!gtk_tree_row_reference_valid (tree_view->priv->cursor)) ++ gtk_tree_view_real_set_cursor (tree_view, path, ++ !tree_view->priv->checkbox_mode, ++ TRUE); ++ ++ return; ++ } ++ } while (gtk_tree_model_iter_next (model, &iter)); ++ ++ GTK_WIDGET_UNSET_FLAGS (tree_view, GTK_CAN_FOCUS); ++} -- cgit v1.2.3-54-g00ecf