1 /* gtktreeview.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 
19 #include "config.h"
20 
21 #include <math.h>
22 #include <string.h>
23 
24 #include "gtktreeview.h"
25 
26 #include "gtkadjustmentprivate.h"
27 #include "gtkcssnumbervalueprivate.h"
28 #include "gtkrbtree.h"
29 #include "gtktreednd.h"
30 #include "gtktreeprivate.h"
31 #include "gtkcellrenderer.h"
32 #include "gtkmarshalers.h"
33 #include "gtkbuildable.h"
34 #include "gtkbutton.h"
35 #include "gtklabel.h"
36 #include "gtkbox.h"
37 #include "gtkintl.h"
38 #include "gtkbindings.h"
39 #include "gtkcontainer.h"
40 #include "gtkentry.h"
41 #include "gtkframe.h"
42 #include "gtkmain.h"
43 #include "gtktreemodelsort.h"
44 #include "gtktooltip.h"
45 #include "gtkscrollable.h"
46 #include "gtkcelllayout.h"
47 #include "gtkprivate.h"
48 #include "gtkwidgetprivate.h"
49 #include "gtkentryprivate.h"
50 #include "gtkstylecontextprivate.h"
51 #include "gtkcssstylepropertyprivate.h"
52 #include "gtkcssrgbavalueprivate.h"
53 #include "gtktypebuiltins.h"
54 #include "gtkmain.h"
55 #include "gtksettingsprivate.h"
56 #include "gtkwidgetpath.h"
57 #include "gtkpixelcacheprivate.h"
58 #include "a11y/gtktreeviewaccessibleprivate.h"
59 
60 
61 /**
62  * SECTION:gtktreeview
63  * @Short_description: A widget for displaying both trees and lists
64  * @Title: GtkTreeView
65  * @See_also: #GtkTreeViewColumn, #GtkTreeSelection, #GtkTreeModel,
66  *   [GtkTreeView drag-and-drop][gtk3-GtkTreeView-drag-and-drop],
67  *   #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore,
68  *   #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf,
69  *   #GtkCellRendererText, #GtkCellRendererToggle
70  *
71  * Widget that displays any object that implements the #GtkTreeModel interface.
72  *
73  * Please refer to the
74  * [tree widget conceptual overview][TreeWidget]
75  * for an overview of all the objects and data types related
76  * to the tree widget and how they work together.
77  *
78  * Several different coordinate systems are exposed in the GtkTreeView API.
79  * These are:
80  *
81  * ![](tree-view-coordinates.png)
82  *
83  * Coordinate systems in GtkTreeView API:
84  *
85  * - Widget coordinates: Coordinates relative to the widget (usually `widget->window`).
86  *
87  * - Bin window coordinates: Coordinates relative to the window that GtkTreeView renders to.
88  *
89  * - Tree coordinates: Coordinates relative to the entire scrollable area of GtkTreeView. These
90  *   coordinates start at (0, 0) for row 0 of the tree.
91  *
92  * Several functions are available for converting between the different
93  * coordinate systems.  The most common translations are between widget and bin
94  * window coordinates and between bin window and tree coordinates. For the
95  * former you can use gtk_tree_view_convert_widget_to_bin_window_coords()
96  * (and vice versa), for the latter gtk_tree_view_convert_bin_window_to_tree_coords()
97  * (and vice versa).
98  *
99  * # GtkTreeView as GtkBuildable
100  *
101  * The GtkTreeView implementation of the GtkBuildable interface accepts
102  * #GtkTreeViewColumn objects as `<child>` elements and exposes the internal
103  * #GtkTreeSelection in UI definitions.
104  *
105  * An example of a UI definition fragment with GtkTreeView:
106  *
107  * |[<!-- language="xml" -->
108  * <object class="GtkTreeView" id="treeview">
109  *   <property name="model">liststore1</property>
110  *   <child>
111  *     <object class="GtkTreeViewColumn" id="test-column">
112  *       <property name="title">Test</property>
113  *       <child>
114  *         <object class="GtkCellRendererText" id="test-renderer"/>
115  *         <attributes>
116  *           <attribute name="text">1</attribute>
117  *         </attributes>
118  *       </child>
119  *     </object>
120  *   </child>
121  *   <child internal-child="selection">
122  *     <object class="GtkTreeSelection" id="selection">
123  *       <signal name="changed" handler="on_treeview_selection_changed"/>
124  *     </object>
125  *   </child>
126  * </object>
127  * ]|
128  *
129  * # CSS nodes
130  *
131  * |[<!-- language="plain" -->
132  * treeview.view
133  * ├── header
134  * │   ├── <column header>
135  * ┊   ┊
136  * │   ╰── <column header>
137  * │
138  * ╰── [rubberband]
139  * ]|
140  *
141  * GtkTreeView has a main CSS node with name treeview and style class .view.
142  * It has a subnode with name header, which is the parent for all the column
143  * header widgets' CSS nodes.
144  * For rubberband selection, a subnode with name rubberband is used.
145  */
146 
147 enum
148 {
149   DRAG_COLUMN_WINDOW_STATE_UNSET = 0,
150   DRAG_COLUMN_WINDOW_STATE_ORIGINAL = 1,
151   DRAG_COLUMN_WINDOW_STATE_ARROW = 2,
152   DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT = 3,
153   DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
154 };
155 
156 enum
157 {
158   RUBBER_BAND_OFF = 0,
159   RUBBER_BAND_MAYBE_START = 1,
160   RUBBER_BAND_ACTIVE = 2
161 };
162 
163 typedef enum {
164   CLEAR_AND_SELECT = (1 << 0),
165   CLAMP_NODE       = (1 << 1),
166   CURSOR_INVALID   = (1 << 2)
167 } SetCursorFlags;
168 
169  /* This lovely little value is used to determine how far away from the title bar
170   * you can move the mouse and still have a column drag work.
171   */
172 #define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*gtk_tree_view_get_effective_header_height(tree_view))
173 
174 #ifdef __GNUC__
175 
176 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
177      if (!(expr))                                                       \
178        {                                                                \
179          g_log (G_LOG_DOMAIN,                                           \
180                 G_LOG_LEVEL_CRITICAL,                                   \
181 		"%s (%s): assertion `%s' failed.\n"                     \
182 	        "There is a disparity between the internal view of the GtkTreeView,\n"    \
183 		"and the GtkTreeModel.  This generally means that the model has changed\n"\
184 		"without letting the view know.  Any display from now on is likely to\n"  \
185 		"be incorrect.\n",                                                        \
186                 G_STRLOC,                                               \
187                 G_STRFUNC,                                              \
188                 #expr);                                                 \
189          return ret;                                                    \
190        };                               }G_STMT_END
191 
192 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
193      if (!(expr))                                                       \
194        {                                                                \
195          g_log (G_LOG_DOMAIN,                                           \
196                 G_LOG_LEVEL_CRITICAL,                                   \
197 		"%s (%s): assertion `%s' failed.\n"                     \
198 	        "There is a disparity between the internal view of the GtkTreeView,\n"    \
199 		"and the GtkTreeModel.  This generally means that the model has changed\n"\
200 		"without letting the view know.  Any display from now on is likely to\n"  \
201 		"be incorrect.\n",                                                        \
202                 G_STRLOC,                                               \
203                 G_STRFUNC,                                              \
204                 #expr);                                                 \
205          return;                                                        \
206        };                               }G_STMT_END
207 
208 #else
209 
210 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
211      if (!(expr))                                                       \
212        {                                                                \
213          g_log (G_LOG_DOMAIN,                                           \
214                 G_LOG_LEVEL_CRITICAL,                                   \
215 		"file %s: line %d: assertion `%s' failed.\n"       \
216 	        "There is a disparity between the internal view of the GtkTreeView,\n"    \
217 		"and the GtkTreeModel.  This generally means that the model has changed\n"\
218 		"without letting the view know.  Any display from now on is likely to\n"  \
219 		"be incorrect.\n",                                                        \
220                 __FILE__,                                               \
221                 __LINE__,                                               \
222                 #expr);                                                 \
223          return ret;                                                    \
224        };                               }G_STMT_END
225 
226 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
227      if (!(expr))                                                       \
228        {                                                                \
229          g_log (G_LOG_DOMAIN,                                           \
230                 G_LOG_LEVEL_CRITICAL,                                   \
231 		"file %s: line %d: assertion '%s' failed.\n"            \
232 	        "There is a disparity between the internal view of the GtkTreeView,\n"    \
233 		"and the GtkTreeModel.  This generally means that the model has changed\n"\
234 		"without letting the view know.  Any display from now on is likely to\n"  \
235 		"be incorrect.\n",                                                        \
236                 __FILE__,                                               \
237                 __LINE__,                                               \
238                 #expr);                                                 \
239          return;                                                        \
240        };                               }G_STMT_END
241 #endif
242 
243 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
244 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
245 /* 3/5 of gdkframeclockidle.c's FRAME_INTERVAL (16667 microsecs) */
246 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 10
247 #define SCROLL_EDGE_SIZE 15
248 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
249 #define AUTO_EXPAND_TIMEOUT 500
250 
251 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
252  * vice versa.
253  */
254 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
255 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
256 
257 typedef struct _GtkTreeViewColumnReorder GtkTreeViewColumnReorder;
258 struct _GtkTreeViewColumnReorder
259 {
260   gint left_align;
261   gint right_align;
262   GtkTreeViewColumn *left_column;
263   GtkTreeViewColumn *right_column;
264 };
265 
266 typedef struct _GtkTreeViewChild GtkTreeViewChild;
267 struct _GtkTreeViewChild
268 {
269   GtkWidget *widget;
270   GtkRBNode *node;
271   GtkRBTree *tree;
272   GtkTreeViewColumn *column;
273   GtkBorder border;
274 };
275 
276 
277 typedef struct _TreeViewDragInfo TreeViewDragInfo;
278 struct _TreeViewDragInfo
279 {
280   GdkModifierType start_button_mask;
281   GtkTargetList *_unused_source_target_list;
282   GdkDragAction source_actions;
283 
284   GtkTargetList *_unused_dest_target_list;
285 
286   guint source_set : 1;
287   guint dest_set : 1;
288 };
289 
290 
291 struct _GtkTreeViewPrivate
292 {
293   GtkTreeModel *model;
294 
295   /* tree information */
296   GtkRBTree *tree;
297 
298   /* Container info */
299   GList *children;
300   gint width;
301 
302   guint presize_handler_tick_cb;
303 
304   /* Adjustments */
305   GtkAdjustment *hadjustment;
306   GtkAdjustment *vadjustment;
307   gint           min_display_width;
308   gint           min_display_height;
309 
310   /* Sub windows */
311   GdkWindow *bin_window;
312   GdkWindow *header_window;
313 
314   GtkPixelCache *pixel_cache;
315 
316   /* CSS nodes */
317   GtkCssNode *header_node;
318 
319   /* Scroll position state keeping */
320   GtkTreeRowReference *top_row;
321   gint top_row_dy;
322   /* dy == y pos of top_row + top_row_dy */
323   /* we cache it for simplicity of the code */
324   gint dy;
325 
326   guint validate_rows_timer;
327   guint scroll_sync_timer;
328 
329   /* Indentation and expander layout */
330   GtkTreeViewColumn *expander_column;
331 
332   gint level_indentation;
333 
334   /* Key navigation (focus), selection */
335   gint cursor_offset;
336 
337   GtkTreeRowReference *anchor;
338   GtkRBNode *cursor_node;
339   GtkRBTree *cursor_tree;
340 
341   GtkTreeViewColumn *focus_column;
342 
343   /* Current pressed node, previously pressed, prelight */
344   GtkRBNode *button_pressed_node;
345   GtkRBTree *button_pressed_tree;
346 
347   gint press_start_x;
348   gint press_start_y;
349 
350   gint event_last_x;
351   gint event_last_y;
352 
353   GtkRBNode *prelight_node;
354   GtkRBTree *prelight_tree;
355 
356   /* Cell Editing */
357   GtkTreeViewColumn *edited_column;
358 
359   /* Auto expand/collapse timeout in hover mode */
360   guint auto_expand_timeout;
361 
362   /* Selection information */
363   GtkTreeSelection *selection;
364 
365   /* Header information */
366   gint header_height;
367   gint n_columns;
368   GList *columns;
369 
370   GtkTreeViewColumnDropFunc column_drop_func;
371   gpointer column_drop_func_data;
372   GDestroyNotify column_drop_func_data_destroy;
373   GList *column_drag_info;
374   GtkTreeViewColumnReorder *cur_reorder;
375 
376   gint prev_width_before_expander;
377 
378   /* Scroll timeout (e.g. during dnd, rubber banding) */
379   guint scroll_timeout;
380 
381   /* Interactive Header reordering */
382   GdkWindow *drag_window;
383   GdkWindow *drag_highlight_window;
384   GtkTreeViewColumn *drag_column;
385   gint drag_column_x;
386 
387   /* Interactive Header Resizing */
388   gint drag_pos;
389   gint x_drag;
390 
391   /* Non-interactive Header Resizing, expand flag support */
392   gint last_extra_space;
393   gint last_extra_space_per_column;
394   gint last_number_of_expand_columns;
395 
396   /* ATK Hack */
397   GtkTreeDestroyCountFunc destroy_count_func;
398   gpointer destroy_count_data;
399   GDestroyNotify destroy_count_destroy;
400 
401   /* Row drag-and-drop */
402   GtkTreeRowReference *drag_dest_row;
403   GtkTreeViewDropPosition drag_dest_pos;
404   guint open_dest_timeout;
405 
406   /* Rubber banding */
407   gint rubber_band_status;
408   gint rubber_band_x;
409   gint rubber_band_y;
410   gint rubber_band_extend;
411   gint rubber_band_modify;
412 
413   /* fixed height */
414   gint fixed_height;
415 
416   GtkRBNode *rubber_band_start_node;
417   GtkRBTree *rubber_band_start_tree;
418 
419   GtkRBNode *rubber_band_end_node;
420   GtkRBTree *rubber_band_end_tree;
421   GtkCssNode *rubber_band_cssnode;
422 
423   /* Scroll-to functionality when unrealized */
424   GtkTreeRowReference *scroll_to_path;
425   GtkTreeViewColumn *scroll_to_column;
426   gfloat scroll_to_row_align;
427   gfloat scroll_to_col_align;
428 
429   /* Interactive search */
430   gint selected_iter;
431   gint search_column;
432   GtkTreeViewSearchPositionFunc search_position_func;
433   GtkTreeViewSearchEqualFunc search_equal_func;
434   gpointer search_user_data;
435   GDestroyNotify search_destroy;
436   gpointer search_position_user_data;
437   GDestroyNotify search_position_destroy;
438   GtkWidget *search_window;
439   GtkWidget *search_entry;
440   gulong search_entry_changed_id;
441   guint typeselect_flush_timeout;
442 
443   /* Grid and tree lines */
444   GtkTreeViewGridLines grid_lines;
445   double grid_line_dashes[2];
446   int grid_line_width;
447 
448   gboolean tree_lines_enabled;
449   double tree_line_dashes[2];
450   int tree_line_width;
451 
452   /* Row separators */
453   GtkTreeViewRowSeparatorFunc row_separator_func;
454   gpointer row_separator_data;
455   GDestroyNotify row_separator_destroy;
456 
457   /* Gestures */
458   GtkGesture *multipress_gesture;
459   GtkGesture *column_multipress_gesture;
460   GtkGesture *drag_gesture; /* Rubberbanding, row DnD */
461   GtkGesture *column_drag_gesture; /* Column reordering, resizing */
462 
463   /* Tooltip support */
464   gint tooltip_column;
465 
466   /* Here comes the bitfield */
467   guint scroll_to_use_align : 1;
468 
469   guint fixed_height_mode : 1;
470   guint fixed_height_check : 1;
471 
472   guint activate_on_single_click : 1;
473   guint reorderable : 1;
474   guint header_has_focus : 1;
475   guint drag_column_window_state : 3;
476   /* hint to display rows in alternating colors */
477   guint has_rules : 1;
478   guint mark_rows_col_dirty : 1;
479 
480   /* for DnD */
481   guint empty_view_drop : 1;
482 
483   guint modify_selection_pressed : 1;
484   guint extend_selection_pressed : 1;
485 
486   guint init_hadjust_value : 1;
487 
488   guint in_top_row_to_dy : 1;
489 
490   /* interactive search */
491   guint enable_search : 1;
492   guint disable_popdown : 1;
493   guint search_custom_entry_set : 1;
494 
495   guint hover_selection : 1;
496   guint hover_expand : 1;
497   guint imcontext_changed : 1;
498 
499   guint rubber_banding_enable : 1;
500 
501   guint in_grab : 1;
502 
503   guint post_validation_flag : 1;
504 
505   /* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
506   guint search_entry_avoid_unhandled_binding : 1;
507 
508   /* GtkScrollablePolicy needs to be checked when
509    * driving the scrollable adjustment values */
510   guint hscroll_policy : 1;
511   guint vscroll_policy : 1;
512 
513   /* GtkTreeView flags */
514   guint is_list : 1;
515   guint show_expanders : 1;
516   guint in_column_resize : 1;
517   guint arrow_prelit : 1;
518   guint headers_visible : 1;
519   guint draw_keyfocus : 1;
520   guint model_setup : 1;
521   guint in_column_drag : 1;
522 };
523 
524 
525 /* Signals */
526 enum
527 {
528   ROW_ACTIVATED,
529   TEST_EXPAND_ROW,
530   TEST_COLLAPSE_ROW,
531   ROW_EXPANDED,
532   ROW_COLLAPSED,
533   COLUMNS_CHANGED,
534   CURSOR_CHANGED,
535   MOVE_CURSOR,
536   SELECT_ALL,
537   UNSELECT_ALL,
538   SELECT_CURSOR_ROW,
539   TOGGLE_CURSOR_ROW,
540   EXPAND_COLLAPSE_CURSOR_ROW,
541   SELECT_CURSOR_PARENT,
542   START_INTERACTIVE_SEARCH,
543   LAST_SIGNAL
544 };
545 
546 /* Properties */
547 enum {
548   PROP_0,
549   PROP_MODEL,
550   PROP_HEADERS_VISIBLE,
551   PROP_HEADERS_CLICKABLE,
552   PROP_EXPANDER_COLUMN,
553   PROP_REORDERABLE,
554   PROP_RULES_HINT,
555   PROP_ENABLE_SEARCH,
556   PROP_SEARCH_COLUMN,
557   PROP_FIXED_HEIGHT_MODE,
558   PROP_HOVER_SELECTION,
559   PROP_HOVER_EXPAND,
560   PROP_SHOW_EXPANDERS,
561   PROP_LEVEL_INDENTATION,
562   PROP_RUBBER_BANDING,
563   PROP_ENABLE_GRID_LINES,
564   PROP_ENABLE_TREE_LINES,
565   PROP_TOOLTIP_COLUMN,
566   PROP_ACTIVATE_ON_SINGLE_CLICK,
567   LAST_PROP,
568   /* overridden */
569   PROP_HADJUSTMENT = LAST_PROP,
570   PROP_VADJUSTMENT,
571   PROP_HSCROLL_POLICY,
572   PROP_VSCROLL_POLICY,
573 };
574 
575 /* object signals */
576 static void     gtk_tree_view_finalize             (GObject          *object);
577 static void     gtk_tree_view_set_property         (GObject         *object,
578 						    guint            prop_id,
579 						    const GValue    *value,
580 						    GParamSpec      *pspec);
581 static void     gtk_tree_view_get_property         (GObject         *object,
582 						    guint            prop_id,
583 						    GValue          *value,
584 						    GParamSpec      *pspec);
585 
586 /* gtkwidget signals */
587 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
588 static void     gtk_tree_view_realize              (GtkWidget        *widget);
589 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
590 static void     gtk_tree_view_map                  (GtkWidget        *widget);
591 static void     gtk_tree_view_unmap                (GtkWidget        *widget);
592 static void     gtk_tree_view_get_preferred_width  (GtkWidget        *widget,
593 						    gint             *minimum,
594 						    gint             *natural);
595 static void     gtk_tree_view_get_preferred_height (GtkWidget        *widget,
596 						    gint             *minimum,
597 						    gint             *natural);
598 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
599 						    GtkAllocation    *allocation);
600 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
601                                                     cairo_t          *cr);
602 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
603 						    GdkEventKey      *event);
604 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
605 						    GdkEventKey      *event);
606 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
607 						    GdkEventMotion   *event);
608 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
609 						    GdkEventCrossing *event);
610 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
611 						    GdkEventCrossing *event);
612 
613 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
614 						    GtkWidget        *child);
615 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
616 						    GdkEventFocus    *event);
617 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
618 						    GtkDirectionType  direction);
619 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
620 static void     gtk_tree_view_style_updated        (GtkWidget        *widget);
621 
622 /* container signals */
623 static void     gtk_tree_view_remove               (GtkContainer     *container,
624 						    GtkWidget        *widget);
625 static void     gtk_tree_view_forall               (GtkContainer     *container,
626 						    gboolean          include_internals,
627 						    GtkCallback       callback,
628 						    gpointer          callback_data);
629 
630 /* Source side drag signals */
631 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
632                                             GdkDragContext   *context);
633 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
634                                             GdkDragContext   *context);
635 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
636                                             GdkDragContext   *context,
637                                             GtkSelectionData *selection_data,
638                                             guint             info,
639                                             guint             time);
640 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
641                                             GdkDragContext   *context);
642 
643 /* Target side drag signals */
644 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
645                                                   GdkDragContext   *context,
646                                                   guint             time);
647 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
648                                                   GdkDragContext   *context,
649                                                   gint              x,
650                                                   gint              y,
651                                                   guint             time);
652 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
653                                                   GdkDragContext   *context,
654                                                   gint              x,
655                                                   gint              y,
656                                                   guint             time);
657 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
658                                                   GdkDragContext   *context,
659                                                   gint              x,
660                                                   gint              y,
661                                                   GtkSelectionData *selection_data,
662                                                   guint             info,
663                                                   guint             time);
664 
665 /* tree_model signals */
666 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
667 							   GtkMovementStep  step,
668 							   gint             count);
669 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
670 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
671 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
672 							   gboolean         start_editing);
673 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
674 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
675 							       gboolean         logical,
676 							       gboolean         expand,
677 							       gboolean         open_all);
678 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
679 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
680 							   GtkTreePath     *path,
681 							   GtkTreeIter     *iter,
682 							   gpointer         data);
683 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
684 							   GtkTreePath     *path,
685 							   GtkTreeIter     *iter,
686 							   gpointer         data);
687 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
688 							   GtkTreePath     *path,
689 							   GtkTreeIter     *iter,
690 							   gpointer         data);
691 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
692 							   GtkTreePath     *path,
693 							   gpointer         data);
694 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
695 							   GtkTreePath     *parent,
696 							   GtkTreeIter     *iter,
697 							   gint            *new_order,
698 							   gpointer         data);
699 
700 /* Incremental reflow */
701 static gboolean validate_row             (GtkTreeView *tree_view,
702 					  GtkRBTree   *tree,
703 					  GtkRBNode   *node,
704 					  GtkTreeIter *iter,
705 					  GtkTreePath *path);
706 static void     validate_visible_area    (GtkTreeView *tree_view);
707 static gboolean do_validate_rows         (GtkTreeView *tree_view,
708 					  gboolean     queue_resize);
709 static gboolean validate_rows            (GtkTreeView *tree_view);
710 static void     install_presize_handler  (GtkTreeView *tree_view);
711 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
712 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
713 					     GtkTreePath *path,
714 					     gint         offset);
715 static void	gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
716 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
717 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
718 
719 /* Internal functions */
720 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
721 							      GtkTreeViewColumn  *column);
722 static inline gboolean gtk_tree_view_draw_expanders          (GtkTreeView        *tree_view);
723 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
724 							      guint               keyval,
725 							      guint               modmask,
726 							      gboolean            add_shifted_binding,
727 							      GtkMovementStep     step,
728 							      gint                count);
729 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
730 							      GtkRBTree          *tree);
731 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
732 							      GtkTreePath        *path,
733 							      const GdkRectangle *clip_rect);
734 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
735 							      GtkRBTree          *tree,
736 							      GtkRBNode          *node);
737 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
738                                                               cairo_t            *cr,
739 							      GtkRBTree          *tree,
740 							      GtkRBNode          *node);
741 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
742 							      GtkRBTree          *tree,
743 							      gint               *x1,
744 							      gint               *x2);
745 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
746 							      GtkTreeView        *tree_view);
747 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
748 							      GtkRBTree          *tree,
749 							      GtkTreeIter        *iter,
750 							      gint                depth,
751 							      gboolean            recurse);
752 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
753 							      GtkRBTree          *tree,
754 							      GtkRBNode          *node);
755 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
756 							      GtkTreeViewColumn  *column,
757 							      gboolean            focus_to_cell);
758 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view);
759 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
760 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
761 							      gint                count);
762 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
763 							      gint                count);
764 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
765 							      gint                count);
766 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
767 							      gint                count);
768 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
769 							      GtkTreePath        *path,
770 							      GtkRBTree          *tree,
771 							      GtkRBNode          *node,
772 							      gboolean            animate);
773 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
774 							      GtkTreePath        *path,
775 							      GtkRBTree          *tree,
776 							      GtkRBNode          *node,
777 							      gboolean            open_all,
778 							      gboolean            animate);
779 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
780 							      GtkTreePath        *path,
781                                                               SetCursorFlags      flags);
782 static gboolean gtk_tree_view_has_can_focus_cell             (GtkTreeView        *tree_view);
783 static void     column_sizing_notify                         (GObject            *object,
784                                                               GParamSpec         *pspec,
785                                                               gpointer            data);
786 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
787 static void     update_prelight                              (GtkTreeView        *tree_view,
788                                                               int                 x,
789                                                               int                 y);
790 static void     gtk_tree_view_queue_draw_region              (GtkWidget          *widget,
791 							      const cairo_region_t *region);
792 
793 static inline gint gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view);
794 
795 static inline gint gtk_tree_view_get_cell_area_y_offset      (GtkTreeView *tree_view,
796                                                               GtkRBTree   *tree,
797                                                               GtkRBNode   *node,
798                                                               gint         vertical_separator);
799 static inline gint gtk_tree_view_get_cell_area_height        (GtkTreeView *tree_view,
800                                                               GtkRBNode   *node,
801                                                               gint         vertical_separator);
802 
803 static inline gint gtk_tree_view_get_row_y_offset            (GtkTreeView *tree_view,
804                                                               GtkRBTree   *tree,
805                                                               GtkRBNode   *node);
806 static inline gint gtk_tree_view_get_row_height              (GtkTreeView *tree_view,
807                                                               GtkRBNode   *node);
808 
809 /* interactive search */
810 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
811 static void     gtk_tree_view_search_window_hide        (GtkWidget        *search_window,
812                                                          GtkTreeView      *tree_view,
813                                                          GdkDevice        *device);
814 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
815 							 GtkWidget        *search_window,
816 							 gpointer          user_data);
817 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
818 							 GtkMenu          *menu,
819 							 gpointer          data);
820 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
821 							 GtkTreeView      *tree_view);
822 static void     gtk_tree_view_search_commit             (GtkIMContext     *im_context,
823                                                          gchar            *buf,
824                                                          GtkTreeView      *tree_view);
825 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
826 							 GtkTreeView      *tree_view);
827 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
828 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
829 							 gpointer          data);
830 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
831 							 GdkEventAny      *event,
832 							 GtkTreeView      *tree_view);
833 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
834 							 GdkEventButton   *event,
835 							 GtkTreeView      *tree_view);
836 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
837 							 GdkEventScroll   *event,
838 							 GtkTreeView      *tree_view);
839 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
840 							 GdkEventKey      *event,
841 							 GtkTreeView      *tree_view);
842 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
843 							 GtkTreeView      *tree_view,
844 							 gboolean          up);
845 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
846 							 gint              column,
847 							 const gchar      *key,
848 							 GtkTreeIter      *iter,
849 							 gpointer          search_data);
850 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
851 							 GtkTreeSelection *selection,
852 							 GtkTreeIter      *iter,
853 							 const gchar      *text,
854 							 gint             *count,
855 							 gint              n);
856 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
857 							 GtkTreeView      *tree_view);
858 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
859 							 GtkWidget        *child_widget,
860                                                          GtkTreePath      *path,
861                                                          GtkTreeViewColumn*column,
862                                                          const GtkBorder  *border);
863 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
864 							 GtkTreePath      *cursor_path,
865 							 gboolean          edit_only);
866 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
867 							 gboolean     cancel_editing);
868 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
869                                                              GdkDevice   *device,
870 							     gboolean     keybinding);
871 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
872 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
873 							 GtkTreeViewColumn *column,
874 							 gint               drop_position);
875 
876 /* GtkBuildable */
877 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
878 							    GtkBuilder        *builder,
879 							    GObject           *child,
880 							    const gchar       *type);
881 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
882 							    GtkBuilder        *builder,
883 							    const gchar       *childname);
884 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
885 
886 /* GtkScrollable */
887 static void     gtk_tree_view_scrollable_init              (GtkScrollableInterface *iface);
888 
889 static GtkAdjustment *gtk_tree_view_do_get_hadjustment (GtkTreeView   *tree_view);
890 static void           gtk_tree_view_do_set_hadjustment (GtkTreeView   *tree_view,
891                                                         GtkAdjustment *adjustment);
892 static GtkAdjustment *gtk_tree_view_do_get_vadjustment (GtkTreeView   *tree_view);
893 static void           gtk_tree_view_do_set_vadjustment (GtkTreeView   *tree_view,
894                                                         GtkAdjustment *adjustment);
895 
896 static gboolean scroll_row_timeout                   (gpointer     data);
897 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
898 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
899 
900 static void     grab_focus_and_unset_draw_keyfocus   (GtkTreeView *tree_view);
901 
902 /* Gestures */
903 static void gtk_tree_view_column_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
904                                                              gint                  n_press,
905                                                              gdouble               x,
906                                                              gdouble               y,
907                                                              GtkTreeView          *tree_view);
908 
909 static void gtk_tree_view_multipress_gesture_pressed        (GtkGestureMultiPress *gesture,
910                                                              gint                  n_press,
911                                                              gdouble               x,
912                                                              gdouble               y,
913                                                              GtkTreeView          *tree_view);
914 static void gtk_tree_view_multipress_gesture_released       (GtkGestureMultiPress *gesture,
915                                                              gint                  n_press,
916                                                              gdouble               x,
917                                                              gdouble               y,
918                                                              GtkTreeView          *tree_view);
919 
920 static void gtk_tree_view_column_drag_gesture_begin         (GtkGestureDrag *gesture,
921                                                              gdouble         start_x,
922                                                              gdouble         start_y,
923                                                              GtkTreeView    *tree_view);
924 static void gtk_tree_view_column_drag_gesture_update        (GtkGestureDrag *gesture,
925                                                              gdouble         offset_x,
926                                                              gdouble         offset_y,
927                                                              GtkTreeView    *tree_view);
928 static void gtk_tree_view_column_drag_gesture_end           (GtkGestureDrag *gesture,
929                                                              gdouble         offset_x,
930                                                              gdouble         offset_y,
931                                                              GtkTreeView    *tree_view);
932 
933 static void gtk_tree_view_drag_gesture_begin                (GtkGestureDrag *gesture,
934                                                              gdouble         start_x,
935                                                              gdouble         start_y,
936                                                              GtkTreeView    *tree_view);
937 static void gtk_tree_view_drag_gesture_update               (GtkGestureDrag *gesture,
938                                                              gdouble         offset_x,
939                                                              gdouble         offset_y,
940                                                              GtkTreeView    *tree_view);
941 static void gtk_tree_view_drag_gesture_end                  (GtkGestureDrag *gesture,
942                                                              gdouble         offset_x,
943                                                              gdouble         offset_y,
944                                                              GtkTreeView    *tree_view);
945 
946 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
947 static GParamSpec *tree_view_props [LAST_PROP] = { NULL };
948 
949 
950 
951 /* GType Methods
952  */
953 
G_DEFINE_TYPE_WITH_CODE(GtkTreeView,gtk_tree_view,GTK_TYPE_CONTAINER,G_ADD_PRIVATE (GtkTreeView)G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,gtk_tree_view_buildable_init)G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE,gtk_tree_view_scrollable_init))954 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
955                          G_ADD_PRIVATE (GtkTreeView)
956 			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
957 						gtk_tree_view_buildable_init)
958 			 G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE,
959                                                 gtk_tree_view_scrollable_init))
960 
961 static void
962 gtk_tree_view_class_init (GtkTreeViewClass *class)
963 {
964   GObjectClass *o_class;
965   GtkWidgetClass *widget_class;
966   GtkContainerClass *container_class;
967   GtkBindingSet *binding_set;
968 
969   binding_set = gtk_binding_set_by_class (class);
970 
971   o_class = (GObjectClass *) class;
972   widget_class = (GtkWidgetClass *) class;
973   container_class = (GtkContainerClass *) class;
974 
975   /* GObject signals */
976   o_class->set_property = gtk_tree_view_set_property;
977   o_class->get_property = gtk_tree_view_get_property;
978   o_class->finalize = gtk_tree_view_finalize;
979 
980   /* GtkWidget signals */
981   widget_class->destroy = gtk_tree_view_destroy;
982   widget_class->map = gtk_tree_view_map;
983   widget_class->unmap = gtk_tree_view_unmap;
984   widget_class->realize = gtk_tree_view_realize;
985   widget_class->unrealize = gtk_tree_view_unrealize;
986   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
987   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
988   widget_class->size_allocate = gtk_tree_view_size_allocate;
989   widget_class->motion_notify_event = gtk_tree_view_motion;
990   widget_class->draw = gtk_tree_view_draw;
991   widget_class->key_press_event = gtk_tree_view_key_press;
992   widget_class->key_release_event = gtk_tree_view_key_release;
993   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
994   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
995   widget_class->focus_out_event = gtk_tree_view_focus_out;
996   widget_class->drag_begin = gtk_tree_view_drag_begin;
997   widget_class->drag_end = gtk_tree_view_drag_end;
998   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
999   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
1000   widget_class->drag_leave = gtk_tree_view_drag_leave;
1001   widget_class->drag_motion = gtk_tree_view_drag_motion;
1002   widget_class->drag_drop = gtk_tree_view_drag_drop;
1003   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
1004   widget_class->focus = gtk_tree_view_focus;
1005   widget_class->grab_focus = gtk_tree_view_grab_focus;
1006   widget_class->style_updated = gtk_tree_view_style_updated;
1007   widget_class->queue_draw_region = gtk_tree_view_queue_draw_region;
1008 
1009   /* GtkContainer signals */
1010   container_class->remove = gtk_tree_view_remove;
1011   container_class->forall = gtk_tree_view_forall;
1012   container_class->set_focus_child = gtk_tree_view_set_focus_child;
1013 
1014   class->move_cursor = gtk_tree_view_real_move_cursor;
1015   class->select_all = gtk_tree_view_real_select_all;
1016   class->unselect_all = gtk_tree_view_real_unselect_all;
1017   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
1018   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
1019   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
1020   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
1021   class->start_interactive_search = gtk_tree_view_start_interactive_search;
1022 
1023   /* Properties */
1024 
1025   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
1026   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
1027   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
1028   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
1029 
1030   tree_view_props[PROP_MODEL] =
1031       g_param_spec_object ("model",
1032                            P_("TreeView Model"),
1033                            P_("The model for the tree view"),
1034                            GTK_TYPE_TREE_MODEL,
1035                            GTK_PARAM_READWRITE);
1036 
1037   tree_view_props[PROP_HEADERS_VISIBLE] =
1038       g_param_spec_boolean ("headers-visible",
1039                             P_("Headers Visible"),
1040                             P_("Show the column header buttons"),
1041                             TRUE,
1042                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1043 
1044   tree_view_props[PROP_HEADERS_CLICKABLE] =
1045       g_param_spec_boolean ("headers-clickable",
1046                             P_("Headers Clickable"),
1047                             P_("Column headers respond to click events"),
1048                             TRUE,
1049                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1050 
1051   tree_view_props[PROP_EXPANDER_COLUMN] =
1052       g_param_spec_object ("expander-column",
1053                            P_("Expander Column"),
1054                            P_("Set the column for the expander column"),
1055                            GTK_TYPE_TREE_VIEW_COLUMN,
1056                            GTK_PARAM_READWRITE);
1057 
1058   tree_view_props[PROP_REORDERABLE] =
1059       g_param_spec_boolean ("reorderable",
1060                             P_("Reorderable"),
1061                             P_("View is reorderable"),
1062                             FALSE,
1063                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1064 
1065   /**
1066    * GtkTreeView:rules-hint:
1067    *
1068    * Sets a hint to the theme to draw rows in alternating colors.
1069    *
1070    * Deprecated: 3.14: The theme is responsible for drawing rows
1071    *   using zebra striping
1072    */
1073   tree_view_props[PROP_RULES_HINT] =
1074       g_param_spec_boolean ("rules-hint",
1075                             P_("Rules Hint"),
1076                             P_("Set a hint to the theme engine to draw rows in alternating colors"),
1077                             FALSE,
1078                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_DEPRECATED);
1079 
1080   tree_view_props[PROP_ENABLE_SEARCH] =
1081       g_param_spec_boolean ("enable-search",
1082                             P_("Enable Search"),
1083                             P_("View allows user to search through columns interactively"),
1084                             TRUE,
1085                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1086 
1087   tree_view_props[PROP_SEARCH_COLUMN] =
1088       g_param_spec_int ("search-column",
1089                         P_("Search Column"),
1090                         P_("Model column to search through during interactive search"),
1091                         -1, G_MAXINT,
1092                         -1,
1093                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1094 
1095   /**
1096    * GtkTreeView:fixed-height-mode:
1097    *
1098    * Setting the ::fixed-height-mode property to %TRUE speeds up
1099    * #GtkTreeView by assuming that all rows have the same height.
1100    * Only enable this option if all rows are the same height.
1101    * Please see gtk_tree_view_set_fixed_height_mode() for more
1102    * information on this option.
1103    *
1104    * Since: 2.4
1105    */
1106   tree_view_props[PROP_FIXED_HEIGHT_MODE] =
1107       g_param_spec_boolean ("fixed-height-mode",
1108                             P_("Fixed Height Mode"),
1109                             P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
1110                             FALSE,
1111                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1112 
1113   /**
1114    * GtkTreeView:hover-selection:
1115    *
1116    * Enables or disables the hover selection mode of @tree_view.
1117    * Hover selection makes the selected row follow the pointer.
1118    * Currently, this works only for the selection modes
1119    * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
1120    *
1121    * This mode is primarily intended for treeviews in popups, e.g.
1122    * in #GtkComboBox or #GtkEntryCompletion.
1123    *
1124    * Since: 2.6
1125    */
1126   tree_view_props[PROP_HOVER_SELECTION] =
1127       g_param_spec_boolean ("hover-selection",
1128                             P_("Hover Selection"),
1129                             P_("Whether the selection should follow the pointer"),
1130                             FALSE,
1131                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1132 
1133   /**
1134    * GtkTreeView:hover-expand:
1135    *
1136    * Enables or disables the hover expansion mode of @tree_view.
1137    * Hover expansion makes rows expand or collapse if the pointer moves
1138    * over them.
1139    *
1140    * This mode is primarily intended for treeviews in popups, e.g.
1141    * in #GtkComboBox or #GtkEntryCompletion.
1142    *
1143    * Since: 2.6
1144    */
1145   tree_view_props[PROP_HOVER_EXPAND] =
1146       g_param_spec_boolean ("hover-expand",
1147                             P_("Hover Expand"),
1148                             P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
1149                             FALSE,
1150                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1151 
1152   /**
1153    * GtkTreeView:show-expanders:
1154    *
1155    * %TRUE if the view has expanders.
1156    *
1157    * Since: 2.12
1158    */
1159   tree_view_props[PROP_SHOW_EXPANDERS] =
1160       g_param_spec_boolean ("show-expanders",
1161                             P_("Show Expanders"),
1162                             P_("View has expanders"),
1163                             TRUE,
1164                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1165 
1166   /**
1167    * GtkTreeView:level-indentation:
1168    *
1169    * Extra indentation for each level.
1170    *
1171    * Since: 2.12
1172    */
1173   tree_view_props[PROP_LEVEL_INDENTATION] =
1174       g_param_spec_int ("level-indentation",
1175                         P_("Level Indentation"),
1176                         P_("Extra indentation for each level"),
1177                         0, G_MAXINT,
1178                         0,
1179                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1180 
1181   tree_view_props[PROP_RUBBER_BANDING] =
1182       g_param_spec_boolean ("rubber-banding",
1183                             P_("Rubber Banding"),
1184                             P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
1185                             FALSE,
1186                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1187 
1188   tree_view_props[PROP_ENABLE_GRID_LINES] =
1189       g_param_spec_enum ("enable-grid-lines",
1190                          P_("Enable Grid Lines"),
1191                          P_("Whether grid lines should be drawn in the tree view"),
1192                          GTK_TYPE_TREE_VIEW_GRID_LINES,
1193                          GTK_TREE_VIEW_GRID_LINES_NONE,
1194                          GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1195 
1196   tree_view_props[PROP_ENABLE_TREE_LINES] =
1197       g_param_spec_boolean ("enable-tree-lines",
1198                             P_("Enable Tree Lines"),
1199                             P_("Whether tree lines should be drawn in the tree view"),
1200                             FALSE,
1201                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1202 
1203   tree_view_props[PROP_TOOLTIP_COLUMN] =
1204       g_param_spec_int ("tooltip-column",
1205                         P_("Tooltip Column"),
1206                         P_("The column in the model containing the tooltip texts for the rows"),
1207                         -1, G_MAXINT,
1208                         -1,
1209                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1210 
1211   /**
1212    * GtkTreeView:activate-on-single-click:
1213    *
1214    * The activate-on-single-click property specifies whether the "row-activated" signal
1215    * will be emitted after a single click.
1216    *
1217    * Since: 3.8
1218    */
1219   tree_view_props[PROP_ACTIVATE_ON_SINGLE_CLICK] =
1220       g_param_spec_boolean ("activate-on-single-click",
1221                             P_("Activate on Single Click"),
1222                             P_("Activate row on a single click"),
1223                             FALSE,
1224                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1225 
1226   g_object_class_install_properties (o_class, LAST_PROP, tree_view_props);
1227 
1228   /* Style properties */
1229 #define _TREE_VIEW_EXPANDER_SIZE 14
1230 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
1231 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
1232 
1233   gtk_widget_class_install_style_property (widget_class,
1234 					   g_param_spec_int ("expander-size",
1235 							     P_("Expander Size"),
1236 							     P_("Size of the expander arrow"),
1237 							     0,
1238 							     G_MAXINT,
1239 							     _TREE_VIEW_EXPANDER_SIZE,
1240 							     GTK_PARAM_READABLE));
1241 
1242   gtk_widget_class_install_style_property (widget_class,
1243 					   g_param_spec_int ("vertical-separator",
1244 							     P_("Vertical Separator Width"),
1245 							     P_("Vertical space between cells.  Must be an even number"),
1246 							     0,
1247 							     G_MAXINT,
1248 							     _TREE_VIEW_VERTICAL_SEPARATOR,
1249 							     GTK_PARAM_READABLE));
1250 
1251   gtk_widget_class_install_style_property (widget_class,
1252 					   g_param_spec_int ("horizontal-separator",
1253 							     P_("Horizontal Separator Width"),
1254 							     P_("Horizontal space between cells.  Must be an even number"),
1255 							     0,
1256 							     G_MAXINT,
1257 							     _TREE_VIEW_HORIZONTAL_SEPARATOR,
1258 							     GTK_PARAM_READABLE));
1259 
1260   gtk_widget_class_install_style_property (widget_class,
1261 					   g_param_spec_boolean ("allow-rules",
1262 								 P_("Allow Rules"),
1263 								 P_("Allow drawing of alternating color rows"),
1264 								 TRUE,
1265 								 GTK_PARAM_READABLE));
1266 
1267   gtk_widget_class_install_style_property (widget_class,
1268 					   g_param_spec_boolean ("indent-expanders",
1269 								 P_("Indent Expanders"),
1270 								 P_("Make the expanders indented"),
1271 								 TRUE,
1272 								 GTK_PARAM_READABLE));
1273 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1274   gtk_widget_class_install_style_property (widget_class,
1275                                            g_param_spec_boxed ("even-row-color",
1276                                                                P_("Even Row Color"),
1277                                                                P_("Color to use for even rows"),
1278 							       GDK_TYPE_COLOR,
1279 							       GTK_PARAM_READABLE));
1280 
1281   gtk_widget_class_install_style_property (widget_class,
1282                                            g_param_spec_boxed ("odd-row-color",
1283                                                                P_("Odd Row Color"),
1284                                                                P_("Color to use for odd rows"),
1285 							       GDK_TYPE_COLOR,
1286 							       GTK_PARAM_READABLE));
1287 G_GNUC_END_IGNORE_DEPRECATIONS
1288 
1289   gtk_widget_class_install_style_property (widget_class,
1290 					   g_param_spec_int ("grid-line-width",
1291 							     P_("Grid line width"),
1292 							     P_("Width, in pixels, of the tree view grid lines"),
1293 							     0, G_MAXINT, 1,
1294 							     GTK_PARAM_READABLE));
1295 
1296   gtk_widget_class_install_style_property (widget_class,
1297 					   g_param_spec_int ("tree-line-width",
1298 							     P_("Tree line width"),
1299 							     P_("Width, in pixels, of the tree view lines"),
1300 							     0, G_MAXINT, 1,
1301 							     GTK_PARAM_READABLE));
1302 
1303   gtk_widget_class_install_style_property (widget_class,
1304 					   g_param_spec_string ("grid-line-pattern",
1305 								P_("Grid line pattern"),
1306 								P_("Dash pattern used to draw the tree view grid lines"),
1307 								"\1\1",
1308 								GTK_PARAM_READABLE));
1309 
1310   gtk_widget_class_install_style_property (widget_class,
1311 					   g_param_spec_string ("tree-line-pattern",
1312 								P_("Tree line pattern"),
1313 								P_("Dash pattern used to draw the tree view lines"),
1314 								"\1\1",
1315 								GTK_PARAM_READABLE));
1316 
1317   /* Signals */
1318   /**
1319    * GtkTreeView::row-activated:
1320    * @tree_view: the object on which the signal is emitted
1321    * @path: the #GtkTreePath for the activated row
1322    * @column: the #GtkTreeViewColumn in which the activation occurred
1323    *
1324    * The "row-activated" signal is emitted when the method
1325    * gtk_tree_view_row_activated() is called, when the user double
1326    * clicks a treeview row with the "activate-on-single-click"
1327    * property set to %FALSE, or when the user single clicks a row when
1328    * the "activate-on-single-click" property set to %TRUE. It is also
1329    * emitted when a non-editable row is selected and one of the keys:
1330    * Space, Shift+Space, Return or Enter is pressed.
1331    *
1332    * For selection handling refer to the
1333    * [tree widget conceptual overview][TreeWidget]
1334    * as well as #GtkTreeSelection.
1335    */
1336   tree_view_signals[ROW_ACTIVATED] =
1337     g_signal_new (I_("row-activated"),
1338 		  G_TYPE_FROM_CLASS (o_class),
1339 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1340 		  G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
1341 		  NULL, NULL,
1342 		  _gtk_marshal_VOID__BOXED_OBJECT,
1343 		  G_TYPE_NONE, 2,
1344 		  GTK_TYPE_TREE_PATH,
1345 		  GTK_TYPE_TREE_VIEW_COLUMN);
1346   g_signal_set_va_marshaller (tree_view_signals[ROW_ACTIVATED],
1347                               G_TYPE_FROM_CLASS (o_class),
1348                               _gtk_marshal_VOID__BOXED_OBJECTv);
1349 
1350   /**
1351    * GtkTreeView::test-expand-row:
1352    * @tree_view: the object on which the signal is emitted
1353    * @iter: the tree iter of the row to expand
1354    * @path: a tree path that points to the row
1355    *
1356    * The given row is about to be expanded (show its children nodes). Use this
1357    * signal if you need to control the expandability of individual rows.
1358    *
1359    * Returns: %FALSE to allow expansion, %TRUE to reject
1360    */
1361   tree_view_signals[TEST_EXPAND_ROW] =
1362     g_signal_new (I_("test-expand-row"),
1363 		  G_TYPE_FROM_CLASS (o_class),
1364 		  G_SIGNAL_RUN_LAST,
1365 		  G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
1366 		  _gtk_boolean_handled_accumulator, NULL,
1367 		  _gtk_marshal_BOOLEAN__BOXED_BOXED,
1368 		  G_TYPE_BOOLEAN, 2,
1369 		  GTK_TYPE_TREE_ITER,
1370 		  GTK_TYPE_TREE_PATH);
1371   g_signal_set_va_marshaller (tree_view_signals[TEST_EXPAND_ROW],
1372                               G_TYPE_FROM_CLASS (o_class),
1373                               _gtk_marshal_BOOLEAN__BOXED_BOXEDv);
1374 
1375   /**
1376    * GtkTreeView::test-collapse-row:
1377    * @tree_view: the object on which the signal is emitted
1378    * @iter: the tree iter of the row to collapse
1379    * @path: a tree path that points to the row
1380    *
1381    * The given row is about to be collapsed (hide its children nodes). Use this
1382    * signal if you need to control the collapsibility of individual rows.
1383    *
1384    * Returns: %FALSE to allow collapsing, %TRUE to reject
1385    */
1386   tree_view_signals[TEST_COLLAPSE_ROW] =
1387     g_signal_new (I_("test-collapse-row"),
1388 		  G_TYPE_FROM_CLASS (o_class),
1389 		  G_SIGNAL_RUN_LAST,
1390 		  G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
1391 		  _gtk_boolean_handled_accumulator, NULL,
1392 		  _gtk_marshal_BOOLEAN__BOXED_BOXED,
1393 		  G_TYPE_BOOLEAN, 2,
1394 		  GTK_TYPE_TREE_ITER,
1395 		  GTK_TYPE_TREE_PATH);
1396   g_signal_set_va_marshaller (tree_view_signals[TEST_COLLAPSE_ROW],
1397                               G_TYPE_FROM_CLASS (o_class),
1398                               _gtk_marshal_BOOLEAN__BOXED_BOXEDv);
1399 
1400   /**
1401    * GtkTreeView::row-expanded:
1402    * @tree_view: the object on which the signal is emitted
1403    * @iter: the tree iter of the expanded row
1404    * @path: a tree path that points to the row
1405    *
1406    * The given row has been expanded (child nodes are shown).
1407    */
1408   tree_view_signals[ROW_EXPANDED] =
1409     g_signal_new (I_("row-expanded"),
1410 		  G_TYPE_FROM_CLASS (o_class),
1411 		  G_SIGNAL_RUN_LAST,
1412 		  G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
1413 		  NULL, NULL,
1414 		  _gtk_marshal_VOID__BOXED_BOXED,
1415 		  G_TYPE_NONE, 2,
1416 		  GTK_TYPE_TREE_ITER,
1417 		  GTK_TYPE_TREE_PATH);
1418   g_signal_set_va_marshaller (tree_view_signals[ROW_EXPANDED],
1419                               G_TYPE_FROM_CLASS (o_class),
1420                               _gtk_marshal_VOID__BOXED_BOXEDv);
1421 
1422   /**
1423    * GtkTreeView::row-collapsed:
1424    * @tree_view: the object on which the signal is emitted
1425    * @iter: the tree iter of the collapsed row
1426    * @path: a tree path that points to the row
1427    *
1428    * The given row has been collapsed (child nodes are hidden).
1429    */
1430   tree_view_signals[ROW_COLLAPSED] =
1431     g_signal_new (I_("row-collapsed"),
1432 		  G_TYPE_FROM_CLASS (o_class),
1433 		  G_SIGNAL_RUN_LAST,
1434 		  G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
1435 		  NULL, NULL,
1436 		  _gtk_marshal_VOID__BOXED_BOXED,
1437 		  G_TYPE_NONE, 2,
1438 		  GTK_TYPE_TREE_ITER,
1439 		  GTK_TYPE_TREE_PATH);
1440   g_signal_set_va_marshaller (tree_view_signals[ROW_COLLAPSED],
1441                               G_TYPE_FROM_CLASS (o_class),
1442                               _gtk_marshal_VOID__BOXED_BOXEDv);
1443 
1444   /**
1445    * GtkTreeView::columns-changed:
1446    * @tree_view: the object on which the signal is emitted
1447    *
1448    * The number of columns of the treeview has changed.
1449    */
1450   tree_view_signals[COLUMNS_CHANGED] =
1451     g_signal_new (I_("columns-changed"),
1452 		  G_TYPE_FROM_CLASS (o_class),
1453 		  G_SIGNAL_RUN_LAST,
1454 		  G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1455 		  NULL, NULL,
1456 		  NULL,
1457 		  G_TYPE_NONE, 0);
1458 
1459   /**
1460    * GtkTreeView::cursor-changed:
1461    * @tree_view: the object on which the signal is emitted
1462    *
1463    * The position of the cursor (focused cell) has changed.
1464    */
1465   tree_view_signals[CURSOR_CHANGED] =
1466     g_signal_new (I_("cursor-changed"),
1467 		  G_TYPE_FROM_CLASS (o_class),
1468 		  G_SIGNAL_RUN_LAST,
1469 		  G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1470 		  NULL, NULL,
1471 		  NULL,
1472 		  G_TYPE_NONE, 0);
1473 
1474   /**
1475    * GtkTreeView::move-cursor:
1476    * @tree_view: the object on which the signal is emitted.
1477    * @step: the granularity of the move, as a
1478    * #GtkMovementStep. %GTK_MOVEMENT_LOGICAL_POSITIONS,
1479    * %GTK_MOVEMENT_VISUAL_POSITIONS, %GTK_MOVEMENT_DISPLAY_LINES,
1480    * %GTK_MOVEMENT_PAGES and %GTK_MOVEMENT_BUFFER_ENDS are
1481    * supported. %GTK_MOVEMENT_LOGICAL_POSITIONS and
1482    * %GTK_MOVEMENT_VISUAL_POSITIONS are treated identically.
1483    * @direction: the direction to move: +1 to move forwards;
1484    * -1 to move backwards. The resulting movement is
1485    * undefined for all other values.
1486    *
1487    * The #GtkTreeView::move-cursor signal is a [keybinding
1488    * signal][GtkBindingSignal] which gets emitted when the user
1489    * presses one of the cursor keys.
1490    *
1491    * Applications should not connect to it, but may emit it with
1492    * g_signal_emit_by_name() if they need to control the cursor
1493    * programmatically. In contrast to gtk_tree_view_set_cursor() and
1494    * gtk_tree_view_set_cursor_on_cell() when moving horizontally
1495    * #GtkTreeView::move-cursor does not reset the current selection.
1496    *
1497    * Returns: %TRUE if @step is supported, %FALSE otherwise.
1498    */
1499   tree_view_signals[MOVE_CURSOR] =
1500     g_signal_new (I_("move-cursor"),
1501 		  G_TYPE_FROM_CLASS (o_class),
1502 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1503 		  G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1504 		  NULL, NULL,
1505 		  _gtk_marshal_BOOLEAN__ENUM_INT,
1506 		  G_TYPE_BOOLEAN, 2,
1507 		  GTK_TYPE_MOVEMENT_STEP,
1508 		  G_TYPE_INT);
1509   g_signal_set_va_marshaller (tree_view_signals[MOVE_CURSOR],
1510                               G_TYPE_FROM_CLASS (o_class),
1511                               _gtk_marshal_BOOLEAN__ENUM_INTv);
1512 
1513   tree_view_signals[SELECT_ALL] =
1514     g_signal_new (I_("select-all"),
1515 		  G_TYPE_FROM_CLASS (o_class),
1516 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1517 		  G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1518 		  NULL, NULL,
1519 		  _gtk_marshal_BOOLEAN__VOID,
1520 		  G_TYPE_BOOLEAN, 0);
1521   g_signal_set_va_marshaller (tree_view_signals[SELECT_ALL],
1522                               G_TYPE_FROM_CLASS (o_class),
1523                               _gtk_marshal_BOOLEAN__VOIDv);
1524 
1525   tree_view_signals[UNSELECT_ALL] =
1526     g_signal_new (I_("unselect-all"),
1527 		  G_TYPE_FROM_CLASS (o_class),
1528 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1529 		  G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1530 		  NULL, NULL,
1531 		  _gtk_marshal_BOOLEAN__VOID,
1532 		  G_TYPE_BOOLEAN, 0);
1533   g_signal_set_va_marshaller (tree_view_signals[UNSELECT_ALL],
1534                               G_TYPE_FROM_CLASS (o_class),
1535                               _gtk_marshal_BOOLEAN__VOIDv);
1536 
1537   tree_view_signals[SELECT_CURSOR_ROW] =
1538     g_signal_new (I_("select-cursor-row"),
1539 		  G_TYPE_FROM_CLASS (o_class),
1540 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1541 		  G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1542 		  NULL, NULL,
1543 		  _gtk_marshal_BOOLEAN__BOOLEAN,
1544 		  G_TYPE_BOOLEAN, 1,
1545 		  G_TYPE_BOOLEAN);
1546   g_signal_set_va_marshaller (tree_view_signals[SELECT_CURSOR_ROW],
1547                               G_TYPE_FROM_CLASS (o_class),
1548                               _gtk_marshal_BOOLEAN__BOOLEANv);
1549 
1550   tree_view_signals[TOGGLE_CURSOR_ROW] =
1551     g_signal_new (I_("toggle-cursor-row"),
1552 		  G_TYPE_FROM_CLASS (o_class),
1553 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1554 		  G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1555 		  NULL, NULL,
1556 		  _gtk_marshal_BOOLEAN__VOID,
1557 		  G_TYPE_BOOLEAN, 0);
1558   g_signal_set_va_marshaller (tree_view_signals[TOGGLE_CURSOR_ROW],
1559                               G_TYPE_FROM_CLASS (o_class),
1560                               _gtk_marshal_BOOLEAN__VOIDv);
1561 
1562   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1563     g_signal_new (I_("expand-collapse-cursor-row"),
1564 		  G_TYPE_FROM_CLASS (o_class),
1565 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1566 		  G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1567 		  NULL, NULL,
1568 		  _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1569 		  G_TYPE_BOOLEAN, 3,
1570 		  G_TYPE_BOOLEAN,
1571 		  G_TYPE_BOOLEAN,
1572 		  G_TYPE_BOOLEAN);
1573   g_signal_set_va_marshaller (tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW],
1574                               G_TYPE_FROM_CLASS (o_class),
1575                               _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEANv);
1576 
1577   tree_view_signals[SELECT_CURSOR_PARENT] =
1578     g_signal_new (I_("select-cursor-parent"),
1579 		  G_TYPE_FROM_CLASS (o_class),
1580 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1581 		  G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1582 		  NULL, NULL,
1583 		  _gtk_marshal_BOOLEAN__VOID,
1584 		  G_TYPE_BOOLEAN, 0);
1585   g_signal_set_va_marshaller (tree_view_signals[SELECT_CURSOR_PARENT],
1586                               G_TYPE_FROM_CLASS (o_class),
1587                               _gtk_marshal_BOOLEAN__VOIDv);
1588 
1589   tree_view_signals[START_INTERACTIVE_SEARCH] =
1590     g_signal_new (I_("start-interactive-search"),
1591 		  G_TYPE_FROM_CLASS (o_class),
1592 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1593 		  G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1594 		  NULL, NULL,
1595 		  _gtk_marshal_BOOLEAN__VOID,
1596 		  G_TYPE_BOOLEAN, 0);
1597   g_signal_set_va_marshaller (tree_view_signals[START_INTERACTIVE_SEARCH],
1598                               G_TYPE_FROM_CLASS (o_class),
1599                               _gtk_marshal_BOOLEAN__VOIDv);
1600 
1601   /* Key bindings */
1602   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1603 				  GTK_MOVEMENT_DISPLAY_LINES, -1);
1604   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1605 				  GTK_MOVEMENT_DISPLAY_LINES, -1);
1606 
1607   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1608 				  GTK_MOVEMENT_DISPLAY_LINES, 1);
1609   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1610 				  GTK_MOVEMENT_DISPLAY_LINES, 1);
1611 
1612   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1613 				  GTK_MOVEMENT_DISPLAY_LINES, -1);
1614 
1615   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1616 				  GTK_MOVEMENT_DISPLAY_LINES, 1);
1617 
1618   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1619 				  GTK_MOVEMENT_BUFFER_ENDS, -1);
1620   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1621 				  GTK_MOVEMENT_BUFFER_ENDS, -1);
1622 
1623   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1624 				  GTK_MOVEMENT_BUFFER_ENDS, 1);
1625   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1626 				  GTK_MOVEMENT_BUFFER_ENDS, 1);
1627 
1628   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1629 				  GTK_MOVEMENT_PAGES, -1);
1630   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1631 				  GTK_MOVEMENT_PAGES, -1);
1632 
1633   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1634 				  GTK_MOVEMENT_PAGES, 1);
1635   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1636 				  GTK_MOVEMENT_PAGES, 1);
1637 
1638 
1639   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1640 				G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1641 				G_TYPE_INT, 1);
1642 
1643   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1644 				G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1645 				G_TYPE_INT, -1);
1646 
1647   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1648 				G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1649 				G_TYPE_INT, 1);
1650 
1651   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1652 				G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1653 				G_TYPE_INT, -1);
1654 
1655   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1656                                 "move-cursor", 2,
1657 				G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1658 				G_TYPE_INT, 1);
1659 
1660   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1661                                 "move-cursor", 2,
1662 				G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1663 				G_TYPE_INT, -1);
1664 
1665   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1666                                 "move-cursor", 2,
1667 				G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1668 				G_TYPE_INT, 1);
1669 
1670   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1671                                 "move-cursor", 2,
1672 				G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1673 				G_TYPE_INT, -1);
1674 
1675   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1676   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1677 
1678   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1679   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1680 
1681   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1682   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1683 
1684   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1685 				G_TYPE_BOOLEAN, TRUE);
1686   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1687 				G_TYPE_BOOLEAN, TRUE);
1688 
1689   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1690 				G_TYPE_BOOLEAN, TRUE);
1691   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1692 				G_TYPE_BOOLEAN, TRUE);
1693   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1694 				G_TYPE_BOOLEAN, TRUE);
1695   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1696 				G_TYPE_BOOLEAN, TRUE);
1697   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1698 				G_TYPE_BOOLEAN, TRUE);
1699 
1700   /* expand and collapse rows */
1701   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1702 				G_TYPE_BOOLEAN, TRUE,
1703 				G_TYPE_BOOLEAN, TRUE,
1704 				G_TYPE_BOOLEAN, FALSE);
1705 
1706   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1707                                 "expand-collapse-cursor-row", 3,
1708                                 G_TYPE_BOOLEAN, TRUE,
1709                                 G_TYPE_BOOLEAN, TRUE,
1710                                 G_TYPE_BOOLEAN, TRUE);
1711   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1712                                 "expand-collapse-cursor-row", 3,
1713                                 G_TYPE_BOOLEAN, TRUE,
1714                                 G_TYPE_BOOLEAN, TRUE,
1715                                 G_TYPE_BOOLEAN, TRUE);
1716 
1717   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1718                                 "expand-collapse-cursor-row", 3,
1719                                 G_TYPE_BOOLEAN, TRUE,
1720                                 G_TYPE_BOOLEAN, FALSE,
1721                                 G_TYPE_BOOLEAN, FALSE);
1722   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1723                                 "expand-collapse-cursor-row", 3,
1724                                 G_TYPE_BOOLEAN, TRUE,
1725                                 G_TYPE_BOOLEAN, FALSE,
1726                                 G_TYPE_BOOLEAN, FALSE);
1727 
1728   /* Not doable on US keyboards */
1729   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1730 				G_TYPE_BOOLEAN, TRUE,
1731 				G_TYPE_BOOLEAN, TRUE,
1732 				G_TYPE_BOOLEAN, TRUE);
1733   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1734 				G_TYPE_BOOLEAN, TRUE,
1735 				G_TYPE_BOOLEAN, TRUE,
1736 				G_TYPE_BOOLEAN, FALSE);
1737   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1738 				G_TYPE_BOOLEAN, TRUE,
1739 				G_TYPE_BOOLEAN, TRUE,
1740 				G_TYPE_BOOLEAN, TRUE);
1741   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1742 				G_TYPE_BOOLEAN, TRUE,
1743 				G_TYPE_BOOLEAN, TRUE,
1744 				G_TYPE_BOOLEAN, TRUE);
1745   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1746                                 "expand-collapse-cursor-row", 3,
1747 				G_TYPE_BOOLEAN, FALSE,
1748 				G_TYPE_BOOLEAN, TRUE,
1749 				G_TYPE_BOOLEAN, TRUE);
1750   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1751                                 "expand-collapse-cursor-row", 3,
1752 				G_TYPE_BOOLEAN, FALSE,
1753 				G_TYPE_BOOLEAN, TRUE,
1754 				G_TYPE_BOOLEAN, TRUE);
1755   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1756                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1757                                 "expand-collapse-cursor-row", 3,
1758 				G_TYPE_BOOLEAN, FALSE,
1759 				G_TYPE_BOOLEAN, TRUE,
1760 				G_TYPE_BOOLEAN, TRUE);
1761   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1762                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1763                                 "expand-collapse-cursor-row", 3,
1764 				G_TYPE_BOOLEAN, FALSE,
1765 				G_TYPE_BOOLEAN, TRUE,
1766 				G_TYPE_BOOLEAN, TRUE);
1767 
1768   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1769 				G_TYPE_BOOLEAN, TRUE,
1770 				G_TYPE_BOOLEAN, FALSE,
1771 				G_TYPE_BOOLEAN, FALSE);
1772   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1773 				G_TYPE_BOOLEAN, TRUE,
1774 				G_TYPE_BOOLEAN, FALSE,
1775 				G_TYPE_BOOLEAN, TRUE);
1776   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1777 				G_TYPE_BOOLEAN, TRUE,
1778 				G_TYPE_BOOLEAN, FALSE,
1779 				G_TYPE_BOOLEAN, FALSE);
1780   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1781 				G_TYPE_BOOLEAN, TRUE,
1782 				G_TYPE_BOOLEAN, FALSE,
1783 				G_TYPE_BOOLEAN, TRUE);
1784   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1785                                 "expand-collapse-cursor-row", 3,
1786 				G_TYPE_BOOLEAN, FALSE,
1787 				G_TYPE_BOOLEAN, FALSE,
1788 				G_TYPE_BOOLEAN, TRUE);
1789   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1790                                 "expand-collapse-cursor-row", 3,
1791 				G_TYPE_BOOLEAN, FALSE,
1792 				G_TYPE_BOOLEAN, FALSE,
1793 				G_TYPE_BOOLEAN, TRUE);
1794   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1795                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1796                                 "expand-collapse-cursor-row", 3,
1797 				G_TYPE_BOOLEAN, FALSE,
1798 				G_TYPE_BOOLEAN, FALSE,
1799 				G_TYPE_BOOLEAN, TRUE);
1800   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1801                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1802                                 "expand-collapse-cursor-row", 3,
1803 				G_TYPE_BOOLEAN, FALSE,
1804 				G_TYPE_BOOLEAN, FALSE,
1805 				G_TYPE_BOOLEAN, TRUE);
1806 
1807   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1808   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1809 
1810   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1811 
1812   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1813 
1814   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_TREE_VIEW_ACCESSIBLE);
1815   gtk_widget_class_set_css_name (widget_class, "treeview");
1816 }
1817 
1818 static void
gtk_tree_view_init(GtkTreeView * tree_view)1819 gtk_tree_view_init (GtkTreeView *tree_view)
1820 {
1821   GtkTreeViewPrivate *priv;
1822   GtkCssNode *widget_node;
1823 
1824   priv = tree_view->priv = gtk_tree_view_get_instance_private (tree_view);
1825 
1826   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1827 
1828   priv->show_expanders = TRUE;
1829   priv->draw_keyfocus = TRUE;
1830   priv->headers_visible = TRUE;
1831   priv->activate_on_single_click = FALSE;
1832 
1833   priv->pixel_cache = _gtk_pixel_cache_new ();
1834 
1835   /* We need some padding */
1836   priv->dy = 0;
1837   priv->cursor_offset = 0;
1838   priv->n_columns = 0;
1839   priv->header_height = 1;
1840   priv->x_drag = 0;
1841   priv->drag_pos = -1;
1842   priv->header_has_focus = FALSE;
1843   priv->press_start_x = -1;
1844   priv->press_start_y = -1;
1845   priv->reorderable = FALSE;
1846   priv->presize_handler_tick_cb = 0;
1847   priv->scroll_sync_timer = 0;
1848   priv->fixed_height = -1;
1849   priv->fixed_height_mode = FALSE;
1850   priv->fixed_height_check = 0;
1851   priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1852   priv->enable_search = TRUE;
1853   priv->search_column = -1;
1854   priv->search_position_func = gtk_tree_view_search_position_func;
1855   priv->search_equal_func = gtk_tree_view_search_equal_func;
1856   priv->search_custom_entry_set = FALSE;
1857   priv->typeselect_flush_timeout = 0;
1858   priv->init_hadjust_value = TRUE;
1859   priv->width = 0;
1860 
1861   priv->hover_selection = FALSE;
1862   priv->hover_expand = FALSE;
1863 
1864   priv->level_indentation = 0;
1865 
1866   priv->rubber_banding_enable = FALSE;
1867 
1868   priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1869   priv->tree_lines_enabled = FALSE;
1870 
1871   priv->tooltip_column = -1;
1872 
1873   priv->post_validation_flag = FALSE;
1874 
1875   priv->event_last_x = -10000;
1876   priv->event_last_y = -10000;
1877 
1878   gtk_tree_view_do_set_vadjustment (tree_view, NULL);
1879   gtk_tree_view_do_set_hadjustment (tree_view, NULL);
1880 
1881   gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (tree_view)),
1882                                GTK_STYLE_CLASS_VIEW);
1883 
1884   widget_node = gtk_widget_get_css_node (GTK_WIDGET (tree_view));
1885   priv->header_node = gtk_css_node_new ();
1886   gtk_css_node_set_name (priv->header_node, I_("header"));
1887   gtk_css_node_set_parent (priv->header_node, widget_node);
1888   gtk_css_node_set_state (priv->header_node, gtk_css_node_get_state (widget_node));
1889   g_object_unref (priv->header_node);
1890 
1891   priv->multipress_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (tree_view));
1892   gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->multipress_gesture), 0);
1893   g_signal_connect (priv->multipress_gesture, "pressed",
1894                     G_CALLBACK (gtk_tree_view_multipress_gesture_pressed), tree_view);
1895   g_signal_connect (priv->multipress_gesture, "released",
1896                     G_CALLBACK (gtk_tree_view_multipress_gesture_released), tree_view);
1897 
1898   priv->column_multipress_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (tree_view));
1899   g_signal_connect (priv->column_multipress_gesture, "pressed",
1900                     G_CALLBACK (gtk_tree_view_column_multipress_gesture_pressed), tree_view);
1901   gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (priv->column_multipress_gesture),
1902                                               GTK_PHASE_CAPTURE);
1903 
1904   priv->drag_gesture = gtk_gesture_drag_new (GTK_WIDGET (tree_view));
1905   g_signal_connect (priv->drag_gesture, "drag-begin",
1906                     G_CALLBACK (gtk_tree_view_drag_gesture_begin), tree_view);
1907   g_signal_connect (priv->drag_gesture, "drag-update",
1908                     G_CALLBACK (gtk_tree_view_drag_gesture_update), tree_view);
1909   g_signal_connect (priv->drag_gesture, "drag-end",
1910                     G_CALLBACK (gtk_tree_view_drag_gesture_end), tree_view);
1911 
1912   priv->column_drag_gesture = gtk_gesture_drag_new (GTK_WIDGET (tree_view));
1913   g_signal_connect (priv->column_drag_gesture, "drag-begin",
1914                     G_CALLBACK (gtk_tree_view_column_drag_gesture_begin), tree_view);
1915   g_signal_connect (priv->column_drag_gesture, "drag-update",
1916                     G_CALLBACK (gtk_tree_view_column_drag_gesture_update), tree_view);
1917   g_signal_connect (priv->column_drag_gesture, "drag-end",
1918                     G_CALLBACK (gtk_tree_view_column_drag_gesture_end), tree_view);
1919   gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (priv->column_drag_gesture),
1920                                               GTK_PHASE_CAPTURE);
1921 }
1922 
1923 
1924 
1925 /* GObject Methods
1926  */
1927 
1928 static void
gtk_tree_view_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1929 gtk_tree_view_set_property (GObject         *object,
1930 			    guint            prop_id,
1931 			    const GValue    *value,
1932 			    GParamSpec      *pspec)
1933 {
1934   GtkTreeView *tree_view;
1935 
1936   tree_view = GTK_TREE_VIEW (object);
1937 
1938   switch (prop_id)
1939     {
1940     case PROP_MODEL:
1941       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1942       break;
1943     case PROP_HADJUSTMENT:
1944       gtk_tree_view_do_set_hadjustment (tree_view, g_value_get_object (value));
1945       break;
1946     case PROP_VADJUSTMENT:
1947       gtk_tree_view_do_set_vadjustment (tree_view, g_value_get_object (value));
1948       break;
1949     case PROP_HSCROLL_POLICY:
1950       if (tree_view->priv->hscroll_policy != g_value_get_enum (value))
1951         {
1952           tree_view->priv->hscroll_policy = g_value_get_enum (value);
1953           gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1954           g_object_notify_by_pspec (object, pspec);
1955         }
1956       break;
1957     case PROP_VSCROLL_POLICY:
1958       if (tree_view->priv->vscroll_policy != g_value_get_enum (value))
1959         {
1960           tree_view->priv->vscroll_policy = g_value_get_enum (value);
1961           gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1962           g_object_notify_by_pspec (object, pspec);
1963         }
1964       break;
1965     case PROP_HEADERS_VISIBLE:
1966       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1967       break;
1968     case PROP_HEADERS_CLICKABLE:
1969       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1970       break;
1971     case PROP_EXPANDER_COLUMN:
1972       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1973       break;
1974     case PROP_REORDERABLE:
1975       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1976       break;
1977     case PROP_RULES_HINT:
1978 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1979       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1980 G_GNUC_END_IGNORE_DEPRECATIONS
1981       break;
1982     case PROP_ENABLE_SEARCH:
1983       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1984       break;
1985     case PROP_SEARCH_COLUMN:
1986       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1987       break;
1988     case PROP_FIXED_HEIGHT_MODE:
1989       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1990       break;
1991     case PROP_HOVER_SELECTION:
1992       if (tree_view->priv->hover_selection != g_value_get_boolean (value))
1993         {
1994           tree_view->priv->hover_selection = g_value_get_boolean (value);
1995           g_object_notify_by_pspec (object, pspec);
1996         }
1997       break;
1998     case PROP_HOVER_EXPAND:
1999       if (tree_view->priv->hover_expand != g_value_get_boolean (value))
2000         {
2001           tree_view->priv->hover_expand = g_value_get_boolean (value);
2002           g_object_notify_by_pspec (object, pspec);
2003         }
2004       break;
2005     case PROP_SHOW_EXPANDERS:
2006       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
2007       break;
2008     case PROP_LEVEL_INDENTATION:
2009       if (tree_view->priv->level_indentation != g_value_get_int (value))
2010         {
2011           tree_view->priv->level_indentation = g_value_get_int (value);
2012           g_object_notify_by_pspec (object, pspec);
2013         }
2014       break;
2015     case PROP_RUBBER_BANDING:
2016       if (tree_view->priv->rubber_banding_enable != g_value_get_boolean (value))
2017         {
2018           tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
2019           g_object_notify_by_pspec (object, pspec);
2020         }
2021       break;
2022     case PROP_ENABLE_GRID_LINES:
2023       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
2024       break;
2025     case PROP_ENABLE_TREE_LINES:
2026       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
2027       break;
2028     case PROP_TOOLTIP_COLUMN:
2029       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
2030       break;
2031     case PROP_ACTIVATE_ON_SINGLE_CLICK:
2032       gtk_tree_view_set_activate_on_single_click (tree_view, g_value_get_boolean (value));
2033       break;
2034     default:
2035       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2036       break;
2037     }
2038 }
2039 
2040 static void
gtk_tree_view_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)2041 gtk_tree_view_get_property (GObject    *object,
2042 			    guint       prop_id,
2043 			    GValue     *value,
2044 			    GParamSpec *pspec)
2045 {
2046   GtkTreeView *tree_view;
2047 
2048   tree_view = GTK_TREE_VIEW (object);
2049 
2050   switch (prop_id)
2051     {
2052     case PROP_MODEL:
2053       g_value_set_object (value, tree_view->priv->model);
2054       break;
2055     case PROP_HADJUSTMENT:
2056       g_value_set_object (value, tree_view->priv->hadjustment);
2057       break;
2058     case PROP_VADJUSTMENT:
2059       g_value_set_object (value, tree_view->priv->vadjustment);
2060       break;
2061     case PROP_HSCROLL_POLICY:
2062       g_value_set_enum (value, tree_view->priv->hscroll_policy);
2063       break;
2064     case PROP_VSCROLL_POLICY:
2065       g_value_set_enum (value, tree_view->priv->vscroll_policy);
2066       break;
2067     case PROP_HEADERS_VISIBLE:
2068       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
2069       break;
2070     case PROP_HEADERS_CLICKABLE:
2071       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
2072       break;
2073     case PROP_EXPANDER_COLUMN:
2074       g_value_set_object (value, tree_view->priv->expander_column);
2075       break;
2076     case PROP_REORDERABLE:
2077       g_value_set_boolean (value, tree_view->priv->reorderable);
2078       break;
2079     case PROP_RULES_HINT:
2080       g_value_set_boolean (value, tree_view->priv->has_rules);
2081       break;
2082     case PROP_ENABLE_SEARCH:
2083       g_value_set_boolean (value, tree_view->priv->enable_search);
2084       break;
2085     case PROP_SEARCH_COLUMN:
2086       g_value_set_int (value, tree_view->priv->search_column);
2087       break;
2088     case PROP_FIXED_HEIGHT_MODE:
2089       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
2090       break;
2091     case PROP_HOVER_SELECTION:
2092       g_value_set_boolean (value, tree_view->priv->hover_selection);
2093       break;
2094     case PROP_HOVER_EXPAND:
2095       g_value_set_boolean (value, tree_view->priv->hover_expand);
2096       break;
2097     case PROP_SHOW_EXPANDERS:
2098       g_value_set_boolean (value, tree_view->priv->show_expanders);
2099       break;
2100     case PROP_LEVEL_INDENTATION:
2101       g_value_set_int (value, tree_view->priv->level_indentation);
2102       break;
2103     case PROP_RUBBER_BANDING:
2104       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
2105       break;
2106     case PROP_ENABLE_GRID_LINES:
2107       g_value_set_enum (value, tree_view->priv->grid_lines);
2108       break;
2109     case PROP_ENABLE_TREE_LINES:
2110       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
2111       break;
2112     case PROP_TOOLTIP_COLUMN:
2113       g_value_set_int (value, tree_view->priv->tooltip_column);
2114       break;
2115     case PROP_ACTIVATE_ON_SINGLE_CLICK:
2116       g_value_set_boolean (value, tree_view->priv->activate_on_single_click);
2117       break;
2118     default:
2119       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2120       break;
2121     }
2122 }
2123 
2124 static void
gtk_tree_view_finalize(GObject * object)2125 gtk_tree_view_finalize (GObject *object)
2126 {
2127   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
2128 }
2129 
2130 
2131 static GtkBuildableIface *parent_buildable_iface;
2132 
2133 static void
gtk_tree_view_buildable_init(GtkBuildableIface * iface)2134 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
2135 {
2136   parent_buildable_iface = g_type_interface_peek_parent (iface);
2137   iface->add_child = gtk_tree_view_buildable_add_child;
2138   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
2139 }
2140 
2141 static void
gtk_tree_view_buildable_add_child(GtkBuildable * tree_view,GtkBuilder * builder,GObject * child,const gchar * type)2142 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
2143 				   GtkBuilder  *builder,
2144 				   GObject     *child,
2145 				   const gchar *type)
2146 {
2147   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
2148 }
2149 
2150 static GObject *
gtk_tree_view_buildable_get_internal_child(GtkBuildable * buildable,GtkBuilder * builder,const gchar * childname)2151 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
2152 					    GtkBuilder        *builder,
2153 					    const gchar       *childname)
2154 {
2155     if (strcmp (childname, "selection") == 0)
2156       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
2157 
2158     return parent_buildable_iface->get_internal_child (buildable,
2159 						       builder,
2160 						       childname);
2161 }
2162 
2163 /* GtkWidget Methods
2164  */
2165 
2166 static void
gtk_tree_view_free_rbtree(GtkTreeView * tree_view)2167 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
2168 {
2169   _gtk_rbtree_free (tree_view->priv->tree);
2170 
2171   tree_view->priv->tree = NULL;
2172   tree_view->priv->button_pressed_node = NULL;
2173   tree_view->priv->button_pressed_tree = NULL;
2174   tree_view->priv->prelight_tree = NULL;
2175   tree_view->priv->prelight_node = NULL;
2176 }
2177 
2178 static void
gtk_tree_view_destroy_search_window(GtkTreeView * tree_view)2179 gtk_tree_view_destroy_search_window (GtkTreeView *tree_view)
2180 {
2181   gtk_widget_destroy (tree_view->priv->search_window);
2182 
2183   tree_view->priv->search_window = NULL;
2184   tree_view->priv->search_entry = NULL;
2185   tree_view->priv->search_entry_changed_id = 0;
2186 }
2187 
2188 static void
gtk_tree_view_destroy(GtkWidget * widget)2189 gtk_tree_view_destroy (GtkWidget *widget)
2190 {
2191   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2192   GList *list;
2193 
2194   gtk_tree_view_stop_editing (tree_view, TRUE);
2195   gtk_tree_view_stop_rubber_band (tree_view);
2196 
2197   if (tree_view->priv->columns != NULL)
2198     {
2199       list = tree_view->priv->columns;
2200       while (list)
2201 	{
2202 	  GtkTreeViewColumn *column;
2203 	  column = GTK_TREE_VIEW_COLUMN (list->data);
2204 	  list = list->next;
2205 	  gtk_tree_view_remove_column (tree_view, column);
2206 	}
2207       tree_view->priv->columns = NULL;
2208     }
2209 
2210   if (tree_view->priv->tree != NULL)
2211     {
2212       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
2213 
2214       gtk_tree_view_free_rbtree (tree_view);
2215     }
2216 
2217   if (tree_view->priv->selection != NULL)
2218     {
2219       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
2220       g_object_unref (tree_view->priv->selection);
2221       tree_view->priv->selection = NULL;
2222     }
2223 
2224   if (tree_view->priv->scroll_to_path != NULL)
2225     {
2226       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
2227       tree_view->priv->scroll_to_path = NULL;
2228     }
2229 
2230   if (tree_view->priv->drag_dest_row != NULL)
2231     {
2232       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
2233       tree_view->priv->drag_dest_row = NULL;
2234     }
2235 
2236   if (tree_view->priv->top_row != NULL)
2237     {
2238       gtk_tree_row_reference_free (tree_view->priv->top_row);
2239       tree_view->priv->top_row = NULL;
2240     }
2241 
2242   if (tree_view->priv->column_drop_func_data &&
2243       tree_view->priv->column_drop_func_data_destroy)
2244     {
2245       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
2246       tree_view->priv->column_drop_func_data = NULL;
2247     }
2248 
2249   if (tree_view->priv->destroy_count_destroy &&
2250       tree_view->priv->destroy_count_data)
2251     {
2252       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
2253       tree_view->priv->destroy_count_data = NULL;
2254     }
2255 
2256   gtk_tree_row_reference_free (tree_view->priv->anchor);
2257   tree_view->priv->anchor = NULL;
2258 
2259   /* destroy interactive search dialog */
2260   if (tree_view->priv->search_window)
2261     {
2262       gtk_tree_view_destroy_search_window (tree_view);
2263       if (tree_view->priv->typeselect_flush_timeout)
2264 	{
2265 	  g_source_remove (tree_view->priv->typeselect_flush_timeout);
2266 	  tree_view->priv->typeselect_flush_timeout = 0;
2267 	}
2268     }
2269 
2270   if (tree_view->priv->search_custom_entry_set)
2271     {
2272       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
2273                                             G_CALLBACK (gtk_tree_view_search_init),
2274                                             tree_view);
2275       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
2276                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
2277                                             tree_view);
2278 
2279       g_object_unref (tree_view->priv->search_entry);
2280 
2281       tree_view->priv->search_entry = NULL;
2282       tree_view->priv->search_custom_entry_set = FALSE;
2283     }
2284 
2285   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
2286     {
2287       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
2288       tree_view->priv->search_user_data = NULL;
2289     }
2290 
2291   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
2292     {
2293       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
2294       tree_view->priv->search_position_user_data = NULL;
2295     }
2296 
2297   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
2298     {
2299       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
2300       tree_view->priv->row_separator_data = NULL;
2301     }
2302 
2303   gtk_tree_view_set_model (tree_view, NULL);
2304 
2305   if (tree_view->priv->hadjustment)
2306     {
2307       g_object_unref (tree_view->priv->hadjustment);
2308       tree_view->priv->hadjustment = NULL;
2309     }
2310   if (tree_view->priv->vadjustment)
2311     {
2312       g_object_unref (tree_view->priv->vadjustment);
2313       tree_view->priv->vadjustment = NULL;
2314     }
2315 
2316   if (tree_view->priv->pixel_cache)
2317     _gtk_pixel_cache_free (tree_view->priv->pixel_cache);
2318   tree_view->priv->pixel_cache = NULL;
2319 
2320   g_clear_object (&tree_view->priv->multipress_gesture);
2321   g_clear_object (&tree_view->priv->drag_gesture);
2322   g_clear_object (&tree_view->priv->column_multipress_gesture);
2323   g_clear_object (&tree_view->priv->column_drag_gesture);
2324 
2325   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
2326 }
2327 
2328 /* GtkWidget::map helper */
2329 static void
gtk_tree_view_map_buttons(GtkTreeView * tree_view)2330 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
2331 {
2332   GList *list;
2333 
2334   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
2335 
2336   if (tree_view->priv->headers_visible)
2337     {
2338       GtkTreeViewColumn *column;
2339       GtkWidget         *button;
2340       GdkWindow         *window;
2341 
2342       for (list = tree_view->priv->columns; list; list = list->next)
2343 	{
2344 	  column = list->data;
2345 	  button = gtk_tree_view_column_get_button (column);
2346 
2347           if (gtk_tree_view_column_get_visible (column) && button)
2348             gtk_widget_show_now (button);
2349 
2350           if (gtk_widget_get_visible (button) &&
2351               !gtk_widget_get_mapped (button))
2352             gtk_widget_map (button);
2353 	}
2354       for (list = tree_view->priv->columns; list; list = list->next)
2355 	{
2356 	  column = list->data;
2357 	  if (gtk_tree_view_column_get_visible (column) == FALSE)
2358 	    continue;
2359 
2360 	  window = _gtk_tree_view_column_get_window (column);
2361 	  if (gtk_tree_view_column_get_resizable (column))
2362 	    {
2363 	      gdk_window_raise (window);
2364 	      gdk_window_show (window);
2365 	    }
2366 	  else
2367 	    gdk_window_hide (window);
2368 	}
2369       gdk_window_show (tree_view->priv->header_window);
2370     }
2371 }
2372 
2373 static void
gtk_tree_view_map(GtkWidget * widget)2374 gtk_tree_view_map (GtkWidget *widget)
2375 {
2376   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2377   GList *tmp_list;
2378 
2379   _gtk_pixel_cache_map (tree_view->priv->pixel_cache);
2380 
2381   gtk_widget_set_mapped (widget, TRUE);
2382 
2383   tmp_list = tree_view->priv->children;
2384   while (tmp_list)
2385     {
2386       GtkTreeViewChild *child = tmp_list->data;
2387       tmp_list = tmp_list->next;
2388 
2389       if (gtk_widget_get_visible (child->widget))
2390 	{
2391 	  if (!gtk_widget_get_mapped (child->widget))
2392 	    gtk_widget_map (child->widget);
2393 	}
2394     }
2395   gdk_window_show (tree_view->priv->bin_window);
2396 
2397   gtk_tree_view_map_buttons (tree_view);
2398 
2399   gdk_window_show (gtk_widget_get_window (widget));
2400 }
2401 
2402 static void
gtk_tree_view_unmap(GtkWidget * widget)2403 gtk_tree_view_unmap (GtkWidget *widget)
2404 {
2405   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2406 
2407   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unmap (widget);
2408 
2409   _gtk_pixel_cache_unmap (tree_view->priv->pixel_cache);
2410 }
2411 
2412 static void
gtk_tree_view_bin_window_invalidate_handler(GdkWindow * window,cairo_region_t * region)2413 gtk_tree_view_bin_window_invalidate_handler (GdkWindow *window,
2414 					     cairo_region_t *region)
2415 {
2416   gpointer widget;
2417   GtkTreeView *tree_view;
2418   int y;
2419 
2420   gdk_window_get_user_data (window, &widget);
2421   tree_view = GTK_TREE_VIEW (widget);
2422 
2423   y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
2424   cairo_region_translate (region,
2425 			  0, y);
2426   _gtk_pixel_cache_invalidate (tree_view->priv->pixel_cache, region);
2427   cairo_region_translate (region,
2428 			  0, -y);
2429 }
2430 
2431 static void
gtk_tree_view_queue_draw_region(GtkWidget * widget,const cairo_region_t * region)2432 gtk_tree_view_queue_draw_region (GtkWidget *widget,
2433 				 const cairo_region_t *region)
2434 {
2435   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2436 
2437   /* There is no way we can know if a region targets the
2438      not-currently-visible but in pixel cache region, so we
2439      always just invalidate the whole thing whenever the
2440      tree view gets a queue draw. This doesn't normally happen
2441      in normal scrolling cases anyway. */
2442   _gtk_pixel_cache_invalidate (tree_view->priv->pixel_cache, NULL);
2443 
2444   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->queue_draw_region (widget,
2445 								    region);
2446 }
2447 
2448 static void
gtk_tree_view_realize(GtkWidget * widget)2449 gtk_tree_view_realize (GtkWidget *widget)
2450 {
2451   GtkAllocation allocation;
2452   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2453   GdkWindow *window;
2454   GdkWindowAttr attributes;
2455   GList *tmp_list;
2456   gint attributes_mask;
2457 
2458   gtk_widget_set_realized (widget, TRUE);
2459 
2460   gtk_widget_get_allocation (widget, &allocation);
2461 
2462   /* Make the main, clipping window */
2463   attributes.window_type = GDK_WINDOW_CHILD;
2464   attributes.x = allocation.x;
2465   attributes.y = allocation.y;
2466   attributes.width = allocation.width;
2467   attributes.height = allocation.height;
2468   attributes.wclass = GDK_INPUT_OUTPUT;
2469   attributes.visual = gtk_widget_get_visual (widget);
2470   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
2471 
2472   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2473 
2474   window = gdk_window_new (gtk_widget_get_parent_window (widget),
2475                            &attributes, attributes_mask);
2476   gtk_widget_set_window (widget, window);
2477   gtk_widget_register_window (widget, window);
2478 
2479   gtk_widget_get_allocation (widget, &allocation);
2480 
2481   /* Make the window for the tree */
2482   attributes.x = 0;
2483   attributes.y = gtk_tree_view_get_effective_header_height (tree_view);
2484   attributes.width = MAX (tree_view->priv->width, allocation.width);
2485   attributes.height = allocation.height;
2486   attributes.event_mask = (GDK_SCROLL_MASK |
2487                            GDK_SMOOTH_SCROLL_MASK |
2488                            GDK_POINTER_MOTION_MASK |
2489                            GDK_ENTER_NOTIFY_MASK |
2490                            GDK_LEAVE_NOTIFY_MASK |
2491                            GDK_BUTTON_PRESS_MASK |
2492                            GDK_BUTTON_RELEASE_MASK |
2493                            gtk_widget_get_events (widget));
2494 
2495   tree_view->priv->bin_window = gdk_window_new (window,
2496 						&attributes, attributes_mask);
2497   gtk_widget_register_window (widget, tree_view->priv->bin_window);
2498   gdk_window_set_invalidate_handler (tree_view->priv->bin_window,
2499 				     gtk_tree_view_bin_window_invalidate_handler);
2500 
2501   gtk_widget_get_allocation (widget, &allocation);
2502 
2503   /* Make the column header window */
2504   attributes.x = 0;
2505   attributes.y = 0;
2506   attributes.width = MAX (tree_view->priv->width, allocation.width);
2507   attributes.height = tree_view->priv->header_height;
2508   attributes.event_mask = (GDK_SCROLL_MASK |
2509                            GDK_ENTER_NOTIFY_MASK |
2510                            GDK_LEAVE_NOTIFY_MASK |
2511                            GDK_BUTTON_PRESS_MASK |
2512                            GDK_BUTTON_RELEASE_MASK |
2513                            GDK_KEY_PRESS_MASK |
2514                            GDK_KEY_RELEASE_MASK |
2515                            gtk_widget_get_events (widget));
2516 
2517   tree_view->priv->header_window = gdk_window_new (window,
2518 						   &attributes, attributes_mask);
2519   gtk_widget_register_window (widget, tree_view->priv->header_window);
2520 
2521   tmp_list = tree_view->priv->children;
2522   while (tmp_list)
2523     {
2524       GtkTreeViewChild *child = tmp_list->data;
2525       tmp_list = tmp_list->next;
2526 
2527       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
2528     }
2529 
2530   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2531     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
2532 
2533   /* Need to call those here, since they create GCs */
2534   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
2535   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
2536 
2537   install_presize_handler (tree_view);
2538 
2539   gtk_gesture_set_window (tree_view->priv->multipress_gesture,
2540                           tree_view->priv->bin_window);
2541   gtk_gesture_set_window (tree_view->priv->drag_gesture,
2542                           tree_view->priv->bin_window);
2543 }
2544 
2545 static void
gtk_tree_view_unrealize(GtkWidget * widget)2546 gtk_tree_view_unrealize (GtkWidget *widget)
2547 {
2548   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2549   GtkTreeViewPrivate *priv = tree_view->priv;
2550   GList *list;
2551 
2552   if (priv->scroll_timeout != 0)
2553     {
2554       g_source_remove (priv->scroll_timeout);
2555       priv->scroll_timeout = 0;
2556     }
2557 
2558   if (priv->auto_expand_timeout != 0)
2559     {
2560       g_source_remove (priv->auto_expand_timeout);
2561       priv->auto_expand_timeout = 0;
2562     }
2563 
2564   if (priv->open_dest_timeout != 0)
2565     {
2566       g_source_remove (priv->open_dest_timeout);
2567       priv->open_dest_timeout = 0;
2568     }
2569 
2570   if (priv->presize_handler_tick_cb != 0)
2571     {
2572       gtk_widget_remove_tick_callback (widget, priv->presize_handler_tick_cb);
2573       priv->presize_handler_tick_cb = 0;
2574     }
2575 
2576   if (priv->validate_rows_timer != 0)
2577     {
2578       g_source_remove (priv->validate_rows_timer);
2579       priv->validate_rows_timer = 0;
2580     }
2581 
2582   if (priv->scroll_sync_timer != 0)
2583     {
2584       g_source_remove (priv->scroll_sync_timer);
2585       priv->scroll_sync_timer = 0;
2586     }
2587 
2588   if (priv->typeselect_flush_timeout)
2589     {
2590       g_source_remove (priv->typeselect_flush_timeout);
2591       priv->typeselect_flush_timeout = 0;
2592     }
2593 
2594   for (list = priv->columns; list; list = list->next)
2595     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
2596 
2597   gtk_widget_unregister_window (widget, priv->bin_window);
2598   gdk_window_destroy (priv->bin_window);
2599   priv->bin_window = NULL;
2600 
2601   gtk_widget_unregister_window (widget, priv->header_window);
2602   gdk_window_destroy (priv->header_window);
2603   priv->header_window = NULL;
2604 
2605   if (priv->drag_window)
2606     {
2607       gtk_widget_unregister_window (widget, priv->drag_window);
2608       gdk_window_destroy (priv->drag_window);
2609       priv->drag_window = NULL;
2610     }
2611 
2612   if (priv->drag_highlight_window)
2613     {
2614       gtk_widget_unregister_window (widget, priv->drag_highlight_window);
2615       gdk_window_destroy (priv->drag_highlight_window);
2616       priv->drag_highlight_window = NULL;
2617     }
2618 
2619   gtk_gesture_set_window (tree_view->priv->multipress_gesture, NULL);
2620   gtk_gesture_set_window (tree_view->priv->drag_gesture, NULL);
2621 
2622   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
2623 }
2624 
2625 /* GtkWidget::get_preferred_height helper */
2626 static void
gtk_tree_view_update_height(GtkTreeView * tree_view)2627 gtk_tree_view_update_height (GtkTreeView *tree_view)
2628 {
2629   GList *list;
2630 
2631   tree_view->priv->header_height = 0;
2632 
2633   for (list = tree_view->priv->columns; list; list = list->next)
2634     {
2635       GtkRequisition     requisition;
2636       GtkTreeViewColumn *column = list->data;
2637       GtkWidget         *button = gtk_tree_view_column_get_button (column);
2638 
2639       if (button == NULL)
2640         continue;
2641 
2642       gtk_widget_get_preferred_size (button, &requisition, NULL);
2643       tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2644     }
2645 }
2646 
2647 static gint
gtk_tree_view_get_height(GtkTreeView * tree_view)2648 gtk_tree_view_get_height (GtkTreeView *tree_view)
2649 {
2650   if (tree_view->priv->tree == NULL)
2651     return 0;
2652   else
2653     return tree_view->priv->tree->root->offset;
2654 }
2655 
2656 static void
gtk_tree_view_get_preferred_width(GtkWidget * widget,gint * minimum,gint * natural)2657 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2658 				   gint      *minimum,
2659 				   gint      *natural)
2660 {
2661   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2662   GList *list;
2663   GtkTreeViewColumn *column;
2664   gint width = 0;
2665 
2666   /* we validate some rows initially just to make sure we have some size.
2667    * In practice, with a lot of static lists, this should get a good width.
2668    */
2669   do_validate_rows (tree_view, FALSE);
2670 
2671   /* keep this in sync with size_allocate below */
2672   for (list = tree_view->priv->columns; list; list = list->next)
2673     {
2674       column = list->data;
2675       if (!gtk_tree_view_column_get_visible (column) || column == tree_view->priv->drag_column)
2676 	continue;
2677 
2678       width += _gtk_tree_view_column_request_width (column);
2679     }
2680 
2681   *minimum = *natural = width;
2682 }
2683 
2684 static void
gtk_tree_view_get_preferred_height(GtkWidget * widget,gint * minimum,gint * natural)2685 gtk_tree_view_get_preferred_height (GtkWidget *widget,
2686 				    gint      *minimum,
2687 				    gint      *natural)
2688 {
2689   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2690   gint height;
2691 
2692   gtk_tree_view_update_height (tree_view);
2693 
2694   height = gtk_tree_view_get_height (tree_view) + gtk_tree_view_get_effective_header_height (tree_view);
2695 
2696   *minimum = *natural = height;
2697 }
2698 
2699 static int
gtk_tree_view_calculate_width_before_expander(GtkTreeView * tree_view)2700 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2701 {
2702   int width = 0;
2703   GList *list;
2704   gboolean rtl;
2705 
2706   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2707   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2708        list->data != tree_view->priv->expander_column;
2709        list = (rtl ? list->prev : list->next))
2710     {
2711       GtkTreeViewColumn *column = list->data;
2712 
2713       width += gtk_tree_view_column_get_width (column);
2714     }
2715 
2716   return width;
2717 }
2718 
2719 /* GtkWidget::size_allocate helper */
2720 static void
gtk_tree_view_size_allocate_columns(GtkWidget * widget,gboolean * width_changed)2721 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2722 				     gboolean  *width_changed)
2723 {
2724   GtkTreeView *tree_view;
2725   GList *list, *first_column, *last_column;
2726   GtkTreeViewColumn *column;
2727   GtkAllocation widget_allocation;
2728   gint width = 0;
2729   gint extra, extra_per_column, extra_for_last;
2730   gint full_requested_width = 0;
2731   gint number_of_expand_columns = 0;
2732   gboolean rtl;
2733   gboolean update_expand;
2734 
2735   tree_view = GTK_TREE_VIEW (widget);
2736 
2737   for (last_column = g_list_last (tree_view->priv->columns);
2738        last_column &&
2739        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
2740        last_column = last_column->prev)
2741     ;
2742   if (last_column == NULL)
2743     return;
2744 
2745   for (first_column = g_list_first (tree_view->priv->columns);
2746        first_column &&
2747        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
2748        first_column = first_column->next)
2749     ;
2750 
2751   if (first_column == NULL)
2752     return;
2753 
2754   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2755 
2756   /* find out how many extra space and expandable columns we have */
2757   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2758     {
2759       column = (GtkTreeViewColumn *)list->data;
2760 
2761       if (!gtk_tree_view_column_get_visible (column) || column == tree_view->priv->drag_column)
2762 	continue;
2763 
2764       full_requested_width += _gtk_tree_view_column_request_width (column);
2765 
2766       if (gtk_tree_view_column_get_expand (column))
2767 	number_of_expand_columns++;
2768     }
2769 
2770   /* Only update the expand value if the width of the widget has changed,
2771    * or the number of expand columns has changed, or if there are no expand
2772    * columns, or if we didn't have an size-allocation yet after the
2773    * last validated node.
2774    */
2775   update_expand = (width_changed && *width_changed == TRUE)
2776       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2777       || number_of_expand_columns == 0
2778       || tree_view->priv->post_validation_flag == TRUE;
2779 
2780   tree_view->priv->post_validation_flag = FALSE;
2781 
2782   gtk_widget_get_allocation (widget, &widget_allocation);
2783   if (!update_expand)
2784     {
2785       extra = tree_view->priv->last_extra_space;
2786       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2787     }
2788   else
2789     {
2790       extra = MAX (widget_allocation.width - full_requested_width, 0);
2791       extra_for_last = 0;
2792 
2793       tree_view->priv->last_extra_space = extra;
2794     }
2795 
2796   if (number_of_expand_columns > 0)
2797     extra_per_column = extra/number_of_expand_columns;
2798   else
2799     extra_per_column = 0;
2800 
2801   if (update_expand)
2802     {
2803       tree_view->priv->last_extra_space_per_column = extra_per_column;
2804       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2805     }
2806 
2807   for (list = (rtl ? last_column : first_column);
2808        list != (rtl ? first_column->prev : last_column->next);
2809        list = (rtl ? list->prev : list->next))
2810     {
2811       gint column_width;
2812 
2813       column = list->data;
2814 
2815       if (!gtk_tree_view_column_get_visible (column) || column == tree_view->priv->drag_column)
2816 	continue;
2817 
2818       column_width = _gtk_tree_view_column_request_width (column);
2819 
2820       if (gtk_tree_view_column_get_expand (column))
2821 	{
2822 	  if (number_of_expand_columns == 1)
2823 	    {
2824 	      /* We add the remander to the last column as
2825 	       * */
2826 	      column_width += extra;
2827 	    }
2828 	  else
2829 	    {
2830 	      column_width += extra_per_column;
2831 	      extra -= extra_per_column;
2832 	      number_of_expand_columns --;
2833 	    }
2834 	}
2835       else if (number_of_expand_columns == 0 &&
2836 	       list == last_column)
2837 	{
2838 	  column_width += extra;
2839 	}
2840 
2841       /* In addition to expand, the last column can get even more
2842        * extra space so all available space is filled up.
2843        */
2844       if (extra_for_last > 0 && list == last_column)
2845 	column_width += extra_for_last;
2846 
2847       _gtk_tree_view_column_allocate (column, width, column_width);
2848 
2849       width += column_width;
2850     }
2851 
2852   /* We change the width here.  The user might have been resizing columns,
2853    * which changes the total width of the tree view.  This is of
2854    * importance for getting the horizontal scroll bar right.
2855    */
2856   if (tree_view->priv->width != width)
2857     {
2858       tree_view->priv->width = width;
2859       if (width_changed)
2860         *width_changed = TRUE;
2861     }
2862 }
2863 
2864 /* GtkWidget::size_allocate helper */
2865 static void
gtk_tree_view_size_allocate_drag_column(GtkWidget * widget)2866 gtk_tree_view_size_allocate_drag_column (GtkWidget *widget)
2867 {
2868   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2869   GtkAllocation drag_allocation;
2870   GtkWidget *button;
2871 
2872   if (tree_view->priv->drag_column == NULL)
2873     return;
2874 
2875   button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
2876 
2877   drag_allocation.x = 0;
2878   drag_allocation.y = 0;
2879   drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2880   drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2881   gtk_widget_size_allocate (button, &drag_allocation);
2882 }
2883 
2884 static void
gtk_tree_view_size_allocate(GtkWidget * widget,GtkAllocation * allocation)2885 gtk_tree_view_size_allocate (GtkWidget     *widget,
2886 			     GtkAllocation *allocation)
2887 {
2888   GtkAllocation widget_allocation;
2889   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2890   GList *tmp_list;
2891   gboolean width_changed = FALSE;
2892   gint old_width;
2893   double page_size;
2894 
2895   gtk_widget_get_allocation (widget, &widget_allocation);
2896   old_width = widget_allocation.width;
2897   if (allocation->width != widget_allocation.width)
2898     width_changed = TRUE;
2899 
2900   gtk_widget_set_allocation (widget, allocation);
2901 
2902   /* We size-allocate the columns first because the width of the
2903    * tree view (used in updating the adjustments below) might change.
2904    */
2905   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2906   gtk_tree_view_size_allocate_drag_column (widget);
2907 
2908   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2909   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2910                                 allocation->width);
2911   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2912                                      allocation->width * 0.9);
2913   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2914                                      allocation->width * 0.1);
2915   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2916   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2917                             MAX (gtk_adjustment_get_page_size (tree_view->priv->hadjustment),
2918                                  tree_view->priv->width));
2919   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2920 
2921   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)
2922     {
2923       if (allocation->width < tree_view->priv->width)
2924         {
2925 	  if (tree_view->priv->init_hadjust_value)
2926 	    {
2927 	      gtk_adjustment_set_value (tree_view->priv->hadjustment,
2928                                         MAX (tree_view->priv->width -
2929                                              allocation->width, 0));
2930 	      tree_view->priv->init_hadjust_value = FALSE;
2931 	    }
2932 	  else if (allocation->width != old_width)
2933 	    {
2934 	      gtk_adjustment_set_value (tree_view->priv->hadjustment,
2935                                         CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) - allocation->width + old_width,
2936                                                0,
2937                                                tree_view->priv->width - allocation->width));
2938 	    }
2939 	}
2940       else
2941         {
2942           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2943 	  tree_view->priv->init_hadjust_value = TRUE;
2944 	}
2945     }
2946   else
2947     if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + allocation->width > tree_view->priv->width)
2948       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2949                                 MAX (tree_view->priv->width -
2950                                      allocation->width, 0));
2951 
2952   page_size = allocation->height - gtk_tree_view_get_effective_header_height (tree_view);
2953   gtk_adjustment_configure (tree_view->priv->vadjustment,
2954                             gtk_adjustment_get_value (tree_view->priv->vadjustment),
2955                             0,
2956                             MAX (page_size, gtk_tree_view_get_height (tree_view)),
2957                             page_size * 0.1,
2958                             page_size * 0.9,
2959                             page_size);
2960 
2961   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2962   if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2963     gtk_tree_view_top_row_to_dy (tree_view);
2964   else
2965     gtk_tree_view_dy_to_top_row (tree_view);
2966 
2967   if (gtk_widget_get_realized (widget))
2968     {
2969       gdk_window_move_resize (gtk_widget_get_window (widget),
2970 			      allocation->x, allocation->y,
2971 			      allocation->width, allocation->height);
2972       gdk_window_move_resize (tree_view->priv->header_window,
2973 			      - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2974 			      0,
2975 			      MAX (tree_view->priv->width, allocation->width),
2976 			      tree_view->priv->header_height);
2977       gdk_window_move_resize (tree_view->priv->bin_window,
2978 			      - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2979 			      gtk_tree_view_get_effective_header_height (tree_view),
2980 			      MAX (tree_view->priv->width, allocation->width),
2981 			      allocation->height - gtk_tree_view_get_effective_header_height (tree_view));
2982 
2983       if (tree_view->priv->tree == NULL)
2984         invalidate_empty_focus (tree_view);
2985 
2986       if (width_changed && tree_view->priv->expander_column)
2987         {
2988           /* Might seem awkward, but is the best heuristic I could come up
2989            * with.  Only if the width of the columns before the expander
2990            * changes, we will update the prelight status.  It is this
2991            * width that makes the expander move vertically.  Always updating
2992            * prelight status causes trouble with hover selections.
2993            */
2994           gint width_before_expander;
2995 
2996           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2997 
2998           if (tree_view->priv->prev_width_before_expander
2999               != width_before_expander)
3000               update_prelight (tree_view,
3001                                tree_view->priv->event_last_x,
3002                                tree_view->priv->event_last_y);
3003 
3004           tree_view->priv->prev_width_before_expander = width_before_expander;
3005         }
3006     }
3007 
3008   for (tmp_list = tree_view->priv->children; tmp_list; tmp_list = tmp_list->next)
3009     {
3010       GtkTreeViewChild *child = tmp_list->data;
3011       GtkTreePath *path;
3012       GdkRectangle child_rect;
3013       int min_x, max_x, min_y, max_y;
3014       int size;
3015       GtkTextDirection direction;
3016 
3017       direction = gtk_widget_get_direction (child->widget);
3018       path = _gtk_tree_path_new_from_rbtree (child->tree, child->node);
3019       gtk_tree_view_get_cell_area (tree_view, path, child->column, &child_rect);
3020       child_rect.x += child->border.left;
3021       child_rect.y += child->border.top;
3022       child_rect.width -= child->border.left + child->border.right;
3023       child_rect.height -= child->border.top + child->border.bottom;
3024 
3025       gtk_widget_get_preferred_width (GTK_WIDGET (child->widget), &size, NULL);
3026 
3027       if (size > child_rect.width)
3028         {
3029           /* Enlarge the child, extending it to the left (RTL) */
3030           if (direction == GTK_TEXT_DIR_RTL)
3031             child_rect.x -= (size - child_rect.width);
3032           /* or to the right (LTR) */
3033           else
3034             child_rect.x += 0;
3035 
3036           child_rect.width = size;
3037         }
3038 
3039       gtk_widget_get_preferred_height_for_width (GTK_WIDGET (child->widget),
3040                                                  child_rect.width,
3041                                                  &size, NULL);
3042       if (size > child_rect.height)
3043         {
3044           /* Enlarge the child, extending in both directions equally */
3045           child_rect.y -= (size - child_rect.height) / 2;
3046           child_rect.height = size;
3047         }
3048 
3049       /* push the rect back in the visible area if needed,
3050        * preferring the top left corner (for RTL)
3051        * or top right corner (for LTR)
3052        */
3053       min_x = gtk_adjustment_get_value (tree_view->priv->hadjustment);
3054       max_x = min_x + allocation->width - child_rect.width;
3055       min_y = 0;
3056       max_y = min_y + allocation->height - gtk_tree_view_get_effective_header_height (tree_view) - child_rect.height;
3057 
3058       if (direction == GTK_TEXT_DIR_LTR)
3059         /* Ensure that child's right edge is not sticking to the right
3060          * (if (child_rect.x > max_x) child_rect.x = max_x),
3061          * then ensure that child's left edge is visible and is not sticking to the left
3062          * (if (child_rect.x < min_x) child_rect.x = min_x).
3063          */
3064         child_rect.x = MAX (min_x, MIN (max_x, child_rect.x));
3065       else
3066         /* Ensure that child's left edge is not sticking to the left
3067          * (if (child_rect.x < min_x) child_rect.x = min_x),
3068          * then ensure that child's right edge is visible and is not sticking to the right
3069          * (if (child_rect.x > max_x) child_rect.x = max_x).
3070          */
3071         child_rect.x = MIN (max_x, MAX (min_x, child_rect.x));
3072 
3073       child_rect.y = MAX (min_y, MIN (max_y, child_rect.y));
3074 
3075       gtk_tree_path_free (path);
3076       gtk_widget_size_allocate (child->widget, &child_rect);
3077     }
3078 }
3079 
3080 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
3081 static void
grab_focus_and_unset_draw_keyfocus(GtkTreeView * tree_view)3082 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
3083 {
3084   GtkWidget *widget = GTK_WIDGET (tree_view);
3085 
3086   if (gtk_widget_get_can_focus (widget) &&
3087       !gtk_widget_has_focus (widget) &&
3088       !_gtk_widget_get_shadowed (widget))
3089     gtk_widget_grab_focus (widget);
3090 
3091   tree_view->priv->draw_keyfocus = 0;
3092 }
3093 
3094 static inline gboolean
row_is_separator(GtkTreeView * tree_view,GtkTreeIter * iter,GtkTreePath * path)3095 row_is_separator (GtkTreeView *tree_view,
3096 		  GtkTreeIter *iter,
3097 		  GtkTreePath *path)
3098 {
3099   gboolean is_separator = FALSE;
3100 
3101   if (tree_view->priv->row_separator_func)
3102     {
3103       GtkTreeIter tmpiter;
3104 
3105       if (iter)
3106         tmpiter = *iter;
3107       else
3108         {
3109           if (!gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path))
3110             return FALSE;
3111         }
3112 
3113       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
3114                                                           &tmpiter,
3115                                                           tree_view->priv->row_separator_data);
3116     }
3117 
3118   return is_separator;
3119 }
3120 
3121 static int
gtk_tree_view_get_expander_size(GtkTreeView * tree_view)3122 gtk_tree_view_get_expander_size (GtkTreeView *tree_view)
3123 {
3124   gint expander_size;
3125   gint horizontal_separator;
3126 
3127   gtk_widget_style_get (GTK_WIDGET (tree_view),
3128 			"expander-size", &expander_size,
3129                         "horizontal-separator", &horizontal_separator,
3130 			NULL);
3131 
3132   return expander_size + (horizontal_separator / 2);
3133 }
3134 
3135 static void
get_current_selection_modifiers(GtkWidget * widget,gboolean * modify,gboolean * extend)3136 get_current_selection_modifiers (GtkWidget *widget,
3137                                  gboolean  *modify,
3138                                  gboolean  *extend)
3139 {
3140   GdkModifierType state = 0;
3141   GdkModifierType mask;
3142 
3143   *modify = FALSE;
3144   *extend = FALSE;
3145 
3146   if (gtk_get_current_event_state (&state))
3147     {
3148       mask = gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_MODIFY_SELECTION);
3149       if ((state & mask) == mask)
3150         *modify = TRUE;
3151       mask = gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_EXTEND_SELECTION);
3152       if ((state & mask) == mask)
3153         *extend = TRUE;
3154     }
3155 }
3156 
3157 static void
gtk_tree_view_multipress_gesture_pressed(GtkGestureMultiPress * gesture,gint n_press,gdouble x,gdouble y,GtkTreeView * tree_view)3158 gtk_tree_view_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
3159                                           gint                  n_press,
3160                                           gdouble               x,
3161                                           gdouble               y,
3162                                           GtkTreeView          *tree_view)
3163 {
3164   gint vertical_separator, horizontal_separator;
3165   GtkWidget *widget = GTK_WIDGET (tree_view);
3166   GdkRectangle background_area, cell_area;
3167   GtkTreeViewColumn *column = NULL;
3168   GdkEventSequence *sequence;
3169   GdkModifierType modifiers;
3170   const GdkEvent *event;
3171   gint new_y, y_offset;
3172   gint bin_x, bin_y;
3173   GtkTreePath *path;
3174   GtkRBNode *node;
3175   GtkRBTree *tree;
3176   gint depth;
3177   guint button;
3178   GList *list;
3179   gboolean rtl;
3180 
3181   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3182   gtk_tree_view_stop_editing (tree_view, FALSE);
3183   gtk_widget_style_get (widget,
3184 			"vertical-separator", &vertical_separator,
3185 			"horizontal-separator", &horizontal_separator,
3186 			NULL);
3187   button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
3188 
3189   if (button > 3)
3190     {
3191       gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
3192       return;
3193     }
3194 
3195   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
3196    * we're done handling the button press.
3197    */
3198   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, x, y,
3199                                                      &bin_x, &bin_y);
3200   gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
3201 
3202   if (n_press > 1)
3203     gtk_gesture_set_state (tree_view->priv->drag_gesture,
3204                            GTK_EVENT_SEQUENCE_DENIED);
3205 
3206   /* Empty tree? */
3207   if (tree_view->priv->tree == NULL)
3208     {
3209       grab_focus_and_unset_draw_keyfocus (tree_view);
3210       return;
3211     }
3212 
3213   /* are we in an arrow? */
3214   if (tree_view->priv->prelight_node &&
3215       tree_view->priv->arrow_prelit &&
3216       gtk_tree_view_draw_expanders (tree_view))
3217     {
3218       if (button == GDK_BUTTON_PRIMARY)
3219         {
3220           tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
3221           tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
3222           gtk_tree_view_queue_draw_arrow (tree_view,
3223                                           tree_view->priv->prelight_tree,
3224                                           tree_view->priv->prelight_node);
3225         }
3226 
3227       grab_focus_and_unset_draw_keyfocus (tree_view);
3228       return;
3229     }
3230 
3231   /* find the node that was clicked */
3232   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, bin_y);
3233   if (new_y < 0)
3234     new_y = 0;
3235   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
3236 
3237   if (node == NULL)
3238     {
3239       /* We clicked in dead space */
3240       grab_focus_and_unset_draw_keyfocus (tree_view);
3241       return;
3242     }
3243 
3244   /* Get the path and the node */
3245   path = _gtk_tree_path_new_from_rbtree (tree, node);
3246 
3247   if (row_is_separator (tree_view, NULL, path))
3248     {
3249       gtk_tree_path_free (path);
3250       grab_focus_and_unset_draw_keyfocus (tree_view);
3251       return;
3252     }
3253 
3254   depth = gtk_tree_path_get_depth (path);
3255   background_area.y = y_offset + bin_y;
3256   background_area.height = gtk_tree_view_get_row_height (tree_view, node);
3257   background_area.x = 0;
3258 
3259   /* Let the column have a chance at selecting it. */
3260   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3261   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
3262        list; list = (rtl ? list->prev : list->next))
3263     {
3264       GtkTreeViewColumn *candidate = list->data;
3265 
3266       if (!gtk_tree_view_column_get_visible (candidate))
3267         continue;
3268 
3269       background_area.width = gtk_tree_view_column_get_width (candidate);
3270       if ((background_area.x > bin_x) ||
3271           (background_area.x + background_area.width <= bin_x))
3272         {
3273           background_area.x += background_area.width;
3274           continue;
3275         }
3276 
3277       /* we found the focus column */
3278       column = candidate;
3279       cell_area = background_area;
3280       cell_area.width -= horizontal_separator;
3281       cell_area.height -= vertical_separator;
3282       cell_area.x += horizontal_separator/2;
3283       cell_area.y += vertical_separator/2;
3284       if (gtk_tree_view_is_expander_column (tree_view, column))
3285         {
3286           if (!rtl)
3287             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
3288           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
3289 
3290           if (gtk_tree_view_draw_expanders (tree_view))
3291             {
3292               gint expander_size = gtk_tree_view_get_expander_size (tree_view);
3293               if (!rtl)
3294                 cell_area.x += depth * expander_size;
3295               cell_area.width -= depth * expander_size;
3296             }
3297         }
3298       break;
3299     }
3300 
3301   if (column == NULL)
3302     {
3303       gtk_tree_path_free (path);
3304       grab_focus_and_unset_draw_keyfocus (tree_view);
3305       gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
3306       return;
3307     }
3308 
3309   _gtk_tree_view_set_focus_column (tree_view, column);
3310 
3311   sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
3312   event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
3313   gdk_event_get_state (event, &modifiers);
3314 
3315   /* decide if we edit */
3316   if (button == GDK_BUTTON_PRIMARY &&
3317       !(modifiers & gtk_accelerator_get_default_mod_mask ()))
3318     {
3319       GtkTreePath *anchor;
3320       GtkTreeIter iter;
3321 
3322       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3323       gtk_tree_view_column_cell_set_cell_data (column,
3324                                                tree_view->priv->model,
3325                                                &iter,
3326                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
3327                                                node->children?TRUE:FALSE);
3328 
3329       if (tree_view->priv->anchor)
3330         anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
3331       else
3332         anchor = NULL;
3333 
3334       if ((anchor && !gtk_tree_path_compare (anchor, path))
3335           || !_gtk_tree_view_column_has_editable_cell (column))
3336         {
3337           GtkCellEditable *cell_editable = NULL;
3338 
3339           /* FIXME: get the right flags */
3340           guint flags = 0;
3341 
3342           if (_gtk_tree_view_column_cell_event (column,
3343                                                 (GdkEvent *)event,
3344                                                 &cell_area, flags))
3345             {
3346               GtkCellArea *area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
3347               cell_editable = gtk_cell_area_get_edit_widget (area);
3348 
3349               if (cell_editable != NULL)
3350                 {
3351                   gtk_tree_path_free (path);
3352                   gtk_tree_path_free (anchor);
3353                   return;
3354                 }
3355             }
3356         }
3357       if (anchor)
3358         gtk_tree_path_free (anchor);
3359     }
3360 
3361   /* we only handle selection modifications on the first button press
3362    */
3363   if (n_press == 1)
3364     {
3365       GtkCellRenderer *focus_cell;
3366       gboolean modify, extend;
3367 
3368       get_current_selection_modifiers (widget, &modify, &extend);
3369       tree_view->priv->modify_selection_pressed = modify;
3370       tree_view->priv->extend_selection_pressed = extend;
3371 
3372       /* We update the focus cell here, this is also needed if the
3373        * column does not contain an editable cell.  In this case,
3374        * GtkCellArea did not receive the event for processing (and
3375        * could not update the focus cell).
3376        */
3377       focus_cell = _gtk_tree_view_column_get_cell_at_pos (column,
3378                                                           &cell_area,
3379                                                           &background_area,
3380                                                           bin_x, bin_y);
3381 
3382       if (focus_cell)
3383         gtk_tree_view_column_focus_cell (column, focus_cell);
3384 
3385       if (modify)
3386         {
3387           gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
3388           gtk_tree_view_real_toggle_cursor_row (tree_view);
3389         }
3390       else if (extend)
3391         {
3392           gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
3393           gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
3394         }
3395       else
3396         {
3397           gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CLAMP_NODE);
3398         }
3399 
3400       tree_view->priv->modify_selection_pressed = FALSE;
3401       tree_view->priv->extend_selection_pressed = FALSE;
3402     }
3403 
3404   if (button == GDK_BUTTON_PRIMARY && n_press == 2)
3405     gtk_tree_view_row_activated (tree_view, path, column);
3406   else
3407     {
3408       if (n_press == 1)
3409         {
3410           tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
3411           tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
3412         }
3413 
3414       grab_focus_and_unset_draw_keyfocus (tree_view);
3415     }
3416 
3417   gtk_tree_path_free (path);
3418 
3419   if (n_press >= 2)
3420     gtk_event_controller_reset (GTK_EVENT_CONTROLLER (gesture));
3421 }
3422 
3423 static void
gtk_tree_view_drag_gesture_begin(GtkGestureDrag * gesture,gdouble start_x,gdouble start_y,GtkTreeView * tree_view)3424 gtk_tree_view_drag_gesture_begin (GtkGestureDrag *gesture,
3425                                   gdouble         start_x,
3426                                   gdouble         start_y,
3427                                   GtkTreeView    *tree_view)
3428 {
3429   gint bin_x, bin_y;
3430   GtkRBTree *tree;
3431   GtkRBNode *node;
3432 
3433   if (tree_view->priv->tree == NULL)
3434     {
3435       gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
3436       return;
3437     }
3438 
3439   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, start_x, start_y,
3440                                                      &bin_x, &bin_y);
3441   tree_view->priv->press_start_x = tree_view->priv->rubber_band_x = bin_x;
3442   tree_view->priv->press_start_y = tree_view->priv->rubber_band_y = bin_y;
3443   _gtk_rbtree_find_offset (tree_view->priv->tree, bin_y + tree_view->priv->dy,
3444                            &tree, &node);
3445 
3446   if (tree_view->priv->rubber_banding_enable
3447       && !GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED)
3448       && gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
3449     {
3450       gboolean modify, extend;
3451 
3452       tree_view->priv->press_start_y += tree_view->priv->dy;
3453       tree_view->priv->rubber_band_y += tree_view->priv->dy;
3454       tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
3455 
3456       get_current_selection_modifiers (GTK_WIDGET (tree_view), &modify, &extend);
3457       tree_view->priv->rubber_band_modify = modify;
3458       tree_view->priv->rubber_band_extend = extend;
3459     }
3460 }
3461 
3462 static void
gtk_tree_view_column_multipress_gesture_pressed(GtkGestureMultiPress * gesture,gint n_press,gdouble x,gdouble y,GtkTreeView * tree_view)3463 gtk_tree_view_column_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
3464                                                  gint                  n_press,
3465                                                  gdouble               x,
3466                                                  gdouble               y,
3467                                                  GtkTreeView          *tree_view)
3468 {
3469   GdkEventSequence *sequence;
3470   GtkTreeViewColumn *column;
3471   const GdkEvent *event;
3472   GList *list;
3473   gint i;
3474 
3475   if (n_press != 2)
3476     return;
3477 
3478   sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
3479   event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
3480 
3481   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3482     {
3483       column = list->data;
3484 
3485       if (event->any.window != _gtk_tree_view_column_get_window (column) ||
3486 	  !gtk_tree_view_column_get_resizable (column))
3487         continue;
3488 
3489       if (gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3490         {
3491           gtk_tree_view_column_set_fixed_width (column, -1);
3492           gtk_tree_view_column_set_expand (column, FALSE);
3493           _gtk_tree_view_column_autosize (tree_view, column);
3494         }
3495 
3496       gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
3497       break;
3498     }
3499 }
3500 
3501 static void
gtk_tree_view_column_drag_gesture_begin(GtkGestureDrag * gesture,gdouble start_x,gdouble start_y,GtkTreeView * tree_view)3502 gtk_tree_view_column_drag_gesture_begin (GtkGestureDrag *gesture,
3503                                          gdouble         start_x,
3504                                          gdouble         start_y,
3505                                          GtkTreeView    *tree_view)
3506 {
3507   GdkEventSequence *sequence;
3508   GtkTreeViewColumn *column;
3509   const GdkEvent *event;
3510   GdkWindow *window;
3511   gboolean rtl;
3512   GList *list;
3513   gint i;
3514 
3515   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
3516   sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
3517   event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
3518   window = event->any.window;
3519 
3520   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3521     {
3522       gpointer drag_data;
3523       gint column_width;
3524 
3525       column = list->data;
3526 
3527       if (window != _gtk_tree_view_column_get_window (column))
3528         continue;
3529 
3530       if (!gtk_tree_view_column_get_resizable (column))
3531         break;
3532 
3533       tree_view->priv->in_column_resize = TRUE;
3534 
3535       /* block attached dnd signal handler */
3536       drag_data = g_object_get_data (G_OBJECT (tree_view), "gtk-site-data");
3537       if (drag_data)
3538         g_signal_handlers_block_matched (tree_view,
3539                                          G_SIGNAL_MATCH_DATA,
3540                                          0, 0, NULL, NULL,
3541                                          drag_data);
3542 
3543       column_width = gtk_tree_view_column_get_width (column);
3544       gtk_tree_view_column_set_fixed_width (column, column_width);
3545       gtk_tree_view_column_set_expand (column, FALSE);
3546 
3547       tree_view->priv->drag_pos = i;
3548       tree_view->priv->x_drag = start_x + (rtl ? column_width : -column_width);
3549 
3550       if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
3551         gtk_widget_grab_focus (GTK_WIDGET (tree_view));
3552 
3553       gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
3554       return;
3555     }
3556 }
3557 
3558 static void
gtk_tree_view_update_button_position(GtkTreeView * tree_view,GtkTreeViewColumn * column)3559 gtk_tree_view_update_button_position (GtkTreeView       *tree_view,
3560                                       GtkTreeViewColumn *column)
3561 {
3562   GtkTreeViewPrivate *priv = tree_view->priv;
3563   GList *column_el;
3564 
3565   column_el = g_list_find (priv->columns, column);
3566   g_return_if_fail (column_el != NULL);
3567 
3568   gtk_css_node_insert_after (priv->header_node,
3569                              gtk_widget_get_css_node (gtk_tree_view_column_get_button (column)),
3570                              column_el->prev ? gtk_widget_get_css_node (
3571                                 gtk_tree_view_column_get_button (column_el->prev->data)) : NULL);
3572 }
3573 
3574 /* column drag gesture helper */
3575 static gboolean
gtk_tree_view_button_release_drag_column(GtkTreeView * tree_view)3576 gtk_tree_view_button_release_drag_column (GtkTreeView *tree_view)
3577 {
3578   GtkWidget *button, *widget = GTK_WIDGET (tree_view);
3579   GList *l;
3580   gboolean rtl;
3581   GtkStyleContext *context;
3582 
3583   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3584 
3585   /* Move the button back */
3586   button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3587 
3588   context = gtk_widget_get_style_context (button);
3589   gtk_style_context_remove_class (context, GTK_STYLE_CLASS_DND);
3590 
3591   g_object_ref (button);
3592   gtk_container_remove (GTK_CONTAINER (tree_view), button);
3593   gtk_widget_set_parent_window (button, tree_view->priv->header_window);
3594   gtk_tree_view_update_button_position (tree_view, tree_view->priv->drag_column);
3595   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
3596   g_object_unref (button);
3597   gtk_widget_queue_resize (widget);
3598   if (gtk_tree_view_column_get_resizable (tree_view->priv->drag_column))
3599     {
3600       gdk_window_raise (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3601       gdk_window_show (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3602     }
3603   else
3604     gdk_window_hide (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3605 
3606   gtk_widget_grab_focus (button);
3607 
3608   if (rtl)
3609     {
3610       if (tree_view->priv->cur_reorder &&
3611 	  tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3612 	gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3613 					 tree_view->priv->cur_reorder->right_column);
3614     }
3615   else
3616     {
3617       if (tree_view->priv->cur_reorder &&
3618 	  tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3619 	gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3620 					 tree_view->priv->cur_reorder->left_column);
3621     }
3622   tree_view->priv->drag_column = NULL;
3623   gtk_widget_unregister_window (widget, tree_view->priv->drag_window);
3624   gdk_window_destroy (tree_view->priv->drag_window);
3625   tree_view->priv->drag_window = NULL;
3626 
3627   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3628     g_slice_free (GtkTreeViewColumnReorder, l->data);
3629   g_list_free (tree_view->priv->column_drag_info);
3630   tree_view->priv->column_drag_info = NULL;
3631   tree_view->priv->cur_reorder = NULL;
3632 
3633   if (tree_view->priv->drag_highlight_window)
3634     gdk_window_hide (tree_view->priv->drag_highlight_window);
3635 
3636   /* Reset our flags */
3637   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3638   tree_view->priv->in_column_drag = FALSE;
3639 
3640   return TRUE;
3641 }
3642 
3643 /* column drag gesture helper */
3644 static gboolean
gtk_tree_view_button_release_column_resize(GtkTreeView * tree_view)3645 gtk_tree_view_button_release_column_resize (GtkTreeView *tree_view)
3646 {
3647   gpointer drag_data;
3648 
3649   tree_view->priv->drag_pos = -1;
3650 
3651   /* unblock attached dnd signal handler */
3652   drag_data = g_object_get_data (G_OBJECT (tree_view), "gtk-site-data");
3653   if (drag_data)
3654     g_signal_handlers_unblock_matched (tree_view,
3655 				       G_SIGNAL_MATCH_DATA,
3656 				       0, 0, NULL, NULL,
3657 				       drag_data);
3658 
3659   tree_view->priv->in_column_resize = FALSE;
3660   return TRUE;
3661 }
3662 
3663 static void
gtk_tree_view_column_drag_gesture_end(GtkGestureDrag * gesture,gdouble offset_x,gdouble offset_y,GtkTreeView * tree_view)3664 gtk_tree_view_column_drag_gesture_end (GtkGestureDrag *gesture,
3665                                        gdouble         offset_x,
3666                                        gdouble         offset_y,
3667                                        GtkTreeView    *tree_view)
3668 {
3669   GdkEventSequence *sequence;
3670 
3671   sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
3672 
3673   /* Cancel reorder if the drag got cancelled */
3674   if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
3675     tree_view->priv->cur_reorder = NULL;
3676 
3677   if (tree_view->priv->in_column_drag)
3678     {
3679       GdkDevice *device;
3680 
3681       gtk_tree_view_button_release_drag_column (tree_view);
3682       device = gtk_gesture_get_device (GTK_GESTURE (gesture));
3683       gdk_seat_ungrab (gdk_device_get_seat (device));
3684     }
3685   else if (tree_view->priv->in_column_resize)
3686     gtk_tree_view_button_release_column_resize (tree_view);
3687 }
3688 
3689 static void
gtk_tree_view_drag_gesture_end(GtkGestureDrag * gesture,gdouble offset_x,gdouble offset_y,GtkTreeView * tree_view)3690 gtk_tree_view_drag_gesture_end (GtkGestureDrag *gesture,
3691                                 gdouble         offset_x,
3692                                 gdouble         offset_y,
3693                                 GtkTreeView    *tree_view)
3694 {
3695   gtk_tree_view_stop_rubber_band (tree_view);
3696 }
3697 
3698 static void
gtk_tree_view_multipress_gesture_released(GtkGestureMultiPress * gesture,gint n_press,gdouble x,gdouble y,GtkTreeView * tree_view)3699 gtk_tree_view_multipress_gesture_released (GtkGestureMultiPress *gesture,
3700                                            gint                  n_press,
3701                                            gdouble               x,
3702                                            gdouble               y,
3703                                            GtkTreeView          *tree_view)
3704 {
3705   gboolean modify, extend;
3706   guint button;
3707 
3708   button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
3709 
3710   if (button != GDK_BUTTON_PRIMARY ||
3711       tree_view->priv->button_pressed_node == NULL ||
3712       tree_view->priv->button_pressed_node != tree_view->priv->prelight_node)
3713     return;
3714 
3715   get_current_selection_modifiers (GTK_WIDGET (tree_view), &modify, &extend);
3716 
3717   if (tree_view->priv->arrow_prelit)
3718     {
3719       GtkTreePath *path = NULL;
3720 
3721       path = _gtk_tree_path_new_from_rbtree (tree_view->priv->button_pressed_tree,
3722                                              tree_view->priv->button_pressed_node);
3723       /* Actually activate the node */
3724       if (tree_view->priv->button_pressed_node->children == NULL)
3725         gtk_tree_view_real_expand_row (tree_view, path,
3726                                        tree_view->priv->button_pressed_tree,
3727                                        tree_view->priv->button_pressed_node,
3728                                        FALSE, TRUE);
3729       else
3730         gtk_tree_view_real_collapse_row (tree_view, path,
3731                                          tree_view->priv->button_pressed_tree,
3732                                          tree_view->priv->button_pressed_node, TRUE);
3733       gtk_tree_path_free (path);
3734     }
3735   else if (tree_view->priv->activate_on_single_click && !modify && !extend)
3736     {
3737       GtkTreePath *path = NULL;
3738 
3739       path = _gtk_tree_path_new_from_rbtree (tree_view->priv->button_pressed_tree,
3740                                              tree_view->priv->button_pressed_node);
3741       gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
3742       gtk_tree_path_free (path);
3743     }
3744 
3745   tree_view->priv->button_pressed_tree = NULL;
3746   tree_view->priv->button_pressed_node = NULL;
3747 }
3748 
3749 /* GtkWidget::motion_event function set.
3750  */
3751 
3752 static gboolean
coords_are_over_arrow(GtkTreeView * tree_view,GtkRBTree * tree,GtkRBNode * node,gint x,gint y)3753 coords_are_over_arrow (GtkTreeView *tree_view,
3754                        GtkRBTree   *tree,
3755                        GtkRBNode   *node,
3756                        /* these are in bin window coords */
3757                        gint         x,
3758                        gint         y)
3759 {
3760   GdkRectangle arrow;
3761   gint x2;
3762 
3763   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3764     return FALSE;
3765 
3766   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3767     return FALSE;
3768 
3769   arrow.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
3770   arrow.height = gtk_tree_view_get_row_height (tree_view, node);
3771 
3772   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3773 
3774   arrow.width = x2 - arrow.x;
3775 
3776   return (x >= arrow.x &&
3777           x < (arrow.x + arrow.width) &&
3778 	  y >= arrow.y &&
3779 	  y < (arrow.y + arrow.height));
3780 }
3781 
3782 static gboolean
auto_expand_timeout(gpointer data)3783 auto_expand_timeout (gpointer data)
3784 {
3785   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3786   GtkTreePath *path;
3787 
3788   if (tree_view->priv->prelight_node)
3789     {
3790       path = _gtk_tree_path_new_from_rbtree (tree_view->priv->prelight_tree,
3791 				             tree_view->priv->prelight_node);
3792 
3793       if (tree_view->priv->prelight_node->children)
3794 	gtk_tree_view_collapse_row (tree_view, path);
3795       else
3796 	gtk_tree_view_expand_row (tree_view, path, FALSE);
3797 
3798       gtk_tree_path_free (path);
3799     }
3800 
3801   tree_view->priv->auto_expand_timeout = 0;
3802 
3803   return FALSE;
3804 }
3805 
3806 static void
remove_auto_expand_timeout(GtkTreeView * tree_view)3807 remove_auto_expand_timeout (GtkTreeView *tree_view)
3808 {
3809   if (tree_view->priv->auto_expand_timeout != 0)
3810     {
3811       g_source_remove (tree_view->priv->auto_expand_timeout);
3812       tree_view->priv->auto_expand_timeout = 0;
3813     }
3814 }
3815 
3816 static void
do_prelight(GtkTreeView * tree_view,GtkRBTree * tree,GtkRBNode * node,gint x,gint y)3817 do_prelight (GtkTreeView *tree_view,
3818              GtkRBTree   *tree,
3819              GtkRBNode   *node,
3820 	     /* these are in bin_window coords */
3821              gint         x,
3822              gint         y)
3823 {
3824   if (tree_view->priv->prelight_tree == tree &&
3825       tree_view->priv->prelight_node == node)
3826     {
3827       /*  We are still on the same node,
3828 	  but we might need to take care of the arrow  */
3829 
3830       if (tree && node && gtk_tree_view_draw_expanders (tree_view))
3831 	{
3832 	  gboolean over_arrow;
3833 
3834 	  over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3835 
3836 	  if (over_arrow != tree_view->priv->arrow_prelit)
3837 	    {
3838 	      if (over_arrow)
3839                 tree_view->priv->arrow_prelit = TRUE;
3840 	      else
3841                 tree_view->priv->arrow_prelit = FALSE;
3842 
3843 	      gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3844 	    }
3845 	}
3846 
3847       return;
3848     }
3849 
3850   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3851     {
3852       /*  Unprelight the old node and arrow  */
3853 
3854       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3855 			     GTK_RBNODE_IS_PRELIT);
3856 
3857       if (tree_view->priv->arrow_prelit
3858 	  && gtk_tree_view_draw_expanders (tree_view))
3859 	{
3860           tree_view->priv->arrow_prelit = FALSE;
3861 
3862 	  gtk_tree_view_queue_draw_arrow (tree_view,
3863                                           tree_view->priv->prelight_tree,
3864                                           tree_view->priv->prelight_node);
3865 	}
3866 
3867       _gtk_tree_view_queue_draw_node (tree_view,
3868 				      tree_view->priv->prelight_tree,
3869 				      tree_view->priv->prelight_node,
3870 				      NULL);
3871     }
3872 
3873 
3874   if (tree_view->priv->hover_expand)
3875     remove_auto_expand_timeout (tree_view);
3876 
3877   /*  Set the new prelight values  */
3878   tree_view->priv->prelight_node = node;
3879   tree_view->priv->prelight_tree = tree;
3880 
3881   if (!node || !tree)
3882     return;
3883 
3884   /*  Prelight the new node and arrow  */
3885 
3886   if (gtk_tree_view_draw_expanders (tree_view)
3887       && coords_are_over_arrow (tree_view, tree, node, x, y))
3888     {
3889       tree_view->priv->arrow_prelit = TRUE;
3890 
3891       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3892     }
3893 
3894   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3895 
3896   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3897 
3898   if (tree_view->priv->hover_expand)
3899     {
3900       tree_view->priv->auto_expand_timeout =
3901 	gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3902       g_source_set_name_by_id (tree_view->priv->auto_expand_timeout, "[gtk+] auto_expand_timeout");
3903     }
3904 }
3905 
3906 static void
prelight_or_select(GtkTreeView * tree_view,GtkRBTree * tree,GtkRBNode * node,gint x,gint y)3907 prelight_or_select (GtkTreeView *tree_view,
3908 		    GtkRBTree   *tree,
3909 		    GtkRBNode   *node,
3910 		    /* these are in bin_window coords */
3911 		    gint         x,
3912 		    gint         y)
3913 {
3914   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3915 
3916   if (tree_view->priv->hover_selection &&
3917       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3918       !(tree_view->priv->edited_column &&
3919 	gtk_cell_area_get_edit_widget
3920 	(gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column)))))
3921     {
3922       if (node)
3923 	{
3924 	  if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3925 	    {
3926 	      GtkTreePath *path;
3927 
3928 	      path = _gtk_tree_path_new_from_rbtree (tree, node);
3929 	      gtk_tree_selection_select_path (tree_view->priv->selection, path);
3930 	      if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3931 		{
3932                   tree_view->priv->draw_keyfocus = FALSE;
3933 		  gtk_tree_view_real_set_cursor (tree_view, path, 0);
3934 		}
3935 	      gtk_tree_path_free (path);
3936 	    }
3937 	}
3938 
3939       else if (mode == GTK_SELECTION_SINGLE)
3940 	gtk_tree_selection_unselect_all (tree_view->priv->selection);
3941     }
3942 
3943     do_prelight (tree_view, tree, node, x, y);
3944 }
3945 
3946 static void
ensure_unprelighted(GtkTreeView * tree_view)3947 ensure_unprelighted (GtkTreeView *tree_view)
3948 {
3949   do_prelight (tree_view,
3950 	       NULL, NULL,
3951 	       -1000, -1000); /* coords not possibly over an arrow */
3952 
3953   g_assert (tree_view->priv->prelight_node == NULL);
3954 }
3955 
3956 static void
update_prelight(GtkTreeView * tree_view,gint x,gint y)3957 update_prelight (GtkTreeView *tree_view,
3958                  gint         x,
3959                  gint         y)
3960 {
3961   int new_y;
3962   GtkRBTree *tree;
3963   GtkRBNode *node;
3964 
3965   if (tree_view->priv->tree == NULL)
3966     return;
3967 
3968   if (x == -10000)
3969     {
3970       ensure_unprelighted (tree_view);
3971       return;
3972     }
3973 
3974   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3975   if (new_y < 0)
3976     new_y = 0;
3977 
3978   _gtk_rbtree_find_offset (tree_view->priv->tree,
3979                            new_y, &tree, &node);
3980 
3981   if (node)
3982     prelight_or_select (tree_view, tree, node, x, y);
3983 }
3984 
3985 
3986 
3987 
3988 /* Our motion arrow is either a box (in the case of the original spot)
3989  * or an arrow.  It is expander_size wide.
3990  */
3991 /*
3992  * 11111111111111
3993  * 01111111111110
3994  * 00111111111100
3995  * 00011111111000
3996  * 00001111110000
3997  * 00000111100000
3998  * 00000111100000
3999  * 00000111100000
4000  * ~ ~ ~ ~ ~ ~ ~
4001  * 00000111100000
4002  * 00000111100000
4003  * 00000111100000
4004  * 00001111110000
4005  * 00011111111000
4006  * 00111111111100
4007  * 01111111111110
4008  * 11111111111111
4009  */
4010 
4011 static void
gtk_tree_view_motion_draw_column_motion_arrow(GtkTreeView * tree_view)4012 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
4013 {
4014   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
4015   GtkWidget *widget = GTK_WIDGET (tree_view);
4016   cairo_surface_t *mask_image;
4017   cairo_region_t *mask_region;
4018   gint x;
4019   gint y;
4020   gint width;
4021   gint height;
4022   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
4023   GdkWindowAttr attributes;
4024   guint attributes_mask;
4025   cairo_t *cr;
4026 
4027   if (!reorder ||
4028       reorder->left_column == tree_view->priv->drag_column ||
4029       reorder->right_column == tree_view->priv->drag_column)
4030     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
4031   else if (reorder->left_column || reorder->right_column)
4032     {
4033       GtkAllocation left_allocation, right_allocation;
4034       GdkRectangle visible_rect;
4035       GtkWidget *button;
4036 
4037       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4038       if (reorder->left_column)
4039         {
4040 	  button = gtk_tree_view_column_get_button (reorder->left_column);
4041           gtk_widget_get_allocation (button, &left_allocation);
4042           x = left_allocation.x + left_allocation.width;
4043         }
4044       else
4045         {
4046 	  button = gtk_tree_view_column_get_button (reorder->right_column);
4047           gtk_widget_get_allocation (button, &right_allocation);
4048           x = right_allocation.x;
4049         }
4050 
4051       if (x < visible_rect.x)
4052 	arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
4053       else if (x > visible_rect.x + visible_rect.width)
4054 	arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
4055       else
4056         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
4057     }
4058 
4059   /* We want to draw the rectangle over the initial location. */
4060   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
4061     {
4062       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
4063 	{
4064           GtkAllocation drag_allocation;
4065 	  GtkWidget    *button;
4066 
4067 	  if (tree_view->priv->drag_highlight_window)
4068 	    {
4069 	      gtk_widget_unregister_window (GTK_WIDGET (tree_view), tree_view->priv->drag_highlight_window);
4070 	      gdk_window_destroy (tree_view->priv->drag_highlight_window);
4071 	    }
4072 
4073 	  button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
4074 	  attributes.window_type = GDK_WINDOW_CHILD;
4075 	  attributes.wclass = GDK_INPUT_OUTPUT;
4076           attributes.x = tree_view->priv->drag_column_x;
4077           attributes.y = 0;
4078           gtk_widget_get_allocation (button, &drag_allocation);
4079 	  width = attributes.width = drag_allocation.width;
4080 	  height = attributes.height = drag_allocation.height;
4081 	  attributes.visual = gdk_screen_get_rgba_visual (gtk_widget_get_screen (widget));
4082 	  attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_POINTER_MOTION_MASK;
4083 	  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
4084 	  tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
4085 	  gtk_widget_register_window (GTK_WIDGET (tree_view), tree_view->priv->drag_highlight_window);
4086 
4087 	  tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
4088 	}
4089     }
4090   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
4091     {
4092       GtkAllocation button_allocation;
4093       GtkWidget    *button;
4094 
4095       width = gtk_tree_view_get_expander_size (tree_view);
4096 
4097       /* Get x, y, width, height of arrow */
4098       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
4099       if (reorder->left_column)
4100 	{
4101 	  button = gtk_tree_view_column_get_button (reorder->left_column);
4102           gtk_widget_get_allocation (button, &button_allocation);
4103 	  x += button_allocation.x + button_allocation.width - width/2;
4104 	  height = button_allocation.height;
4105 	}
4106       else
4107 	{
4108 	  button = gtk_tree_view_column_get_button (reorder->right_column);
4109           gtk_widget_get_allocation (button, &button_allocation);
4110 	  x += button_allocation.x - width/2;
4111 	  height = button_allocation.height;
4112 	}
4113       y -= width/2; /* The arrow takes up only half the space */
4114       height += width;
4115 
4116       /* Create the new window */
4117       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
4118 	{
4119 	  if (tree_view->priv->drag_highlight_window)
4120 	    {
4121 	      gtk_widget_unregister_window (GTK_WIDGET (tree_view), tree_view->priv->drag_highlight_window);
4122 	      gdk_window_destroy (tree_view->priv->drag_highlight_window);
4123 	    }
4124 
4125 	  attributes.window_type = GDK_WINDOW_TEMP;
4126 	  attributes.wclass = GDK_INPUT_OUTPUT;
4127 	  attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
4128 	  attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_POINTER_MOTION_MASK;
4129 	  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
4130           attributes.x = x;
4131           attributes.y = y;
4132 	  attributes.width = width;
4133 	  attributes.height = height;
4134 	  tree_view->priv->drag_highlight_window = gdk_window_new (gdk_screen_get_root_window (gtk_widget_get_screen (widget)),
4135 								   &attributes, attributes_mask);
4136 	  gtk_widget_register_window (GTK_WIDGET (tree_view), tree_view->priv->drag_highlight_window);
4137 
4138 	  mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
4139 
4140           cr = cairo_create (mask_image);
4141           cairo_move_to (cr, 0, 0);
4142           cairo_line_to (cr, width, 0);
4143           cairo_line_to (cr, width / 2., width / 2);
4144           cairo_move_to (cr, 0, height);
4145           cairo_line_to (cr, width, height);
4146           cairo_line_to (cr, width / 2., height - width / 2.);
4147           cairo_fill (cr);
4148           cairo_destroy (cr);
4149 
4150           mask_region = gdk_cairo_region_create_from_surface (mask_image);
4151 	  gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
4152 					   mask_region, 0, 0);
4153 
4154           cairo_region_destroy (mask_region);
4155           cairo_surface_destroy (mask_image);
4156 	}
4157 
4158       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
4159       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
4160     }
4161   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
4162 	   arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
4163     {
4164       GtkAllocation allocation;
4165       GtkWidget    *button;
4166       gint          expander_size;
4167 
4168       expander_size = gtk_tree_view_get_expander_size (tree_view);
4169 
4170       /* Get x, y, width, height of arrow */
4171       width = expander_size/2; /* remember, the arrow only takes half the available width */
4172       gdk_window_get_origin (gtk_widget_get_window (widget),
4173                              &x, &y);
4174       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
4175         {
4176           gtk_widget_get_allocation (widget, &allocation);
4177           x += allocation.width - width;
4178         }
4179 
4180       if (reorder->left_column)
4181         {
4182 	  button = gtk_tree_view_column_get_button (reorder->left_column);
4183           gtk_widget_get_allocation (button, &allocation);
4184           height = allocation.height;
4185         }
4186       else
4187         {
4188 	  button = gtk_tree_view_column_get_button (reorder->right_column);
4189           gtk_widget_get_allocation (button, &allocation);
4190           height = allocation.height;
4191         }
4192 
4193       y -= expander_size;
4194       height += 2 * expander_size;
4195 
4196       /* Create the new window */
4197       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
4198 	  tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
4199 	{
4200 	  if (tree_view->priv->drag_highlight_window)
4201 	    {
4202 	      gtk_widget_unregister_window (GTK_WIDGET (tree_view), tree_view->priv->drag_highlight_window);
4203 	      gdk_window_destroy (tree_view->priv->drag_highlight_window);
4204 	    }
4205 
4206 	  attributes.window_type = GDK_WINDOW_TEMP;
4207 	  attributes.wclass = GDK_INPUT_OUTPUT;
4208 	  attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
4209 	  attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_POINTER_MOTION_MASK;
4210 	  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
4211           attributes.x = x;
4212           attributes.y = y;
4213 	  attributes.width = width;
4214 	  attributes.height = height;
4215 	  tree_view->priv->drag_highlight_window = gdk_window_new (gdk_screen_get_root_window (gtk_widget_get_screen (widget)), &attributes, attributes_mask);
4216 	  gtk_widget_register_window (GTK_WIDGET (tree_view), tree_view->priv->drag_highlight_window);
4217 
4218 	  mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
4219 
4220           cr = cairo_create (mask_image);
4221           /* mirror if we're on the left */
4222           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
4223             {
4224               cairo_translate (cr, width, 0);
4225               cairo_scale (cr, -1, 1);
4226             }
4227           cairo_move_to (cr, 0, 0);
4228           cairo_line_to (cr, width, width);
4229           cairo_line_to (cr, 0, expander_size);
4230           cairo_move_to (cr, 0, height);
4231           cairo_line_to (cr, width, height - width);
4232           cairo_line_to (cr, 0, height - expander_size);
4233           cairo_fill (cr);
4234           cairo_destroy (cr);
4235 
4236           mask_region = gdk_cairo_region_create_from_surface (mask_image);
4237 	  gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
4238 					   mask_region, 0, 0);
4239 
4240           cairo_region_destroy (mask_region);
4241           cairo_surface_destroy (mask_image);
4242 	}
4243 
4244       tree_view->priv->drag_column_window_state = arrow_type;
4245       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
4246    }
4247   else
4248     {
4249       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
4250       gdk_window_hide (tree_view->priv->drag_highlight_window);
4251       return;
4252     }
4253 
4254   gdk_window_show (tree_view->priv->drag_highlight_window);
4255   gdk_window_raise (tree_view->priv->drag_highlight_window);
4256 }
4257 
4258 static gboolean
gtk_tree_view_motion_resize_column(GtkTreeView * tree_view,gdouble x,gdouble y)4259 gtk_tree_view_motion_resize_column (GtkTreeView *tree_view,
4260                                     gdouble      x,
4261                                     gdouble      y)
4262 {
4263   gint new_width;
4264   GtkTreeViewColumn *column;
4265 
4266   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
4267 
4268   if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
4269     new_width = MAX (tree_view->priv->x_drag - x, 0);
4270   else
4271     new_width = MAX (x - tree_view->priv->x_drag, 0);
4272 
4273   if (new_width != gtk_tree_view_column_get_fixed_width (column))
4274     gtk_tree_view_column_set_fixed_width (column, new_width);
4275 
4276   return FALSE;
4277 }
4278 
4279 static void
gtk_tree_view_update_current_reorder(GtkTreeView * tree_view)4280 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
4281 {
4282   GtkTreeViewColumnReorder *reorder = NULL;
4283   GdkEventSequence *sequence;
4284   GList *list;
4285   gdouble x;
4286 
4287   sequence = gtk_gesture_single_get_current_sequence
4288     (GTK_GESTURE_SINGLE (tree_view->priv->column_drag_gesture));
4289   gtk_gesture_get_point (tree_view->priv->column_drag_gesture,
4290                          sequence, &x, NULL);
4291   x += gtk_adjustment_get_value (tree_view->priv->hadjustment);
4292 
4293   for (list = tree_view->priv->column_drag_info; list; list = list->next)
4294     {
4295       reorder = (GtkTreeViewColumnReorder *) list->data;
4296       if (x >= reorder->left_align && x < reorder->right_align)
4297 	break;
4298       reorder = NULL;
4299     }
4300 
4301   tree_view->priv->cur_reorder = reorder;
4302   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
4303 }
4304 
4305 static void
gtk_tree_view_vertical_autoscroll(GtkTreeView * tree_view)4306 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
4307 {
4308   GdkRectangle visible_rect;
4309   gint y;
4310   gint offset;
4311 
4312   if (gtk_gesture_is_recognized (tree_view->priv->drag_gesture))
4313     {
4314       GdkEventSequence *sequence;
4315       gdouble py;
4316 
4317       sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (tree_view->priv->drag_gesture));
4318       gtk_gesture_get_point (tree_view->priv->drag_gesture, sequence, NULL, &py);
4319       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, 0, py,
4320                                                          NULL, &y);
4321     }
4322   else
4323     {
4324       y = tree_view->priv->event_last_y;
4325       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, 0, y, NULL, &y);
4326     }
4327 
4328   y += tree_view->priv->dy;
4329   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4330 
4331   /* see if we are near the edge. */
4332   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
4333   if (offset > 0)
4334     {
4335       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
4336       if (offset < 0)
4337 	return;
4338     }
4339 
4340   gtk_adjustment_set_value (tree_view->priv->vadjustment,
4341                             MAX (gtk_adjustment_get_value (tree_view->priv->vadjustment) + offset, 0.0));
4342 }
4343 
4344 static gboolean
gtk_tree_view_horizontal_autoscroll(GtkTreeView * tree_view)4345 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
4346 {
4347   GdkEventSequence *sequence;
4348   GdkRectangle visible_rect;
4349   gdouble x;
4350   gint offset;
4351 
4352   sequence = gtk_gesture_single_get_current_sequence
4353     (GTK_GESTURE_SINGLE (tree_view->priv->column_drag_gesture));
4354   gtk_gesture_get_point (tree_view->priv->column_drag_gesture,
4355                          sequence, &x, NULL);
4356   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4357 
4358   x += gtk_adjustment_get_value (tree_view->priv->hadjustment);
4359 
4360   /* See if we are near the edge. */
4361   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
4362   if (offset > 0)
4363     {
4364       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
4365       if (offset < 0)
4366 	return TRUE;
4367     }
4368   offset = offset/3;
4369 
4370   gtk_adjustment_set_value (tree_view->priv->hadjustment,
4371                             MAX (gtk_adjustment_get_value (tree_view->priv->hadjustment) + offset, 0.0));
4372 
4373   return TRUE;
4374 
4375 }
4376 
4377 static gboolean
gtk_tree_view_motion_drag_column(GtkTreeView * tree_view,gdouble x,gdouble y)4378 gtk_tree_view_motion_drag_column (GtkTreeView *tree_view,
4379                                   gdouble      x,
4380                                   gdouble      y)
4381 {
4382   GtkAllocation allocation, button_allocation;
4383   GtkTreeViewColumn *column = tree_view->priv->drag_column;
4384   GtkWidget *button;
4385   gint win_x, win_y;
4386 
4387   button = gtk_tree_view_column_get_button (column);
4388   x += gtk_adjustment_get_value (tree_view->priv->hadjustment);
4389 
4390   /* Handle moving the header */
4391   gdk_window_get_position (tree_view->priv->drag_window, &win_x, &win_y);
4392   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
4393   gtk_widget_get_allocation (button, &button_allocation);
4394   win_x = CLAMP (x - _gtk_tree_view_column_get_drag_x (column), 0,
4395                  MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
4396   gdk_window_move (tree_view->priv->drag_window, win_x, win_y);
4397   gdk_window_raise (tree_view->priv->drag_window);
4398 
4399   /* autoscroll, if needed */
4400   gtk_tree_view_horizontal_autoscroll (tree_view);
4401   /* Update the current reorder position and arrow; */
4402   gtk_tree_view_update_current_reorder (tree_view);
4403 
4404   return TRUE;
4405 }
4406 
4407 static void
gtk_tree_view_stop_rubber_band(GtkTreeView * tree_view)4408 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
4409 {
4410   remove_scroll_timeout (tree_view);
4411 
4412   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4413     {
4414       GtkTreePath *tmp_path;
4415 
4416       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4417 
4418       /* The anchor path should be set to the start path */
4419       if (tree_view->priv->rubber_band_start_node)
4420         {
4421           tmp_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->rubber_band_start_tree,
4422                                                      tree_view->priv->rubber_band_start_node);
4423 
4424           if (tree_view->priv->anchor)
4425             gtk_tree_row_reference_free (tree_view->priv->anchor);
4426 
4427           tree_view->priv->anchor =
4428             gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
4429                                               tree_view->priv->model,
4430                                               tmp_path);
4431 
4432           gtk_tree_path_free (tmp_path);
4433         }
4434 
4435       /* ... and the cursor to the end path */
4436       if (tree_view->priv->rubber_band_end_node)
4437         {
4438           tmp_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->rubber_band_end_tree,
4439                                                      tree_view->priv->rubber_band_end_node);
4440           gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, 0);
4441           gtk_tree_path_free (tmp_path);
4442         }
4443 
4444       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
4445 
4446       gtk_css_node_set_parent (tree_view->priv->rubber_band_cssnode, NULL);
4447       tree_view->priv->rubber_band_cssnode = NULL;
4448     }
4449 
4450   /* Clear status variables */
4451   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
4452   tree_view->priv->rubber_band_extend = FALSE;
4453   tree_view->priv->rubber_band_modify = FALSE;
4454 
4455   tree_view->priv->rubber_band_start_node = NULL;
4456   tree_view->priv->rubber_band_start_tree = NULL;
4457   tree_view->priv->rubber_band_end_node = NULL;
4458   tree_view->priv->rubber_band_end_tree = NULL;
4459 }
4460 
4461 static void
gtk_tree_view_update_rubber_band_selection_range(GtkTreeView * tree_view,GtkRBTree * start_tree,GtkRBNode * start_node,GtkRBTree * end_tree,GtkRBNode * end_node,gboolean select,gboolean skip_start,gboolean skip_end)4462 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
4463 						 GtkRBTree   *start_tree,
4464 						 GtkRBNode   *start_node,
4465 						 GtkRBTree   *end_tree,
4466 						 GtkRBNode   *end_node,
4467 						 gboolean     select,
4468 						 gboolean     skip_start,
4469 						 gboolean     skip_end)
4470 {
4471   if (start_node == end_node)
4472     return;
4473 
4474   /* We skip the first node and jump inside the loop */
4475   if (skip_start)
4476     goto skip_first;
4477 
4478   do
4479     {
4480       /* Small optimization by assuming insensitive nodes are never
4481        * selected.
4482        */
4483       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4484         {
4485 	  GtkTreePath *path;
4486 	  gboolean selectable;
4487 
4488 	  path = _gtk_tree_path_new_from_rbtree (start_tree, start_node);
4489 	  selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
4490 	  gtk_tree_path_free (path);
4491 
4492 	  if (!selectable)
4493 	    goto node_not_selectable;
4494 	}
4495 
4496       if (select)
4497         {
4498 	  if (tree_view->priv->rubber_band_extend)
4499             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4500 	  else if (tree_view->priv->rubber_band_modify)
4501 	    {
4502 	      /* Toggle the selection state */
4503 	      if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4504 		GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4505 	      else
4506 		GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4507 	    }
4508 	  else
4509 	    GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4510 	}
4511       else
4512         {
4513 	  /* Mirror the above */
4514 	  if (tree_view->priv->rubber_band_extend)
4515 	    GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4516 	  else if (tree_view->priv->rubber_band_modify)
4517 	    {
4518 	      /* Toggle the selection state */
4519 	      if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4520 		GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4521 	      else
4522 		GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4523 	    }
4524 	  else
4525 	    GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4526 	}
4527 
4528       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
4529 
4530 node_not_selectable:
4531       if (start_node == end_node)
4532 	break;
4533 
4534 skip_first:
4535 
4536       if (start_node->children)
4537         {
4538 	  start_tree = start_node->children;
4539           start_node = _gtk_rbtree_first (start_tree);
4540 	}
4541       else
4542         {
4543 	  _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
4544 
4545 	  if (!start_tree)
4546 	    /* Ran out of tree */
4547 	    break;
4548 	}
4549 
4550       if (skip_end && start_node == end_node)
4551 	break;
4552     }
4553   while (TRUE);
4554 }
4555 
4556 static void
gtk_tree_view_update_rubber_band_selection(GtkTreeView * tree_view)4557 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
4558 {
4559   GtkRBTree *start_tree, *end_tree;
4560   GtkRBNode *start_node, *end_node;
4561   gdouble start_y, offset_y;
4562   gint bin_y;
4563 
4564   if (!gtk_gesture_is_active (tree_view->priv->drag_gesture))
4565     return;
4566 
4567   gtk_gesture_drag_get_offset (GTK_GESTURE_DRAG (tree_view->priv->drag_gesture),
4568                                NULL, &offset_y);
4569   gtk_gesture_drag_get_start_point (GTK_GESTURE_DRAG (tree_view->priv->drag_gesture),
4570                                     NULL, &start_y);
4571   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, 0, start_y,
4572                                                      NULL, &bin_y);
4573   bin_y = MAX (0, bin_y + offset_y + tree_view->priv->dy);
4574 
4575   _gtk_rbtree_find_offset (tree_view->priv->tree, MIN (tree_view->priv->press_start_y, bin_y), &start_tree, &start_node);
4576   _gtk_rbtree_find_offset (tree_view->priv->tree, MAX (tree_view->priv->press_start_y, bin_y), &end_tree, &end_node);
4577 
4578   /* Handle the start area first */
4579   if (!start_node && !end_node)
4580     {
4581       if (tree_view->priv->rubber_band_start_node)
4582         {
4583           GtkRBNode *node = tree_view->priv->rubber_band_start_node;
4584           GtkRBTree *tree = tree_view->priv->rubber_band_start_tree;
4585 
4586 	  if (tree_view->priv->rubber_band_modify)
4587 	    {
4588 	      /* Toggle the selection state */
4589 	      if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4590 		GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SELECTED);
4591 	      else
4592 		GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SELECTED);
4593 	    }
4594           else
4595             GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SELECTED);
4596 
4597           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
4598         }
4599     }
4600   if (!tree_view->priv->rubber_band_start_node || !start_node)
4601     {
4602       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4603 						       start_tree,
4604 						       start_node,
4605 						       end_tree,
4606 						       end_node,
4607 						       TRUE,
4608 						       FALSE,
4609 						       FALSE);
4610     }
4611   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
4612            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4613     {
4614       /* New node is above the old one; selection became bigger */
4615       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4616 						       start_tree,
4617 						       start_node,
4618 						       tree_view->priv->rubber_band_start_tree,
4619 						       tree_view->priv->rubber_band_start_node,
4620 						       TRUE,
4621 						       FALSE,
4622 						       TRUE);
4623     }
4624   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
4625            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4626     {
4627       /* New node is below the old one; selection became smaller */
4628       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4629 						       tree_view->priv->rubber_band_start_tree,
4630 						       tree_view->priv->rubber_band_start_node,
4631 						       start_tree,
4632 						       start_node,
4633 						       FALSE,
4634 						       FALSE,
4635 						       TRUE);
4636     }
4637 
4638   tree_view->priv->rubber_band_start_tree = start_tree;
4639   tree_view->priv->rubber_band_start_node = start_node;
4640 
4641   /* Next, handle the end area */
4642   if (!tree_view->priv->rubber_band_end_node)
4643     {
4644       /* In the event this happens, start_node was also NULL; this case is
4645        * handled above.
4646        */
4647     }
4648   else if (!end_node)
4649     {
4650       /* Find the last node in the tree */
4651       _gtk_rbtree_find_offset (tree_view->priv->tree, gtk_tree_view_get_height (tree_view) - 1,
4652 			       &end_tree, &end_node);
4653 
4654       /* Selection reached end of the tree */
4655       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4656 						       tree_view->priv->rubber_band_end_tree,
4657 						       tree_view->priv->rubber_band_end_node,
4658 						       end_tree,
4659 						       end_node,
4660 						       TRUE,
4661 						       TRUE,
4662 						       FALSE);
4663     }
4664   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4665            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4666     {
4667       /* New node is below the old one; selection became bigger */
4668       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4669 						       tree_view->priv->rubber_band_end_tree,
4670 						       tree_view->priv->rubber_band_end_node,
4671 						       end_tree,
4672 						       end_node,
4673 						       TRUE,
4674 						       TRUE,
4675 						       FALSE);
4676     }
4677   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4678            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4679     {
4680       /* New node is above the old one; selection became smaller */
4681       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4682 						       end_tree,
4683 						       end_node,
4684 						       tree_view->priv->rubber_band_end_tree,
4685 						       tree_view->priv->rubber_band_end_node,
4686 						       FALSE,
4687 						       TRUE,
4688 						       FALSE);
4689     }
4690 
4691   tree_view->priv->rubber_band_end_tree = end_tree;
4692   tree_view->priv->rubber_band_end_node = end_node;
4693 }
4694 
4695 static void
gtk_tree_view_update_rubber_band(GtkTreeView * tree_view)4696 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4697 {
4698   gdouble start_x, start_y, offset_x, offset_y, x, y;
4699   GdkRectangle old_area;
4700   GdkRectangle new_area;
4701   cairo_region_t *invalid_region;
4702   gint bin_x, bin_y;
4703 
4704   if (!gtk_gesture_is_recognized (tree_view->priv->drag_gesture))
4705     return;
4706 
4707   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4708   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4709   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4710   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4711 
4712   gtk_gesture_drag_get_offset (GTK_GESTURE_DRAG (tree_view->priv->drag_gesture),
4713                                &offset_x, &offset_y);
4714   gtk_gesture_drag_get_start_point (GTK_GESTURE_DRAG (tree_view->priv->drag_gesture),
4715                                     &start_x, &start_y);
4716   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, start_x, start_y,
4717                                                      &bin_x, &bin_y);
4718   bin_y += tree_view->priv->dy;
4719 
4720   x = MAX (bin_x + offset_x, 0);
4721   y = MAX (bin_y + offset_y, 0);
4722 
4723   new_area.x = MIN (tree_view->priv->press_start_x, x);
4724   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4725   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4726   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4727 
4728   invalid_region = cairo_region_create_rectangle (&old_area);
4729   cairo_region_union_rectangle (invalid_region, &new_area);
4730 
4731   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4732 
4733   cairo_region_destroy (invalid_region);
4734 
4735   tree_view->priv->rubber_band_x = x;
4736   tree_view->priv->rubber_band_y = y;
4737 
4738   gtk_tree_view_update_rubber_band_selection (tree_view);
4739 }
4740 
4741 static void
gtk_tree_view_paint_rubber_band(GtkTreeView * tree_view,cairo_t * cr)4742 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4743                                  cairo_t      *cr)
4744 {
4745   gdouble start_x, start_y, offset_x, offset_y;
4746   GdkRectangle rect;
4747   GtkStyleContext *context;
4748   gint bin_x, bin_y;
4749 
4750   if (!gtk_gesture_is_recognized (tree_view->priv->drag_gesture))
4751     return;
4752 
4753   gtk_gesture_drag_get_offset (GTK_GESTURE_DRAG (tree_view->priv->drag_gesture),
4754                                &offset_x, &offset_y);
4755   gtk_gesture_drag_get_start_point (GTK_GESTURE_DRAG (tree_view->priv->drag_gesture),
4756                                     &start_x, &start_y);
4757   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, start_x, start_y,
4758                                                      &bin_x, &bin_y);
4759   bin_x = MAX (0, bin_x + offset_x);
4760   bin_y = MAX (0, bin_y + offset_y + tree_view->priv->dy);
4761 
4762   cairo_save (cr);
4763 
4764   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4765 
4766   gtk_style_context_save_to_node (context, tree_view->priv->rubber_band_cssnode);
4767 
4768   rect.x = MIN (tree_view->priv->press_start_x, bin_x);
4769   rect.y = MIN (tree_view->priv->press_start_y, bin_y) - tree_view->priv->dy;
4770   rect.width = ABS (tree_view->priv->press_start_x - bin_x) + 1;
4771   rect.height = ABS (tree_view->priv->press_start_y - bin_y) + 1;
4772 
4773   gdk_cairo_rectangle (cr, &rect);
4774   cairo_clip (cr);
4775 
4776   gtk_render_background (context, cr,
4777                          rect.x, rect.y,
4778                          rect.width, rect.height);
4779   gtk_render_frame (context, cr,
4780                     rect.x, rect.y,
4781                     rect.width, rect.height);
4782 
4783   gtk_style_context_restore (context);
4784   cairo_restore (cr);
4785 }
4786 
4787 static void
gtk_tree_view_column_drag_gesture_update(GtkGestureDrag * gesture,gdouble offset_x,gdouble offset_y,GtkTreeView * tree_view)4788 gtk_tree_view_column_drag_gesture_update (GtkGestureDrag *gesture,
4789                                           gdouble         offset_x,
4790                                           gdouble         offset_y,
4791                                           GtkTreeView    *tree_view)
4792 {
4793   gdouble start_x, start_y, x, y;
4794   GdkEventSequence *sequence;
4795 
4796   sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
4797 
4798   if (gtk_gesture_get_sequence_state (GTK_GESTURE (gesture), sequence) != GTK_EVENT_SEQUENCE_CLAIMED)
4799     return;
4800 
4801   gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
4802   x = start_x + offset_x;
4803   y = start_y + offset_y;
4804 
4805   if (tree_view->priv->in_column_resize)
4806     gtk_tree_view_motion_resize_column (tree_view, x, y);
4807   else if (tree_view->priv->in_column_drag)
4808     gtk_tree_view_motion_drag_column (tree_view, x, y);
4809 }
4810 
4811 static void
gtk_tree_view_drag_gesture_update(GtkGestureDrag * gesture,gdouble offset_x,gdouble offset_y,GtkTreeView * tree_view)4812 gtk_tree_view_drag_gesture_update (GtkGestureDrag *gesture,
4813                                    gdouble         offset_x,
4814                                    gdouble         offset_y,
4815                                    GtkTreeView    *tree_view)
4816 {
4817   if (tree_view->priv->tree == NULL)
4818     {
4819       gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
4820       return;
4821     }
4822 
4823   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4824     {
4825       GtkCssNode *widget_node;
4826 
4827       widget_node = gtk_widget_get_css_node (GTK_WIDGET (tree_view));
4828       tree_view->priv->rubber_band_cssnode = gtk_css_node_new ();
4829       gtk_css_node_set_name (tree_view->priv->rubber_band_cssnode, I_("rubberband"));
4830       gtk_css_node_set_parent (tree_view->priv->rubber_band_cssnode, widget_node);
4831       gtk_css_node_set_state (tree_view->priv->rubber_band_cssnode, gtk_css_node_get_state (widget_node));
4832       g_object_unref (tree_view->priv->rubber_band_cssnode);
4833 
4834       gtk_tree_view_update_rubber_band (tree_view);
4835 
4836       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4837       gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
4838     }
4839   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4840     {
4841       gtk_tree_view_update_rubber_band (tree_view);
4842 
4843       add_scroll_timeout (tree_view);
4844     }
4845   else if (!tree_view->priv->rubber_band_status)
4846     {
4847       if (gtk_tree_view_maybe_begin_dragging_row (tree_view))
4848         gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
4849     }
4850 }
4851 
4852 static gboolean
gtk_tree_view_motion(GtkWidget * widget,GdkEventMotion * event)4853 gtk_tree_view_motion (GtkWidget      *widget,
4854 		      GdkEventMotion *event)
4855 {
4856   GtkTreeView *tree_view;
4857   GtkRBTree *tree;
4858   GtkRBNode *node;
4859   gint new_y;
4860 
4861   tree_view = (GtkTreeView *) widget;
4862 
4863   if (tree_view->priv->tree)
4864     {
4865       /* If we are currently pressing down a button, we don't want to prelight anything else. */
4866       if (gtk_gesture_is_active (tree_view->priv->drag_gesture) ||
4867           gtk_gesture_is_active (tree_view->priv->multipress_gesture))
4868         node = NULL;
4869 
4870       new_y = MAX (0, TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->y));
4871 
4872       _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4873 
4874       tree_view->priv->event_last_x = event->x;
4875       tree_view->priv->event_last_y = event->y;
4876       prelight_or_select (tree_view, tree, node, event->x, event->y);
4877     }
4878 
4879   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->motion_notify_event (widget, event);
4880 }
4881 
4882 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4883  * the tree is empty.
4884  */
4885 static void
invalidate_empty_focus(GtkTreeView * tree_view)4886 invalidate_empty_focus (GtkTreeView *tree_view)
4887 {
4888   GdkRectangle area;
4889 
4890   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4891     return;
4892 
4893   area.x = 0;
4894   area.y = 0;
4895   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4896   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4897   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4898 }
4899 
4900 /* Draws background and a focus rectangle near the edge of the bin_window;
4901  * used when the tree is empty.
4902  */
4903 static void
draw_empty(GtkTreeView * tree_view,cairo_t * cr)4904 draw_empty (GtkTreeView *tree_view,
4905             cairo_t     *cr)
4906 {
4907   GtkWidget *widget = GTK_WIDGET (tree_view);
4908   GtkStyleContext *context;
4909   gint width, height;
4910 
4911   context = gtk_widget_get_style_context (widget);
4912 
4913   width = gdk_window_get_width (tree_view->priv->bin_window);
4914   height = gdk_window_get_height (tree_view->priv->bin_window);
4915 
4916   gtk_render_background (context, cr, 0, 0, width, height);
4917 
4918   if (gtk_widget_has_visible_focus (widget))
4919     gtk_render_focus (context, cr, 0, 0, width, height);
4920 }
4921 
4922 typedef enum {
4923   GTK_TREE_VIEW_GRID_LINE,
4924   GTK_TREE_VIEW_TREE_LINE,
4925   GTK_TREE_VIEW_FOREGROUND_LINE
4926 } GtkTreeViewLineType;
4927 
4928 static void
gtk_tree_view_draw_line(GtkTreeView * tree_view,cairo_t * cr,GtkTreeViewLineType type,int x1,int y1,int x2,int y2)4929 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4930                          cairo_t             *cr,
4931                          GtkTreeViewLineType  type,
4932                          int                  x1,
4933                          int                  y1,
4934                          int                  x2,
4935                          int                  y2)
4936 {
4937   GtkStyleContext *context;
4938 
4939   cairo_save (cr);
4940 
4941   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4942 
4943   switch (type)
4944     {
4945     case GTK_TREE_VIEW_TREE_LINE:
4946       {
4947         const GdkRGBA *color;
4948 
4949         color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_LEFT_COLOR));
4950 
4951         gdk_cairo_set_source_rgba (cr, color);
4952         cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4953         if (tree_view->priv->tree_line_dashes[0])
4954           cairo_set_dash (cr, tree_view->priv->tree_line_dashes, 2, 0.5);
4955       }
4956       break;
4957 
4958     case GTK_TREE_VIEW_GRID_LINE:
4959       {
4960         const GdkRGBA *color;
4961 
4962         color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_COLOR));
4963 
4964         gdk_cairo_set_source_rgba (cr, color);
4965         cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4966         if (tree_view->priv->grid_line_dashes[0])
4967           cairo_set_dash (cr, tree_view->priv->grid_line_dashes, 2, 0.5);
4968       }
4969       break;
4970 
4971     case GTK_TREE_VIEW_FOREGROUND_LINE:
4972       {
4973         GdkRGBA color;
4974 
4975         cairo_set_line_width (cr, 1.0);
4976         gtk_style_context_get_color (context, gtk_style_context_get_state (context), &color);
4977         gdk_cairo_set_source_rgba (cr, &color);
4978       }
4979       break;
4980 
4981     default:
4982       g_assert_not_reached ();
4983       break;
4984     }
4985 
4986   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4987   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4988   cairo_stroke (cr);
4989 
4990   cairo_restore (cr);
4991 }
4992 
4993 static void
gtk_tree_view_draw_grid_lines(GtkTreeView * tree_view,cairo_t * cr)4994 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4995 			       cairo_t        *cr)
4996 {
4997   GList *list, *first, *last;
4998   gboolean rtl;
4999   gint current_x = 0;
5000 
5001   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
5002       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
5003     return;
5004 
5005   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5006 
5007   first = g_list_first (tree_view->priv->columns);
5008   last = g_list_last (tree_view->priv->columns);
5009 
5010   for (list = (rtl ? last : first);
5011        list;
5012        list = (rtl ? list->prev : list->next))
5013     {
5014       GtkTreeViewColumn *column = list->data;
5015 
5016       /* We don't want a line for the last column */
5017       if (column == (rtl ? first->data : last->data))
5018         break;
5019 
5020       if (!gtk_tree_view_column_get_visible (column))
5021         continue;
5022 
5023       current_x += gtk_tree_view_column_get_width (column);
5024 
5025       gtk_tree_view_draw_line (tree_view, cr,
5026                                GTK_TREE_VIEW_GRID_LINE,
5027                                current_x - 1, 0,
5028                                current_x - 1, gtk_tree_view_get_height (tree_view));
5029     }
5030 }
5031 
5032 /* Warning: Very scary function.
5033  * Modify at your own risk
5034  *
5035  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
5036  * FIXME: It’s not...
5037  */
5038 static gboolean
gtk_tree_view_bin_draw(GtkWidget * widget,cairo_t * cr)5039 gtk_tree_view_bin_draw (GtkWidget      *widget,
5040 			cairo_t        *cr)
5041 {
5042   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5043   GtkTreePath *path;
5044   GtkRBTree *tree;
5045   GList *list;
5046   GtkRBNode *node;
5047   GtkRBNode *drag_highlight = NULL;
5048   GtkRBTree *drag_highlight_tree = NULL;
5049   GtkTreeIter iter;
5050   gint new_y;
5051   gint y_offset, cell_offset;
5052   gint max_height;
5053   gint depth;
5054   GdkRectangle background_area;
5055   GdkRectangle cell_area;
5056   GdkRectangle clip;
5057   guint flags;
5058   gint bin_window_width;
5059   gint bin_window_height;
5060   GtkTreePath *drag_dest_path = NULL;
5061   GList *first_column, *last_column;
5062   gint vertical_separator;
5063   gint horizontal_separator;
5064   gboolean allow_rules;
5065   gboolean has_can_focus_cell;
5066   gboolean rtl;
5067   gint n_visible_columns;
5068   gint grid_line_width;
5069   gint expander_size;
5070   gboolean draw_vgrid_lines, draw_hgrid_lines;
5071   GtkStyleContext *context;
5072   gboolean parity;
5073 
5074   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5075   context = gtk_widget_get_style_context (widget);
5076 
5077   gtk_widget_style_get (widget,
5078 			"horizontal-separator", &horizontal_separator,
5079 			"vertical-separator", &vertical_separator,
5080 			"allow-rules", &allow_rules,
5081 			NULL);
5082 
5083   if (tree_view->priv->tree == NULL)
5084     {
5085       draw_empty (tree_view, cr);
5086       return TRUE;
5087     }
5088 
5089   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
5090   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
5091   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
5092     return TRUE;
5093 
5094   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
5095 
5096   if (new_y < 0)
5097     new_y = 0;
5098   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5099 
5100   if (gtk_tree_view_get_height (tree_view) < bin_window_height)
5101     {
5102       gtk_style_context_save (context);
5103       gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
5104 
5105       gtk_render_background (context, cr,
5106                              0, gtk_tree_view_get_height (tree_view),
5107                              bin_window_width,
5108                              bin_window_height - gtk_tree_view_get_height (tree_view));
5109 
5110       gtk_style_context_restore (context);
5111     }
5112 
5113   if (node == NULL)
5114     goto done;
5115 
5116   /* find the path for the node */
5117   path = _gtk_tree_path_new_from_rbtree (tree, node);
5118   gtk_tree_model_get_iter (tree_view->priv->model,
5119 			   &iter,
5120 			   path);
5121   depth = gtk_tree_path_get_depth (path);
5122   gtk_tree_path_free (path);
5123 
5124   if (tree_view->priv->drag_dest_row)
5125     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
5126 
5127   if (drag_dest_path)
5128     _gtk_tree_view_find_node (tree_view, drag_dest_path,
5129                               &drag_highlight_tree, &drag_highlight);
5130 
5131   draw_vgrid_lines =
5132     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5133     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5134   draw_hgrid_lines =
5135     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5136     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5137   expander_size = gtk_tree_view_get_expander_size (tree_view);
5138 
5139   if (draw_vgrid_lines || draw_hgrid_lines)
5140     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
5141 
5142   n_visible_columns = 0;
5143   for (list = tree_view->priv->columns; list; list = list->next)
5144     {
5145       if (!gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
5146 	continue;
5147       n_visible_columns ++;
5148     }
5149 
5150   /* Find the last column */
5151   for (last_column = g_list_last (tree_view->priv->columns);
5152        last_column &&
5153        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
5154        last_column = last_column->prev)
5155     ;
5156 
5157   /* and the first */
5158   for (first_column = g_list_first (tree_view->priv->columns);
5159        first_column &&
5160        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
5161        first_column = first_column->next)
5162     ;
5163 
5164   /* Actually process the expose event.  To do this, we want to
5165    * start at the first node of the event, and walk the tree in
5166    * order, drawing each successive node.
5167    */
5168 
5169   parity = !(_gtk_rbtree_node_get_index (tree, node) % 2);
5170 
5171   do
5172     {
5173       gboolean is_separator = FALSE;
5174       gint n_col = 0;
5175 
5176       parity = !parity;
5177       is_separator = row_is_separator (tree_view, &iter, NULL);
5178 
5179       max_height = gtk_tree_view_get_row_height (tree_view, node);
5180 
5181       cell_offset = 0;
5182 
5183       background_area.y = y_offset + clip.y;
5184       background_area.height = max_height;
5185 
5186       flags = 0;
5187 
5188       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
5189 	flags |= GTK_CELL_RENDERER_PRELIT;
5190 
5191       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
5192         flags |= GTK_CELL_RENDERER_SELECTED;
5193 
5194       /* we *need* to set cell data on all cells before the call
5195        * to _has_can_focus_cell, else _has_can_focus_cell() does not
5196        * return a correct value.
5197        */
5198       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
5199 	   list;
5200 	   list = (rtl ? list->prev : list->next))
5201         {
5202 	  GtkTreeViewColumn *column = list->data;
5203 	  gtk_tree_view_column_cell_set_cell_data (column,
5204 						   tree_view->priv->model,
5205 						   &iter,
5206 						   GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5207 						   node->children?TRUE:FALSE);
5208         }
5209 
5210       has_can_focus_cell = gtk_tree_view_has_can_focus_cell (tree_view);
5211 
5212       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
5213 	   list;
5214 	   list = (rtl ? list->prev : list->next))
5215 	{
5216 	  GtkTreeViewColumn *column = list->data;
5217 	  GtkStateFlags state = 0;
5218           gint width;
5219           gboolean draw_focus;
5220 
5221 	  if (!gtk_tree_view_column_get_visible (column))
5222             continue;
5223 
5224           n_col++;
5225           width = gtk_tree_view_column_get_width (column);
5226 
5227 	  if (cell_offset > clip.x + clip.width ||
5228 	      cell_offset + width < clip.x)
5229 	    {
5230 	      cell_offset += width;
5231 	      continue;
5232 	    }
5233 
5234           if (gtk_tree_view_column_get_sort_indicator (column))
5235 	    flags |= GTK_CELL_RENDERER_SORTED;
5236           else
5237             flags &= ~GTK_CELL_RENDERER_SORTED;
5238 
5239 	  if (tree_view->priv->cursor_node == node)
5240             flags |= GTK_CELL_RENDERER_FOCUSED;
5241           else
5242             flags &= ~GTK_CELL_RENDERER_FOCUSED;
5243 
5244           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
5245             flags |= GTK_CELL_RENDERER_EXPANDABLE;
5246           else
5247             flags &= ~GTK_CELL_RENDERER_EXPANDABLE;
5248 
5249           if (node->children)
5250             flags |= GTK_CELL_RENDERER_EXPANDED;
5251           else
5252             flags &= ~GTK_CELL_RENDERER_EXPANDED;
5253 
5254 	  background_area.x = cell_offset;
5255 	  background_area.width = width;
5256 
5257           cell_area = background_area;
5258           cell_area.y += vertical_separator / 2;
5259           cell_area.x += horizontal_separator / 2;
5260           cell_area.height -= vertical_separator;
5261 	  cell_area.width -= horizontal_separator;
5262 
5263 	  if (draw_vgrid_lines)
5264 	    {
5265 	      if (list == first_column)
5266 	        {
5267 		  cell_area.width -= grid_line_width / 2;
5268 		}
5269 	      else if (list == last_column)
5270 	        {
5271 		  cell_area.x += grid_line_width / 2;
5272 		  cell_area.width -= grid_line_width / 2;
5273 		}
5274 	      else
5275 	        {
5276 	          cell_area.x += grid_line_width / 2;
5277 	          cell_area.width -= grid_line_width;
5278 		}
5279 	    }
5280 
5281 	  if (draw_hgrid_lines)
5282 	    {
5283 	      cell_area.y += grid_line_width / 2;
5284 	      cell_area.height -= grid_line_width;
5285 	    }
5286 
5287 	  if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
5288 	    {
5289 	      cell_offset += gtk_tree_view_column_get_width (column);
5290 	      continue;
5291 	    }
5292 
5293 	  gtk_tree_view_column_cell_set_cell_data (column,
5294 						   tree_view->priv->model,
5295 						   &iter,
5296 						   GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5297 						   node->children?TRUE:FALSE);
5298 
5299           gtk_style_context_save (context);
5300 
5301           state = gtk_cell_renderer_get_state (NULL, widget, flags);
5302           gtk_style_context_set_state (context, state);
5303 
5304           gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
5305 
5306 	  if (node == tree_view->priv->cursor_node && has_can_focus_cell
5307               && ((column == tree_view->priv->focus_column
5308                    && tree_view->priv->draw_keyfocus &&
5309                    gtk_widget_has_visible_focus (widget))
5310                   || (column == tree_view->priv->edited_column)))
5311             draw_focus = TRUE;
5312           else
5313             draw_focus = FALSE;
5314 
5315 	  /* Draw background */
5316           gtk_render_background (context, cr,
5317                                  background_area.x,
5318                                  background_area.y,
5319                                  background_area.width,
5320                                  background_area.height);
5321 
5322           /* Draw frame */
5323           gtk_render_frame (context, cr,
5324                             background_area.x,
5325                             background_area.y,
5326                             background_area.width,
5327                             background_area.height);
5328 
5329 	  if (gtk_tree_view_is_expander_column (tree_view, column))
5330 	    {
5331 	      if (!rtl)
5332 		cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
5333 	      cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
5334 
5335               if (gtk_tree_view_draw_expanders (tree_view))
5336 	        {
5337 	          if (!rtl)
5338 		    cell_area.x += depth * expander_size;
5339 		  cell_area.width -= depth * expander_size;
5340 		}
5341 
5342 	      if (is_separator)
5343                 {
5344                   gtk_style_context_save (context);
5345                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5346 
5347                   gtk_render_line (context, cr,
5348                                    cell_area.x,
5349                                    cell_area.y + cell_area.height / 2,
5350                                    cell_area.x + cell_area.width,
5351                                    cell_area.y + cell_area.height / 2);
5352 
5353                   gtk_style_context_restore (context);
5354                 }
5355 	      else
5356                 {
5357                   _gtk_tree_view_column_cell_render (column,
5358                                                      cr,
5359                                                      &background_area,
5360                                                      &cell_area,
5361                                                      flags,
5362                                                      draw_focus);
5363                 }
5364 
5365 	      if (gtk_tree_view_draw_expanders (tree_view)
5366 		  && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
5367 		{
5368 		  gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
5369                                             cr,
5370 					    tree,
5371 					    node);
5372 		}
5373 	    }
5374 	  else
5375 	    {
5376 	      if (is_separator)
5377                 {
5378                   gtk_style_context_save (context);
5379                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5380 
5381                   gtk_render_line (context, cr,
5382                                    cell_area.x,
5383                                    cell_area.y + cell_area.height / 2,
5384                                    cell_area.x + cell_area.width,
5385                                    cell_area.y + cell_area.height / 2);
5386 
5387                   gtk_style_context_restore (context);
5388                 }
5389 	      else
5390 		_gtk_tree_view_column_cell_render (column,
5391 						   cr,
5392 						   &background_area,
5393 						   &cell_area,
5394 						   flags,
5395                                                    draw_focus);
5396 	    }
5397 
5398 	  if (draw_hgrid_lines)
5399 	    {
5400 	      if (background_area.y >= clip.y)
5401                 gtk_tree_view_draw_line (tree_view, cr,
5402                                          GTK_TREE_VIEW_GRID_LINE,
5403                                          background_area.x, background_area.y,
5404                                          background_area.x + background_area.width,
5405 			                 background_area.y);
5406 
5407 	      if (background_area.y + max_height < clip.y + clip.height)
5408                 gtk_tree_view_draw_line (tree_view, cr,
5409                                          GTK_TREE_VIEW_GRID_LINE,
5410                                          background_area.x, background_area.y + max_height,
5411                                          background_area.x + background_area.width,
5412 			                 background_area.y + max_height);
5413 	    }
5414 
5415 	  if (gtk_tree_view_is_expander_column (tree_view, column) &&
5416 	      tree_view->priv->tree_lines_enabled)
5417 	    {
5418 	      gint x = background_area.x;
5419 	      gint mult = rtl ? -1 : 1;
5420 	      gint y0 = background_area.y;
5421 	      gint y1 = background_area.y + background_area.height/2;
5422 	      gint y2 = background_area.y + background_area.height;
5423 
5424 	      if (rtl)
5425 		x += background_area.width - 1;
5426 
5427 	      if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
5428 		  && depth > 1)
5429 	        {
5430                   gtk_tree_view_draw_line (tree_view, cr,
5431                                            GTK_TREE_VIEW_TREE_LINE,
5432                                            x + expander_size * (depth - 1.5) * mult,
5433                                            y1,
5434                                            x + expander_size * (depth - 1.1) * mult,
5435                                            y1);
5436 	        }
5437 	      else if (depth > 1)
5438 	        {
5439                   gtk_tree_view_draw_line (tree_view, cr,
5440                                            GTK_TREE_VIEW_TREE_LINE,
5441                                            x + expander_size * (depth - 1.5) * mult,
5442                                            y1,
5443                                            x + expander_size * (depth - 0.5) * mult,
5444                                            y1);
5445 		}
5446 
5447 	      if (depth > 1)
5448 	        {
5449 		  gint i;
5450 		  GtkRBNode *tmp_node;
5451 		  GtkRBTree *tmp_tree;
5452 
5453 	          if (!_gtk_rbtree_next (tree, node))
5454                     gtk_tree_view_draw_line (tree_view, cr,
5455                                              GTK_TREE_VIEW_TREE_LINE,
5456                                              x + expander_size * (depth - 1.5) * mult,
5457                                              y0,
5458                                              x + expander_size * (depth - 1.5) * mult,
5459                                              y1);
5460 		  else
5461                     gtk_tree_view_draw_line (tree_view, cr,
5462                                              GTK_TREE_VIEW_TREE_LINE,
5463                                              x + expander_size * (depth - 1.5) * mult,
5464                                              y0,
5465                                              x + expander_size * (depth - 1.5) * mult,
5466                                              y2);
5467 
5468 		  tmp_node = tree->parent_node;
5469 		  tmp_tree = tree->parent_tree;
5470 
5471 		  for (i = depth - 2; i > 0; i--)
5472 		    {
5473 	              if (_gtk_rbtree_next (tmp_tree, tmp_node))
5474                         gtk_tree_view_draw_line (tree_view, cr,
5475                                                  GTK_TREE_VIEW_TREE_LINE,
5476                                                  x + expander_size * (i - 0.5) * mult,
5477                                                  y0,
5478                                                  x + expander_size * (i - 0.5) * mult,
5479                                                  y2);
5480 
5481 		      tmp_node = tmp_tree->parent_node;
5482 		      tmp_tree = tmp_tree->parent_tree;
5483 		    }
5484 		}
5485 	    }
5486 
5487           gtk_style_context_restore (context);
5488 	  cell_offset += gtk_tree_view_column_get_width (column);
5489 	}
5490 
5491       if (node == drag_highlight)
5492         {
5493           /* Draw indicator for the drop
5494            */
5495 	  GtkRBTree *drag_tree = NULL;
5496 	  GtkRBNode *drag_node = NULL;
5497 
5498           gtk_style_context_save (context);
5499           gtk_style_context_set_state (context, gtk_style_context_get_state (context) | GTK_STATE_FLAG_DROP_ACTIVE);
5500 
5501           switch (tree_view->priv->drag_dest_pos)
5502             {
5503             case GTK_TREE_VIEW_DROP_BEFORE:
5504               gtk_style_context_add_class (context, "before");
5505               break;
5506 
5507             case GTK_TREE_VIEW_DROP_AFTER:
5508               gtk_style_context_add_class (context, "after");
5509               break;
5510 
5511             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
5512             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
5513               gtk_style_context_add_class (context, "into");
5514               break;
5515             }
5516 
5517           _gtk_tree_view_find_node (tree_view, drag_dest_path, &drag_tree, &drag_node);
5518           if (drag_tree != NULL)
5519              gtk_render_frame (context, cr,
5520                                0, gtk_tree_view_get_row_y_offset (tree_view, drag_tree, drag_node),
5521                                gdk_window_get_width (tree_view->priv->bin_window),
5522                                gtk_tree_view_get_row_height (tree_view, drag_node));
5523 
5524           gtk_style_context_restore (context);
5525         }
5526 
5527       /* draw the big row-spanning focus rectangle, if needed */
5528       if (!has_can_focus_cell && node == tree_view->priv->cursor_node &&
5529           tree_view->priv->draw_keyfocus &&
5530 	  gtk_widget_has_visible_focus (widget))
5531         {
5532 	  gint tmp_y, tmp_height;
5533 	  GtkStateFlags focus_rect_state = 0;
5534 
5535           gtk_style_context_save (context);
5536 
5537           focus_rect_state = gtk_cell_renderer_get_state (NULL, widget, flags);
5538           gtk_style_context_set_state (context, focus_rect_state);
5539 
5540 	  if (draw_hgrid_lines)
5541 	    {
5542 	      tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node) + grid_line_width / 2;
5543               tmp_height = gtk_tree_view_get_row_height (tree_view, node) - grid_line_width;
5544 	    }
5545 	  else
5546 	    {
5547 	      tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
5548               tmp_height = gtk_tree_view_get_row_height (tree_view, node);
5549 	    }
5550 
5551           gtk_render_focus (context, cr,
5552                             0, tmp_y,
5553                             gdk_window_get_width (tree_view->priv->bin_window),
5554                             tmp_height);
5555 
5556           gtk_style_context_restore (context);
5557         }
5558 
5559       y_offset += max_height;
5560       if (node->children)
5561 	{
5562 	  GtkTreeIter parent = iter;
5563 	  gboolean has_child;
5564 
5565 	  tree = node->children;
5566           node = _gtk_rbtree_first (tree);
5567 
5568 	  has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5569 						    &iter,
5570 						    &parent);
5571 	  depth++;
5572 
5573 	  /* Sanity Check! */
5574 	  TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
5575 	}
5576       else
5577 	{
5578 	  gboolean done = FALSE;
5579 
5580 	  do
5581 	    {
5582 	      node = _gtk_rbtree_next (tree, node);
5583 	      if (node != NULL)
5584 		{
5585 		  gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5586 		  done = TRUE;
5587 
5588 		  /* Sanity Check! */
5589 		  TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5590 		}
5591 	      else
5592 		{
5593 		  GtkTreeIter parent_iter = iter;
5594 		  gboolean has_parent;
5595 
5596 		  node = tree->parent_node;
5597 		  tree = tree->parent_tree;
5598 		  if (tree == NULL)
5599 		    /* we should go to done to free some memory */
5600 		    goto done;
5601 		  has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5602 							   &iter,
5603 							   &parent_iter);
5604 		  depth--;
5605 
5606 		  /* Sanity check */
5607 		  TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5608 		}
5609 	    }
5610 	  while (!done);
5611 	}
5612     }
5613   while (y_offset < clip.height);
5614 
5615 done:
5616   gtk_tree_view_draw_grid_lines (tree_view, cr);
5617 
5618   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5619     gtk_tree_view_paint_rubber_band (tree_view, cr);
5620 
5621   if (drag_dest_path)
5622     gtk_tree_path_free (drag_dest_path);
5623 
5624   return FALSE;
5625 }
5626 
5627 static void
draw_bin(cairo_t * cr,gpointer user_data)5628 draw_bin (cairo_t *cr,
5629 	  gpointer user_data)
5630 {
5631   GtkWidget *widget = GTK_WIDGET (user_data);
5632   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5633   GList *tmp_list;
5634 
5635   cairo_save (cr);
5636 
5637   gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5638   gtk_tree_view_bin_draw (widget, cr);
5639 
5640   cairo_restore (cr);
5641 
5642   /* We can't just chain up to Container::draw as it will try to send the
5643    * event to the headers, so we handle propagating it to our children
5644    * (eg. widgets being edited) ourselves.
5645    */
5646   tmp_list = tree_view->priv->children;
5647   while (tmp_list)
5648     {
5649       GtkTreeViewChild *child = tmp_list->data;
5650       tmp_list = tmp_list->next;
5651 
5652       gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5653     }
5654 }
5655 
5656 static gboolean
gtk_tree_view_draw(GtkWidget * widget,cairo_t * cr)5657 gtk_tree_view_draw (GtkWidget *widget,
5658                     cairo_t   *cr)
5659 {
5660   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5661   GtkWidget   *button;
5662   GtkStyleContext *context;
5663 
5664   context = gtk_widget_get_style_context (widget);
5665 
5666   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5667     {
5668       cairo_rectangle_int_t view_rect;
5669       cairo_rectangle_int_t canvas_rect;
5670 
5671       view_rect.x = 0;
5672       view_rect.y = gtk_tree_view_get_effective_header_height (tree_view);
5673       view_rect.width = gtk_widget_get_allocated_width (widget);
5674       view_rect.height = gtk_widget_get_allocated_height (widget) - view_rect.y;
5675 
5676       gdk_window_get_position (tree_view->priv->bin_window, &canvas_rect.x, &canvas_rect.y);
5677       canvas_rect.y = -gtk_adjustment_get_value (tree_view->priv->vadjustment);
5678       canvas_rect.width = gdk_window_get_width (tree_view->priv->bin_window);
5679       canvas_rect.height = gtk_tree_view_get_height (tree_view);
5680 
5681       _gtk_pixel_cache_draw (tree_view->priv->pixel_cache, cr, tree_view->priv->bin_window,
5682 			     &view_rect, &canvas_rect,
5683 			     draw_bin, widget);
5684     }
5685   else if (tree_view->priv->drag_highlight_window &&
5686            gtk_cairo_should_draw_window (cr, tree_view->priv->drag_highlight_window))
5687     {
5688       GdkRGBA color;
5689 
5690       gtk_style_context_get_color (context, gtk_style_context_get_state (context), &color);
5691       cairo_save (cr);
5692       gtk_cairo_transform_to_window (cr, GTK_WIDGET (tree_view), tree_view->priv->drag_highlight_window);
5693       if (tree_view->priv->drag_column_window_state == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
5694         {
5695           cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
5696           cairo_paint (cr);
5697           gdk_cairo_set_source_rgba (cr, &color);
5698           cairo_rectangle (cr,
5699                            1, 1,
5700                            gdk_window_get_width (tree_view->priv->drag_highlight_window) - 2,
5701                            gdk_window_get_height (tree_view->priv->drag_highlight_window) - 2);
5702           cairo_stroke (cr);
5703         }
5704       else
5705         {
5706           gdk_cairo_set_source_rgba (cr, &color);
5707           cairo_paint (cr);
5708         }
5709       cairo_restore (cr);
5710     }
5711   else
5712     {
5713       gtk_render_background (context, cr,
5714                              0, 0,
5715                              gtk_widget_get_allocated_width (widget),
5716                              gtk_widget_get_allocated_height (widget));
5717     }
5718 
5719   gtk_style_context_save (context);
5720   gtk_style_context_remove_class (context, GTK_STYLE_CLASS_VIEW);
5721 
5722   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5723     {
5724       GList *list;
5725 
5726       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5727 	{
5728 	  GtkTreeViewColumn *column = list->data;
5729 
5730 	  if (column == tree_view->priv->drag_column)
5731 	    continue;
5732 
5733 	  if (gtk_tree_view_column_get_visible (column))
5734 	    {
5735 	      button = gtk_tree_view_column_get_button (column);
5736 	      gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5737 					    button, cr);
5738 	    }
5739 	}
5740     }
5741 
5742   if (tree_view->priv->drag_window &&
5743       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5744     {
5745       button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
5746       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5747                                     button, cr);
5748     }
5749 
5750   gtk_style_context_restore (context);
5751 
5752   return FALSE;
5753 }
5754 
5755 enum
5756 {
5757   DROP_HOME,
5758   DROP_RIGHT,
5759   DROP_LEFT,
5760   DROP_END
5761 };
5762 
5763 /* returns 0x1 when no column has been found -- yes it's hackish */
5764 static GtkTreeViewColumn *
gtk_tree_view_get_drop_column(GtkTreeView * tree_view,GtkTreeViewColumn * column,gint drop_position)5765 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5766 			       GtkTreeViewColumn *column,
5767 			       gint               drop_position)
5768 {
5769   GtkTreeViewColumn *left_column = NULL;
5770   GtkTreeViewColumn *cur_column = NULL;
5771   GList *tmp_list;
5772 
5773   if (!gtk_tree_view_column_get_reorderable (column))
5774     return (GtkTreeViewColumn *)0x1;
5775 
5776   switch (drop_position)
5777     {
5778       case DROP_HOME:
5779 	/* find first column where we can drop */
5780 	tmp_list = tree_view->priv->columns;
5781 	if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5782 	  return (GtkTreeViewColumn *)0x1;
5783 
5784 	while (tmp_list)
5785 	  {
5786 	    g_assert (tmp_list);
5787 
5788 	    cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5789 	    tmp_list = tmp_list->next;
5790 
5791 	    if (left_column &&
5792                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5793 	      continue;
5794 
5795 	    if (!tree_view->priv->column_drop_func)
5796 	      return left_column;
5797 
5798 	    if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5799 	      {
5800 		left_column = cur_column;
5801 		continue;
5802 	      }
5803 
5804 	    return left_column;
5805 	  }
5806 
5807 	if (!tree_view->priv->column_drop_func)
5808 	  return left_column;
5809 
5810 	if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5811 	  return left_column;
5812 	else
5813 	  return (GtkTreeViewColumn *)0x1;
5814 	break;
5815 
5816       case DROP_RIGHT:
5817 	/* find first column after column where we can drop */
5818 	tmp_list = tree_view->priv->columns;
5819 
5820 	for (; tmp_list; tmp_list = tmp_list->next)
5821 	  if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5822 	    break;
5823 
5824 	if (!tmp_list || !tmp_list->next)
5825 	  return (GtkTreeViewColumn *)0x1;
5826 
5827 	tmp_list = tmp_list->next;
5828 	left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5829 	tmp_list = tmp_list->next;
5830 
5831 	while (tmp_list)
5832 	  {
5833 	    g_assert (tmp_list);
5834 
5835 	    cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5836 	    tmp_list = tmp_list->next;
5837 
5838 	    if (left_column &&
5839                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5840 	      {
5841 		left_column = cur_column;
5842 		if (tmp_list)
5843 		  tmp_list = tmp_list->next;
5844 	        continue;
5845 	      }
5846 
5847 	    if (!tree_view->priv->column_drop_func)
5848 	      return left_column;
5849 
5850 	    if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5851 	      {
5852 		left_column = cur_column;
5853 		continue;
5854 	      }
5855 
5856 	    return left_column;
5857 	  }
5858 
5859 	if (!tree_view->priv->column_drop_func)
5860 	  return left_column;
5861 
5862 	if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5863 	  return left_column;
5864 	else
5865 	  return (GtkTreeViewColumn *)0x1;
5866 	break;
5867 
5868       case DROP_LEFT:
5869 	/* find first column before column where we can drop */
5870 	tmp_list = tree_view->priv->columns;
5871 
5872 	for (; tmp_list; tmp_list = tmp_list->next)
5873 	  if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5874 	    break;
5875 
5876 	if (!tmp_list || !tmp_list->prev)
5877 	  return (GtkTreeViewColumn *)0x1;
5878 
5879 	tmp_list = tmp_list->prev;
5880 	cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5881 	tmp_list = tmp_list->prev;
5882 
5883 	while (tmp_list)
5884 	  {
5885 	    g_assert (tmp_list);
5886 
5887 	    left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5888 
5889 	    if (left_column &&
5890                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5891 	      {
5892 		/*if (!tmp_list->prev)
5893 		  return (GtkTreeViewColumn *)0x1;
5894 		  */
5895 /*
5896 		cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5897 		tmp_list = tmp_list->prev->prev;
5898 		continue;*/
5899 
5900 		cur_column = left_column;
5901 		if (tmp_list)
5902 		  tmp_list = tmp_list->prev;
5903 		continue;
5904 	      }
5905 
5906 	    if (!tree_view->priv->column_drop_func)
5907 	      return left_column;
5908 
5909 	    if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5910 	      return left_column;
5911 
5912 	    cur_column = left_column;
5913 	    tmp_list = tmp_list->prev;
5914 	  }
5915 
5916 	if (!tree_view->priv->column_drop_func)
5917 	  return NULL;
5918 
5919 	if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5920 	  return NULL;
5921 	else
5922 	  return (GtkTreeViewColumn *)0x1;
5923 	break;
5924 
5925       case DROP_END:
5926 	/* same as DROP_HOME case, but doing it backwards */
5927 	tmp_list = g_list_last (tree_view->priv->columns);
5928 	cur_column = NULL;
5929 
5930 	if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5931 	  return (GtkTreeViewColumn *)0x1;
5932 
5933 	while (tmp_list)
5934 	  {
5935 	    g_assert (tmp_list);
5936 
5937 	    left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5938 
5939 	    if (left_column &&
5940                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5941 	      {
5942 		cur_column = left_column;
5943 		tmp_list = tmp_list->prev;
5944 	      }
5945 
5946 	    if (!tree_view->priv->column_drop_func)
5947 	      return left_column;
5948 
5949 	    if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5950 	      return left_column;
5951 
5952 	    cur_column = left_column;
5953 	    tmp_list = tmp_list->prev;
5954 	  }
5955 
5956 	if (!tree_view->priv->column_drop_func)
5957 	  return NULL;
5958 
5959 	if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5960 	  return NULL;
5961 	else
5962 	  return (GtkTreeViewColumn *)0x1;
5963 	break;
5964     }
5965 
5966   return (GtkTreeViewColumn *)0x1;
5967 }
5968 
5969 static gboolean
gtk_tree_view_search_key_cancels_search(guint keyval)5970 gtk_tree_view_search_key_cancels_search (guint keyval)
5971 {
5972   return keyval == GDK_KEY_Escape
5973       || keyval == GDK_KEY_Tab
5974       || keyval == GDK_KEY_KP_Tab
5975       || keyval == GDK_KEY_ISO_Left_Tab;
5976 }
5977 
5978 static gboolean
gtk_tree_view_key_press(GtkWidget * widget,GdkEventKey * event)5979 gtk_tree_view_key_press (GtkWidget   *widget,
5980 			 GdkEventKey *event)
5981 {
5982   GtkTreeView *tree_view = (GtkTreeView *) widget;
5983   GtkWidget   *button;
5984 
5985   if (tree_view->priv->rubber_band_status)
5986     {
5987       if (event->keyval == GDK_KEY_Escape)
5988 	gtk_tree_view_stop_rubber_band (tree_view);
5989 
5990       return TRUE;
5991     }
5992 
5993   if (tree_view->priv->in_column_drag)
5994     {
5995       if (event->keyval == GDK_KEY_Escape)
5996         gtk_gesture_set_state (GTK_GESTURE (tree_view->priv->column_drag_gesture),
5997                                GTK_EVENT_SEQUENCE_DENIED);
5998       return TRUE;
5999     }
6000 
6001   if (tree_view->priv->headers_visible)
6002     {
6003       GList *focus_column;
6004       gboolean rtl;
6005 
6006       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
6007 
6008       for (focus_column = tree_view->priv->columns;
6009            focus_column;
6010            focus_column = focus_column->next)
6011         {
6012           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
6013 
6014 	  button = gtk_tree_view_column_get_button (column);
6015           if (gtk_widget_has_focus (button))
6016             break;
6017         }
6018 
6019       if (focus_column &&
6020           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
6021           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
6022            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
6023         {
6024           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
6025           gint column_width;
6026 
6027           if (!gtk_tree_view_column_get_resizable (column))
6028             {
6029               gtk_widget_error_bell (widget);
6030               return TRUE;
6031             }
6032 
6033 	  column_width = gtk_tree_view_column_get_width (column);
6034 
6035           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
6036               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
6037             {
6038 	      column_width = MAX (column_width - 2, 0);
6039             }
6040           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
6041                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
6042             {
6043 	      column_width = column_width + 2;
6044             }
6045 
6046 	  gtk_tree_view_column_set_fixed_width (column, column_width);
6047 	  gtk_tree_view_column_set_expand (column, FALSE);
6048           return TRUE;
6049         }
6050 
6051       if (focus_column &&
6052           (event->state & GDK_MOD1_MASK) &&
6053           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
6054            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
6055            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
6056            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
6057         {
6058           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
6059 
6060           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
6061               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
6062             {
6063               GtkTreeViewColumn *col;
6064               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
6065               if (col != (GtkTreeViewColumn *)0x1)
6066                 gtk_tree_view_move_column_after (tree_view, column, col);
6067               else
6068                 gtk_widget_error_bell (widget);
6069             }
6070           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
6071                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
6072             {
6073               GtkTreeViewColumn *col;
6074               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
6075               if (col != (GtkTreeViewColumn *)0x1)
6076                 gtk_tree_view_move_column_after (tree_view, column, col);
6077               else
6078                 gtk_widget_error_bell (widget);
6079             }
6080           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
6081             {
6082               GtkTreeViewColumn *col;
6083               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
6084               if (col != (GtkTreeViewColumn *)0x1)
6085                 gtk_tree_view_move_column_after (tree_view, column, col);
6086               else
6087                 gtk_widget_error_bell (widget);
6088             }
6089           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
6090             {
6091               GtkTreeViewColumn *col;
6092               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
6093               if (col != (GtkTreeViewColumn *)0x1)
6094                 gtk_tree_view_move_column_after (tree_view, column, col);
6095               else
6096                 gtk_widget_error_bell (widget);
6097             }
6098 
6099           return TRUE;
6100         }
6101     }
6102 
6103   /* Chain up to the parent class.  It handles the keybindings. */
6104   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
6105     return TRUE;
6106 
6107   if (tree_view->priv->search_entry_avoid_unhandled_binding)
6108     {
6109       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
6110       return FALSE;
6111     }
6112 
6113   /* Initially, before the search window is visible, we pass the event to the
6114    * IM context of the search entry box. If it triggers a commit or a preedit,
6115    * we then show the search window without loosing tree view focus.
6116    * If the seach window is already visible, we forward the events to it,
6117    * keeping the focus on the tree view.
6118    */
6119   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
6120       && tree_view->priv->enable_search
6121       && !tree_view->priv->search_custom_entry_set
6122       && !gtk_tree_view_search_key_cancels_search (event->keyval))
6123     {
6124       GtkWidget *search_window;
6125 
6126       gtk_tree_view_ensure_interactive_directory (tree_view);
6127 
6128       search_window = tree_view->priv->search_window;
6129       if (!gtk_widget_is_visible (search_window))
6130         {
6131           GtkIMContext *im_context =
6132             _gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry));
6133 
6134           tree_view->priv->imcontext_changed = FALSE;
6135           gtk_im_context_filter_keypress (im_context, event);
6136 
6137           if (tree_view->priv->imcontext_changed)
6138             {
6139               GdkDevice *device;
6140 
6141               device = gdk_event_get_device ((GdkEvent *) event);
6142               if (gtk_tree_view_real_start_interactive_search (tree_view,
6143                                                                device,
6144                                                                FALSE))
6145                 {
6146                   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
6147                   return TRUE;
6148                 }
6149               else
6150                 {
6151                   gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
6152                   return FALSE;
6153                 }
6154             }
6155         }
6156       else
6157         {
6158           GdkEvent *new_event;
6159           gulong popup_menu_id;
6160 
6161           new_event = gdk_event_copy ((GdkEvent *) event);
6162           g_object_unref (((GdkEventKey *) new_event)->window);
6163           ((GdkEventKey *) new_event)->window =
6164             g_object_ref (gtk_widget_get_window (search_window));
6165           gtk_widget_realize (search_window);
6166 
6167           popup_menu_id = g_signal_connect (tree_view->priv->search_entry,
6168                                             "popup-menu", G_CALLBACK (gtk_true),
6169                                             NULL);
6170 
6171           /* Because we keep the focus on the treeview, we need to forward the
6172            * key events to the entry, when it is visible. */
6173           gtk_widget_event (search_window, new_event);
6174           gdk_event_free (new_event);
6175 
6176           g_signal_handler_disconnect (tree_view->priv->search_entry,
6177                                        popup_menu_id);
6178 
6179         }
6180     }
6181 
6182   return FALSE;
6183 }
6184 
6185 static gboolean
gtk_tree_view_key_release(GtkWidget * widget,GdkEventKey * event)6186 gtk_tree_view_key_release (GtkWidget   *widget,
6187 			   GdkEventKey *event)
6188 {
6189   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
6190 
6191   if (tree_view->priv->rubber_band_status)
6192     return TRUE;
6193 
6194   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
6195 }
6196 
6197 /* FIXME Is this function necessary? Can I get an enter_notify event
6198  * w/o either an expose event or a mouse motion event?
6199  */
6200 static gboolean
gtk_tree_view_enter_notify(GtkWidget * widget,GdkEventCrossing * event)6201 gtk_tree_view_enter_notify (GtkWidget        *widget,
6202 			    GdkEventCrossing *event)
6203 {
6204   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
6205   GtkRBTree *tree;
6206   GtkRBNode *node;
6207   gint new_y;
6208 
6209   /* Sanity check it */
6210   if (event->window != tree_view->priv->bin_window)
6211     return FALSE;
6212 
6213   if (tree_view->priv->tree == NULL)
6214     return FALSE;
6215 
6216   /* find the node internally */
6217   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
6218   if (new_y < 0)
6219     new_y = 0;
6220   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
6221 
6222   tree_view->priv->event_last_x = event->x;
6223   tree_view->priv->event_last_y = event->y;
6224 
6225   if ((tree_view->priv->button_pressed_node == NULL) ||
6226       (tree_view->priv->button_pressed_node == node))
6227     prelight_or_select (tree_view, tree, node, event->x, event->y);
6228 
6229   return TRUE;
6230 }
6231 
6232 static gboolean
gtk_tree_view_leave_notify(GtkWidget * widget,GdkEventCrossing * event)6233 gtk_tree_view_leave_notify (GtkWidget        *widget,
6234 			    GdkEventCrossing *event)
6235 {
6236   GtkTreeView *tree_view;
6237 
6238   tree_view = GTK_TREE_VIEW (widget);
6239 
6240   if (tree_view->priv->prelight_node)
6241     _gtk_tree_view_queue_draw_node (tree_view,
6242                                    tree_view->priv->prelight_tree,
6243                                    tree_view->priv->prelight_node,
6244                                    NULL);
6245 
6246   tree_view->priv->event_last_x = -10000;
6247   tree_view->priv->event_last_y = -10000;
6248 
6249   prelight_or_select (tree_view,
6250 		      NULL, NULL,
6251 		      -1000, -1000); /* coords not possibly over an arrow */
6252 
6253   return TRUE;
6254 }
6255 
6256 
6257 static gint
gtk_tree_view_focus_out(GtkWidget * widget,GdkEventFocus * event)6258 gtk_tree_view_focus_out (GtkWidget     *widget,
6259 			 GdkEventFocus *event)
6260 {
6261   GtkTreeView *tree_view;
6262 
6263   tree_view = GTK_TREE_VIEW (widget);
6264 
6265   gtk_widget_queue_draw (widget);
6266 
6267   /* destroy interactive search dialog */
6268   if (tree_view->priv->search_window)
6269     gtk_tree_view_search_window_hide (tree_view->priv->search_window, tree_view,
6270                                       gdk_event_get_device ((GdkEvent *) event));
6271   return FALSE;
6272 }
6273 
6274 
6275 /* Incremental Reflow
6276  */
6277 
6278 static void
gtk_tree_view_node_queue_redraw(GtkTreeView * tree_view,GtkRBTree * tree,GtkRBNode * node)6279 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
6280 				 GtkRBTree   *tree,
6281 				 GtkRBNode   *node)
6282 {
6283   GdkRectangle rect;
6284 
6285   rect.x = 0;
6286   rect.y =
6287     _gtk_rbtree_node_find_offset (tree, node)
6288     - gtk_adjustment_get_value (tree_view->priv->vadjustment);
6289   rect.width = gtk_widget_get_allocated_width (GTK_WIDGET (tree_view));
6290   rect.height = GTK_RBNODE_GET_HEIGHT (node);
6291 
6292   gdk_window_invalidate_rect (tree_view->priv->bin_window,
6293 			      &rect, TRUE);
6294 }
6295 
6296 static gboolean
node_is_visible(GtkTreeView * tree_view,GtkRBTree * tree,GtkRBNode * node)6297 node_is_visible (GtkTreeView *tree_view,
6298 		 GtkRBTree   *tree,
6299 		 GtkRBNode   *node)
6300 {
6301   int y;
6302   int height;
6303 
6304   y = _gtk_rbtree_node_find_offset (tree, node);
6305   height = gtk_tree_view_get_row_height (tree_view, node);
6306 
6307   if (y >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6308       y + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6309 	             + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6310     return TRUE;
6311 
6312   return FALSE;
6313 }
6314 
6315 static gint
get_separator_height(GtkTreeView * tree_view)6316 get_separator_height (GtkTreeView *tree_view)
6317 {
6318   GtkStyleContext *context;
6319   GtkCssStyle *style;
6320   gdouble d;
6321   gint min_size;
6322 
6323   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
6324   gtk_style_context_save (context);
6325   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
6326 
6327   style = gtk_style_context_lookup_style (context);
6328   d = _gtk_css_number_value_get
6329     (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_MIN_HEIGHT), 100);
6330 
6331   if (d < 1)
6332     min_size = ceil (d);
6333   else
6334     min_size = floor (d);
6335 
6336   gtk_style_context_restore (context);
6337 
6338   return min_size;
6339 }
6340 
6341 /* Returns TRUE if it updated the size
6342  */
6343 static gboolean
validate_row(GtkTreeView * tree_view,GtkRBTree * tree,GtkRBNode * node,GtkTreeIter * iter,GtkTreePath * path)6344 validate_row (GtkTreeView *tree_view,
6345 	      GtkRBTree   *tree,
6346 	      GtkRBNode   *node,
6347 	      GtkTreeIter *iter,
6348 	      GtkTreePath *path)
6349 {
6350   GtkTreeViewColumn *column;
6351   GtkStyleContext *context;
6352   GList *list, *first_column, *last_column;
6353   gint height = 0;
6354   gint horizontal_separator;
6355   gint vertical_separator;
6356   gint depth = gtk_tree_path_get_depth (path);
6357   gboolean retval = FALSE;
6358   gboolean is_separator = FALSE;
6359   gboolean draw_vgrid_lines, draw_hgrid_lines;
6360   gint grid_line_width;
6361   gint expander_size;
6362 
6363   /* double check the row needs validating */
6364   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
6365       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6366     return FALSE;
6367 
6368   is_separator = row_is_separator (tree_view, iter, NULL);
6369 
6370   gtk_widget_style_get (GTK_WIDGET (tree_view),
6371 			"horizontal-separator", &horizontal_separator,
6372 			"vertical-separator", &vertical_separator,
6373 			"grid-line-width", &grid_line_width,
6374 			NULL);
6375 
6376   draw_vgrid_lines =
6377     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
6378     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6379   draw_hgrid_lines =
6380     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
6381     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6382   expander_size = gtk_tree_view_get_expander_size (tree_view);
6383 
6384   for (last_column = g_list_last (tree_view->priv->columns);
6385        last_column &&
6386        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
6387        last_column = last_column->prev)
6388     ;
6389 
6390   for (first_column = g_list_first (tree_view->priv->columns);
6391        first_column &&
6392        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
6393        first_column = first_column->next)
6394     ;
6395 
6396   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
6397   gtk_style_context_save (context);
6398   gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
6399 
6400   for (list = tree_view->priv->columns; list; list = list->next)
6401     {
6402       gint padding = 0;
6403       gint original_width;
6404       gint new_width;
6405       gint row_height;
6406 
6407       column = list->data;
6408 
6409       if (!gtk_tree_view_column_get_visible (column))
6410 	continue;
6411 
6412       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) &&
6413 	  !_gtk_tree_view_column_cell_get_dirty (column))
6414 	continue;
6415 
6416       original_width = _gtk_tree_view_column_get_requested_width (column);
6417 
6418       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
6419 					       GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
6420 					       node->children?TRUE:FALSE);
6421       gtk_tree_view_column_cell_get_size (column,
6422 					  NULL, NULL, NULL,
6423 					  NULL, &row_height);
6424 
6425       if (is_separator)
6426         {
6427           height = get_separator_height (tree_view);
6428           /* gtk_tree_view_get_row_height() assumes separator nodes are > 0 */
6429           height = MAX (height, 1);
6430         }
6431       else
6432         {
6433           row_height += vertical_separator;
6434           height = MAX (height, row_height);
6435           height = MAX (height, expander_size);
6436         }
6437 
6438       if (gtk_tree_view_is_expander_column (tree_view, column))
6439         {
6440 	  padding += horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
6441 
6442 	  if (gtk_tree_view_draw_expanders (tree_view))
6443 	    padding += depth * expander_size;
6444 	}
6445       else
6446 	padding += horizontal_separator;
6447 
6448       if (draw_vgrid_lines)
6449         {
6450 	  if (list->data == first_column || list->data == last_column)
6451 	    padding += grid_line_width / 2.0;
6452 	  else
6453 	    padding += grid_line_width;
6454 	}
6455 
6456       /* Update the padding for the column */
6457       _gtk_tree_view_column_push_padding (column, padding);
6458       new_width = _gtk_tree_view_column_get_requested_width (column);
6459 
6460       if (new_width > original_width)
6461 	retval = TRUE;
6462     }
6463 
6464   gtk_style_context_restore (context);
6465 
6466   if (draw_hgrid_lines)
6467     height += grid_line_width;
6468 
6469   if (height != GTK_RBNODE_GET_HEIGHT (node))
6470     {
6471       retval = TRUE;
6472       _gtk_rbtree_node_set_height (tree, node, height);
6473     }
6474   _gtk_rbtree_node_mark_valid (tree, node);
6475   tree_view->priv->post_validation_flag = TRUE;
6476 
6477   return retval;
6478 }
6479 
6480 
6481 static void
validate_visible_area(GtkTreeView * tree_view)6482 validate_visible_area (GtkTreeView *tree_view)
6483 {
6484   GtkAllocation allocation;
6485   GtkTreePath *path = NULL;
6486   GtkTreePath *above_path = NULL;
6487   GtkTreeIter iter;
6488   GtkRBTree *tree = NULL;
6489   GtkRBNode *node = NULL;
6490   gboolean need_redraw = FALSE;
6491   gboolean size_changed = FALSE;
6492   gint total_height;
6493   gint area_above = 0;
6494   gint area_below = 0;
6495 
6496   if (tree_view->priv->tree == NULL)
6497     return;
6498 
6499   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
6500       tree_view->priv->scroll_to_path == NULL)
6501     return;
6502 
6503   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6504   total_height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
6505 
6506   if (total_height == 0)
6507     return;
6508 
6509   /* First, we check to see if we need to scroll anywhere
6510    */
6511   if (tree_view->priv->scroll_to_path)
6512     {
6513       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
6514       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
6515 	{
6516           /* we are going to scroll, and will update dy */
6517 	  gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6518 	  if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6519 	      GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6520 	    {
6521 	      _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6522 	      if (validate_row (tree_view, tree, node, &iter, path))
6523 		size_changed = TRUE;
6524 	    }
6525 
6526 	  if (tree_view->priv->scroll_to_use_align)
6527 	    {
6528 	      gint height = gtk_tree_view_get_row_height (tree_view, node);
6529 	      area_above = (total_height - height) *
6530 		tree_view->priv->scroll_to_row_align;
6531 	      area_below = total_height - area_above - height;
6532 	      area_above = MAX (area_above, 0);
6533 	      area_below = MAX (area_below, 0);
6534 	    }
6535 	  else
6536 	    {
6537 	      /* two cases:
6538 	       * 1) row not visible
6539 	       * 2) row visible
6540 	       */
6541 	      gint dy;
6542 	      gint height = gtk_tree_view_get_row_height (tree_view, node);
6543 
6544 	      dy = _gtk_rbtree_node_find_offset (tree, node);
6545 
6546 	      if (dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6547 		  dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6548 		                  + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6549 	        {
6550 		  /* row visible: keep the row at the same position */
6551 		  area_above = dy - gtk_adjustment_get_value (tree_view->priv->vadjustment);
6552 		  area_below = (gtk_adjustment_get_value (tree_view->priv->vadjustment) +
6553 		                gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6554 		               - dy - height;
6555 		}
6556 	      else
6557 	        {
6558 		  /* row not visible */
6559 		  if (dy >= 0
6560 		      && dy + height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6561 		    {
6562 		      /* row at the beginning -- fixed */
6563 		      area_above = dy;
6564 		      area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment)
6565 				   - area_above - height;
6566 		    }
6567 		  else if (dy >= (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6568 			          gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6569 		    {
6570 		      /* row at the end -- fixed */
6571 		      area_above = dy - (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6572 			           gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6573                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) -
6574                                    area_above - height;
6575 
6576                       if (area_below < 0)
6577                         {
6578 			  area_above = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) - height;
6579                           area_below = 0;
6580                         }
6581 		    }
6582 		  else
6583 		    {
6584 		      /* row somewhere in the middle, bring it to the top
6585 		       * of the view
6586 		       */
6587 		      area_above = 0;
6588 		      area_below = total_height - height;
6589 		    }
6590 		}
6591 	    }
6592 	}
6593       else
6594 	/* the scroll to isn't valid; ignore it.
6595 	 */
6596 	{
6597 	  if (tree_view->priv->scroll_to_path && !path)
6598 	    {
6599 	      gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6600 	      tree_view->priv->scroll_to_path = NULL;
6601 	    }
6602 	  if (path)
6603 	    gtk_tree_path_free (path);
6604 	  path = NULL;
6605 	}
6606     }
6607 
6608   /* We didn't have a scroll_to set, so we just handle things normally
6609    */
6610   if (path == NULL)
6611     {
6612       gint offset;
6613 
6614       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6615 					TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
6616 					&tree, &node);
6617       if (node == NULL)
6618 	{
6619 	  /* In this case, nothing has been validated */
6620 	  path = gtk_tree_path_new_first ();
6621 	  _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6622 	}
6623       else
6624 	{
6625 	  path = _gtk_tree_path_new_from_rbtree (tree, node);
6626 	  total_height += offset;
6627 	}
6628 
6629       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6630 
6631       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6632 	  GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6633 	{
6634 	  _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6635 	  if (validate_row (tree_view, tree, node, &iter, path))
6636 	    size_changed = TRUE;
6637 	}
6638       area_above = 0;
6639       area_below = total_height - gtk_tree_view_get_row_height (tree_view, node);
6640     }
6641 
6642   above_path = gtk_tree_path_copy (path);
6643 
6644   /* if we do not validate any row above the new top_row, we will make sure
6645    * that the row immediately above top_row has been validated. (if we do not
6646    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6647    * when invalidated that row's height will be zero. and this will mess up
6648    * scrolling).
6649    */
6650   if (area_above == 0)
6651     {
6652       GtkRBTree *tmptree;
6653       GtkRBNode *tmpnode;
6654 
6655       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6656       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6657 
6658       if (tmpnode)
6659         {
6660 	  GtkTreePath *tmppath;
6661 	  GtkTreeIter tmpiter;
6662 
6663 	  tmppath = _gtk_tree_path_new_from_rbtree (tmptree, tmpnode);
6664 	  gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6665 
6666 	  if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6667 	      GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6668 	    {
6669 	      _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6670 	      if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6671 		size_changed = TRUE;
6672 	    }
6673 
6674 	  gtk_tree_path_free (tmppath);
6675 	}
6676     }
6677 
6678   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6679    * backwards is much slower then forward, as there is no iter_prev function.
6680    * We go forwards first in case we run out of tree.  Then we go backwards to
6681    * fill out the top.
6682    */
6683   while (node && area_below > 0)
6684     {
6685       if (node->children)
6686 	{
6687 	  GtkTreeIter parent = iter;
6688 	  gboolean has_child;
6689 
6690 	  tree = node->children;
6691           node = _gtk_rbtree_first (tree);
6692 
6693 	  has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6694 						    &iter,
6695 						    &parent);
6696 	  TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6697 	  gtk_tree_path_down (path);
6698 	}
6699       else
6700 	{
6701 	  gboolean done = FALSE;
6702 	  do
6703 	    {
6704 	      node = _gtk_rbtree_next (tree, node);
6705 	      if (node != NULL)
6706 		{
6707 		  gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6708 		  done = TRUE;
6709 		  gtk_tree_path_next (path);
6710 
6711 		  /* Sanity Check! */
6712 		  TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6713 		}
6714 	      else
6715 		{
6716 		  GtkTreeIter parent_iter = iter;
6717 		  gboolean has_parent;
6718 
6719 		  node = tree->parent_node;
6720 		  tree = tree->parent_tree;
6721 		  if (tree == NULL)
6722 		    break;
6723 		  has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6724 							   &iter,
6725 							   &parent_iter);
6726 		  gtk_tree_path_up (path);
6727 
6728 		  /* Sanity check */
6729 		  TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6730 		}
6731 	    }
6732 	  while (!done);
6733 	}
6734 
6735       if (!node)
6736         break;
6737 
6738       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6739 	  GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6740 	{
6741 	  _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6742 	  if (validate_row (tree_view, tree, node, &iter, path))
6743 	      size_changed = TRUE;
6744 	}
6745 
6746       area_below -= gtk_tree_view_get_row_height (tree_view, node);
6747     }
6748   gtk_tree_path_free (path);
6749 
6750   /* If we ran out of tree, and have extra area_below left, we need to add it
6751    * to area_above */
6752   if (area_below > 0)
6753     area_above += area_below;
6754 
6755   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6756 
6757   /* We walk backwards */
6758   while (area_above > 0)
6759     {
6760       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6761 
6762       /* Always find the new path in the tree.  We cannot just assume
6763        * a gtk_tree_path_prev() is enough here, as there might be children
6764        * in between this node and the previous sibling node.  If this
6765        * appears to be a performance hotspot in profiles, we can look into
6766        * intrigate logic for keeping path, node and iter in sync like
6767        * we do for forward walks.  (Which will be hard because of the lacking
6768        * iter_prev).
6769        */
6770 
6771       if (node == NULL)
6772 	break;
6773 
6774       gtk_tree_path_free (above_path);
6775       above_path = _gtk_tree_path_new_from_rbtree (tree, node);
6776 
6777       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6778 
6779       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6780 	  GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6781 	{
6782 	  _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6783 	  if (validate_row (tree_view, tree, node, &iter, above_path))
6784 	    size_changed = TRUE;
6785 	}
6786       area_above -= gtk_tree_view_get_row_height (tree_view, node);
6787     }
6788 
6789   /* if we scrolled to a path, we need to set the dy here,
6790    * and sync the top row accordingly
6791    */
6792   if (tree_view->priv->scroll_to_path)
6793     {
6794       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6795       gtk_tree_view_top_row_to_dy (tree_view);
6796 
6797       need_redraw = TRUE;
6798     }
6799   else if (gtk_tree_view_get_height (tree_view) <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6800     {
6801       /* when we are not scrolling, we should never set dy to something
6802        * else than zero. we update top_row to be in sync with dy = 0.
6803        */
6804       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6805       gtk_tree_view_dy_to_top_row (tree_view);
6806     }
6807   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > gtk_tree_view_get_height (tree_view))
6808     {
6809       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), gtk_tree_view_get_height (tree_view) - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6810       gtk_tree_view_dy_to_top_row (tree_view);
6811     }
6812   else
6813     gtk_tree_view_top_row_to_dy (tree_view);
6814 
6815   /* update width/height and queue a resize */
6816   if (size_changed)
6817     {
6818       GtkRequisition requisition;
6819 
6820       /* We temporarily guess a size, under the assumption that it will be the
6821        * same when we get our next size_allocate.  If we don't do this, we'll be
6822        * in an inconsistent state if we call top_row_to_dy. */
6823 
6824       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6825                                      &requisition, NULL);
6826       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6827                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6828       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6829                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6830       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6831     }
6832 
6833   if (tree_view->priv->scroll_to_path)
6834     {
6835       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6836       tree_view->priv->scroll_to_path = NULL;
6837     }
6838 
6839   if (above_path)
6840     gtk_tree_path_free (above_path);
6841 
6842   if (tree_view->priv->scroll_to_column)
6843     {
6844       tree_view->priv->scroll_to_column = NULL;
6845     }
6846   if (need_redraw)
6847     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6848 }
6849 
6850 static void
initialize_fixed_height_mode(GtkTreeView * tree_view)6851 initialize_fixed_height_mode (GtkTreeView *tree_view)
6852 {
6853   if (!tree_view->priv->tree)
6854     return;
6855 
6856   if (tree_view->priv->fixed_height < 0)
6857     {
6858       GtkTreeIter iter;
6859       GtkTreePath *path;
6860 
6861       GtkRBTree *tree = NULL;
6862       GtkRBNode *node = NULL;
6863 
6864       tree = tree_view->priv->tree;
6865       node = tree->root;
6866 
6867       path = _gtk_tree_path_new_from_rbtree (tree, node);
6868       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6869 
6870       validate_row (tree_view, tree, node, &iter, path);
6871 
6872       gtk_tree_path_free (path);
6873 
6874       tree_view->priv->fixed_height = gtk_tree_view_get_row_height (tree_view, node);
6875     }
6876 
6877    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6878                                  tree_view->priv->fixed_height, TRUE);
6879 }
6880 
6881 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6882  * the left-most uninvalidated node.  We then try walking right, validating
6883  * nodes.  Once we find a valid node, we repeat the previous process of finding
6884  * the first invalid node.
6885  */
6886 
6887 static gboolean
do_validate_rows(GtkTreeView * tree_view,gboolean queue_resize)6888 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6889 {
6890   static gboolean prevent_recursion_hack = FALSE;
6891 
6892   GtkRBTree *tree = NULL;
6893   GtkRBNode *node = NULL;
6894   gboolean validated_area = FALSE;
6895   gint retval = TRUE;
6896   GtkTreePath *path = NULL;
6897   GtkTreeIter iter;
6898   GTimer *timer;
6899   gint i = 0;
6900 
6901   gint y = -1;
6902   gint prev_height = -1;
6903   gboolean fixed_height = TRUE;
6904 
6905   g_assert (tree_view);
6906 
6907   /* prevent infinite recursion via get_preferred_width() */
6908   if (prevent_recursion_hack)
6909     return FALSE;
6910 
6911   if (tree_view->priv->tree == NULL)
6912       return FALSE;
6913 
6914   if (tree_view->priv->fixed_height_mode)
6915     {
6916       if (tree_view->priv->fixed_height < 0)
6917         initialize_fixed_height_mode (tree_view);
6918 
6919       return FALSE;
6920     }
6921 
6922   timer = g_timer_new ();
6923   g_timer_start (timer);
6924 
6925   do
6926     {
6927       gboolean changed = FALSE;
6928 
6929       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6930 	{
6931 	  retval = FALSE;
6932 	  goto done;
6933 	}
6934 
6935       if (path != NULL)
6936 	{
6937 	  node = _gtk_rbtree_next (tree, node);
6938 	  if (node != NULL)
6939 	    {
6940 	      TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6941 	      gtk_tree_path_next (path);
6942 	    }
6943 	  else
6944 	    {
6945 	      gtk_tree_path_free (path);
6946 	      path = NULL;
6947 	    }
6948 	}
6949 
6950       if (path == NULL)
6951 	{
6952 	  tree = tree_view->priv->tree;
6953 	  node = tree_view->priv->tree->root;
6954 
6955 	  g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6956 
6957 	  do
6958 	    {
6959 	      if (!_gtk_rbtree_is_nil (node->left) &&
6960 		  GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6961 		{
6962 		  node = node->left;
6963 		}
6964               else if (!_gtk_rbtree_is_nil (node->right) &&
6965 		       GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6966 		{
6967 		  node = node->right;
6968 		}
6969 	      else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6970 		       GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6971 		{
6972 		  break;
6973 		}
6974 	      else if (node->children != NULL)
6975 		{
6976 		  tree = node->children;
6977 		  node = tree->root;
6978 		}
6979 	      else
6980 		/* RBTree corruption!  All bad */
6981 		g_assert_not_reached ();
6982 	    }
6983 	  while (TRUE);
6984 	  path = _gtk_tree_path_new_from_rbtree (tree, node);
6985 	  gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6986 	}
6987 
6988       changed = validate_row (tree_view, tree, node, &iter, path);
6989       validated_area = changed || validated_area;
6990 
6991       if (changed)
6992         {
6993           gint offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
6994 
6995           if (y == -1 || y > offset)
6996             y = offset;
6997         }
6998 
6999       if (!tree_view->priv->fixed_height_check)
7000         {
7001 	  gint height;
7002 
7003 	  height = gtk_tree_view_get_row_height (tree_view, node);
7004 	  if (prev_height < 0)
7005 	    prev_height = height;
7006 	  else if (prev_height != height)
7007 	    fixed_height = FALSE;
7008 	}
7009 
7010       i++;
7011     }
7012   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
7013 
7014   if (!tree_view->priv->fixed_height_check)
7015    {
7016      if (fixed_height)
7017        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
7018 
7019      tree_view->priv->fixed_height_check = 1;
7020    }
7021 
7022  done:
7023   if (validated_area)
7024     {
7025       GtkRequisition requisition;
7026       gint dummy;
7027 
7028       /* We temporarily guess a size, under the assumption that it will be the
7029        * same when we get our next size_allocate.  If we don't do this, we'll be
7030        * in an inconsistent state when we call top_row_to_dy. */
7031 
7032       /* FIXME: This is called from size_request, for some reason it is not infinitely
7033        * recursing, we cannot call gtk_widget_get_preferred_size() here because that's
7034        * not allowed (from inside ->get_preferred_width/height() implementations, one
7035        * should call the vfuncs directly). However what is desired here is the full
7036        * size including any margins and limited by any alignment (i.e. after
7037        * GtkWidget:adjust_size_request() is called).
7038        *
7039        * Currently bypassing this but the real solution is to not update the scroll adjustments
7040        * untill we've recieved an allocation (never update scroll adjustments from size-requests).
7041        */
7042       prevent_recursion_hack = TRUE;
7043       gtk_tree_view_get_preferred_width (GTK_WIDGET (tree_view), &requisition.width, &dummy);
7044       gtk_tree_view_get_preferred_height (GTK_WIDGET (tree_view), &requisition.height, &dummy);
7045       prevent_recursion_hack = FALSE;
7046 
7047       /* If rows above the current position have changed height, this has
7048        * affected the current view and thus needs a redraw.
7049        */
7050       if (y != -1 && y < gtk_adjustment_get_value (tree_view->priv->vadjustment))
7051         gtk_widget_queue_draw (GTK_WIDGET (tree_view));
7052 
7053       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
7054                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
7055       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
7056                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
7057 
7058       if (queue_resize)
7059         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
7060     }
7061 
7062   if (path) gtk_tree_path_free (path);
7063   g_timer_destroy (timer);
7064 
7065   if (!retval && gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
7066     update_prelight (tree_view,
7067                      tree_view->priv->event_last_x,
7068                      tree_view->priv->event_last_y);
7069 
7070   return retval;
7071 }
7072 
7073 static void
disable_adjustment_animation(GtkTreeView * tree_view)7074 disable_adjustment_animation (GtkTreeView *tree_view)
7075 {
7076   gtk_adjustment_enable_animation (tree_view->priv->vadjustment,
7077                                    NULL,
7078                                    gtk_adjustment_get_animation_duration (tree_view->priv->vadjustment));
7079 }
7080 
7081 static void
maybe_reenable_adjustment_animation(GtkTreeView * tree_view)7082 maybe_reenable_adjustment_animation (GtkTreeView *tree_view)
7083 {
7084   if (tree_view->priv->presize_handler_tick_cb != 0 ||
7085       tree_view->priv->validate_rows_timer != 0)
7086     return;
7087 
7088   gtk_adjustment_enable_animation (tree_view->priv->vadjustment,
7089                                    gtk_widget_get_frame_clock (GTK_WIDGET (tree_view)),
7090                                    gtk_adjustment_get_animation_duration (tree_view->priv->vadjustment));
7091 }
7092 
7093 static gboolean
do_presize_handler(GtkTreeView * tree_view)7094 do_presize_handler (GtkTreeView *tree_view)
7095 {
7096   if (tree_view->priv->mark_rows_col_dirty)
7097    {
7098       if (tree_view->priv->tree)
7099 	_gtk_rbtree_column_invalid (tree_view->priv->tree);
7100       tree_view->priv->mark_rows_col_dirty = FALSE;
7101     }
7102   validate_visible_area (tree_view);
7103   if (tree_view->priv->presize_handler_tick_cb != 0)
7104     {
7105       gtk_widget_remove_tick_callback (GTK_WIDGET (tree_view), tree_view->priv->presize_handler_tick_cb);
7106       tree_view->priv->presize_handler_tick_cb = 0;
7107     }
7108 
7109   if (tree_view->priv->fixed_height_mode)
7110     {
7111       GtkRequisition requisition;
7112 
7113       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
7114                                      &requisition, NULL);
7115 
7116       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
7117                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
7118       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
7119                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
7120       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7121     }
7122 
7123   maybe_reenable_adjustment_animation (tree_view);
7124 
7125   return FALSE;
7126 }
7127 
7128 static gboolean
presize_handler_callback(GtkWidget * widget,GdkFrameClock * clock,gpointer unused)7129 presize_handler_callback (GtkWidget     *widget,
7130                           GdkFrameClock *clock,
7131                           gpointer       unused)
7132 {
7133   do_presize_handler (GTK_TREE_VIEW (widget));
7134 
7135   return G_SOURCE_REMOVE;
7136 }
7137 
7138 static gboolean
validate_rows(GtkTreeView * tree_view)7139 validate_rows (GtkTreeView *tree_view)
7140 {
7141   gboolean retval;
7142 
7143   if (tree_view->priv->presize_handler_tick_cb)
7144     {
7145       do_presize_handler (tree_view);
7146       return G_SOURCE_CONTINUE;
7147     }
7148 
7149   retval = do_validate_rows (tree_view, TRUE);
7150 
7151   if (! retval && tree_view->priv->validate_rows_timer)
7152     {
7153       g_source_remove (tree_view->priv->validate_rows_timer);
7154       tree_view->priv->validate_rows_timer = 0;
7155       maybe_reenable_adjustment_animation (tree_view);
7156     }
7157 
7158   return retval;
7159 }
7160 
7161 static void
install_presize_handler(GtkTreeView * tree_view)7162 install_presize_handler (GtkTreeView *tree_view)
7163 {
7164   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
7165     return;
7166 
7167   disable_adjustment_animation (tree_view);
7168 
7169   if (! tree_view->priv->presize_handler_tick_cb)
7170     {
7171       tree_view->priv->presize_handler_tick_cb =
7172 	gtk_widget_add_tick_callback (GTK_WIDGET (tree_view), presize_handler_callback, NULL, NULL);
7173     }
7174   if (! tree_view->priv->validate_rows_timer)
7175     {
7176       tree_view->priv->validate_rows_timer =
7177 	gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows, tree_view, NULL);
7178       g_source_set_name_by_id (tree_view->priv->validate_rows_timer, "[gtk+] validate_rows");
7179     }
7180 }
7181 
7182 static gboolean
scroll_sync_handler(GtkTreeView * tree_view)7183 scroll_sync_handler (GtkTreeView *tree_view)
7184 {
7185   if (gtk_tree_view_get_height (tree_view) <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
7186     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
7187   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
7188     gtk_tree_view_top_row_to_dy (tree_view);
7189   else
7190     gtk_tree_view_dy_to_top_row (tree_view);
7191 
7192   tree_view->priv->scroll_sync_timer = 0;
7193 
7194   return FALSE;
7195 }
7196 
7197 static void
install_scroll_sync_handler(GtkTreeView * tree_view)7198 install_scroll_sync_handler (GtkTreeView *tree_view)
7199 {
7200   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
7201     return;
7202 
7203   if (!tree_view->priv->scroll_sync_timer)
7204     {
7205       tree_view->priv->scroll_sync_timer =
7206 	gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
7207       g_source_set_name_by_id (tree_view->priv->scroll_sync_timer, "[gtk+] scroll_sync_handler");
7208     }
7209 }
7210 
7211 static void
gtk_tree_view_set_top_row(GtkTreeView * tree_view,GtkTreePath * path,gint offset)7212 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
7213 			   GtkTreePath *path,
7214 			   gint         offset)
7215 {
7216   gtk_tree_row_reference_free (tree_view->priv->top_row);
7217 
7218   if (!path)
7219     {
7220       tree_view->priv->top_row = NULL;
7221       tree_view->priv->top_row_dy = 0;
7222     }
7223   else
7224     {
7225       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
7226       tree_view->priv->top_row_dy = offset;
7227     }
7228 }
7229 
7230 /* Always call this iff dy is in the visible range.  If the tree is empty, then
7231  * it’s set to be NULL, and top_row_dy is 0;
7232  */
7233 static void
gtk_tree_view_dy_to_top_row(GtkTreeView * tree_view)7234 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
7235 {
7236   gint offset;
7237   GtkTreePath *path;
7238   GtkRBTree *tree;
7239   GtkRBNode *node;
7240 
7241   if (tree_view->priv->tree == NULL)
7242     {
7243       gtk_tree_view_set_top_row (tree_view, NULL, 0);
7244     }
7245   else
7246     {
7247       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
7248 					tree_view->priv->dy,
7249 					&tree, &node);
7250 
7251       if (tree == NULL)
7252         {
7253 	  gtk_tree_view_set_top_row (tree_view, NULL, 0);
7254 	}
7255       else
7256         {
7257 	  path = _gtk_tree_path_new_from_rbtree (tree, node);
7258 	  gtk_tree_view_set_top_row (tree_view, path, offset);
7259 	  gtk_tree_path_free (path);
7260 	}
7261     }
7262 }
7263 
7264 static void
gtk_tree_view_top_row_to_dy(GtkTreeView * tree_view)7265 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
7266 {
7267   GtkTreePath *path;
7268   GtkRBTree *tree;
7269   GtkRBNode *node;
7270   int new_dy;
7271 
7272   /* Avoid recursive calls */
7273   if (tree_view->priv->in_top_row_to_dy)
7274     return;
7275 
7276   if (tree_view->priv->top_row)
7277     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
7278   else
7279     path = NULL;
7280 
7281   if (!path)
7282     tree = NULL;
7283   else
7284     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
7285 
7286   if (path)
7287     gtk_tree_path_free (path);
7288 
7289   if (tree == NULL)
7290     {
7291       /* keep dy and set new toprow */
7292       gtk_tree_row_reference_free (tree_view->priv->top_row);
7293       tree_view->priv->top_row = NULL;
7294       tree_view->priv->top_row_dy = 0;
7295       /* DO NOT install the idle handler */
7296       gtk_tree_view_dy_to_top_row (tree_view);
7297       return;
7298     }
7299 
7300   if (gtk_tree_view_get_row_height (tree_view, node)
7301       < tree_view->priv->top_row_dy)
7302     {
7303       /* new top row -- do NOT install the idle handler */
7304       gtk_tree_view_dy_to_top_row (tree_view);
7305       return;
7306     }
7307 
7308   new_dy = _gtk_rbtree_node_find_offset (tree, node);
7309   new_dy += tree_view->priv->top_row_dy;
7310 
7311   if (new_dy + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > gtk_tree_view_get_height (tree_view))
7312     new_dy = gtk_tree_view_get_height (tree_view) - gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
7313 
7314   new_dy = MAX (0, new_dy);
7315 
7316   tree_view->priv->in_top_row_to_dy = TRUE;
7317   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
7318   tree_view->priv->in_top_row_to_dy = FALSE;
7319 }
7320 
7321 
7322 void
_gtk_tree_view_install_mark_rows_col_dirty(GtkTreeView * tree_view,gboolean install_handler)7323 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view,
7324 					    gboolean     install_handler)
7325 {
7326   tree_view->priv->mark_rows_col_dirty = TRUE;
7327 
7328   if (install_handler)
7329     install_presize_handler (tree_view);
7330 }
7331 
7332 /*
7333  * This function works synchronously (due to the while (validate_rows...)
7334  * loop).
7335  *
7336  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
7337  * here. You now need to check that yourself.
7338  */
7339 void
_gtk_tree_view_column_autosize(GtkTreeView * tree_view,GtkTreeViewColumn * column)7340 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
7341 			        GtkTreeViewColumn *column)
7342 {
7343   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7344   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
7345 
7346   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
7347 
7348   do_presize_handler (tree_view);
7349   while (validate_rows (tree_view));
7350 
7351   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7352 }
7353 
7354 /* Drag-and-drop */
7355 
7356 static void
set_source_row(GdkDragContext * context,GtkTreeModel * model,GtkTreePath * source_row)7357 set_source_row (GdkDragContext *context,
7358                 GtkTreeModel   *model,
7359                 GtkTreePath    *source_row)
7360 {
7361   g_object_set_data_full (G_OBJECT (context),
7362                           I_("gtk-tree-view-source-row"),
7363                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
7364                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
7365 }
7366 
7367 static GtkTreePath*
get_source_row(GdkDragContext * context)7368 get_source_row (GdkDragContext *context)
7369 {
7370   GtkTreeRowReference *ref =
7371     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
7372 
7373   if (ref)
7374     return gtk_tree_row_reference_get_path (ref);
7375   else
7376     return NULL;
7377 }
7378 
7379 typedef struct
7380 {
7381   GtkTreeRowReference *dest_row;
7382   guint                path_down_mode   : 1;
7383   guint                empty_view_drop  : 1;
7384   guint                drop_append_mode : 1;
7385 }
7386 DestRow;
7387 
7388 static void
dest_row_free(gpointer data)7389 dest_row_free (gpointer data)
7390 {
7391   DestRow *dr = (DestRow *)data;
7392 
7393   gtk_tree_row_reference_free (dr->dest_row);
7394   g_slice_free (DestRow, dr);
7395 }
7396 
7397 static void
set_dest_row(GdkDragContext * context,GtkTreeModel * model,GtkTreePath * dest_row,gboolean path_down_mode,gboolean empty_view_drop,gboolean drop_append_mode)7398 set_dest_row (GdkDragContext *context,
7399               GtkTreeModel   *model,
7400               GtkTreePath    *dest_row,
7401               gboolean        path_down_mode,
7402               gboolean        empty_view_drop,
7403               gboolean        drop_append_mode)
7404 {
7405   DestRow *dr;
7406 
7407   if (!dest_row)
7408     {
7409       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7410                               NULL, NULL);
7411       return;
7412     }
7413 
7414   dr = g_slice_new (DestRow);
7415 
7416   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
7417   dr->path_down_mode = path_down_mode != FALSE;
7418   dr->empty_view_drop = empty_view_drop != FALSE;
7419   dr->drop_append_mode = drop_append_mode != FALSE;
7420 
7421   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7422                           dr, (GDestroyNotify) dest_row_free);
7423 }
7424 
7425 static GtkTreePath*
get_dest_row(GdkDragContext * context,gboolean * path_down_mode)7426 get_dest_row (GdkDragContext *context,
7427               gboolean       *path_down_mode)
7428 {
7429   DestRow *dr =
7430     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
7431 
7432   if (dr)
7433     {
7434       GtkTreePath *path = NULL;
7435 
7436       if (path_down_mode)
7437         *path_down_mode = dr->path_down_mode;
7438 
7439       if (dr->dest_row)
7440         path = gtk_tree_row_reference_get_path (dr->dest_row);
7441       else if (dr->empty_view_drop)
7442         path = gtk_tree_path_new_from_indices (0, -1);
7443       else
7444         path = NULL;
7445 
7446       if (path && dr->drop_append_mode)
7447         gtk_tree_path_next (path);
7448 
7449       return path;
7450     }
7451   else
7452     return NULL;
7453 }
7454 
7455 /* Get/set whether drag_motion requested the drag data and
7456  * drag_data_received should thus not actually insert the data,
7457  * since the data doesn’t result from a drop.
7458  */
7459 static void
set_status_pending(GdkDragContext * context,GdkDragAction suggested_action)7460 set_status_pending (GdkDragContext *context,
7461                     GdkDragAction   suggested_action)
7462 {
7463   g_object_set_data (G_OBJECT (context),
7464                      I_("gtk-tree-view-status-pending"),
7465                      GINT_TO_POINTER (suggested_action));
7466 }
7467 
7468 static GdkDragAction
get_status_pending(GdkDragContext * context)7469 get_status_pending (GdkDragContext *context)
7470 {
7471   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
7472                                              "gtk-tree-view-status-pending"));
7473 }
7474 
7475 static TreeViewDragInfo*
get_info(GtkTreeView * tree_view)7476 get_info (GtkTreeView *tree_view)
7477 {
7478   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
7479 }
7480 
7481 static void
destroy_info(TreeViewDragInfo * di)7482 destroy_info (TreeViewDragInfo *di)
7483 {
7484   g_slice_free (TreeViewDragInfo, di);
7485 }
7486 
7487 static TreeViewDragInfo*
ensure_info(GtkTreeView * tree_view)7488 ensure_info (GtkTreeView *tree_view)
7489 {
7490   TreeViewDragInfo *di;
7491 
7492   di = get_info (tree_view);
7493 
7494   if (di == NULL)
7495     {
7496       di = g_slice_new0 (TreeViewDragInfo);
7497 
7498       g_object_set_data_full (G_OBJECT (tree_view),
7499                               I_("gtk-tree-view-drag-info"),
7500                               di,
7501                               (GDestroyNotify) destroy_info);
7502     }
7503 
7504   return di;
7505 }
7506 
7507 static void
remove_info(GtkTreeView * tree_view)7508 remove_info (GtkTreeView *tree_view)
7509 {
7510   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
7511 }
7512 
7513 #if 0
7514 static gint
7515 drag_scan_timeout (gpointer data)
7516 {
7517   GtkTreeView *tree_view;
7518   gint x, y;
7519   GdkModifierType state;
7520   GtkTreePath *path = NULL;
7521   GtkTreeViewColumn *column = NULL;
7522   GdkRectangle visible_rect;
7523   GdkSeat *seat;
7524 
7525   gdk_threads_enter ();
7526 
7527   tree_view = GTK_TREE_VIEW (data);
7528 
7529   seat = gdk_display_get_default_seat (gtk_widget_get_display (GTK_WIDGET (tree_view)));
7530   gdk_window_get_device_position (tree_view->priv->bin_window,
7531                                   gdk_seat_get_pointer (seat),
7532                                   &x, &y, &state);
7533 
7534   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
7535 
7536   /* See if we are near the edge. */
7537   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
7538       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
7539       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
7540       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
7541     {
7542       gtk_tree_view_get_path_at_pos (tree_view,
7543                                      tree_view->priv->bin_window,
7544                                      x, y,
7545                                      &path,
7546                                      &column,
7547                                      NULL,
7548                                      NULL);
7549 
7550       if (path != NULL)
7551         {
7552           gtk_tree_view_scroll_to_cell (tree_view,
7553                                         path,
7554                                         column,
7555 					TRUE,
7556                                         0.5, 0.5);
7557 
7558           gtk_tree_path_free (path);
7559         }
7560     }
7561 
7562   gdk_threads_leave ();
7563 
7564   return TRUE;
7565 }
7566 #endif /* 0 */
7567 
7568 static void
add_scroll_timeout(GtkTreeView * tree_view)7569 add_scroll_timeout (GtkTreeView *tree_view)
7570 {
7571   if (tree_view->priv->scroll_timeout == 0)
7572     {
7573       tree_view->priv->scroll_timeout =
7574 	gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
7575       g_source_set_name_by_id (tree_view->priv->scroll_timeout, "[gtk+] scroll_row_timeout");
7576     }
7577 }
7578 
7579 static void
remove_scroll_timeout(GtkTreeView * tree_view)7580 remove_scroll_timeout (GtkTreeView *tree_view)
7581 {
7582   if (tree_view->priv->scroll_timeout != 0)
7583     {
7584       g_source_remove (tree_view->priv->scroll_timeout);
7585       tree_view->priv->scroll_timeout = 0;
7586     }
7587 }
7588 
7589 static gboolean
check_model_dnd(GtkTreeModel * model,GType required_iface,const gchar * signal)7590 check_model_dnd (GtkTreeModel *model,
7591                  GType         required_iface,
7592                  const gchar  *signal)
7593 {
7594   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
7595     {
7596       g_warning ("You must override the default '%s' handler "
7597                  "on GtkTreeView when using models that don't support "
7598                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
7599                  "is to connect to '%s' and call "
7600                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
7601                  "the default handler from running. Look at the source code "
7602                  "for the default handler in gtktreeview.c to get an idea what "
7603                  "your handler should do. (gtktreeview.c is in the GTK source "
7604                  "code.) If you're using GTK from a language other than C, "
7605                  "there may be a more natural way to override default handlers, e.g. via derivation.",
7606                  signal, g_type_name (required_iface), signal);
7607       return FALSE;
7608     }
7609   else
7610     return TRUE;
7611 }
7612 
7613 static void
remove_open_timeout(GtkTreeView * tree_view)7614 remove_open_timeout (GtkTreeView *tree_view)
7615 {
7616   if (tree_view->priv->open_dest_timeout != 0)
7617     {
7618       g_source_remove (tree_view->priv->open_dest_timeout);
7619       tree_view->priv->open_dest_timeout = 0;
7620     }
7621 }
7622 
7623 
7624 static gint
open_row_timeout(gpointer data)7625 open_row_timeout (gpointer data)
7626 {
7627   GtkTreeView *tree_view = data;
7628   GtkTreePath *dest_path = NULL;
7629   GtkTreeViewDropPosition pos;
7630   gboolean result = FALSE;
7631 
7632   gtk_tree_view_get_drag_dest_row (tree_view,
7633                                    &dest_path,
7634                                    &pos);
7635 
7636   if (dest_path &&
7637       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7638        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7639     {
7640       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
7641       tree_view->priv->open_dest_timeout = 0;
7642 
7643       gtk_tree_path_free (dest_path);
7644     }
7645   else
7646     {
7647       if (dest_path)
7648         gtk_tree_path_free (dest_path);
7649 
7650       result = TRUE;
7651     }
7652 
7653   return result;
7654 }
7655 
7656 static gboolean
scroll_row_timeout(gpointer data)7657 scroll_row_timeout (gpointer data)
7658 {
7659   GtkTreeView *tree_view = data;
7660 
7661   gtk_tree_view_vertical_autoscroll (tree_view);
7662 
7663   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
7664     gtk_tree_view_update_rubber_band (tree_view);
7665 
7666   return TRUE;
7667 }
7668 
7669 /* Returns TRUE if event should not be propagated to parent widgets */
7670 static gboolean
set_destination_row(GtkTreeView * tree_view,GdkDragContext * context,gint x,gint y,GdkDragAction * suggested_action,GdkAtom * target)7671 set_destination_row (GtkTreeView    *tree_view,
7672                      GdkDragContext *context,
7673                      /* coordinates relative to the widget */
7674                      gint            x,
7675                      gint            y,
7676                      GdkDragAction  *suggested_action,
7677                      GdkAtom        *target)
7678 {
7679   GtkTreePath *path = NULL;
7680   GtkTreeViewDropPosition pos;
7681   GtkTreeViewDropPosition old_pos;
7682   TreeViewDragInfo *di;
7683   GtkWidget *widget;
7684   GtkTreePath *old_dest_path = NULL;
7685   gboolean can_drop = FALSE;
7686 
7687   *suggested_action = 0;
7688   *target = GDK_NONE;
7689 
7690   widget = GTK_WIDGET (tree_view);
7691 
7692   di = get_info (tree_view);
7693 
7694   if (di == NULL || y - gtk_tree_view_get_effective_header_height (tree_view) < 0)
7695     {
7696       /* someone unset us as a drag dest, note that if
7697        * we return FALSE drag_leave isn't called
7698        */
7699 
7700       gtk_tree_view_set_drag_dest_row (tree_view,
7701                                        NULL,
7702                                        GTK_TREE_VIEW_DROP_BEFORE);
7703 
7704       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7705       remove_open_timeout (GTK_TREE_VIEW (widget));
7706 
7707       return FALSE; /* no longer a drop site */
7708     }
7709 
7710   *target = gtk_drag_dest_find_target (widget, context,
7711                                        gtk_drag_dest_get_target_list (widget));
7712   if (*target == GDK_NONE)
7713     {
7714       return FALSE;
7715     }
7716 
7717   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7718                                           x, y,
7719                                           &path,
7720                                           &pos))
7721     {
7722       gint n_children;
7723       GtkTreeModel *model;
7724 
7725       remove_open_timeout (tree_view);
7726 
7727       /* the row got dropped on empty space, let's setup a special case
7728        */
7729 
7730       if (path)
7731 	gtk_tree_path_free (path);
7732 
7733       model = gtk_tree_view_get_model (tree_view);
7734 
7735       n_children = gtk_tree_model_iter_n_children (model, NULL);
7736       if (n_children)
7737         {
7738           pos = GTK_TREE_VIEW_DROP_AFTER;
7739           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7740         }
7741       else
7742         {
7743           pos = GTK_TREE_VIEW_DROP_BEFORE;
7744           path = gtk_tree_path_new_from_indices (0, -1);
7745         }
7746 
7747       can_drop = TRUE;
7748 
7749       goto out;
7750     }
7751 
7752   g_assert (path);
7753 
7754   /* If we left the current row's "open" zone, unset the timeout for
7755    * opening the row
7756    */
7757   gtk_tree_view_get_drag_dest_row (tree_view,
7758                                    &old_dest_path,
7759                                    &old_pos);
7760 
7761   if (old_dest_path &&
7762       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7763        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7764          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7765     remove_open_timeout (tree_view);
7766 
7767   if (old_dest_path)
7768     gtk_tree_path_free (old_dest_path);
7769 
7770   if (TRUE /* FIXME if the location droppable predicate */)
7771     {
7772       can_drop = TRUE;
7773     }
7774 
7775 out:
7776   if (can_drop)
7777     {
7778       GtkWidget *source_widget;
7779 
7780       *suggested_action = gdk_drag_context_get_suggested_action (context);
7781       source_widget = gtk_drag_get_source_widget (context);
7782 
7783       if (source_widget == widget)
7784         {
7785           /* Default to MOVE, unless the user has
7786            * pressed ctrl or shift to affect available actions
7787            */
7788           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
7789             *suggested_action = GDK_ACTION_MOVE;
7790         }
7791 
7792       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7793                                        path, pos);
7794     }
7795   else
7796     {
7797       /* can't drop here */
7798       remove_open_timeout (tree_view);
7799 
7800       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7801                                        NULL,
7802                                        GTK_TREE_VIEW_DROP_BEFORE);
7803     }
7804 
7805   if (path)
7806     gtk_tree_path_free (path);
7807 
7808   return TRUE;
7809 }
7810 
7811 static GtkTreePath*
get_logical_dest_row(GtkTreeView * tree_view,gboolean * path_down_mode,gboolean * drop_append_mode)7812 get_logical_dest_row (GtkTreeView *tree_view,
7813                       gboolean    *path_down_mode,
7814                       gboolean    *drop_append_mode)
7815 {
7816   /* adjust path to point to the row the drop goes in front of */
7817   GtkTreePath *path = NULL;
7818   GtkTreeViewDropPosition pos;
7819 
7820   g_return_val_if_fail (path_down_mode != NULL, NULL);
7821   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7822 
7823   *path_down_mode = FALSE;
7824   *drop_append_mode = 0;
7825 
7826   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7827 
7828   if (path == NULL)
7829     return NULL;
7830 
7831   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7832     ; /* do nothing */
7833   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7834            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7835     *path_down_mode = TRUE;
7836   else
7837     {
7838       GtkTreeIter iter;
7839       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7840 
7841       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7842 
7843       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7844           !gtk_tree_model_iter_next (model, &iter))
7845         *drop_append_mode = 1;
7846       else
7847         {
7848           *drop_append_mode = 0;
7849           gtk_tree_path_next (path);
7850         }
7851     }
7852 
7853   return path;
7854 }
7855 
7856 static gboolean
gtk_tree_view_maybe_begin_dragging_row(GtkTreeView * tree_view)7857 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view)
7858 {
7859   GtkWidget *widget = GTK_WIDGET (tree_view);
7860   gdouble start_x, start_y, offset_x, offset_y;
7861   GdkEventSequence *sequence;
7862   const GdkEvent *event;
7863   GdkDragContext *context;
7864   TreeViewDragInfo *di;
7865   GtkTreePath *path = NULL;
7866   gint button;
7867   GtkTreeModel *model;
7868   gboolean retval = FALSE;
7869   gint bin_x, bin_y;
7870 
7871   di = get_info (tree_view);
7872 
7873   if (di == NULL || !di->source_set)
7874     goto out;
7875 
7876   if (!gtk_gesture_is_recognized (tree_view->priv->drag_gesture))
7877     goto out;
7878 
7879   gtk_gesture_drag_get_start_point (GTK_GESTURE_DRAG (tree_view->priv->drag_gesture),
7880                                     &start_x, &start_y);
7881   gtk_gesture_drag_get_offset (GTK_GESTURE_DRAG (tree_view->priv->drag_gesture),
7882                                &offset_x, &offset_y);
7883 
7884   if (!gtk_drag_check_threshold (widget, 0, 0, offset_x, offset_y))
7885     goto out;
7886 
7887   model = gtk_tree_view_get_model (tree_view);
7888 
7889   if (model == NULL)
7890     goto out;
7891 
7892   button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (tree_view->priv->drag_gesture));
7893 
7894   /* Deny the multipress gesture */
7895   gtk_gesture_set_state (GTK_GESTURE (tree_view->priv->multipress_gesture),
7896                          GTK_EVENT_SEQUENCE_DENIED);
7897 
7898   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, start_x, start_y,
7899                                                      &bin_x, &bin_y);
7900   gtk_tree_view_get_path_at_pos (tree_view, bin_x, bin_y, &path,
7901                                  NULL, NULL, NULL);
7902 
7903   if (path == NULL)
7904     goto out;
7905 
7906   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7907       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7908 					   path))
7909     goto out;
7910 
7911   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7912     goto out;
7913 
7914   retval = TRUE;
7915 
7916   /* Now we can begin the drag */
7917   gtk_gesture_set_state (GTK_GESTURE (tree_view->priv->drag_gesture),
7918                          GTK_EVENT_SEQUENCE_CLAIMED);
7919   sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (tree_view->priv->drag_gesture));
7920   event = gtk_gesture_get_last_event (GTK_GESTURE (tree_view->priv->drag_gesture), sequence);
7921 
7922   context = gtk_drag_begin_with_coordinates (widget,
7923                                              gtk_drag_source_get_target_list (widget),
7924                                              di->source_actions,
7925                                              button,
7926                                              (GdkEvent*)event,
7927                                              start_x, start_y);
7928 
7929   set_source_row (context, model, path);
7930 
7931  out:
7932   if (path)
7933     gtk_tree_path_free (path);
7934 
7935   return retval;
7936 }
7937 
7938 
7939 static void
gtk_tree_view_drag_begin(GtkWidget * widget,GdkDragContext * context)7940 gtk_tree_view_drag_begin (GtkWidget      *widget,
7941                           GdkDragContext *context)
7942 {
7943   GtkTreeView *tree_view;
7944   GtkTreePath *path = NULL;
7945   gint cell_x, cell_y;
7946   cairo_surface_t *row_pix;
7947   TreeViewDragInfo *di;
7948   double sx, sy;
7949 
7950   tree_view = GTK_TREE_VIEW (widget);
7951 
7952   /* if the user uses a custom DND source impl, we don't set the icon here */
7953   di = get_info (tree_view);
7954 
7955   if (di == NULL || !di->source_set)
7956     return;
7957 
7958   gtk_tree_view_get_path_at_pos (tree_view,
7959                                  tree_view->priv->press_start_x,
7960                                  tree_view->priv->press_start_y,
7961                                  &path,
7962                                  NULL,
7963                                  &cell_x,
7964                                  &cell_y);
7965 
7966   /* If path is NULL, there's nothing we can drag.  For now, we silently
7967    * bail out.  Actually, dragging should not be possible from an empty
7968    * tree view, but there's no way we can cancel that from here.
7969    * Automatically unsetting the tree view as drag source for empty models
7970    * is something that would likely break other people's code ...
7971    */
7972   if (!path)
7973     return;
7974 
7975   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7976                                                 path);
7977   cairo_surface_get_device_scale (row_pix, &sx, &sy);
7978   cairo_surface_set_device_offset (row_pix,
7979                                    /* the + 1 is for the black border in the icon */
7980                                    - (tree_view->priv->press_start_x + 1) * sx,
7981                                    - (cell_y + 1) * sy);
7982 
7983   gtk_drag_set_icon_surface (context, row_pix);
7984 
7985   cairo_surface_destroy (row_pix);
7986   gtk_tree_path_free (path);
7987 }
7988 
7989 static void
gtk_tree_view_drag_end(GtkWidget * widget,GdkDragContext * context)7990 gtk_tree_view_drag_end (GtkWidget      *widget,
7991                         GdkDragContext *context)
7992 {
7993   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
7994 
7995   tree_view->priv->event_last_x = -10000;
7996   tree_view->priv->event_last_y = -10000;
7997 }
7998 
7999 /* Default signal implementations for the drag signals */
8000 static void
gtk_tree_view_drag_data_get(GtkWidget * widget,GdkDragContext * context,GtkSelectionData * selection_data,guint info,guint time)8001 gtk_tree_view_drag_data_get (GtkWidget        *widget,
8002                              GdkDragContext   *context,
8003                              GtkSelectionData *selection_data,
8004                              guint             info,
8005                              guint             time)
8006 {
8007   GtkTreeView *tree_view;
8008   GtkTreeModel *model;
8009   TreeViewDragInfo *di;
8010   GtkTreePath *source_row;
8011 
8012   tree_view = GTK_TREE_VIEW (widget);
8013 
8014   model = gtk_tree_view_get_model (tree_view);
8015 
8016   if (model == NULL)
8017     return;
8018 
8019   di = get_info (GTK_TREE_VIEW (widget));
8020 
8021   if (di == NULL)
8022     return;
8023 
8024   source_row = get_source_row (context);
8025 
8026   if (source_row == NULL)
8027     return;
8028 
8029   /* We can implement the GTK_TREE_MODEL_ROW target generically for
8030    * any model; for DragSource models there are some other targets
8031    * we also support.
8032    */
8033 
8034   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
8035       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
8036                                           source_row,
8037                                           selection_data))
8038     goto done;
8039 
8040   /* If drag_data_get does nothing, try providing row data. */
8041   if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
8042     {
8043       gtk_tree_set_row_drag_data (selection_data,
8044 				  model,
8045 				  source_row);
8046     }
8047 
8048  done:
8049   gtk_tree_path_free (source_row);
8050 }
8051 
8052 
8053 static void
gtk_tree_view_drag_data_delete(GtkWidget * widget,GdkDragContext * context)8054 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
8055                                 GdkDragContext *context)
8056 {
8057   TreeViewDragInfo *di;
8058   GtkTreeModel *model;
8059   GtkTreeView *tree_view;
8060   GtkTreePath *source_row;
8061 
8062   tree_view = GTK_TREE_VIEW (widget);
8063   model = gtk_tree_view_get_model (tree_view);
8064 
8065   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
8066     return;
8067 
8068   di = get_info (tree_view);
8069 
8070   if (di == NULL)
8071     return;
8072 
8073   source_row = get_source_row (context);
8074 
8075   if (source_row == NULL)
8076     return;
8077 
8078   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
8079                                          source_row);
8080 
8081   gtk_tree_path_free (source_row);
8082 
8083   set_source_row (context, NULL, NULL);
8084 }
8085 
8086 static void
gtk_tree_view_drag_leave(GtkWidget * widget,GdkDragContext * context,guint time)8087 gtk_tree_view_drag_leave (GtkWidget      *widget,
8088                           GdkDragContext *context,
8089                           guint             time)
8090 {
8091   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8092 
8093   /* unset any highlight row */
8094   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
8095                                    NULL,
8096                                    GTK_TREE_VIEW_DROP_BEFORE);
8097 
8098   remove_scroll_timeout (GTK_TREE_VIEW (widget));
8099   remove_open_timeout (GTK_TREE_VIEW (widget));
8100 
8101   tree_view->priv->event_last_x = -10000;
8102   tree_view->priv->event_last_y = -10000;
8103 }
8104 
8105 
8106 static gboolean
gtk_tree_view_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time)8107 gtk_tree_view_drag_motion (GtkWidget        *widget,
8108                            GdkDragContext   *context,
8109 			   /* coordinates relative to the widget */
8110                            gint              x,
8111                            gint              y,
8112                            guint             time)
8113 {
8114   gboolean empty;
8115   GtkTreePath *path = NULL;
8116   GtkTreeViewDropPosition pos;
8117   GtkTreeView *tree_view;
8118   GdkDragAction suggested_action = 0;
8119   GdkAtom target;
8120 
8121   tree_view = GTK_TREE_VIEW (widget);
8122 
8123   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
8124     return FALSE;
8125 
8126   tree_view->priv->event_last_x = x;
8127   tree_view->priv->event_last_y = y;
8128 
8129   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
8130 
8131   /* we only know this *after* set_desination_row */
8132   empty = tree_view->priv->empty_view_drop;
8133 
8134   if (path == NULL && !empty)
8135     {
8136       /* Can't drop here. */
8137       gdk_drag_status (context, 0, time);
8138     }
8139   else
8140     {
8141       if (tree_view->priv->open_dest_timeout == 0 &&
8142           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
8143            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
8144         {
8145           tree_view->priv->open_dest_timeout =
8146             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
8147           g_source_set_name_by_id (tree_view->priv->open_dest_timeout, "[gtk+] open_row_timeout");
8148         }
8149       else
8150         {
8151 	  add_scroll_timeout (tree_view);
8152 	}
8153 
8154       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
8155         {
8156           /* Request data so we can use the source row when
8157            * determining whether to accept the drop
8158            */
8159           set_status_pending (context, suggested_action);
8160           gtk_drag_get_data (widget, context, target, time);
8161         }
8162       else
8163         {
8164           set_status_pending (context, 0);
8165           gdk_drag_status (context, suggested_action, time);
8166         }
8167     }
8168 
8169   if (path)
8170     gtk_tree_path_free (path);
8171 
8172   return TRUE;
8173 }
8174 
8175 
8176 static gboolean
gtk_tree_view_drag_drop(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time)8177 gtk_tree_view_drag_drop (GtkWidget        *widget,
8178                          GdkDragContext   *context,
8179 			 /* coordinates relative to the widget */
8180                          gint              x,
8181                          gint              y,
8182                          guint             time)
8183 {
8184   GtkTreeView *tree_view;
8185   GtkTreePath *path;
8186   GdkDragAction suggested_action = 0;
8187   GdkAtom target = GDK_NONE;
8188   TreeViewDragInfo *di;
8189   GtkTreeModel *model;
8190   gboolean path_down_mode;
8191   gboolean drop_append_mode;
8192 
8193   tree_view = GTK_TREE_VIEW (widget);
8194 
8195   model = gtk_tree_view_get_model (tree_view);
8196 
8197   remove_scroll_timeout (GTK_TREE_VIEW (widget));
8198   remove_open_timeout (GTK_TREE_VIEW (widget));
8199 
8200   di = get_info (tree_view);
8201 
8202   if (di == NULL)
8203     return FALSE;
8204 
8205   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
8206     return FALSE;
8207 
8208   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
8209     return FALSE;
8210 
8211   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
8212 
8213   if (target != GDK_NONE && path != NULL)
8214     {
8215       /* in case a motion had requested drag data, change things so we
8216        * treat drag data receives as a drop.
8217        */
8218       set_status_pending (context, 0);
8219       set_dest_row (context, model, path,
8220                     path_down_mode, tree_view->priv->empty_view_drop,
8221                     drop_append_mode);
8222     }
8223 
8224   if (path)
8225     gtk_tree_path_free (path);
8226 
8227   /* Unset this thing */
8228   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
8229                                    NULL,
8230                                    GTK_TREE_VIEW_DROP_BEFORE);
8231 
8232   if (target != GDK_NONE)
8233     {
8234       gtk_drag_get_data (widget, context, target, time);
8235       return TRUE;
8236     }
8237   else
8238     return FALSE;
8239 }
8240 
8241 static void
gtk_tree_view_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * selection_data,guint info,guint time)8242 gtk_tree_view_drag_data_received (GtkWidget        *widget,
8243                                   GdkDragContext   *context,
8244 				  /* coordinates relative to the widget */
8245                                   gint              x,
8246                                   gint              y,
8247                                   GtkSelectionData *selection_data,
8248                                   guint             info,
8249                                   guint             time)
8250 {
8251   GtkTreePath *path;
8252   TreeViewDragInfo *di;
8253   gboolean accepted = FALSE;
8254   GtkTreeModel *model;
8255   GtkTreeView *tree_view;
8256   GtkTreePath *dest_row;
8257   GdkDragAction suggested_action;
8258   gboolean path_down_mode;
8259   gboolean drop_append_mode;
8260 
8261   tree_view = GTK_TREE_VIEW (widget);
8262 
8263   model = gtk_tree_view_get_model (tree_view);
8264 
8265   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
8266     return;
8267 
8268   di = get_info (tree_view);
8269 
8270   if (di == NULL)
8271     return;
8272 
8273   suggested_action = get_status_pending (context);
8274 
8275   if (suggested_action)
8276     {
8277       /* We are getting this data due to a request in drag_motion,
8278        * rather than due to a request in drag_drop, so we are just
8279        * supposed to call drag_status, not actually paste in the
8280        * data.
8281        */
8282       path = get_logical_dest_row (tree_view, &path_down_mode,
8283                                    &drop_append_mode);
8284 
8285       if (path == NULL)
8286         suggested_action = 0;
8287       else if (path_down_mode)
8288         gtk_tree_path_down (path);
8289 
8290       if (suggested_action)
8291         {
8292 	  if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
8293 						     path,
8294 						     selection_data))
8295             {
8296               if (path_down_mode)
8297                 {
8298                   path_down_mode = FALSE;
8299                   gtk_tree_path_up (path);
8300 
8301                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
8302                                                              path,
8303                                                              selection_data))
8304                     suggested_action = 0;
8305                 }
8306               else
8307 	        suggested_action = 0;
8308             }
8309         }
8310 
8311       gdk_drag_status (context, suggested_action, time);
8312 
8313       if (path)
8314         gtk_tree_path_free (path);
8315 
8316       /* If you can't drop, remove user drop indicator until the next motion */
8317       if (suggested_action == 0)
8318         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
8319                                          NULL,
8320                                          GTK_TREE_VIEW_DROP_BEFORE);
8321 
8322       return;
8323     }
8324 
8325   dest_row = get_dest_row (context, &path_down_mode);
8326 
8327   if (dest_row == NULL)
8328     return;
8329 
8330   if (gtk_selection_data_get_length (selection_data) >= 0)
8331     {
8332       if (path_down_mode)
8333         {
8334           gtk_tree_path_down (dest_row);
8335           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
8336                                                      dest_row, selection_data))
8337             gtk_tree_path_up (dest_row);
8338         }
8339     }
8340 
8341   if (gtk_selection_data_get_length (selection_data) >= 0)
8342     {
8343       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
8344                                                  dest_row,
8345                                                  selection_data))
8346         accepted = TRUE;
8347     }
8348 
8349   gtk_drag_finish (context,
8350                    accepted,
8351                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
8352                    time);
8353 
8354   if (gtk_tree_path_get_depth (dest_row) == 1 &&
8355       gtk_tree_path_get_indices (dest_row)[0] == 0 &&
8356       gtk_tree_model_iter_n_children (tree_view->priv->model, NULL) != 0)
8357     {
8358       /* special special case drag to "0", scroll to first item */
8359       if (!tree_view->priv->scroll_to_path)
8360         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
8361     }
8362 
8363   gtk_tree_path_free (dest_row);
8364 
8365   /* drop dest_row */
8366   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
8367 }
8368 
8369 
8370 
8371 /* GtkContainer Methods
8372  */
8373 
8374 
8375 static void
gtk_tree_view_remove(GtkContainer * container,GtkWidget * widget)8376 gtk_tree_view_remove (GtkContainer *container,
8377 		      GtkWidget    *widget)
8378 {
8379   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8380   GtkTreeViewChild *child = NULL;
8381   GList *tmp_list;
8382 
8383   tmp_list = tree_view->priv->children;
8384   while (tmp_list)
8385     {
8386       child = tmp_list->data;
8387       if (child->widget == widget)
8388 	{
8389 	  gtk_widget_unparent (widget);
8390 
8391 	  tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
8392 	  g_list_free_1 (tmp_list);
8393 	  g_slice_free (GtkTreeViewChild, child);
8394 	  return;
8395 	}
8396 
8397       tmp_list = tmp_list->next;
8398     }
8399 
8400   tmp_list = tree_view->priv->columns;
8401 
8402   while (tmp_list)
8403     {
8404       GtkTreeViewColumn *column;
8405       GtkWidget         *button;
8406 
8407       column = tmp_list->data;
8408       button = gtk_tree_view_column_get_button (column);
8409 
8410       if (button == widget)
8411 	{
8412 	  gtk_widget_unparent (widget);
8413 	  return;
8414 	}
8415       tmp_list = tmp_list->next;
8416     }
8417 }
8418 
8419 static void
gtk_tree_view_forall(GtkContainer * container,gboolean include_internals,GtkCallback callback,gpointer callback_data)8420 gtk_tree_view_forall (GtkContainer *container,
8421 		      gboolean      include_internals,
8422 		      GtkCallback   callback,
8423 		      gpointer      callback_data)
8424 {
8425   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8426   GtkTreeViewChild *child = NULL;
8427   GtkTreeViewColumn *column;
8428   GtkWidget *button;
8429   GList *tmp_list;
8430 
8431   tmp_list = tree_view->priv->children;
8432   while (tmp_list)
8433     {
8434       child = tmp_list->data;
8435       tmp_list = tmp_list->next;
8436 
8437       (* callback) (child->widget, callback_data);
8438     }
8439   if (include_internals == FALSE)
8440     return;
8441 
8442   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8443     {
8444       column = tmp_list->data;
8445       button = gtk_tree_view_column_get_button (column);
8446 
8447       if (button)
8448 	(* callback) (button, callback_data);
8449     }
8450 }
8451 
8452 /* Returns TRUE is any of the columns contains a cell that can-focus.
8453  * If this is not the case, a column-spanning focus rectangle will be
8454  * drawn.
8455  */
8456 static gboolean
gtk_tree_view_has_can_focus_cell(GtkTreeView * tree_view)8457 gtk_tree_view_has_can_focus_cell (GtkTreeView *tree_view)
8458 {
8459   GList *list;
8460 
8461   for (list = tree_view->priv->columns; list; list = list->next)
8462     {
8463       GtkTreeViewColumn *column = list->data;
8464 
8465       if (!gtk_tree_view_column_get_visible (column))
8466 	continue;
8467       if (gtk_cell_area_is_activatable (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column))))
8468 	return TRUE;
8469     }
8470 
8471   return FALSE;
8472 }
8473 
8474 static void
column_sizing_notify(GObject * object,GParamSpec * pspec,gpointer data)8475 column_sizing_notify (GObject    *object,
8476                       GParamSpec *pspec,
8477                       gpointer    data)
8478 {
8479   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
8480 
8481   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
8482     /* disable fixed height mode */
8483     g_object_set (data, "fixed-height-mode", FALSE, NULL);
8484 }
8485 
8486 /**
8487  * gtk_tree_view_set_fixed_height_mode:
8488  * @tree_view: a #GtkTreeView
8489  * @enable: %TRUE to enable fixed height mode
8490  *
8491  * Enables or disables the fixed height mode of @tree_view.
8492  * Fixed height mode speeds up #GtkTreeView by assuming that all
8493  * rows have the same height.
8494  * Only enable this option if all rows are the same height and all
8495  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
8496  *
8497  * Since: 2.6
8498  **/
8499 void
gtk_tree_view_set_fixed_height_mode(GtkTreeView * tree_view,gboolean enable)8500 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
8501                                      gboolean     enable)
8502 {
8503   GList *l;
8504 
8505   enable = enable != FALSE;
8506 
8507   if (enable == tree_view->priv->fixed_height_mode)
8508     return;
8509 
8510   if (!enable)
8511     {
8512       tree_view->priv->fixed_height_mode = 0;
8513       tree_view->priv->fixed_height = -1;
8514     }
8515   else
8516     {
8517       /* make sure all columns are of type FIXED */
8518       for (l = tree_view->priv->columns; l; l = l->next)
8519 	{
8520 	  GtkTreeViewColumn *c = l->data;
8521 
8522 	  g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
8523 	}
8524 
8525       /* yes, we really have to do this is in a separate loop */
8526       for (l = tree_view->priv->columns; l; l = l->next)
8527 	g_signal_connect (l->data, "notify::sizing",
8528 			  G_CALLBACK (column_sizing_notify), tree_view);
8529 
8530       tree_view->priv->fixed_height_mode = 1;
8531       tree_view->priv->fixed_height = -1;
8532     }
8533 
8534   /* force a revalidation */
8535   install_presize_handler (tree_view);
8536 
8537   g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_FIXED_HEIGHT_MODE]);
8538 }
8539 
8540 /**
8541  * gtk_tree_view_get_fixed_height_mode:
8542  * @tree_view: a #GtkTreeView
8543  *
8544  * Returns whether fixed height mode is turned on for @tree_view.
8545  *
8546  * Returns: %TRUE if @tree_view is in fixed height mode
8547  *
8548  * Since: 2.6
8549  **/
8550 gboolean
gtk_tree_view_get_fixed_height_mode(GtkTreeView * tree_view)8551 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
8552 {
8553   return tree_view->priv->fixed_height_mode;
8554 }
8555 
8556 /* Returns TRUE if the focus is within the headers, after the focus operation is
8557  * done
8558  */
8559 static gboolean
gtk_tree_view_header_focus(GtkTreeView * tree_view,GtkDirectionType dir,gboolean clamp_column_visible)8560 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
8561 			    GtkDirectionType  dir,
8562 			    gboolean          clamp_column_visible)
8563 {
8564   GtkTreeViewColumn *column;
8565   GtkWidget *button;
8566   GtkWidget *focus_child;
8567   GList *last_column, *first_column;
8568   GList *tmp_list;
8569   gboolean rtl;
8570 
8571   if (! tree_view->priv->headers_visible)
8572     return FALSE;
8573 
8574   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
8575 
8576   first_column = tree_view->priv->columns;
8577   while (first_column)
8578     {
8579       column = GTK_TREE_VIEW_COLUMN (first_column->data);
8580       button = gtk_tree_view_column_get_button (column);
8581 
8582       if (gtk_widget_get_can_focus (button) &&
8583           gtk_tree_view_column_get_visible (column) &&
8584           (gtk_tree_view_column_get_clickable (column) ||
8585            gtk_tree_view_column_get_reorderable (column)))
8586 	break;
8587       first_column = first_column->next;
8588     }
8589 
8590   /* No headers are visible, or are focusable.  We can't focus in or out.
8591    */
8592   if (first_column == NULL)
8593     return FALSE;
8594 
8595   last_column = g_list_last (tree_view->priv->columns);
8596   while (last_column)
8597     {
8598       column = GTK_TREE_VIEW_COLUMN (last_column->data);
8599       button = gtk_tree_view_column_get_button (column);
8600 
8601       if (gtk_widget_get_can_focus (button) &&
8602           gtk_tree_view_column_get_visible (column) &&
8603           (gtk_tree_view_column_get_clickable (column) ||
8604            gtk_tree_view_column_get_reorderable (column)))
8605 	break;
8606       last_column = last_column->prev;
8607     }
8608 
8609 
8610   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8611 
8612   switch (dir)
8613     {
8614     case GTK_DIR_TAB_BACKWARD:
8615     case GTK_DIR_TAB_FORWARD:
8616     case GTK_DIR_UP:
8617     case GTK_DIR_DOWN:
8618       if (focus_child == NULL)
8619 	{
8620 	  if (tree_view->priv->focus_column != NULL)
8621 	    button = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8622 	  else
8623 	    button = NULL;
8624 
8625 	  if (button && gtk_widget_get_can_focus (button))
8626 	    focus_child = button;
8627 	  else
8628 	    focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8629 
8630 	  gtk_widget_grab_focus (focus_child);
8631 	  break;
8632 	}
8633       return FALSE;
8634 
8635     case GTK_DIR_LEFT:
8636     case GTK_DIR_RIGHT:
8637       if (focus_child == NULL)
8638 	{
8639 	  if (tree_view->priv->focus_column != NULL)
8640 	    focus_child = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8641 	  else if (dir == GTK_DIR_LEFT)
8642 	    focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (last_column->data));
8643 	  else
8644 	    focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8645 
8646 	  gtk_widget_grab_focus (focus_child);
8647 	  break;
8648 	}
8649 
8650       if (gtk_widget_child_focus (focus_child, dir))
8651 	{
8652 	  /* The focus moves inside the button. */
8653 	  /* This is probably a great example of bad UI */
8654 	  break;
8655 	}
8656 
8657       /* We need to move the focus among the row of buttons. */
8658       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8659 	if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8660 	  break;
8661 
8662       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
8663 	  || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
8664         {
8665 	  gtk_widget_error_bell (GTK_WIDGET (tree_view));
8666 	  break;
8667 	}
8668 
8669       while (tmp_list)
8670 	{
8671 	  if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
8672 	    tmp_list = tmp_list->next;
8673 	  else
8674 	    tmp_list = tmp_list->prev;
8675 
8676 	  if (tmp_list == NULL)
8677 	    {
8678 	      g_warning ("Internal button not found");
8679 	      break;
8680 	    }
8681 	  column = tmp_list->data;
8682 	  button = gtk_tree_view_column_get_button (column);
8683 	  if (button &&
8684 	      gtk_tree_view_column_get_visible (column) &&
8685 	      gtk_widget_get_can_focus (button))
8686 	    {
8687 	      focus_child = button;
8688 	      gtk_widget_grab_focus (button);
8689 	      break;
8690 	    }
8691 	}
8692       break;
8693     default:
8694       g_assert_not_reached ();
8695       break;
8696     }
8697 
8698   /* if focus child is non-null, we assume it's been set to the current focus child
8699    */
8700   if (focus_child)
8701     {
8702       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8703 	if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8704 	  {
8705             _gtk_tree_view_set_focus_column (tree_view, GTK_TREE_VIEW_COLUMN (tmp_list->data));
8706 	    break;
8707 	  }
8708 
8709       if (clamp_column_visible)
8710         {
8711 	  gtk_tree_view_clamp_column_visible (tree_view,
8712 					      tree_view->priv->focus_column,
8713 					      FALSE);
8714 	}
8715     }
8716 
8717   return (focus_child != NULL);
8718 }
8719 
8720 /* This function returns in 'path' the first focusable path, if the given path
8721  * is already focusable, it’s the returned one.
8722  */
8723 static gboolean
search_first_focusable_path(GtkTreeView * tree_view,GtkTreePath ** path,gboolean search_forward,GtkRBTree ** new_tree,GtkRBNode ** new_node)8724 search_first_focusable_path (GtkTreeView  *tree_view,
8725 			     GtkTreePath **path,
8726 			     gboolean      search_forward,
8727 			     GtkRBTree   **new_tree,
8728 			     GtkRBNode   **new_node)
8729 {
8730   GtkRBTree *tree = NULL;
8731   GtkRBNode *node = NULL;
8732 
8733   if (!path || !*path)
8734     return FALSE;
8735 
8736   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
8737 
8738   if (!tree || !node)
8739     return FALSE;
8740 
8741   while (node && row_is_separator (tree_view, NULL, *path))
8742     {
8743       if (search_forward)
8744 	_gtk_rbtree_next_full (tree, node, &tree, &node);
8745       else
8746 	_gtk_rbtree_prev_full (tree, node, &tree, &node);
8747 
8748       if (*path)
8749 	gtk_tree_path_free (*path);
8750 
8751       if (node)
8752 	*path = _gtk_tree_path_new_from_rbtree (tree, node);
8753       else
8754 	*path = NULL;
8755     }
8756 
8757   if (new_tree)
8758     *new_tree = tree;
8759 
8760   if (new_node)
8761     *new_node = node;
8762 
8763   return (*path != NULL);
8764 }
8765 
8766 static gint
gtk_tree_view_focus(GtkWidget * widget,GtkDirectionType direction)8767 gtk_tree_view_focus (GtkWidget        *widget,
8768 		     GtkDirectionType  direction)
8769 {
8770   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8771   GtkContainer *container = GTK_CONTAINER (widget);
8772   GtkWidget *focus_child;
8773 
8774   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8775     return FALSE;
8776 
8777   focus_child = gtk_container_get_focus_child (container);
8778 
8779   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8780   /* Case 1.  Headers currently have focus. */
8781   if (focus_child)
8782     {
8783       switch (direction)
8784 	{
8785 	case GTK_DIR_LEFT:
8786 	case GTK_DIR_RIGHT:
8787 	  gtk_tree_view_header_focus (tree_view, direction, TRUE);
8788 	  return TRUE;
8789 	case GTK_DIR_TAB_BACKWARD:
8790 	case GTK_DIR_UP:
8791 	  return FALSE;
8792 	case GTK_DIR_TAB_FORWARD:
8793 	case GTK_DIR_DOWN:
8794 	  gtk_widget_grab_focus (widget);
8795 	  return TRUE;
8796 	default:
8797 	  g_assert_not_reached ();
8798 	  return FALSE;
8799 	}
8800     }
8801 
8802   /* Case 2. We don't have focus at all. */
8803   if (!gtk_widget_has_focus (widget))
8804     {
8805       gtk_widget_grab_focus (widget);
8806       return TRUE;
8807     }
8808 
8809   /* Case 3. We have focus already. */
8810   if (direction == GTK_DIR_TAB_BACKWARD)
8811     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8812   else if (direction == GTK_DIR_TAB_FORWARD)
8813     return FALSE;
8814 
8815   /* Other directions caught by the keybindings */
8816   gtk_widget_grab_focus (widget);
8817   return TRUE;
8818 }
8819 
8820 static void
gtk_tree_view_grab_focus(GtkWidget * widget)8821 gtk_tree_view_grab_focus (GtkWidget *widget)
8822 {
8823   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8824 
8825   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8826 }
8827 
8828 static void
gtk_tree_view_style_updated(GtkWidget * widget)8829 gtk_tree_view_style_updated (GtkWidget *widget)
8830 {
8831   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8832   GList *list;
8833   GtkTreeViewColumn *column;
8834   GtkStyleContext *style_context;
8835   GtkCssStyleChange *change;
8836 
8837   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->style_updated (widget);
8838 
8839   if (gtk_widget_get_realized (widget))
8840     {
8841       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8842       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8843     }
8844 
8845   style_context = gtk_widget_get_style_context (widget);
8846   change = gtk_style_context_get_change (style_context);
8847 
8848   if (change == NULL || gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_SIZE | GTK_CSS_AFFECTS_CLIP))
8849     {
8850       for (list = tree_view->priv->columns; list; list = list->next)
8851 	{
8852 	  column = list->data;
8853 	  _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8854 	}
8855 
8856       tree_view->priv->fixed_height = -1;
8857       _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8858     }
8859 }
8860 
8861 
8862 static void
gtk_tree_view_set_focus_child(GtkContainer * container,GtkWidget * child)8863 gtk_tree_view_set_focus_child (GtkContainer *container,
8864 			       GtkWidget    *child)
8865 {
8866   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8867   GList *list;
8868 
8869   for (list = tree_view->priv->columns; list; list = list->next)
8870     {
8871       if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (list->data)) == child)
8872 	{
8873           _gtk_tree_view_set_focus_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data));
8874 	  break;
8875 	}
8876     }
8877 
8878   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8879 }
8880 
8881 static gboolean
gtk_tree_view_real_move_cursor(GtkTreeView * tree_view,GtkMovementStep step,gint count)8882 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8883 				GtkMovementStep    step,
8884 				gint               count)
8885 {
8886   GdkModifierType state;
8887 
8888   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8889   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8890 			step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8891 			step == GTK_MOVEMENT_DISPLAY_LINES ||
8892 			step == GTK_MOVEMENT_PAGES ||
8893 			step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8894 
8895   if (tree_view->priv->tree == NULL)
8896     return FALSE;
8897   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8898     return FALSE;
8899 
8900   gtk_tree_view_stop_editing (tree_view, FALSE);
8901   tree_view->priv->draw_keyfocus = TRUE;
8902   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8903 
8904   if (gtk_get_current_event_state (&state))
8905     {
8906       GdkModifierType extend_mod_mask;
8907       GdkModifierType modify_mod_mask;
8908 
8909       extend_mod_mask =
8910         gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
8911                                       GDK_MODIFIER_INTENT_EXTEND_SELECTION);
8912 
8913       modify_mod_mask =
8914         gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
8915                                       GDK_MODIFIER_INTENT_MODIFY_SELECTION);
8916 
8917       if ((state & modify_mod_mask) == modify_mod_mask)
8918         tree_view->priv->modify_selection_pressed = TRUE;
8919       if ((state & extend_mod_mask) == extend_mod_mask)
8920         tree_view->priv->extend_selection_pressed = TRUE;
8921     }
8922   /* else we assume not pressed */
8923 
8924   switch (step)
8925     {
8926       /* currently we make no distinction.  When we go bi-di, we need to */
8927     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8928     case GTK_MOVEMENT_VISUAL_POSITIONS:
8929       gtk_tree_view_move_cursor_left_right (tree_view, count);
8930       break;
8931     case GTK_MOVEMENT_DISPLAY_LINES:
8932       gtk_tree_view_move_cursor_up_down (tree_view, count);
8933       break;
8934     case GTK_MOVEMENT_PAGES:
8935       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8936       break;
8937     case GTK_MOVEMENT_BUFFER_ENDS:
8938       gtk_tree_view_move_cursor_start_end (tree_view, count);
8939       break;
8940     default:
8941       g_assert_not_reached ();
8942     }
8943 
8944   tree_view->priv->modify_selection_pressed = FALSE;
8945   tree_view->priv->extend_selection_pressed = FALSE;
8946 
8947   return TRUE;
8948 }
8949 
8950 static void
gtk_tree_view_put(GtkTreeView * tree_view,GtkWidget * child_widget,GtkTreePath * path,GtkTreeViewColumn * column,const GtkBorder * border)8951 gtk_tree_view_put (GtkTreeView       *tree_view,
8952 		   GtkWidget         *child_widget,
8953                    GtkTreePath       *path,
8954                    GtkTreeViewColumn *column,
8955                    const GtkBorder   *border)
8956 {
8957   GtkTreeViewChild *child;
8958 
8959   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8960   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8961 
8962   child = g_slice_new (GtkTreeViewChild);
8963 
8964   child->widget = child_widget;
8965   if (_gtk_tree_view_find_node (tree_view,
8966 				path,
8967 				&child->tree,
8968 				&child->node))
8969     {
8970       g_assert_not_reached ();
8971     }
8972   child->column = column;
8973   child->border = *border;
8974 
8975   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8976 
8977   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8978     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8979 
8980   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8981 }
8982 
8983 /* TreeModel Callbacks
8984  */
8985 
8986 static void
gtk_tree_view_row_changed(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)8987 gtk_tree_view_row_changed (GtkTreeModel *model,
8988 			   GtkTreePath  *path,
8989 			   GtkTreeIter  *iter,
8990 			   gpointer      data)
8991 {
8992   GtkTreeView *tree_view = (GtkTreeView *)data;
8993   GtkRBTree *tree;
8994   GtkRBNode *node;
8995   gboolean free_path = FALSE;
8996   GList *list;
8997   GtkTreePath *cursor_path;
8998 
8999   g_return_if_fail (path != NULL || iter != NULL);
9000 
9001   if (tree_view->priv->cursor_node != NULL)
9002     cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
9003                                                   tree_view->priv->cursor_node);
9004   else
9005     cursor_path = NULL;
9006 
9007   if (tree_view->priv->edited_column &&
9008       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
9009     gtk_tree_view_stop_editing (tree_view, TRUE);
9010 
9011   if (cursor_path != NULL)
9012     gtk_tree_path_free (cursor_path);
9013 
9014   if (path == NULL)
9015     {
9016       path = gtk_tree_model_get_path (model, iter);
9017       free_path = TRUE;
9018     }
9019   else if (iter == NULL)
9020     gtk_tree_model_get_iter (model, iter, path);
9021 
9022   if (_gtk_tree_view_find_node (tree_view,
9023 				path,
9024 				&tree,
9025 				&node))
9026     /* We aren't actually showing the node */
9027     goto done;
9028 
9029   if (tree == NULL)
9030     goto done;
9031 
9032   _gtk_tree_view_accessible_changed (tree_view, tree, node);
9033 
9034   if (tree_view->priv->fixed_height_mode
9035       && tree_view->priv->fixed_height >= 0)
9036     {
9037       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
9038       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9039 	gtk_tree_view_node_queue_redraw (tree_view, tree, node);
9040     }
9041   else
9042     {
9043       _gtk_rbtree_node_mark_invalid (tree, node);
9044       for (list = tree_view->priv->columns; list; list = list->next)
9045         {
9046           GtkTreeViewColumn *column;
9047 
9048           column = list->data;
9049           if (!gtk_tree_view_column_get_visible (column))
9050             continue;
9051 
9052           if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
9053             {
9054               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
9055             }
9056         }
9057     }
9058 
9059  done:
9060   if (!tree_view->priv->fixed_height_mode &&
9061       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9062     install_presize_handler (tree_view);
9063   if (free_path)
9064     gtk_tree_path_free (path);
9065 }
9066 
9067 static void
gtk_tree_view_row_inserted(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)9068 gtk_tree_view_row_inserted (GtkTreeModel *model,
9069 			    GtkTreePath  *path,
9070 			    GtkTreeIter  *iter,
9071 			    gpointer      data)
9072 {
9073   GtkTreeView *tree_view = (GtkTreeView *) data;
9074   gint *indices;
9075   GtkRBTree *tree;
9076   GtkRBNode *tmpnode = NULL;
9077   gint depth;
9078   gint i = 0;
9079   gint height;
9080   gboolean free_path = FALSE;
9081   gboolean node_visible = TRUE;
9082 
9083   g_return_if_fail (path != NULL || iter != NULL);
9084 
9085   if (tree_view->priv->fixed_height_mode
9086       && tree_view->priv->fixed_height >= 0)
9087     height = tree_view->priv->fixed_height;
9088   else
9089     height = 0;
9090 
9091   if (path == NULL)
9092     {
9093       path = gtk_tree_model_get_path (model, iter);
9094       free_path = TRUE;
9095     }
9096   else if (iter == NULL)
9097     gtk_tree_model_get_iter (model, iter, path);
9098 
9099   if (tree_view->priv->tree == NULL)
9100     tree_view->priv->tree = _gtk_rbtree_new ();
9101 
9102   tree = tree_view->priv->tree;
9103 
9104   /* Update all row-references */
9105   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
9106   depth = gtk_tree_path_get_depth (path);
9107   indices = gtk_tree_path_get_indices (path);
9108 
9109   /* First, find the parent tree */
9110   while (i < depth - 1)
9111     {
9112       if (tree == NULL)
9113 	{
9114 	  /* We aren't showing the node */
9115 	  node_visible = FALSE;
9116           goto done;
9117 	}
9118 
9119       tmpnode = _gtk_rbtree_find_count (tree, indices[i] + 1);
9120       if (tmpnode == NULL)
9121 	{
9122 	  g_warning ("A node was inserted with a parent that's not in the tree.\n" \
9123 		     "This possibly means that a GtkTreeModel inserted a child node\n" \
9124 		     "before the parent was inserted.");
9125           goto done;
9126 	}
9127       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
9128 	{
9129           /* FIXME enforce correct behavior on model, probably */
9130 	  /* In theory, the model should have emitted has_child_toggled here.  We
9131 	   * try to catch it anyway, just to be safe, in case the model hasn't.
9132 	   */
9133 	  GtkTreePath *tmppath = _gtk_tree_path_new_from_rbtree (tree, tmpnode);
9134 	  gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
9135 	  gtk_tree_path_free (tmppath);
9136           goto done;
9137 	}
9138 
9139       tree = tmpnode->children;
9140       i++;
9141     }
9142 
9143   if (tree == NULL)
9144     {
9145       node_visible = FALSE;
9146       goto done;
9147     }
9148 
9149   /* ref the node */
9150   gtk_tree_model_ref_node (tree_view->priv->model, iter);
9151   if (indices[depth - 1] == 0)
9152     {
9153       tmpnode = _gtk_rbtree_find_count (tree, 1);
9154       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
9155     }
9156   else
9157     {
9158       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
9159       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
9160     }
9161 
9162   _gtk_tree_view_accessible_add (tree_view, tree, tmpnode);
9163 
9164  done:
9165   if (height > 0)
9166     {
9167       if (tree)
9168         _gtk_rbtree_node_mark_valid (tree, tmpnode);
9169 
9170       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
9171 	gtk_widget_queue_resize (GTK_WIDGET (tree_view));
9172       else
9173 	gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
9174     }
9175   else
9176     install_presize_handler (tree_view);
9177   if (free_path)
9178     gtk_tree_path_free (path);
9179 }
9180 
9181 static void
gtk_tree_view_row_has_child_toggled(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)9182 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
9183 				     GtkTreePath  *path,
9184 				     GtkTreeIter  *iter,
9185 				     gpointer      data)
9186 {
9187   GtkTreeView *tree_view = (GtkTreeView *)data;
9188   GtkTreeIter real_iter;
9189   gboolean has_child;
9190   GtkRBTree *tree;
9191   GtkRBNode *node;
9192   gboolean free_path = FALSE;
9193 
9194   g_return_if_fail (path != NULL || iter != NULL);
9195 
9196   if (iter)
9197     real_iter = *iter;
9198 
9199   if (path == NULL)
9200     {
9201       path = gtk_tree_model_get_path (model, iter);
9202       free_path = TRUE;
9203     }
9204   else if (iter == NULL)
9205     gtk_tree_model_get_iter (model, &real_iter, path);
9206 
9207   if (_gtk_tree_view_find_node (tree_view,
9208 				path,
9209 				&tree,
9210 				&node))
9211     /* We aren't actually showing the node */
9212     goto done;
9213 
9214   if (tree == NULL)
9215     goto done;
9216 
9217   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
9218   /* Sanity check.
9219    */
9220   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
9221     goto done;
9222 
9223   if (has_child)
9224     {
9225       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
9226       _gtk_tree_view_accessible_add_state (tree_view, tree, node, GTK_CELL_RENDERER_EXPANDABLE);
9227     }
9228   else
9229     {
9230       GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
9231       _gtk_tree_view_accessible_remove_state (tree_view, tree, node, GTK_CELL_RENDERER_EXPANDABLE);
9232     }
9233 
9234   if (has_child && tree_view->priv->is_list)
9235     {
9236       tree_view->priv->is_list = FALSE;
9237       if (tree_view->priv->show_expanders)
9238 	{
9239 	  GList *list;
9240 
9241 	  for (list = tree_view->priv->columns; list; list = list->next)
9242 	    if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9243 	      {
9244 		_gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
9245 		break;
9246 	      }
9247 	}
9248       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
9249     }
9250   else
9251     {
9252       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
9253     }
9254 
9255  done:
9256   if (free_path)
9257     gtk_tree_path_free (path);
9258 }
9259 
9260 static void
count_children_helper(GtkRBTree * tree,GtkRBNode * node,gpointer data)9261 count_children_helper (GtkRBTree *tree,
9262 		       GtkRBNode *node,
9263 		       gpointer   data)
9264 {
9265   if (node->children)
9266     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
9267   (*((gint *)data))++;
9268 }
9269 
9270 static void
check_selection_helper(GtkRBTree * tree,GtkRBNode * node,gpointer data)9271 check_selection_helper (GtkRBTree *tree,
9272                         GtkRBNode *node,
9273                         gpointer   data)
9274 {
9275   gint *value = (gint *)data;
9276 
9277   *value |= GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
9278 
9279   if (node->children && !*value)
9280     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
9281 }
9282 
9283 static void
gtk_tree_view_row_deleted(GtkTreeModel * model,GtkTreePath * path,gpointer data)9284 gtk_tree_view_row_deleted (GtkTreeModel *model,
9285 			   GtkTreePath  *path,
9286 			   gpointer      data)
9287 {
9288   GtkTreeView *tree_view = (GtkTreeView *)data;
9289   GtkRBTree *tree;
9290   GtkRBNode *node;
9291   GList *list;
9292   gboolean selection_changed = FALSE, cursor_changed = FALSE;
9293   GtkRBTree *cursor_tree = NULL;
9294   GtkRBNode *cursor_node = NULL;
9295 
9296   g_return_if_fail (path != NULL);
9297 
9298   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
9299 
9300   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
9301     return;
9302 
9303   if (tree == NULL)
9304     return;
9305 
9306   /* check if the selection has been changed */
9307   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
9308                         check_selection_helper, &selection_changed);
9309 
9310   for (list = tree_view->priv->columns; list; list = list->next)
9311     if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)) &&
9312 	gtk_tree_view_column_get_sizing (GTK_TREE_VIEW_COLUMN (list->data)) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
9313       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
9314 
9315   /* Ensure we don't have a dangling pointer to a dead node */
9316   ensure_unprelighted (tree_view);
9317 
9318   /* Cancel editting if we've started */
9319   gtk_tree_view_stop_editing (tree_view, TRUE);
9320 
9321   /* If the cursor row got deleted, move the cursor to the next row */
9322   if (tree_view->priv->cursor_node &&
9323       (tree_view->priv->cursor_node == node ||
9324        (node->children && (tree_view->priv->cursor_tree == node->children ||
9325                            _gtk_rbtree_contains (node->children, tree_view->priv->cursor_tree)))))
9326     {
9327       GtkTreePath *cursor_path;
9328 
9329       cursor_tree = tree;
9330       cursor_node = _gtk_rbtree_next (tree, node);
9331       /* find the first node that is not going to be deleted */
9332       while (cursor_node == NULL && cursor_tree->parent_tree)
9333         {
9334           cursor_node = _gtk_rbtree_next (cursor_tree->parent_tree,
9335                                           cursor_tree->parent_node);
9336           cursor_tree = cursor_tree->parent_tree;
9337         }
9338 
9339       if (cursor_node != NULL)
9340         cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
9341       else
9342         cursor_path = NULL;
9343 
9344       if (cursor_path == NULL ||
9345           ! search_first_focusable_path (tree_view, &cursor_path, TRUE,
9346                                          &cursor_tree, &cursor_node))
9347         {
9348           /* It looks like we reached the end of the view without finding
9349            * a focusable row.  We will step backwards to find the last
9350            * focusable row.
9351            */
9352           _gtk_rbtree_prev_full (tree, node, &cursor_tree, &cursor_node);
9353           if (cursor_node)
9354             {
9355               cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
9356               if (! search_first_focusable_path (tree_view, &cursor_path, FALSE,
9357                                                  &cursor_tree, &cursor_node))
9358                 cursor_node = NULL;
9359               gtk_tree_path_free (cursor_path);
9360             }
9361         }
9362       else if (cursor_path)
9363         gtk_tree_path_free (cursor_path);
9364 
9365       cursor_changed = TRUE;
9366     }
9367 
9368   if (tree_view->priv->destroy_count_func)
9369     {
9370       gint child_count = 0;
9371       if (node->children)
9372 	_gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
9373       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
9374     }
9375 
9376   if (tree->root->count == 1)
9377     {
9378       if (tree_view->priv->tree == tree)
9379 	tree_view->priv->tree = NULL;
9380 
9381       _gtk_tree_view_accessible_remove_state (tree_view,
9382                                               tree->parent_tree, tree->parent_node,
9383                                               GTK_CELL_RENDERER_EXPANDED);
9384       _gtk_tree_view_accessible_remove (tree_view, tree, NULL);
9385       _gtk_rbtree_remove (tree);
9386     }
9387   else
9388     {
9389       _gtk_tree_view_accessible_remove (tree_view, tree, node);
9390       _gtk_rbtree_remove_node (tree, node);
9391     }
9392 
9393   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
9394     {
9395       gtk_tree_row_reference_free (tree_view->priv->top_row);
9396       tree_view->priv->top_row = NULL;
9397     }
9398 
9399   install_scroll_sync_handler (tree_view);
9400 
9401   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
9402 
9403   if (cursor_changed)
9404     {
9405       if (cursor_node)
9406         {
9407           GtkTreePath *cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
9408           gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT | CURSOR_INVALID);
9409           gtk_tree_path_free (cursor_path);
9410         }
9411       else
9412         gtk_tree_view_real_set_cursor (tree_view, NULL, CLEAR_AND_SELECT | CURSOR_INVALID);
9413     }
9414   if (selection_changed)
9415     g_signal_emit_by_name (tree_view->priv->selection, "changed");
9416 }
9417 
9418 static void
gtk_tree_view_rows_reordered(GtkTreeModel * model,GtkTreePath * parent,GtkTreeIter * iter,gint * new_order,gpointer data)9419 gtk_tree_view_rows_reordered (GtkTreeModel *model,
9420 			      GtkTreePath  *parent,
9421 			      GtkTreeIter  *iter,
9422 			      gint         *new_order,
9423 			      gpointer      data)
9424 {
9425   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
9426   GtkRBTree *tree;
9427   GtkRBNode *node;
9428   gint len;
9429 
9430   len = gtk_tree_model_iter_n_children (model, iter);
9431 
9432   if (len < 2)
9433     return;
9434 
9435   gtk_tree_row_reference_reordered (G_OBJECT (data),
9436 				    parent,
9437 				    iter,
9438 				    new_order);
9439 
9440   if (_gtk_tree_view_find_node (tree_view,
9441 				parent,
9442 				&tree,
9443 				&node))
9444     return;
9445 
9446   /* We need to special case the parent path */
9447   if (tree == NULL)
9448     tree = tree_view->priv->tree;
9449   else
9450     tree = node->children;
9451 
9452   if (tree == NULL)
9453     return;
9454 
9455   if (tree_view->priv->edited_column)
9456     gtk_tree_view_stop_editing (tree_view, TRUE);
9457 
9458   /* we need to be unprelighted */
9459   ensure_unprelighted (tree_view);
9460 
9461   _gtk_rbtree_reorder (tree, new_order, len);
9462 
9463   _gtk_tree_view_accessible_reorder (tree_view);
9464 
9465   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
9466 
9467   gtk_tree_view_dy_to_top_row (tree_view);
9468 }
9469 
9470 
9471 /* Internal tree functions
9472  */
9473 
9474 
9475 static void
gtk_tree_view_get_background_xrange(GtkTreeView * tree_view,GtkRBTree * tree,GtkTreeViewColumn * column,gint * x1,gint * x2)9476 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
9477                                      GtkRBTree         *tree,
9478                                      GtkTreeViewColumn *column,
9479                                      gint              *x1,
9480                                      gint              *x2)
9481 {
9482   GtkTreeViewColumn *tmp_column = NULL;
9483   gint total_width;
9484   GList *list;
9485   gboolean rtl;
9486 
9487   if (x1)
9488     *x1 = 0;
9489 
9490   if (x2)
9491     *x2 = 0;
9492 
9493   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9494 
9495   total_width = 0;
9496   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9497        list;
9498        list = (rtl ? list->prev : list->next))
9499     {
9500       tmp_column = list->data;
9501 
9502       if (tmp_column == column)
9503         break;
9504 
9505       if (gtk_tree_view_column_get_visible (tmp_column))
9506         total_width += gtk_tree_view_column_get_width (tmp_column);
9507     }
9508 
9509   if (tmp_column != column)
9510     {
9511       g_warning (G_STRLOC": passed-in column isn't in the tree");
9512       return;
9513     }
9514 
9515   if (x1)
9516     *x1 = total_width;
9517 
9518   if (x2)
9519     {
9520       if (gtk_tree_view_column_get_visible (column))
9521         *x2 = total_width + gtk_tree_view_column_get_width (column);
9522       else
9523         *x2 = total_width; /* width of 0 */
9524     }
9525 }
9526 
9527 static void
gtk_tree_view_get_arrow_xrange(GtkTreeView * tree_view,GtkRBTree * tree,gint * x1,gint * x2)9528 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
9529 				GtkRBTree   *tree,
9530                                 gint        *x1,
9531                                 gint        *x2)
9532 {
9533   gint x_offset = 0;
9534   GList *list;
9535   GtkTreeViewColumn *tmp_column = NULL;
9536   gint total_width;
9537   gint expander_size, expander_render_size;
9538   gint horizontal_separator;
9539   gboolean indent_expanders;
9540   gboolean rtl;
9541 
9542   gtk_widget_style_get (GTK_WIDGET (tree_view),
9543 			"indent-expanders", &indent_expanders,
9544                         "horizontal-separator", &horizontal_separator,
9545 			NULL);
9546 
9547   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9548   expander_size = gtk_tree_view_get_expander_size (tree_view);
9549   expander_render_size = expander_size - (horizontal_separator / 2);
9550 
9551   total_width = 0;
9552   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9553        list;
9554        list = (rtl ? list->prev : list->next))
9555     {
9556       tmp_column = list->data;
9557 
9558       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
9559         {
9560 	  if (rtl)
9561 	    x_offset = total_width + gtk_tree_view_column_get_width (tmp_column) - expander_size;
9562 	  else
9563 	    x_offset = total_width;
9564           break;
9565         }
9566 
9567       if (gtk_tree_view_column_get_visible (tmp_column))
9568         total_width += gtk_tree_view_column_get_width (tmp_column);
9569     }
9570 
9571   x_offset += (expander_size - expander_render_size);
9572 
9573   if (indent_expanders)
9574     {
9575       if (rtl)
9576 	x_offset -= expander_size * _gtk_rbtree_get_depth (tree);
9577       else
9578 	x_offset += expander_size * _gtk_rbtree_get_depth (tree);
9579     }
9580 
9581   *x1 = x_offset;
9582 
9583   if (tmp_column &&
9584       gtk_tree_view_column_get_visible (tmp_column))
9585     *x2 = *x1 + expander_render_size;
9586   else
9587     *x2 = *x1;
9588 }
9589 
9590 static void
gtk_tree_view_build_tree(GtkTreeView * tree_view,GtkRBTree * tree,GtkTreeIter * iter,gint depth,gboolean recurse)9591 gtk_tree_view_build_tree (GtkTreeView *tree_view,
9592 			  GtkRBTree   *tree,
9593 			  GtkTreeIter *iter,
9594 			  gint         depth,
9595 			  gboolean     recurse)
9596 {
9597   GtkRBNode *temp = NULL;
9598   GtkTreePath *path = NULL;
9599 
9600   do
9601     {
9602       gtk_tree_model_ref_node (tree_view->priv->model, iter);
9603       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
9604 
9605       if (tree_view->priv->fixed_height > 0)
9606         {
9607           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
9608 	    {
9609               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
9610 	      _gtk_rbtree_node_mark_valid (tree, temp);
9611 	    }
9612         }
9613 
9614       if (tree_view->priv->is_list)
9615         continue;
9616 
9617       if (recurse)
9618 	{
9619 	  GtkTreeIter child;
9620 
9621 	  if (!path)
9622 	    path = gtk_tree_model_get_path (tree_view->priv->model, iter);
9623 	  else
9624 	    gtk_tree_path_next (path);
9625 
9626 	  if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
9627 	    {
9628 	      gboolean expand;
9629 
9630 	      g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
9631 
9632 	      if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter)
9633 		  && !expand)
9634 	        {
9635 	          temp->children = _gtk_rbtree_new ();
9636 	          temp->children->parent_tree = tree;
9637 	          temp->children->parent_node = temp;
9638 	          gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
9639 		}
9640 	    }
9641 	}
9642 
9643       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
9644 	{
9645 	  if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
9646 	    temp->flags ^= GTK_RBNODE_IS_PARENT;
9647 	}
9648     }
9649   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
9650 
9651   if (path)
9652     gtk_tree_path_free (path);
9653 }
9654 
9655 /* Make sure the node is visible vertically */
9656 static void
gtk_tree_view_clamp_node_visible(GtkTreeView * tree_view,GtkRBTree * tree,GtkRBNode * node)9657 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
9658 				  GtkRBTree   *tree,
9659 				  GtkRBNode   *node)
9660 {
9661   gint node_dy, height;
9662   GtkTreePath *path = NULL;
9663 
9664   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9665     return;
9666 
9667   /* just return if the node is visible, avoiding a costly expose */
9668   node_dy = _gtk_rbtree_node_find_offset (tree, node);
9669   height = gtk_tree_view_get_row_height (tree_view, node);
9670   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
9671       && node_dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment)
9672       && node_dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
9673                               + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
9674     return;
9675 
9676   path = _gtk_tree_path_new_from_rbtree (tree, node);
9677   if (path)
9678     {
9679       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
9680       gtk_tree_path_free (path);
9681     }
9682 }
9683 
9684 static void
gtk_tree_view_clamp_column_visible(GtkTreeView * tree_view,GtkTreeViewColumn * column,gboolean focus_to_cell)9685 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
9686 				    GtkTreeViewColumn *column,
9687 				    gboolean           focus_to_cell)
9688 {
9689   GtkAllocation allocation;
9690   gint x, width;
9691 
9692   if (column == NULL)
9693     return;
9694 
9695   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
9696   x = allocation.x;
9697   width = allocation.width;
9698 
9699   if (width > gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9700     {
9701       /* The column is larger than the horizontal page size.  If the
9702        * column has cells which can be focused individually, then we make
9703        * sure the cell which gets focus is fully visible (if even the
9704        * focus cell is bigger than the page size, we make sure the
9705        * left-hand side of the cell is visible).
9706        *
9707        * If the column does not have an activatable cell, we
9708        * make sure the left-hand side of the column is visible.
9709        */
9710 
9711       if (focus_to_cell && gtk_tree_view_has_can_focus_cell (tree_view))
9712         {
9713           GtkCellArea *cell_area;
9714           GtkCellRenderer *focus_cell;
9715 
9716           cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
9717           focus_cell = gtk_cell_area_get_focus_cell (cell_area);
9718 
9719           if (gtk_tree_view_column_cell_get_position (column, focus_cell,
9720                                                       &x, &width))
9721             {
9722               if (width < gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9723                 {
9724                   if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment) < x + width)
9725                     gtk_adjustment_set_value (tree_view->priv->hadjustment,
9726                                               x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9727                   else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9728                     gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9729                 }
9730             }
9731         }
9732 
9733       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9734     }
9735   else
9736     {
9737       if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
9738 	  gtk_adjustment_set_value (tree_view->priv->hadjustment,
9739 				    x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9740       else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9741 	gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9742   }
9743 }
9744 
9745 /* This function could be more efficient.  I'll optimize it if profiling seems
9746  * to imply that it is important */
9747 GtkTreePath *
_gtk_tree_path_new_from_rbtree(GtkRBTree * tree,GtkRBNode * node)9748 _gtk_tree_path_new_from_rbtree (GtkRBTree   *tree,
9749 			        GtkRBNode   *node)
9750 {
9751   GtkTreePath *path;
9752   GtkRBTree *tmp_tree;
9753   GtkRBNode *tmp_node, *last;
9754   gint count;
9755 
9756   path = gtk_tree_path_new ();
9757 
9758   g_return_val_if_fail (node != NULL, path);
9759 
9760   count = 1 + node->left->count;
9761 
9762   last = node;
9763   tmp_node = node->parent;
9764   tmp_tree = tree;
9765   while (tmp_tree)
9766     {
9767       while (!_gtk_rbtree_is_nil (tmp_node))
9768 	{
9769 	  if (tmp_node->right == last)
9770 	    count += 1 + tmp_node->left->count;
9771 	  last = tmp_node;
9772 	  tmp_node = tmp_node->parent;
9773 	}
9774       gtk_tree_path_prepend_index (path, count - 1);
9775       last = tmp_tree->parent_node;
9776       tmp_tree = tmp_tree->parent_tree;
9777       if (last)
9778 	{
9779 	  count = 1 + last->left->count;
9780 	  tmp_node = last->parent;
9781 	}
9782     }
9783   return path;
9784 }
9785 
9786 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9787  * invalid (ie. points to a node that’s not in the tree), *tree and *node are
9788  * both set to NULL.
9789  */
9790 gboolean
_gtk_tree_view_find_node(GtkTreeView * tree_view,GtkTreePath * path,GtkRBTree ** tree,GtkRBNode ** node)9791 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9792 			  GtkTreePath  *path,
9793 			  GtkRBTree   **tree,
9794 			  GtkRBNode   **node)
9795 {
9796   GtkRBNode *tmpnode = NULL;
9797   GtkRBTree *tmptree = tree_view->priv->tree;
9798   gint *indices = gtk_tree_path_get_indices (path);
9799   gint depth = gtk_tree_path_get_depth (path);
9800   gint i = 0;
9801 
9802   *node = NULL;
9803   *tree = NULL;
9804 
9805   if (depth == 0 || tmptree == NULL)
9806     return FALSE;
9807   do
9808     {
9809       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9810       ++i;
9811       if (tmpnode == NULL)
9812 	{
9813 	  *tree = NULL;
9814 	  *node = NULL;
9815 	  return FALSE;
9816 	}
9817       if (i >= depth)
9818 	{
9819 	  *tree = tmptree;
9820 	  *node = tmpnode;
9821 	  return FALSE;
9822 	}
9823       *tree = tmptree;
9824       *node = tmpnode;
9825       tmptree = tmpnode->children;
9826       if (tmptree == NULL)
9827 	return TRUE;
9828     }
9829   while (1);
9830 }
9831 
9832 static gboolean
gtk_tree_view_is_expander_column(GtkTreeView * tree_view,GtkTreeViewColumn * column)9833 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9834 				  GtkTreeViewColumn *column)
9835 {
9836   GList *list;
9837 
9838   if (tree_view->priv->is_list)
9839     return FALSE;
9840 
9841   if (tree_view->priv->expander_column != NULL)
9842     {
9843       if (tree_view->priv->expander_column == column)
9844 	return TRUE;
9845       return FALSE;
9846     }
9847   else
9848     {
9849       for (list = tree_view->priv->columns;
9850 	   list;
9851 	   list = list->next)
9852 	if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9853 	  break;
9854       if (list && list->data == column)
9855 	return TRUE;
9856     }
9857   return FALSE;
9858 }
9859 
9860 static inline gboolean
gtk_tree_view_draw_expanders(GtkTreeView * tree_view)9861 gtk_tree_view_draw_expanders (GtkTreeView *tree_view)
9862 {
9863   if (!tree_view->priv->is_list && tree_view->priv->show_expanders)
9864     return TRUE;
9865   /* else */
9866   return FALSE;
9867 }
9868 
9869 static void
gtk_tree_view_add_move_binding(GtkBindingSet * binding_set,guint keyval,guint modmask,gboolean add_shifted_binding,GtkMovementStep step,gint count)9870 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9871 				guint           keyval,
9872 				guint           modmask,
9873 				gboolean        add_shifted_binding,
9874 				GtkMovementStep step,
9875 				gint            count)
9876 {
9877 
9878   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9879                                 "move-cursor", 2,
9880                                 G_TYPE_ENUM, step,
9881                                 G_TYPE_INT, count);
9882 
9883   if (add_shifted_binding)
9884     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9885 				  "move-cursor", 2,
9886 				  G_TYPE_ENUM, step,
9887 				  G_TYPE_INT, count);
9888 
9889   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9890    return;
9891 
9892   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9893                                 "move-cursor", 2,
9894                                 G_TYPE_ENUM, step,
9895                                 G_TYPE_INT, count);
9896 
9897   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9898                                 "move-cursor", 2,
9899                                 G_TYPE_ENUM, step,
9900                                 G_TYPE_INT, count);
9901 }
9902 
9903 static gint
gtk_tree_view_unref_tree_helper(GtkTreeModel * model,GtkTreeIter * iter,GtkRBTree * tree,GtkRBNode * node)9904 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9905 				 GtkTreeIter  *iter,
9906 				 GtkRBTree    *tree,
9907 				 GtkRBNode    *node)
9908 {
9909   gint retval = FALSE;
9910   do
9911     {
9912       g_return_val_if_fail (node != NULL, FALSE);
9913 
9914       if (node->children)
9915 	{
9916 	  GtkTreeIter child;
9917 	  GtkRBTree *new_tree;
9918 	  GtkRBNode *new_node;
9919 
9920 	  new_tree = node->children;
9921           new_node = _gtk_rbtree_first (new_tree);
9922 
9923 	  if (!gtk_tree_model_iter_children (model, &child, iter))
9924 	    return FALSE;
9925 
9926 	  retval = gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node) | retval;
9927 	}
9928 
9929       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9930 	retval = TRUE;
9931       gtk_tree_model_unref_node (model, iter);
9932       node = _gtk_rbtree_next (tree, node);
9933     }
9934   while (gtk_tree_model_iter_next (model, iter));
9935 
9936   return retval;
9937 }
9938 
9939 static gint
gtk_tree_view_unref_and_check_selection_tree(GtkTreeView * tree_view,GtkRBTree * tree)9940 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9941 					      GtkRBTree   *tree)
9942 {
9943   GtkTreeIter iter;
9944   GtkTreePath *path;
9945   GtkRBNode *node;
9946   gint retval;
9947 
9948   if (!tree)
9949     return FALSE;
9950 
9951   node = _gtk_rbtree_first (tree);
9952 
9953   g_return_val_if_fail (node != NULL, FALSE);
9954   path = _gtk_tree_path_new_from_rbtree (tree, node);
9955   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9956 			   &iter, path);
9957   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9958   gtk_tree_path_free (path);
9959 
9960   return retval;
9961 }
9962 
9963 static void
gtk_tree_view_set_column_drag_info(GtkTreeView * tree_view,GtkTreeViewColumn * column)9964 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9965 				    GtkTreeViewColumn *column)
9966 {
9967   GtkTreeViewColumn *left_column;
9968   GtkTreeViewColumn *cur_column = NULL;
9969   GtkTreeViewColumnReorder *reorder;
9970   gboolean rtl;
9971   GList *tmp_list;
9972   gint left;
9973 
9974   /* We want to precalculate the motion list such that we know what column slots
9975    * are available.
9976    */
9977   left_column = NULL;
9978   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9979 
9980   /* First, identify all possible drop spots */
9981   if (rtl)
9982     tmp_list = g_list_last (tree_view->priv->columns);
9983   else
9984     tmp_list = g_list_first (tree_view->priv->columns);
9985 
9986   while (tmp_list)
9987     {
9988       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9989       tmp_list = rtl ? tmp_list->prev : tmp_list->next;
9990 
9991       if (gtk_tree_view_column_get_visible (cur_column) == FALSE)
9992 	continue;
9993 
9994       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9995       if (left_column != column && cur_column != column &&
9996 	  tree_view->priv->column_drop_func &&
9997 	  ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9998 	{
9999 	  left_column = cur_column;
10000 	  continue;
10001 	}
10002       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
10003       reorder->left_column = left_column;
10004       left_column = reorder->right_column = cur_column;
10005 
10006       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
10007     }
10008 
10009   /* Add the last one */
10010   if (tree_view->priv->column_drop_func == NULL ||
10011       ((left_column != column) &&
10012        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
10013     {
10014       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
10015       reorder->left_column = left_column;
10016       reorder->right_column = NULL;
10017       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
10018     }
10019 
10020   /* We quickly check to see if it even makes sense to reorder columns. */
10021   /* If there is nothing that can be moved, then we return */
10022 
10023   if (tree_view->priv->column_drag_info == NULL)
10024     return;
10025 
10026   /* We know there are always 2 slots possbile, as you can always return column. */
10027   /* If that's all there is, return */
10028   if (tree_view->priv->column_drag_info->next == NULL ||
10029       (tree_view->priv->column_drag_info->next->next == NULL &&
10030        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
10031        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
10032     {
10033       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
10034 	g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
10035       g_list_free (tree_view->priv->column_drag_info);
10036       tree_view->priv->column_drag_info = NULL;
10037       return;
10038     }
10039   /* We fill in the ranges for the columns, now that we've isolated them */
10040   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
10041 
10042   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
10043     {
10044       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
10045 
10046       reorder->left_align = left;
10047       if (tmp_list->next != NULL)
10048 	{
10049           GtkAllocation right_allocation, left_allocation;
10050 	  GtkWidget    *left_button, *right_button;
10051 
10052 	  g_assert (tmp_list->next->data);
10053 
10054 	  right_button = gtk_tree_view_column_get_button (reorder->right_column);
10055 	  left_button  = gtk_tree_view_column_get_button
10056 	    (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column);
10057 
10058           gtk_widget_get_allocation (right_button, &right_allocation);
10059           gtk_widget_get_allocation (left_button, &left_allocation);
10060 	  left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
10061 	}
10062       else
10063 	{
10064 	  reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
10065                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
10066 	}
10067     }
10068 }
10069 
10070 void
_gtk_tree_view_column_start_drag(GtkTreeView * tree_view,GtkTreeViewColumn * column,GdkDevice * device)10071 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
10072 				  GtkTreeViewColumn *column,
10073                                   GdkDevice         *device)
10074 {
10075   GtkAllocation allocation;
10076   GtkAllocation button_allocation;
10077   GtkWidget *button;
10078   GdkWindowAttr attributes;
10079   guint attributes_mask;
10080   GtkStyleContext *context;
10081 
10082   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
10083   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
10084   g_return_if_fail (tree_view->priv->drag_window == NULL);
10085 
10086   gtk_tree_view_set_column_drag_info (tree_view, column);
10087 
10088   if (tree_view->priv->column_drag_info == NULL)
10089     return;
10090 
10091   button = gtk_tree_view_column_get_button (column);
10092 
10093   context = gtk_widget_get_style_context (button);
10094   gtk_style_context_add_class (context, GTK_STYLE_CLASS_DND);
10095 
10096   gtk_widget_get_allocation (button, &button_allocation);
10097 
10098   attributes.window_type = GDK_WINDOW_CHILD;
10099   attributes.wclass = GDK_INPUT_OUTPUT;
10100   attributes.x = button_allocation.x;
10101   attributes.y = 0;
10102   attributes.width = button_allocation.width;
10103   attributes.height = button_allocation.height;
10104   attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
10105   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_POINTER_MOTION_MASK;
10106   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
10107 
10108   tree_view->priv->drag_window = gdk_window_new (tree_view->priv->header_window,
10109                                                  &attributes,
10110                                                  attributes_mask);
10111   gtk_widget_register_window (GTK_WIDGET (tree_view), tree_view->priv->drag_window);
10112 
10113   /* Kids, don't try this at home */
10114   g_object_ref (button);
10115   gtk_container_remove (GTK_CONTAINER (tree_view), button);
10116   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
10117   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
10118   g_object_unref (button);
10119 
10120   gtk_widget_get_allocation (button, &button_allocation);
10121   tree_view->priv->drag_column_x = button_allocation.x;
10122   allocation = button_allocation;
10123   allocation.x = 0;
10124   gtk_widget_size_allocate (button, &allocation);
10125 
10126   tree_view->priv->drag_column = column;
10127   gdk_window_show (tree_view->priv->drag_window);
10128 
10129   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10130 
10131   tree_view->priv->in_column_drag = TRUE;
10132 
10133   /* Widget reparenting above unmaps and indirectly breaks
10134    * the implicit grab, replace it with an active one.
10135    */
10136   gdk_seat_grab (gdk_device_get_seat (device),
10137                  tree_view->priv->drag_window,
10138                  GDK_SEAT_CAPABILITY_ALL, FALSE,
10139                  NULL, NULL, NULL, NULL);
10140 
10141   gtk_gesture_set_state (tree_view->priv->column_drag_gesture,
10142                          GTK_EVENT_SEQUENCE_CLAIMED);
10143 }
10144 
10145 static void
gtk_tree_view_queue_draw_arrow(GtkTreeView * tree_view,GtkRBTree * tree,GtkRBNode * node)10146 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
10147 				GtkRBTree          *tree,
10148 				GtkRBNode          *node)
10149 {
10150   GtkAllocation allocation;
10151   GdkRectangle rect;
10152 
10153   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10154     return;
10155 
10156   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
10157   rect.x = 0;
10158   rect.width = gtk_tree_view_get_expander_size (tree_view);
10159   rect.width = MAX (rect.width, MAX (tree_view->priv->width, allocation.width));
10160 
10161   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
10162   rect.height = gtk_tree_view_get_row_height (tree_view, node);
10163 
10164   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
10165 }
10166 
10167 void
_gtk_tree_view_queue_draw_node(GtkTreeView * tree_view,GtkRBTree * tree,GtkRBNode * node,const GdkRectangle * clip_rect)10168 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
10169 				GtkRBTree          *tree,
10170 				GtkRBNode          *node,
10171 				const GdkRectangle *clip_rect)
10172 {
10173   GtkAllocation allocation;
10174   GdkRectangle rect;
10175 
10176   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10177     return;
10178 
10179   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
10180   rect.x = 0;
10181   rect.width = MAX (tree_view->priv->width, allocation.width);
10182 
10183   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
10184   rect.height = gtk_tree_view_get_row_height (tree_view, node);
10185 
10186   if (clip_rect)
10187     {
10188       GdkRectangle new_rect;
10189 
10190       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
10191 
10192       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
10193     }
10194   else
10195     {
10196       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
10197     }
10198 }
10199 
10200 static inline gint
gtk_tree_view_get_effective_header_height(GtkTreeView * tree_view)10201 gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view)
10202 {
10203   if (tree_view->priv->headers_visible)
10204     return tree_view->priv->header_height;
10205   /* else */
10206   return 0;
10207 }
10208 
10209 gint
_gtk_tree_view_get_header_height(GtkTreeView * tree_view)10210 _gtk_tree_view_get_header_height (GtkTreeView *tree_view)
10211 {
10212   return tree_view->priv->header_height;
10213 }
10214 
10215 void
_gtk_tree_view_get_row_separator_func(GtkTreeView * tree_view,GtkTreeViewRowSeparatorFunc * func,gpointer * data)10216 _gtk_tree_view_get_row_separator_func (GtkTreeView                 *tree_view,
10217 				       GtkTreeViewRowSeparatorFunc *func,
10218 				       gpointer                    *data)
10219 {
10220   *func = tree_view->priv->row_separator_func;
10221   *data = tree_view->priv->row_separator_data;
10222 }
10223 
10224 GtkTreePath *
_gtk_tree_view_get_anchor_path(GtkTreeView * tree_view)10225 _gtk_tree_view_get_anchor_path (GtkTreeView *tree_view)
10226 {
10227   if (tree_view->priv->anchor)
10228     return gtk_tree_row_reference_get_path (tree_view->priv->anchor);
10229 
10230   return NULL;
10231 }
10232 
10233 void
_gtk_tree_view_set_anchor_path(GtkTreeView * tree_view,GtkTreePath * anchor_path)10234 _gtk_tree_view_set_anchor_path (GtkTreeView *tree_view,
10235 				GtkTreePath *anchor_path)
10236 {
10237   if (tree_view->priv->anchor)
10238     {
10239       gtk_tree_row_reference_free (tree_view->priv->anchor);
10240       tree_view->priv->anchor = NULL;
10241     }
10242 
10243   if (anchor_path && tree_view->priv->model)
10244     tree_view->priv->anchor =
10245       gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
10246 					tree_view->priv->model, anchor_path);
10247 }
10248 
10249 GtkRBTree *
_gtk_tree_view_get_rbtree(GtkTreeView * tree_view)10250 _gtk_tree_view_get_rbtree (GtkTreeView *tree_view)
10251 {
10252   return tree_view->priv->tree;
10253 }
10254 
10255 gboolean
_gtk_tree_view_get_cursor_node(GtkTreeView * tree_view,GtkRBTree ** tree,GtkRBNode ** node)10256 _gtk_tree_view_get_cursor_node (GtkTreeView  *tree_view,
10257                                 GtkRBTree   **tree,
10258                                 GtkRBNode   **node)
10259 {
10260   GtkTreeViewPrivate *priv;
10261 
10262   priv = tree_view->priv;
10263 
10264   if (priv->cursor_node == NULL)
10265     return FALSE;
10266 
10267   *tree = priv->cursor_tree;
10268   *node = priv->cursor_node;
10269 
10270   return TRUE;
10271 }
10272 
10273 GdkWindow *
_gtk_tree_view_get_header_window(GtkTreeView * tree_view)10274 _gtk_tree_view_get_header_window (GtkTreeView *tree_view)
10275 {
10276   return tree_view->priv->header_window;
10277 }
10278 
10279 GtkTreeViewColumn *
_gtk_tree_view_get_focus_column(GtkTreeView * tree_view)10280 _gtk_tree_view_get_focus_column (GtkTreeView *tree_view)
10281 {
10282   return tree_view->priv->focus_column;
10283 }
10284 
10285 void
_gtk_tree_view_set_focus_column(GtkTreeView * tree_view,GtkTreeViewColumn * column)10286 _gtk_tree_view_set_focus_column (GtkTreeView       *tree_view,
10287 				 GtkTreeViewColumn *column)
10288 {
10289   GtkTreeViewColumn *old_column = tree_view->priv->focus_column;
10290 
10291   if (old_column == column)
10292     return;
10293 
10294   tree_view->priv->focus_column = column;
10295 
10296   _gtk_tree_view_accessible_update_focus_column (tree_view,
10297                                                  old_column,
10298                                                  column);
10299 }
10300 
10301 
10302 static void
gtk_tree_view_queue_draw_path(GtkTreeView * tree_view,GtkTreePath * path,const GdkRectangle * clip_rect)10303 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
10304                                GtkTreePath        *path,
10305                                const GdkRectangle *clip_rect)
10306 {
10307   GtkRBTree *tree = NULL;
10308   GtkRBNode *node = NULL;
10309 
10310   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
10311 
10312   if (tree)
10313     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
10314 }
10315 
10316 /* x and y are the mouse position
10317  */
10318 static void
gtk_tree_view_draw_arrow(GtkTreeView * tree_view,cairo_t * cr,GtkRBTree * tree,GtkRBNode * node)10319 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
10320                           cairo_t     *cr,
10321                           GtkRBTree   *tree,
10322 			  GtkRBNode   *node)
10323 {
10324   GdkRectangle area;
10325   GtkStateFlags state = 0;
10326   GtkStyleContext *context;
10327   GtkWidget *widget;
10328   gint x_offset = 0;
10329   gint x2;
10330   gint vertical_separator;
10331   GtkCellRendererState flags = 0;
10332 
10333   widget = GTK_WIDGET (tree_view);
10334   context = gtk_widget_get_style_context (widget);
10335 
10336   gtk_widget_style_get (widget,
10337                         "vertical-separator", &vertical_separator,
10338                         NULL);
10339 
10340   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
10341     return;
10342 
10343   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
10344 
10345   area.x = x_offset;
10346   area.y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
10347                                                  vertical_separator);
10348   area.width = x2 - x_offset;
10349   area.height = gtk_tree_view_get_cell_area_height (tree_view, node,
10350                                                     vertical_separator);
10351 
10352   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
10353     flags |= GTK_CELL_RENDERER_SELECTED;
10354 
10355   if (node == tree_view->priv->prelight_node &&
10356       tree_view->priv->arrow_prelit)
10357     flags |= GTK_CELL_RENDERER_PRELIT;
10358 
10359   state = gtk_cell_renderer_get_state (NULL, widget, flags);
10360 
10361   if (node->children != NULL)
10362     state |= GTK_STATE_FLAG_CHECKED;
10363   else
10364     state &= ~(GTK_STATE_FLAG_CHECKED);
10365 
10366   gtk_style_context_save (context);
10367 
10368   gtk_style_context_set_state (context, state);
10369   gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
10370 
10371   /* Make sure area.height has the same parity as the "expander-size" style
10372    * property (which area.width is assumed to be exactly equal to). This is done
10373    * to avoid the arrow being vertically centered in a half-pixel, which would
10374    * result in a fuzzy rendering.
10375    */
10376   if (area.height % 2 != area.width % 2)
10377     {
10378       area.y += 1;
10379       area.height -= 1;
10380     }
10381 
10382   gtk_render_expander (context, cr,
10383                        area.x, area.y,
10384                        area.width, area.height);
10385 
10386   gtk_style_context_restore (context);
10387 }
10388 
10389 static void
gtk_tree_view_focus_to_cursor(GtkTreeView * tree_view)10390 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
10391 
10392 {
10393   GtkTreePath *cursor_path;
10394 
10395   if ((tree_view->priv->tree == NULL) ||
10396       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
10397     return;
10398 
10399   cursor_path = NULL;
10400   if (tree_view->priv->cursor_node)
10401     cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10402                                                   tree_view->priv->cursor_node);
10403 
10404   if (cursor_path == NULL)
10405     {
10406       /* Consult the selection before defaulting to the
10407        * first focusable element
10408        */
10409       GList *selected_rows;
10410       GtkTreeModel *model;
10411       GtkTreeSelection *selection;
10412 
10413       selection = gtk_tree_view_get_selection (tree_view);
10414       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
10415 
10416       if (selected_rows)
10417 	{
10418           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
10419 	  g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
10420         }
10421       else
10422 	{
10423 	  cursor_path = gtk_tree_path_new_first ();
10424 	  search_first_focusable_path (tree_view, &cursor_path,
10425 				       TRUE, NULL, NULL);
10426 	}
10427 
10428       if (cursor_path)
10429 	{
10430 	  if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
10431 	    gtk_tree_view_real_set_cursor (tree_view, cursor_path, 0);
10432 	  else
10433 	    gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT);
10434 	}
10435     }
10436 
10437   if (cursor_path)
10438     {
10439       tree_view->priv->draw_keyfocus = TRUE;
10440 
10441       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10442       gtk_tree_path_free (cursor_path);
10443 
10444       if (tree_view->priv->focus_column == NULL)
10445 	{
10446 	  GList *list;
10447 	  for (list = tree_view->priv->columns; list; list = list->next)
10448 	    {
10449 	      if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
10450 		{
10451 		  GtkCellArea *cell_area;
10452 
10453                   _gtk_tree_view_set_focus_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data));
10454 
10455 		  /* This happens when the treeview initially grabs focus and there
10456 		   * is no column in focus, here we explicitly focus into the first cell */
10457 		  cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10458 		  if (!gtk_cell_area_get_focus_cell (cell_area))
10459                     {
10460                       gboolean rtl;
10461 
10462                       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10463                       gtk_cell_area_focus (cell_area,
10464                                            rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT);
10465                     }
10466 
10467 		  break;
10468 		}
10469 	    }
10470 	}
10471     }
10472 }
10473 
10474 static void
gtk_tree_view_move_cursor_up_down(GtkTreeView * tree_view,gint count)10475 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
10476 				   gint         count)
10477 {
10478   gint selection_count;
10479   GtkRBTree *new_cursor_tree = NULL;
10480   GtkRBNode *new_cursor_node = NULL;
10481   GtkTreePath *cursor_path = NULL;
10482   gboolean grab_focus = TRUE;
10483   gboolean selectable;
10484   GtkDirectionType direction;
10485   GtkCellArea *cell_area = NULL;
10486   GtkCellRenderer *last_focus_cell = NULL;
10487   GtkTreeIter iter;
10488 
10489   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10490     return;
10491 
10492   if (tree_view->priv->cursor_node == NULL)
10493     return;
10494 
10495   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10496                                                 tree_view->priv->cursor_node);
10497 
10498   direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
10499 
10500   if (tree_view->priv->focus_column)
10501     cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10502 
10503   /* If focus stays in the area for this row, then just return for this round */
10504   if (cell_area && (count == -1 || count == 1) &&
10505       gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path))
10506     {
10507       gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
10508 					       tree_view->priv->model,
10509                                                &iter,
10510                                                GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT),
10511 					       tree_view->priv->cursor_node->children ? TRUE : FALSE);
10512 
10513       /* Save the last cell that had focus, if we hit the end of the view we'll give
10514        * focus back to it. */
10515       last_focus_cell = gtk_cell_area_get_focus_cell (cell_area);
10516 
10517       /* If focus stays in the area, no need to change the cursor row */
10518       if (gtk_cell_area_focus (cell_area, direction))
10519 	return;
10520     }
10521 
10522   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
10523   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
10524 						      tree_view->priv->cursor_node,
10525 						      cursor_path);
10526 
10527   if (selection_count == 0
10528       && gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_NONE
10529       && !tree_view->priv->modify_selection_pressed
10530       && selectable)
10531     {
10532       /* Don't move the cursor, but just select the current node */
10533       new_cursor_tree = tree_view->priv->cursor_tree;
10534       new_cursor_node = tree_view->priv->cursor_node;
10535     }
10536   else
10537     {
10538       if (count == -1)
10539 	_gtk_rbtree_prev_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10540 			       &new_cursor_tree, &new_cursor_node);
10541       else
10542 	_gtk_rbtree_next_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10543 			       &new_cursor_tree, &new_cursor_node);
10544     }
10545 
10546   gtk_tree_path_free (cursor_path);
10547 
10548   if (new_cursor_node)
10549     {
10550       cursor_path = _gtk_tree_path_new_from_rbtree (new_cursor_tree, new_cursor_node);
10551 
10552       search_first_focusable_path (tree_view, &cursor_path,
10553 				   (count != -1),
10554 				   &new_cursor_tree,
10555 				   &new_cursor_node);
10556 
10557       if (cursor_path)
10558 	gtk_tree_path_free (cursor_path);
10559     }
10560 
10561   /*
10562    * If the list has only one item and multi-selection is set then select
10563    * the row (if not yet selected).
10564    */
10565   if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE &&
10566       new_cursor_node == NULL)
10567     {
10568       if (count == -1)
10569         _gtk_rbtree_next_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10570     			       &new_cursor_tree, &new_cursor_node);
10571       else
10572         _gtk_rbtree_prev_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10573 			       &new_cursor_tree, &new_cursor_node);
10574 
10575       if (new_cursor_node == NULL
10576 	  && !GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_SELECTED))
10577         {
10578           new_cursor_node = tree_view->priv->cursor_node;
10579           new_cursor_tree = tree_view->priv->cursor_tree;
10580         }
10581       else
10582         {
10583           new_cursor_tree = NULL;
10584           new_cursor_node = NULL;
10585         }
10586     }
10587 
10588   if (new_cursor_node)
10589     {
10590       cursor_path = _gtk_tree_path_new_from_rbtree (new_cursor_tree, new_cursor_node);
10591       gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT | CLAMP_NODE);
10592       gtk_tree_path_free (cursor_path);
10593 
10594       /* Give focus to the area in the new row */
10595       if (cell_area)
10596 	gtk_cell_area_focus (cell_area, direction);
10597     }
10598   else
10599     {
10600       gtk_tree_view_clamp_node_visible (tree_view,
10601                                         tree_view->priv->cursor_tree,
10602                                         tree_view->priv->cursor_node);
10603 
10604       if (!tree_view->priv->extend_selection_pressed)
10605         {
10606           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
10607                                           count < 0 ?
10608                                           GTK_DIR_UP : GTK_DIR_DOWN))
10609             {
10610               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10611 
10612               if (toplevel)
10613                 gtk_widget_child_focus (toplevel,
10614                                         count < 0 ?
10615                                         GTK_DIR_TAB_BACKWARD :
10616                                         GTK_DIR_TAB_FORWARD);
10617 
10618               grab_focus = FALSE;
10619             }
10620         }
10621       else
10622         {
10623           gtk_widget_error_bell (GTK_WIDGET (tree_view));
10624         }
10625 
10626       if (cell_area)
10627 	gtk_cell_area_set_focus_cell (cell_area, last_focus_cell);
10628     }
10629 
10630   if (grab_focus)
10631     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10632 }
10633 
10634 static void
gtk_tree_view_move_cursor_page_up_down(GtkTreeView * tree_view,gint count)10635 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
10636 					gint         count)
10637 {
10638   GtkTreePath *old_cursor_path = NULL;
10639   GtkTreePath *cursor_path = NULL;
10640   GtkRBTree *start_cursor_tree = NULL;
10641   GtkRBNode *start_cursor_node = NULL;
10642   GtkRBTree *cursor_tree;
10643   GtkRBNode *cursor_node;
10644   gint y;
10645   gint window_y;
10646   gint vertical_separator;
10647 
10648   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10649     return;
10650 
10651   if (tree_view->priv->cursor_node == NULL)
10652     return;
10653 
10654   old_cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10655                                                     tree_view->priv->cursor_node);
10656 
10657   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
10658 
10659   y = _gtk_rbtree_node_find_offset (tree_view->priv->cursor_tree, tree_view->priv->cursor_node);
10660   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
10661   y += tree_view->priv->cursor_offset;
10662   y += count * (int)gtk_adjustment_get_page_increment (tree_view->priv->vadjustment);
10663   y = CLAMP (y, (gint)gtk_adjustment_get_lower (tree_view->priv->vadjustment),  (gint)gtk_adjustment_get_upper (tree_view->priv->vadjustment) - vertical_separator);
10664 
10665   if (y >= gtk_tree_view_get_height (tree_view))
10666     y = gtk_tree_view_get_height (tree_view) - 1;
10667 
10668   tree_view->priv->cursor_offset =
10669     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
10670 			     &cursor_tree, &cursor_node);
10671 
10672   if (cursor_tree == NULL)
10673     {
10674       /* FIXME: we lost the cursor.  Should we try to get one? */
10675       gtk_tree_path_free (old_cursor_path);
10676       return;
10677     }
10678 
10679   if (tree_view->priv->cursor_offset
10680       > gtk_tree_view_get_row_height (tree_view, cursor_node))
10681     {
10682       _gtk_rbtree_next_full (cursor_tree, cursor_node,
10683 			     &cursor_tree, &cursor_node);
10684       tree_view->priv->cursor_offset -= gtk_tree_view_get_row_height (tree_view, cursor_node);
10685     }
10686 
10687   y -= tree_view->priv->cursor_offset;
10688   cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10689 
10690   start_cursor_tree = cursor_tree;
10691   start_cursor_node = cursor_node;
10692 
10693   if (! search_first_focusable_path (tree_view, &cursor_path,
10694 				     (count != -1),
10695 				     &cursor_tree, &cursor_node))
10696     {
10697       /* It looks like we reached the end of the view without finding
10698        * a focusable row.  We will step backwards to find the last
10699        * focusable row.
10700        */
10701       cursor_tree = start_cursor_tree;
10702       cursor_node = start_cursor_node;
10703       cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10704 
10705       search_first_focusable_path (tree_view, &cursor_path,
10706 				   (count == -1),
10707 				   &cursor_tree, &cursor_node);
10708     }
10709 
10710   if (!cursor_path)
10711     goto cleanup;
10712 
10713   /* update y */
10714   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10715 
10716   gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT);
10717 
10718   y -= window_y;
10719   gtk_tree_view_scroll_to_point (tree_view, -1, y);
10720   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10721   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10722 
10723   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
10724     gtk_widget_error_bell (GTK_WIDGET (tree_view));
10725 
10726   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10727 
10728 cleanup:
10729   gtk_tree_path_free (old_cursor_path);
10730   gtk_tree_path_free (cursor_path);
10731 }
10732 
10733 static void
gtk_tree_view_move_cursor_left_right(GtkTreeView * tree_view,gint count)10734 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
10735 				      gint         count)
10736 {
10737   GtkTreePath *cursor_path = NULL;
10738   GtkTreeViewColumn *column;
10739   GtkTreeIter iter;
10740   GList *list;
10741   gboolean found_column = FALSE;
10742   gboolean rtl;
10743   GtkDirectionType direction;
10744   GtkCellArea     *cell_area;
10745   GtkCellRenderer *last_focus_cell = NULL;
10746   GtkCellArea     *last_focus_area = NULL;
10747 
10748   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10749 
10750   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10751     return;
10752 
10753   if (tree_view->priv->cursor_node == NULL)
10754     return;
10755 
10756   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10757                                                 tree_view->priv->cursor_node);
10758 
10759   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
10760     {
10761       gtk_tree_path_free (cursor_path);
10762       return;
10763     }
10764   gtk_tree_path_free (cursor_path);
10765 
10766   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
10767   if (tree_view->priv->focus_column)
10768     {
10769       /* Save the cell/area we are moving focus from, if moving the cursor
10770        * by one step hits the end we'll set focus back here */
10771       last_focus_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10772       last_focus_cell = gtk_cell_area_get_focus_cell (last_focus_area);
10773 
10774       for (; list; list = (rtl ? list->prev : list->next))
10775 	{
10776 	  if (list->data == tree_view->priv->focus_column)
10777 	    break;
10778 	}
10779     }
10780 
10781   direction = count > 0 ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
10782 
10783   while (list)
10784     {
10785       column = list->data;
10786       if (gtk_tree_view_column_get_visible (column) == FALSE)
10787 	goto loop_end;
10788 
10789       gtk_tree_view_column_cell_set_cell_data (column,
10790 					       tree_view->priv->model,
10791 					       &iter,
10792 					       GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT),
10793 					       tree_view->priv->cursor_node->children ? TRUE : FALSE);
10794 
10795       cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
10796       if (gtk_cell_area_focus (cell_area, direction))
10797 	{
10798           _gtk_tree_view_set_focus_column (tree_view, column);
10799 	  found_column = TRUE;
10800 	  break;
10801 	}
10802 
10803     loop_end:
10804       if (count == 1)
10805 	list = rtl ? list->prev : list->next;
10806       else
10807 	list = rtl ? list->next : list->prev;
10808     }
10809 
10810   if (found_column)
10811     {
10812       if (!gtk_tree_view_has_can_focus_cell (tree_view))
10813 	_gtk_tree_view_queue_draw_node (tree_view,
10814 				        tree_view->priv->cursor_tree,
10815 				        tree_view->priv->cursor_node,
10816 				        NULL);
10817       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
10818       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10819     }
10820   else
10821     {
10822       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10823 
10824       if (last_focus_area)
10825 	gtk_cell_area_set_focus_cell (last_focus_area, last_focus_cell);
10826     }
10827 
10828   gtk_tree_view_clamp_column_visible (tree_view,
10829 				      tree_view->priv->focus_column, TRUE);
10830 }
10831 
10832 static void
gtk_tree_view_move_cursor_start_end(GtkTreeView * tree_view,gint count)10833 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
10834 				     gint         count)
10835 {
10836   GtkRBTree *cursor_tree;
10837   GtkRBNode *cursor_node;
10838   GtkTreePath *path;
10839   GtkTreePath *old_path;
10840 
10841   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10842     return;
10843 
10844   g_return_if_fail (tree_view->priv->tree != NULL);
10845 
10846   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
10847 
10848   cursor_tree = tree_view->priv->tree;
10849 
10850   if (count == -1)
10851     {
10852       cursor_node = _gtk_rbtree_first (cursor_tree);
10853 
10854       /* Now go forward to find the first focusable row. */
10855       path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10856       search_first_focusable_path (tree_view, &path,
10857 				   TRUE, &cursor_tree, &cursor_node);
10858     }
10859   else
10860     {
10861       cursor_node = cursor_tree->root;
10862 
10863       do
10864 	{
10865 	  while (cursor_node && !_gtk_rbtree_is_nil (cursor_node->right))
10866 	    cursor_node = cursor_node->right;
10867 	  if (cursor_node->children == NULL)
10868 	    break;
10869 
10870 	  cursor_tree = cursor_node->children;
10871 	  cursor_node = cursor_tree->root;
10872 	}
10873       while (1);
10874 
10875       /* Now go backwards to find last focusable row. */
10876       path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10877       search_first_focusable_path (tree_view, &path,
10878 				   FALSE, &cursor_tree, &cursor_node);
10879     }
10880 
10881   if (!path)
10882     goto cleanup;
10883 
10884   if (gtk_tree_path_compare (old_path, path))
10885     {
10886       gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CLAMP_NODE);
10887       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10888     }
10889   else
10890     {
10891       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10892     }
10893 
10894 cleanup:
10895   gtk_tree_path_free (old_path);
10896   gtk_tree_path_free (path);
10897 }
10898 
10899 static gboolean
gtk_tree_view_real_select_all(GtkTreeView * tree_view)10900 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10901 {
10902   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10903     return FALSE;
10904 
10905   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10906     return FALSE;
10907 
10908   gtk_tree_selection_select_all (tree_view->priv->selection);
10909 
10910   return TRUE;
10911 }
10912 
10913 static gboolean
gtk_tree_view_real_unselect_all(GtkTreeView * tree_view)10914 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10915 {
10916   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10917     return FALSE;
10918 
10919   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10920     return FALSE;
10921 
10922   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10923 
10924   return TRUE;
10925 }
10926 
10927 static gboolean
gtk_tree_view_real_select_cursor_row(GtkTreeView * tree_view,gboolean start_editing)10928 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10929 				      gboolean     start_editing)
10930 {
10931   GtkRBTree *new_tree = NULL;
10932   GtkRBNode *new_node = NULL;
10933   GtkRBTree *cursor_tree = NULL;
10934   GtkRBNode *cursor_node = NULL;
10935   GtkTreePath *cursor_path = NULL;
10936   GtkTreeSelectMode mode = 0;
10937 
10938   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10939     return FALSE;
10940 
10941   if (tree_view->priv->cursor_node == NULL)
10942     return FALSE;
10943 
10944   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10945                                                 tree_view->priv->cursor_node);
10946 
10947   _gtk_tree_view_find_node (tree_view, cursor_path,
10948 			    &cursor_tree, &cursor_node);
10949 
10950   if (cursor_tree == NULL)
10951     {
10952       gtk_tree_path_free (cursor_path);
10953       return FALSE;
10954     }
10955 
10956   if (!tree_view->priv->extend_selection_pressed && start_editing &&
10957       tree_view->priv->focus_column)
10958     {
10959       if (gtk_tree_view_start_editing (tree_view, cursor_path, FALSE))
10960 	{
10961 	  gtk_tree_path_free (cursor_path);
10962 	  return TRUE;
10963 	}
10964     }
10965 
10966   if (tree_view->priv->modify_selection_pressed)
10967     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10968   if (tree_view->priv->extend_selection_pressed)
10969     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10970 
10971   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10972 					    cursor_node,
10973 					    cursor_tree,
10974 					    cursor_path,
10975                                             mode,
10976 					    FALSE);
10977 
10978   /* We bail out if the original (tree, node) don't exist anymore after
10979    * handling the selection-changed callback.  We do return TRUE because
10980    * the key press has been handled at this point.
10981    */
10982   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10983 
10984   if (cursor_tree != new_tree || cursor_node != new_node)
10985     return FALSE;
10986 
10987   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10988 
10989   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10990   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10991 
10992   if (!tree_view->priv->extend_selection_pressed)
10993     gtk_tree_view_row_activated (tree_view, cursor_path,
10994                                  tree_view->priv->focus_column);
10995 
10996   gtk_tree_path_free (cursor_path);
10997 
10998   return TRUE;
10999 }
11000 
11001 static gboolean
gtk_tree_view_real_toggle_cursor_row(GtkTreeView * tree_view)11002 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
11003 {
11004   GtkRBTree *new_tree = NULL;
11005   GtkRBNode *new_node = NULL;
11006   GtkTreePath *cursor_path = NULL;
11007 
11008   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
11009     return FALSE;
11010 
11011   if (tree_view->priv->cursor_node == NULL)
11012     return FALSE;
11013 
11014   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
11015                                                 tree_view->priv->cursor_node);
11016 
11017   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
11018 					    tree_view->priv->cursor_node,
11019 					    tree_view->priv->cursor_tree,
11020 					    cursor_path,
11021                                             GTK_TREE_SELECT_MODE_TOGGLE,
11022 					    FALSE);
11023 
11024   /* We bail out if the original (tree, node) don't exist anymore after
11025    * handling the selection-changed callback.  We do return TRUE because
11026    * the key press has been handled at this point.
11027    */
11028   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
11029 
11030   if (tree_view->priv->cursor_node != new_node)
11031     return FALSE;
11032 
11033   gtk_tree_view_clamp_node_visible (tree_view,
11034                                     tree_view->priv->cursor_tree,
11035                                     tree_view->priv->cursor_node);
11036 
11037   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
11038   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
11039   gtk_tree_path_free (cursor_path);
11040 
11041   return TRUE;
11042 }
11043 
11044 static gboolean
gtk_tree_view_real_expand_collapse_cursor_row(GtkTreeView * tree_view,gboolean logical,gboolean expand,gboolean open_all)11045 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
11046 					       gboolean     logical,
11047 					       gboolean     expand,
11048 					       gboolean     open_all)
11049 {
11050   GtkTreePath *cursor_path = NULL;
11051 
11052   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
11053     return FALSE;
11054 
11055   if (tree_view->priv->cursor_node == NULL)
11056     return FALSE;
11057 
11058   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
11059                                                 tree_view->priv->cursor_node);
11060 
11061   /* Don't handle the event if we aren't an expander */
11062   if (!GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT))
11063     return FALSE;
11064 
11065   if (!logical
11066       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
11067     expand = !expand;
11068 
11069   if (expand)
11070     gtk_tree_view_real_expand_row (tree_view,
11071                                    cursor_path,
11072                                    tree_view->priv->cursor_tree,
11073                                    tree_view->priv->cursor_node,
11074                                    open_all,
11075                                    TRUE);
11076   else
11077     gtk_tree_view_real_collapse_row (tree_view,
11078                                      cursor_path,
11079                                      tree_view->priv->cursor_tree,
11080                                      tree_view->priv->cursor_node,
11081                                      TRUE);
11082 
11083   gtk_tree_path_free (cursor_path);
11084 
11085   return TRUE;
11086 }
11087 
11088 static gboolean
gtk_tree_view_real_select_cursor_parent(GtkTreeView * tree_view)11089 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
11090 {
11091   GtkTreePath *cursor_path = NULL;
11092   GdkModifierType state;
11093 
11094   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
11095     goto out;
11096 
11097   if (tree_view->priv->cursor_node == NULL)
11098     goto out;
11099 
11100   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
11101                                                 tree_view->priv->cursor_node);
11102 
11103   if (tree_view->priv->cursor_tree->parent_node)
11104     {
11105       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
11106 
11107       gtk_tree_path_up (cursor_path);
11108 
11109       if (gtk_get_current_event_state (&state))
11110 	{
11111           GdkModifierType modify_mod_mask;
11112 
11113           modify_mod_mask =
11114             gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
11115                                           GDK_MODIFIER_INTENT_MODIFY_SELECTION);
11116 
11117 	  if ((state & modify_mod_mask) == modify_mod_mask)
11118 	    tree_view->priv->modify_selection_pressed = TRUE;
11119 	}
11120 
11121       gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT | CLAMP_NODE);
11122       gtk_tree_path_free (cursor_path);
11123 
11124       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
11125 
11126       tree_view->priv->modify_selection_pressed = FALSE;
11127 
11128       return TRUE;
11129     }
11130 
11131  out:
11132 
11133   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
11134   return FALSE;
11135 }
11136 
11137 static gboolean
gtk_tree_view_search_entry_flush_timeout(GtkTreeView * tree_view)11138 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
11139 {
11140   gtk_tree_view_search_window_hide (tree_view->priv->search_window, tree_view, NULL);
11141   tree_view->priv->typeselect_flush_timeout = 0;
11142 
11143   return FALSE;
11144 }
11145 
11146 /* Cut and paste from gtkwindow.c */
11147 static void
send_focus_change(GtkWidget * widget,GdkDevice * device,gboolean in)11148 send_focus_change (GtkWidget *widget,
11149                    GdkDevice *device,
11150 		   gboolean   in)
11151 {
11152   GdkDeviceManager *device_manager;
11153   GList *devices, *d;
11154 
11155   G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
11156   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
11157   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
11158   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
11159   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
11160   G_GNUC_END_IGNORE_DEPRECATIONS;
11161 
11162   for (d = devices; d; d = d->next)
11163     {
11164       GdkDevice *dev = d->data;
11165       GdkEvent *fevent;
11166       GdkWindow *window;
11167 
11168       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
11169         continue;
11170 
11171       window = gtk_widget_get_window (widget);
11172 
11173       /* Skip non-master keyboards that haven't
11174        * selected for events from this window
11175        */
11176       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
11177           !gdk_window_get_device_events (window, dev))
11178         continue;
11179 
11180       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
11181 
11182       fevent->focus_change.type = GDK_FOCUS_CHANGE;
11183       fevent->focus_change.window = g_object_ref (window);
11184       fevent->focus_change.in = in;
11185       gdk_event_set_device (fevent, device);
11186 
11187       gtk_widget_send_focus_change (widget, fevent);
11188 
11189       gdk_event_free (fevent);
11190     }
11191 
11192   g_list_free (devices);
11193 }
11194 
11195 static void
gtk_tree_view_ensure_interactive_directory(GtkTreeView * tree_view)11196 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
11197 {
11198   GtkWidget *frame, *vbox, *toplevel;
11199   GdkScreen *screen;
11200 
11201   if (tree_view->priv->search_custom_entry_set)
11202     return;
11203 
11204   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
11205   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
11206 
11207    if (tree_view->priv->search_window != NULL)
11208      {
11209        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
11210          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
11211                                       GTK_WINDOW (tree_view->priv->search_window));
11212        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
11213          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
11214                                          GTK_WINDOW (tree_view->priv->search_window));
11215 
11216        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
11217 
11218        return;
11219      }
11220 
11221   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
11222   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
11223 
11224   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
11225     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
11226 				 GTK_WINDOW (tree_view->priv->search_window));
11227 
11228   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
11229                             GDK_WINDOW_TYPE_HINT_UTILITY);
11230   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
11231   gtk_window_set_transient_for (GTK_WINDOW (tree_view->priv->search_window),
11232                                 GTK_WINDOW (toplevel));
11233 
11234   g_signal_connect (tree_view->priv->search_window, "delete-event",
11235 		    G_CALLBACK (gtk_tree_view_search_delete_event),
11236 		    tree_view);
11237   g_signal_connect (tree_view->priv->search_window, "key-press-event",
11238 		    G_CALLBACK (gtk_tree_view_search_key_press_event),
11239 		    tree_view);
11240   g_signal_connect (tree_view->priv->search_window, "button-press-event",
11241 		    G_CALLBACK (gtk_tree_view_search_button_press_event),
11242 		    tree_view);
11243   g_signal_connect (tree_view->priv->search_window, "scroll-event",
11244 		    G_CALLBACK (gtk_tree_view_search_scroll_event),
11245 		    tree_view);
11246 
11247   frame = gtk_frame_new (NULL);
11248   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
11249   gtk_widget_show (frame);
11250   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
11251 
11252   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
11253   gtk_widget_show (vbox);
11254   gtk_container_add (GTK_CONTAINER (frame), vbox);
11255   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
11256 
11257   /* add entry */
11258   tree_view->priv->search_entry = gtk_entry_new ();
11259   gtk_widget_show (tree_view->priv->search_entry);
11260   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
11261 		    G_CALLBACK (gtk_tree_view_search_disable_popdown),
11262 		    tree_view);
11263   g_signal_connect (tree_view->priv->search_entry,
11264 		    "activate", G_CALLBACK (gtk_tree_view_search_activate),
11265 		    tree_view);
11266 
11267   g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
11268 		    "preedit-changed",
11269 		    G_CALLBACK (gtk_tree_view_search_preedit_changed),
11270 		    tree_view);
11271   g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
11272 		    "commit",
11273 		    G_CALLBACK (gtk_tree_view_search_commit),
11274 		    tree_view);
11275 
11276   gtk_container_add (GTK_CONTAINER (vbox),
11277 		     tree_view->priv->search_entry);
11278 
11279   gtk_widget_realize (tree_view->priv->search_entry);
11280 }
11281 
11282 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
11283  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from
11284  */
11285 static gboolean
gtk_tree_view_real_start_interactive_search(GtkTreeView * tree_view,GdkDevice * device,gboolean keybinding)11286 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
11287                                              GdkDevice   *device,
11288 					     gboolean     keybinding)
11289 {
11290   /* We only start interactive search if we have focus or the columns
11291    * have focus.  If one of our children have focus, we don't want to
11292    * start the search.
11293    */
11294   GList *list;
11295   gboolean found_focus = FALSE;
11296 
11297   if (!tree_view->priv->enable_search && !keybinding)
11298     return FALSE;
11299 
11300   if (tree_view->priv->search_custom_entry_set)
11301     return FALSE;
11302 
11303   if (tree_view->priv->search_window != NULL &&
11304       gtk_widget_get_visible (tree_view->priv->search_window))
11305     return TRUE;
11306 
11307   for (list = tree_view->priv->columns; list; list = list->next)
11308     {
11309       GtkTreeViewColumn *column;
11310       GtkWidget         *button;
11311 
11312       column = list->data;
11313       if (!gtk_tree_view_column_get_visible (column))
11314 	continue;
11315 
11316       button = gtk_tree_view_column_get_button (column);
11317       if (gtk_widget_has_focus (button))
11318 	{
11319 	  found_focus = TRUE;
11320 	  break;
11321 	}
11322     }
11323 
11324   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
11325     found_focus = TRUE;
11326 
11327   if (!found_focus)
11328     return FALSE;
11329 
11330   if (tree_view->priv->search_column < 0)
11331     return FALSE;
11332 
11333   gtk_tree_view_ensure_interactive_directory (tree_view);
11334 
11335   if (keybinding)
11336     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
11337 
11338   /* done, show it */
11339   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
11340 
11341   /* Grab focus without selecting all the text. */
11342   gtk_entry_grab_focus_without_selecting (GTK_ENTRY (tree_view->priv->search_entry));
11343 
11344   gtk_widget_show (tree_view->priv->search_window);
11345   if (tree_view->priv->search_entry_changed_id == 0)
11346     {
11347       tree_view->priv->search_entry_changed_id =
11348 	g_signal_connect (tree_view->priv->search_entry, "changed",
11349 			  G_CALLBACK (gtk_tree_view_search_init),
11350 			  tree_view);
11351     }
11352 
11353   tree_view->priv->typeselect_flush_timeout =
11354     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
11355 		   (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
11356 		   tree_view);
11357   g_source_set_name_by_id (tree_view->priv->typeselect_flush_timeout, "[gtk+] gtk_tree_view_search_entry_flush_timeout");
11358 
11359   /* send focus-in event */
11360   send_focus_change (tree_view->priv->search_entry, device, TRUE);
11361 
11362   /* search first matching iter */
11363   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
11364 
11365   return TRUE;
11366 }
11367 
11368 static gboolean
gtk_tree_view_start_interactive_search(GtkTreeView * tree_view)11369 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
11370 {
11371   return gtk_tree_view_real_start_interactive_search (tree_view,
11372                                                       gtk_get_current_event_device (),
11373                                                       TRUE);
11374 }
11375 
11376 /* Callbacks */
11377 static void
gtk_tree_view_adjustment_changed(GtkAdjustment * adjustment,GtkTreeView * tree_view)11378 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
11379 				  GtkTreeView   *tree_view)
11380 {
11381   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11382     {
11383       gint dy;
11384 
11385       gdk_window_move (tree_view->priv->bin_window,
11386 		       - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11387 		       gtk_tree_view_get_effective_header_height (tree_view));
11388       gdk_window_move (tree_view->priv->header_window,
11389 		       - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11390 		       0);
11391       dy = tree_view->priv->dy - (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11392       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
11393 
11394       if (dy != 0)
11395         {
11396           /* update our dy and top_row */
11397           tree_view->priv->dy = (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11398 
11399           update_prelight (tree_view,
11400                            tree_view->priv->event_last_x,
11401                            tree_view->priv->event_last_y);
11402 
11403           if (!tree_view->priv->in_top_row_to_dy)
11404             gtk_tree_view_dy_to_top_row (tree_view);
11405 
11406         }
11407     }
11408 }
11409 
11410 
11411 
11412 /* Public methods
11413  */
11414 
11415 /**
11416  * gtk_tree_view_new:
11417  *
11418  * Creates a new #GtkTreeView widget.
11419  *
11420  * Returns: A newly created #GtkTreeView widget.
11421  **/
11422 GtkWidget *
gtk_tree_view_new(void)11423 gtk_tree_view_new (void)
11424 {
11425   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
11426 }
11427 
11428 /**
11429  * gtk_tree_view_new_with_model:
11430  * @model: the model.
11431  *
11432  * Creates a new #GtkTreeView widget with the model initialized to @model.
11433  *
11434  * Returns: A newly created #GtkTreeView widget.
11435  **/
11436 GtkWidget *
gtk_tree_view_new_with_model(GtkTreeModel * model)11437 gtk_tree_view_new_with_model (GtkTreeModel *model)
11438 {
11439   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
11440 }
11441 
11442 /* Public Accessors
11443  */
11444 
11445 /**
11446  * gtk_tree_view_get_model:
11447  * @tree_view: a #GtkTreeView
11448  *
11449  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
11450  * model is unset.
11451  *
11452  * Returns: (transfer none) (nullable): A #GtkTreeModel, or %NULL if
11453  * none is currently being used.
11454  **/
11455 GtkTreeModel *
gtk_tree_view_get_model(GtkTreeView * tree_view)11456 gtk_tree_view_get_model (GtkTreeView *tree_view)
11457 {
11458   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11459 
11460   return tree_view->priv->model;
11461 }
11462 
11463 /**
11464  * gtk_tree_view_set_model:
11465  * @tree_view: A #GtkTreeView.
11466  * @model: (allow-none): The model.
11467  *
11468  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
11469  * set, it will remove it before setting the new model.  If @model is %NULL,
11470  * then it will unset the old model.
11471  **/
11472 void
gtk_tree_view_set_model(GtkTreeView * tree_view,GtkTreeModel * model)11473 gtk_tree_view_set_model (GtkTreeView  *tree_view,
11474 			 GtkTreeModel *model)
11475 {
11476   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11477   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
11478 
11479   if (model == tree_view->priv->model)
11480     return;
11481 
11482   if (tree_view->priv->scroll_to_path)
11483     {
11484       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11485       tree_view->priv->scroll_to_path = NULL;
11486     }
11487 
11488   if (tree_view->priv->rubber_band_status)
11489     gtk_tree_view_stop_rubber_band (tree_view);
11490 
11491   if (tree_view->priv->model)
11492     {
11493       GList *tmplist = tree_view->priv->columns;
11494 
11495       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
11496       gtk_tree_view_stop_editing (tree_view, TRUE);
11497 
11498       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11499 					    gtk_tree_view_row_changed,
11500 					    tree_view);
11501       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11502 					    gtk_tree_view_row_inserted,
11503 					    tree_view);
11504       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11505 					    gtk_tree_view_row_has_child_toggled,
11506 					    tree_view);
11507       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11508 					    gtk_tree_view_row_deleted,
11509 					    tree_view);
11510       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11511 					    gtk_tree_view_rows_reordered,
11512 					    tree_view);
11513 
11514       for (; tmplist; tmplist = tmplist->next)
11515 	_gtk_tree_view_column_unset_model (tmplist->data,
11516 					   tree_view->priv->model);
11517 
11518       if (tree_view->priv->tree)
11519 	gtk_tree_view_free_rbtree (tree_view);
11520 
11521       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
11522       tree_view->priv->drag_dest_row = NULL;
11523       gtk_tree_row_reference_free (tree_view->priv->anchor);
11524       tree_view->priv->anchor = NULL;
11525       gtk_tree_row_reference_free (tree_view->priv->top_row);
11526       tree_view->priv->top_row = NULL;
11527       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11528       tree_view->priv->scroll_to_path = NULL;
11529 
11530       tree_view->priv->scroll_to_column = NULL;
11531 
11532       g_object_unref (tree_view->priv->model);
11533 
11534       tree_view->priv->search_column = -1;
11535       tree_view->priv->fixed_height_check = 0;
11536       tree_view->priv->fixed_height = -1;
11537       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
11538     }
11539 
11540   tree_view->priv->model = model;
11541 
11542   if (tree_view->priv->model)
11543     {
11544       gint i;
11545       GtkTreePath *path;
11546       GtkTreeIter iter;
11547       GtkTreeModelFlags flags;
11548 
11549       if (tree_view->priv->search_column == -1)
11550 	{
11551 	  for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
11552 	    {
11553 	      GType type = gtk_tree_model_get_column_type (model, i);
11554 
11555 	      if (g_value_type_transformable (type, G_TYPE_STRING))
11556 		{
11557 		  tree_view->priv->search_column = i;
11558 		  break;
11559 		}
11560 	    }
11561 	}
11562 
11563       g_object_ref (tree_view->priv->model);
11564       g_signal_connect (tree_view->priv->model,
11565 			"row-changed",
11566 			G_CALLBACK (gtk_tree_view_row_changed),
11567 			tree_view);
11568       g_signal_connect (tree_view->priv->model,
11569 			"row-inserted",
11570 			G_CALLBACK (gtk_tree_view_row_inserted),
11571 			tree_view);
11572       g_signal_connect (tree_view->priv->model,
11573 			"row-has-child-toggled",
11574 			G_CALLBACK (gtk_tree_view_row_has_child_toggled),
11575 			tree_view);
11576       g_signal_connect (tree_view->priv->model,
11577 			"row-deleted",
11578 			G_CALLBACK (gtk_tree_view_row_deleted),
11579 			tree_view);
11580       g_signal_connect (tree_view->priv->model,
11581 			"rows-reordered",
11582 			G_CALLBACK (gtk_tree_view_rows_reordered),
11583 			tree_view);
11584 
11585       flags = gtk_tree_model_get_flags (tree_view->priv->model);
11586       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
11587         tree_view->priv->is_list = TRUE;
11588       else
11589         tree_view->priv->is_list = FALSE;
11590 
11591       path = gtk_tree_path_new_first ();
11592       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
11593 	{
11594 	  tree_view->priv->tree = _gtk_rbtree_new ();
11595 	  gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
11596           _gtk_tree_view_accessible_add (tree_view, tree_view->priv->tree, NULL);
11597 	}
11598       gtk_tree_path_free (path);
11599 
11600       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
11601       install_presize_handler (tree_view);
11602     }
11603 
11604   gtk_tree_view_real_set_cursor (tree_view, NULL, CURSOR_INVALID);
11605 
11606   g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_MODEL]);
11607 
11608   if (tree_view->priv->selection)
11609   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
11610 
11611   if (tree_view->priv->pixel_cache != NULL)
11612     _gtk_pixel_cache_set_always_cache (tree_view->priv->pixel_cache, (model != NULL));
11613 
11614   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11615     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11616 }
11617 
11618 /**
11619  * gtk_tree_view_get_selection:
11620  * @tree_view: A #GtkTreeView.
11621  *
11622  * Gets the #GtkTreeSelection associated with @tree_view.
11623  *
11624  * Returns: (transfer none): A #GtkTreeSelection object.
11625  **/
11626 GtkTreeSelection *
gtk_tree_view_get_selection(GtkTreeView * tree_view)11627 gtk_tree_view_get_selection (GtkTreeView *tree_view)
11628 {
11629   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11630 
11631   return tree_view->priv->selection;
11632 }
11633 
11634 /**
11635  * gtk_tree_view_get_hadjustment:
11636  * @tree_view: A #GtkTreeView
11637  *
11638  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
11639  *
11640  * Returns: (transfer none): A #GtkAdjustment object, or %NULL
11641  *     if none is currently being used.
11642  *
11643  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
11644  **/
11645 GtkAdjustment *
gtk_tree_view_get_hadjustment(GtkTreeView * tree_view)11646 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
11647 {
11648   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11649 
11650   return gtk_tree_view_do_get_hadjustment (tree_view);
11651 }
11652 
11653 static GtkAdjustment *
gtk_tree_view_do_get_hadjustment(GtkTreeView * tree_view)11654 gtk_tree_view_do_get_hadjustment (GtkTreeView *tree_view)
11655 {
11656   return tree_view->priv->hadjustment;
11657 }
11658 
11659 /**
11660  * gtk_tree_view_set_hadjustment:
11661  * @tree_view: A #GtkTreeView
11662  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11663  *
11664  * Sets the #GtkAdjustment for the current horizontal aspect.
11665  *
11666  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
11667  **/
11668 void
gtk_tree_view_set_hadjustment(GtkTreeView * tree_view,GtkAdjustment * adjustment)11669 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
11670                                GtkAdjustment *adjustment)
11671 {
11672   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11673   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11674 
11675   gtk_tree_view_do_set_hadjustment (tree_view, adjustment);
11676 }
11677 
11678 static void
gtk_tree_view_do_set_hadjustment(GtkTreeView * tree_view,GtkAdjustment * adjustment)11679 gtk_tree_view_do_set_hadjustment (GtkTreeView   *tree_view,
11680                                   GtkAdjustment *adjustment)
11681 {
11682   GtkTreeViewPrivate *priv = tree_view->priv;
11683 
11684   if (adjustment && priv->hadjustment == adjustment)
11685     return;
11686 
11687   if (priv->hadjustment != NULL)
11688     {
11689       g_signal_handlers_disconnect_by_func (priv->hadjustment,
11690                                             gtk_tree_view_adjustment_changed,
11691                                             tree_view);
11692       g_object_unref (priv->hadjustment);
11693     }
11694 
11695   if (adjustment == NULL)
11696     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11697                                      0.0, 0.0, 0.0);
11698 
11699   g_signal_connect (adjustment, "value-changed",
11700                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11701   priv->hadjustment = g_object_ref_sink (adjustment);
11702   /* FIXME: Adjustment should probably be populated here with fresh values, but
11703    * internal details are too complicated for me to decipher right now.
11704    */
11705   gtk_tree_view_adjustment_changed (NULL, tree_view);
11706 
11707   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11708 }
11709 
11710 /**
11711  * gtk_tree_view_get_vadjustment:
11712  * @tree_view: A #GtkTreeView
11713  *
11714  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11715  *
11716  * Returns: (transfer none): A #GtkAdjustment object, or %NULL
11717  *     if none is currently being used.
11718  *
11719  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
11720  **/
11721 GtkAdjustment *
gtk_tree_view_get_vadjustment(GtkTreeView * tree_view)11722 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11723 {
11724   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11725 
11726   return gtk_tree_view_do_get_vadjustment (tree_view);
11727 }
11728 
11729 static GtkAdjustment *
gtk_tree_view_do_get_vadjustment(GtkTreeView * tree_view)11730 gtk_tree_view_do_get_vadjustment (GtkTreeView *tree_view)
11731 {
11732   return tree_view->priv->vadjustment;
11733 }
11734 
11735 /**
11736  * gtk_tree_view_set_vadjustment:
11737  * @tree_view: A #GtkTreeView
11738  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11739  *
11740  * Sets the #GtkAdjustment for the current vertical aspect.
11741  *
11742  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
11743  **/
11744 void
gtk_tree_view_set_vadjustment(GtkTreeView * tree_view,GtkAdjustment * adjustment)11745 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
11746                                GtkAdjustment *adjustment)
11747 {
11748   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11749   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11750 
11751   gtk_tree_view_do_set_vadjustment (tree_view, adjustment);
11752 }
11753 
11754 static void
gtk_tree_view_do_set_vadjustment(GtkTreeView * tree_view,GtkAdjustment * adjustment)11755 gtk_tree_view_do_set_vadjustment (GtkTreeView   *tree_view,
11756                                   GtkAdjustment *adjustment)
11757 {
11758   GtkTreeViewPrivate *priv = tree_view->priv;
11759 
11760   if (adjustment && priv->vadjustment == adjustment)
11761     return;
11762 
11763   if (priv->vadjustment != NULL)
11764     {
11765       g_signal_handlers_disconnect_by_func (priv->vadjustment,
11766                                             gtk_tree_view_adjustment_changed,
11767                                             tree_view);
11768       g_object_unref (priv->vadjustment);
11769     }
11770 
11771   if (adjustment == NULL)
11772     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11773                                      0.0, 0.0, 0.0);
11774 
11775   g_signal_connect (adjustment, "value-changed",
11776                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11777   priv->vadjustment = g_object_ref_sink (adjustment);
11778   /* FIXME: Adjustment should probably be populated here with fresh values, but
11779    * internal details are too complicated for me to decipher right now.
11780    */
11781   gtk_tree_view_adjustment_changed (NULL, tree_view);
11782   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11783 }
11784 
11785 /* Column and header operations */
11786 
11787 /**
11788  * gtk_tree_view_get_headers_visible:
11789  * @tree_view: A #GtkTreeView.
11790  *
11791  * Returns %TRUE if the headers on the @tree_view are visible.
11792  *
11793  * Returns: Whether the headers are visible or not.
11794  **/
11795 gboolean
gtk_tree_view_get_headers_visible(GtkTreeView * tree_view)11796 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11797 {
11798   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11799 
11800   return tree_view->priv->headers_visible;
11801 }
11802 
11803 /**
11804  * gtk_tree_view_set_headers_visible:
11805  * @tree_view: A #GtkTreeView.
11806  * @headers_visible: %TRUE if the headers are visible
11807  *
11808  * Sets the visibility state of the headers.
11809  **/
11810 void
gtk_tree_view_set_headers_visible(GtkTreeView * tree_view,gboolean headers_visible)11811 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11812 				   gboolean     headers_visible)
11813 {
11814   gint x, y;
11815   GList *list;
11816   GtkTreeViewColumn *column;
11817   GtkAllocation allocation;
11818   GtkWidget *button;
11819 
11820   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11821 
11822   headers_visible = !! headers_visible;
11823 
11824   if (tree_view->priv->headers_visible == headers_visible)
11825     return;
11826 
11827   tree_view->priv->headers_visible = headers_visible == TRUE;
11828 
11829   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11830     {
11831       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11832       if (headers_visible)
11833 	{
11834           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11835 	  gdk_window_move_resize (tree_view->priv->bin_window,
11836                                   x, y  + gtk_tree_view_get_effective_header_height (tree_view),
11837                                   tree_view->priv->width, allocation.height -  + gtk_tree_view_get_effective_header_height (tree_view));
11838 
11839           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11840             gtk_tree_view_map_buttons (tree_view);
11841  	}
11842       else
11843 	{
11844 	  gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, gtk_tree_view_get_height (tree_view));
11845 
11846 	  for (list = tree_view->priv->columns; list; list = list->next)
11847 	    {
11848 	      column = list->data;
11849 	      button = gtk_tree_view_column_get_button (column);
11850 
11851               gtk_widget_hide (button);
11852 	      gtk_widget_unmap (button);
11853 	    }
11854 	  gdk_window_hide (tree_view->priv->header_window);
11855 	}
11856     }
11857 
11858   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11859   gtk_adjustment_configure (tree_view->priv->vadjustment,
11860                             gtk_adjustment_get_value (tree_view->priv->vadjustment),
11861                             0,
11862                             gtk_tree_view_get_height (tree_view),
11863                             gtk_adjustment_get_step_increment (tree_view->priv->vadjustment),
11864                             (allocation.height - gtk_tree_view_get_effective_header_height (tree_view)) / 2,
11865                             allocation.height - gtk_tree_view_get_effective_header_height (tree_view));
11866 
11867   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11868 
11869   g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_HEADERS_VISIBLE]);
11870 }
11871 
11872 /**
11873  * gtk_tree_view_columns_autosize:
11874  * @tree_view: A #GtkTreeView.
11875  *
11876  * Resizes all columns to their optimal width. Only works after the
11877  * treeview has been realized.
11878  **/
11879 void
gtk_tree_view_columns_autosize(GtkTreeView * tree_view)11880 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11881 {
11882   gboolean dirty = FALSE;
11883   GList *list;
11884   GtkTreeViewColumn *column;
11885 
11886   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11887 
11888   for (list = tree_view->priv->columns; list; list = list->next)
11889     {
11890       column = list->data;
11891       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11892 	continue;
11893       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11894       dirty = TRUE;
11895     }
11896 
11897   if (dirty)
11898     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11899 }
11900 
11901 /**
11902  * gtk_tree_view_set_headers_clickable:
11903  * @tree_view: A #GtkTreeView.
11904  * @setting: %TRUE if the columns are clickable.
11905  *
11906  * Allow the column title buttons to be clicked.
11907  **/
11908 void
gtk_tree_view_set_headers_clickable(GtkTreeView * tree_view,gboolean setting)11909 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11910 				     gboolean   setting)
11911 {
11912   GList *list;
11913   gboolean changed = FALSE;
11914 
11915   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11916 
11917   for (list = tree_view->priv->columns; list; list = list->next)
11918     {
11919       if (gtk_tree_view_column_get_clickable (GTK_TREE_VIEW_COLUMN (list->data)) != setting)
11920         {
11921           gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11922           changed = TRUE;
11923         }
11924     }
11925 
11926   if (changed)
11927     g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_HEADERS_CLICKABLE]);
11928 }
11929 
11930 
11931 /**
11932  * gtk_tree_view_get_headers_clickable:
11933  * @tree_view: A #GtkTreeView.
11934  *
11935  * Returns whether all header columns are clickable.
11936  *
11937  * Returns: %TRUE if all header columns are clickable, otherwise %FALSE
11938  *
11939  * Since: 2.10
11940  **/
11941 gboolean
gtk_tree_view_get_headers_clickable(GtkTreeView * tree_view)11942 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11943 {
11944   GList *list;
11945 
11946   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11947 
11948   for (list = tree_view->priv->columns; list; list = list->next)
11949     if (!gtk_tree_view_column_get_clickable (GTK_TREE_VIEW_COLUMN (list->data)))
11950       return FALSE;
11951 
11952   return TRUE;
11953 }
11954 
11955 /**
11956  * gtk_tree_view_set_rules_hint:
11957  * @tree_view: a #GtkTreeView
11958  * @setting: %TRUE if the tree requires reading across rows
11959  *
11960  * Sets a hint for the theme to draw even/odd rows in the @tree_view
11961  * with different colors, also known as "zebra striping".
11962  *
11963  * This function tells the GTK+ theme that the user interface for your
11964  * application requires users to read across tree rows and associate
11965  * cells with one another.
11966  *
11967  * Do not use it just because you prefer the appearance of the ruled
11968  * tree; that’s a question for the theme. Some themes will draw tree
11969  * rows in alternating colors even when rules are turned off, and
11970  * users who prefer that appearance all the time can choose those
11971  * themes. You should call this function only as a semantic hint to
11972  * the theme engine that your tree makes alternating colors useful
11973  * from a functional standpoint (since it has lots of columns,
11974  * generally).
11975  *
11976  * Deprecated: 3.14
11977  */
11978 void
gtk_tree_view_set_rules_hint(GtkTreeView * tree_view,gboolean setting)11979 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11980                               gboolean      setting)
11981 {
11982   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11983 
11984   setting = setting != FALSE;
11985 
11986   if (tree_view->priv->has_rules != setting)
11987     {
11988       tree_view->priv->has_rules = setting;
11989       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11990       g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_RULES_HINT]);
11991     }
11992 }
11993 
11994 /**
11995  * gtk_tree_view_get_rules_hint:
11996  * @tree_view: a #GtkTreeView
11997  *
11998  * Gets the setting set by gtk_tree_view_set_rules_hint().
11999  *
12000  * Returns: %TRUE if the hint is set
12001  *
12002  * Deprecated: 3.14
12003  */
12004 gboolean
gtk_tree_view_get_rules_hint(GtkTreeView * tree_view)12005 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
12006 {
12007   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12008 
12009   return tree_view->priv->has_rules;
12010 }
12011 
12012 
12013 /**
12014  * gtk_tree_view_set_activate_on_single_click:
12015  * @tree_view: a #GtkTreeView
12016  * @single: %TRUE to emit row-activated on a single click
12017  *
12018  * Cause the #GtkTreeView::row-activated signal to be emitted
12019  * on a single click instead of a double click.
12020  *
12021  * Since: 3.8
12022  **/
12023 void
gtk_tree_view_set_activate_on_single_click(GtkTreeView * tree_view,gboolean single)12024 gtk_tree_view_set_activate_on_single_click (GtkTreeView *tree_view,
12025                                             gboolean     single)
12026 {
12027   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12028 
12029   single = single != FALSE;
12030 
12031   if (tree_view->priv->activate_on_single_click == single)
12032     return;
12033 
12034   tree_view->priv->activate_on_single_click = single;
12035   g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_ACTIVATE_ON_SINGLE_CLICK]);
12036 }
12037 
12038 /**
12039  * gtk_tree_view_get_activate_on_single_click:
12040  * @tree_view: a #GtkTreeView
12041  *
12042  * Gets the setting set by gtk_tree_view_set_activate_on_single_click().
12043  *
12044  * Returns: %TRUE if row-activated will be emitted on a single click
12045  *
12046  * Since: 3.8
12047  **/
12048 gboolean
gtk_tree_view_get_activate_on_single_click(GtkTreeView * tree_view)12049 gtk_tree_view_get_activate_on_single_click (GtkTreeView *tree_view)
12050 {
12051   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12052 
12053   return tree_view->priv->activate_on_single_click;
12054 }
12055 
12056 /* Public Column functions
12057  */
12058 
12059 /**
12060  * gtk_tree_view_append_column:
12061  * @tree_view: A #GtkTreeView.
12062  * @column: The #GtkTreeViewColumn to add.
12063  *
12064  * Appends @column to the list of columns. If @tree_view has “fixed_height”
12065  * mode enabled, then @column must have its “sizing” property set to be
12066  * GTK_TREE_VIEW_COLUMN_FIXED.
12067  *
12068  * Returns: The number of columns in @tree_view after appending.
12069  **/
12070 gint
gtk_tree_view_append_column(GtkTreeView * tree_view,GtkTreeViewColumn * column)12071 gtk_tree_view_append_column (GtkTreeView       *tree_view,
12072 			     GtkTreeViewColumn *column)
12073 {
12074   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12075   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
12076   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
12077 
12078   return gtk_tree_view_insert_column (tree_view, column, -1);
12079 }
12080 
12081 /**
12082  * gtk_tree_view_remove_column:
12083  * @tree_view: A #GtkTreeView.
12084  * @column: The #GtkTreeViewColumn to remove.
12085  *
12086  * Removes @column from @tree_view.
12087  *
12088  * Returns: The number of columns in @tree_view after removing.
12089  **/
12090 gint
gtk_tree_view_remove_column(GtkTreeView * tree_view,GtkTreeViewColumn * column)12091 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
12092                              GtkTreeViewColumn *column)
12093 {
12094   guint position;
12095 
12096   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12097   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
12098   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view), -1);
12099 
12100   if (tree_view->priv->focus_column == column)
12101     _gtk_tree_view_set_focus_column (tree_view, NULL);
12102 
12103   if (tree_view->priv->edited_column == column)
12104     {
12105       gtk_tree_view_stop_editing (tree_view, TRUE);
12106 
12107       /* no need to, but just to be sure ... */
12108       tree_view->priv->edited_column = NULL;
12109     }
12110 
12111   if (tree_view->priv->expander_column == column)
12112     tree_view->priv->expander_column = NULL;
12113 
12114   g_signal_handlers_disconnect_by_func (column,
12115                                         G_CALLBACK (column_sizing_notify),
12116                                         tree_view);
12117 
12118   position = g_list_index (tree_view->priv->columns, column);
12119 
12120   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12121     _gtk_tree_view_column_unrealize_button (column);
12122 
12123   _gtk_tree_view_column_unset_tree_view (column);
12124 
12125   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
12126   tree_view->priv->n_columns--;
12127 
12128   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12129     {
12130       GList *list;
12131 
12132       for (list = tree_view->priv->columns; list; list = list->next)
12133 	{
12134 	  GtkTreeViewColumn *tmp_column;
12135 
12136 	  tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
12137 	  if (gtk_tree_view_column_get_visible (tmp_column))
12138             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
12139 	}
12140 
12141       if (tree_view->priv->n_columns == 0 &&
12142 	  gtk_tree_view_get_headers_visible (tree_view))
12143 	gdk_window_hide (tree_view->priv->header_window);
12144 
12145       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12146     }
12147 
12148   _gtk_tree_view_accessible_remove_column (tree_view, column, position);
12149 
12150   g_object_unref (column);
12151   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12152 
12153   return tree_view->priv->n_columns;
12154 }
12155 
12156 /**
12157  * gtk_tree_view_insert_column:
12158  * @tree_view: A #GtkTreeView.
12159  * @column: The #GtkTreeViewColumn to be inserted.
12160  * @position: The position to insert @column in.
12161  *
12162  * This inserts the @column into the @tree_view at @position.  If @position is
12163  * -1, then the column is inserted at the end. If @tree_view has
12164  * “fixed_height” mode enabled, then @column must have its “sizing” property
12165  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
12166  *
12167  * Returns: The number of columns in @tree_view after insertion.
12168  **/
12169 gint
gtk_tree_view_insert_column(GtkTreeView * tree_view,GtkTreeViewColumn * column,gint position)12170 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
12171                              GtkTreeViewColumn *column,
12172                              gint               position)
12173 {
12174   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12175   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
12176   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
12177 
12178   if (tree_view->priv->fixed_height_mode)
12179     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
12180                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
12181 
12182   if (position < 0 || position > tree_view->priv->n_columns)
12183     position = tree_view->priv->n_columns;
12184 
12185   g_object_ref_sink (column);
12186 
12187   if (tree_view->priv->n_columns == 0 &&
12188       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
12189       gtk_tree_view_get_headers_visible (tree_view))
12190     {
12191       gdk_window_show (tree_view->priv->header_window);
12192     }
12193 
12194   g_signal_connect (column, "notify::sizing",
12195                     G_CALLBACK (column_sizing_notify), tree_view);
12196 
12197   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
12198 					    column, position);
12199   tree_view->priv->n_columns++;
12200 
12201   _gtk_tree_view_column_set_tree_view (column, tree_view);
12202 
12203   gtk_tree_view_update_button_position (tree_view, column);
12204 
12205   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12206     {
12207       GList *list;
12208 
12209       _gtk_tree_view_column_realize_button (column);
12210 
12211       for (list = tree_view->priv->columns; list; list = list->next)
12212 	{
12213 	  column = GTK_TREE_VIEW_COLUMN (list->data);
12214 	  if (gtk_tree_view_column_get_visible (column))
12215             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12216 	}
12217       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12218     }
12219 
12220   _gtk_tree_view_accessible_add_column (tree_view, column, position);
12221 
12222   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12223 
12224   return tree_view->priv->n_columns;
12225 }
12226 
12227 /**
12228  * gtk_tree_view_insert_column_with_attributes:
12229  * @tree_view: A #GtkTreeView
12230  * @position: The position to insert the new column in
12231  * @title: The title to set the header to
12232  * @cell: The #GtkCellRenderer
12233  * @...: A %NULL-terminated list of attributes
12234  *
12235  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
12236  * @position.  If @position is -1, then the newly created column is inserted at
12237  * the end.  The column is initialized with the attributes given. If @tree_view
12238  * has “fixed_height” mode enabled, then the new column will have its sizing
12239  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12240  *
12241  * Returns: The number of columns in @tree_view after insertion.
12242  **/
12243 gint
gtk_tree_view_insert_column_with_attributes(GtkTreeView * tree_view,gint position,const gchar * title,GtkCellRenderer * cell,...)12244 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
12245 					     gint             position,
12246 					     const gchar     *title,
12247 					     GtkCellRenderer *cell,
12248 					     ...)
12249 {
12250   GtkTreeViewColumn *column;
12251   gchar *attribute;
12252   va_list args;
12253   gint column_id;
12254 
12255   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12256 
12257   column = gtk_tree_view_column_new ();
12258   if (tree_view->priv->fixed_height_mode)
12259     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12260 
12261   gtk_tree_view_column_set_title (column, title);
12262   gtk_tree_view_column_pack_start (column, cell, TRUE);
12263 
12264   va_start (args, cell);
12265 
12266   attribute = va_arg (args, gchar *);
12267 
12268   while (attribute != NULL)
12269     {
12270       column_id = va_arg (args, gint);
12271       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
12272       attribute = va_arg (args, gchar *);
12273     }
12274 
12275   va_end (args);
12276 
12277   return gtk_tree_view_insert_column (tree_view, column, position);
12278 }
12279 
12280 /**
12281  * gtk_tree_view_insert_column_with_data_func:
12282  * @tree_view: a #GtkTreeView
12283  * @position: Position to insert, -1 for append
12284  * @title: column title
12285  * @cell: cell renderer for column
12286  * @func: function to set attributes of cell renderer
12287  * @data: data for @func
12288  * @dnotify: destroy notifier for @data
12289  *
12290  * Convenience function that inserts a new column into the #GtkTreeView
12291  * with the given cell renderer and a #GtkTreeCellDataFunc to set cell renderer
12292  * attributes (normally using data from the model). See also
12293  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
12294  * If @tree_view has “fixed_height” mode enabled, then the new column will have its
12295  * “sizing” property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12296  *
12297  * Returns: number of columns in the tree view post-insert
12298  **/
12299 gint
gtk_tree_view_insert_column_with_data_func(GtkTreeView * tree_view,gint position,const gchar * title,GtkCellRenderer * cell,GtkTreeCellDataFunc func,gpointer data,GDestroyNotify dnotify)12300 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
12301                                              gint                       position,
12302                                              const gchar               *title,
12303                                              GtkCellRenderer           *cell,
12304                                              GtkTreeCellDataFunc        func,
12305                                              gpointer                   data,
12306                                              GDestroyNotify             dnotify)
12307 {
12308   GtkTreeViewColumn *column;
12309 
12310   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12311 
12312   column = gtk_tree_view_column_new ();
12313   if (tree_view->priv->fixed_height_mode)
12314     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12315 
12316   gtk_tree_view_column_set_title (column, title);
12317   gtk_tree_view_column_pack_start (column, cell, TRUE);
12318   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
12319 
12320   return gtk_tree_view_insert_column (tree_view, column, position);
12321 }
12322 
12323 /**
12324  * gtk_tree_view_get_n_columns:
12325  * @tree_view: a #GtkTreeView
12326  *
12327  * Queries the number of columns in the given @tree_view.
12328  *
12329  * Returns: The number of columns in the @tree_view
12330  *
12331  * Since: 3.4
12332  **/
12333 guint
gtk_tree_view_get_n_columns(GtkTreeView * tree_view)12334 gtk_tree_view_get_n_columns (GtkTreeView *tree_view)
12335 {
12336   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
12337 
12338   return tree_view->priv->n_columns;
12339 }
12340 
12341 /**
12342  * gtk_tree_view_get_column:
12343  * @tree_view: A #GtkTreeView.
12344  * @n: The position of the column, counting from 0.
12345  *
12346  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
12347  *
12348  * Returns: (nullable) (transfer none): The #GtkTreeViewColumn, or %NULL if the
12349  * position is outside the range of columns.
12350  **/
12351 GtkTreeViewColumn *
gtk_tree_view_get_column(GtkTreeView * tree_view,gint n)12352 gtk_tree_view_get_column (GtkTreeView *tree_view,
12353 			  gint         n)
12354 {
12355   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12356 
12357   if (n < 0 || n >= tree_view->priv->n_columns)
12358     return NULL;
12359 
12360   if (tree_view->priv->columns == NULL)
12361     return NULL;
12362 
12363   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
12364 }
12365 
12366 /**
12367  * gtk_tree_view_get_columns:
12368  * @tree_view: A #GtkTreeView
12369  *
12370  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
12371  * The returned list must be freed with g_list_free ().
12372  *
12373  * Returns: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
12374  **/
12375 GList *
gtk_tree_view_get_columns(GtkTreeView * tree_view)12376 gtk_tree_view_get_columns (GtkTreeView *tree_view)
12377 {
12378   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12379 
12380   return g_list_copy (tree_view->priv->columns);
12381 }
12382 
12383 /**
12384  * gtk_tree_view_move_column_after:
12385  * @tree_view: A #GtkTreeView
12386  * @column: The #GtkTreeViewColumn to be moved.
12387  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
12388  *
12389  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
12390  * @column is placed in the first position.
12391  **/
12392 void
gtk_tree_view_move_column_after(GtkTreeView * tree_view,GtkTreeViewColumn * column,GtkTreeViewColumn * base_column)12393 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
12394 				 GtkTreeViewColumn *column,
12395 				 GtkTreeViewColumn *base_column)
12396 {
12397   GList *column_list_el, *base_el = NULL;
12398 
12399   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12400 
12401   column_list_el = g_list_find (tree_view->priv->columns, column);
12402   g_return_if_fail (column_list_el != NULL);
12403 
12404   if (base_column)
12405     {
12406       base_el = g_list_find (tree_view->priv->columns, base_column);
12407       g_return_if_fail (base_el != NULL);
12408     }
12409 
12410   if (column_list_el->prev == base_el)
12411     return;
12412 
12413   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
12414   if (base_el == NULL)
12415     {
12416       column_list_el->prev = NULL;
12417       column_list_el->next = tree_view->priv->columns;
12418       if (column_list_el->next)
12419 	column_list_el->next->prev = column_list_el;
12420       tree_view->priv->columns = column_list_el;
12421     }
12422   else
12423     {
12424       column_list_el->prev = base_el;
12425       column_list_el->next = base_el->next;
12426       if (column_list_el->next)
12427 	column_list_el->next->prev = column_list_el;
12428       base_el->next = column_list_el;
12429     }
12430 
12431   gtk_tree_view_update_button_position (tree_view, column);
12432 
12433   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12434     {
12435       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12436       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
12437     }
12438 
12439   _gtk_tree_view_accessible_reorder_column (tree_view, column);
12440 
12441   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12442 }
12443 
12444 /**
12445  * gtk_tree_view_set_expander_column:
12446  * @tree_view: A #GtkTreeView
12447  * @column: (nullable): %NULL, or the column to draw the expander arrow at.
12448  *
12449  * Sets the column to draw the expander arrow at. It must be in @tree_view.
12450  * If @column is %NULL, then the expander arrow is always at the first
12451  * visible column.
12452  *
12453  * If you do not want expander arrow to appear in your tree, set the
12454  * expander column to a hidden column.
12455  **/
12456 void
gtk_tree_view_set_expander_column(GtkTreeView * tree_view,GtkTreeViewColumn * column)12457 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
12458                                    GtkTreeViewColumn *column)
12459 {
12460   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12461   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12462   g_return_if_fail (column == NULL || gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view));
12463 
12464   if (tree_view->priv->expander_column != column)
12465     {
12466       tree_view->priv->expander_column = column;
12467       g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_EXPANDER_COLUMN]);
12468     }
12469 }
12470 
12471 /**
12472  * gtk_tree_view_get_expander_column:
12473  * @tree_view: A #GtkTreeView
12474  *
12475  * Returns the column that is the current expander column.
12476  * This column has the expander arrow drawn next to it.
12477  *
12478  * Returns: (transfer none): The expander column.
12479  **/
12480 GtkTreeViewColumn *
gtk_tree_view_get_expander_column(GtkTreeView * tree_view)12481 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
12482 {
12483   GList *list;
12484 
12485   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12486 
12487   for (list = tree_view->priv->columns; list; list = list->next)
12488     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
12489       return (GtkTreeViewColumn *) list->data;
12490   return NULL;
12491 }
12492 
12493 
12494 /**
12495  * gtk_tree_view_set_column_drag_function:
12496  * @tree_view: A #GtkTreeView.
12497  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
12498  * @user_data: (allow-none): User data to be passed to @func, or %NULL
12499  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
12500  *
12501  * Sets a user function for determining where a column may be dropped when
12502  * dragged.  This function is called on every column pair in turn at the
12503  * beginning of a column drag to determine where a drop can take place.  The
12504  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
12505  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
12506  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
12507  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
12508  * @tree_view reverts to the default behavior of allowing all columns to be
12509  * dropped everywhere.
12510  **/
12511 void
gtk_tree_view_set_column_drag_function(GtkTreeView * tree_view,GtkTreeViewColumnDropFunc func,gpointer user_data,GDestroyNotify destroy)12512 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
12513 					GtkTreeViewColumnDropFunc  func,
12514 					gpointer                   user_data,
12515 					GDestroyNotify             destroy)
12516 {
12517   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12518 
12519   if (tree_view->priv->column_drop_func_data_destroy)
12520     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
12521 
12522   tree_view->priv->column_drop_func = func;
12523   tree_view->priv->column_drop_func_data = user_data;
12524   tree_view->priv->column_drop_func_data_destroy = destroy;
12525 }
12526 
12527 /**
12528  * gtk_tree_view_scroll_to_point:
12529  * @tree_view: a #GtkTreeView
12530  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
12531  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
12532  *
12533  * Scrolls the tree view such that the top-left corner of the visible
12534  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
12535  * in tree coordinates.  The @tree_view must be realized before
12536  * this function is called.  If it isn't, you probably want to be
12537  * using gtk_tree_view_scroll_to_cell().
12538  *
12539  * If either @tree_x or @tree_y are -1, then that direction isn’t scrolled.
12540  **/
12541 void
gtk_tree_view_scroll_to_point(GtkTreeView * tree_view,gint tree_x,gint tree_y)12542 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
12543                                gint         tree_x,
12544                                gint         tree_y)
12545 {
12546   GtkAdjustment *hadj;
12547   GtkAdjustment *vadj;
12548 
12549   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12550   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12551 
12552   hadj = tree_view->priv->hadjustment;
12553   vadj = tree_view->priv->vadjustment;
12554 
12555   if (tree_x != -1)
12556     gtk_adjustment_animate_to_value (hadj, tree_x);
12557   if (tree_y != -1)
12558     gtk_adjustment_animate_to_value (vadj, tree_y);
12559 }
12560 
12561 /**
12562  * gtk_tree_view_scroll_to_cell:
12563  * @tree_view: A #GtkTreeView.
12564  * @path: (allow-none): The path of the row to move to, or %NULL.
12565  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
12566  * @use_align: whether to use alignment arguments, or %FALSE.
12567  * @row_align: The vertical alignment of the row specified by @path.
12568  * @col_align: The horizontal alignment of the column specified by @column.
12569  *
12570  * Moves the alignments of @tree_view to the position specified by @column and
12571  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
12572  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
12573  * or @path need to be non-%NULL.  @row_align determines where the row is
12574  * placed, and @col_align determines where @column is placed.  Both are expected
12575  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
12576  * right/bottom alignment, 0.5 means center.
12577  *
12578  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
12579  * tree does the minimum amount of work to scroll the cell onto the screen.
12580  * This means that the cell will be scrolled to the edge closest to its current
12581  * position.  If the cell is currently visible on the screen, nothing is done.
12582  *
12583  * This function only works if the model is set, and @path is a valid row on the
12584  * model.  If the model changes before the @tree_view is realized, the centered
12585  * path will be modified to reflect this change.
12586  **/
12587 void
gtk_tree_view_scroll_to_cell(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,gboolean use_align,gfloat row_align,gfloat col_align)12588 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
12589                               GtkTreePath       *path,
12590                               GtkTreeViewColumn *column,
12591 			      gboolean           use_align,
12592                               gfloat             row_align,
12593                               gfloat             col_align)
12594 {
12595   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12596   g_return_if_fail (tree_view->priv->model != NULL);
12597   g_return_if_fail (tree_view->priv->tree != NULL);
12598   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
12599   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
12600   g_return_if_fail (path != NULL || column != NULL);
12601 
12602   row_align = CLAMP (row_align, 0.0, 1.0);
12603   col_align = CLAMP (col_align, 0.0, 1.0);
12604 
12605 
12606   /* Note: Despite the benefits that come from having one code path for the
12607    * scrolling code, we short-circuit validate_visible_area's immplementation as
12608    * it is much slower than just going to the point.
12609    */
12610   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
12611       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
12612       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
12613       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
12614     {
12615       if (tree_view->priv->scroll_to_path)
12616 	gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
12617 
12618       tree_view->priv->scroll_to_path = NULL;
12619       tree_view->priv->scroll_to_column = NULL;
12620 
12621       if (path)
12622 	tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
12623       if (column)
12624 	tree_view->priv->scroll_to_column = column;
12625       tree_view->priv->scroll_to_use_align = use_align;
12626       tree_view->priv->scroll_to_row_align = row_align;
12627       tree_view->priv->scroll_to_col_align = col_align;
12628 
12629       install_presize_handler (tree_view);
12630     }
12631   else
12632     {
12633       GdkRectangle cell_rect;
12634       GdkRectangle vis_rect;
12635       gint dest_x, dest_y;
12636 
12637       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
12638       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
12639 
12640       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
12641 
12642       dest_x = vis_rect.x;
12643       dest_y = vis_rect.y;
12644 
12645       if (column)
12646 	{
12647 	  if (use_align)
12648 	    {
12649 	      dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
12650 	    }
12651 	  else
12652 	    {
12653 	      if (cell_rect.x < vis_rect.x)
12654 		dest_x = cell_rect.x;
12655 	      if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
12656 		dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
12657 	    }
12658 	}
12659 
12660       if (path)
12661 	{
12662 	  if (use_align)
12663 	    {
12664 	      dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
12665 	      dest_y = MAX (dest_y, 0);
12666 	    }
12667 	  else
12668 	    {
12669 	      if (cell_rect.y < vis_rect.y)
12670 		dest_y = cell_rect.y;
12671 	      if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
12672 		dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
12673 	    }
12674 	}
12675 
12676       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
12677     }
12678 }
12679 
12680 /**
12681  * gtk_tree_view_row_activated:
12682  * @tree_view: A #GtkTreeView
12683  * @path: The #GtkTreePath to be activated.
12684  * @column: The #GtkTreeViewColumn to be activated.
12685  *
12686  * Activates the cell determined by @path and @column.
12687  **/
12688 void
gtk_tree_view_row_activated(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column)12689 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
12690 			     GtkTreePath       *path,
12691 			     GtkTreeViewColumn *column)
12692 {
12693   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12694 
12695   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
12696 }
12697 
12698 
12699 static void
gtk_tree_view_expand_all_emission_helper(GtkRBTree * tree,GtkRBNode * node,gpointer data)12700 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
12701                                           GtkRBNode *node,
12702                                           gpointer   data)
12703 {
12704   GtkTreeView *tree_view = data;
12705 
12706   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
12707       node->children)
12708     {
12709       GtkTreePath *path;
12710       GtkTreeIter iter;
12711 
12712       path = _gtk_tree_path_new_from_rbtree (tree, node);
12713       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12714 
12715       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12716 
12717       gtk_tree_path_free (path);
12718     }
12719 
12720   if (node->children)
12721     _gtk_rbtree_traverse (node->children,
12722                           node->children->root,
12723                           G_PRE_ORDER,
12724                           gtk_tree_view_expand_all_emission_helper,
12725                           tree_view);
12726 }
12727 
12728 /**
12729  * gtk_tree_view_expand_all:
12730  * @tree_view: A #GtkTreeView.
12731  *
12732  * Recursively expands all nodes in the @tree_view.
12733  **/
12734 void
gtk_tree_view_expand_all(GtkTreeView * tree_view)12735 gtk_tree_view_expand_all (GtkTreeView *tree_view)
12736 {
12737   GtkTreePath *path;
12738   GtkRBTree *tree;
12739   GtkRBNode *node;
12740 
12741   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12742 
12743   if (tree_view->priv->tree == NULL)
12744     return;
12745 
12746   path = gtk_tree_path_new_first ();
12747   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12748 
12749   while (node)
12750     {
12751       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
12752       node = _gtk_rbtree_next (tree, node);
12753       gtk_tree_path_next (path);
12754   }
12755 
12756   gtk_tree_path_free (path);
12757 }
12758 
12759 /**
12760  * gtk_tree_view_collapse_all:
12761  * @tree_view: A #GtkTreeView.
12762  *
12763  * Recursively collapses all visible, expanded nodes in @tree_view.
12764  **/
12765 void
gtk_tree_view_collapse_all(GtkTreeView * tree_view)12766 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12767 {
12768   GtkRBTree *tree;
12769   GtkRBNode *node;
12770   GtkTreePath *path;
12771   gint *indices;
12772 
12773   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12774 
12775   if (tree_view->priv->tree == NULL)
12776     return;
12777 
12778   path = gtk_tree_path_new ();
12779   gtk_tree_path_down (path);
12780   indices = gtk_tree_path_get_indices (path);
12781 
12782   tree = tree_view->priv->tree;
12783   node = _gtk_rbtree_first (tree);
12784 
12785   while (node)
12786     {
12787       if (node->children)
12788 	gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12789       indices[0]++;
12790       node = _gtk_rbtree_next (tree, node);
12791     }
12792 
12793   gtk_tree_path_free (path);
12794 }
12795 
12796 /**
12797  * gtk_tree_view_expand_to_path:
12798  * @tree_view: A #GtkTreeView.
12799  * @path: path to a row.
12800  *
12801  * Expands the row at @path. This will also expand all parent rows of
12802  * @path as necessary.
12803  *
12804  * Since: 2.2
12805  **/
12806 void
gtk_tree_view_expand_to_path(GtkTreeView * tree_view,GtkTreePath * path)12807 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12808 			      GtkTreePath *path)
12809 {
12810   gint i, depth;
12811   gint *indices;
12812   GtkTreePath *tmp;
12813 
12814   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12815   g_return_if_fail (path != NULL);
12816 
12817   depth = gtk_tree_path_get_depth (path);
12818   indices = gtk_tree_path_get_indices (path);
12819 
12820   tmp = gtk_tree_path_new ();
12821   g_return_if_fail (tmp != NULL);
12822 
12823   for (i = 0; i < depth; i++)
12824     {
12825       gtk_tree_path_append_index (tmp, indices[i]);
12826       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12827     }
12828 
12829   gtk_tree_path_free (tmp);
12830 }
12831 
12832 /* FIXME the bool return values for expand_row and collapse_row are
12833  * not analagous; they should be TRUE if the row had children and
12834  * was not already in the requested state.
12835  */
12836 
12837 
12838 static gboolean
gtk_tree_view_real_expand_row(GtkTreeView * tree_view,GtkTreePath * path,GtkRBTree * tree,GtkRBNode * node,gboolean open_all,gboolean animate)12839 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12840 			       GtkTreePath *path,
12841 			       GtkRBTree   *tree,
12842 			       GtkRBNode   *node,
12843 			       gboolean     open_all,
12844 			       gboolean     animate)
12845 {
12846   GtkTreeIter iter;
12847   GtkTreeIter temp;
12848   gboolean expand;
12849 
12850   if (animate)
12851     animate = gtk_settings_get_enable_animations (gtk_widget_get_settings (GTK_WIDGET (tree_view)));
12852 
12853   remove_auto_expand_timeout (tree_view);
12854 
12855   if (node->children && !open_all)
12856     return FALSE;
12857 
12858   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12859     return FALSE;
12860 
12861   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12862   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12863     return FALSE;
12864 
12865 
12866    if (node->children && open_all)
12867     {
12868       gboolean retval = FALSE;
12869       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12870 
12871       gtk_tree_path_append_index (tmp_path, 0);
12872       tree = node->children;
12873       node = _gtk_rbtree_first (tree);
12874       /* try to expand the children */
12875       do
12876         {
12877          gboolean t;
12878 	 t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12879 					    TRUE, animate);
12880          if (t)
12881            retval = TRUE;
12882 
12883          gtk_tree_path_next (tmp_path);
12884 	 node = _gtk_rbtree_next (tree, node);
12885        }
12886       while (node != NULL);
12887 
12888       gtk_tree_path_free (tmp_path);
12889 
12890       return retval;
12891     }
12892 
12893   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12894 
12895   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12896     return FALSE;
12897 
12898   if (expand)
12899     return FALSE;
12900 
12901   node->children = _gtk_rbtree_new ();
12902   node->children->parent_tree = tree;
12903   node->children->parent_node = node;
12904 
12905   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12906 
12907   gtk_tree_view_build_tree (tree_view,
12908 			    node->children,
12909 			    &temp,
12910 			    gtk_tree_path_get_depth (path) + 1,
12911 			    open_all);
12912 
12913   _gtk_tree_view_accessible_add (tree_view, node->children, NULL);
12914   _gtk_tree_view_accessible_add_state (tree_view,
12915                                        tree, node,
12916                                        GTK_CELL_RENDERER_EXPANDED);
12917 
12918   install_presize_handler (tree_view);
12919 
12920   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12921   if (open_all && node->children)
12922     {
12923       _gtk_rbtree_traverse (node->children,
12924                             node->children->root,
12925                             G_PRE_ORDER,
12926                             gtk_tree_view_expand_all_emission_helper,
12927                             tree_view);
12928     }
12929   return TRUE;
12930 }
12931 
12932 
12933 /**
12934  * gtk_tree_view_expand_row:
12935  * @tree_view: a #GtkTreeView
12936  * @path: path to a row
12937  * @open_all: whether to recursively expand, or just expand immediate children
12938  *
12939  * Opens the row so its children are visible.
12940  *
12941  * Returns: %TRUE if the row existed and had children
12942  **/
12943 gboolean
gtk_tree_view_expand_row(GtkTreeView * tree_view,GtkTreePath * path,gboolean open_all)12944 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12945 			  GtkTreePath *path,
12946 			  gboolean     open_all)
12947 {
12948   GtkRBTree *tree;
12949   GtkRBNode *node;
12950 
12951   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12952   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12953   g_return_val_if_fail (path != NULL, FALSE);
12954 
12955   if (_gtk_tree_view_find_node (tree_view,
12956 				path,
12957 				&tree,
12958 				&node))
12959     return FALSE;
12960 
12961   if (tree != NULL)
12962     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12963   else
12964     return FALSE;
12965 }
12966 
12967 static gboolean
gtk_tree_view_real_collapse_row(GtkTreeView * tree_view,GtkTreePath * path,GtkRBTree * tree,GtkRBNode * node,gboolean animate)12968 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12969 				 GtkTreePath *path,
12970 				 GtkRBTree   *tree,
12971 				 GtkRBNode   *node,
12972 				 gboolean     animate)
12973 {
12974   GtkTreeIter iter;
12975   GtkTreeIter children;
12976   gboolean collapse;
12977   GList *list;
12978   gboolean selection_changed, cursor_changed;
12979 
12980   if (animate)
12981     animate = gtk_settings_get_enable_animations (gtk_widget_get_settings (GTK_WIDGET (tree_view)));
12982 
12983   remove_auto_expand_timeout (tree_view);
12984 
12985   if (node->children == NULL)
12986     return FALSE;
12987   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12988 
12989   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12990 
12991   if (collapse)
12992     return FALSE;
12993 
12994   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12995    * a chance to prelight the correct node below */
12996 
12997   if (tree_view->priv->prelight_tree)
12998     {
12999       GtkRBTree *parent_tree;
13000       GtkRBNode *parent_node;
13001 
13002       parent_tree = tree_view->priv->prelight_tree->parent_tree;
13003       parent_node = tree_view->priv->prelight_tree->parent_node;
13004       while (parent_tree)
13005 	{
13006 	  if (parent_tree == tree && parent_node == node)
13007 	    {
13008 	      ensure_unprelighted (tree_view);
13009 	      break;
13010 	    }
13011 	  parent_node = parent_tree->parent_node;
13012 	  parent_tree = parent_tree->parent_tree;
13013 	}
13014     }
13015 
13016   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
13017 
13018   for (list = tree_view->priv->columns; list; list = list->next)
13019     {
13020       GtkTreeViewColumn *column = list->data;
13021 
13022       if (gtk_tree_view_column_get_visible (column) == FALSE)
13023 	continue;
13024       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
13025 	_gtk_tree_view_column_cell_set_dirty (column, TRUE);
13026     }
13027 
13028   if (tree_view->priv->destroy_count_func)
13029     {
13030       GtkTreePath *child_path;
13031       gint child_count = 0;
13032       child_path = gtk_tree_path_copy (path);
13033       gtk_tree_path_down (child_path);
13034       if (node->children)
13035 	_gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
13036       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
13037       gtk_tree_path_free (child_path);
13038     }
13039 
13040   if (tree_view->priv->cursor_node)
13041     {
13042       cursor_changed = (node->children == tree_view->priv->cursor_tree)
13043                        || _gtk_rbtree_contains (node->children, tree_view->priv->cursor_tree);
13044     }
13045   else
13046     cursor_changed = FALSE;
13047 
13048   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
13049     {
13050       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
13051       if (gtk_tree_path_is_ancestor (path, anchor_path))
13052 	{
13053 	  gtk_tree_row_reference_free (tree_view->priv->anchor);
13054 	  tree_view->priv->anchor = NULL;
13055 	}
13056       gtk_tree_path_free (anchor_path);
13057     }
13058 
13059   selection_changed = gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children);
13060 
13061   /* Stop a pending double click */
13062   gtk_event_controller_reset (GTK_EVENT_CONTROLLER (tree_view->priv->multipress_gesture));
13063 
13064   _gtk_tree_view_accessible_remove (tree_view, node->children, NULL);
13065   _gtk_tree_view_accessible_remove_state (tree_view,
13066                                           tree, node,
13067                                           GTK_CELL_RENDERER_EXPANDED);
13068 
13069   _gtk_rbtree_remove (node->children);
13070 
13071   if (cursor_changed)
13072     gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CURSOR_INVALID);
13073   if (selection_changed)
13074     g_signal_emit_by_name (tree_view->priv->selection, "changed");
13075 
13076   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
13077     {
13078       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
13079     }
13080 
13081   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
13082 
13083   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
13084     update_prelight (tree_view,
13085                      tree_view->priv->event_last_x,
13086                      tree_view->priv->event_last_y);
13087 
13088   return TRUE;
13089 }
13090 
13091 /**
13092  * gtk_tree_view_collapse_row:
13093  * @tree_view: a #GtkTreeView
13094  * @path: path to a row in the @tree_view
13095  *
13096  * Collapses a row (hides its child rows, if they exist).
13097  *
13098  * Returns: %TRUE if the row was collapsed.
13099  **/
13100 gboolean
gtk_tree_view_collapse_row(GtkTreeView * tree_view,GtkTreePath * path)13101 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
13102 			    GtkTreePath *path)
13103 {
13104   GtkRBTree *tree;
13105   GtkRBNode *node;
13106 
13107   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13108   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
13109   g_return_val_if_fail (path != NULL, FALSE);
13110 
13111   if (_gtk_tree_view_find_node (tree_view,
13112 				path,
13113 				&tree,
13114 				&node))
13115     return FALSE;
13116 
13117   if (tree == NULL || node->children == NULL)
13118     return FALSE;
13119 
13120   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
13121 }
13122 
13123 static void
gtk_tree_view_map_expanded_rows_helper(GtkTreeView * tree_view,GtkRBTree * tree,GtkTreePath * path,GtkTreeViewMappingFunc func,gpointer user_data)13124 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
13125 					GtkRBTree              *tree,
13126 					GtkTreePath            *path,
13127 					GtkTreeViewMappingFunc  func,
13128 					gpointer                user_data)
13129 {
13130   GtkRBNode *node;
13131 
13132   if (tree == NULL || tree->root == NULL)
13133     return;
13134 
13135   node = _gtk_rbtree_first (tree);
13136 
13137   while (node)
13138     {
13139       if (node->children)
13140 	{
13141 	  (* func) (tree_view, path, user_data);
13142 	  gtk_tree_path_down (path);
13143 	  gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
13144 	  gtk_tree_path_up (path);
13145 	}
13146       gtk_tree_path_next (path);
13147       node = _gtk_rbtree_next (tree, node);
13148     }
13149 }
13150 
13151 /**
13152  * gtk_tree_view_map_expanded_rows:
13153  * @tree_view: A #GtkTreeView
13154  * @func: (scope call): A function to be called
13155  * @data: User data to be passed to the function.
13156  *
13157  * Calls @func on all expanded rows.
13158  **/
13159 void
gtk_tree_view_map_expanded_rows(GtkTreeView * tree_view,GtkTreeViewMappingFunc func,gpointer user_data)13160 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
13161 				 GtkTreeViewMappingFunc  func,
13162 				 gpointer                user_data)
13163 {
13164   GtkTreePath *path;
13165 
13166   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13167   g_return_if_fail (func != NULL);
13168 
13169   path = gtk_tree_path_new_first ();
13170 
13171   gtk_tree_view_map_expanded_rows_helper (tree_view,
13172 					  tree_view->priv->tree,
13173 					  path, func, user_data);
13174 
13175   gtk_tree_path_free (path);
13176 }
13177 
13178 /**
13179  * gtk_tree_view_row_expanded:
13180  * @tree_view: A #GtkTreeView.
13181  * @path: A #GtkTreePath to test expansion state.
13182  *
13183  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
13184  *
13185  * Returns: %TRUE if #path is expanded.
13186  **/
13187 gboolean
gtk_tree_view_row_expanded(GtkTreeView * tree_view,GtkTreePath * path)13188 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
13189 			    GtkTreePath *path)
13190 {
13191   GtkRBTree *tree;
13192   GtkRBNode *node;
13193 
13194   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13195   g_return_val_if_fail (path != NULL, FALSE);
13196 
13197   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13198 
13199   if (node == NULL)
13200     return FALSE;
13201 
13202   return (node->children != NULL);
13203 }
13204 
13205 /**
13206  * gtk_tree_view_get_reorderable:
13207  * @tree_view: a #GtkTreeView
13208  *
13209  * Retrieves whether the user can reorder the tree via drag-and-drop. See
13210  * gtk_tree_view_set_reorderable().
13211  *
13212  * Returns: %TRUE if the tree can be reordered.
13213  **/
13214 gboolean
gtk_tree_view_get_reorderable(GtkTreeView * tree_view)13215 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
13216 {
13217   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13218 
13219   return tree_view->priv->reorderable;
13220 }
13221 
13222 /**
13223  * gtk_tree_view_set_reorderable:
13224  * @tree_view: A #GtkTreeView.
13225  * @reorderable: %TRUE, if the tree can be reordered.
13226  *
13227  * This function is a convenience function to allow you to reorder
13228  * models that support the #GtkTreeDragSourceIface and the
13229  * #GtkTreeDragDestIface.  Both #GtkTreeStore and #GtkListStore support
13230  * these.  If @reorderable is %TRUE, then the user can reorder the
13231  * model by dragging and dropping rows. The developer can listen to
13232  * these changes by connecting to the model’s #GtkTreeModel::row-inserted
13233  * and #GtkTreeModel::row-deleted signals. The reordering is implemented
13234  * by setting up the tree view as a drag source and destination.
13235  * Therefore, drag and drop can not be used in a reorderable view for any
13236  * other purpose.
13237  *
13238  * This function does not give you any degree of control over the order -- any
13239  * reordering is allowed.  If more control is needed, you should probably
13240  * handle drag and drop manually.
13241  **/
13242 void
gtk_tree_view_set_reorderable(GtkTreeView * tree_view,gboolean reorderable)13243 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
13244 			       gboolean     reorderable)
13245 {
13246   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13247 
13248   reorderable = reorderable != FALSE;
13249 
13250   if (tree_view->priv->reorderable == reorderable)
13251     return;
13252 
13253   if (reorderable)
13254     {
13255       const GtkTargetEntry row_targets[] = {
13256         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
13257       };
13258 
13259       gtk_tree_view_enable_model_drag_source (tree_view,
13260 					      GDK_BUTTON1_MASK,
13261 					      row_targets,
13262 					      G_N_ELEMENTS (row_targets),
13263 					      GDK_ACTION_MOVE);
13264       gtk_tree_view_enable_model_drag_dest (tree_view,
13265 					    row_targets,
13266 					    G_N_ELEMENTS (row_targets),
13267 					    GDK_ACTION_MOVE);
13268     }
13269   else
13270     {
13271       gtk_tree_view_unset_rows_drag_source (tree_view);
13272       gtk_tree_view_unset_rows_drag_dest (tree_view);
13273     }
13274 
13275   tree_view->priv->reorderable = reorderable;
13276 
13277   g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_REORDERABLE]);
13278 }
13279 
13280 static void
gtk_tree_view_real_set_cursor(GtkTreeView * tree_view,GtkTreePath * path,SetCursorFlags flags)13281 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
13282 			       GtkTreePath     *path,
13283                                SetCursorFlags   flags)
13284 {
13285   if (!(flags & CURSOR_INVALID) && tree_view->priv->cursor_node)
13286     {
13287       _gtk_tree_view_accessible_remove_state (tree_view,
13288                                               tree_view->priv->cursor_tree,
13289                                               tree_view->priv->cursor_node,
13290                                               GTK_CELL_RENDERER_FOCUSED);
13291       _gtk_tree_view_queue_draw_node (tree_view,
13292                                       tree_view->priv->cursor_tree,
13293                                       tree_view->priv->cursor_node,
13294                                       NULL);
13295     }
13296 
13297   /* One cannot set the cursor on a separator.   Also, if
13298    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
13299    * before finding the tree and node belonging to path.  The
13300    * path maps to a non-existing path and we will silently bail out.
13301    * We unset tree and node to avoid further processing.
13302    */
13303   if (path == NULL ||
13304       row_is_separator (tree_view, NULL, path)
13305       || _gtk_tree_view_find_node (tree_view,
13306                                    path,
13307                                    &tree_view->priv->cursor_tree,
13308                                    &tree_view->priv->cursor_node))
13309     {
13310       tree_view->priv->cursor_tree = NULL;
13311       tree_view->priv->cursor_node = NULL;
13312     }
13313 
13314   if (tree_view->priv->cursor_node != NULL)
13315     {
13316       GtkRBTree *new_tree = NULL;
13317       GtkRBNode *new_node = NULL;
13318 
13319       if ((flags & CLEAR_AND_SELECT) && !tree_view->priv->modify_selection_pressed)
13320         {
13321           GtkTreeSelectMode mode = 0;
13322 
13323           if (tree_view->priv->extend_selection_pressed)
13324             mode |= GTK_TREE_SELECT_MODE_EXTEND;
13325 
13326           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
13327                                                     tree_view->priv->cursor_node,
13328                                                     tree_view->priv->cursor_tree,
13329                                                     path,
13330                                                     mode,
13331                                                     FALSE);
13332         }
13333 
13334       /* We have to re-find tree and node here again, somebody might have
13335        * cleared the node or the whole tree in the GtkTreeSelection::changed
13336        * callback. If the nodes differ we bail out here.
13337        */
13338       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
13339 
13340       if (tree_view->priv->cursor_node == NULL ||
13341           tree_view->priv->cursor_node != new_node)
13342         return;
13343 
13344       if (flags & CLAMP_NODE)
13345         {
13346 	  gtk_tree_view_clamp_node_visible (tree_view,
13347                                             tree_view->priv->cursor_tree,
13348                                             tree_view->priv->cursor_node);
13349 	  _gtk_tree_view_queue_draw_node (tree_view,
13350                                           tree_view->priv->cursor_tree,
13351                                           tree_view->priv->cursor_node,
13352                                           NULL);
13353 	}
13354 
13355       _gtk_tree_view_accessible_add_state (tree_view,
13356                                            tree_view->priv->cursor_tree,
13357                                            tree_view->priv->cursor_node,
13358                                            GTK_CELL_RENDERER_FOCUSED);
13359     }
13360 
13361   if (!gtk_widget_in_destruction (GTK_WIDGET (tree_view)))
13362     g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
13363 }
13364 
13365 /**
13366  * gtk_tree_view_get_cursor:
13367  * @tree_view: A #GtkTreeView
13368  * @path: (out) (transfer full) (optional) (nullable): A pointer to be
13369  *   filled with the current cursor path, or %NULL
13370  * @focus_column: (out) (transfer none) (optional) (nullable): A
13371  *   pointer to be filled with the current focus column, or %NULL
13372  *
13373  * Fills in @path and @focus_column with the current path and focus column.  If
13374  * the cursor isn’t currently set, then *@path will be %NULL.  If no column
13375  * currently has focus, then *@focus_column will be %NULL.
13376  *
13377  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
13378  * you are done with it.
13379  **/
13380 void
gtk_tree_view_get_cursor(GtkTreeView * tree_view,GtkTreePath ** path,GtkTreeViewColumn ** focus_column)13381 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
13382 			  GtkTreePath       **path,
13383 			  GtkTreeViewColumn **focus_column)
13384 {
13385   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13386 
13387   if (path)
13388     {
13389       if (tree_view->priv->cursor_node)
13390         *path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
13391                                                 tree_view->priv->cursor_node);
13392       else
13393 	*path = NULL;
13394     }
13395 
13396   if (focus_column)
13397     {
13398       *focus_column = tree_view->priv->focus_column;
13399     }
13400 }
13401 
13402 /**
13403  * gtk_tree_view_set_cursor:
13404  * @tree_view: A #GtkTreeView
13405  * @path: A #GtkTreePath
13406  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13407  * @start_editing: %TRUE if the specified cell should start being edited.
13408  *
13409  * Sets the current keyboard focus to be at @path, and selects it.  This is
13410  * useful when you want to focus the user’s attention on a particular row.  If
13411  * @focus_column is not %NULL, then focus is given to the column specified by
13412  * it. Additionally, if @focus_column is specified, and @start_editing is
13413  * %TRUE, then editing should be started in the specified cell.
13414  * This function is often followed by @gtk_widget_grab_focus (@tree_view)
13415  * in order to give keyboard focus to the widget.  Please note that editing
13416  * can only happen when the widget is realized.
13417  *
13418  * If @path is invalid for @model, the current cursor (if any) will be unset
13419  * and the function will return without failing.
13420  **/
13421 void
gtk_tree_view_set_cursor(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * focus_column,gboolean start_editing)13422 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
13423 			  GtkTreePath       *path,
13424 			  GtkTreeViewColumn *focus_column,
13425 			  gboolean           start_editing)
13426 {
13427   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
13428 				    NULL, start_editing);
13429 }
13430 
13431 /**
13432  * gtk_tree_view_set_cursor_on_cell:
13433  * @tree_view: A #GtkTreeView
13434  * @path: A #GtkTreePath
13435  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13436  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
13437  * @start_editing: %TRUE if the specified cell should start being edited.
13438  *
13439  * Sets the current keyboard focus to be at @path, and selects it.  This is
13440  * useful when you want to focus the user’s attention on a particular row.  If
13441  * @focus_column is not %NULL, then focus is given to the column specified by
13442  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
13443  * contains 2 or more editable or activatable cells, then focus is given to
13444  * the cell specified by @focus_cell. Additionally, if @focus_column is
13445  * specified, and @start_editing is %TRUE, then editing should be started in
13446  * the specified cell.  This function is often followed by
13447  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
13448  * widget.  Please note that editing can only happen when the widget is
13449  * realized.
13450  *
13451  * If @path is invalid for @model, the current cursor (if any) will be unset
13452  * and the function will return without failing.
13453  *
13454  * Since: 2.2
13455  **/
13456 void
gtk_tree_view_set_cursor_on_cell(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * focus_column,GtkCellRenderer * focus_cell,gboolean start_editing)13457 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
13458 				  GtkTreePath       *path,
13459 				  GtkTreeViewColumn *focus_column,
13460 				  GtkCellRenderer   *focus_cell,
13461 				  gboolean           start_editing)
13462 {
13463   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13464   g_return_if_fail (path != NULL);
13465   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
13466 
13467   if (!tree_view->priv->model)
13468     return;
13469 
13470   if (focus_cell)
13471     {
13472       g_return_if_fail (focus_column);
13473       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
13474     }
13475 
13476   /* cancel the current editing, if it exists */
13477   if (tree_view->priv->edited_column &&
13478       gtk_cell_area_get_edit_widget
13479       (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column))))
13480     gtk_tree_view_stop_editing (tree_view, TRUE);
13481 
13482   gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CLAMP_NODE);
13483 
13484   if (focus_column &&
13485       gtk_tree_view_column_get_visible (focus_column))
13486     {
13487       GList *list;
13488       gboolean column_in_tree = FALSE;
13489 
13490       for (list = tree_view->priv->columns; list; list = list->next)
13491 	if (list->data == focus_column)
13492 	  {
13493 	    column_in_tree = TRUE;
13494 	    break;
13495 	  }
13496       g_return_if_fail (column_in_tree);
13497       _gtk_tree_view_set_focus_column (tree_view, focus_column);
13498       if (focus_cell)
13499 	gtk_tree_view_column_focus_cell (focus_column, focus_cell);
13500       if (start_editing)
13501 	gtk_tree_view_start_editing (tree_view, path, TRUE);
13502     }
13503 }
13504 
13505 /**
13506  * gtk_tree_view_get_bin_window:
13507  * @tree_view: A #GtkTreeView
13508  *
13509  * Returns the window that @tree_view renders to.
13510  * This is used primarily to compare to `event->window`
13511  * to confirm that the event on @tree_view is on the right window.
13512  *
13513  * Returns: (nullable) (transfer none): A #GdkWindow, or %NULL when @tree_view
13514  * hasn’t been realized yet.
13515  **/
13516 GdkWindow *
gtk_tree_view_get_bin_window(GtkTreeView * tree_view)13517 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
13518 {
13519   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13520 
13521   return tree_view->priv->bin_window;
13522 }
13523 
13524 /**
13525  * gtk_tree_view_get_path_at_pos:
13526  * @tree_view: A #GtkTreeView.
13527  * @x: The x position to be identified (relative to bin_window).
13528  * @y: The y position to be identified (relative to bin_window).
13529  * @path: (out) (optional) (nullable): A pointer to a #GtkTreePath
13530  *   pointer to be filled in, or %NULL
13531  * @column: (out) (transfer none) (optional) (nullable): A pointer to
13532  *   a #GtkTreeViewColumn pointer to be filled in, or %NULL
13533  * @cell_x: (out) (optional): A pointer where the X coordinate
13534  *   relative to the cell can be placed, or %NULL
13535  * @cell_y: (out) (optional): A pointer where the Y coordinate
13536  *   relative to the cell can be placed, or %NULL
13537  *
13538  * Finds the path at the point (@x, @y), relative to bin_window coordinates
13539  * (please see gtk_tree_view_get_bin_window()).
13540  * That is, @x and @y are relative to an events coordinates. @x and @y must
13541  * come from an event on the @tree_view only where `event->window ==
13542  * gtk_tree_view_get_bin_window ()`. It is primarily for
13543  * things like popup menus. If @path is non-%NULL, then it will be filled
13544  * with the #GtkTreePath at that point.  This path should be freed with
13545  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
13546  * with the column at that point.  @cell_x and @cell_y return the coordinates
13547  * relative to the cell background (i.e. the @background_area passed to
13548  * gtk_cell_renderer_render()).  This function is only meaningful if
13549  * @tree_view is realized.  Therefore this function will always return %FALSE
13550  * if @tree_view is not realized or does not have a model.
13551  *
13552  * For converting widget coordinates (eg. the ones you get from
13553  * GtkWidget::query-tooltip), please see
13554  * gtk_tree_view_convert_widget_to_bin_window_coords().
13555  *
13556  * Returns: %TRUE if a row exists at that coordinate.
13557  **/
13558 gboolean
gtk_tree_view_get_path_at_pos(GtkTreeView * tree_view,gint x,gint y,GtkTreePath ** path,GtkTreeViewColumn ** column,gint * cell_x,gint * cell_y)13559 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
13560 			       gint                x,
13561 			       gint                y,
13562 			       GtkTreePath       **path,
13563 			       GtkTreeViewColumn **column,
13564                                gint               *cell_x,
13565                                gint               *cell_y)
13566 {
13567   GtkRBTree *tree;
13568   GtkRBNode *node;
13569   gint y_offset;
13570 
13571   g_return_val_if_fail (tree_view != NULL, FALSE);
13572 
13573   if (path)
13574     *path = NULL;
13575   if (column)
13576     *column = NULL;
13577 
13578   if (tree_view->priv->bin_window == NULL)
13579     return FALSE;
13580 
13581   if (tree_view->priv->tree == NULL)
13582     return FALSE;
13583 
13584   if (x > gtk_adjustment_get_upper (tree_view->priv->hadjustment))
13585     return FALSE;
13586 
13587   if (x < 0 || y < 0)
13588     return FALSE;
13589 
13590   if (column || cell_x)
13591     {
13592       GtkTreeViewColumn *tmp_column;
13593       GtkTreeViewColumn *last_column = NULL;
13594       GList *list;
13595       gint remaining_x = x;
13596       gboolean found = FALSE;
13597       gboolean rtl;
13598       gint width;
13599 
13600       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
13601       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13602 	   list;
13603 	   list = (rtl ? list->prev : list->next))
13604 	{
13605 	  tmp_column = list->data;
13606 
13607 	  if (gtk_tree_view_column_get_visible (tmp_column) == FALSE)
13608 	    continue;
13609 
13610 	  last_column = tmp_column;
13611           width = gtk_tree_view_column_get_width (tmp_column);
13612 	  if (remaining_x < width)
13613 	    {
13614               found = TRUE;
13615 
13616               if (column)
13617                 *column = tmp_column;
13618 
13619               if (cell_x)
13620                 *cell_x = remaining_x;
13621 
13622 	      break;
13623 	    }
13624 	  remaining_x -= width;
13625 	}
13626 
13627       /* If found is FALSE and there is a last_column, then it the remainder
13628        * space is in that area
13629        */
13630       if (!found)
13631         {
13632 	  if (last_column)
13633 	    {
13634 	      if (column)
13635 		*column = last_column;
13636 
13637 	      if (cell_x)
13638 		*cell_x = gtk_tree_view_column_get_width (last_column) + remaining_x;
13639 	    }
13640 	  else
13641 	    {
13642 	      return FALSE;
13643 	    }
13644 	}
13645     }
13646 
13647   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
13648 				      TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
13649 				      &tree, &node);
13650 
13651   if (tree == NULL)
13652     return FALSE;
13653 
13654   if (cell_y)
13655     *cell_y = y_offset;
13656 
13657   if (path)
13658     *path = _gtk_tree_path_new_from_rbtree (tree, node);
13659 
13660   return TRUE;
13661 }
13662 
13663 
13664 static inline gint
gtk_tree_view_get_cell_area_height(GtkTreeView * tree_view,GtkRBNode * node,gint vertical_separator)13665 gtk_tree_view_get_cell_area_height (GtkTreeView *tree_view,
13666                                     GtkRBNode   *node,
13667                                     gint         vertical_separator)
13668 {
13669   int expander_size = gtk_tree_view_get_expander_size (tree_view);
13670   int height;
13671 
13672   /* The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
13673    * i.e. just the cells, no spacing.
13674    *
13675    * The cell area height is at least expander_size - vertical_separator.
13676    * For regular nodes, the height is then at least expander_size. We should
13677    * be able to enforce the expander_size minimum here, because this
13678    * function will not be called for irregular (e.g. separator) rows.
13679    */
13680   height = gtk_tree_view_get_row_height (tree_view, node);
13681   if (height < expander_size)
13682     height = expander_size;
13683 
13684   return height - vertical_separator;
13685 }
13686 
13687 static inline gint
gtk_tree_view_get_cell_area_y_offset(GtkTreeView * tree_view,GtkRBTree * tree,GtkRBNode * node,gint vertical_separator)13688 gtk_tree_view_get_cell_area_y_offset (GtkTreeView *tree_view,
13689                                       GtkRBTree   *tree,
13690                                       GtkRBNode   *node,
13691                                       gint         vertical_separator)
13692 {
13693   int offset;
13694 
13695   offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13696   offset += vertical_separator / 2;
13697 
13698   return offset;
13699 }
13700 
13701 /**
13702  * gtk_tree_view_get_cell_area:
13703  * @tree_view: a #GtkTreeView
13704  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13705  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
13706  * @rect: (out): rectangle to fill with cell rect
13707  *
13708  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13709  * row specified by @path and the column specified by @column.  If @path is
13710  * %NULL, or points to a path not currently displayed, the @y and @height fields
13711  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13712  * fields will be filled with 0.  The sum of all cell rects does not cover the
13713  * entire tree; there are extra pixels in between rows, for example. The
13714  * returned rectangle is equivalent to the @cell_area passed to
13715  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
13716  * realized.
13717  **/
13718 void
gtk_tree_view_get_cell_area(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,GdkRectangle * rect)13719 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13720                              GtkTreePath        *path,
13721                              GtkTreeViewColumn  *column,
13722                              GdkRectangle       *rect)
13723 {
13724   GtkRBTree *tree = NULL;
13725   GtkRBNode *node = NULL;
13726   gint vertical_separator;
13727   gint horizontal_separator;
13728 
13729   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13730   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13731   g_return_if_fail (rect != NULL);
13732   g_return_if_fail (!column || gtk_tree_view_column_get_tree_view (column) == (GtkWidget *) tree_view);
13733   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13734 
13735   gtk_widget_style_get (GTK_WIDGET (tree_view),
13736 			"vertical-separator", &vertical_separator,
13737 			"horizontal-separator", &horizontal_separator,
13738 			NULL);
13739 
13740   rect->x = 0;
13741   rect->y = 0;
13742   rect->width = 0;
13743   rect->height = 0;
13744 
13745   if (column)
13746     {
13747       rect->x = gtk_tree_view_column_get_x_offset (column) + horizontal_separator/2;
13748       rect->width = gtk_tree_view_column_get_width (column) - horizontal_separator;
13749     }
13750 
13751   if (path)
13752     {
13753       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13754 
13755       /* Get vertical coords */
13756       if ((!ret && tree == NULL) || ret)
13757 	return;
13758 
13759       if (row_is_separator (tree_view, NULL, path))
13760         {
13761           /* There isn't really a "cell area" for separator, so we
13762            * return the y, height values for background area instead.
13763            */
13764           rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13765           rect->height = gtk_tree_view_get_row_height (tree_view, node);
13766         }
13767       else
13768         {
13769           rect->y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
13770                                                           vertical_separator);
13771           rect->height = gtk_tree_view_get_cell_area_height (tree_view, node,
13772                                                              vertical_separator);
13773         }
13774 
13775       if (column &&
13776 	  gtk_tree_view_is_expander_column (tree_view, column))
13777 	{
13778 	  gint depth = gtk_tree_path_get_depth (path);
13779 	  gboolean rtl;
13780 
13781 	  rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13782 
13783 	  if (!rtl)
13784 	    rect->x += (depth - 1) * tree_view->priv->level_indentation;
13785 	  rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13786 
13787 	  if (gtk_tree_view_draw_expanders (tree_view))
13788 	    {
13789               int expander_size = gtk_tree_view_get_expander_size (tree_view);
13790 	      if (!rtl)
13791 		rect->x += depth * expander_size;
13792 	      rect->width -= depth * expander_size;
13793 	    }
13794 
13795 	  rect->width = MAX (rect->width, 0);
13796 	}
13797     }
13798 }
13799 
13800 static inline gint
gtk_tree_view_get_row_height(GtkTreeView * tree_view,GtkRBNode * node)13801 gtk_tree_view_get_row_height (GtkTreeView *tree_view,
13802                               GtkRBNode   *node)
13803 {
13804   int expander_size = gtk_tree_view_get_expander_size (tree_view);
13805   int height;
13806 
13807   /* The "background" areas of all rows/cells add up to cover the entire tree.
13808    * The background includes all inter-row and inter-cell spacing.
13809    *
13810    * If the row pointed at by node does not have a height set, we default
13811    * to expander_size, which is the minimum height for regular nodes.
13812    * Non-regular nodes (e.g. separators) can have a height set smaller
13813    * than expander_size and should not be overruled here.
13814    */
13815   height = GTK_RBNODE_GET_HEIGHT (node);
13816   if (height <= 0)
13817     height = expander_size;
13818 
13819   return height;
13820 }
13821 
13822 static inline gint
gtk_tree_view_get_row_y_offset(GtkTreeView * tree_view,GtkRBTree * tree,GtkRBNode * node)13823 gtk_tree_view_get_row_y_offset (GtkTreeView *tree_view,
13824                                 GtkRBTree   *tree,
13825                                 GtkRBNode   *node)
13826 {
13827   int offset;
13828 
13829   offset = _gtk_rbtree_node_find_offset (tree, node);
13830 
13831   return RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, offset);
13832 }
13833 
13834 /**
13835  * gtk_tree_view_get_background_area:
13836  * @tree_view: a #GtkTreeView
13837  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13838  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13839  * @rect: (out): rectangle to fill with cell background rect
13840  *
13841  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13842  * row specified by @path and the column specified by @column.  If @path is
13843  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13844  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13845  * fields will be filled with 0.  The returned rectangle is equivalent to the
13846  * @background_area passed to gtk_cell_renderer_render().  These background
13847  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13848  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13849  * itself, excluding surrounding borders and the tree expander area.
13850  *
13851  **/
13852 void
gtk_tree_view_get_background_area(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,GdkRectangle * rect)13853 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13854                                    GtkTreePath        *path,
13855                                    GtkTreeViewColumn  *column,
13856                                    GdkRectangle       *rect)
13857 {
13858   GtkRBTree *tree = NULL;
13859   GtkRBNode *node = NULL;
13860 
13861   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13862   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13863   g_return_if_fail (rect != NULL);
13864 
13865   rect->x = 0;
13866   rect->y = 0;
13867   rect->width = 0;
13868   rect->height = 0;
13869 
13870   if (path)
13871     {
13872       /* Get vertical coords */
13873 
13874       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13875 	  tree == NULL)
13876 	return;
13877 
13878       rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13879       rect->height = gtk_tree_view_get_row_height (tree_view, node);
13880     }
13881 
13882   if (column)
13883     {
13884       gint x2 = 0;
13885 
13886       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13887       rect->width = x2 - rect->x;
13888     }
13889 }
13890 
13891 /**
13892  * gtk_tree_view_get_visible_rect:
13893  * @tree_view: a #GtkTreeView
13894  * @visible_rect: (out): rectangle to fill
13895  *
13896  * Fills @visible_rect with the currently-visible region of the
13897  * buffer, in tree coordinates. Convert to bin_window coordinates with
13898  * gtk_tree_view_convert_tree_to_bin_window_coords().
13899  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13900  * scrollable area of the tree.
13901  **/
13902 void
gtk_tree_view_get_visible_rect(GtkTreeView * tree_view,GdkRectangle * visible_rect)13903 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13904                                 GdkRectangle *visible_rect)
13905 {
13906   GtkAllocation allocation;
13907   GtkWidget *widget;
13908 
13909   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13910 
13911   widget = GTK_WIDGET (tree_view);
13912 
13913   if (visible_rect)
13914     {
13915       gtk_widget_get_allocation (widget, &allocation);
13916       visible_rect->x = gtk_adjustment_get_value (tree_view->priv->hadjustment);
13917       visible_rect->y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
13918       visible_rect->width = allocation.width;
13919       visible_rect->height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
13920     }
13921 }
13922 
13923 /**
13924  * gtk_tree_view_convert_widget_to_tree_coords:
13925  * @tree_view: a #GtkTreeView
13926  * @wx: X coordinate relative to the widget
13927  * @wy: Y coordinate relative to the widget
13928  * @tx: (out): return location for tree X coordinate
13929  * @ty: (out): return location for tree Y coordinate
13930  *
13931  * Converts widget coordinates to coordinates for the
13932  * tree (the full scrollable area of the tree).
13933  *
13934  * Since: 2.12
13935  **/
13936 void
gtk_tree_view_convert_widget_to_tree_coords(GtkTreeView * tree_view,gint wx,gint wy,gint * tx,gint * ty)13937 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13938                                              gint         wx,
13939                                              gint         wy,
13940                                              gint        *tx,
13941                                              gint        *ty)
13942 {
13943   gint x, y;
13944 
13945   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13946 
13947   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13948 						     wx, wy,
13949 						     &x, &y);
13950   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13951 						   x, y,
13952 						   tx, ty);
13953 }
13954 
13955 /**
13956  * gtk_tree_view_convert_tree_to_widget_coords:
13957  * @tree_view: a #GtkTreeView
13958  * @tx: X coordinate relative to the tree
13959  * @ty: Y coordinate relative to the tree
13960  * @wx: (out): return location for widget X coordinate
13961  * @wy: (out): return location for widget Y coordinate
13962  *
13963  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13964  * to widget coordinates.
13965  *
13966  * Since: 2.12
13967  **/
13968 void
gtk_tree_view_convert_tree_to_widget_coords(GtkTreeView * tree_view,gint tx,gint ty,gint * wx,gint * wy)13969 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13970                                              gint         tx,
13971                                              gint         ty,
13972                                              gint        *wx,
13973                                              gint        *wy)
13974 {
13975   gint x, y;
13976 
13977   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13978 
13979   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13980 						   tx, ty,
13981 						   &x, &y);
13982   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13983 						     x, y,
13984 						     wx, wy);
13985 }
13986 
13987 /**
13988  * gtk_tree_view_convert_widget_to_bin_window_coords:
13989  * @tree_view: a #GtkTreeView
13990  * @wx: X coordinate relative to the widget
13991  * @wy: Y coordinate relative to the widget
13992  * @bx: (out): return location for bin_window X coordinate
13993  * @by: (out): return location for bin_window Y coordinate
13994  *
13995  * Converts widget coordinates to coordinates for the bin_window
13996  * (see gtk_tree_view_get_bin_window()).
13997  *
13998  * Since: 2.12
13999  **/
14000 void
gtk_tree_view_convert_widget_to_bin_window_coords(GtkTreeView * tree_view,gint wx,gint wy,gint * bx,gint * by)14001 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
14002                                                    gint         wx,
14003                                                    gint         wy,
14004                                                    gint        *bx,
14005                                                    gint        *by)
14006 {
14007   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14008 
14009   if (bx)
14010     *bx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
14011   if (by)
14012     *by = wy - gtk_tree_view_get_effective_header_height (tree_view);
14013 }
14014 
14015 /**
14016  * gtk_tree_view_convert_bin_window_to_widget_coords:
14017  * @tree_view: a #GtkTreeView
14018  * @bx: bin_window X coordinate
14019  * @by: bin_window Y coordinate
14020  * @wx: (out): return location for widget X coordinate
14021  * @wy: (out): return location for widget Y coordinate
14022  *
14023  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
14024  * to widget relative coordinates.
14025  *
14026  * Since: 2.12
14027  **/
14028 void
gtk_tree_view_convert_bin_window_to_widget_coords(GtkTreeView * tree_view,gint bx,gint by,gint * wx,gint * wy)14029 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
14030                                                    gint         bx,
14031                                                    gint         by,
14032                                                    gint        *wx,
14033                                                    gint        *wy)
14034 {
14035   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14036 
14037   if (wx)
14038     *wx = bx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
14039   if (wy)
14040     *wy = by + gtk_tree_view_get_effective_header_height (tree_view);
14041 }
14042 
14043 /**
14044  * gtk_tree_view_convert_tree_to_bin_window_coords:
14045  * @tree_view: a #GtkTreeView
14046  * @tx: tree X coordinate
14047  * @ty: tree Y coordinate
14048  * @bx: (out): return location for X coordinate relative to bin_window
14049  * @by: (out): return location for Y coordinate relative to bin_window
14050  *
14051  * Converts tree coordinates (coordinates in full scrollable area of the tree)
14052  * to bin_window coordinates.
14053  *
14054  * Since: 2.12
14055  **/
14056 void
gtk_tree_view_convert_tree_to_bin_window_coords(GtkTreeView * tree_view,gint tx,gint ty,gint * bx,gint * by)14057 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
14058                                                  gint         tx,
14059                                                  gint         ty,
14060                                                  gint        *bx,
14061                                                  gint        *by)
14062 {
14063   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14064 
14065   if (bx)
14066     *bx = tx;
14067   if (by)
14068     *by = ty - tree_view->priv->dy;
14069 }
14070 
14071 /**
14072  * gtk_tree_view_convert_bin_window_to_tree_coords:
14073  * @tree_view: a #GtkTreeView
14074  * @bx: X coordinate relative to bin_window
14075  * @by: Y coordinate relative to bin_window
14076  * @tx: (out): return location for tree X coordinate
14077  * @ty: (out): return location for tree Y coordinate
14078  *
14079  * Converts bin_window coordinates to coordinates for the
14080  * tree (the full scrollable area of the tree).
14081  *
14082  * Since: 2.12
14083  **/
14084 void
gtk_tree_view_convert_bin_window_to_tree_coords(GtkTreeView * tree_view,gint bx,gint by,gint * tx,gint * ty)14085 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
14086                                                  gint         bx,
14087                                                  gint         by,
14088                                                  gint        *tx,
14089                                                  gint        *ty)
14090 {
14091   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14092 
14093   if (tx)
14094     *tx = bx;
14095   if (ty)
14096     *ty = by + tree_view->priv->dy;
14097 }
14098 
14099 
14100 
14101 /**
14102  * gtk_tree_view_get_visible_range:
14103  * @tree_view: A #GtkTreeView
14104  * @start_path: (out) (allow-none): Return location for start of region,
14105  *              or %NULL.
14106  * @end_path: (out) (allow-none): Return location for end of region, or %NULL.
14107  *
14108  * Sets @start_path and @end_path to be the first and last visible path.
14109  * Note that there may be invisible paths in between.
14110  *
14111  * The paths should be freed with gtk_tree_path_free() after use.
14112  *
14113  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
14114  *
14115  * Since: 2.8
14116  **/
14117 gboolean
gtk_tree_view_get_visible_range(GtkTreeView * tree_view,GtkTreePath ** start_path,GtkTreePath ** end_path)14118 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
14119                                  GtkTreePath **start_path,
14120                                  GtkTreePath **end_path)
14121 {
14122   GtkRBTree *tree;
14123   GtkRBNode *node;
14124   gboolean retval;
14125 
14126   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14127 
14128   if (!tree_view->priv->tree)
14129     return FALSE;
14130 
14131   retval = TRUE;
14132 
14133   if (start_path)
14134     {
14135       _gtk_rbtree_find_offset (tree_view->priv->tree,
14136                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
14137                                &tree, &node);
14138       if (node)
14139         *start_path = _gtk_tree_path_new_from_rbtree (tree, node);
14140       else
14141         retval = FALSE;
14142     }
14143 
14144   if (end_path)
14145     {
14146       gint y;
14147 
14148       if (gtk_tree_view_get_height (tree_view) < gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
14149         y = gtk_tree_view_get_height (tree_view) - 1;
14150       else
14151         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, gtk_adjustment_get_page_size (tree_view->priv->vadjustment)) - 1;
14152 
14153       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
14154       if (node)
14155         *end_path = _gtk_tree_path_new_from_rbtree (tree, node);
14156       else
14157         retval = FALSE;
14158     }
14159 
14160   return retval;
14161 }
14162 
14163 /**
14164  * gtk_tree_view_is_blank_at_pos:
14165  * @tree_view: A #GtkTreeView
14166  * @x: The x position to be identified (relative to bin_window)
14167  * @y: The y position to be identified (relative to bin_window)
14168  * @path: (out) (optional) (nullable): A pointer to a #GtkTreePath pointer to
14169  *   be filled in, or %NULL
14170  * @column: (out) (transfer none) (optional) (nullable): A pointer to a
14171  *   #GtkTreeViewColumn pointer to be filled in, or %NULL
14172  * @cell_x: (out) (optional): A pointer where the X coordinate relative to the
14173  *   cell can be placed, or %NULL
14174  * @cell_y: (out) (optional): A pointer where the Y coordinate relative to the
14175  *   cell can be placed, or %NULL
14176  *
14177  * Determine whether the point (@x, @y) in @tree_view is blank, that is no
14178  * cell content nor an expander arrow is drawn at the location. If so, the
14179  * location can be considered as the background. You might wish to take
14180  * special action on clicks on the background, such as clearing a current
14181  * selection, having a custom context menu or starting rubber banding.
14182  *
14183  * The @x and @y coordinate that are provided must be relative to bin_window
14184  * coordinates.  That is, @x and @y must come from an event on @tree_view
14185  * where `event->window == gtk_tree_view_get_bin_window ()`.
14186  *
14187  * For converting widget coordinates (eg. the ones you get from
14188  * GtkWidget::query-tooltip), please see
14189  * gtk_tree_view_convert_widget_to_bin_window_coords().
14190  *
14191  * The @path, @column, @cell_x and @cell_y arguments will be filled in
14192  * likewise as for gtk_tree_view_get_path_at_pos().  Please see
14193  * gtk_tree_view_get_path_at_pos() for more information.
14194  *
14195  * Returns: %TRUE if the area at the given coordinates is blank,
14196  * %FALSE otherwise.
14197  *
14198  * Since: 3.0
14199  */
14200 gboolean
gtk_tree_view_is_blank_at_pos(GtkTreeView * tree_view,gint x,gint y,GtkTreePath ** path,GtkTreeViewColumn ** column,gint * cell_x,gint * cell_y)14201 gtk_tree_view_is_blank_at_pos (GtkTreeView       *tree_view,
14202                                gint                x,
14203                                gint                y,
14204                                GtkTreePath       **path,
14205                                GtkTreeViewColumn **column,
14206                                gint               *cell_x,
14207                                gint               *cell_y)
14208 {
14209   GtkRBTree *tree;
14210   GtkRBNode *node;
14211   GtkTreeIter iter;
14212   GtkTreePath *real_path;
14213   GtkTreeViewColumn *real_column;
14214   GdkRectangle cell_area, background_area;
14215 
14216   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14217 
14218   if (!gtk_tree_view_get_path_at_pos (tree_view, x, y,
14219                                       &real_path, &real_column,
14220                                       cell_x, cell_y))
14221     /* If there's no path here, it is blank */
14222     return TRUE;
14223 
14224   if (path)
14225     *path = real_path;
14226 
14227   if (column)
14228     *column = real_column;
14229 
14230   gtk_tree_model_get_iter (tree_view->priv->model, &iter, real_path);
14231   _gtk_tree_view_find_node (tree_view, real_path, &tree, &node);
14232 
14233   /* Check if there's an expander arrow at (x, y) */
14234   if (real_column == tree_view->priv->expander_column
14235       && gtk_tree_view_draw_expanders (tree_view))
14236     {
14237       gboolean over_arrow;
14238 
14239       over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
14240 
14241       if (over_arrow)
14242         {
14243           if (!path)
14244             gtk_tree_path_free (real_path);
14245           return FALSE;
14246         }
14247     }
14248 
14249   /* Otherwise, have the column see if there's a cell at (x, y) */
14250   gtk_tree_view_column_cell_set_cell_data (real_column,
14251                                            tree_view->priv->model,
14252                                            &iter,
14253                                            GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14254                                            node->children ? TRUE : FALSE);
14255 
14256   gtk_tree_view_get_background_area (tree_view, real_path, real_column,
14257                                      &background_area);
14258   gtk_tree_view_get_cell_area (tree_view, real_path, real_column,
14259                                &cell_area);
14260 
14261   if (!path)
14262     gtk_tree_path_free (real_path);
14263 
14264   return _gtk_tree_view_column_is_blank_at_pos (real_column,
14265                                                 &cell_area,
14266                                                 &background_area,
14267                                                 x, y);
14268 }
14269 
14270 static void
unset_reorderable(GtkTreeView * tree_view)14271 unset_reorderable (GtkTreeView *tree_view)
14272 {
14273   if (tree_view->priv->reorderable)
14274     {
14275       tree_view->priv->reorderable = FALSE;
14276       g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_REORDERABLE]);
14277     }
14278 }
14279 
14280 /**
14281  * gtk_tree_view_enable_model_drag_source:
14282  * @tree_view: a #GtkTreeView
14283  * @start_button_mask: Mask of allowed buttons to start drag
14284  * @targets: (array length=n_targets): the table of targets that the drag will support
14285  * @n_targets: the number of items in @targets
14286  * @actions: the bitmask of possible actions for a drag from this
14287  *    widget
14288  *
14289  * Turns @tree_view into a drag source for automatic DND. Calling this
14290  * method sets #GtkTreeView:reorderable to %FALSE.
14291  **/
14292 void
gtk_tree_view_enable_model_drag_source(GtkTreeView * tree_view,GdkModifierType start_button_mask,const GtkTargetEntry * targets,gint n_targets,GdkDragAction actions)14293 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
14294 					GdkModifierType           start_button_mask,
14295 					const GtkTargetEntry     *targets,
14296 					gint                      n_targets,
14297 					GdkDragAction             actions)
14298 {
14299   TreeViewDragInfo *di;
14300 
14301   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14302 
14303   gtk_drag_source_set (GTK_WIDGET (tree_view),
14304 		       0,
14305 		       targets,
14306 		       n_targets,
14307 		       actions);
14308 
14309   di = ensure_info (tree_view);
14310 
14311   di->start_button_mask = start_button_mask;
14312   di->source_actions = actions;
14313   di->source_set = TRUE;
14314 
14315   unset_reorderable (tree_view);
14316 }
14317 
14318 /**
14319  * gtk_tree_view_enable_model_drag_dest:
14320  * @tree_view: a #GtkTreeView
14321  * @targets: (array length=n_targets): the table of targets that
14322  *           the drag will support
14323  * @n_targets: the number of items in @targets
14324  * @actions: the bitmask of possible actions for a drag from this
14325  *    widget
14326  *
14327  * Turns @tree_view into a drop destination for automatic DND. Calling
14328  * this method sets #GtkTreeView:reorderable to %FALSE.
14329  **/
14330 void
gtk_tree_view_enable_model_drag_dest(GtkTreeView * tree_view,const GtkTargetEntry * targets,gint n_targets,GdkDragAction actions)14331 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
14332 				      const GtkTargetEntry     *targets,
14333 				      gint                      n_targets,
14334 				      GdkDragAction             actions)
14335 {
14336   TreeViewDragInfo *di;
14337 
14338   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14339 
14340   gtk_drag_dest_set (GTK_WIDGET (tree_view),
14341                      0,
14342                      targets,
14343                      n_targets,
14344                      actions);
14345 
14346   di = ensure_info (tree_view);
14347   di->dest_set = TRUE;
14348 
14349   unset_reorderable (tree_view);
14350 }
14351 
14352 /**
14353  * gtk_tree_view_unset_rows_drag_source:
14354  * @tree_view: a #GtkTreeView
14355  *
14356  * Undoes the effect of
14357  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
14358  * #GtkTreeView:reorderable to %FALSE.
14359  **/
14360 void
gtk_tree_view_unset_rows_drag_source(GtkTreeView * tree_view)14361 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
14362 {
14363   TreeViewDragInfo *di;
14364 
14365   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14366 
14367   di = get_info (tree_view);
14368 
14369   if (di)
14370     {
14371       if (di->source_set)
14372         {
14373           gtk_drag_source_unset (GTK_WIDGET (tree_view));
14374           di->source_set = FALSE;
14375         }
14376 
14377       if (!di->dest_set && !di->source_set)
14378         remove_info (tree_view);
14379     }
14380 
14381   unset_reorderable (tree_view);
14382 }
14383 
14384 /**
14385  * gtk_tree_view_unset_rows_drag_dest:
14386  * @tree_view: a #GtkTreeView
14387  *
14388  * Undoes the effect of
14389  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
14390  * #GtkTreeView:reorderable to %FALSE.
14391  **/
14392 void
gtk_tree_view_unset_rows_drag_dest(GtkTreeView * tree_view)14393 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
14394 {
14395   TreeViewDragInfo *di;
14396 
14397   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14398 
14399   di = get_info (tree_view);
14400 
14401   if (di)
14402     {
14403       if (di->dest_set)
14404         {
14405           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
14406           di->dest_set = FALSE;
14407         }
14408 
14409       if (!di->dest_set && !di->source_set)
14410         remove_info (tree_view);
14411     }
14412 
14413   unset_reorderable (tree_view);
14414 }
14415 
14416 /**
14417  * gtk_tree_view_set_drag_dest_row:
14418  * @tree_view: a #GtkTreeView
14419  * @path: (allow-none): The path of the row to highlight, or %NULL
14420  * @pos: Specifies whether to drop before, after or into the row
14421  *
14422  * Sets the row that is highlighted for feedback.
14423  * If @path is %NULL, an existing highlight is removed.
14424  */
14425 void
gtk_tree_view_set_drag_dest_row(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewDropPosition pos)14426 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
14427                                  GtkTreePath            *path,
14428                                  GtkTreeViewDropPosition pos)
14429 {
14430   GtkTreePath *current_dest;
14431 
14432   /* Note; this function is exported to allow a custom DND
14433    * implementation, so it can't touch TreeViewDragInfo
14434    */
14435 
14436   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14437 
14438   current_dest = NULL;
14439 
14440   if (tree_view->priv->drag_dest_row)
14441     {
14442       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14443       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
14444     }
14445 
14446   /* special case a drop on an empty model */
14447   tree_view->priv->empty_view_drop = 0;
14448 
14449   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
14450       && gtk_tree_path_get_depth (path) == 1
14451       && gtk_tree_path_get_indices (path)[0] == 0)
14452     {
14453       gint n_children;
14454 
14455       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
14456                                                    NULL);
14457 
14458       if (!n_children)
14459         tree_view->priv->empty_view_drop = 1;
14460     }
14461 
14462   tree_view->priv->drag_dest_pos = pos;
14463 
14464   if (path)
14465     {
14466       tree_view->priv->drag_dest_row =
14467         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
14468       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
14469     }
14470   else
14471     tree_view->priv->drag_dest_row = NULL;
14472 
14473   if (current_dest)
14474     {
14475       GtkRBTree *tree, *new_tree;
14476       GtkRBNode *node, *new_node;
14477 
14478       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
14479       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
14480 
14481       if (tree && node)
14482 	{
14483 	  _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
14484 	  if (new_tree && new_node)
14485 	    _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14486 
14487 	  _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
14488 	  if (new_tree && new_node)
14489 	    _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14490 	}
14491       gtk_tree_path_free (current_dest);
14492     }
14493 }
14494 
14495 /**
14496  * gtk_tree_view_get_drag_dest_row:
14497  * @tree_view: a #GtkTreeView
14498  * @path: (out) (optional) (nullable): Return location for the path of the highlighted row, or %NULL.
14499  * @pos: (out) (optional): Return location for the drop position, or %NULL
14500  *
14501  * Gets information about the row that is highlighted for feedback.
14502  **/
14503 void
gtk_tree_view_get_drag_dest_row(GtkTreeView * tree_view,GtkTreePath ** path,GtkTreeViewDropPosition * pos)14504 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
14505                                  GtkTreePath             **path,
14506                                  GtkTreeViewDropPosition  *pos)
14507 {
14508   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14509 
14510   if (path)
14511     {
14512       if (tree_view->priv->drag_dest_row)
14513         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14514       else
14515         {
14516           if (tree_view->priv->empty_view_drop)
14517             *path = gtk_tree_path_new_from_indices (0, -1);
14518           else
14519             *path = NULL;
14520         }
14521     }
14522 
14523   if (pos)
14524     *pos = tree_view->priv->drag_dest_pos;
14525 }
14526 
14527 /**
14528  * gtk_tree_view_get_dest_row_at_pos:
14529  * @tree_view: a #GtkTreeView
14530  * @drag_x: the position to determine the destination row for
14531  * @drag_y: the position to determine the destination row for
14532  * @path: (out) (optional) (nullable): Return location for the path of
14533  *   the highlighted row, or %NULL.
14534  * @pos: (out) (optional): Return location for the drop position, or
14535  *   %NULL
14536  *
14537  * Determines the destination row for a given position.  @drag_x and
14538  * @drag_y are expected to be in widget coordinates.  This function is only
14539  * meaningful if @tree_view is realized.  Therefore this function will always
14540  * return %FALSE if @tree_view is not realized or does not have a model.
14541  *
14542  * Returns: whether there is a row at the given position, %TRUE if this
14543  * is indeed the case.
14544  **/
14545 gboolean
gtk_tree_view_get_dest_row_at_pos(GtkTreeView * tree_view,gint drag_x,gint drag_y,GtkTreePath ** path,GtkTreeViewDropPosition * pos)14546 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
14547                                    gint                     drag_x,
14548                                    gint                     drag_y,
14549                                    GtkTreePath            **path,
14550                                    GtkTreeViewDropPosition *pos)
14551 {
14552   gint cell_y;
14553   gint bin_x, bin_y;
14554   gdouble offset_into_row;
14555   gdouble fourth;
14556   GdkRectangle cell;
14557   GtkTreeViewColumn *column = NULL;
14558   GtkTreePath *tmp_path = NULL;
14559 
14560   /* Note; this function is exported to allow a custom DND
14561    * implementation, so it can't touch TreeViewDragInfo
14562    */
14563 
14564   g_return_val_if_fail (tree_view != NULL, FALSE);
14565   g_return_val_if_fail (drag_x >= 0, FALSE);
14566   g_return_val_if_fail (drag_y >= 0, FALSE);
14567 
14568   if (path)
14569     *path = NULL;
14570 
14571   if (tree_view->priv->bin_window == NULL)
14572     return FALSE;
14573 
14574   if (tree_view->priv->tree == NULL)
14575     return FALSE;
14576 
14577   /* If in the top fourth of a row, we drop before that row; if
14578    * in the bottom fourth, drop after that row; if in the middle,
14579    * and the row has children, drop into the row.
14580    */
14581   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
14582 						     &bin_x, &bin_y);
14583 
14584   if (!gtk_tree_view_get_path_at_pos (tree_view,
14585 				      bin_x,
14586 				      bin_y,
14587                                       &tmp_path,
14588                                       &column,
14589                                       NULL,
14590                                       &cell_y))
14591     return FALSE;
14592 
14593   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
14594                                      &cell);
14595 
14596   offset_into_row = cell_y;
14597 
14598   if (path)
14599     *path = tmp_path;
14600   else
14601     gtk_tree_path_free (tmp_path);
14602 
14603   tmp_path = NULL;
14604 
14605   fourth = cell.height / 4.0;
14606 
14607   if (pos)
14608     {
14609       if (offset_into_row < fourth)
14610         {
14611           *pos = GTK_TREE_VIEW_DROP_BEFORE;
14612         }
14613       else if (offset_into_row < (cell.height / 2.0))
14614         {
14615           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
14616         }
14617       else if (offset_into_row < cell.height - fourth)
14618         {
14619           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
14620         }
14621       else
14622         {
14623           *pos = GTK_TREE_VIEW_DROP_AFTER;
14624         }
14625     }
14626 
14627   return TRUE;
14628 }
14629 
14630 
14631 
14632 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
14633 /**
14634  * gtk_tree_view_create_row_drag_icon:
14635  * @tree_view: a #GtkTreeView
14636  * @path: a #GtkTreePath in @tree_view
14637  *
14638  * Creates a #cairo_surface_t representation of the row at @path.
14639  * This image is used for a drag icon.
14640  *
14641  * Returns: (transfer full): a newly-allocated surface of the drag icon.
14642  **/
14643 cairo_surface_t *
gtk_tree_view_create_row_drag_icon(GtkTreeView * tree_view,GtkTreePath * path)14644 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
14645                                     GtkTreePath  *path)
14646 {
14647   GtkTreeIter   iter;
14648   GtkRBTree    *tree;
14649   GtkRBNode    *node;
14650   GtkStyleContext *context;
14651   gint cell_offset;
14652   GList *list;
14653   GdkRectangle background_area;
14654   GtkWidget *widget;
14655   gint depth;
14656   /* start drawing inside the black outline */
14657   gint x = 1, y = 1;
14658   cairo_surface_t *surface;
14659   gint bin_window_width;
14660   gboolean is_separator = FALSE;
14661   gboolean rtl;
14662   cairo_t *cr;
14663 
14664   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14665   g_return_val_if_fail (path != NULL, NULL);
14666 
14667   widget = GTK_WIDGET (tree_view);
14668 
14669   if (!gtk_widget_get_realized (widget))
14670     return NULL;
14671 
14672   depth = gtk_tree_path_get_depth (path);
14673 
14674   _gtk_tree_view_find_node (tree_view,
14675                             path,
14676                             &tree,
14677                             &node);
14678 
14679   if (tree == NULL)
14680     return NULL;
14681 
14682   if (!gtk_tree_model_get_iter (tree_view->priv->model,
14683                                 &iter,
14684                                 path))
14685     return NULL;
14686 
14687   context = gtk_widget_get_style_context (widget);
14688 
14689   is_separator = row_is_separator (tree_view, &iter, NULL);
14690 
14691   cell_offset = x;
14692 
14693   background_area.y = y;
14694   background_area.height = gtk_tree_view_get_row_height (tree_view, node);
14695 
14696   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
14697 
14698   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
14699                                                CAIRO_CONTENT_COLOR,
14700                                                bin_window_width + 2,
14701                                                background_area.height + 2);
14702 
14703   cr = cairo_create (surface);
14704 
14705   gtk_render_background (context, cr, 0, 0,
14706                          bin_window_width + 2,
14707                          background_area.height + 2);
14708 
14709   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
14710 
14711   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
14712       list;
14713       list = (rtl ? list->prev : list->next))
14714     {
14715       GtkTreeViewColumn *column = list->data;
14716       GdkRectangle cell_area;
14717       gint vertical_separator;
14718 
14719       if (!gtk_tree_view_column_get_visible (column))
14720         continue;
14721 
14722       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
14723 					       GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14724 					       node->children?TRUE:FALSE);
14725 
14726       background_area.x = cell_offset;
14727       background_area.width = gtk_tree_view_column_get_width (column);
14728 
14729       gtk_widget_style_get (widget,
14730 			    "vertical-separator", &vertical_separator,
14731 			    NULL);
14732 
14733       cell_area = background_area;
14734 
14735       cell_area.y += vertical_separator / 2;
14736       cell_area.height -= vertical_separator;
14737 
14738       if (gtk_tree_view_is_expander_column (tree_view, column))
14739         {
14740 	  if (!rtl)
14741 	    cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
14742 	  cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
14743 
14744           if (gtk_tree_view_draw_expanders (tree_view))
14745 	    {
14746               int expander_size = gtk_tree_view_get_expander_size (tree_view);
14747 	      if (!rtl)
14748 		cell_area.x += depth * expander_size;
14749 	      cell_area.width -= depth * expander_size;
14750 	    }
14751         }
14752 
14753       if (gtk_tree_view_column_cell_is_visible (column))
14754 	{
14755 	  if (is_separator)
14756             {
14757               gtk_style_context_save (context);
14758               gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
14759 
14760               gtk_render_line (context, cr,
14761                                cell_area.x,
14762                                cell_area.y + cell_area.height / 2,
14763                                cell_area.x + cell_area.width,
14764                                cell_area.y + cell_area.height / 2);
14765 
14766               gtk_style_context_restore (context);
14767             }
14768 	  else
14769             {
14770               _gtk_tree_view_column_cell_render (column,
14771                                                  cr,
14772                                                  &background_area,
14773                                                  &cell_area,
14774                                                  0, FALSE);
14775             }
14776 	}
14777       cell_offset += gtk_tree_view_column_get_width (column);
14778     }
14779 
14780   cairo_set_source_rgb (cr, 0, 0, 0);
14781   cairo_rectangle (cr,
14782                    0.5, 0.5,
14783                    bin_window_width + 1,
14784                    background_area.height + 1);
14785   cairo_set_line_width (cr, 1.0);
14786   cairo_stroke (cr);
14787 
14788   cairo_destroy (cr);
14789 
14790   cairo_surface_set_device_offset (surface, 2, 2);
14791 
14792   return surface;
14793 }
14794 
14795 
14796 /**
14797  * gtk_tree_view_set_destroy_count_func:
14798  * @tree_view: A #GtkTreeView
14799  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
14800  * @data: (allow-none): User data to be passed to @func, or %NULL
14801  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14802  *
14803  * This function should almost never be used.  It is meant for private use by
14804  * ATK for determining the number of visible children that are removed when the
14805  * user collapses a row, or a row is deleted.
14806  *
14807  * Deprecated: 3.4: Accessibility does not need the function anymore.
14808  **/
14809 void
gtk_tree_view_set_destroy_count_func(GtkTreeView * tree_view,GtkTreeDestroyCountFunc func,gpointer data,GDestroyNotify destroy)14810 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
14811 				      GtkTreeDestroyCountFunc  func,
14812 				      gpointer                 data,
14813 				      GDestroyNotify           destroy)
14814 {
14815   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14816 
14817   if (tree_view->priv->destroy_count_destroy)
14818     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
14819 
14820   tree_view->priv->destroy_count_func = func;
14821   tree_view->priv->destroy_count_data = data;
14822   tree_view->priv->destroy_count_destroy = destroy;
14823 }
14824 
14825 
14826 /*
14827  * Interactive search
14828  */
14829 
14830 /**
14831  * gtk_tree_view_set_enable_search:
14832  * @tree_view: A #GtkTreeView
14833  * @enable_search: %TRUE, if the user can search interactively
14834  *
14835  * If @enable_search is set, then the user can type in text to search through
14836  * the tree interactively (this is sometimes called "typeahead find").
14837  *
14838  * Note that even if this is %FALSE, the user can still initiate a search
14839  * using the “start-interactive-search” key binding.
14840  */
14841 void
gtk_tree_view_set_enable_search(GtkTreeView * tree_view,gboolean enable_search)14842 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
14843 				 gboolean     enable_search)
14844 {
14845   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14846 
14847   enable_search = !!enable_search;
14848 
14849   if (tree_view->priv->enable_search != enable_search)
14850     {
14851        tree_view->priv->enable_search = enable_search;
14852        g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_ENABLE_SEARCH]);
14853     }
14854 }
14855 
14856 /**
14857  * gtk_tree_view_get_enable_search:
14858  * @tree_view: A #GtkTreeView
14859  *
14860  * Returns whether or not the tree allows to start interactive searching
14861  * by typing in text.
14862  *
14863  * Returns: whether or not to let the user search interactively
14864  */
14865 gboolean
gtk_tree_view_get_enable_search(GtkTreeView * tree_view)14866 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
14867 {
14868   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14869 
14870   return tree_view->priv->enable_search;
14871 }
14872 
14873 
14874 /**
14875  * gtk_tree_view_get_search_column:
14876  * @tree_view: A #GtkTreeView
14877  *
14878  * Gets the column searched on by the interactive search code.
14879  *
14880  * Returns: the column the interactive search code searches in.
14881  */
14882 gint
gtk_tree_view_get_search_column(GtkTreeView * tree_view)14883 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14884 {
14885   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14886 
14887   return (tree_view->priv->search_column);
14888 }
14889 
14890 /**
14891  * gtk_tree_view_set_search_column:
14892  * @tree_view: A #GtkTreeView
14893  * @column: the column of the model to search in, or -1 to disable searching
14894  *
14895  * Sets @column as the column where the interactive search code should
14896  * search in for the current model.
14897  *
14898  * If the search column is set, users can use the “start-interactive-search”
14899  * key binding to bring up search popup. The enable-search property controls
14900  * whether simply typing text will also start an interactive search.
14901  *
14902  * Note that @column refers to a column of the current model. The search
14903  * column is reset to -1 when the model is changed.
14904  */
14905 void
gtk_tree_view_set_search_column(GtkTreeView * tree_view,gint column)14906 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14907 				 gint         column)
14908 {
14909   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14910   g_return_if_fail (column >= -1);
14911 
14912   if (tree_view->priv->search_column == column)
14913     return;
14914 
14915   tree_view->priv->search_column = column;
14916   g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_SEARCH_COLUMN]);
14917 }
14918 
14919 /**
14920  * gtk_tree_view_get_search_equal_func: (skip)
14921  * @tree_view: A #GtkTreeView
14922  *
14923  * Returns the compare function currently in use.
14924  *
14925  * Returns: the currently used compare function for the search code.
14926  */
14927 
14928 GtkTreeViewSearchEqualFunc
gtk_tree_view_get_search_equal_func(GtkTreeView * tree_view)14929 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14930 {
14931   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14932 
14933   return tree_view->priv->search_equal_func;
14934 }
14935 
14936 /**
14937  * gtk_tree_view_set_search_equal_func:
14938  * @tree_view: A #GtkTreeView
14939  * @search_equal_func: the compare function to use during the search
14940  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14941  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14942  *
14943  * Sets the compare function for the interactive search capabilities; note
14944  * that somewhat like strcmp() returning 0 for equality
14945  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14946  **/
14947 void
gtk_tree_view_set_search_equal_func(GtkTreeView * tree_view,GtkTreeViewSearchEqualFunc search_equal_func,gpointer search_user_data,GDestroyNotify search_destroy)14948 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14949 				     GtkTreeViewSearchEqualFunc  search_equal_func,
14950 				     gpointer                    search_user_data,
14951 				     GDestroyNotify              search_destroy)
14952 {
14953   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14954   g_return_if_fail (search_equal_func != NULL);
14955 
14956   if (tree_view->priv->search_destroy)
14957     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14958 
14959   tree_view->priv->search_equal_func = search_equal_func;
14960   tree_view->priv->search_user_data = search_user_data;
14961   tree_view->priv->search_destroy = search_destroy;
14962   if (tree_view->priv->search_equal_func == NULL)
14963     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14964 }
14965 
14966 /**
14967  * gtk_tree_view_get_search_entry:
14968  * @tree_view: A #GtkTreeView
14969  *
14970  * Returns the #GtkEntry which is currently in use as interactive search
14971  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14972  * will be returned.
14973  *
14974  * Returns: (transfer none): the entry currently in use as search entry.
14975  *
14976  * Since: 2.10
14977  */
14978 GtkEntry *
gtk_tree_view_get_search_entry(GtkTreeView * tree_view)14979 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14980 {
14981   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14982 
14983   if (tree_view->priv->search_custom_entry_set)
14984     return GTK_ENTRY (tree_view->priv->search_entry);
14985 
14986   return NULL;
14987 }
14988 
14989 /**
14990  * gtk_tree_view_set_search_entry:
14991  * @tree_view: A #GtkTreeView
14992  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14993  *
14994  * Sets the entry which the interactive search code will use for this
14995  * @tree_view.  This is useful when you want to provide a search entry
14996  * in our interface at all time at a fixed position.  Passing %NULL for
14997  * @entry will make the interactive search code use the built-in popup
14998  * entry again.
14999  *
15000  * Since: 2.10
15001  */
15002 void
gtk_tree_view_set_search_entry(GtkTreeView * tree_view,GtkEntry * entry)15003 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
15004 				GtkEntry    *entry)
15005 {
15006   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15007   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
15008 
15009   if (tree_view->priv->search_custom_entry_set)
15010     {
15011       if (tree_view->priv->search_entry_changed_id)
15012         {
15013 	  g_signal_handler_disconnect (tree_view->priv->search_entry,
15014 				       tree_view->priv->search_entry_changed_id);
15015 	  tree_view->priv->search_entry_changed_id = 0;
15016 	}
15017       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
15018 					    G_CALLBACK (gtk_tree_view_search_key_press_event),
15019 					    tree_view);
15020 
15021       g_object_unref (tree_view->priv->search_entry);
15022     }
15023   else if (tree_view->priv->search_window)
15024     {
15025       gtk_tree_view_destroy_search_window (tree_view);
15026     }
15027 
15028   if (entry)
15029     {
15030       tree_view->priv->search_entry = GTK_WIDGET (g_object_ref (entry));
15031       tree_view->priv->search_custom_entry_set = TRUE;
15032 
15033       if (tree_view->priv->search_entry_changed_id == 0)
15034         {
15035           tree_view->priv->search_entry_changed_id =
15036 	    g_signal_connect (tree_view->priv->search_entry, "changed",
15037 			      G_CALLBACK (gtk_tree_view_search_init),
15038 			      tree_view);
15039 	}
15040 
15041         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
15042 		          G_CALLBACK (gtk_tree_view_search_key_press_event),
15043 		          tree_view);
15044 
15045 	gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
15046     }
15047   else
15048     {
15049       tree_view->priv->search_entry = NULL;
15050       tree_view->priv->search_custom_entry_set = FALSE;
15051     }
15052 }
15053 
15054 /**
15055  * gtk_tree_view_set_search_position_func:
15056  * @tree_view: A #GtkTreeView
15057  * @func: (allow-none): the function to use to position the search dialog, or %NULL
15058  *    to use the default search position function
15059  * @data: (allow-none): user data to pass to @func, or %NULL
15060  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
15061  *
15062  * Sets the function to use when positioning the search dialog.
15063  *
15064  * Since: 2.10
15065  **/
15066 void
gtk_tree_view_set_search_position_func(GtkTreeView * tree_view,GtkTreeViewSearchPositionFunc func,gpointer user_data,GDestroyNotify destroy)15067 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
15068 				        GtkTreeViewSearchPositionFunc  func,
15069 				        gpointer                       user_data,
15070 				        GDestroyNotify                 destroy)
15071 {
15072   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15073 
15074   if (tree_view->priv->search_position_destroy)
15075     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
15076 
15077   tree_view->priv->search_position_func = func;
15078   tree_view->priv->search_position_user_data = user_data;
15079   tree_view->priv->search_position_destroy = destroy;
15080   if (tree_view->priv->search_position_func == NULL)
15081     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
15082 }
15083 
15084 /**
15085  * gtk_tree_view_get_search_position_func: (skip)
15086  * @tree_view: A #GtkTreeView
15087  *
15088  * Returns the positioning function currently in use.
15089  *
15090  * Returns: the currently used function for positioning the search dialog.
15091  *
15092  * Since: 2.10
15093  */
15094 GtkTreeViewSearchPositionFunc
gtk_tree_view_get_search_position_func(GtkTreeView * tree_view)15095 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
15096 {
15097   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15098 
15099   return tree_view->priv->search_position_func;
15100 }
15101 
15102 
15103 static void
gtk_tree_view_search_window_hide(GtkWidget * search_window,GtkTreeView * tree_view,GdkDevice * device)15104 gtk_tree_view_search_window_hide (GtkWidget   *search_window,
15105                                   GtkTreeView *tree_view,
15106                                   GdkDevice   *device)
15107 {
15108   if (tree_view->priv->disable_popdown)
15109     return;
15110 
15111   if (tree_view->priv->search_entry_changed_id)
15112     {
15113       g_signal_handler_disconnect (tree_view->priv->search_entry,
15114 				   tree_view->priv->search_entry_changed_id);
15115       tree_view->priv->search_entry_changed_id = 0;
15116     }
15117   if (tree_view->priv->typeselect_flush_timeout)
15118     {
15119       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15120       tree_view->priv->typeselect_flush_timeout = 0;
15121     }
15122 
15123   if (gtk_widget_get_visible (search_window))
15124     {
15125       /* send focus-in event */
15126       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
15127       gtk_widget_hide (search_window);
15128       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
15129       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
15130     }
15131 }
15132 
15133 static void
gtk_tree_view_search_position_func(GtkTreeView * tree_view,GtkWidget * search_window,gpointer user_data)15134 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
15135 				    GtkWidget   *search_window,
15136 				    gpointer     user_data)
15137 {
15138   gint x, y;
15139   gint tree_x, tree_y;
15140   gint tree_width, tree_height;
15141   GdkDisplay *display;
15142   GdkMonitor *monitor;
15143   GdkRectangle workarea;
15144   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
15145   GtkRequisition requisition;
15146 
15147   gtk_widget_realize (search_window);
15148 
15149   display = gtk_widget_get_display (GTK_WIDGET (tree_view));
15150   monitor = gdk_display_get_monitor_at_window (display, tree_window);
15151   gdk_monitor_get_workarea (monitor, &workarea);
15152 
15153   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
15154   tree_width = gdk_window_get_width (tree_window);
15155   tree_height = gdk_window_get_height (tree_window);
15156   gtk_widget_get_preferred_size (search_window, &requisition, NULL);
15157 
15158   if (tree_x + tree_width > workarea.x + workarea.width)
15159     x = workarea.x + workarea.width - requisition.width;
15160   else if (tree_x + tree_width - requisition.width < workarea.x)
15161     x = workarea.x;
15162   else
15163     x = tree_x + tree_width - requisition.width;
15164 
15165   if (tree_y + tree_height + requisition.height > workarea.y + workarea.height)
15166     y = workarea.y + workarea.height - requisition.height;
15167   else if (tree_y + tree_height < workarea.y) /* isn't really possible ... */
15168     y = workarea.y;
15169   else
15170     y = tree_y + tree_height;
15171 
15172   gtk_window_move (GTK_WINDOW (search_window), x, y);
15173 }
15174 
15175 static void
gtk_tree_view_search_disable_popdown(GtkEntry * entry,GtkMenu * menu,gpointer data)15176 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
15177 				      GtkMenu  *menu,
15178 				      gpointer  data)
15179 {
15180   GtkTreeView *tree_view = (GtkTreeView *)data;
15181 
15182   tree_view->priv->disable_popdown = 1;
15183   g_signal_connect (menu, "hide",
15184 		    G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
15185 }
15186 
15187 /* Because we're visible but offscreen, we just set a flag in the preedit
15188  * callback.
15189  */
15190 static void
gtk_tree_view_search_preedit_changed(GtkIMContext * im_context,GtkTreeView * tree_view)15191 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
15192 				      GtkTreeView  *tree_view)
15193 {
15194   tree_view->priv->imcontext_changed = 1;
15195   if (tree_view->priv->typeselect_flush_timeout)
15196     {
15197       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15198       tree_view->priv->typeselect_flush_timeout =
15199 	gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15200 		       (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15201 		       tree_view);
15202       g_source_set_name_by_id (tree_view->priv->typeselect_flush_timeout, "[gtk+] gtk_tree_view_search_entry_flush_timeout");
15203     }
15204 
15205 }
15206 
15207 static void
gtk_tree_view_search_commit(GtkIMContext * im_context,gchar * buf,GtkTreeView * tree_view)15208 gtk_tree_view_search_commit (GtkIMContext *im_context,
15209                              gchar        *buf,
15210                              GtkTreeView  *tree_view)
15211 {
15212   tree_view->priv->imcontext_changed = 1;
15213 }
15214 
15215 static void
gtk_tree_view_search_activate(GtkEntry * entry,GtkTreeView * tree_view)15216 gtk_tree_view_search_activate (GtkEntry    *entry,
15217 			       GtkTreeView *tree_view)
15218 {
15219   GtkTreePath *path;
15220 
15221   gtk_tree_view_search_window_hide (tree_view->priv->search_window,
15222                                     tree_view,
15223                                     gtk_get_current_event_device ());
15224 
15225   /* If we have a row selected and it's the cursor row, we activate
15226    * the row XXX */
15227   if (tree_view->priv->cursor_node &&
15228       GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_SELECTED))
15229     {
15230       path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
15231                                              tree_view->priv->cursor_node);
15232 
15233       gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
15234 
15235       gtk_tree_path_free (path);
15236     }
15237 }
15238 
15239 static gboolean
gtk_tree_view_real_search_enable_popdown(gpointer data)15240 gtk_tree_view_real_search_enable_popdown (gpointer data)
15241 {
15242   GtkTreeView *tree_view = (GtkTreeView *)data;
15243 
15244   tree_view->priv->disable_popdown = 0;
15245 
15246   return FALSE;
15247 }
15248 
15249 static void
gtk_tree_view_search_enable_popdown(GtkWidget * widget,gpointer data)15250 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
15251 				     gpointer   data)
15252 {
15253   guint id;
15254   id = gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
15255   g_source_set_name_by_id (id, "[gtk+] gtk_tree_view_real_search_enable_popdown");
15256 }
15257 
15258 static gboolean
gtk_tree_view_search_delete_event(GtkWidget * widget,GdkEventAny * event,GtkTreeView * tree_view)15259 gtk_tree_view_search_delete_event (GtkWidget *widget,
15260 				   GdkEventAny *event,
15261 				   GtkTreeView *tree_view)
15262 {
15263   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15264 
15265   gtk_tree_view_search_window_hide (widget, tree_view, NULL);
15266 
15267   return TRUE;
15268 }
15269 
15270 static gboolean
gtk_tree_view_search_button_press_event(GtkWidget * widget,GdkEventButton * event,GtkTreeView * tree_view)15271 gtk_tree_view_search_button_press_event (GtkWidget *widget,
15272 					 GdkEventButton *event,
15273 					 GtkTreeView *tree_view)
15274 {
15275   GdkDevice *keyb_device;
15276 
15277   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15278 
15279   keyb_device = gdk_device_get_associated_device (event->device);
15280   gtk_tree_view_search_window_hide (widget, tree_view, keyb_device);
15281 
15282   return TRUE;
15283 }
15284 
15285 static gboolean
gtk_tree_view_search_scroll_event(GtkWidget * widget,GdkEventScroll * event,GtkTreeView * tree_view)15286 gtk_tree_view_search_scroll_event (GtkWidget *widget,
15287 				   GdkEventScroll *event,
15288 				   GtkTreeView *tree_view)
15289 {
15290   gboolean retval = FALSE;
15291 
15292   if (event->direction == GDK_SCROLL_UP)
15293     {
15294       gtk_tree_view_search_move (widget, tree_view, TRUE);
15295       retval = TRUE;
15296     }
15297   else if (event->direction == GDK_SCROLL_DOWN)
15298     {
15299       gtk_tree_view_search_move (widget, tree_view, FALSE);
15300       retval = TRUE;
15301     }
15302 
15303   /* renew the flush timeout */
15304   if (retval && tree_view->priv->typeselect_flush_timeout
15305       && !tree_view->priv->search_custom_entry_set)
15306     {
15307       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15308       tree_view->priv->typeselect_flush_timeout =
15309 	gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15310 		       (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15311 		       tree_view);
15312       g_source_set_name_by_id (tree_view->priv->typeselect_flush_timeout, "[gtk+] gtk_tree_view_search_entry_flush_timeout");
15313     }
15314 
15315   return retval;
15316 }
15317 
15318 static gboolean
gtk_tree_view_search_key_press_event(GtkWidget * widget,GdkEventKey * event,GtkTreeView * tree_view)15319 gtk_tree_view_search_key_press_event (GtkWidget *widget,
15320 				      GdkEventKey *event,
15321 				      GtkTreeView *tree_view)
15322 {
15323   GdkModifierType default_accel;
15324   gboolean        retval = FALSE;
15325 
15326   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15327   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15328 
15329   /* close window and cancel the search */
15330   if (!tree_view->priv->search_custom_entry_set
15331       && gtk_tree_view_search_key_cancels_search (event->keyval))
15332     {
15333       gtk_tree_view_search_window_hide (widget, tree_view,
15334                                         gdk_event_get_device ((GdkEvent *) event));
15335       return TRUE;
15336     }
15337 
15338   default_accel = gtk_widget_get_modifier_mask (widget,
15339                                                 GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
15340 
15341   /* select previous matching iter */
15342   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
15343     {
15344       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15345         gtk_widget_error_bell (widget);
15346 
15347       retval = TRUE;
15348     }
15349 
15350   if (((event->state & (default_accel | GDK_SHIFT_MASK)) == (default_accel | GDK_SHIFT_MASK))
15351       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15352     {
15353       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15354         gtk_widget_error_bell (widget);
15355 
15356       retval = TRUE;
15357     }
15358 
15359   /* select next matching iter */
15360   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
15361     {
15362       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15363         gtk_widget_error_bell (widget);
15364 
15365       retval = TRUE;
15366     }
15367 
15368   if (((event->state & (default_accel | GDK_SHIFT_MASK)) == default_accel)
15369       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15370     {
15371       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15372         gtk_widget_error_bell (widget);
15373 
15374       retval = TRUE;
15375     }
15376 
15377   /* renew the flush timeout */
15378   if (retval && tree_view->priv->typeselect_flush_timeout
15379       && !tree_view->priv->search_custom_entry_set)
15380     {
15381       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15382       tree_view->priv->typeselect_flush_timeout =
15383 	gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15384 		       (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15385 		       tree_view);
15386       g_source_set_name_by_id (tree_view->priv->typeselect_flush_timeout, "[gtk+] gtk_tree_view_search_entry_flush_timeout");
15387     }
15388 
15389   return retval;
15390 }
15391 
15392 /*  this function returns FALSE if there is a search string but
15393  *  nothing was found, and TRUE otherwise.
15394  */
15395 static gboolean
gtk_tree_view_search_move(GtkWidget * window,GtkTreeView * tree_view,gboolean up)15396 gtk_tree_view_search_move (GtkWidget   *window,
15397 			   GtkTreeView *tree_view,
15398 			   gboolean     up)
15399 {
15400   gboolean ret;
15401   gint len;
15402   gint count = 0;
15403   const gchar *text;
15404   GtkTreeIter iter;
15405   GtkTreeModel *model;
15406   GtkTreeSelection *selection;
15407 
15408   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
15409 
15410   g_return_val_if_fail (text != NULL, FALSE);
15411 
15412   len = strlen (text);
15413 
15414   if (up && tree_view->priv->selected_iter == 1)
15415     return len < 1;
15416 
15417   if (len < 1)
15418     return TRUE;
15419 
15420   model = gtk_tree_view_get_model (tree_view);
15421   selection = gtk_tree_view_get_selection (tree_view);
15422 
15423   /* search */
15424   gtk_tree_selection_unselect_all (selection);
15425   if (!gtk_tree_model_get_iter_first (model, &iter))
15426     return TRUE;
15427 
15428   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
15429 				   &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
15430 
15431   if (ret)
15432     {
15433       /* found */
15434       tree_view->priv->selected_iter += up?(-1):(1);
15435       return TRUE;
15436     }
15437   else
15438     {
15439       /* return to old iter */
15440       count = 0;
15441       gtk_tree_model_get_iter_first (model, &iter);
15442       gtk_tree_view_search_iter (model, selection,
15443 				 &iter, text,
15444 				 &count, tree_view->priv->selected_iter);
15445       return FALSE;
15446     }
15447 }
15448 
15449 static gboolean
gtk_tree_view_search_equal_func(GtkTreeModel * model,gint column,const gchar * key,GtkTreeIter * iter,gpointer search_data)15450 gtk_tree_view_search_equal_func (GtkTreeModel *model,
15451 				 gint          column,
15452 				 const gchar  *key,
15453 				 GtkTreeIter  *iter,
15454 				 gpointer      search_data)
15455 {
15456   gboolean retval = TRUE;
15457   const gchar *str;
15458   gchar *normalized_string;
15459   gchar *normalized_key;
15460   gchar *case_normalized_string = NULL;
15461   gchar *case_normalized_key = NULL;
15462   GValue value = G_VALUE_INIT;
15463   GValue transformed = G_VALUE_INIT;
15464 
15465   gtk_tree_model_get_value (model, iter, column, &value);
15466 
15467   g_value_init (&transformed, G_TYPE_STRING);
15468 
15469   if (!g_value_transform (&value, &transformed))
15470     {
15471       g_value_unset (&value);
15472       return TRUE;
15473     }
15474 
15475   g_value_unset (&value);
15476 
15477   str = g_value_get_string (&transformed);
15478   if (!str)
15479     {
15480       g_value_unset (&transformed);
15481       return TRUE;
15482     }
15483 
15484   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
15485   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
15486 
15487   if (normalized_string && normalized_key)
15488     {
15489       case_normalized_string = g_utf8_casefold (normalized_string, -1);
15490       case_normalized_key = g_utf8_casefold (normalized_key, -1);
15491 
15492       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
15493         retval = FALSE;
15494     }
15495 
15496   g_value_unset (&transformed);
15497   g_free (normalized_key);
15498   g_free (normalized_string);
15499   g_free (case_normalized_key);
15500   g_free (case_normalized_string);
15501 
15502   return retval;
15503 }
15504 
15505 static gboolean
gtk_tree_view_search_iter(GtkTreeModel * model,GtkTreeSelection * selection,GtkTreeIter * iter,const gchar * text,gint * count,gint n)15506 gtk_tree_view_search_iter (GtkTreeModel     *model,
15507 			   GtkTreeSelection *selection,
15508 			   GtkTreeIter      *iter,
15509 			   const gchar      *text,
15510 			   gint             *count,
15511 			   gint              n)
15512 {
15513   GtkRBTree *tree = NULL;
15514   GtkRBNode *node = NULL;
15515   GtkTreePath *path;
15516 
15517   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
15518 
15519   path = gtk_tree_model_get_path (model, iter);
15520   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15521 
15522   do
15523     {
15524       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
15525         {
15526           (*count)++;
15527           if (*count == n)
15528             {
15529               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
15530 					    TRUE, 0.5, 0.0);
15531               gtk_tree_selection_select_iter (selection, iter);
15532               gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
15533 
15534 	      if (path)
15535 		gtk_tree_path_free (path);
15536 
15537               return TRUE;
15538             }
15539         }
15540 
15541       if (node->children)
15542 	{
15543 	  gboolean has_child;
15544 	  GtkTreeIter tmp;
15545 
15546 	  tree = node->children;
15547           node = _gtk_rbtree_first (tree);
15548 
15549 	  tmp = *iter;
15550 	  has_child = gtk_tree_model_iter_children (model, iter, &tmp);
15551 	  gtk_tree_path_down (path);
15552 
15553 	  /* sanity check */
15554 	  TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
15555 	}
15556       else
15557 	{
15558 	  gboolean done = FALSE;
15559 
15560 	  do
15561 	    {
15562 	      node = _gtk_rbtree_next (tree, node);
15563 
15564 	      if (node)
15565 		{
15566 		  gboolean has_next;
15567 
15568 		  has_next = gtk_tree_model_iter_next (model, iter);
15569 
15570 		  done = TRUE;
15571 		  gtk_tree_path_next (path);
15572 
15573 		  /* sanity check */
15574 		  TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
15575 		}
15576 	      else
15577 		{
15578 		  gboolean has_parent;
15579 		  GtkTreeIter tmp_iter = *iter;
15580 
15581 		  node = tree->parent_node;
15582 		  tree = tree->parent_tree;
15583 
15584 		  if (!tree)
15585 		    {
15586 		      if (path)
15587 			gtk_tree_path_free (path);
15588 
15589 		      /* we've run out of tree, done with this func */
15590 		      return FALSE;
15591 		    }
15592 
15593 		  has_parent = gtk_tree_model_iter_parent (model,
15594 							   iter,
15595 							   &tmp_iter);
15596 		  gtk_tree_path_up (path);
15597 
15598 		  /* sanity check */
15599 		  TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
15600 		}
15601 	    }
15602 	  while (!done);
15603 	}
15604     }
15605   while (1);
15606 
15607   return FALSE;
15608 }
15609 
15610 static void
gtk_tree_view_search_init(GtkWidget * entry,GtkTreeView * tree_view)15611 gtk_tree_view_search_init (GtkWidget   *entry,
15612 			   GtkTreeView *tree_view)
15613 {
15614   gint ret;
15615   gint count = 0;
15616   const gchar *text;
15617   GtkTreeIter iter;
15618   GtkTreeModel *model;
15619   GtkTreeSelection *selection;
15620 
15621   g_return_if_fail (GTK_IS_ENTRY (entry));
15622   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15623 
15624   text = gtk_entry_get_text (GTK_ENTRY (entry));
15625 
15626   model = gtk_tree_view_get_model (tree_view);
15627   selection = gtk_tree_view_get_selection (tree_view);
15628 
15629   /* search */
15630   gtk_tree_selection_unselect_all (selection);
15631   if (tree_view->priv->typeselect_flush_timeout
15632       && !tree_view->priv->search_custom_entry_set)
15633     {
15634       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15635       tree_view->priv->typeselect_flush_timeout =
15636 	gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15637 		       (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15638 		       tree_view);
15639       g_source_set_name_by_id (tree_view->priv->typeselect_flush_timeout, "[gtk+] gtk_tree_view_search_entry_flush_timeout");
15640     }
15641 
15642   if (*text == '\0')
15643     return;
15644 
15645   if (!gtk_tree_model_get_iter_first (model, &iter))
15646     return;
15647 
15648   ret = gtk_tree_view_search_iter (model, selection,
15649 				   &iter, text,
15650 				   &count, 1);
15651 
15652   if (ret)
15653     tree_view->priv->selected_iter = 1;
15654 }
15655 
15656 void
_gtk_tree_view_remove_editable(GtkTreeView * tree_view,GtkTreeViewColumn * column,GtkCellEditable * cell_editable)15657 _gtk_tree_view_remove_editable (GtkTreeView       *tree_view,
15658                                 GtkTreeViewColumn *column,
15659                                 GtkCellEditable   *cell_editable)
15660 {
15661   if (tree_view->priv->edited_column == NULL)
15662     return;
15663 
15664   g_return_if_fail (column == tree_view->priv->edited_column);
15665 
15666   tree_view->priv->edited_column = NULL;
15667 
15668   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
15669     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
15670 
15671   gtk_container_remove (GTK_CONTAINER (tree_view),
15672                         GTK_WIDGET (cell_editable));
15673 
15674   /* FIXME should only redraw a single node */
15675   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15676 }
15677 
15678 static gboolean
gtk_tree_view_start_editing(GtkTreeView * tree_view,GtkTreePath * cursor_path,gboolean edit_only)15679 gtk_tree_view_start_editing (GtkTreeView *tree_view,
15680 			     GtkTreePath *cursor_path,
15681 			     gboolean     edit_only)
15682 {
15683   GtkTreeIter iter;
15684   GdkRectangle cell_area;
15685   GtkTreeViewColumn *focus_column;
15686   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
15687   gint retval = FALSE;
15688   GtkRBTree *cursor_tree;
15689   GtkRBNode *cursor_node;
15690 
15691   g_assert (tree_view->priv->focus_column);
15692   focus_column = tree_view->priv->focus_column;
15693 
15694   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
15695     return FALSE;
15696 
15697   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
15698       cursor_node == NULL)
15699     return FALSE;
15700 
15701   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
15702 
15703   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
15704 
15705   gtk_tree_view_column_cell_set_cell_data (focus_column,
15706                                            tree_view->priv->model,
15707                                            &iter,
15708                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
15709                                            cursor_node->children ? TRUE : FALSE);
15710   gtk_tree_view_get_cell_area (tree_view,
15711                                cursor_path,
15712                                focus_column,
15713                                &cell_area);
15714 
15715   if (gtk_cell_area_activate (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (focus_column)),
15716                               _gtk_tree_view_column_get_context (focus_column),
15717                               GTK_WIDGET (tree_view),
15718                               &cell_area,
15719                               flags, edit_only))
15720     retval = TRUE;
15721 
15722   return retval;
15723 }
15724 
15725 void
_gtk_tree_view_add_editable(GtkTreeView * tree_view,GtkTreeViewColumn * column,GtkTreePath * path,GtkCellEditable * cell_editable,GdkRectangle * cell_area)15726 _gtk_tree_view_add_editable (GtkTreeView       *tree_view,
15727                              GtkTreeViewColumn *column,
15728                              GtkTreePath       *path,
15729                              GtkCellEditable   *cell_editable,
15730                              GdkRectangle      *cell_area)
15731 {
15732   GdkRectangle full_area;
15733   GtkBorder border;
15734 
15735   tree_view->priv->edited_column = column;
15736 
15737   gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
15738 
15739   tree_view->priv->draw_keyfocus = TRUE;
15740 
15741   gtk_tree_view_get_cell_area (tree_view, path, column, &full_area);
15742   border.left = cell_area->x - full_area.x;
15743   border.top = cell_area->y - full_area.y;
15744   border.right = (full_area.x + full_area.width) - (cell_area->x + cell_area->width);
15745   border.bottom = (full_area.y + full_area.height) - (cell_area->y + cell_area->height);
15746 
15747   gtk_tree_view_put (tree_view,
15748                      GTK_WIDGET (cell_editable),
15749                      path,
15750                      column,
15751                      &border);
15752 }
15753 
15754 static void
gtk_tree_view_stop_editing(GtkTreeView * tree_view,gboolean cancel_editing)15755 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
15756 			    gboolean     cancel_editing)
15757 {
15758   GtkTreeViewColumn *column;
15759 
15760   if (tree_view->priv->edited_column == NULL)
15761     return;
15762 
15763   /*
15764    * This is very evil. We need to do this, because
15765    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
15766    * later on. If gtk_tree_view_row_changed notices
15767    * tree_view->priv->edited_column != NULL, it'll call
15768    * gtk_tree_view_stop_editing again. Bad things will happen then.
15769    *
15770    * Please read that again if you intend to modify anything here.
15771    */
15772 
15773   column = tree_view->priv->edited_column;
15774   gtk_cell_area_stop_editing (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column)), cancel_editing);
15775   tree_view->priv->edited_column = NULL;
15776 }
15777 
15778 
15779 /**
15780  * gtk_tree_view_set_hover_selection:
15781  * @tree_view: a #GtkTreeView
15782  * @hover: %TRUE to enable hover selection mode
15783  *
15784  * Enables or disables the hover selection mode of @tree_view.
15785  * Hover selection makes the selected row follow the pointer.
15786  * Currently, this works only for the selection modes
15787  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
15788  *
15789  * Since: 2.6
15790  **/
15791 void
gtk_tree_view_set_hover_selection(GtkTreeView * tree_view,gboolean hover)15792 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
15793 				   gboolean     hover)
15794 {
15795   hover = hover != FALSE;
15796 
15797   if (hover != tree_view->priv->hover_selection)
15798     {
15799       tree_view->priv->hover_selection = hover;
15800 
15801       g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_HOVER_SELECTION]);
15802     }
15803 }
15804 
15805 /**
15806  * gtk_tree_view_get_hover_selection:
15807  * @tree_view: a #GtkTreeView
15808  *
15809  * Returns whether hover selection mode is turned on for @tree_view.
15810  *
15811  * Returns: %TRUE if @tree_view is in hover selection mode
15812  *
15813  * Since: 2.6
15814  **/
15815 gboolean
gtk_tree_view_get_hover_selection(GtkTreeView * tree_view)15816 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
15817 {
15818   return tree_view->priv->hover_selection;
15819 }
15820 
15821 /**
15822  * gtk_tree_view_set_hover_expand:
15823  * @tree_view: a #GtkTreeView
15824  * @expand: %TRUE to enable hover selection mode
15825  *
15826  * Enables or disables the hover expansion mode of @tree_view.
15827  * Hover expansion makes rows expand or collapse if the pointer
15828  * moves over them.
15829  *
15830  * Since: 2.6
15831  **/
15832 void
gtk_tree_view_set_hover_expand(GtkTreeView * tree_view,gboolean expand)15833 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15834 				gboolean     expand)
15835 {
15836   expand = expand != FALSE;
15837 
15838   if (expand != tree_view->priv->hover_expand)
15839     {
15840       tree_view->priv->hover_expand = expand;
15841 
15842       g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_HOVER_EXPAND]);
15843     }
15844 }
15845 
15846 /**
15847  * gtk_tree_view_get_hover_expand:
15848  * @tree_view: a #GtkTreeView
15849  *
15850  * Returns whether hover expansion mode is turned on for @tree_view.
15851  *
15852  * Returns: %TRUE if @tree_view is in hover expansion mode
15853  *
15854  * Since: 2.6
15855  **/
15856 gboolean
gtk_tree_view_get_hover_expand(GtkTreeView * tree_view)15857 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15858 {
15859   return tree_view->priv->hover_expand;
15860 }
15861 
15862 /**
15863  * gtk_tree_view_set_rubber_banding:
15864  * @tree_view: a #GtkTreeView
15865  * @enable: %TRUE to enable rubber banding
15866  *
15867  * Enables or disables rubber banding in @tree_view.  If the selection mode
15868  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15869  * multiple rows by dragging the mouse.
15870  *
15871  * Since: 2.10
15872  **/
15873 void
gtk_tree_view_set_rubber_banding(GtkTreeView * tree_view,gboolean enable)15874 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15875 				  gboolean     enable)
15876 {
15877   enable = enable != FALSE;
15878 
15879   if (enable != tree_view->priv->rubber_banding_enable)
15880     {
15881       tree_view->priv->rubber_banding_enable = enable;
15882 
15883       g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_RUBBER_BANDING]);
15884     }
15885 }
15886 
15887 /**
15888  * gtk_tree_view_get_rubber_banding:
15889  * @tree_view: a #GtkTreeView
15890  *
15891  * Returns whether rubber banding is turned on for @tree_view.  If the
15892  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15893  * user to select multiple rows by dragging the mouse.
15894  *
15895  * Returns: %TRUE if rubber banding in @tree_view is enabled.
15896  *
15897  * Since: 2.10
15898  **/
15899 gboolean
gtk_tree_view_get_rubber_banding(GtkTreeView * tree_view)15900 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15901 {
15902   return tree_view->priv->rubber_banding_enable;
15903 }
15904 
15905 /**
15906  * gtk_tree_view_is_rubber_banding_active:
15907  * @tree_view: a #GtkTreeView
15908  *
15909  * Returns whether a rubber banding operation is currently being done
15910  * in @tree_view.
15911  *
15912  * Returns: %TRUE if a rubber banding operation is currently being
15913  * done in @tree_view.
15914  *
15915  * Since: 2.12
15916  **/
15917 gboolean
gtk_tree_view_is_rubber_banding_active(GtkTreeView * tree_view)15918 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15919 {
15920   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15921 
15922   if (tree_view->priv->rubber_banding_enable
15923       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15924     return TRUE;
15925 
15926   return FALSE;
15927 }
15928 
15929 /**
15930  * gtk_tree_view_get_row_separator_func: (skip)
15931  * @tree_view: a #GtkTreeView
15932  *
15933  * Returns the current row separator function.
15934  *
15935  * Returns: the current row separator function.
15936  *
15937  * Since: 2.6
15938  **/
15939 GtkTreeViewRowSeparatorFunc
gtk_tree_view_get_row_separator_func(GtkTreeView * tree_view)15940 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15941 {
15942   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15943 
15944   return tree_view->priv->row_separator_func;
15945 }
15946 
15947 /**
15948  * gtk_tree_view_set_row_separator_func:
15949  * @tree_view: a #GtkTreeView
15950  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15951  * @data: (allow-none): user data to pass to @func, or %NULL
15952  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15953  *
15954  * Sets the row separator function, which is used to determine
15955  * whether a row should be drawn as a separator. If the row separator
15956  * function is %NULL, no separators are drawn. This is the default value.
15957  *
15958  * Since: 2.6
15959  **/
15960 void
gtk_tree_view_set_row_separator_func(GtkTreeView * tree_view,GtkTreeViewRowSeparatorFunc func,gpointer data,GDestroyNotify destroy)15961 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15962 				      GtkTreeViewRowSeparatorFunc  func,
15963 				      gpointer                     data,
15964 				      GDestroyNotify               destroy)
15965 {
15966   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15967 
15968   if (tree_view->priv->row_separator_destroy)
15969     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15970 
15971   tree_view->priv->row_separator_func = func;
15972   tree_view->priv->row_separator_data = data;
15973   tree_view->priv->row_separator_destroy = destroy;
15974 
15975   /* Have the tree recalculate heights */
15976   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15977   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15978 }
15979 
15980 /**
15981  * gtk_tree_view_get_grid_lines:
15982  * @tree_view: a #GtkTreeView
15983  *
15984  * Returns which grid lines are enabled in @tree_view.
15985  *
15986  * Returns: a #GtkTreeViewGridLines value indicating which grid lines
15987  * are enabled.
15988  *
15989  * Since: 2.10
15990  */
15991 GtkTreeViewGridLines
gtk_tree_view_get_grid_lines(GtkTreeView * tree_view)15992 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15993 {
15994   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15995 
15996   return tree_view->priv->grid_lines;
15997 }
15998 
15999 /**
16000  * gtk_tree_view_set_grid_lines:
16001  * @tree_view: a #GtkTreeView
16002  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
16003  * enable.
16004  *
16005  * Sets which grid lines to draw in @tree_view.
16006  *
16007  * Since: 2.10
16008  */
16009 void
gtk_tree_view_set_grid_lines(GtkTreeView * tree_view,GtkTreeViewGridLines grid_lines)16010 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
16011 			      GtkTreeViewGridLines   grid_lines)
16012 {
16013   GtkTreeViewPrivate *priv;
16014   GtkWidget *widget;
16015   GtkTreeViewGridLines old_grid_lines;
16016 
16017   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16018 
16019   priv = tree_view->priv;
16020   widget = GTK_WIDGET (tree_view);
16021 
16022   old_grid_lines = priv->grid_lines;
16023   priv->grid_lines = grid_lines;
16024 
16025   if (gtk_widget_get_realized (widget))
16026     {
16027       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
16028 	  priv->grid_line_width)
16029 	{
16030 	  priv->grid_line_width = 0;
16031 	}
16032 
16033       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE &&
16034 	  !priv->grid_line_width)
16035 	{
16036 	  gint8 *dash_list;
16037 
16038 	  gtk_widget_style_get (widget,
16039 				"grid-line-width", &priv->grid_line_width,
16040 				"grid-line-pattern", (gchar *)&dash_list,
16041 				NULL);
16042 
16043           if (dash_list)
16044             {
16045               priv->grid_line_dashes[0] = dash_list[0];
16046               if (dash_list[0])
16047                 priv->grid_line_dashes[1] = dash_list[1];
16048 
16049               g_free (dash_list);
16050             }
16051           else
16052             {
16053               priv->grid_line_dashes[0] = 1;
16054               priv->grid_line_dashes[1] = 1;
16055             }
16056 	}
16057     }
16058 
16059   if (old_grid_lines != grid_lines)
16060     {
16061       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16062 
16063       g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_ENABLE_GRID_LINES]);
16064     }
16065 }
16066 
16067 /**
16068  * gtk_tree_view_get_enable_tree_lines:
16069  * @tree_view: a #GtkTreeView.
16070  *
16071  * Returns whether or not tree lines are drawn in @tree_view.
16072  *
16073  * Returns: %TRUE if tree lines are drawn in @tree_view, %FALSE
16074  * otherwise.
16075  *
16076  * Since: 2.10
16077  */
16078 gboolean
gtk_tree_view_get_enable_tree_lines(GtkTreeView * tree_view)16079 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
16080 {
16081   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16082 
16083   return tree_view->priv->tree_lines_enabled;
16084 }
16085 
16086 /**
16087  * gtk_tree_view_set_enable_tree_lines:
16088  * @tree_view: a #GtkTreeView
16089  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
16090  *
16091  * Sets whether to draw lines interconnecting the expanders in @tree_view.
16092  * This does not have any visible effects for lists.
16093  *
16094  * Since: 2.10
16095  */
16096 void
gtk_tree_view_set_enable_tree_lines(GtkTreeView * tree_view,gboolean enabled)16097 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
16098 				     gboolean     enabled)
16099 {
16100   GtkTreeViewPrivate *priv;
16101   GtkWidget *widget;
16102   gboolean was_enabled;
16103 
16104   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16105 
16106   enabled = enabled != FALSE;
16107 
16108   priv = tree_view->priv;
16109   widget = GTK_WIDGET (tree_view);
16110 
16111   was_enabled = priv->tree_lines_enabled;
16112 
16113   priv->tree_lines_enabled = enabled;
16114 
16115   if (gtk_widget_get_realized (widget))
16116     {
16117       if (!enabled && priv->tree_line_width)
16118 	{
16119           priv->tree_line_width = 0;
16120 	}
16121 
16122       if (enabled && !priv->tree_line_width)
16123 	{
16124 	  gint8 *dash_list;
16125 	  gtk_widget_style_get (widget,
16126 				"tree-line-width", &priv->tree_line_width,
16127 				"tree-line-pattern", (gchar *)&dash_list,
16128 				NULL);
16129 
16130           if (dash_list)
16131             {
16132               priv->tree_line_dashes[0] = dash_list[0];
16133               if (dash_list[0])
16134                 priv->tree_line_dashes[1] = dash_list[1];
16135 
16136               g_free (dash_list);
16137             }
16138           else
16139             {
16140               priv->tree_line_dashes[0] = 1;
16141               priv->tree_line_dashes[1] = 1;
16142             }
16143 	}
16144     }
16145 
16146   if (was_enabled != enabled)
16147     {
16148       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16149 
16150       g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_ENABLE_TREE_LINES]);
16151     }
16152 }
16153 
16154 
16155 /**
16156  * gtk_tree_view_set_show_expanders:
16157  * @tree_view: a #GtkTreeView
16158  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
16159  *
16160  * Sets whether to draw and enable expanders and indent child rows in
16161  * @tree_view.  When disabled there will be no expanders visible in trees
16162  * and there will be no way to expand and collapse rows by default.  Also
16163  * note that hiding the expanders will disable the default indentation.  You
16164  * can set a custom indentation in this case using
16165  * gtk_tree_view_set_level_indentation().
16166  * This does not have any visible effects for lists.
16167  *
16168  * Since: 2.12
16169  */
16170 void
gtk_tree_view_set_show_expanders(GtkTreeView * tree_view,gboolean enabled)16171 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
16172 				  gboolean     enabled)
16173 {
16174   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16175 
16176   enabled = enabled != FALSE;
16177   if (tree_view->priv->show_expanders != enabled)
16178     {
16179       tree_view->priv->show_expanders = enabled;
16180       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16181       g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_SHOW_EXPANDERS]);
16182     }
16183 }
16184 
16185 /**
16186  * gtk_tree_view_get_show_expanders:
16187  * @tree_view: a #GtkTreeView.
16188  *
16189  * Returns whether or not expanders are drawn in @tree_view.
16190  *
16191  * Returns: %TRUE if expanders are drawn in @tree_view, %FALSE
16192  * otherwise.
16193  *
16194  * Since: 2.12
16195  */
16196 gboolean
gtk_tree_view_get_show_expanders(GtkTreeView * tree_view)16197 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
16198 {
16199   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16200 
16201   return tree_view->priv->show_expanders;
16202 }
16203 
16204 /**
16205  * gtk_tree_view_set_level_indentation:
16206  * @tree_view: a #GtkTreeView
16207  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
16208  *
16209  * Sets the amount of extra indentation for child levels to use in @tree_view
16210  * in addition to the default indentation.  The value should be specified in
16211  * pixels, a value of 0 disables this feature and in this case only the default
16212  * indentation will be used.
16213  * This does not have any visible effects for lists.
16214  *
16215  * Since: 2.12
16216  */
16217 void
gtk_tree_view_set_level_indentation(GtkTreeView * tree_view,gint indentation)16218 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
16219 				     gint         indentation)
16220 {
16221   tree_view->priv->level_indentation = indentation;
16222 
16223   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16224 }
16225 
16226 /**
16227  * gtk_tree_view_get_level_indentation:
16228  * @tree_view: a #GtkTreeView.
16229  *
16230  * Returns the amount, in pixels, of extra indentation for child levels
16231  * in @tree_view.
16232  *
16233  * Returns: the amount of extra indentation for child levels in
16234  * @tree_view.  A return value of 0 means that this feature is disabled.
16235  *
16236  * Since: 2.12
16237  */
16238 gint
gtk_tree_view_get_level_indentation(GtkTreeView * tree_view)16239 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
16240 {
16241   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16242 
16243   return tree_view->priv->level_indentation;
16244 }
16245 
16246 /**
16247  * gtk_tree_view_set_tooltip_row:
16248  * @tree_view: a #GtkTreeView
16249  * @tooltip: a #GtkTooltip
16250  * @path: a #GtkTreePath
16251  *
16252  * Sets the tip area of @tooltip to be the area covered by the row at @path.
16253  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16254  * See also gtk_tooltip_set_tip_area().
16255  *
16256  * Since: 2.12
16257  */
16258 void
gtk_tree_view_set_tooltip_row(GtkTreeView * tree_view,GtkTooltip * tooltip,GtkTreePath * path)16259 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
16260 			       GtkTooltip  *tooltip,
16261 			       GtkTreePath *path)
16262 {
16263   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16264   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16265 
16266   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
16267 }
16268 
16269 /**
16270  * gtk_tree_view_set_tooltip_cell:
16271  * @tree_view: a #GtkTreeView
16272  * @tooltip: a #GtkTooltip
16273  * @path: (allow-none): a #GtkTreePath or %NULL
16274  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
16275  * @cell: (allow-none): a #GtkCellRenderer or %NULL
16276  *
16277  * Sets the tip area of @tooltip to the area @path, @column and @cell have
16278  * in common.  For example if @path is %NULL and @column is set, the tip
16279  * area will be set to the full area covered by @column.  See also
16280  * gtk_tooltip_set_tip_area().
16281  *
16282  * Note that if @path is not specified and @cell is set and part of a column
16283  * containing the expander, the tooltip might not show and hide at the correct
16284  * position.  In such cases @path must be set to the current node under the
16285  * mouse cursor for this function to operate correctly.
16286  *
16287  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16288  *
16289  * Since: 2.12
16290  */
16291 void
gtk_tree_view_set_tooltip_cell(GtkTreeView * tree_view,GtkTooltip * tooltip,GtkTreePath * path,GtkTreeViewColumn * column,GtkCellRenderer * cell)16292 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
16293 				GtkTooltip        *tooltip,
16294 				GtkTreePath       *path,
16295 				GtkTreeViewColumn *column,
16296 				GtkCellRenderer   *cell)
16297 {
16298   GtkAllocation allocation;
16299   GdkRectangle rect;
16300 
16301   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16302   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16303   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
16304   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
16305 
16306   /* Determine x values. */
16307   if (column && cell)
16308     {
16309       GdkRectangle tmp;
16310       gint start, width;
16311 
16312       /* We always pass in path here, whether it is NULL or not.
16313        * For cells in expander columns path must be specified so that
16314        * we can correctly account for the indentation.  This also means
16315        * that the tooltip is constrained vertically by the "Determine y
16316        * values" code below; this is not a real problem since cells actually
16317        * don't stretch vertically in constrast to columns.
16318        */
16319       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
16320       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
16321 
16322       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16323 							 tmp.x + start, 0,
16324 							 &rect.x, NULL);
16325       rect.width = width;
16326     }
16327   else if (column)
16328     {
16329       GdkRectangle tmp;
16330 
16331       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
16332       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16333 							 tmp.x, 0,
16334 							 &rect.x, NULL);
16335       rect.width = tmp.width;
16336     }
16337   else
16338     {
16339       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
16340       rect.x = 0;
16341       rect.width = allocation.width;
16342     }
16343 
16344   /* Determine y values. */
16345   if (path)
16346     {
16347       GdkRectangle tmp;
16348 
16349       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
16350       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16351 							 0, tmp.y,
16352 							 NULL, &rect.y);
16353       rect.height = tmp.height;
16354     }
16355   else
16356     {
16357       rect.y = 0;
16358       rect.height = gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
16359     }
16360 
16361   gtk_tooltip_set_tip_area (tooltip, &rect);
16362 }
16363 
16364 /**
16365  * gtk_tree_view_get_tooltip_context:
16366  * @tree_view: a #GtkTreeView
16367  * @x: (inout): the x coordinate (relative to widget coordinates)
16368  * @y: (inout): the y coordinate (relative to widget coordinates)
16369  * @keyboard_tip: whether this is a keyboard tooltip or not
16370  * @model: (out) (optional) (nullable) (transfer none): a pointer to
16371  *         receive a #GtkTreeModel or %NULL
16372  * @path: (out) (optional): a pointer to receive a #GtkTreePath or %NULL
16373  * @iter: (out) (optional): a pointer to receive a #GtkTreeIter or %NULL
16374  *
16375  * This function is supposed to be used in a #GtkWidget::query-tooltip
16376  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
16377  * which are received in the signal handler, should be passed to this
16378  * function without modification.
16379  *
16380  * The return value indicates whether there is a tree view row at the given
16381  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
16382  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
16383  * @model, @path and @iter which have been provided will be set to point to
16384  * that row and the corresponding model.  @x and @y will always be converted
16385  * to be relative to @tree_view’s bin_window if @keyboard_tooltip is %FALSE.
16386  *
16387  * Returns: whether or not the given tooltip context points to a row.
16388  *
16389  * Since: 2.12
16390  */
16391 gboolean
gtk_tree_view_get_tooltip_context(GtkTreeView * tree_view,gint * x,gint * y,gboolean keyboard_tip,GtkTreeModel ** model,GtkTreePath ** path,GtkTreeIter * iter)16392 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
16393 				   gint          *x,
16394 				   gint          *y,
16395 				   gboolean       keyboard_tip,
16396 				   GtkTreeModel **model,
16397 				   GtkTreePath  **path,
16398 				   GtkTreeIter   *iter)
16399 {
16400   GtkTreePath *tmppath = NULL;
16401 
16402   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16403   g_return_val_if_fail (x != NULL, FALSE);
16404   g_return_val_if_fail (y != NULL, FALSE);
16405 
16406   if (keyboard_tip)
16407     {
16408       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
16409 
16410       if (!tmppath)
16411 	return FALSE;
16412     }
16413   else
16414     {
16415       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
16416 							 x, y);
16417 
16418       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
16419 					  &tmppath, NULL, NULL, NULL))
16420 	return FALSE;
16421     }
16422 
16423   if (model)
16424     *model = gtk_tree_view_get_model (tree_view);
16425 
16426   if (iter)
16427     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
16428 			     iter, tmppath);
16429 
16430   if (path)
16431     *path = tmppath;
16432   else
16433     gtk_tree_path_free (tmppath);
16434 
16435   return TRUE;
16436 }
16437 
16438 static gboolean
gtk_tree_view_set_tooltip_query_cb(GtkWidget * widget,gint x,gint y,gboolean keyboard_tip,GtkTooltip * tooltip,gpointer data)16439 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
16440 				    gint        x,
16441 				    gint        y,
16442 				    gboolean    keyboard_tip,
16443 				    GtkTooltip *tooltip,
16444 				    gpointer    data)
16445 {
16446   GValue value = G_VALUE_INIT;
16447   GValue transformed = G_VALUE_INIT;
16448   GtkTreeIter iter;
16449   GtkTreePath *path;
16450   GtkTreeModel *model;
16451   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
16452   const char *transformed_str = NULL;
16453 
16454   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
16455 					  &x, &y,
16456 					  keyboard_tip,
16457 					  &model, &path, &iter))
16458     return FALSE;
16459 
16460   gtk_tree_model_get_value (model, &iter,
16461                             tree_view->priv->tooltip_column, &value);
16462 
16463   g_value_init (&transformed, G_TYPE_STRING);
16464 
16465   if (!g_value_transform (&value, &transformed))
16466     {
16467       g_value_unset (&value);
16468       gtk_tree_path_free (path);
16469 
16470       return FALSE;
16471     }
16472 
16473   g_value_unset (&value);
16474 
16475   transformed_str = g_value_get_string (&transformed);
16476   if (transformed_str == NULL || *transformed_str == '\0')
16477     {
16478       g_value_unset (&transformed);
16479       gtk_tree_path_free (path);
16480 
16481       return FALSE;
16482     }
16483 
16484   gtk_tooltip_set_markup (tooltip, transformed_str);
16485   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
16486 
16487   gtk_tree_path_free (path);
16488   g_value_unset (&transformed);
16489 
16490   return TRUE;
16491 }
16492 
16493 /**
16494  * gtk_tree_view_set_tooltip_column:
16495  * @tree_view: a #GtkTreeView
16496  * @column: an integer, which is a valid column number for @tree_view’s model
16497  *
16498  * If you only plan to have simple (text-only) tooltips on full rows, you
16499  * can use this function to have #GtkTreeView handle these automatically
16500  * for you. @column should be set to the column in @tree_view’s model
16501  * containing the tooltip texts, or -1 to disable this feature.
16502  *
16503  * When enabled, #GtkWidget:has-tooltip will be set to %TRUE and
16504  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
16505  *
16506  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
16507  * so &, <, etc have to be escaped in the text.
16508  *
16509  * Since: 2.12
16510  */
16511 void
gtk_tree_view_set_tooltip_column(GtkTreeView * tree_view,gint column)16512 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
16513 			          gint         column)
16514 {
16515   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16516 
16517   if (column == tree_view->priv->tooltip_column)
16518     return;
16519 
16520   if (column == -1)
16521     {
16522       g_signal_handlers_disconnect_by_func (tree_view,
16523 	  				    gtk_tree_view_set_tooltip_query_cb,
16524 					    NULL);
16525       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
16526     }
16527   else
16528     {
16529       if (tree_view->priv->tooltip_column == -1)
16530         {
16531           g_signal_connect (tree_view, "query-tooltip",
16532 		            G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
16533           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
16534         }
16535     }
16536 
16537   tree_view->priv->tooltip_column = column;
16538   g_object_notify_by_pspec (G_OBJECT (tree_view), tree_view_props[PROP_TOOLTIP_COLUMN]);
16539 }
16540 
16541 /**
16542  * gtk_tree_view_get_tooltip_column:
16543  * @tree_view: a #GtkTreeView
16544  *
16545  * Returns the column of @tree_view’s model which is being used for
16546  * displaying tooltips on @tree_view’s rows.
16547  *
16548  * Returns: the index of the tooltip column that is currently being
16549  * used, or -1 if this is disabled.
16550  *
16551  * Since: 2.12
16552  */
16553 gint
gtk_tree_view_get_tooltip_column(GtkTreeView * tree_view)16554 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
16555 {
16556   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16557 
16558   return tree_view->priv->tooltip_column;
16559 }
16560 
16561 static gboolean
gtk_tree_view_get_border(GtkScrollable * scrollable,GtkBorder * border)16562 gtk_tree_view_get_border (GtkScrollable *scrollable,
16563                           GtkBorder     *border)
16564 {
16565   border->top = _gtk_tree_view_get_header_height (GTK_TREE_VIEW (scrollable));
16566 
16567   return TRUE;
16568 }
16569 
16570 static void
gtk_tree_view_scrollable_init(GtkScrollableInterface * iface)16571 gtk_tree_view_scrollable_init (GtkScrollableInterface *iface)
16572 {
16573   iface->get_border = gtk_tree_view_get_border;
16574 }
16575