1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald,
3  * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>
4  *
5  * GtkCTree widget for GTK+
6  * Copyright (C) 1998 Lars Hamann and Stefan Jeske
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23 
24 /*
25  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
26  * file for a list of people on the GTK+ Team.  See the ChangeLog
27  * files for a list of changes.  These files are distributed with
28  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
29  */
30 
31 #include "config.h"
32 #include <stdlib.h>
33 
34 #undef GDK_DISABLE_DEPRECATED
35 #undef GTK_DISABLE_DEPRECATED
36 #define __GTK_CTREE_C__
37 
38 #include "gtkctree.h"
39 #include "gtkbindings.h"
40 #include "gtkmain.h"
41 #include "gtkmarshalers.h"
42 #include "gtkdnd.h"
43 #include "gtkintl.h"
44 #include <gdk/gdkkeysyms.h>
45 
46 #include "gtkalias.h"
47 
48 #define PM_SIZE                    8
49 #define TAB_SIZE                   (PM_SIZE + 6)
50 #define CELL_SPACING               1
51 #define CLIST_OPTIMUM_SIZE         64
52 #define COLUMN_INSET               3
53 #define DRAG_WIDTH                 6
54 
55 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
56 				    (((row) + 1) * CELL_SPACING) + \
57 				    (clist)->voffset)
58 #define ROW_FROM_YPIXEL(clist, y)  (((y) - (clist)->voffset) / \
59                                     ((clist)->row_height + CELL_SPACING))
60 #define COLUMN_LEFT_XPIXEL(clist, col)  ((clist)->column[(col)].area.x \
61                                     + (clist)->hoffset)
62 #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x)
63 
64 static inline gint
COLUMN_FROM_XPIXEL(GtkCList * clist,gint x)65 COLUMN_FROM_XPIXEL (GtkCList * clist,
66 		    gint x)
67 {
68   gint i, cx;
69 
70   for (i = 0; i < clist->columns; i++)
71     if (clist->column[i].visible)
72       {
73 	cx = clist->column[i].area.x + clist->hoffset;
74 
75 	if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) &&
76 	    x <= (cx + clist->column[i].area.width + COLUMN_INSET))
77 	  return i;
78       }
79 
80   /* no match */
81   return -1;
82 }
83 
84 #define CLIST_UNFROZEN(clist)     (((GtkCList*) (clist))->freeze_count == 0)
85 #define CLIST_REFRESH(clist)    G_STMT_START { \
86   if (CLIST_UNFROZEN (clist)) \
87     GTK_CLIST_GET_CLASS (clist)->refresh ((GtkCList*) (clist)); \
88 } G_STMT_END
89 
90 
91 enum {
92   ARG_0,
93   ARG_N_COLUMNS,
94   ARG_TREE_COLUMN,
95   ARG_INDENT,
96   ARG_SPACING,
97   ARG_SHOW_STUB,
98   ARG_LINE_STYLE,
99   ARG_EXPANDER_STYLE
100 };
101 
102 
103 static void     gtk_ctree_class_init    (GtkCTreeClass         *klass);
104 static void     gtk_ctree_init          (GtkCTree              *ctree);
105 static GObject* gtk_ctree_constructor   (GType                  type,
106 				         guint                  n_construct_properties,
107 				         GObjectConstructParam *construct_params);
108 static void gtk_ctree_set_arg		(GtkObject      *object,
109 					 GtkArg         *arg,
110 					 guint           arg_id);
111 static void gtk_ctree_get_arg      	(GtkObject      *object,
112 					 GtkArg         *arg,
113 					 guint           arg_id);
114 static void gtk_ctree_realize           (GtkWidget      *widget);
115 static void gtk_ctree_unrealize         (GtkWidget      *widget);
116 static gint gtk_ctree_button_press      (GtkWidget      *widget,
117 					 GdkEventButton *event);
118 static void ctree_attach_styles         (GtkCTree       *ctree,
119 					 GtkCTreeNode   *node,
120 					 gpointer        data);
121 static void ctree_detach_styles         (GtkCTree       *ctree,
122 					 GtkCTreeNode   *node,
123 					 gpointer        data);
124 static gint draw_cell_pixmap            (GdkWindow      *window,
125 					 GdkRectangle   *clip_rectangle,
126 					 GdkGC          *fg_gc,
127 					 GdkPixmap      *pixmap,
128 					 GdkBitmap      *mask,
129 					 gint            x,
130 					 gint            y,
131 					 gint            width,
132 					 gint            height);
133 static void get_cell_style              (GtkCList       *clist,
134 					 GtkCListRow    *clist_row,
135 					 gint            state,
136 					 gint            column,
137 					 GtkStyle      **style,
138 					 GdkGC         **fg_gc,
139 					 GdkGC         **bg_gc);
140 static gint gtk_ctree_draw_expander     (GtkCTree       *ctree,
141 					 GtkCTreeRow    *ctree_row,
142 					 GtkStyle       *style,
143 					 GdkRectangle   *clip_rectangle,
144 					 gint            x);
145 static gint gtk_ctree_draw_lines        (GtkCTree       *ctree,
146 					 GtkCTreeRow    *ctree_row,
147 					 gint            row,
148 					 gint            column,
149 					 gint            state,
150 					 GdkRectangle   *clip_rectangle,
151 					 GdkRectangle   *cell_rectangle,
152 					 GdkRectangle   *crect,
153 					 GdkRectangle   *area,
154 					 GtkStyle       *style);
155 static void draw_row                    (GtkCList       *clist,
156 					 GdkRectangle   *area,
157 					 gint            row,
158 					 GtkCListRow    *clist_row);
159 static void draw_drag_highlight         (GtkCList        *clist,
160 					 GtkCListRow     *dest_row,
161 					 gint             dest_row_number,
162 					 GtkCListDragPos  drag_pos);
163 static void tree_draw_node              (GtkCTree      *ctree,
164 					 GtkCTreeNode  *node);
165 static void set_cell_contents           (GtkCList      *clist,
166 					 GtkCListRow   *clist_row,
167 					 gint           column,
168 					 GtkCellType    type,
169 					 const gchar   *text,
170 					 guint8         spacing,
171 					 GdkPixmap     *pixmap,
172 					 GdkBitmap     *mask);
173 static void set_node_info               (GtkCTree      *ctree,
174 					 GtkCTreeNode  *node,
175 					 const gchar   *text,
176 					 guint8         spacing,
177 					 GdkPixmap     *pixmap_closed,
178 					 GdkBitmap     *mask_closed,
179 					 GdkPixmap     *pixmap_opened,
180 					 GdkBitmap     *mask_opened,
181 					 gboolean       is_leaf,
182 					 gboolean       expanded);
183 static GtkCTreeRow *row_new             (GtkCTree      *ctree);
184 static void row_delete                  (GtkCTree      *ctree,
185 				 	 GtkCTreeRow   *ctree_row);
186 static void tree_delete                 (GtkCTree      *ctree,
187 					 GtkCTreeNode  *node,
188 					 gpointer       data);
189 static void tree_delete_row             (GtkCTree      *ctree,
190 					 GtkCTreeNode  *node,
191 					 gpointer       data);
192 static void real_clear                  (GtkCList      *clist);
193 static void tree_update_level           (GtkCTree      *ctree,
194 					 GtkCTreeNode  *node,
195 					 gpointer       data);
196 static void tree_select                 (GtkCTree      *ctree,
197 					 GtkCTreeNode  *node,
198 					 gpointer       data);
199 static void tree_unselect               (GtkCTree      *ctree,
200 					 GtkCTreeNode  *node,
201 				         gpointer       data);
202 static void real_select_all             (GtkCList      *clist);
203 static void real_unselect_all           (GtkCList      *clist);
204 static void tree_expand                 (GtkCTree      *ctree,
205 					 GtkCTreeNode  *node,
206 					 gpointer       data);
207 static void tree_collapse               (GtkCTree      *ctree,
208 					 GtkCTreeNode  *node,
209 					 gpointer       data);
210 static void tree_collapse_to_depth      (GtkCTree      *ctree,
211 					 GtkCTreeNode  *node,
212 					 gint           depth);
213 static void tree_toggle_expansion       (GtkCTree      *ctree,
214 					 GtkCTreeNode  *node,
215 					 gpointer       data);
216 static void change_focus_row_expansion  (GtkCTree      *ctree,
217 				         GtkCTreeExpansionType expansion);
218 static void real_select_row             (GtkCList      *clist,
219 					 gint           row,
220 					 gint           column,
221 					 GdkEvent      *event);
222 static void real_unselect_row           (GtkCList      *clist,
223 					 gint           row,
224 					 gint           column,
225 					 GdkEvent      *event);
226 static void real_tree_select            (GtkCTree      *ctree,
227 					 GtkCTreeNode  *node,
228 					 gint           column);
229 static void real_tree_unselect          (GtkCTree      *ctree,
230 					 GtkCTreeNode  *node,
231 					 gint           column);
232 static void real_tree_expand            (GtkCTree      *ctree,
233 					 GtkCTreeNode  *node);
234 static void real_tree_collapse          (GtkCTree      *ctree,
235 					 GtkCTreeNode  *node);
236 static void real_tree_move              (GtkCTree      *ctree,
237 					 GtkCTreeNode  *node,
238 					 GtkCTreeNode  *new_parent,
239 					 GtkCTreeNode  *new_sibling);
240 static void real_row_move               (GtkCList      *clist,
241 					 gint           source_row,
242 					 gint           dest_row);
243 static void gtk_ctree_link              (GtkCTree      *ctree,
244 					 GtkCTreeNode  *node,
245 					 GtkCTreeNode  *parent,
246 					 GtkCTreeNode  *sibling,
247 					 gboolean       update_focus_row);
248 static void gtk_ctree_unlink            (GtkCTree      *ctree,
249 					 GtkCTreeNode  *node,
250 					 gboolean       update_focus_row);
251 static GtkCTreeNode * gtk_ctree_last_visible (GtkCTree     *ctree,
252 					      GtkCTreeNode *node);
253 static gboolean ctree_is_hot_spot       (GtkCTree      *ctree,
254 					 GtkCTreeNode  *node,
255 					 gint           row,
256 					 gint           x,
257 					 gint           y);
258 static void tree_sort                   (GtkCTree      *ctree,
259 					 GtkCTreeNode  *node,
260 					 gpointer       data);
261 static void fake_unselect_all           (GtkCList      *clist,
262 					 gint           row);
263 static GList * selection_find           (GtkCList      *clist,
264 					 gint           row_number,
265 					 GList         *row_list_element);
266 static void resync_selection            (GtkCList      *clist,
267 					 GdkEvent      *event);
268 static void real_undo_selection         (GtkCList      *clist);
269 static void select_row_recursive        (GtkCTree      *ctree,
270 					 GtkCTreeNode  *node,
271 					 gpointer       data);
272 static gint real_insert_row             (GtkCList      *clist,
273 					 gint           row,
274 					 gchar         *text[]);
275 static void real_remove_row             (GtkCList      *clist,
276 					 gint           row);
277 static void real_sort_list              (GtkCList      *clist);
278 static void cell_size_request           (GtkCList       *clist,
279 					 GtkCListRow    *clist_row,
280 					 gint            column,
281 					 GtkRequisition *requisition);
282 static void column_auto_resize          (GtkCList       *clist,
283 					 GtkCListRow    *clist_row,
284 					 gint            column,
285 					 gint            old_width);
286 static void auto_resize_columns         (GtkCList       *clist);
287 
288 
289 static gboolean check_drag               (GtkCTree         *ctree,
290 			                  GtkCTreeNode     *drag_source,
291 					  GtkCTreeNode     *drag_target,
292 					  GtkCListDragPos   insert_pos);
293 static void gtk_ctree_drag_begin         (GtkWidget        *widget,
294 					  GdkDragContext   *context);
295 static gint gtk_ctree_drag_motion        (GtkWidget        *widget,
296 					  GdkDragContext   *context,
297 					  gint              x,
298 					  gint              y,
299 					  guint             time);
300 static void gtk_ctree_drag_data_received (GtkWidget        *widget,
301 					  GdkDragContext   *context,
302 					  gint              x,
303 					  gint              y,
304 					  GtkSelectionData *selection_data,
305 					  guint             info,
306 					  guint32           time);
307 static void remove_grab                  (GtkCList         *clist);
308 static void drag_dest_cell               (GtkCList         *clist,
309 					  gint              x,
310 					  gint              y,
311 					  GtkCListDestInfo *dest_info);
312 
313 
314 enum
315 {
316   TREE_SELECT_ROW,
317   TREE_UNSELECT_ROW,
318   TREE_EXPAND,
319   TREE_COLLAPSE,
320   TREE_MOVE,
321   CHANGE_FOCUS_ROW_EXPANSION,
322   LAST_SIGNAL
323 };
324 
325 static GtkCListClass *parent_class = NULL;
326 static GtkContainerClass *container_class = NULL;
327 static guint ctree_signals[LAST_SIGNAL] = {0};
328 
329 
330 GtkType
gtk_ctree_get_type(void)331 gtk_ctree_get_type (void)
332 {
333   static GtkType ctree_type = 0;
334 
335   if (!ctree_type)
336     {
337       static const GtkTypeInfo ctree_info =
338       {
339 	"GtkCTree",
340 	sizeof (GtkCTree),
341 	sizeof (GtkCTreeClass),
342 	(GtkClassInitFunc) gtk_ctree_class_init,
343 	(GtkObjectInitFunc) gtk_ctree_init,
344 	/* reserved_1 */ NULL,
345         /* reserved_2 */ NULL,
346         (GtkClassInitFunc) NULL,
347       };
348 
349       I_("GtkCTree");
350       ctree_type = gtk_type_unique (GTK_TYPE_CLIST, &ctree_info);
351     }
352 
353   return ctree_type;
354 }
355 
356 static void
gtk_ctree_class_init(GtkCTreeClass * klass)357 gtk_ctree_class_init (GtkCTreeClass *klass)
358 {
359   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
360   GtkObjectClass *object_class;
361   GtkWidgetClass *widget_class;
362   GtkCListClass *clist_class;
363   GtkBindingSet *binding_set;
364 
365   gobject_class->constructor = gtk_ctree_constructor;
366 
367   object_class = (GtkObjectClass *) klass;
368   widget_class = (GtkWidgetClass *) klass;
369   container_class = (GtkContainerClass *) klass;
370   clist_class = (GtkCListClass *) klass;
371 
372   parent_class = gtk_type_class (GTK_TYPE_CLIST);
373   container_class = gtk_type_class (GTK_TYPE_CONTAINER);
374 
375   object_class->set_arg = gtk_ctree_set_arg;
376   object_class->get_arg = gtk_ctree_get_arg;
377 
378   widget_class->realize = gtk_ctree_realize;
379   widget_class->unrealize = gtk_ctree_unrealize;
380   widget_class->button_press_event = gtk_ctree_button_press;
381 
382   widget_class->drag_begin = gtk_ctree_drag_begin;
383   widget_class->drag_motion = gtk_ctree_drag_motion;
384   widget_class->drag_data_received = gtk_ctree_drag_data_received;
385 
386   clist_class->select_row = real_select_row;
387   clist_class->unselect_row = real_unselect_row;
388   clist_class->row_move = real_row_move;
389   clist_class->undo_selection = real_undo_selection;
390   clist_class->resync_selection = resync_selection;
391   clist_class->selection_find = selection_find;
392   clist_class->click_column = NULL;
393   clist_class->draw_row = draw_row;
394   clist_class->draw_drag_highlight = draw_drag_highlight;
395   clist_class->clear = real_clear;
396   clist_class->select_all = real_select_all;
397   clist_class->unselect_all = real_unselect_all;
398   clist_class->fake_unselect_all = fake_unselect_all;
399   clist_class->insert_row = real_insert_row;
400   clist_class->remove_row = real_remove_row;
401   clist_class->sort_list = real_sort_list;
402   clist_class->set_cell_contents = set_cell_contents;
403   clist_class->cell_size_request = cell_size_request;
404 
405   klass->tree_select_row = real_tree_select;
406   klass->tree_unselect_row = real_tree_unselect;
407   klass->tree_expand = real_tree_expand;
408   klass->tree_collapse = real_tree_collapse;
409   klass->tree_move = real_tree_move;
410   klass->change_focus_row_expansion = change_focus_row_expansion;
411 
412   gtk_object_add_arg_type ("GtkCTree::n-columns", /* overrides GtkCList::n_columns!! */
413 			   GTK_TYPE_UINT,
414 			   GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME,
415 			   ARG_N_COLUMNS);
416   gtk_object_add_arg_type ("GtkCTree::tree-column",
417 			   GTK_TYPE_UINT,
418 			   GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME,
419 			   ARG_TREE_COLUMN);
420   gtk_object_add_arg_type ("GtkCTree::indent",
421 			   GTK_TYPE_UINT,
422 			   GTK_ARG_READWRITE | G_PARAM_STATIC_NAME,
423 			   ARG_INDENT);
424   gtk_object_add_arg_type ("GtkCTree::spacing",
425 			   GTK_TYPE_UINT,
426 			   GTK_ARG_READWRITE | G_PARAM_STATIC_NAME,
427 			   ARG_SPACING);
428   gtk_object_add_arg_type ("GtkCTree::show-stub",
429 			   GTK_TYPE_BOOL,
430 			   GTK_ARG_READWRITE | G_PARAM_STATIC_NAME,
431 			   ARG_SHOW_STUB);
432   gtk_object_add_arg_type ("GtkCTree::line-style",
433 			   GTK_TYPE_CTREE_LINE_STYLE,
434 			   GTK_ARG_READWRITE | G_PARAM_STATIC_NAME,
435 			   ARG_LINE_STYLE);
436   gtk_object_add_arg_type ("GtkCTree::expander-style",
437 			   GTK_TYPE_CTREE_EXPANDER_STYLE,
438 			   GTK_ARG_READWRITE | G_PARAM_STATIC_NAME,
439 			   ARG_EXPANDER_STYLE);
440 
441   ctree_signals[TREE_SELECT_ROW] =
442     gtk_signal_new (I_("tree-select-row"),
443 		    GTK_RUN_FIRST,
444 		    GTK_CLASS_TYPE (object_class),
445 		    GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_select_row),
446 		    _gtk_marshal_VOID__POINTER_INT,
447 		    GTK_TYPE_NONE, 2,
448 		    GTK_TYPE_CTREE_NODE,
449 		    GTK_TYPE_INT);
450   ctree_signals[TREE_UNSELECT_ROW] =
451     gtk_signal_new (I_("tree-unselect-row"),
452 		    GTK_RUN_FIRST,
453 		    GTK_CLASS_TYPE (object_class),
454 		    GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_unselect_row),
455 		    _gtk_marshal_VOID__POINTER_INT,
456 		    GTK_TYPE_NONE, 2,
457 		    GTK_TYPE_CTREE_NODE,
458 		    GTK_TYPE_INT);
459   ctree_signals[TREE_EXPAND] =
460     gtk_signal_new (I_("tree-expand"),
461 		    GTK_RUN_LAST,
462 		    GTK_CLASS_TYPE (object_class),
463 		    GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_expand),
464 		    _gtk_marshal_VOID__POINTER,
465 		    GTK_TYPE_NONE, 1,
466 		    GTK_TYPE_CTREE_NODE);
467   ctree_signals[TREE_COLLAPSE] =
468     gtk_signal_new (I_("tree-collapse"),
469 		    GTK_RUN_LAST,
470 		    GTK_CLASS_TYPE (object_class),
471 		    GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_collapse),
472 		    _gtk_marshal_VOID__POINTER,
473 		    GTK_TYPE_NONE, 1,
474 		    GTK_TYPE_CTREE_NODE);
475   ctree_signals[TREE_MOVE] =
476     gtk_signal_new (I_("tree-move"),
477 		    GTK_RUN_LAST,
478 		    GTK_CLASS_TYPE (object_class),
479 		    GTK_SIGNAL_OFFSET (GtkCTreeClass, tree_move),
480 		    _gtk_marshal_VOID__POINTER_POINTER_POINTER,
481 		    GTK_TYPE_NONE, 3,
482 		    GTK_TYPE_CTREE_NODE,
483 		    GTK_TYPE_CTREE_NODE,
484 		    GTK_TYPE_CTREE_NODE);
485   ctree_signals[CHANGE_FOCUS_ROW_EXPANSION] =
486     gtk_signal_new (I_("change-focus-row-expansion"),
487 		    GTK_RUN_LAST | GTK_RUN_ACTION,
488 		    GTK_CLASS_TYPE (object_class),
489 		    GTK_SIGNAL_OFFSET (GtkCTreeClass,
490 				       change_focus_row_expansion),
491 		    _gtk_marshal_VOID__ENUM,
492 		    GTK_TYPE_NONE, 1, GTK_TYPE_CTREE_EXPANSION_TYPE);
493 
494   binding_set = gtk_binding_set_by_class (klass);
495   gtk_binding_entry_add_signal (binding_set,
496 				GDK_plus, 0,
497 				"change-focus-row-expansion", 1,
498 				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_EXPAND);
499   gtk_binding_entry_add_signal (binding_set,
500 				GDK_plus, GDK_CONTROL_MASK,
501 				"change-focus-row-expansion", 1,
502 				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_EXPAND_RECURSIVE);
503 
504   gtk_binding_entry_add_signal (binding_set,
505 				GDK_KP_Add, 0,
506 				"change-focus-row-expansion", 1,
507 				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_EXPAND);
508   gtk_binding_entry_add_signal (binding_set,
509 				GDK_KP_Add, GDK_CONTROL_MASK,
510 				"change-focus-row-expansion", 1,
511 				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_EXPAND_RECURSIVE);
512 
513   gtk_binding_entry_add_signal (binding_set,
514 				GDK_minus, 0,
515 				"change-focus-row-expansion", 1,
516 				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_COLLAPSE);
517   gtk_binding_entry_add_signal (binding_set,
518                                 GDK_minus, GDK_CONTROL_MASK,
519 				"change-focus-row-expansion", 1,
520 				GTK_TYPE_ENUM,
521 				GTK_CTREE_EXPANSION_COLLAPSE_RECURSIVE);
522   gtk_binding_entry_add_signal (binding_set,
523 				GDK_KP_Subtract, 0,
524 				"change-focus-row-expansion", 1,
525 				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_COLLAPSE);
526   gtk_binding_entry_add_signal (binding_set,
527 				GDK_KP_Subtract, GDK_CONTROL_MASK,
528 				"change-focus-row-expansion", 1,
529 				GTK_TYPE_ENUM,
530 				GTK_CTREE_EXPANSION_COLLAPSE_RECURSIVE);
531   gtk_binding_entry_add_signal (binding_set,
532 				GDK_equal, 0,
533 				"change-focus-row-expansion", 1,
534 				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_TOGGLE);
535   gtk_binding_entry_add_signal (binding_set,
536 				GDK_KP_Equal, 0,
537 				"change-focus-row-expansion", 1,
538 				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_TOGGLE);
539   gtk_binding_entry_add_signal (binding_set,
540 				GDK_KP_Multiply, 0,
541 				"change-focus-row-expansion", 1,
542 				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_TOGGLE);
543   gtk_binding_entry_add_signal (binding_set,
544 				GDK_asterisk, 0,
545 				"change-focus-row-expansion", 1,
546 				GTK_TYPE_ENUM, GTK_CTREE_EXPANSION_TOGGLE);
547   gtk_binding_entry_add_signal (binding_set,
548 				GDK_KP_Multiply, GDK_CONTROL_MASK,
549 				"change-focus-row-expansion", 1,
550 				GTK_TYPE_ENUM,
551 				GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE);
552   gtk_binding_entry_add_signal (binding_set,
553 				GDK_asterisk, GDK_CONTROL_MASK,
554 				"change-focus-row-expansion", 1,
555 				GTK_TYPE_ENUM,
556 				GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE);
557 }
558 
559 static void
gtk_ctree_set_arg(GtkObject * object,GtkArg * arg,guint arg_id)560 gtk_ctree_set_arg (GtkObject      *object,
561 		   GtkArg         *arg,
562 		   guint           arg_id)
563 {
564   GtkCTree *ctree;
565   GtkCList *clist;
566 
567   ctree = GTK_CTREE (object);
568   clist = GTK_CLIST (ctree);
569 
570   switch (arg_id)
571     {
572     case ARG_N_COLUMNS: /* construct-only arg, only set at construction time */
573       clist->columns = MAX (1, GTK_VALUE_UINT (*arg));
574       ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns);
575       break;
576     case ARG_TREE_COLUMN: /* construct-only arg, only set at construction time */
577       ctree->tree_column = GTK_VALUE_UINT (*arg);
578       ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns);
579       break;
580     case ARG_INDENT:
581       gtk_ctree_set_indent (ctree, GTK_VALUE_UINT (*arg));
582       break;
583     case ARG_SPACING:
584       gtk_ctree_set_spacing (ctree, GTK_VALUE_UINT (*arg));
585       break;
586     case ARG_SHOW_STUB:
587       gtk_ctree_set_show_stub (ctree, GTK_VALUE_BOOL (*arg));
588       break;
589     case ARG_LINE_STYLE:
590       gtk_ctree_set_line_style (ctree, GTK_VALUE_ENUM (*arg));
591       break;
592     case ARG_EXPANDER_STYLE:
593       gtk_ctree_set_expander_style (ctree, GTK_VALUE_ENUM (*arg));
594       break;
595     default:
596       break;
597     }
598 }
599 
600 static void
gtk_ctree_get_arg(GtkObject * object,GtkArg * arg,guint arg_id)601 gtk_ctree_get_arg (GtkObject      *object,
602 		   GtkArg         *arg,
603 		   guint           arg_id)
604 {
605   GtkCTree *ctree;
606 
607   ctree = GTK_CTREE (object);
608 
609   switch (arg_id)
610     {
611     case ARG_N_COLUMNS:
612       GTK_VALUE_UINT (*arg) = GTK_CLIST (ctree)->columns;
613       break;
614     case ARG_TREE_COLUMN:
615       GTK_VALUE_UINT (*arg) = ctree->tree_column;
616       break;
617     case ARG_INDENT:
618       GTK_VALUE_UINT (*arg) = ctree->tree_indent;
619       break;
620     case ARG_SPACING:
621       GTK_VALUE_UINT (*arg) = ctree->tree_spacing;
622       break;
623     case ARG_SHOW_STUB:
624       GTK_VALUE_BOOL (*arg) = ctree->show_stub;
625       break;
626     case ARG_LINE_STYLE:
627       GTK_VALUE_ENUM (*arg) = ctree->line_style;
628       break;
629     case ARG_EXPANDER_STYLE:
630       GTK_VALUE_ENUM (*arg) = ctree->expander_style;
631       break;
632     default:
633       arg->type = GTK_TYPE_INVALID;
634       break;
635     }
636 }
637 
638 static void
gtk_ctree_init(GtkCTree * ctree)639 gtk_ctree_init (GtkCTree *ctree)
640 {
641   GtkCList *clist;
642 
643   GTK_CLIST_SET_FLAG (ctree, CLIST_DRAW_DRAG_RECT);
644   GTK_CLIST_SET_FLAG (ctree, CLIST_DRAW_DRAG_LINE);
645 
646   clist = GTK_CLIST (ctree);
647 
648   ctree->tree_indent    = 20;
649   ctree->tree_spacing   = 5;
650   ctree->tree_column    = 0;
651   ctree->line_style     = GTK_CTREE_LINES_SOLID;
652   ctree->expander_style = GTK_CTREE_EXPANDER_SQUARE;
653   ctree->drag_compare   = NULL;
654   ctree->show_stub      = TRUE;
655 
656   clist->button_actions[0] |= GTK_BUTTON_EXPANDS;
657 }
658 
659 static void
ctree_attach_styles(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)660 ctree_attach_styles (GtkCTree     *ctree,
661 		     GtkCTreeNode *node,
662 		     gpointer      data)
663 {
664   GtkCList *clist;
665   gint i;
666 
667   clist = GTK_CLIST (ctree);
668 
669   if (GTK_CTREE_ROW (node)->row.style)
670     GTK_CTREE_ROW (node)->row.style =
671       gtk_style_attach (GTK_CTREE_ROW (node)->row.style, clist->clist_window);
672 
673   if (GTK_CTREE_ROW (node)->row.fg_set || GTK_CTREE_ROW (node)->row.bg_set)
674     {
675       GdkColormap *colormap;
676 
677       colormap = gtk_widget_get_colormap (GTK_WIDGET (ctree));
678       if (GTK_CTREE_ROW (node)->row.fg_set)
679 	gdk_colormap_alloc_color (colormap,
680                                   &(GTK_CTREE_ROW (node)->row.foreground),
681                                   FALSE, TRUE);
682       if (GTK_CTREE_ROW (node)->row.bg_set)
683 	gdk_colormap_alloc_color (colormap,
684                                   &(GTK_CTREE_ROW (node)->row.background),
685                                   FALSE, TRUE);
686     }
687 
688   for (i = 0; i < clist->columns; i++)
689     if  (GTK_CTREE_ROW (node)->row.cell[i].style)
690       GTK_CTREE_ROW (node)->row.cell[i].style =
691 	gtk_style_attach (GTK_CTREE_ROW (node)->row.cell[i].style,
692 			  clist->clist_window);
693 }
694 
695 static void
ctree_detach_styles(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)696 ctree_detach_styles (GtkCTree     *ctree,
697 		     GtkCTreeNode *node,
698 		     gpointer      data)
699 {
700   GtkCList *clist;
701   gint i;
702 
703   clist = GTK_CLIST (ctree);
704 
705   if (GTK_CTREE_ROW (node)->row.style)
706     gtk_style_detach (GTK_CTREE_ROW (node)->row.style);
707   for (i = 0; i < clist->columns; i++)
708     if  (GTK_CTREE_ROW (node)->row.cell[i].style)
709       gtk_style_detach (GTK_CTREE_ROW (node)->row.cell[i].style);
710 }
711 
712 static void
gtk_ctree_realize(GtkWidget * widget)713 gtk_ctree_realize (GtkWidget *widget)
714 {
715   GtkCTree *ctree;
716   GtkCList *clist;
717   GdkGCValues values;
718   GtkCTreeNode *node;
719   GtkCTreeNode *child;
720   gint i;
721 
722   g_return_if_fail (GTK_IS_CTREE (widget));
723 
724   GTK_WIDGET_CLASS (parent_class)->realize (widget);
725 
726   ctree = GTK_CTREE (widget);
727   clist = GTK_CLIST (widget);
728 
729   node = GTK_CTREE_NODE (clist->row_list);
730   for (i = 0; i < clist->rows; i++)
731     {
732       if (GTK_CTREE_ROW (node)->children && !GTK_CTREE_ROW (node)->expanded)
733 	for (child = GTK_CTREE_ROW (node)->children; child;
734 	     child = GTK_CTREE_ROW (child)->sibling)
735 	  gtk_ctree_pre_recursive (ctree, child, ctree_attach_styles, NULL);
736       node = GTK_CTREE_NODE_NEXT (node);
737     }
738 
739   values.foreground = widget->style->fg[GTK_STATE_NORMAL];
740   values.background = widget->style->base[GTK_STATE_NORMAL];
741   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
742   values.line_style = GDK_LINE_SOLID;
743   ctree->lines_gc = gdk_gc_new_with_values (GTK_CLIST(widget)->clist_window,
744 					    &values,
745 					    GDK_GC_FOREGROUND |
746 					    GDK_GC_BACKGROUND |
747 					    GDK_GC_SUBWINDOW |
748 					    GDK_GC_LINE_STYLE);
749 
750   if (ctree->line_style == GTK_CTREE_LINES_DOTTED)
751     {
752       gint8 dashes[] = { 1, 1 };
753 
754       gdk_gc_set_line_attributes (ctree->lines_gc, 1,
755 				  GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER);
756       gdk_gc_set_dashes (ctree->lines_gc, 0, dashes, G_N_ELEMENTS (dashes));
757     }
758 }
759 
760 static void
gtk_ctree_unrealize(GtkWidget * widget)761 gtk_ctree_unrealize (GtkWidget *widget)
762 {
763   GtkCTree *ctree;
764   GtkCList *clist;
765 
766   g_return_if_fail (GTK_IS_CTREE (widget));
767 
768   GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
769 
770   ctree = GTK_CTREE (widget);
771   clist = GTK_CLIST (widget);
772 
773   if (gtk_widget_get_realized (widget))
774     {
775       GtkCTreeNode *node;
776       GtkCTreeNode *child;
777       gint i;
778 
779       node = GTK_CTREE_NODE (clist->row_list);
780       for (i = 0; i < clist->rows; i++)
781 	{
782 	  if (GTK_CTREE_ROW (node)->children &&
783 	      !GTK_CTREE_ROW (node)->expanded)
784 	    for (child = GTK_CTREE_ROW (node)->children; child;
785 		 child = GTK_CTREE_ROW (child)->sibling)
786 	      gtk_ctree_pre_recursive(ctree, child, ctree_detach_styles, NULL);
787 	  node = GTK_CTREE_NODE_NEXT (node);
788 	}
789     }
790 
791   g_object_unref (ctree->lines_gc);
792 }
793 
794 static gint
gtk_ctree_button_press(GtkWidget * widget,GdkEventButton * event)795 gtk_ctree_button_press (GtkWidget      *widget,
796 			GdkEventButton *event)
797 {
798   GtkCTree *ctree;
799   GtkCList *clist;
800   gint button_actions;
801 
802   g_return_val_if_fail (GTK_IS_CTREE (widget), FALSE);
803   g_return_val_if_fail (event != NULL, FALSE);
804 
805   ctree = GTK_CTREE (widget);
806   clist = GTK_CLIST (widget);
807 
808   button_actions = clist->button_actions[event->button - 1];
809 
810   if (button_actions == GTK_BUTTON_IGNORED)
811     return FALSE;
812 
813   if (event->window == clist->clist_window)
814     {
815       GtkCTreeNode *work;
816       gint x;
817       gint y;
818       gint row;
819       gint column;
820 
821       x = event->x;
822       y = event->y;
823 
824       if (!gtk_clist_get_selection_info (clist, x, y, &row, &column))
825 	return FALSE;
826 
827       work = GTK_CTREE_NODE (g_list_nth (clist->row_list, row));
828 
829       if (button_actions & GTK_BUTTON_EXPANDS &&
830 	  (GTK_CTREE_ROW (work)->children && !GTK_CTREE_ROW (work)->is_leaf  &&
831 	   (event->type == GDK_2BUTTON_PRESS ||
832 	    ctree_is_hot_spot (ctree, work, row, x, y))))
833 	{
834 	  if (GTK_CTREE_ROW (work)->expanded)
835 	    gtk_ctree_collapse (ctree, work);
836 	  else
837 	    gtk_ctree_expand (ctree, work);
838 
839 	  return TRUE;
840 	}
841     }
842 
843   return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
844 }
845 
846 static void
draw_drag_highlight(GtkCList * clist,GtkCListRow * dest_row,gint dest_row_number,GtkCListDragPos drag_pos)847 draw_drag_highlight (GtkCList        *clist,
848 		     GtkCListRow     *dest_row,
849 		     gint             dest_row_number,
850 		     GtkCListDragPos  drag_pos)
851 {
852   GtkCTree *ctree;
853   GdkPoint points[4];
854   gint level;
855   gint i;
856   gint y = 0;
857 
858   g_return_if_fail (GTK_IS_CTREE (clist));
859 
860   ctree = GTK_CTREE (clist);
861 
862   level = ((GtkCTreeRow *)(dest_row))->level;
863 
864   y = ROW_TOP_YPIXEL (clist, dest_row_number) - 1;
865 
866   switch (drag_pos)
867     {
868     case GTK_CLIST_DRAG_NONE:
869       break;
870     case GTK_CLIST_DRAG_AFTER:
871       y += clist->row_height + 1;
872     case GTK_CLIST_DRAG_BEFORE:
873 
874       if (clist->column[ctree->tree_column].visible)
875 	switch (clist->column[ctree->tree_column].justification)
876 	  {
877 	  case GTK_JUSTIFY_CENTER:
878 	  case GTK_JUSTIFY_FILL:
879 	  case GTK_JUSTIFY_LEFT:
880 	    if (ctree->tree_column > 0)
881 	      gdk_draw_line (clist->clist_window, clist->xor_gc,
882 			     COLUMN_LEFT_XPIXEL(clist, 0), y,
883 			     COLUMN_LEFT_XPIXEL(clist, ctree->tree_column - 1)+
884 			     clist->column[ctree->tree_column - 1].area.width,
885 			     y);
886 
887 	    gdk_draw_line (clist->clist_window, clist->xor_gc,
888 			   COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) +
889 			   ctree->tree_indent * level -
890 			   (ctree->tree_indent - PM_SIZE) / 2, y,
891 			   GTK_WIDGET (ctree)->allocation.width, y);
892 	    break;
893 	  case GTK_JUSTIFY_RIGHT:
894 	    if (ctree->tree_column < clist->columns - 1)
895 	      gdk_draw_line (clist->clist_window, clist->xor_gc,
896 			     COLUMN_LEFT_XPIXEL(clist, ctree->tree_column + 1),
897 			     y,
898 			     COLUMN_LEFT_XPIXEL(clist, clist->columns - 1) +
899 			     clist->column[clist->columns - 1].area.width, y);
900 
901 	    gdk_draw_line (clist->clist_window, clist->xor_gc,
902 			   0, y, COLUMN_LEFT_XPIXEL(clist, ctree->tree_column)
903 			   + clist->column[ctree->tree_column].area.width -
904 			   ctree->tree_indent * level +
905 			   (ctree->tree_indent - PM_SIZE) / 2, y);
906 	    break;
907 	  }
908       else
909 	gdk_draw_line (clist->clist_window, clist->xor_gc,
910 		       0, y, clist->clist_window_width, y);
911       break;
912     case GTK_CLIST_DRAG_INTO:
913       y = ROW_TOP_YPIXEL (clist, dest_row_number) + clist->row_height;
914 
915       if (clist->column[ctree->tree_column].visible)
916 	switch (clist->column[ctree->tree_column].justification)
917 	  {
918 	  case GTK_JUSTIFY_CENTER:
919 	  case GTK_JUSTIFY_FILL:
920 	  case GTK_JUSTIFY_LEFT:
921 	    points[0].x =  COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) +
922 	      ctree->tree_indent * level - (ctree->tree_indent - PM_SIZE) / 2;
923 	    points[0].y = y;
924 	    points[3].x = points[0].x;
925 	    points[3].y = y - clist->row_height - 1;
926 	    points[1].x = clist->clist_window_width - 1;
927 	    points[1].y = points[0].y;
928 	    points[2].x = points[1].x;
929 	    points[2].y = points[3].y;
930 
931 	    for (i = 0; i < 3; i++)
932 	      gdk_draw_line (clist->clist_window, clist->xor_gc,
933 			     points[i].x, points[i].y,
934 			     points[i+1].x, points[i+1].y);
935 
936 	    if (ctree->tree_column > 0)
937 	      {
938 		points[0].x = COLUMN_LEFT_XPIXEL(clist,
939 						 ctree->tree_column - 1) +
940 		  clist->column[ctree->tree_column - 1].area.width ;
941 		points[0].y = y;
942 		points[3].x = points[0].x;
943 		points[3].y = y - clist->row_height - 1;
944 		points[1].x = 0;
945 		points[1].y = points[0].y;
946 		points[2].x = 0;
947 		points[2].y = points[3].y;
948 
949 		for (i = 0; i < 3; i++)
950 		  gdk_draw_line (clist->clist_window, clist->xor_gc,
951 				 points[i].x, points[i].y, points[i+1].x,
952 				 points[i+1].y);
953 	      }
954 	    break;
955 	  case GTK_JUSTIFY_RIGHT:
956 	    points[0].x =  COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) -
957 	      ctree->tree_indent * level + (ctree->tree_indent - PM_SIZE) / 2 +
958 	      clist->column[ctree->tree_column].area.width;
959 	    points[0].y = y;
960 	    points[3].x = points[0].x;
961 	    points[3].y = y - clist->row_height - 1;
962 	    points[1].x = 0;
963 	    points[1].y = points[0].y;
964 	    points[2].x = 0;
965 	    points[2].y = points[3].y;
966 
967 	    for (i = 0; i < 3; i++)
968 	      gdk_draw_line (clist->clist_window, clist->xor_gc,
969 			     points[i].x, points[i].y,
970 			     points[i+1].x, points[i+1].y);
971 
972 	    if (ctree->tree_column < clist->columns - 1)
973 	      {
974 		points[0].x = COLUMN_LEFT_XPIXEL(clist, ctree->tree_column +1);
975 		points[0].y = y;
976 		points[3].x = points[0].x;
977 		points[3].y = y - clist->row_height - 1;
978 		points[1].x = clist->clist_window_width - 1;
979 		points[1].y = points[0].y;
980 		points[2].x = points[1].x;
981 		points[2].y = points[3].y;
982 
983 		for (i = 0; i < 3; i++)
984 		  gdk_draw_line (clist->clist_window, clist->xor_gc,
985 				 points[i].x, points[i].y,
986 				 points[i+1].x, points[i+1].y);
987 	      }
988 	    break;
989 	  }
990       else
991 	gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
992 			    0, y - clist->row_height,
993 			    clist->clist_window_width - 1, clist->row_height);
994       break;
995     }
996 }
997 
998 static gint
draw_cell_pixmap(GdkWindow * window,GdkRectangle * clip_rectangle,GdkGC * fg_gc,GdkPixmap * pixmap,GdkBitmap * mask,gint x,gint y,gint width,gint height)999 draw_cell_pixmap (GdkWindow    *window,
1000 		  GdkRectangle *clip_rectangle,
1001 		  GdkGC        *fg_gc,
1002 		  GdkPixmap    *pixmap,
1003 		  GdkBitmap    *mask,
1004 		  gint          x,
1005 		  gint          y,
1006 		  gint          width,
1007 		  gint          height)
1008 {
1009   gint xsrc = 0;
1010   gint ysrc = 0;
1011 
1012   if (mask)
1013     {
1014       gdk_gc_set_clip_mask (fg_gc, mask);
1015       gdk_gc_set_clip_origin (fg_gc, x, y);
1016     }
1017   if (x < clip_rectangle->x)
1018     {
1019       xsrc = clip_rectangle->x - x;
1020       width -= xsrc;
1021       x = clip_rectangle->x;
1022     }
1023   if (x + width > clip_rectangle->x + clip_rectangle->width)
1024     width = clip_rectangle->x + clip_rectangle->width - x;
1025 
1026   if (y < clip_rectangle->y)
1027     {
1028       ysrc = clip_rectangle->y - y;
1029       height -= ysrc;
1030       y = clip_rectangle->y;
1031     }
1032   if (y + height > clip_rectangle->y + clip_rectangle->height)
1033     height = clip_rectangle->y + clip_rectangle->height - y;
1034 
1035   if (width > 0 && height > 0)
1036     gdk_draw_drawable (window, fg_gc, pixmap, xsrc, ysrc, x, y, width, height);
1037 
1038   if (mask)
1039     {
1040       gdk_gc_set_clip_rectangle (fg_gc, NULL);
1041       gdk_gc_set_clip_origin (fg_gc, 0, 0);
1042     }
1043 
1044   return x + MAX (width, 0);
1045 }
1046 
1047 static void
get_cell_style(GtkCList * clist,GtkCListRow * clist_row,gint state,gint column,GtkStyle ** style,GdkGC ** fg_gc,GdkGC ** bg_gc)1048 get_cell_style (GtkCList     *clist,
1049 		GtkCListRow  *clist_row,
1050 		gint          state,
1051 		gint          column,
1052 		GtkStyle    **style,
1053 		GdkGC       **fg_gc,
1054 		GdkGC       **bg_gc)
1055 {
1056   gint fg_state;
1057 
1058   if ((state == GTK_STATE_NORMAL) &&
1059       (GTK_WIDGET (clist)->state == GTK_STATE_INSENSITIVE))
1060     fg_state = GTK_STATE_INSENSITIVE;
1061   else
1062     fg_state = state;
1063 
1064   if (clist_row->cell[column].style)
1065     {
1066       if (style)
1067 	*style = clist_row->cell[column].style;
1068       if (fg_gc)
1069 	*fg_gc = clist_row->cell[column].style->fg_gc[fg_state];
1070       if (bg_gc) {
1071 	if (state == GTK_STATE_SELECTED)
1072 	  *bg_gc = clist_row->cell[column].style->bg_gc[state];
1073 	else
1074 	  *bg_gc = clist_row->cell[column].style->base_gc[state];
1075       }
1076     }
1077   else if (clist_row->style)
1078     {
1079       if (style)
1080 	*style = clist_row->style;
1081       if (fg_gc)
1082 	*fg_gc = clist_row->style->fg_gc[fg_state];
1083       if (bg_gc) {
1084 	if (state == GTK_STATE_SELECTED)
1085 	  *bg_gc = clist_row->style->bg_gc[state];
1086 	else
1087 	  *bg_gc = clist_row->style->base_gc[state];
1088       }
1089     }
1090   else
1091     {
1092       if (style)
1093 	*style = GTK_WIDGET (clist)->style;
1094       if (fg_gc)
1095 	*fg_gc = GTK_WIDGET (clist)->style->fg_gc[fg_state];
1096       if (bg_gc) {
1097 	if (state == GTK_STATE_SELECTED)
1098 	  *bg_gc = GTK_WIDGET (clist)->style->bg_gc[state];
1099 	else
1100 	  *bg_gc = GTK_WIDGET (clist)->style->base_gc[state];
1101       }
1102 
1103       if (state != GTK_STATE_SELECTED)
1104 	{
1105 	  if (fg_gc && clist_row->fg_set)
1106 	    *fg_gc = clist->fg_gc;
1107 	  if (bg_gc && clist_row->bg_set)
1108 	    *bg_gc = clist->bg_gc;
1109 	}
1110     }
1111 }
1112 
1113 static gint
gtk_ctree_draw_expander(GtkCTree * ctree,GtkCTreeRow * ctree_row,GtkStyle * style,GdkRectangle * clip_rectangle,gint x)1114 gtk_ctree_draw_expander (GtkCTree     *ctree,
1115 			 GtkCTreeRow  *ctree_row,
1116 			 GtkStyle     *style,
1117 			 GdkRectangle *clip_rectangle,
1118 			 gint          x)
1119 {
1120   GtkCList *clist;
1121   GdkPoint points[3];
1122   gint justification_factor;
1123   gint y;
1124 
1125  if (ctree->expander_style == GTK_CTREE_EXPANDER_NONE)
1126    return x;
1127 
1128   clist = GTK_CLIST (ctree);
1129   if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
1130     justification_factor = -1;
1131   else
1132     justification_factor = 1;
1133   y = (clip_rectangle->y + (clip_rectangle->height - PM_SIZE) / 2 -
1134        (clip_rectangle->height + 1) % 2);
1135 
1136   if (!ctree_row->children)
1137     {
1138       switch (ctree->expander_style)
1139 	{
1140 	case GTK_CTREE_EXPANDER_NONE:
1141 	  return x;
1142 	case GTK_CTREE_EXPANDER_TRIANGLE:
1143 	  return x + justification_factor * (PM_SIZE + 3);
1144 	case GTK_CTREE_EXPANDER_SQUARE:
1145 	case GTK_CTREE_EXPANDER_CIRCULAR:
1146 	  return x + justification_factor * (PM_SIZE + 1);
1147 	}
1148     }
1149 
1150   gdk_gc_set_clip_rectangle (style->fg_gc[GTK_STATE_NORMAL], clip_rectangle);
1151   gdk_gc_set_clip_rectangle (style->base_gc[GTK_STATE_NORMAL], clip_rectangle);
1152 
1153   switch (ctree->expander_style)
1154     {
1155     case GTK_CTREE_EXPANDER_NONE:
1156       break;
1157     case GTK_CTREE_EXPANDER_TRIANGLE:
1158       if (ctree_row->expanded)
1159 	{
1160 	  points[0].x = x;
1161 	  points[0].y = y + (PM_SIZE + 2) / 6;
1162 	  points[1].x = points[0].x + justification_factor * (PM_SIZE + 2);
1163 	  points[1].y = points[0].y;
1164 	  points[2].x = (points[0].x +
1165 			 justification_factor * (PM_SIZE + 2) / 2);
1166 	  points[2].y = y + 2 * (PM_SIZE + 2) / 3;
1167 	}
1168       else
1169 	{
1170 	  points[0].x = x + justification_factor * ((PM_SIZE + 2) / 6 + 2);
1171 	  points[0].y = y - 1;
1172 	  points[1].x = points[0].x;
1173 	  points[1].y = points[0].y + (PM_SIZE + 2);
1174 	  points[2].x = (points[0].x +
1175 			 justification_factor * (2 * (PM_SIZE + 2) / 3 - 1));
1176 	  points[2].y = points[0].y + (PM_SIZE + 2) / 2;
1177 	}
1178 
1179       gdk_draw_polygon (clist->clist_window, style->base_gc[GTK_STATE_NORMAL],
1180 			TRUE, points, 3);
1181       gdk_draw_polygon (clist->clist_window, style->fg_gc[GTK_STATE_NORMAL],
1182 			FALSE, points, 3);
1183 
1184       x += justification_factor * (PM_SIZE + 3);
1185       break;
1186     case GTK_CTREE_EXPANDER_SQUARE:
1187     case GTK_CTREE_EXPANDER_CIRCULAR:
1188       if (justification_factor == -1)
1189 	x += justification_factor * (PM_SIZE + 1);
1190 
1191       if (ctree->expander_style == GTK_CTREE_EXPANDER_CIRCULAR)
1192 	{
1193 	  gdk_draw_arc (clist->clist_window, style->base_gc[GTK_STATE_NORMAL],
1194 			TRUE, x, y, PM_SIZE, PM_SIZE, 0, 360 * 64);
1195 	  gdk_draw_arc (clist->clist_window, style->fg_gc[GTK_STATE_NORMAL],
1196 			FALSE, x, y, PM_SIZE, PM_SIZE, 0, 360 * 64);
1197 	}
1198       else
1199 	{
1200 	  gdk_draw_rectangle (clist->clist_window,
1201 			      style->base_gc[GTK_STATE_NORMAL], TRUE,
1202 			      x, y, PM_SIZE, PM_SIZE);
1203 	  gdk_draw_rectangle (clist->clist_window,
1204 			      style->fg_gc[GTK_STATE_NORMAL], FALSE,
1205 			      x, y, PM_SIZE, PM_SIZE);
1206 	}
1207 
1208       gdk_draw_line (clist->clist_window, style->fg_gc[GTK_STATE_NORMAL],
1209 		     x + 2, y + PM_SIZE / 2, x + PM_SIZE - 2, y + PM_SIZE / 2);
1210 
1211       if (!ctree_row->expanded)
1212 	gdk_draw_line (clist->clist_window, style->fg_gc[GTK_STATE_NORMAL],
1213 		       x + PM_SIZE / 2, y + 2,
1214 		       x + PM_SIZE / 2, y + PM_SIZE - 2);
1215 
1216       if (justification_factor == 1)
1217 	x += justification_factor * (PM_SIZE + 1);
1218       break;
1219     }
1220 
1221   gdk_gc_set_clip_rectangle (style->fg_gc[GTK_STATE_NORMAL], NULL);
1222   gdk_gc_set_clip_rectangle (style->base_gc[GTK_STATE_NORMAL], NULL);
1223 
1224   return x;
1225 }
1226 
1227 
1228 static gint
gtk_ctree_draw_lines(GtkCTree * ctree,GtkCTreeRow * ctree_row,gint row,gint column,gint state,GdkRectangle * clip_rectangle,GdkRectangle * cell_rectangle,GdkRectangle * crect,GdkRectangle * area,GtkStyle * style)1229 gtk_ctree_draw_lines (GtkCTree     *ctree,
1230 		      GtkCTreeRow  *ctree_row,
1231 		      gint          row,
1232 		      gint          column,
1233 		      gint          state,
1234 		      GdkRectangle *clip_rectangle,
1235 		      GdkRectangle *cell_rectangle,
1236 		      GdkRectangle *crect,
1237 		      GdkRectangle *area,
1238 		      GtkStyle     *style)
1239 {
1240   GtkCList *clist;
1241   GtkCTreeNode *node;
1242   GtkCTreeNode *parent;
1243   GdkRectangle tree_rectangle;
1244   GdkRectangle tc_rectangle;
1245   GdkGC *bg_gc;
1246   gint offset;
1247   gint offset_x;
1248   gint offset_y;
1249   gint xcenter;
1250   gint ycenter;
1251   gint next_level;
1252   gint column_right;
1253   gint column_left;
1254   gint justify_right;
1255   gint justification_factor;
1256 
1257   clist = GTK_CLIST (ctree);
1258   ycenter = clip_rectangle->y + (clip_rectangle->height / 2);
1259   justify_right = (clist->column[column].justification == GTK_JUSTIFY_RIGHT);
1260 
1261   if (justify_right)
1262     {
1263       offset = (clip_rectangle->x + clip_rectangle->width - 1 -
1264 		ctree->tree_indent * (ctree_row->level - 1));
1265       justification_factor = -1;
1266     }
1267   else
1268     {
1269       offset = clip_rectangle->x + ctree->tree_indent * (ctree_row->level - 1);
1270       justification_factor = 1;
1271     }
1272 
1273   switch (ctree->line_style)
1274     {
1275     case GTK_CTREE_LINES_NONE:
1276       break;
1277     case GTK_CTREE_LINES_TABBED:
1278       xcenter = offset + justification_factor * TAB_SIZE;
1279 
1280       column_right = (COLUMN_LEFT_XPIXEL (clist, ctree->tree_column) +
1281 		      clist->column[ctree->tree_column].area.width +
1282 		      COLUMN_INSET);
1283       column_left = (COLUMN_LEFT_XPIXEL (clist, ctree->tree_column) -
1284 		     COLUMN_INSET - CELL_SPACING);
1285 
1286       if (area)
1287 	{
1288 	  tree_rectangle.y = crect->y;
1289 	  tree_rectangle.height = crect->height;
1290 
1291 	  if (justify_right)
1292 	    {
1293 	      tree_rectangle.x = xcenter;
1294 	      tree_rectangle.width = column_right - xcenter;
1295 	    }
1296 	  else
1297 	    {
1298 	      tree_rectangle.x = column_left;
1299 	      tree_rectangle.width = xcenter - column_left;
1300 	    }
1301 
1302 	  if (!gdk_rectangle_intersect (area, &tree_rectangle, &tc_rectangle))
1303 	    {
1304 	      offset += justification_factor * 3;
1305 	      break;
1306 	    }
1307 	}
1308 
1309       gdk_gc_set_clip_rectangle (ctree->lines_gc, crect);
1310 
1311       next_level = ctree_row->level;
1312 
1313       if (!ctree_row->sibling || (ctree_row->children && ctree_row->expanded))
1314 	{
1315 	  node = gtk_ctree_find_node_ptr (ctree, ctree_row);
1316 	  if (GTK_CTREE_NODE_NEXT (node))
1317 	    next_level = GTK_CTREE_ROW (GTK_CTREE_NODE_NEXT (node))->level;
1318 	  else
1319 	    next_level = 0;
1320 	}
1321 
1322       if (ctree->tree_indent > 0)
1323 	{
1324 	  node = ctree_row->parent;
1325 	  while (node)
1326 	    {
1327 	      xcenter -= (justification_factor * ctree->tree_indent);
1328 
1329 	      if ((justify_right && xcenter < column_left) ||
1330 		  (!justify_right && xcenter > column_right))
1331 		{
1332 		  node = GTK_CTREE_ROW (node)->parent;
1333 		  continue;
1334 		}
1335 
1336 	      tree_rectangle.y = cell_rectangle->y;
1337 	      tree_rectangle.height = cell_rectangle->height;
1338 	      if (justify_right)
1339 		{
1340 		  tree_rectangle.x = MAX (xcenter - ctree->tree_indent + 1,
1341 					  column_left);
1342 		  tree_rectangle.width = MIN (xcenter - column_left,
1343 					      ctree->tree_indent);
1344 		}
1345 	      else
1346 		{
1347 		  tree_rectangle.x = xcenter;
1348 		  tree_rectangle.width = MIN (column_right - xcenter,
1349 					      ctree->tree_indent);
1350 		}
1351 
1352 	      if (!area || gdk_rectangle_intersect (area, &tree_rectangle,
1353 						    &tc_rectangle))
1354 		{
1355 		  get_cell_style (clist, &GTK_CTREE_ROW (node)->row,
1356 				  state, column, NULL, NULL, &bg_gc);
1357 
1358 		  if (bg_gc == clist->bg_gc)
1359 		    gdk_gc_set_foreground
1360 		      (clist->bg_gc, &GTK_CTREE_ROW (node)->row.background);
1361 
1362 		  if (!area)
1363 		    gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE,
1364 					tree_rectangle.x,
1365 					tree_rectangle.y,
1366 					tree_rectangle.width,
1367 					tree_rectangle.height);
1368 		  else
1369 		    gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE,
1370 					tc_rectangle.x,
1371 					tc_rectangle.y,
1372 					tc_rectangle.width,
1373 					tc_rectangle.height);
1374 		}
1375 	      if (next_level > GTK_CTREE_ROW (node)->level)
1376 		gdk_draw_line (clist->clist_window, ctree->lines_gc,
1377 			       xcenter, crect->y,
1378 			       xcenter, crect->y + crect->height);
1379 	      else
1380 		{
1381 		  gint width;
1382 
1383 		  offset_x = MIN (ctree->tree_indent, 2 * TAB_SIZE);
1384 		  width = offset_x / 2 + offset_x % 2;
1385 
1386 		  parent = GTK_CTREE_ROW (node)->parent;
1387 
1388 		  tree_rectangle.y = ycenter;
1389 		  tree_rectangle.height = (cell_rectangle->y - ycenter +
1390 					   cell_rectangle->height);
1391 
1392 		  if (justify_right)
1393 		    {
1394 		      tree_rectangle.x = MAX(xcenter + 1 - width, column_left);
1395 		      tree_rectangle.width = MIN (xcenter + 1 - column_left,
1396 						  width);
1397 		    }
1398 		  else
1399 		    {
1400 		      tree_rectangle.x = xcenter;
1401 		      tree_rectangle.width = MIN (column_right - xcenter,
1402 						  width);
1403 		    }
1404 
1405 		  if (!area ||
1406 		      gdk_rectangle_intersect (area, &tree_rectangle,
1407 					       &tc_rectangle))
1408 		    {
1409 		      if (parent)
1410 			{
1411 			  get_cell_style (clist, &GTK_CTREE_ROW (parent)->row,
1412 					  state, column, NULL, NULL, &bg_gc);
1413 			  if (bg_gc == clist->bg_gc)
1414 			    gdk_gc_set_foreground
1415 			      (clist->bg_gc,
1416 			       &GTK_CTREE_ROW (parent)->row.background);
1417 			}
1418 		      else if (state == GTK_STATE_SELECTED)
1419 			bg_gc = style->base_gc[state];
1420 		      else
1421 			bg_gc = GTK_WIDGET (clist)->style->base_gc[state];
1422 
1423 		      if (!area)
1424 			gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE,
1425 					    tree_rectangle.x,
1426 					    tree_rectangle.y,
1427 					    tree_rectangle.width,
1428 					    tree_rectangle.height);
1429 		      else
1430 			gdk_draw_rectangle (clist->clist_window,
1431 					    bg_gc, TRUE,
1432 					    tc_rectangle.x,
1433 					    tc_rectangle.y,
1434 					    tc_rectangle.width,
1435 					    tc_rectangle.height);
1436 		    }
1437 
1438 		  get_cell_style (clist, &GTK_CTREE_ROW (node)->row,
1439 				  state, column, NULL, NULL, &bg_gc);
1440 		  if (bg_gc == clist->bg_gc)
1441 		    gdk_gc_set_foreground
1442 		      (clist->bg_gc, &GTK_CTREE_ROW (node)->row.background);
1443 
1444 		  gdk_gc_set_clip_rectangle (bg_gc, crect);
1445 		  gdk_draw_arc (clist->clist_window, bg_gc, TRUE,
1446 				xcenter - (justify_right * offset_x),
1447 				cell_rectangle->y,
1448 				offset_x, clist->row_height,
1449 				(180 + (justify_right * 90)) * 64, 90 * 64);
1450 		  gdk_gc_set_clip_rectangle (bg_gc, NULL);
1451 
1452 		  gdk_draw_line (clist->clist_window, ctree->lines_gc,
1453 				 xcenter, cell_rectangle->y, xcenter, ycenter);
1454 
1455 		  if (justify_right)
1456 		    gdk_draw_arc (clist->clist_window, ctree->lines_gc, FALSE,
1457 				  xcenter - offset_x, cell_rectangle->y,
1458 				  offset_x, clist->row_height,
1459 				  270 * 64, 90 * 64);
1460 		  else
1461 		    gdk_draw_arc (clist->clist_window, ctree->lines_gc, FALSE,
1462 				  xcenter, cell_rectangle->y,
1463 				  offset_x, clist->row_height,
1464 				  180 * 64, 90 * 64);
1465 		}
1466 	      node = GTK_CTREE_ROW (node)->parent;
1467 	    }
1468 	}
1469 
1470       if (state != GTK_STATE_SELECTED)
1471 	{
1472 	  tree_rectangle.y = clip_rectangle->y;
1473 	  tree_rectangle.height = clip_rectangle->height;
1474 	  tree_rectangle.width = COLUMN_INSET + CELL_SPACING +
1475 	    MIN (clist->column[ctree->tree_column].area.width + COLUMN_INSET,
1476 		 TAB_SIZE);
1477 
1478 	  if (justify_right)
1479 	    tree_rectangle.x = MAX (xcenter + 1, column_left);
1480 	  else
1481 	    tree_rectangle.x = column_left;
1482 
1483 	  if (!area)
1484 	    gdk_draw_rectangle (clist->clist_window,
1485 				GTK_WIDGET
1486 				(ctree)->style->base_gc[GTK_STATE_NORMAL],
1487 				TRUE,
1488 				tree_rectangle.x,
1489 				tree_rectangle.y,
1490 				tree_rectangle.width,
1491 				tree_rectangle.height);
1492 	  else if (gdk_rectangle_intersect (area, &tree_rectangle,
1493 					    &tc_rectangle))
1494 	    gdk_draw_rectangle (clist->clist_window,
1495 				GTK_WIDGET
1496 				(ctree)->style->base_gc[GTK_STATE_NORMAL],
1497 				TRUE,
1498 				tc_rectangle.x,
1499 				tc_rectangle.y,
1500 				tc_rectangle.width,
1501 				tc_rectangle.height);
1502 	}
1503 
1504       xcenter = offset + (justification_factor * ctree->tree_indent / 2);
1505 
1506       get_cell_style (clist, &ctree_row->row, state, column, NULL, NULL,
1507 		      &bg_gc);
1508       if (bg_gc == clist->bg_gc)
1509 	gdk_gc_set_foreground (clist->bg_gc, &ctree_row->row.background);
1510 
1511       gdk_gc_set_clip_rectangle (bg_gc, crect);
1512       if (ctree_row->is_leaf)
1513 	{
1514 	  GdkPoint points[6];
1515 
1516 	  points[0].x = offset + justification_factor * TAB_SIZE;
1517 	  points[0].y = cell_rectangle->y;
1518 
1519 	  points[1].x = points[0].x - justification_factor * 4;
1520 	  points[1].y = points[0].y;
1521 
1522 	  points[2].x = points[1].x - justification_factor * 2;
1523 	  points[2].y = points[1].y + 3;
1524 
1525 	  points[3].x = points[2].x;
1526 	  points[3].y = points[2].y + clist->row_height - 5;
1527 
1528 	  points[4].x = points[3].x + justification_factor * 2;
1529 	  points[4].y = points[3].y + 3;
1530 
1531 	  points[5].x = points[4].x + justification_factor * 4;
1532 	  points[5].y = points[4].y;
1533 
1534 	  gdk_draw_polygon (clist->clist_window, bg_gc, TRUE, points, 6);
1535 	  gdk_draw_lines (clist->clist_window, ctree->lines_gc, points, 6);
1536 	}
1537       else
1538 	{
1539 	  gdk_draw_arc (clist->clist_window, bg_gc, TRUE,
1540 			offset - (justify_right * 2 * TAB_SIZE),
1541 			cell_rectangle->y,
1542 			2 * TAB_SIZE, clist->row_height,
1543 			(90 + (180 * justify_right)) * 64, 180 * 64);
1544 	  gdk_draw_arc (clist->clist_window, ctree->lines_gc, FALSE,
1545 			offset - (justify_right * 2 * TAB_SIZE),
1546 			cell_rectangle->y,
1547 			2 * TAB_SIZE, clist->row_height,
1548 			(90 + (180 * justify_right)) * 64, 180 * 64);
1549 	}
1550       gdk_gc_set_clip_rectangle (bg_gc, NULL);
1551       gdk_gc_set_clip_rectangle (ctree->lines_gc, NULL);
1552 
1553       offset += justification_factor * 3;
1554       break;
1555     default:
1556       xcenter = offset + justification_factor * PM_SIZE / 2;
1557 
1558       if (area)
1559 	{
1560 	  tree_rectangle.y = crect->y;
1561 	  tree_rectangle.height = crect->height;
1562 
1563 	  if (justify_right)
1564 	    {
1565 	      tree_rectangle.x = xcenter - PM_SIZE / 2 - 2;
1566 	      tree_rectangle.width = (clip_rectangle->x +
1567 				      clip_rectangle->width -tree_rectangle.x);
1568 	    }
1569 	  else
1570 	    {
1571 	      tree_rectangle.x = clip_rectangle->x + PM_SIZE / 2;
1572 	      tree_rectangle.width = (xcenter + PM_SIZE / 2 + 2 -
1573 				      clip_rectangle->x);
1574 	    }
1575 
1576 	  if (!gdk_rectangle_intersect (area, &tree_rectangle, &tc_rectangle))
1577 	    break;
1578 	}
1579 
1580       offset_x = 1;
1581       offset_y = 0;
1582       if (ctree->line_style == GTK_CTREE_LINES_DOTTED)
1583 	{
1584 	  offset_x += abs((clip_rectangle->x + clist->hoffset) % 2);
1585 	  offset_y  = abs((cell_rectangle->y + clist->voffset) % 2);
1586 	}
1587 
1588       clip_rectangle->y--;
1589       clip_rectangle->height++;
1590       gdk_gc_set_clip_rectangle (ctree->lines_gc, clip_rectangle);
1591       gdk_draw_line (clist->clist_window, ctree->lines_gc,
1592 		     xcenter,
1593 		     (ctree->show_stub || clist->row_list->data != ctree_row) ?
1594 		     cell_rectangle->y + offset_y : ycenter,
1595 		     xcenter,
1596 		     (ctree_row->sibling) ? crect->y +crect->height : ycenter);
1597 
1598       gdk_draw_line (clist->clist_window, ctree->lines_gc,
1599 		     xcenter + (justification_factor * offset_x), ycenter,
1600 		     xcenter + (justification_factor * (PM_SIZE / 2 + 2)),
1601 		     ycenter);
1602 
1603       node = ctree_row->parent;
1604       while (node)
1605 	{
1606 	  xcenter -= (justification_factor * ctree->tree_indent);
1607 
1608 	  if (GTK_CTREE_ROW (node)->sibling)
1609 	    gdk_draw_line (clist->clist_window, ctree->lines_gc,
1610 			   xcenter, cell_rectangle->y + offset_y,
1611 			   xcenter, crect->y + crect->height);
1612 	  node = GTK_CTREE_ROW (node)->parent;
1613 	}
1614       gdk_gc_set_clip_rectangle (ctree->lines_gc, NULL);
1615       clip_rectangle->y++;
1616       clip_rectangle->height--;
1617       break;
1618     }
1619   return offset;
1620 }
1621 
1622 static void
draw_row(GtkCList * clist,GdkRectangle * area,gint row,GtkCListRow * clist_row)1623 draw_row (GtkCList     *clist,
1624 	  GdkRectangle *area,
1625 	  gint          row,
1626 	  GtkCListRow  *clist_row)
1627 {
1628   GtkWidget *widget;
1629   GtkCTree  *ctree;
1630   GdkRectangle *crect;
1631   GdkRectangle row_rectangle;
1632   GdkRectangle cell_rectangle;
1633   GdkRectangle clip_rectangle;
1634   GdkRectangle intersect_rectangle;
1635   gint last_column;
1636   gint column_left = 0;
1637   gint column_right = 0;
1638   gint offset = 0;
1639   gint state;
1640   gint i;
1641 
1642   g_return_if_fail (clist != NULL);
1643 
1644   /* bail now if we arn't drawable yet */
1645   if (!GTK_WIDGET_DRAWABLE (clist) || row < 0 || row >= clist->rows)
1646     return;
1647 
1648   widget = GTK_WIDGET (clist);
1649   ctree  = GTK_CTREE  (clist);
1650 
1651   /* if the function is passed the pointer to the row instead of null,
1652    * it avoids this expensive lookup */
1653   if (!clist_row)
1654     clist_row = (g_list_nth (clist->row_list, row))->data;
1655 
1656   /* rectangle of the entire row */
1657   row_rectangle.x = 0;
1658   row_rectangle.y = ROW_TOP_YPIXEL (clist, row);
1659   row_rectangle.width = clist->clist_window_width;
1660   row_rectangle.height = clist->row_height;
1661 
1662   /* rectangle of the cell spacing above the row */
1663   cell_rectangle.x = 0;
1664   cell_rectangle.y = row_rectangle.y - CELL_SPACING;
1665   cell_rectangle.width = row_rectangle.width;
1666   cell_rectangle.height = CELL_SPACING;
1667 
1668   /* rectangle used to clip drawing operations, its y and height
1669    * positions only need to be set once, so we set them once here.
1670    * the x and width are set withing the drawing loop below once per
1671    * column */
1672   clip_rectangle.y = row_rectangle.y;
1673   clip_rectangle.height = row_rectangle.height;
1674 
1675   if (clist_row->state == GTK_STATE_NORMAL)
1676     {
1677       if (clist_row->fg_set)
1678 	gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground);
1679       if (clist_row->bg_set)
1680 	gdk_gc_set_foreground (clist->bg_gc, &clist_row->background);
1681     }
1682 
1683   state = clist_row->state;
1684 
1685   gdk_gc_set_foreground (ctree->lines_gc,
1686 			 &widget->style->fg[clist_row->state]);
1687 
1688   /* draw the cell borders */
1689   if (area)
1690     {
1691       crect = &intersect_rectangle;
1692 
1693       if (gdk_rectangle_intersect (area, &cell_rectangle, crect))
1694 	gdk_draw_rectangle (clist->clist_window,
1695 			    widget->style->base_gc[GTK_STATE_NORMAL], TRUE,
1696 			    crect->x, crect->y, crect->width, crect->height);
1697     }
1698   else
1699     {
1700       crect = &cell_rectangle;
1701 
1702       gdk_draw_rectangle (clist->clist_window,
1703 			  widget->style->base_gc[GTK_STATE_NORMAL], TRUE,
1704 			  crect->x, crect->y, crect->width, crect->height);
1705     }
1706 
1707   /* horizontal black lines */
1708   if (ctree->line_style == GTK_CTREE_LINES_TABBED)
1709     {
1710 
1711       column_right = (COLUMN_LEFT_XPIXEL (clist, ctree->tree_column) +
1712 		      clist->column[ctree->tree_column].area.width +
1713 		      COLUMN_INSET);
1714       column_left = (COLUMN_LEFT_XPIXEL (clist, ctree->tree_column) -
1715 		     COLUMN_INSET - (ctree->tree_column != 0) * CELL_SPACING);
1716 
1717       switch (clist->column[ctree->tree_column].justification)
1718 	{
1719 	case GTK_JUSTIFY_CENTER:
1720 	case GTK_JUSTIFY_FILL:
1721 	case GTK_JUSTIFY_LEFT:
1722 	  offset = (column_left + ctree->tree_indent *
1723 		    (((GtkCTreeRow *)clist_row)->level - 1));
1724 
1725 	  gdk_draw_line (clist->clist_window, ctree->lines_gc,
1726 			 MIN (offset + TAB_SIZE, column_right),
1727 			 cell_rectangle.y,
1728 			 clist->clist_window_width, cell_rectangle.y);
1729 	  break;
1730 	case GTK_JUSTIFY_RIGHT:
1731 	  offset = (column_right - 1 - ctree->tree_indent *
1732 		    (((GtkCTreeRow *)clist_row)->level - 1));
1733 
1734 	  gdk_draw_line (clist->clist_window, ctree->lines_gc,
1735 			 -1, cell_rectangle.y,
1736 			 MAX (offset - TAB_SIZE, column_left),
1737 			 cell_rectangle.y);
1738 	  break;
1739 	}
1740     }
1741 
1742   /* the last row has to clear its bottom cell spacing too */
1743   if (clist_row == clist->row_list_end->data)
1744     {
1745       cell_rectangle.y += clist->row_height + CELL_SPACING;
1746 
1747       if (!area || gdk_rectangle_intersect (area, &cell_rectangle, crect))
1748 	{
1749 	  gdk_draw_rectangle (clist->clist_window,
1750 			      widget->style->base_gc[GTK_STATE_NORMAL], TRUE,
1751 			      crect->x, crect->y, crect->width, crect->height);
1752 
1753 	  /* horizontal black lines */
1754 	  if (ctree->line_style == GTK_CTREE_LINES_TABBED)
1755 	    {
1756 	      switch (clist->column[ctree->tree_column].justification)
1757 		{
1758 		case GTK_JUSTIFY_CENTER:
1759 		case GTK_JUSTIFY_FILL:
1760 		case GTK_JUSTIFY_LEFT:
1761 		  gdk_draw_line (clist->clist_window, ctree->lines_gc,
1762 				 MIN (column_left + TAB_SIZE + COLUMN_INSET +
1763 				      (((GtkCTreeRow *)clist_row)->level > 1) *
1764 				      MIN (ctree->tree_indent / 2, TAB_SIZE),
1765 				      column_right),
1766 				 cell_rectangle.y,
1767 				 clist->clist_window_width, cell_rectangle.y);
1768 		  break;
1769 		case GTK_JUSTIFY_RIGHT:
1770 		  gdk_draw_line (clist->clist_window, ctree->lines_gc,
1771 				 -1, cell_rectangle.y,
1772 				 MAX (column_right - TAB_SIZE - 1 -
1773 				      COLUMN_INSET -
1774 				      (((GtkCTreeRow *)clist_row)->level > 1) *
1775 				      MIN (ctree->tree_indent / 2, TAB_SIZE),
1776 				      column_left - 1), cell_rectangle.y);
1777 		  break;
1778 		}
1779 	    }
1780 	}
1781     }
1782 
1783   for (last_column = clist->columns - 1;
1784        last_column >= 0 && !clist->column[last_column].visible; last_column--)
1785     ;
1786 
1787   /* iterate and draw all the columns (row cells) and draw their contents */
1788   for (i = 0; i < clist->columns; i++)
1789     {
1790       GtkStyle *style;
1791       GdkGC *fg_gc;
1792       GdkGC *bg_gc;
1793       PangoLayout *layout = NULL;
1794       PangoRectangle logical_rect;
1795 
1796       gint width;
1797       gint height;
1798       gint pixmap_width;
1799       gint string_width;
1800       gint old_offset;
1801 
1802       if (!clist->column[i].visible)
1803 	continue;
1804 
1805       get_cell_style (clist, clist_row, state, i, &style, &fg_gc, &bg_gc);
1806 
1807       /* calculate clipping region */
1808       clip_rectangle.x = clist->column[i].area.x + clist->hoffset;
1809       clip_rectangle.width = clist->column[i].area.width;
1810 
1811       cell_rectangle.x = clip_rectangle.x - COLUMN_INSET - CELL_SPACING;
1812       cell_rectangle.width = (clip_rectangle.width + 2 * COLUMN_INSET +
1813 			      (1 + (i == last_column)) * CELL_SPACING);
1814       cell_rectangle.y = clip_rectangle.y;
1815       cell_rectangle.height = clip_rectangle.height;
1816 
1817       string_width = 0;
1818       pixmap_width = 0;
1819 
1820       if (area && !gdk_rectangle_intersect (area, &cell_rectangle,
1821 					    &intersect_rectangle))
1822 	{
1823 	  if (i != ctree->tree_column)
1824 	    continue;
1825 	}
1826       else
1827 	{
1828 	  gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE,
1829 			      crect->x, crect->y, crect->width, crect->height);
1830 
1831 
1832 	  layout = _gtk_clist_create_cell_layout (clist, clist_row, i);
1833 	  if (layout)
1834 	    {
1835 	      pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1836 	      width = logical_rect.width;
1837 	    }
1838 	  else
1839 	    width = 0;
1840 
1841 	  switch (clist_row->cell[i].type)
1842 	    {
1843 	    case GTK_CELL_PIXMAP:
1844 	      gdk_drawable_get_size
1845 		(GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &pixmap_width,
1846 		 &height);
1847 	      width += pixmap_width;
1848 	      break;
1849 	    case GTK_CELL_PIXTEXT:
1850 	      if (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap)
1851 		{
1852 		  gdk_drawable_get_size
1853 		    (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
1854 		     &pixmap_width, &height);
1855 		  width += pixmap_width;
1856 		}
1857 
1858 	      if (GTK_CELL_PIXTEXT (clist_row->cell[i])->text &&
1859 		  GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap)
1860 		width +=  GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
1861 
1862 	      if (i == ctree->tree_column)
1863 		width += (ctree->tree_indent *
1864 			  ((GtkCTreeRow *)clist_row)->level);
1865 	      break;
1866 	    default:
1867 	      break;
1868 	    }
1869 
1870 	  switch (clist->column[i].justification)
1871 	    {
1872 	    case GTK_JUSTIFY_LEFT:
1873 	      offset = clip_rectangle.x + clist_row->cell[i].horizontal;
1874 	      break;
1875 	    case GTK_JUSTIFY_RIGHT:
1876 	      offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
1877 			clip_rectangle.width - width);
1878 	      break;
1879 	    case GTK_JUSTIFY_CENTER:
1880 	    case GTK_JUSTIFY_FILL:
1881 	      offset = (clip_rectangle.x + clist_row->cell[i].horizontal +
1882 			(clip_rectangle.width / 2) - (width / 2));
1883 	      break;
1884 	    };
1885 
1886 	  if (i != ctree->tree_column)
1887 	    {
1888 	      offset += clist_row->cell[i].horizontal;
1889 	      switch (clist_row->cell[i].type)
1890 		{
1891 		case GTK_CELL_PIXMAP:
1892 		  draw_cell_pixmap
1893 		    (clist->clist_window, &clip_rectangle, fg_gc,
1894 		     GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap,
1895 		     GTK_CELL_PIXMAP (clist_row->cell[i])->mask,
1896 		     offset,
1897 		     clip_rectangle.y + clist_row->cell[i].vertical +
1898 		     (clip_rectangle.height - height) / 2,
1899 		     pixmap_width, height);
1900 		  break;
1901 		case GTK_CELL_PIXTEXT:
1902 		  offset = draw_cell_pixmap
1903 		    (clist->clist_window, &clip_rectangle, fg_gc,
1904 		     GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
1905 		     GTK_CELL_PIXTEXT (clist_row->cell[i])->mask,
1906 		     offset,
1907 		     clip_rectangle.y + clist_row->cell[i].vertical +
1908 		     (clip_rectangle.height - height) / 2,
1909 		     pixmap_width, height);
1910 		  offset += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
1911 
1912 		  /* Fall through */
1913 		case GTK_CELL_TEXT:
1914 		  if (layout)
1915 		    {
1916 		      gint row_center_offset = (clist->row_height - logical_rect.height) / 2;
1917 
1918 		      gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle);
1919 		      gdk_draw_layout (clist->clist_window, fg_gc,
1920 				       offset,
1921 				       row_rectangle.y + row_center_offset + clist_row->cell[i].vertical,
1922 				       layout);
1923 		      gdk_gc_set_clip_rectangle (fg_gc, NULL);
1924 		      g_object_unref (G_OBJECT (layout));
1925 		    }
1926 		  break;
1927 		default:
1928 		  break;
1929 		}
1930 	      continue;
1931 	    }
1932 	}
1933 
1934       if (bg_gc == clist->bg_gc)
1935 	gdk_gc_set_background (ctree->lines_gc, &clist_row->background);
1936 
1937       /* draw ctree->tree_column */
1938       cell_rectangle.y -= CELL_SPACING;
1939       cell_rectangle.height += CELL_SPACING;
1940 
1941       if (area && !gdk_rectangle_intersect (area, &cell_rectangle,
1942 					    &intersect_rectangle))
1943 	{
1944 	  if (layout)
1945             g_object_unref (G_OBJECT (layout));
1946 	  continue;
1947 	}
1948 
1949       /* draw lines */
1950       offset = gtk_ctree_draw_lines (ctree, (GtkCTreeRow *)clist_row, row, i,
1951 				     state, &clip_rectangle, &cell_rectangle,
1952 				     crect, area, style);
1953 
1954       /* draw expander */
1955       offset = gtk_ctree_draw_expander (ctree, (GtkCTreeRow *)clist_row,
1956 					style, &clip_rectangle, offset);
1957 
1958       if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
1959 	offset -= ctree->tree_spacing;
1960       else
1961 	offset += ctree->tree_spacing;
1962 
1963       if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
1964 	offset -= (pixmap_width + clist_row->cell[i].horizontal);
1965       else
1966 	offset += clist_row->cell[i].horizontal;
1967 
1968       old_offset = offset;
1969       offset = draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc,
1970 				 GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap,
1971 				 GTK_CELL_PIXTEXT (clist_row->cell[i])->mask,
1972 				 offset,
1973 				 clip_rectangle.y + clist_row->cell[i].vertical
1974 				 + (clip_rectangle.height - height) / 2,
1975 				 pixmap_width, height);
1976 
1977       if (layout)
1978 	{
1979 	  gint row_center_offset = (clist->row_height - logical_rect.height) / 2;
1980 
1981 	  if (clist->column[i].justification == GTK_JUSTIFY_RIGHT)
1982 	    {
1983 	      offset = (old_offset - string_width);
1984 	      if (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap)
1985 		offset -= GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
1986 	    }
1987 	  else
1988 	    {
1989 	      if (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap)
1990 		offset += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
1991 	    }
1992 
1993 	  gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle);
1994 	  gdk_draw_layout (clist->clist_window, fg_gc,
1995 			   offset,
1996 			   row_rectangle.y + row_center_offset + clist_row->cell[i].vertical,
1997 			   layout);
1998 
1999           g_object_unref (G_OBJECT (layout));
2000 	}
2001       gdk_gc_set_clip_rectangle (fg_gc, NULL);
2002     }
2003 
2004   /* draw focus rectangle */
2005   if (clist->focus_row == row &&
2006       GTK_WIDGET_CAN_FOCUS (widget) && gtk_widget_has_focus (widget))
2007     {
2008       if (!area)
2009 	gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
2010 			    row_rectangle.x, row_rectangle.y,
2011 			    row_rectangle.width - 1, row_rectangle.height - 1);
2012       else if (gdk_rectangle_intersect (area, &row_rectangle,
2013 					&intersect_rectangle))
2014 	{
2015 	  gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle);
2016 	  gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE,
2017 			      row_rectangle.x, row_rectangle.y,
2018 			      row_rectangle.width - 1,
2019 			      row_rectangle.height - 1);
2020 	  gdk_gc_set_clip_rectangle (clist->xor_gc, NULL);
2021 	}
2022     }
2023 }
2024 
2025 static void
tree_draw_node(GtkCTree * ctree,GtkCTreeNode * node)2026 tree_draw_node (GtkCTree     *ctree,
2027 	        GtkCTreeNode *node)
2028 {
2029   GtkCList *clist;
2030 
2031   clist = GTK_CLIST (ctree);
2032 
2033   if (CLIST_UNFROZEN (clist) && gtk_ctree_is_viewable (ctree, node))
2034     {
2035       GtkCTreeNode *work;
2036       gint num = 0;
2037 
2038       work = GTK_CTREE_NODE (clist->row_list);
2039       while (work && work != node)
2040 	{
2041 	  work = GTK_CTREE_NODE_NEXT (work);
2042 	  num++;
2043 	}
2044       if (work && gtk_clist_row_is_visible (clist, num) != GTK_VISIBILITY_NONE)
2045 	GTK_CLIST_GET_CLASS (clist)->draw_row
2046 	  (clist, NULL, num, GTK_CLIST_ROW ((GList *) node));
2047     }
2048 }
2049 
2050 static GtkCTreeNode *
gtk_ctree_last_visible(GtkCTree * ctree,GtkCTreeNode * node)2051 gtk_ctree_last_visible (GtkCTree     *ctree,
2052 			GtkCTreeNode *node)
2053 {
2054   GtkCTreeNode *work;
2055 
2056   if (!node)
2057     return NULL;
2058 
2059   work = GTK_CTREE_ROW (node)->children;
2060 
2061   if (!work || !GTK_CTREE_ROW (node)->expanded)
2062     return node;
2063 
2064   while (GTK_CTREE_ROW (work)->sibling)
2065     work = GTK_CTREE_ROW (work)->sibling;
2066 
2067   return gtk_ctree_last_visible (ctree, work);
2068 }
2069 
2070 static void
gtk_ctree_link(GtkCTree * ctree,GtkCTreeNode * node,GtkCTreeNode * parent,GtkCTreeNode * sibling,gboolean update_focus_row)2071 gtk_ctree_link (GtkCTree     *ctree,
2072 		GtkCTreeNode *node,
2073 		GtkCTreeNode *parent,
2074 		GtkCTreeNode *sibling,
2075 		gboolean      update_focus_row)
2076 {
2077   GtkCList *clist;
2078   GList *list_end;
2079   GList *list;
2080   GList *work;
2081   gboolean visible = FALSE;
2082   gint rows = 0;
2083 
2084   if (sibling)
2085     g_return_if_fail (GTK_CTREE_ROW (sibling)->parent == parent);
2086   g_return_if_fail (node != NULL);
2087   g_return_if_fail (node != sibling);
2088   g_return_if_fail (node != parent);
2089 
2090   clist = GTK_CLIST (ctree);
2091 
2092   if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE)
2093     {
2094       GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2095 
2096       g_list_free (clist->undo_selection);
2097       g_list_free (clist->undo_unselection);
2098       clist->undo_selection = NULL;
2099       clist->undo_unselection = NULL;
2100     }
2101 
2102   for (rows = 1, list_end = (GList *)node; list_end->next;
2103        list_end = list_end->next)
2104     rows++;
2105 
2106   GTK_CTREE_ROW (node)->parent = parent;
2107   GTK_CTREE_ROW (node)->sibling = sibling;
2108 
2109   if (!parent || (parent && (gtk_ctree_is_viewable (ctree, parent) &&
2110 			     GTK_CTREE_ROW (parent)->expanded)))
2111     {
2112       visible = TRUE;
2113       clist->rows += rows;
2114     }
2115 
2116   if (parent)
2117     work = (GList *)(GTK_CTREE_ROW (parent)->children);
2118   else
2119     work = clist->row_list;
2120 
2121   if (sibling)
2122     {
2123       if (work != (GList *)sibling)
2124 	{
2125 	  while (GTK_CTREE_ROW (work)->sibling != sibling)
2126 	    work = (GList *)(GTK_CTREE_ROW (work)->sibling);
2127 	  GTK_CTREE_ROW (work)->sibling = node;
2128 	}
2129 
2130       if (sibling == GTK_CTREE_NODE (clist->row_list))
2131 	clist->row_list = (GList *) node;
2132       if (GTK_CTREE_NODE_PREV (sibling) &&
2133 	  GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (sibling)) == sibling)
2134 	{
2135 	  list = (GList *)GTK_CTREE_NODE_PREV (sibling);
2136 	  list->next = (GList *)node;
2137 	}
2138 
2139       list = (GList *)node;
2140       list->prev = (GList *)GTK_CTREE_NODE_PREV (sibling);
2141       list_end->next = (GList *)sibling;
2142       list = (GList *)sibling;
2143       list->prev = list_end;
2144       if (parent && GTK_CTREE_ROW (parent)->children == sibling)
2145 	GTK_CTREE_ROW (parent)->children = node;
2146     }
2147   else
2148     {
2149       if (work)
2150 	{
2151 	  /* find sibling */
2152 	  while (GTK_CTREE_ROW (work)->sibling)
2153 	    work = (GList *)(GTK_CTREE_ROW (work)->sibling);
2154 	  GTK_CTREE_ROW (work)->sibling = node;
2155 
2156 	  /* find last visible child of sibling */
2157 	  work = (GList *) gtk_ctree_last_visible (ctree,
2158 						   GTK_CTREE_NODE (work));
2159 
2160 	  list_end->next = work->next;
2161 	  if (work->next)
2162 	    list = work->next->prev = list_end;
2163 	  work->next = (GList *)node;
2164 	  list = (GList *)node;
2165 	  list->prev = work;
2166 	}
2167       else
2168 	{
2169 	  if (parent)
2170 	    {
2171 	      GTK_CTREE_ROW (parent)->children = node;
2172 	      list = (GList *)node;
2173 	      list->prev = (GList *)parent;
2174 	      if (GTK_CTREE_ROW (parent)->expanded)
2175 		{
2176 		  list_end->next = (GList *)GTK_CTREE_NODE_NEXT (parent);
2177 		  if (GTK_CTREE_NODE_NEXT(parent))
2178 		    {
2179 		      list = (GList *)GTK_CTREE_NODE_NEXT (parent);
2180 		      list->prev = list_end;
2181 		    }
2182 		  list = (GList *)parent;
2183 		  list->next = (GList *)node;
2184 		}
2185 	      else
2186 		list_end->next = NULL;
2187 	    }
2188 	  else
2189 	    {
2190 	      clist->row_list = (GList *)node;
2191 	      list = (GList *)node;
2192 	      list->prev = NULL;
2193 	      list_end->next = NULL;
2194 	    }
2195 	}
2196     }
2197 
2198   gtk_ctree_pre_recursive (ctree, node, tree_update_level, NULL);
2199 
2200   if (clist->row_list_end == NULL ||
2201       clist->row_list_end->next == (GList *)node)
2202     clist->row_list_end = list_end;
2203 
2204   if (visible && update_focus_row)
2205     {
2206       gint pos;
2207 
2208       pos = g_list_position (clist->row_list, (GList *)node);
2209 
2210       if (pos <= clist->focus_row)
2211 	{
2212 	  clist->focus_row += rows;
2213 	  clist->undo_anchor = clist->focus_row;
2214 	}
2215     }
2216 }
2217 
2218 static void
gtk_ctree_unlink(GtkCTree * ctree,GtkCTreeNode * node,gboolean update_focus_row)2219 gtk_ctree_unlink (GtkCTree     *ctree,
2220 		  GtkCTreeNode *node,
2221                   gboolean      update_focus_row)
2222 {
2223   GtkCList *clist;
2224   gint rows;
2225   gint level;
2226   gint visible;
2227   GtkCTreeNode *work;
2228   GtkCTreeNode *parent;
2229   GList *list;
2230 
2231   g_return_if_fail (GTK_IS_CTREE (ctree));
2232   g_return_if_fail (node != NULL);
2233 
2234   clist = GTK_CLIST (ctree);
2235 
2236   if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE)
2237     {
2238       GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2239 
2240       g_list_free (clist->undo_selection);
2241       g_list_free (clist->undo_unselection);
2242       clist->undo_selection = NULL;
2243       clist->undo_unselection = NULL;
2244     }
2245 
2246   visible = gtk_ctree_is_viewable (ctree, node);
2247 
2248   /* clist->row_list_end unlinked ? */
2249   if (visible &&
2250       (GTK_CTREE_NODE_NEXT (node) == NULL ||
2251        (GTK_CTREE_ROW (node)->children &&
2252 	gtk_ctree_is_ancestor (ctree, node,
2253 			       GTK_CTREE_NODE (clist->row_list_end)))))
2254     clist->row_list_end = (GList *) (GTK_CTREE_NODE_PREV (node));
2255 
2256   /* update list */
2257   rows = 0;
2258   level = GTK_CTREE_ROW (node)->level;
2259   work = GTK_CTREE_NODE_NEXT (node);
2260   while (work && GTK_CTREE_ROW (work)->level > level)
2261     {
2262       work = GTK_CTREE_NODE_NEXT (work);
2263       rows++;
2264     }
2265 
2266   if (visible)
2267     {
2268       clist->rows -= (rows + 1);
2269 
2270       if (update_focus_row)
2271 	{
2272 	  gint pos;
2273 
2274 	  pos = g_list_position (clist->row_list, (GList *)node);
2275 	  if (pos + rows < clist->focus_row)
2276 	    clist->focus_row -= (rows + 1);
2277 	  else if (pos <= clist->focus_row)
2278 	    {
2279 	      if (!GTK_CTREE_ROW (node)->sibling)
2280 		clist->focus_row = MAX (pos - 1, 0);
2281 	      else
2282 		clist->focus_row = pos;
2283 
2284 	      clist->focus_row = MIN (clist->focus_row, clist->rows - 1);
2285 	    }
2286 	  clist->undo_anchor = clist->focus_row;
2287 	}
2288     }
2289 
2290   if (work)
2291     {
2292       list = (GList *)GTK_CTREE_NODE_PREV (work);
2293       list->next = NULL;
2294       list = (GList *)work;
2295       list->prev = (GList *)GTK_CTREE_NODE_PREV (node);
2296     }
2297 
2298   if (GTK_CTREE_NODE_PREV (node) &&
2299       GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (node)) == node)
2300     {
2301       list = (GList *)GTK_CTREE_NODE_PREV (node);
2302       list->next = (GList *)work;
2303     }
2304 
2305   /* update tree */
2306   parent = GTK_CTREE_ROW (node)->parent;
2307   if (parent)
2308     {
2309       if (GTK_CTREE_ROW (parent)->children == node)
2310 	{
2311 	  GTK_CTREE_ROW (parent)->children = GTK_CTREE_ROW (node)->sibling;
2312 	  if (!GTK_CTREE_ROW (parent)->children)
2313 	    gtk_ctree_collapse (ctree, parent);
2314 	}
2315       else
2316 	{
2317 	  GtkCTreeNode *sibling;
2318 
2319 	  sibling = GTK_CTREE_ROW (parent)->children;
2320 	  while (GTK_CTREE_ROW (sibling)->sibling != node)
2321 	    sibling = GTK_CTREE_ROW (sibling)->sibling;
2322 	  GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
2323 	}
2324     }
2325   else
2326     {
2327       if (clist->row_list == (GList *)node)
2328 	clist->row_list = (GList *) (GTK_CTREE_ROW (node)->sibling);
2329       else
2330 	{
2331 	  GtkCTreeNode *sibling;
2332 
2333 	  sibling = GTK_CTREE_NODE (clist->row_list);
2334 	  while (GTK_CTREE_ROW (sibling)->sibling != node)
2335 	    sibling = GTK_CTREE_ROW (sibling)->sibling;
2336 	  GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling;
2337 	}
2338     }
2339 }
2340 
2341 static void
real_row_move(GtkCList * clist,gint source_row,gint dest_row)2342 real_row_move (GtkCList *clist,
2343 	       gint      source_row,
2344 	       gint      dest_row)
2345 {
2346   GtkCTree *ctree;
2347   GtkCTreeNode *node;
2348 
2349   g_return_if_fail (GTK_IS_CTREE (clist));
2350 
2351   if (GTK_CLIST_AUTO_SORT (clist))
2352     return;
2353 
2354   if (source_row < 0 || source_row >= clist->rows ||
2355       dest_row   < 0 || dest_row   >= clist->rows ||
2356       source_row == dest_row)
2357     return;
2358 
2359   ctree = GTK_CTREE (clist);
2360   node = GTK_CTREE_NODE (g_list_nth (clist->row_list, source_row));
2361 
2362   if (source_row < dest_row)
2363     {
2364       GtkCTreeNode *work;
2365 
2366       dest_row++;
2367       work = GTK_CTREE_ROW (node)->children;
2368 
2369       while (work && GTK_CTREE_ROW (work)->level > GTK_CTREE_ROW (node)->level)
2370 	{
2371 	  work = GTK_CTREE_NODE_NEXT (work);
2372 	  dest_row++;
2373 	}
2374 
2375       if (dest_row > clist->rows)
2376 	dest_row = clist->rows;
2377     }
2378 
2379   if (dest_row < clist->rows)
2380     {
2381       GtkCTreeNode *sibling;
2382 
2383       sibling = GTK_CTREE_NODE (g_list_nth (clist->row_list, dest_row));
2384       gtk_ctree_move (ctree, node, GTK_CTREE_ROW (sibling)->parent, sibling);
2385     }
2386   else
2387     gtk_ctree_move (ctree, node, NULL, NULL);
2388 }
2389 
2390 static void
real_tree_move(GtkCTree * ctree,GtkCTreeNode * node,GtkCTreeNode * new_parent,GtkCTreeNode * new_sibling)2391 real_tree_move (GtkCTree     *ctree,
2392 		GtkCTreeNode *node,
2393 		GtkCTreeNode *new_parent,
2394 		GtkCTreeNode *new_sibling)
2395 {
2396   GtkCList *clist;
2397   GtkCTreeNode *work;
2398   gboolean visible = FALSE;
2399 
2400   g_return_if_fail (ctree != NULL);
2401   g_return_if_fail (node != NULL);
2402   g_return_if_fail (!new_sibling ||
2403 		    GTK_CTREE_ROW (new_sibling)->parent == new_parent);
2404 
2405   if (new_parent && GTK_CTREE_ROW (new_parent)->is_leaf)
2406     return;
2407 
2408   /* new_parent != child of child */
2409   for (work = new_parent; work; work = GTK_CTREE_ROW (work)->parent)
2410     if (work == node)
2411       return;
2412 
2413   clist = GTK_CLIST (ctree);
2414 
2415   visible = gtk_ctree_is_viewable (ctree, node);
2416 
2417   if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
2418     {
2419       GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2420 
2421       g_list_free (clist->undo_selection);
2422       g_list_free (clist->undo_unselection);
2423       clist->undo_selection = NULL;
2424       clist->undo_unselection = NULL;
2425     }
2426 
2427   if (GTK_CLIST_AUTO_SORT (clist))
2428     {
2429       if (new_parent == GTK_CTREE_ROW (node)->parent)
2430 	return;
2431 
2432       if (new_parent)
2433 	new_sibling = GTK_CTREE_ROW (new_parent)->children;
2434       else
2435 	new_sibling = GTK_CTREE_NODE (clist->row_list);
2436 
2437       while (new_sibling && clist->compare
2438 	     (clist, GTK_CTREE_ROW (node), GTK_CTREE_ROW (new_sibling)) > 0)
2439 	new_sibling = GTK_CTREE_ROW (new_sibling)->sibling;
2440     }
2441 
2442   if (new_parent == GTK_CTREE_ROW (node)->parent &&
2443       new_sibling == GTK_CTREE_ROW (node)->sibling)
2444     return;
2445 
2446   gtk_clist_freeze (clist);
2447 
2448   work = NULL;
2449   if (gtk_ctree_is_viewable (ctree, node))
2450     work = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
2451 
2452   gtk_ctree_unlink (ctree, node, FALSE);
2453   gtk_ctree_link (ctree, node, new_parent, new_sibling, FALSE);
2454 
2455   if (work)
2456     {
2457       while (work &&  !gtk_ctree_is_viewable (ctree, work))
2458 	work = GTK_CTREE_ROW (work)->parent;
2459       clist->focus_row = g_list_position (clist->row_list, (GList *)work);
2460       clist->undo_anchor = clist->focus_row;
2461     }
2462 
2463   if (clist->column[ctree->tree_column].auto_resize &&
2464       !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist) &&
2465       (visible || gtk_ctree_is_viewable (ctree, node)))
2466     gtk_clist_set_column_width
2467       (clist, ctree->tree_column,
2468        gtk_clist_optimal_column_width (clist, ctree->tree_column));
2469 
2470   gtk_clist_thaw (clist);
2471 }
2472 
2473 static void
change_focus_row_expansion(GtkCTree * ctree,GtkCTreeExpansionType action)2474 change_focus_row_expansion (GtkCTree          *ctree,
2475 			    GtkCTreeExpansionType action)
2476 {
2477   GtkCList *clist;
2478   GtkCTreeNode *node;
2479 
2480   g_return_if_fail (GTK_IS_CTREE (ctree));
2481 
2482   clist = GTK_CLIST (ctree);
2483 
2484   if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (ctree))) &&
2485       GTK_WIDGET_HAS_GRAB (ctree))
2486     return;
2487 
2488   if (!(node =
2489 	GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))) ||
2490       GTK_CTREE_ROW (node)->is_leaf || !(GTK_CTREE_ROW (node)->children))
2491     return;
2492 
2493   switch (action)
2494     {
2495     case GTK_CTREE_EXPANSION_EXPAND:
2496       gtk_ctree_expand (ctree, node);
2497       break;
2498     case GTK_CTREE_EXPANSION_EXPAND_RECURSIVE:
2499       gtk_ctree_expand_recursive (ctree, node);
2500       break;
2501     case GTK_CTREE_EXPANSION_COLLAPSE:
2502       gtk_ctree_collapse (ctree, node);
2503       break;
2504     case GTK_CTREE_EXPANSION_COLLAPSE_RECURSIVE:
2505       gtk_ctree_collapse_recursive (ctree, node);
2506       break;
2507     case GTK_CTREE_EXPANSION_TOGGLE:
2508       gtk_ctree_toggle_expansion (ctree, node);
2509       break;
2510     case GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE:
2511       gtk_ctree_toggle_expansion_recursive (ctree, node);
2512       break;
2513     }
2514 }
2515 
2516 static void
real_tree_expand(GtkCTree * ctree,GtkCTreeNode * node)2517 real_tree_expand (GtkCTree     *ctree,
2518 		  GtkCTreeNode *node)
2519 {
2520   GtkCList *clist;
2521   GtkCTreeNode *work;
2522   GtkRequisition requisition;
2523   gboolean visible;
2524 
2525   g_return_if_fail (GTK_IS_CTREE (ctree));
2526 
2527   if (!node || GTK_CTREE_ROW (node)->expanded || GTK_CTREE_ROW (node)->is_leaf)
2528     return;
2529 
2530   clist = GTK_CLIST (ctree);
2531 
2532   GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2533 
2534   GTK_CTREE_ROW (node)->expanded = TRUE;
2535 
2536   visible = gtk_ctree_is_viewable (ctree, node);
2537   /* get cell width if tree_column is auto resized */
2538   if (visible && clist->column[ctree->tree_column].auto_resize &&
2539       !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2540     GTK_CLIST_GET_CLASS (clist)->cell_size_request
2541       (clist, &GTK_CTREE_ROW (node)->row, ctree->tree_column, &requisition);
2542 
2543   /* unref/unset closed pixmap */
2544   if (GTK_CELL_PIXTEXT
2545       (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap)
2546     {
2547       g_object_unref
2548 	(GTK_CELL_PIXTEXT
2549 	 (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap);
2550 
2551       GTK_CELL_PIXTEXT
2552 	(GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = NULL;
2553 
2554       if (GTK_CELL_PIXTEXT
2555 	  (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask)
2556 	{
2557 	  g_object_unref
2558 	    (GTK_CELL_PIXTEXT
2559 	     (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask);
2560 	  GTK_CELL_PIXTEXT
2561 	    (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask = NULL;
2562 	}
2563     }
2564 
2565   /* set/ref opened pixmap */
2566   if (GTK_CTREE_ROW (node)->pixmap_opened)
2567     {
2568       GTK_CELL_PIXTEXT
2569 	(GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap =
2570 	g_object_ref (GTK_CTREE_ROW (node)->pixmap_opened);
2571 
2572       if (GTK_CTREE_ROW (node)->mask_opened)
2573 	GTK_CELL_PIXTEXT
2574 	  (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask =
2575 	  g_object_ref (GTK_CTREE_ROW (node)->mask_opened);
2576     }
2577 
2578 
2579   work = GTK_CTREE_ROW (node)->children;
2580   if (work)
2581     {
2582       GList *list = (GList *)work;
2583       gint *cell_width = NULL;
2584       gint tmp = 0;
2585       gint row;
2586       gint i;
2587 
2588       if (visible && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2589 	{
2590 	  cell_width = g_new0 (gint, clist->columns);
2591 	  if (clist->column[ctree->tree_column].auto_resize)
2592 	      cell_width[ctree->tree_column] = requisition.width;
2593 
2594 	  while (work)
2595 	    {
2596 	      /* search maximum cell widths of auto_resize columns */
2597 	      for (i = 0; i < clist->columns; i++)
2598 		if (clist->column[i].auto_resize)
2599 		  {
2600 		    GTK_CLIST_GET_CLASS (clist)->cell_size_request
2601 		      (clist, &GTK_CTREE_ROW (work)->row, i, &requisition);
2602 		    cell_width[i] = MAX (requisition.width, cell_width[i]);
2603 		  }
2604 
2605 	      list = (GList *)work;
2606 	      work = GTK_CTREE_NODE_NEXT (work);
2607 	      tmp++;
2608 	    }
2609 	}
2610       else
2611 	while (work)
2612 	  {
2613 	    list = (GList *)work;
2614 	    work = GTK_CTREE_NODE_NEXT (work);
2615 	    tmp++;
2616 	  }
2617 
2618       list->next = (GList *)GTK_CTREE_NODE_NEXT (node);
2619 
2620       if (GTK_CTREE_NODE_NEXT (node))
2621 	{
2622 	  GList *tmp_list;
2623 
2624 	  tmp_list = (GList *)GTK_CTREE_NODE_NEXT (node);
2625 	  tmp_list->prev = list;
2626 	}
2627       else
2628 	clist->row_list_end = list;
2629 
2630       list = (GList *)node;
2631       list->next = (GList *)(GTK_CTREE_ROW (node)->children);
2632 
2633       if (visible)
2634 	{
2635 	  /* resize auto_resize columns if needed */
2636 	  for (i = 0; i < clist->columns; i++)
2637 	    if (clist->column[i].auto_resize &&
2638 		cell_width[i] > clist->column[i].width)
2639 	      gtk_clist_set_column_width (clist, i, cell_width[i]);
2640 	  g_free (cell_width);
2641 
2642 	  /* update focus_row position */
2643 	  row = g_list_position (clist->row_list, (GList *)node);
2644 	  if (row < clist->focus_row)
2645 	    clist->focus_row += tmp;
2646 
2647 	  clist->rows += tmp;
2648 	  CLIST_REFRESH (clist);
2649 	}
2650     }
2651   else if (visible && clist->column[ctree->tree_column].auto_resize)
2652     /* resize tree_column if needed */
2653     column_auto_resize (clist, &GTK_CTREE_ROW (node)->row, ctree->tree_column,
2654 			requisition.width);
2655 }
2656 
2657 static void
real_tree_collapse(GtkCTree * ctree,GtkCTreeNode * node)2658 real_tree_collapse (GtkCTree     *ctree,
2659 		    GtkCTreeNode *node)
2660 {
2661   GtkCList *clist;
2662   GtkCTreeNode *work;
2663   GtkRequisition requisition;
2664   gboolean visible;
2665   gint level;
2666 
2667   g_return_if_fail (GTK_IS_CTREE (ctree));
2668 
2669   if (!node || !GTK_CTREE_ROW (node)->expanded ||
2670       GTK_CTREE_ROW (node)->is_leaf)
2671     return;
2672 
2673   clist = GTK_CLIST (ctree);
2674 
2675   GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
2676 
2677   GTK_CTREE_ROW (node)->expanded = FALSE;
2678   level = GTK_CTREE_ROW (node)->level;
2679 
2680   visible = gtk_ctree_is_viewable (ctree, node);
2681   /* get cell width if tree_column is auto resized */
2682   if (visible && clist->column[ctree->tree_column].auto_resize &&
2683       !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2684     GTK_CLIST_GET_CLASS (clist)->cell_size_request
2685       (clist, &GTK_CTREE_ROW (node)->row, ctree->tree_column, &requisition);
2686 
2687   /* unref/unset opened pixmap */
2688   if (GTK_CELL_PIXTEXT
2689       (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap)
2690     {
2691       g_object_unref
2692 	(GTK_CELL_PIXTEXT
2693 	 (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap);
2694 
2695       GTK_CELL_PIXTEXT
2696 	(GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = NULL;
2697 
2698       if (GTK_CELL_PIXTEXT
2699 	  (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask)
2700 	{
2701 	  g_object_unref
2702 	    (GTK_CELL_PIXTEXT
2703 	     (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask);
2704 	  GTK_CELL_PIXTEXT
2705 	    (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask = NULL;
2706 	}
2707     }
2708 
2709   /* set/ref closed pixmap */
2710   if (GTK_CTREE_ROW (node)->pixmap_closed)
2711     {
2712       GTK_CELL_PIXTEXT
2713 	(GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap =
2714 	g_object_ref (GTK_CTREE_ROW (node)->pixmap_closed);
2715 
2716       if (GTK_CTREE_ROW (node)->mask_closed)
2717 	GTK_CELL_PIXTEXT
2718 	  (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask =
2719 	  g_object_ref (GTK_CTREE_ROW (node)->mask_closed);
2720     }
2721 
2722   work = GTK_CTREE_ROW (node)->children;
2723   if (work)
2724     {
2725       gint tmp = 0;
2726       gint row;
2727       GList *list;
2728 
2729       while (work && GTK_CTREE_ROW (work)->level > level)
2730 	{
2731 	  work = GTK_CTREE_NODE_NEXT (work);
2732 	  tmp++;
2733 	}
2734 
2735       if (work)
2736 	{
2737 	  list = (GList *)node;
2738 	  list->next = (GList *)work;
2739 	  list = (GList *)GTK_CTREE_NODE_PREV (work);
2740 	  list->next = NULL;
2741 	  list = (GList *)work;
2742 	  list->prev = (GList *)node;
2743 	}
2744       else
2745 	{
2746 	  list = (GList *)node;
2747 	  list->next = NULL;
2748 	  clist->row_list_end = (GList *)node;
2749 	}
2750 
2751       if (visible)
2752 	{
2753 	  /* resize auto_resize columns if needed */
2754 	  auto_resize_columns (clist);
2755 
2756 	  row = g_list_position (clist->row_list, (GList *)node);
2757 	  if (row < clist->focus_row)
2758 	    clist->focus_row -= tmp;
2759 	  clist->rows -= tmp;
2760 	  CLIST_REFRESH (clist);
2761 	}
2762     }
2763   else if (visible && clist->column[ctree->tree_column].auto_resize &&
2764 	   !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2765     /* resize tree_column if needed */
2766     column_auto_resize (clist, &GTK_CTREE_ROW (node)->row, ctree->tree_column,
2767 			requisition.width);
2768 
2769 }
2770 
2771 static void
column_auto_resize(GtkCList * clist,GtkCListRow * clist_row,gint column,gint old_width)2772 column_auto_resize (GtkCList    *clist,
2773 		    GtkCListRow *clist_row,
2774 		    gint         column,
2775 		    gint         old_width)
2776 {
2777   /* resize column if needed for auto_resize */
2778   GtkRequisition requisition;
2779 
2780   if (!clist->column[column].auto_resize ||
2781       GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2782     return;
2783 
2784   if (clist_row)
2785     GTK_CLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2786 						   column, &requisition);
2787   else
2788     requisition.width = 0;
2789 
2790   if (requisition.width > clist->column[column].width)
2791     gtk_clist_set_column_width (clist, column, requisition.width);
2792   else if (requisition.width < old_width &&
2793 	   old_width == clist->column[column].width)
2794     {
2795       GList *list;
2796       gint new_width;
2797 
2798       /* run a "gtk_clist_optimal_column_width" but break, if
2799        * the column doesn't shrink */
2800       if (GTK_CLIST_SHOW_TITLES (clist) && clist->column[column].button)
2801 	new_width = (clist->column[column].button->requisition.width -
2802 		     (CELL_SPACING + (2 * COLUMN_INSET)));
2803       else
2804 	new_width = 0;
2805 
2806       for (list = clist->row_list; list; list = list->next)
2807 	{
2808 	  GTK_CLIST_GET_CLASS (clist)->cell_size_request
2809 	    (clist, GTK_CLIST_ROW (list), column, &requisition);
2810 	  new_width = MAX (new_width, requisition.width);
2811 	  if (new_width == clist->column[column].width)
2812 	    break;
2813 	}
2814       if (new_width < clist->column[column].width)
2815 	gtk_clist_set_column_width (clist, column, new_width);
2816     }
2817 }
2818 
2819 static void
auto_resize_columns(GtkCList * clist)2820 auto_resize_columns (GtkCList *clist)
2821 {
2822   gint i;
2823 
2824   if (GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2825     return;
2826 
2827   for (i = 0; i < clist->columns; i++)
2828     column_auto_resize (clist, NULL, i, clist->column[i].width);
2829 }
2830 
2831 static void
cell_size_request(GtkCList * clist,GtkCListRow * clist_row,gint column,GtkRequisition * requisition)2832 cell_size_request (GtkCList       *clist,
2833 		   GtkCListRow    *clist_row,
2834 		   gint            column,
2835 		   GtkRequisition *requisition)
2836 {
2837   GtkCTree *ctree;
2838   gint width;
2839   gint height;
2840   PangoLayout *layout;
2841   PangoRectangle logical_rect;
2842 
2843   g_return_if_fail (GTK_IS_CTREE (clist));
2844   g_return_if_fail (requisition != NULL);
2845 
2846   ctree = GTK_CTREE (clist);
2847 
2848   layout = _gtk_clist_create_cell_layout (clist, clist_row, column);
2849   if (layout)
2850     {
2851       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
2852 
2853       requisition->width = logical_rect.width;
2854       requisition->height = logical_rect.height;
2855 
2856       g_object_unref (G_OBJECT (layout));
2857     }
2858   else
2859     {
2860       requisition->width  = 0;
2861       requisition->height = 0;
2862     }
2863 
2864   switch (clist_row->cell[column].type)
2865     {
2866     case GTK_CELL_PIXTEXT:
2867       if (GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap)
2868 	{
2869 	  gdk_drawable_get_size (GTK_CELL_PIXTEXT
2870                                  (clist_row->cell[column])->pixmap,
2871                                  &width, &height);
2872 	  width += GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing;
2873 	}
2874       else
2875 	width = height = 0;
2876 
2877       requisition->width += width;
2878       requisition->height = MAX (requisition->height, height);
2879 
2880       if (column == ctree->tree_column)
2881 	{
2882 	  requisition->width += (ctree->tree_spacing + ctree->tree_indent *
2883 				 (((GtkCTreeRow *) clist_row)->level - 1));
2884 	  switch (ctree->expander_style)
2885 	    {
2886 	    case GTK_CTREE_EXPANDER_NONE:
2887 	      break;
2888 	    case GTK_CTREE_EXPANDER_TRIANGLE:
2889 	      requisition->width += PM_SIZE + 3;
2890 	      break;
2891 	    case GTK_CTREE_EXPANDER_SQUARE:
2892 	    case GTK_CTREE_EXPANDER_CIRCULAR:
2893 	      requisition->width += PM_SIZE + 1;
2894 	      break;
2895 	    }
2896 	  if (ctree->line_style == GTK_CTREE_LINES_TABBED)
2897 	    requisition->width += 3;
2898 	}
2899       break;
2900     case GTK_CELL_PIXMAP:
2901       gdk_drawable_get_size (GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap,
2902                              &width, &height);
2903       requisition->width += width;
2904       requisition->height = MAX (requisition->height, height);
2905       break;
2906     default:
2907       break;
2908     }
2909 
2910   requisition->width  += clist_row->cell[column].horizontal;
2911   requisition->height += clist_row->cell[column].vertical;
2912 }
2913 
2914 static void
set_cell_contents(GtkCList * clist,GtkCListRow * clist_row,gint column,GtkCellType type,const gchar * text,guint8 spacing,GdkPixmap * pixmap,GdkBitmap * mask)2915 set_cell_contents (GtkCList    *clist,
2916 		   GtkCListRow *clist_row,
2917 		   gint         column,
2918 		   GtkCellType  type,
2919 		   const gchar *text,
2920 		   guint8       spacing,
2921 		   GdkPixmap   *pixmap,
2922 		   GdkBitmap   *mask)
2923 {
2924   gboolean visible = FALSE;
2925   GtkCTree *ctree;
2926   GtkRequisition requisition;
2927   gchar *old_text = NULL;
2928   GdkPixmap *old_pixmap = NULL;
2929   GdkBitmap *old_mask = NULL;
2930 
2931   g_return_if_fail (GTK_IS_CTREE (clist));
2932   g_return_if_fail (clist_row != NULL);
2933 
2934   ctree = GTK_CTREE (clist);
2935 
2936   if (clist->column[column].auto_resize &&
2937       !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
2938     {
2939       GtkCTreeNode *parent;
2940 
2941       parent = ((GtkCTreeRow *)clist_row)->parent;
2942       if (!parent || (parent && GTK_CTREE_ROW (parent)->expanded &&
2943 		      gtk_ctree_is_viewable (ctree, parent)))
2944 	{
2945 	  visible = TRUE;
2946 	  GTK_CLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row,
2947 							 column, &requisition);
2948 	}
2949     }
2950 
2951   switch (clist_row->cell[column].type)
2952     {
2953     case GTK_CELL_EMPTY:
2954       break;
2955     case GTK_CELL_TEXT:
2956       old_text = GTK_CELL_TEXT (clist_row->cell[column])->text;
2957       break;
2958     case GTK_CELL_PIXMAP:
2959       old_pixmap = GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap;
2960       old_mask = GTK_CELL_PIXMAP (clist_row->cell[column])->mask;
2961       break;
2962     case GTK_CELL_PIXTEXT:
2963       old_text = GTK_CELL_PIXTEXT (clist_row->cell[column])->text;
2964       old_pixmap = GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap;
2965       old_mask = GTK_CELL_PIXTEXT (clist_row->cell[column])->mask;
2966       break;
2967     case GTK_CELL_WIDGET:
2968       /* unimplemented */
2969       break;
2970 
2971     default:
2972       break;
2973     }
2974 
2975   clist_row->cell[column].type = GTK_CELL_EMPTY;
2976   if (column == ctree->tree_column && type != GTK_CELL_EMPTY)
2977     type = GTK_CELL_PIXTEXT;
2978 
2979   /* Note that pixmap and mask were already ref'ed by the caller
2980    */
2981   switch (type)
2982     {
2983     case GTK_CELL_TEXT:
2984       if (text)
2985 	{
2986 	  clist_row->cell[column].type = GTK_CELL_TEXT;
2987 	  GTK_CELL_TEXT (clist_row->cell[column])->text = g_strdup (text);
2988 	}
2989       break;
2990     case GTK_CELL_PIXMAP:
2991       if (pixmap)
2992 	{
2993 	  clist_row->cell[column].type = GTK_CELL_PIXMAP;
2994 	  GTK_CELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap;
2995 	  /* We set the mask even if it is NULL */
2996 	  GTK_CELL_PIXMAP (clist_row->cell[column])->mask = mask;
2997 	}
2998       break;
2999     case GTK_CELL_PIXTEXT:
3000       if (column == ctree->tree_column)
3001 	{
3002 	  clist_row->cell[column].type = GTK_CELL_PIXTEXT;
3003 	  GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
3004 	  if (text)
3005 	    GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
3006 	  else
3007 	    GTK_CELL_PIXTEXT (clist_row->cell[column])->text = NULL;
3008 	  if (pixmap)
3009 	    {
3010 	      GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
3011 	      GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
3012 	    }
3013 	  else
3014 	    {
3015 	      GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = NULL;
3016 	      GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = NULL;
3017 	    }
3018 	}
3019       else if (text && pixmap)
3020 	{
3021 	  clist_row->cell[column].type = GTK_CELL_PIXTEXT;
3022 	  GTK_CELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text);
3023 	  GTK_CELL_PIXTEXT (clist_row->cell[column])->spacing = spacing;
3024 	  GTK_CELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap;
3025 	  GTK_CELL_PIXTEXT (clist_row->cell[column])->mask = mask;
3026 	}
3027       break;
3028     default:
3029       break;
3030     }
3031 
3032   if (visible && clist->column[column].auto_resize &&
3033       !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
3034     column_auto_resize (clist, clist_row, column, requisition.width);
3035 
3036   g_free (old_text);
3037   if (old_pixmap)
3038     g_object_unref (old_pixmap);
3039   if (old_mask)
3040     g_object_unref (old_mask);
3041 }
3042 
3043 static void
set_node_info(GtkCTree * ctree,GtkCTreeNode * node,const gchar * text,guint8 spacing,GdkPixmap * pixmap_closed,GdkBitmap * mask_closed,GdkPixmap * pixmap_opened,GdkBitmap * mask_opened,gboolean is_leaf,gboolean expanded)3044 set_node_info (GtkCTree     *ctree,
3045 	       GtkCTreeNode *node,
3046 	       const gchar  *text,
3047 	       guint8        spacing,
3048 	       GdkPixmap    *pixmap_closed,
3049 	       GdkBitmap    *mask_closed,
3050 	       GdkPixmap    *pixmap_opened,
3051 	       GdkBitmap    *mask_opened,
3052 	       gboolean      is_leaf,
3053 	       gboolean      expanded)
3054 {
3055   if (GTK_CTREE_ROW (node)->pixmap_opened)
3056     {
3057       g_object_unref (GTK_CTREE_ROW (node)->pixmap_opened);
3058       if (GTK_CTREE_ROW (node)->mask_opened)
3059 	g_object_unref (GTK_CTREE_ROW (node)->mask_opened);
3060     }
3061   if (GTK_CTREE_ROW (node)->pixmap_closed)
3062     {
3063       g_object_unref (GTK_CTREE_ROW (node)->pixmap_closed);
3064       if (GTK_CTREE_ROW (node)->mask_closed)
3065 	g_object_unref (GTK_CTREE_ROW (node)->mask_closed);
3066     }
3067 
3068   GTK_CTREE_ROW (node)->pixmap_opened = NULL;
3069   GTK_CTREE_ROW (node)->mask_opened   = NULL;
3070   GTK_CTREE_ROW (node)->pixmap_closed = NULL;
3071   GTK_CTREE_ROW (node)->mask_closed   = NULL;
3072 
3073   if (pixmap_closed)
3074     {
3075       GTK_CTREE_ROW (node)->pixmap_closed = g_object_ref (pixmap_closed);
3076       if (mask_closed)
3077 	GTK_CTREE_ROW (node)->mask_closed = g_object_ref (mask_closed);
3078     }
3079   if (pixmap_opened)
3080     {
3081       GTK_CTREE_ROW (node)->pixmap_opened = g_object_ref (pixmap_opened);
3082       if (mask_opened)
3083 	GTK_CTREE_ROW (node)->mask_opened = g_object_ref (mask_opened);
3084     }
3085 
3086   GTK_CTREE_ROW (node)->is_leaf  = is_leaf;
3087   GTK_CTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
3088 
3089   if (GTK_CTREE_ROW (node)->expanded)
3090     gtk_ctree_node_set_pixtext (ctree, node, ctree->tree_column,
3091 				text, spacing, pixmap_opened, mask_opened);
3092   else
3093     gtk_ctree_node_set_pixtext (ctree, node, ctree->tree_column,
3094 				text, spacing, pixmap_closed, mask_closed);
3095 }
3096 
3097 static void
tree_delete(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)3098 tree_delete (GtkCTree     *ctree,
3099 	     GtkCTreeNode *node,
3100 	     gpointer      data)
3101 {
3102   tree_unselect (ctree,  node, NULL);
3103   row_delete (ctree, GTK_CTREE_ROW (node));
3104   g_list_free_1 ((GList *)node);
3105 }
3106 
3107 static void
tree_delete_row(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)3108 tree_delete_row (GtkCTree     *ctree,
3109 		 GtkCTreeNode *node,
3110 		 gpointer      data)
3111 {
3112   row_delete (ctree, GTK_CTREE_ROW (node));
3113   g_list_free_1 ((GList *)node);
3114 }
3115 
3116 static void
tree_update_level(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)3117 tree_update_level (GtkCTree     *ctree,
3118 		   GtkCTreeNode *node,
3119 		   gpointer      data)
3120 {
3121   if (!node)
3122     return;
3123 
3124   if (GTK_CTREE_ROW (node)->parent)
3125       GTK_CTREE_ROW (node)->level =
3126 	GTK_CTREE_ROW (GTK_CTREE_ROW (node)->parent)->level + 1;
3127   else
3128       GTK_CTREE_ROW (node)->level = 1;
3129 }
3130 
3131 static void
tree_select(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)3132 tree_select (GtkCTree     *ctree,
3133 	     GtkCTreeNode *node,
3134 	     gpointer      data)
3135 {
3136   if (node && GTK_CTREE_ROW (node)->row.state != GTK_STATE_SELECTED &&
3137       GTK_CTREE_ROW (node)->row.selectable)
3138     gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW],
3139 		     node, -1);
3140 }
3141 
3142 static void
tree_unselect(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)3143 tree_unselect (GtkCTree     *ctree,
3144 	       GtkCTreeNode *node,
3145 	       gpointer      data)
3146 {
3147   if (node && GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
3148     gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW],
3149 		     node, -1);
3150 }
3151 
3152 static void
tree_expand(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)3153 tree_expand (GtkCTree     *ctree,
3154 	     GtkCTreeNode *node,
3155 	     gpointer      data)
3156 {
3157   if (node && !GTK_CTREE_ROW (node)->expanded)
3158     gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_EXPAND], node);
3159 }
3160 
3161 static void
tree_collapse(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)3162 tree_collapse (GtkCTree     *ctree,
3163 	       GtkCTreeNode *node,
3164 	       gpointer      data)
3165 {
3166   if (node && GTK_CTREE_ROW (node)->expanded)
3167     gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], node);
3168 }
3169 
3170 static void
tree_collapse_to_depth(GtkCTree * ctree,GtkCTreeNode * node,gint depth)3171 tree_collapse_to_depth (GtkCTree     *ctree,
3172 			GtkCTreeNode *node,
3173 			gint          depth)
3174 {
3175   if (node && GTK_CTREE_ROW (node)->level == depth)
3176     gtk_ctree_collapse_recursive (ctree, node);
3177 }
3178 
3179 static void
tree_toggle_expansion(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)3180 tree_toggle_expansion (GtkCTree     *ctree,
3181 		       GtkCTreeNode *node,
3182 		       gpointer      data)
3183 {
3184   if (!node)
3185     return;
3186 
3187   if (GTK_CTREE_ROW (node)->expanded)
3188     gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], node);
3189   else
3190     gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_EXPAND], node);
3191 }
3192 
3193 static GtkCTreeRow *
row_new(GtkCTree * ctree)3194 row_new (GtkCTree *ctree)
3195 {
3196   GtkCList *clist;
3197   GtkCTreeRow *ctree_row;
3198   int i;
3199 
3200   clist = GTK_CLIST (ctree);
3201   ctree_row = g_slice_new (GtkCTreeRow);
3202   ctree_row->row.cell = g_slice_alloc (sizeof (GtkCell) * clist->columns);
3203 
3204   for (i = 0; i < clist->columns; i++)
3205     {
3206       ctree_row->row.cell[i].type = GTK_CELL_EMPTY;
3207       ctree_row->row.cell[i].vertical = 0;
3208       ctree_row->row.cell[i].horizontal = 0;
3209       ctree_row->row.cell[i].style = NULL;
3210     }
3211 
3212   GTK_CELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL;
3213 
3214   ctree_row->row.fg_set     = FALSE;
3215   ctree_row->row.bg_set     = FALSE;
3216   ctree_row->row.style      = NULL;
3217   ctree_row->row.selectable = TRUE;
3218   ctree_row->row.state      = GTK_STATE_NORMAL;
3219   ctree_row->row.data       = NULL;
3220   ctree_row->row.destroy    = NULL;
3221 
3222   ctree_row->level         = 0;
3223   ctree_row->expanded      = FALSE;
3224   ctree_row->parent        = NULL;
3225   ctree_row->sibling       = NULL;
3226   ctree_row->children      = NULL;
3227   ctree_row->pixmap_closed = NULL;
3228   ctree_row->mask_closed   = NULL;
3229   ctree_row->pixmap_opened = NULL;
3230   ctree_row->mask_opened   = NULL;
3231 
3232   return ctree_row;
3233 }
3234 
3235 static void
row_delete(GtkCTree * ctree,GtkCTreeRow * ctree_row)3236 row_delete (GtkCTree    *ctree,
3237 	    GtkCTreeRow *ctree_row)
3238 {
3239   GtkCList *clist;
3240   gint i;
3241 
3242   clist = GTK_CLIST (ctree);
3243 
3244   for (i = 0; i < clist->columns; i++)
3245     {
3246       GTK_CLIST_GET_CLASS (clist)->set_cell_contents
3247 	(clist, &(ctree_row->row), i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL);
3248       if (ctree_row->row.cell[i].style)
3249 	{
3250 	  if (gtk_widget_get_realized (GTK_WIDGET (ctree)))
3251 	    gtk_style_detach (ctree_row->row.cell[i].style);
3252 	  g_object_unref (ctree_row->row.cell[i].style);
3253 	}
3254     }
3255 
3256   if (ctree_row->row.style)
3257     {
3258       if (gtk_widget_get_realized (GTK_WIDGET (ctree)))
3259 	gtk_style_detach (ctree_row->row.style);
3260       g_object_unref (ctree_row->row.style);
3261     }
3262 
3263   if (ctree_row->pixmap_closed)
3264     {
3265       g_object_unref (ctree_row->pixmap_closed);
3266       if (ctree_row->mask_closed)
3267 	g_object_unref (ctree_row->mask_closed);
3268     }
3269 
3270   if (ctree_row->pixmap_opened)
3271     {
3272       g_object_unref (ctree_row->pixmap_opened);
3273       if (ctree_row->mask_opened)
3274 	g_object_unref (ctree_row->mask_opened);
3275     }
3276 
3277   if (ctree_row->row.destroy)
3278     {
3279       GDestroyNotify dnotify = ctree_row->row.destroy;
3280       gpointer ddata = ctree_row->row.data;
3281 
3282       ctree_row->row.destroy = NULL;
3283       ctree_row->row.data = NULL;
3284 
3285       dnotify (ddata);
3286     }
3287 
3288   g_slice_free1 (sizeof (GtkCell) * clist->columns, ctree_row->row.cell);
3289   g_slice_free (GtkCTreeRow, ctree_row);
3290 }
3291 
3292 static void
real_select_row(GtkCList * clist,gint row,gint column,GdkEvent * event)3293 real_select_row (GtkCList *clist,
3294 		 gint      row,
3295 		 gint      column,
3296 		 GdkEvent *event)
3297 {
3298   GList *node;
3299 
3300   g_return_if_fail (GTK_IS_CTREE (clist));
3301 
3302   if ((node = g_list_nth (clist->row_list, row)) &&
3303       GTK_CTREE_ROW (node)->row.selectable)
3304     gtk_signal_emit (GTK_OBJECT (clist), ctree_signals[TREE_SELECT_ROW],
3305 		     node, column);
3306 }
3307 
3308 static void
real_unselect_row(GtkCList * clist,gint row,gint column,GdkEvent * event)3309 real_unselect_row (GtkCList *clist,
3310 		   gint      row,
3311 		   gint      column,
3312 		   GdkEvent *event)
3313 {
3314   GList *node;
3315 
3316   g_return_if_fail (GTK_IS_CTREE (clist));
3317 
3318   if ((node = g_list_nth (clist->row_list, row)))
3319     gtk_signal_emit (GTK_OBJECT (clist), ctree_signals[TREE_UNSELECT_ROW],
3320 		     node, column);
3321 }
3322 
3323 static void
real_tree_select(GtkCTree * ctree,GtkCTreeNode * node,gint column)3324 real_tree_select (GtkCTree     *ctree,
3325 		  GtkCTreeNode *node,
3326 		  gint          column)
3327 {
3328   GtkCList *clist;
3329   GList *list;
3330   GtkCTreeNode *sel_row;
3331   gboolean node_selected;
3332 
3333   g_return_if_fail (GTK_IS_CTREE (ctree));
3334 
3335   if (!node || GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED ||
3336       !GTK_CTREE_ROW (node)->row.selectable)
3337     return;
3338 
3339   clist = GTK_CLIST (ctree);
3340 
3341   switch (clist->selection_mode)
3342     {
3343     case GTK_SELECTION_SINGLE:
3344     case GTK_SELECTION_BROWSE:
3345 
3346       node_selected = FALSE;
3347       list = clist->selection;
3348 
3349       while (list)
3350 	{
3351 	  sel_row = list->data;
3352 	  list = list->next;
3353 
3354 	  if (node == sel_row)
3355 	    node_selected = TRUE;
3356 	  else
3357 	    gtk_signal_emit (GTK_OBJECT (ctree),
3358 			     ctree_signals[TREE_UNSELECT_ROW], sel_row, column);
3359 	}
3360 
3361       if (node_selected)
3362 	return;
3363 
3364     default:
3365       break;
3366     }
3367 
3368   GTK_CTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
3369 
3370   if (!clist->selection)
3371     {
3372       clist->selection = g_list_append (clist->selection, node);
3373       clist->selection_end = clist->selection;
3374     }
3375   else
3376     clist->selection_end = g_list_append (clist->selection_end, node)->next;
3377 
3378   tree_draw_node (ctree, node);
3379 }
3380 
3381 static void
real_tree_unselect(GtkCTree * ctree,GtkCTreeNode * node,gint column)3382 real_tree_unselect (GtkCTree     *ctree,
3383 		    GtkCTreeNode *node,
3384 		    gint          column)
3385 {
3386   GtkCList *clist;
3387 
3388   g_return_if_fail (GTK_IS_CTREE (ctree));
3389 
3390   if (!node || GTK_CTREE_ROW (node)->row.state != GTK_STATE_SELECTED)
3391     return;
3392 
3393   clist = GTK_CLIST (ctree);
3394 
3395   if (clist->selection_end && clist->selection_end->data == node)
3396     clist->selection_end = clist->selection_end->prev;
3397 
3398   clist->selection = g_list_remove (clist->selection, node);
3399 
3400   GTK_CTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
3401 
3402   tree_draw_node (ctree, node);
3403 }
3404 
3405 static void
select_row_recursive(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)3406 select_row_recursive (GtkCTree     *ctree,
3407 		      GtkCTreeNode *node,
3408 		      gpointer      data)
3409 {
3410   if (!node || GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED ||
3411       !GTK_CTREE_ROW (node)->row.selectable)
3412     return;
3413 
3414   GTK_CLIST (ctree)->undo_unselection =
3415     g_list_prepend (GTK_CLIST (ctree)->undo_unselection, node);
3416   gtk_ctree_select (ctree, node);
3417 }
3418 
3419 static void
real_select_all(GtkCList * clist)3420 real_select_all (GtkCList *clist)
3421 {
3422   GtkCTree *ctree;
3423   GtkCTreeNode *node;
3424 
3425   g_return_if_fail (GTK_IS_CTREE (clist));
3426 
3427   ctree = GTK_CTREE (clist);
3428 
3429   switch (clist->selection_mode)
3430     {
3431     case GTK_SELECTION_SINGLE:
3432     case GTK_SELECTION_BROWSE:
3433       return;
3434 
3435     case GTK_SELECTION_MULTIPLE:
3436 
3437       gtk_clist_freeze (clist);
3438 
3439       g_list_free (clist->undo_selection);
3440       g_list_free (clist->undo_unselection);
3441       clist->undo_selection = NULL;
3442       clist->undo_unselection = NULL;
3443 
3444       clist->anchor_state = GTK_STATE_SELECTED;
3445       clist->anchor = -1;
3446       clist->drag_pos = -1;
3447       clist->undo_anchor = clist->focus_row;
3448 
3449       for (node = GTK_CTREE_NODE (clist->row_list); node;
3450 	   node = GTK_CTREE_NODE_NEXT (node))
3451 	gtk_ctree_pre_recursive (ctree, node, select_row_recursive, NULL);
3452 
3453       gtk_clist_thaw (clist);
3454       break;
3455 
3456     default:
3457       /* do nothing */
3458       break;
3459     }
3460 }
3461 
3462 static void
real_unselect_all(GtkCList * clist)3463 real_unselect_all (GtkCList *clist)
3464 {
3465   GtkCTree *ctree;
3466   GtkCTreeNode *node;
3467   GList *list;
3468 
3469   g_return_if_fail (GTK_IS_CTREE (clist));
3470 
3471   ctree = GTK_CTREE (clist);
3472 
3473   switch (clist->selection_mode)
3474     {
3475     case GTK_SELECTION_BROWSE:
3476       if (clist->focus_row >= 0)
3477 	{
3478 	  gtk_ctree_select
3479 	    (ctree,
3480 	     GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)));
3481 	  return;
3482 	}
3483       break;
3484 
3485     case GTK_SELECTION_MULTIPLE:
3486       g_list_free (clist->undo_selection);
3487       g_list_free (clist->undo_unselection);
3488       clist->undo_selection = NULL;
3489       clist->undo_unselection = NULL;
3490 
3491       clist->anchor = -1;
3492       clist->drag_pos = -1;
3493       clist->undo_anchor = clist->focus_row;
3494       break;
3495 
3496     default:
3497       break;
3498     }
3499 
3500   list = clist->selection;
3501 
3502   while (list)
3503     {
3504       node = list->data;
3505       list = list->next;
3506       gtk_ctree_unselect (ctree, node);
3507     }
3508 }
3509 
3510 static gboolean
ctree_is_hot_spot(GtkCTree * ctree,GtkCTreeNode * node,gint row,gint x,gint y)3511 ctree_is_hot_spot (GtkCTree     *ctree,
3512 		   GtkCTreeNode *node,
3513 		   gint          row,
3514 		   gint          x,
3515 		   gint          y)
3516 {
3517   GtkCTreeRow *tree_row;
3518   GtkCList *clist;
3519   gint xl;
3520   gint yu;
3521 
3522   g_return_val_if_fail (GTK_IS_CTREE (ctree), FALSE);
3523   g_return_val_if_fail (node != NULL, FALSE);
3524 
3525   clist = GTK_CLIST (ctree);
3526 
3527   if (!clist->column[ctree->tree_column].visible ||
3528       ctree->expander_style == GTK_CTREE_EXPANDER_NONE)
3529     return FALSE;
3530 
3531   tree_row = GTK_CTREE_ROW (node);
3532 
3533   yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height - PM_SIZE) / 2 -
3534 	(clist->row_height - 1) % 2);
3535 
3536   if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
3537     xl = (clist->column[ctree->tree_column].area.x +
3538 	  clist->column[ctree->tree_column].area.width - 1 + clist->hoffset -
3539 	  (tree_row->level - 1) * ctree->tree_indent - PM_SIZE -
3540 	  (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3);
3541   else
3542     xl = (clist->column[ctree->tree_column].area.x + clist->hoffset +
3543 	  (tree_row->level - 1) * ctree->tree_indent +
3544 	  (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3);
3545 
3546   return (x >= xl && x <= xl + PM_SIZE && y >= yu && y <= yu + PM_SIZE);
3547 }
3548 
3549 /***********************************************************
3550  ***********************************************************
3551  ***                  Public interface                   ***
3552  ***********************************************************
3553  ***********************************************************/
3554 
3555 
3556 /***********************************************************
3557  *           Creation, insertion, deletion                 *
3558  ***********************************************************/
3559 
3560 static GObject*
gtk_ctree_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)3561 gtk_ctree_constructor (GType                  type,
3562 		       guint                  n_construct_properties,
3563 		       GObjectConstructParam *construct_properties)
3564 {
3565   GObject *object = G_OBJECT_CLASS (parent_class)->constructor (type,
3566 								n_construct_properties,
3567 								construct_properties);
3568 
3569   return object;
3570 }
3571 
3572 GtkWidget*
gtk_ctree_new_with_titles(gint columns,gint tree_column,gchar * titles[])3573 gtk_ctree_new_with_titles (gint         columns,
3574 			   gint         tree_column,
3575 			   gchar       *titles[])
3576 {
3577   GtkWidget *widget;
3578 
3579   g_return_val_if_fail (columns > 0, NULL);
3580   g_return_val_if_fail (tree_column >= 0 && tree_column < columns, NULL);
3581 
3582   widget = g_object_new (GTK_TYPE_CTREE,
3583 			   "n_columns", columns,
3584 			   "tree_column", tree_column,
3585 			   NULL);
3586   if (titles)
3587     {
3588       GtkCList *clist = GTK_CLIST (widget);
3589       guint i;
3590 
3591       for (i = 0; i < columns; i++)
3592 	gtk_clist_set_column_title (clist, i, titles[i]);
3593       gtk_clist_column_titles_show (clist);
3594     }
3595 
3596   return widget;
3597 }
3598 
3599 GtkWidget *
gtk_ctree_new(gint columns,gint tree_column)3600 gtk_ctree_new (gint columns,
3601 	       gint tree_column)
3602 {
3603   return gtk_ctree_new_with_titles (columns, tree_column, NULL);
3604 }
3605 
3606 static gint
real_insert_row(GtkCList * clist,gint row,gchar * text[])3607 real_insert_row (GtkCList *clist,
3608 		 gint      row,
3609 		 gchar    *text[])
3610 {
3611   GtkCTreeNode *parent = NULL;
3612   GtkCTreeNode *sibling;
3613   GtkCTreeNode *node;
3614 
3615   g_return_val_if_fail (GTK_IS_CTREE (clist), -1);
3616 
3617   sibling = GTK_CTREE_NODE (g_list_nth (clist->row_list, row));
3618   if (sibling)
3619     parent = GTK_CTREE_ROW (sibling)->parent;
3620 
3621   node = gtk_ctree_insert_node (GTK_CTREE (clist), parent, sibling, text, 5,
3622 				NULL, NULL, NULL, NULL, TRUE, FALSE);
3623 
3624   if (GTK_CLIST_AUTO_SORT (clist) || !sibling)
3625     return g_list_position (clist->row_list, (GList *) node);
3626 
3627   return row;
3628 }
3629 
3630 
3631 /**
3632  * gtk_ctree_insert_node:
3633  * @pixmap_closed: (allow-none):
3634  * @mask_closed: (allow-none):
3635  * @pixmap_opened: (allow-none):
3636  * @mask_opened: (allow-none):
3637  */
3638 GtkCTreeNode *
gtk_ctree_insert_node(GtkCTree * ctree,GtkCTreeNode * parent,GtkCTreeNode * sibling,gchar * text[],guint8 spacing,GdkPixmap * pixmap_closed,GdkBitmap * mask_closed,GdkPixmap * pixmap_opened,GdkBitmap * mask_opened,gboolean is_leaf,gboolean expanded)3639 gtk_ctree_insert_node (GtkCTree     *ctree,
3640 		       GtkCTreeNode *parent,
3641 		       GtkCTreeNode *sibling,
3642 		       gchar        *text[],
3643 		       guint8        spacing,
3644 		       GdkPixmap    *pixmap_closed,
3645 		       GdkBitmap    *mask_closed,
3646 		       GdkPixmap    *pixmap_opened,
3647 		       GdkBitmap    *mask_opened,
3648 		       gboolean      is_leaf,
3649 		       gboolean      expanded)
3650 {
3651   GtkCList *clist;
3652   GtkCTreeRow *new_row;
3653   GtkCTreeNode *node;
3654   GList *list;
3655   gint i;
3656 
3657   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
3658   if (sibling)
3659     g_return_val_if_fail (GTK_CTREE_ROW (sibling)->parent == parent, NULL);
3660 
3661   if (parent && GTK_CTREE_ROW (parent)->is_leaf)
3662     return NULL;
3663 
3664   clist = GTK_CLIST (ctree);
3665 
3666   /* create the row */
3667   new_row = row_new (ctree);
3668   list = g_list_alloc ();
3669   list->data = new_row;
3670   node = GTK_CTREE_NODE (list);
3671 
3672   if (text)
3673     for (i = 0; i < clist->columns; i++)
3674       if (text[i] && i != ctree->tree_column)
3675 	GTK_CLIST_GET_CLASS (clist)->set_cell_contents
3676 	  (clist, &(new_row->row), i, GTK_CELL_TEXT, text[i], 0, NULL, NULL);
3677 
3678   set_node_info (ctree, node, text ?
3679 		 text[ctree->tree_column] : NULL, spacing, pixmap_closed,
3680 		 mask_closed, pixmap_opened, mask_opened, is_leaf, expanded);
3681 
3682   /* sorted insertion */
3683   if (GTK_CLIST_AUTO_SORT (clist))
3684     {
3685       if (parent)
3686 	sibling = GTK_CTREE_ROW (parent)->children;
3687       else
3688 	sibling = GTK_CTREE_NODE (clist->row_list);
3689 
3690       while (sibling && clist->compare
3691 	     (clist, GTK_CTREE_ROW (node), GTK_CTREE_ROW (sibling)) > 0)
3692 	sibling = GTK_CTREE_ROW (sibling)->sibling;
3693     }
3694 
3695   gtk_ctree_link (ctree, node, parent, sibling, TRUE);
3696 
3697   if (text && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist) &&
3698       gtk_ctree_is_viewable (ctree, node))
3699     {
3700       for (i = 0; i < clist->columns; i++)
3701 	if (clist->column[i].auto_resize)
3702 	  column_auto_resize (clist, &(new_row->row), i, 0);
3703     }
3704 
3705   if (clist->rows == 1)
3706     {
3707       clist->focus_row = 0;
3708       if (clist->selection_mode == GTK_SELECTION_BROWSE)
3709 	gtk_ctree_select (ctree, node);
3710     }
3711 
3712 
3713   CLIST_REFRESH (clist);
3714 
3715   return node;
3716 }
3717 
3718 GtkCTreeNode *
gtk_ctree_insert_gnode(GtkCTree * ctree,GtkCTreeNode * parent,GtkCTreeNode * sibling,GNode * gnode,GtkCTreeGNodeFunc func,gpointer data)3719 gtk_ctree_insert_gnode (GtkCTree          *ctree,
3720 			GtkCTreeNode      *parent,
3721 			GtkCTreeNode      *sibling,
3722 			GNode             *gnode,
3723 			GtkCTreeGNodeFunc  func,
3724 			gpointer           data)
3725 {
3726   GtkCList *clist;
3727   GtkCTreeNode *cnode = NULL;
3728   GtkCTreeNode *child = NULL;
3729   GtkCTreeNode *new_child;
3730   GList *list;
3731   GNode *work;
3732   guint depth = 1;
3733 
3734   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
3735   g_return_val_if_fail (gnode != NULL, NULL);
3736   g_return_val_if_fail (func != NULL, NULL);
3737   if (sibling)
3738     g_return_val_if_fail (GTK_CTREE_ROW (sibling)->parent == parent, NULL);
3739 
3740   clist = GTK_CLIST (ctree);
3741 
3742   if (parent)
3743     depth = GTK_CTREE_ROW (parent)->level + 1;
3744 
3745   list = g_list_alloc ();
3746   list->data = row_new (ctree);
3747   cnode = GTK_CTREE_NODE (list);
3748 
3749   gtk_clist_freeze (clist);
3750 
3751   set_node_info (ctree, cnode, "", 0, NULL, NULL, NULL, NULL, TRUE, FALSE);
3752 
3753   if (!func (ctree, depth, gnode, cnode, data))
3754     {
3755       tree_delete_row (ctree, cnode, NULL);
3756       gtk_clist_thaw (clist);
3757       return NULL;
3758     }
3759 
3760   if (GTK_CLIST_AUTO_SORT (clist))
3761     {
3762       if (parent)
3763 	sibling = GTK_CTREE_ROW (parent)->children;
3764       else
3765 	sibling = GTK_CTREE_NODE (clist->row_list);
3766 
3767       while (sibling && clist->compare
3768 	     (clist, GTK_CTREE_ROW (cnode), GTK_CTREE_ROW (sibling)) > 0)
3769 	sibling = GTK_CTREE_ROW (sibling)->sibling;
3770     }
3771 
3772   gtk_ctree_link (ctree, cnode, parent, sibling, TRUE);
3773 
3774   for (work = g_node_last_child (gnode); work; work = work->prev)
3775     {
3776       new_child = gtk_ctree_insert_gnode (ctree, cnode, child,
3777 					  work, func, data);
3778       if (new_child)
3779 	child = new_child;
3780     }
3781 
3782   gtk_clist_thaw (clist);
3783 
3784   return cnode;
3785 }
3786 
3787 GNode *
gtk_ctree_export_to_gnode(GtkCTree * ctree,GNode * parent,GNode * sibling,GtkCTreeNode * node,GtkCTreeGNodeFunc func,gpointer data)3788 gtk_ctree_export_to_gnode (GtkCTree          *ctree,
3789 			   GNode             *parent,
3790 			   GNode             *sibling,
3791 			   GtkCTreeNode      *node,
3792 			   GtkCTreeGNodeFunc  func,
3793 			   gpointer           data)
3794 {
3795   GtkCTreeNode *work;
3796   GNode *gnode;
3797   gint depth;
3798 
3799   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
3800   g_return_val_if_fail (node != NULL, NULL);
3801   g_return_val_if_fail (func != NULL, NULL);
3802   if (sibling)
3803     {
3804       g_return_val_if_fail (parent != NULL, NULL);
3805       g_return_val_if_fail (sibling->parent == parent, NULL);
3806     }
3807 
3808   gnode = g_node_new (NULL);
3809   depth = g_node_depth (parent) + 1;
3810 
3811   if (!func (ctree, depth, gnode, node, data))
3812     {
3813       g_node_destroy (gnode);
3814       return NULL;
3815     }
3816 
3817   if (parent)
3818     g_node_insert_before (parent, sibling, gnode);
3819 
3820   if (!GTK_CTREE_ROW (node)->is_leaf)
3821     {
3822       GNode *new_sibling = NULL;
3823 
3824       for (work = GTK_CTREE_ROW (node)->children; work;
3825 	   work = GTK_CTREE_ROW (work)->sibling)
3826 	new_sibling = gtk_ctree_export_to_gnode (ctree, gnode, new_sibling,
3827 						 work, func, data);
3828 
3829       g_node_reverse_children (gnode);
3830     }
3831 
3832   return gnode;
3833 }
3834 
3835 static void
real_remove_row(GtkCList * clist,gint row)3836 real_remove_row (GtkCList *clist,
3837 		 gint      row)
3838 {
3839   GtkCTreeNode *node;
3840 
3841   g_return_if_fail (GTK_IS_CTREE (clist));
3842 
3843   node = GTK_CTREE_NODE (g_list_nth (clist->row_list, row));
3844 
3845   if (node)
3846     gtk_ctree_remove_node (GTK_CTREE (clist), node);
3847 }
3848 
3849 void
gtk_ctree_remove_node(GtkCTree * ctree,GtkCTreeNode * node)3850 gtk_ctree_remove_node (GtkCTree     *ctree,
3851 		       GtkCTreeNode *node)
3852 {
3853   GtkCList *clist;
3854 
3855   g_return_if_fail (GTK_IS_CTREE (ctree));
3856 
3857   clist = GTK_CLIST (ctree);
3858 
3859   gtk_clist_freeze (clist);
3860 
3861   if (node)
3862     {
3863       gtk_ctree_unlink (ctree, node, TRUE);
3864       gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_delete),
3865 				NULL);
3866       if (clist->selection_mode == GTK_SELECTION_BROWSE && !clist->selection &&
3867 	  clist->focus_row >= 0)
3868 	gtk_clist_select_row (clist, clist->focus_row, -1);
3869 
3870       auto_resize_columns (clist);
3871     }
3872   else
3873     gtk_clist_clear (clist);
3874 
3875   gtk_clist_thaw (clist);
3876 }
3877 
3878 static void
real_clear(GtkCList * clist)3879 real_clear (GtkCList *clist)
3880 {
3881   GtkCTree *ctree;
3882   GtkCTreeNode *work;
3883   GtkCTreeNode *ptr;
3884 
3885   g_return_if_fail (GTK_IS_CTREE (clist));
3886 
3887   ctree = GTK_CTREE (clist);
3888 
3889   /* remove all rows */
3890   work = GTK_CTREE_NODE (clist->row_list);
3891   clist->row_list = NULL;
3892   clist->row_list_end = NULL;
3893 
3894   GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED);
3895   while (work)
3896     {
3897       ptr = work;
3898       work = GTK_CTREE_ROW (work)->sibling;
3899       gtk_ctree_post_recursive (ctree, ptr, GTK_CTREE_FUNC (tree_delete_row),
3900 				NULL);
3901     }
3902   GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED);
3903 
3904   parent_class->clear (clist);
3905 }
3906 
3907 
3908 /***********************************************************
3909  *  Generic recursive functions, querying / finding tree   *
3910  *  information                                            *
3911  ***********************************************************/
3912 
3913 
3914 void
gtk_ctree_post_recursive(GtkCTree * ctree,GtkCTreeNode * node,GtkCTreeFunc func,gpointer data)3915 gtk_ctree_post_recursive (GtkCTree     *ctree,
3916 			  GtkCTreeNode *node,
3917 			  GtkCTreeFunc  func,
3918 			  gpointer      data)
3919 {
3920   GtkCTreeNode *work;
3921   GtkCTreeNode *tmp;
3922 
3923   g_return_if_fail (GTK_IS_CTREE (ctree));
3924   g_return_if_fail (func != NULL);
3925 
3926   if (node)
3927     work = GTK_CTREE_ROW (node)->children;
3928   else
3929     work = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
3930 
3931   while (work)
3932     {
3933       tmp = GTK_CTREE_ROW (work)->sibling;
3934       gtk_ctree_post_recursive (ctree, work, func, data);
3935       work = tmp;
3936     }
3937 
3938   if (node)
3939     func (ctree, node, data);
3940 }
3941 
3942 void
gtk_ctree_post_recursive_to_depth(GtkCTree * ctree,GtkCTreeNode * node,gint depth,GtkCTreeFunc func,gpointer data)3943 gtk_ctree_post_recursive_to_depth (GtkCTree     *ctree,
3944 				   GtkCTreeNode *node,
3945 				   gint          depth,
3946 				   GtkCTreeFunc  func,
3947 				   gpointer      data)
3948 {
3949   GtkCTreeNode *work;
3950   GtkCTreeNode *tmp;
3951 
3952   g_return_if_fail (GTK_IS_CTREE (ctree));
3953   g_return_if_fail (func != NULL);
3954 
3955   if (depth < 0)
3956     {
3957       gtk_ctree_post_recursive (ctree, node, func, data);
3958       return;
3959     }
3960 
3961   if (node)
3962     work = GTK_CTREE_ROW (node)->children;
3963   else
3964     work = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
3965 
3966   if (work && GTK_CTREE_ROW (work)->level <= depth)
3967     {
3968       while (work)
3969 	{
3970 	  tmp = GTK_CTREE_ROW (work)->sibling;
3971 	  gtk_ctree_post_recursive_to_depth (ctree, work, depth, func, data);
3972 	  work = tmp;
3973 	}
3974     }
3975 
3976   if (node && GTK_CTREE_ROW (node)->level <= depth)
3977     func (ctree, node, data);
3978 }
3979 
3980 void
gtk_ctree_pre_recursive(GtkCTree * ctree,GtkCTreeNode * node,GtkCTreeFunc func,gpointer data)3981 gtk_ctree_pre_recursive (GtkCTree     *ctree,
3982 			 GtkCTreeNode *node,
3983 			 GtkCTreeFunc  func,
3984 			 gpointer      data)
3985 {
3986   GtkCTreeNode *work;
3987   GtkCTreeNode *tmp;
3988 
3989   g_return_if_fail (GTK_IS_CTREE (ctree));
3990   g_return_if_fail (func != NULL);
3991 
3992   if (node)
3993     {
3994       work = GTK_CTREE_ROW (node)->children;
3995       func (ctree, node, data);
3996     }
3997   else
3998     work = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
3999 
4000   while (work)
4001     {
4002       tmp = GTK_CTREE_ROW (work)->sibling;
4003       gtk_ctree_pre_recursive (ctree, work, func, data);
4004       work = tmp;
4005     }
4006 }
4007 
4008 void
gtk_ctree_pre_recursive_to_depth(GtkCTree * ctree,GtkCTreeNode * node,gint depth,GtkCTreeFunc func,gpointer data)4009 gtk_ctree_pre_recursive_to_depth (GtkCTree     *ctree,
4010 				  GtkCTreeNode *node,
4011 				  gint          depth,
4012 				  GtkCTreeFunc  func,
4013 				  gpointer      data)
4014 {
4015   GtkCTreeNode *work;
4016   GtkCTreeNode *tmp;
4017 
4018   g_return_if_fail (GTK_IS_CTREE (ctree));
4019   g_return_if_fail (func != NULL);
4020 
4021   if (depth < 0)
4022     {
4023       gtk_ctree_pre_recursive (ctree, node, func, data);
4024       return;
4025     }
4026 
4027   if (node)
4028     {
4029       work = GTK_CTREE_ROW (node)->children;
4030       if (GTK_CTREE_ROW (node)->level <= depth)
4031 	func (ctree, node, data);
4032     }
4033   else
4034     work = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
4035 
4036   if (work && GTK_CTREE_ROW (work)->level <= depth)
4037     {
4038       while (work)
4039 	{
4040 	  tmp = GTK_CTREE_ROW (work)->sibling;
4041 	  gtk_ctree_pre_recursive_to_depth (ctree, work, depth, func, data);
4042 	  work = tmp;
4043 	}
4044     }
4045 }
4046 
4047 gboolean
gtk_ctree_is_viewable(GtkCTree * ctree,GtkCTreeNode * node)4048 gtk_ctree_is_viewable (GtkCTree     *ctree,
4049 		       GtkCTreeNode *node)
4050 {
4051   GtkCTreeRow *work;
4052 
4053   g_return_val_if_fail (GTK_IS_CTREE (ctree), FALSE);
4054   g_return_val_if_fail (node != NULL, FALSE);
4055 
4056   work = GTK_CTREE_ROW (node);
4057 
4058   while (work->parent && GTK_CTREE_ROW (work->parent)->expanded)
4059     work = GTK_CTREE_ROW (work->parent);
4060 
4061   if (!work->parent)
4062     return TRUE;
4063 
4064   return FALSE;
4065 }
4066 
4067 GtkCTreeNode *
gtk_ctree_last(GtkCTree * ctree,GtkCTreeNode * node)4068 gtk_ctree_last (GtkCTree     *ctree,
4069 		GtkCTreeNode *node)
4070 {
4071   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
4072 
4073   if (!node)
4074     return NULL;
4075 
4076   while (GTK_CTREE_ROW (node)->sibling)
4077     node = GTK_CTREE_ROW (node)->sibling;
4078 
4079   if (GTK_CTREE_ROW (node)->children)
4080     return gtk_ctree_last (ctree, GTK_CTREE_ROW (node)->children);
4081 
4082   return node;
4083 }
4084 
4085 GtkCTreeNode *
gtk_ctree_find_node_ptr(GtkCTree * ctree,GtkCTreeRow * ctree_row)4086 gtk_ctree_find_node_ptr (GtkCTree    *ctree,
4087 			 GtkCTreeRow *ctree_row)
4088 {
4089   GtkCTreeNode *node;
4090 
4091   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
4092   g_return_val_if_fail (ctree_row != NULL, NULL);
4093 
4094   if (ctree_row->parent)
4095     node = GTK_CTREE_ROW (ctree_row->parent)->children;
4096   else
4097     node = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
4098 
4099   while (GTK_CTREE_ROW (node) != ctree_row)
4100     node = GTK_CTREE_ROW (node)->sibling;
4101 
4102   return node;
4103 }
4104 
4105 GtkCTreeNode *
gtk_ctree_node_nth(GtkCTree * ctree,guint row)4106 gtk_ctree_node_nth (GtkCTree *ctree,
4107 		    guint     row)
4108 {
4109   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
4110 
4111   if ((row >= GTK_CLIST(ctree)->rows))
4112     return NULL;
4113 
4114   return GTK_CTREE_NODE (g_list_nth (GTK_CLIST (ctree)->row_list, row));
4115 }
4116 
4117 gboolean
gtk_ctree_find(GtkCTree * ctree,GtkCTreeNode * node,GtkCTreeNode * child)4118 gtk_ctree_find (GtkCTree     *ctree,
4119 		GtkCTreeNode *node,
4120 		GtkCTreeNode *child)
4121 {
4122   if (!child)
4123     return FALSE;
4124 
4125   if (!node)
4126     node = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
4127 
4128   while (node)
4129     {
4130       if (node == child)
4131 	return TRUE;
4132       if (GTK_CTREE_ROW (node)->children)
4133 	{
4134 	  if (gtk_ctree_find (ctree, GTK_CTREE_ROW (node)->children, child))
4135 	    return TRUE;
4136 	}
4137       node = GTK_CTREE_ROW (node)->sibling;
4138     }
4139   return FALSE;
4140 }
4141 
4142 gboolean
gtk_ctree_is_ancestor(GtkCTree * ctree,GtkCTreeNode * node,GtkCTreeNode * child)4143 gtk_ctree_is_ancestor (GtkCTree     *ctree,
4144 		       GtkCTreeNode *node,
4145 		       GtkCTreeNode *child)
4146 {
4147   g_return_val_if_fail (GTK_IS_CTREE (ctree), FALSE);
4148   g_return_val_if_fail (node != NULL, FALSE);
4149 
4150   if (GTK_CTREE_ROW (node)->children)
4151     return gtk_ctree_find (ctree, GTK_CTREE_ROW (node)->children, child);
4152 
4153   return FALSE;
4154 }
4155 
4156 GtkCTreeNode *
gtk_ctree_find_by_row_data(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)4157 gtk_ctree_find_by_row_data (GtkCTree     *ctree,
4158 			    GtkCTreeNode *node,
4159 			    gpointer      data)
4160 {
4161   GtkCTreeNode *work;
4162 
4163   if (!node)
4164     node = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
4165 
4166   while (node)
4167     {
4168       if (GTK_CTREE_ROW (node)->row.data == data)
4169 	return node;
4170       if (GTK_CTREE_ROW (node)->children &&
4171 	  (work = gtk_ctree_find_by_row_data
4172 	   (ctree, GTK_CTREE_ROW (node)->children, data)))
4173 	return work;
4174       node = GTK_CTREE_ROW (node)->sibling;
4175     }
4176   return NULL;
4177 }
4178 
4179 GList *
gtk_ctree_find_all_by_row_data(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)4180 gtk_ctree_find_all_by_row_data (GtkCTree     *ctree,
4181 				GtkCTreeNode *node,
4182 				gpointer      data)
4183 {
4184   GList *list = NULL;
4185 
4186   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
4187 
4188   /* if node == NULL then look in the whole tree */
4189   if (!node)
4190     node = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
4191 
4192   while (node)
4193     {
4194       if (GTK_CTREE_ROW (node)->row.data == data)
4195         list = g_list_append (list, node);
4196 
4197       if (GTK_CTREE_ROW (node)->children)
4198         {
4199 	  GList *sub_list;
4200 
4201           sub_list = gtk_ctree_find_all_by_row_data (ctree,
4202 						     GTK_CTREE_ROW
4203 						     (node)->children,
4204 						     data);
4205           list = g_list_concat (list, sub_list);
4206         }
4207       node = GTK_CTREE_ROW (node)->sibling;
4208     }
4209   return list;
4210 }
4211 
4212 GtkCTreeNode *
gtk_ctree_find_by_row_data_custom(GtkCTree * ctree,GtkCTreeNode * node,gpointer data,GCompareFunc func)4213 gtk_ctree_find_by_row_data_custom (GtkCTree     *ctree,
4214 				   GtkCTreeNode *node,
4215 				   gpointer      data,
4216 				   GCompareFunc  func)
4217 {
4218   GtkCTreeNode *work;
4219 
4220   g_return_val_if_fail (func != NULL, NULL);
4221 
4222   if (!node)
4223     node = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
4224 
4225   while (node)
4226     {
4227       if (!func (GTK_CTREE_ROW (node)->row.data, data))
4228 	return node;
4229       if (GTK_CTREE_ROW (node)->children &&
4230 	  (work = gtk_ctree_find_by_row_data_custom
4231 	   (ctree, GTK_CTREE_ROW (node)->children, data, func)))
4232 	return work;
4233       node = GTK_CTREE_ROW (node)->sibling;
4234     }
4235   return NULL;
4236 }
4237 
4238 GList *
gtk_ctree_find_all_by_row_data_custom(GtkCTree * ctree,GtkCTreeNode * node,gpointer data,GCompareFunc func)4239 gtk_ctree_find_all_by_row_data_custom (GtkCTree     *ctree,
4240 				       GtkCTreeNode *node,
4241 				       gpointer      data,
4242 				       GCompareFunc  func)
4243 {
4244   GList *list = NULL;
4245 
4246   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
4247   g_return_val_if_fail (func != NULL, NULL);
4248 
4249   /* if node == NULL then look in the whole tree */
4250   if (!node)
4251     node = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list);
4252 
4253   while (node)
4254     {
4255       if (!func (GTK_CTREE_ROW (node)->row.data, data))
4256         list = g_list_append (list, node);
4257 
4258       if (GTK_CTREE_ROW (node)->children)
4259         {
4260 	  GList *sub_list;
4261 
4262           sub_list = gtk_ctree_find_all_by_row_data_custom (ctree,
4263 							    GTK_CTREE_ROW
4264 							    (node)->children,
4265 							    data,
4266 							    func);
4267           list = g_list_concat (list, sub_list);
4268         }
4269       node = GTK_CTREE_ROW (node)->sibling;
4270     }
4271   return list;
4272 }
4273 
4274 gboolean
gtk_ctree_is_hot_spot(GtkCTree * ctree,gint x,gint y)4275 gtk_ctree_is_hot_spot (GtkCTree *ctree,
4276 		       gint      x,
4277 		       gint      y)
4278 {
4279   GtkCTreeNode *node;
4280   gint column;
4281   gint row;
4282 
4283   g_return_val_if_fail (GTK_IS_CTREE (ctree), FALSE);
4284 
4285   if (gtk_clist_get_selection_info (GTK_CLIST (ctree), x, y, &row, &column))
4286     if ((node = GTK_CTREE_NODE(g_list_nth (GTK_CLIST (ctree)->row_list, row))))
4287       return ctree_is_hot_spot (ctree, node, row, x, y);
4288 
4289   return FALSE;
4290 }
4291 
4292 
4293 /***********************************************************
4294  *   Tree signals : move, expand, collapse, (un)select     *
4295  ***********************************************************/
4296 
4297 
4298 /**
4299  * gtk_ctree_move:
4300  * @new_parent: (allow-none):
4301  * @new_sibling: (allow-none):
4302  */
4303 void
gtk_ctree_move(GtkCTree * ctree,GtkCTreeNode * node,GtkCTreeNode * new_parent,GtkCTreeNode * new_sibling)4304 gtk_ctree_move (GtkCTree     *ctree,
4305 		GtkCTreeNode *node,
4306 		GtkCTreeNode *new_parent,
4307 		GtkCTreeNode *new_sibling)
4308 {
4309   g_return_if_fail (GTK_IS_CTREE (ctree));
4310   g_return_if_fail (node != NULL);
4311 
4312   gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_MOVE], node,
4313 		   new_parent, new_sibling);
4314 }
4315 
4316 void
gtk_ctree_expand(GtkCTree * ctree,GtkCTreeNode * node)4317 gtk_ctree_expand (GtkCTree     *ctree,
4318 		  GtkCTreeNode *node)
4319 {
4320   g_return_if_fail (GTK_IS_CTREE (ctree));
4321   g_return_if_fail (node != NULL);
4322 
4323   if (GTK_CTREE_ROW (node)->is_leaf)
4324     return;
4325 
4326   gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_EXPAND], node);
4327 }
4328 
4329 void
gtk_ctree_expand_recursive(GtkCTree * ctree,GtkCTreeNode * node)4330 gtk_ctree_expand_recursive (GtkCTree     *ctree,
4331 			    GtkCTreeNode *node)
4332 {
4333   GtkCList *clist;
4334   gboolean thaw = FALSE;
4335 
4336   g_return_if_fail (GTK_IS_CTREE (ctree));
4337 
4338   clist = GTK_CLIST (ctree);
4339 
4340   if (node && GTK_CTREE_ROW (node)->is_leaf)
4341     return;
4342 
4343   if (CLIST_UNFROZEN (clist) && (!node || gtk_ctree_is_viewable (ctree, node)))
4344     {
4345       gtk_clist_freeze (clist);
4346       thaw = TRUE;
4347     }
4348 
4349   gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_expand), NULL);
4350 
4351   if (thaw)
4352     gtk_clist_thaw (clist);
4353 }
4354 
4355 void
gtk_ctree_expand_to_depth(GtkCTree * ctree,GtkCTreeNode * node,gint depth)4356 gtk_ctree_expand_to_depth (GtkCTree     *ctree,
4357 			   GtkCTreeNode *node,
4358 			   gint          depth)
4359 {
4360   GtkCList *clist;
4361   gboolean thaw = FALSE;
4362 
4363   g_return_if_fail (GTK_IS_CTREE (ctree));
4364 
4365   clist = GTK_CLIST (ctree);
4366 
4367   if (node && GTK_CTREE_ROW (node)->is_leaf)
4368     return;
4369 
4370   if (CLIST_UNFROZEN (clist) && (!node || gtk_ctree_is_viewable (ctree, node)))
4371     {
4372       gtk_clist_freeze (clist);
4373       thaw = TRUE;
4374     }
4375 
4376   gtk_ctree_post_recursive_to_depth (ctree, node, depth,
4377 				     GTK_CTREE_FUNC (tree_expand), NULL);
4378 
4379   if (thaw)
4380     gtk_clist_thaw (clist);
4381 }
4382 
4383 void
gtk_ctree_collapse(GtkCTree * ctree,GtkCTreeNode * node)4384 gtk_ctree_collapse (GtkCTree     *ctree,
4385 		    GtkCTreeNode *node)
4386 {
4387   g_return_if_fail (GTK_IS_CTREE (ctree));
4388   g_return_if_fail (node != NULL);
4389 
4390   if (GTK_CTREE_ROW (node)->is_leaf)
4391     return;
4392 
4393   gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], node);
4394 }
4395 
4396 void
gtk_ctree_collapse_recursive(GtkCTree * ctree,GtkCTreeNode * node)4397 gtk_ctree_collapse_recursive (GtkCTree     *ctree,
4398 			      GtkCTreeNode *node)
4399 {
4400   GtkCList *clist;
4401   gboolean thaw = FALSE;
4402   gint i;
4403 
4404   g_return_if_fail (GTK_IS_CTREE (ctree));
4405 
4406   if (node && GTK_CTREE_ROW (node)->is_leaf)
4407     return;
4408 
4409   clist = GTK_CLIST (ctree);
4410 
4411   if (CLIST_UNFROZEN (clist) && (!node || gtk_ctree_is_viewable (ctree, node)))
4412     {
4413       gtk_clist_freeze (clist);
4414       thaw = TRUE;
4415     }
4416 
4417   GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED);
4418   gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_collapse), NULL);
4419   GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED);
4420   for (i = 0; i < clist->columns; i++)
4421     if (clist->column[i].auto_resize)
4422       gtk_clist_set_column_width (clist, i,
4423 				  gtk_clist_optimal_column_width (clist, i));
4424 
4425   if (thaw)
4426     gtk_clist_thaw (clist);
4427 }
4428 
4429 void
gtk_ctree_collapse_to_depth(GtkCTree * ctree,GtkCTreeNode * node,gint depth)4430 gtk_ctree_collapse_to_depth (GtkCTree     *ctree,
4431 			     GtkCTreeNode *node,
4432 			     gint          depth)
4433 {
4434   GtkCList *clist;
4435   gboolean thaw = FALSE;
4436   gint i;
4437 
4438   g_return_if_fail (GTK_IS_CTREE (ctree));
4439 
4440   if (node && GTK_CTREE_ROW (node)->is_leaf)
4441     return;
4442 
4443   clist = GTK_CLIST (ctree);
4444 
4445   if (CLIST_UNFROZEN (clist) && (!node || gtk_ctree_is_viewable (ctree, node)))
4446     {
4447       gtk_clist_freeze (clist);
4448       thaw = TRUE;
4449     }
4450 
4451   GTK_CLIST_SET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED);
4452   gtk_ctree_post_recursive_to_depth (ctree, node, depth,
4453 				     GTK_CTREE_FUNC (tree_collapse_to_depth),
4454 				     GINT_TO_POINTER (depth));
4455   GTK_CLIST_UNSET_FLAG (clist, CLIST_AUTO_RESIZE_BLOCKED);
4456   for (i = 0; i < clist->columns; i++)
4457     if (clist->column[i].auto_resize)
4458       gtk_clist_set_column_width (clist, i,
4459 				  gtk_clist_optimal_column_width (clist, i));
4460 
4461   if (thaw)
4462     gtk_clist_thaw (clist);
4463 }
4464 
4465 void
gtk_ctree_toggle_expansion(GtkCTree * ctree,GtkCTreeNode * node)4466 gtk_ctree_toggle_expansion (GtkCTree     *ctree,
4467 			    GtkCTreeNode *node)
4468 {
4469   g_return_if_fail (GTK_IS_CTREE (ctree));
4470   g_return_if_fail (node != NULL);
4471 
4472   if (GTK_CTREE_ROW (node)->is_leaf)
4473     return;
4474 
4475   tree_toggle_expansion (ctree, node, NULL);
4476 }
4477 
4478 void
gtk_ctree_toggle_expansion_recursive(GtkCTree * ctree,GtkCTreeNode * node)4479 gtk_ctree_toggle_expansion_recursive (GtkCTree     *ctree,
4480 				      GtkCTreeNode *node)
4481 {
4482   GtkCList *clist;
4483   gboolean thaw = FALSE;
4484 
4485   g_return_if_fail (GTK_IS_CTREE (ctree));
4486 
4487   if (node && GTK_CTREE_ROW (node)->is_leaf)
4488     return;
4489 
4490   clist = GTK_CLIST (ctree);
4491 
4492   if (CLIST_UNFROZEN (clist) && (!node || gtk_ctree_is_viewable (ctree, node)))
4493     {
4494       gtk_clist_freeze (clist);
4495       thaw = TRUE;
4496     }
4497 
4498   gtk_ctree_post_recursive (ctree, node,
4499 			    GTK_CTREE_FUNC (tree_toggle_expansion), NULL);
4500 
4501   if (thaw)
4502     gtk_clist_thaw (clist);
4503 }
4504 
4505 void
gtk_ctree_select(GtkCTree * ctree,GtkCTreeNode * node)4506 gtk_ctree_select (GtkCTree     *ctree,
4507 		  GtkCTreeNode *node)
4508 {
4509   g_return_if_fail (GTK_IS_CTREE (ctree));
4510   g_return_if_fail (node != NULL);
4511 
4512   if (GTK_CTREE_ROW (node)->row.selectable)
4513     gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW],
4514 		     node, -1);
4515 }
4516 
4517 void
gtk_ctree_unselect(GtkCTree * ctree,GtkCTreeNode * node)4518 gtk_ctree_unselect (GtkCTree     *ctree,
4519 		    GtkCTreeNode *node)
4520 {
4521   g_return_if_fail (GTK_IS_CTREE (ctree));
4522   g_return_if_fail (node != NULL);
4523 
4524   gtk_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW],
4525 		   node, -1);
4526 }
4527 
4528 void
gtk_ctree_select_recursive(GtkCTree * ctree,GtkCTreeNode * node)4529 gtk_ctree_select_recursive (GtkCTree     *ctree,
4530 			    GtkCTreeNode *node)
4531 {
4532   gtk_ctree_real_select_recursive (ctree, node, TRUE);
4533 }
4534 
4535 void
gtk_ctree_unselect_recursive(GtkCTree * ctree,GtkCTreeNode * node)4536 gtk_ctree_unselect_recursive (GtkCTree     *ctree,
4537 			      GtkCTreeNode *node)
4538 {
4539   gtk_ctree_real_select_recursive (ctree, node, FALSE);
4540 }
4541 
4542 void
gtk_ctree_real_select_recursive(GtkCTree * ctree,GtkCTreeNode * node,gint state)4543 gtk_ctree_real_select_recursive (GtkCTree     *ctree,
4544 				 GtkCTreeNode *node,
4545 				 gint          state)
4546 {
4547   GtkCList *clist;
4548   gboolean thaw = FALSE;
4549 
4550   g_return_if_fail (GTK_IS_CTREE (ctree));
4551 
4552   clist = GTK_CLIST (ctree);
4553 
4554   if ((state &&
4555        (clist->selection_mode ==  GTK_SELECTION_BROWSE ||
4556 	clist->selection_mode == GTK_SELECTION_SINGLE)) ||
4557       (!state && clist->selection_mode ==  GTK_SELECTION_BROWSE))
4558     return;
4559 
4560   if (CLIST_UNFROZEN (clist) && (!node || gtk_ctree_is_viewable (ctree, node)))
4561     {
4562       gtk_clist_freeze (clist);
4563       thaw = TRUE;
4564     }
4565 
4566   if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
4567     {
4568       GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4569 
4570       g_list_free (clist->undo_selection);
4571       g_list_free (clist->undo_unselection);
4572       clist->undo_selection = NULL;
4573       clist->undo_unselection = NULL;
4574     }
4575 
4576   if (state)
4577     gtk_ctree_post_recursive (ctree, node,
4578 			      GTK_CTREE_FUNC (tree_select), NULL);
4579   else
4580     gtk_ctree_post_recursive (ctree, node,
4581 			      GTK_CTREE_FUNC (tree_unselect), NULL);
4582 
4583   if (thaw)
4584     gtk_clist_thaw (clist);
4585 }
4586 
4587 
4588 /***********************************************************
4589  *           Analogons of GtkCList functions               *
4590  ***********************************************************/
4591 
4592 
4593 void
gtk_ctree_node_set_text(GtkCTree * ctree,GtkCTreeNode * node,gint column,const gchar * text)4594 gtk_ctree_node_set_text (GtkCTree     *ctree,
4595 			 GtkCTreeNode *node,
4596 			 gint          column,
4597 			 const gchar  *text)
4598 {
4599   GtkCList *clist;
4600 
4601   g_return_if_fail (GTK_IS_CTREE (ctree));
4602   g_return_if_fail (node != NULL);
4603 
4604   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4605     return;
4606 
4607   clist = GTK_CLIST (ctree);
4608 
4609   GTK_CLIST_GET_CLASS (clist)->set_cell_contents
4610     (clist, &(GTK_CTREE_ROW (node)->row), column, GTK_CELL_TEXT,
4611      text, 0, NULL, NULL);
4612 
4613   tree_draw_node (ctree, node);
4614 }
4615 
4616 
4617 /**
4618  * gtk_ctree_node_set_pixmap:
4619  * @mask: (allow-none):
4620  */
4621 void
gtk_ctree_node_set_pixmap(GtkCTree * ctree,GtkCTreeNode * node,gint column,GdkPixmap * pixmap,GdkBitmap * mask)4622 gtk_ctree_node_set_pixmap (GtkCTree     *ctree,
4623 			   GtkCTreeNode *node,
4624 			   gint          column,
4625 			   GdkPixmap    *pixmap,
4626 			   GdkBitmap    *mask)
4627 {
4628   GtkCList *clist;
4629 
4630   g_return_if_fail (GTK_IS_CTREE (ctree));
4631   g_return_if_fail (node != NULL);
4632   g_return_if_fail (pixmap != NULL);
4633 
4634   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4635     return;
4636 
4637   g_object_ref (pixmap);
4638   if (mask)
4639     g_object_ref (mask);
4640 
4641   clist = GTK_CLIST (ctree);
4642 
4643   GTK_CLIST_GET_CLASS (clist)->set_cell_contents
4644     (clist, &(GTK_CTREE_ROW (node)->row), column, GTK_CELL_PIXMAP,
4645      NULL, 0, pixmap, mask);
4646 
4647   tree_draw_node (ctree, node);
4648 }
4649 
4650 
4651 /**
4652  * gtk_ctree_node_set_pixtext:
4653  * @mask: (allow-none):
4654  */
4655 void
gtk_ctree_node_set_pixtext(GtkCTree * ctree,GtkCTreeNode * node,gint column,const gchar * text,guint8 spacing,GdkPixmap * pixmap,GdkBitmap * mask)4656 gtk_ctree_node_set_pixtext (GtkCTree     *ctree,
4657 			    GtkCTreeNode *node,
4658 			    gint          column,
4659 			    const gchar  *text,
4660 			    guint8        spacing,
4661 			    GdkPixmap    *pixmap,
4662 			    GdkBitmap    *mask)
4663 {
4664   GtkCList *clist;
4665 
4666   g_return_if_fail (GTK_IS_CTREE (ctree));
4667   g_return_if_fail (node != NULL);
4668   if (column != ctree->tree_column)
4669     g_return_if_fail (pixmap != NULL);
4670   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4671     return;
4672 
4673   clist = GTK_CLIST (ctree);
4674 
4675   if (pixmap)
4676     {
4677       g_object_ref (pixmap);
4678       if (mask)
4679 	g_object_ref (mask);
4680     }
4681 
4682   GTK_CLIST_GET_CLASS (clist)->set_cell_contents
4683     (clist, &(GTK_CTREE_ROW (node)->row), column, GTK_CELL_PIXTEXT,
4684      text, spacing, pixmap, mask);
4685 
4686   tree_draw_node (ctree, node);
4687 }
4688 
4689 
4690 /**
4691  * gtk_ctree_set_node_info:
4692  * @pixmap_closed: (allow-none):
4693  * @mask_closed: (allow-none):
4694  * @pixmap_opened: (allow-none):
4695  * @mask_opened: (allow-none):
4696  */
4697 void
gtk_ctree_set_node_info(GtkCTree * ctree,GtkCTreeNode * node,const gchar * text,guint8 spacing,GdkPixmap * pixmap_closed,GdkBitmap * mask_closed,GdkPixmap * pixmap_opened,GdkBitmap * mask_opened,gboolean is_leaf,gboolean expanded)4698 gtk_ctree_set_node_info (GtkCTree     *ctree,
4699 			 GtkCTreeNode *node,
4700 			 const gchar  *text,
4701 			 guint8        spacing,
4702 			 GdkPixmap    *pixmap_closed,
4703 			 GdkBitmap    *mask_closed,
4704 			 GdkPixmap    *pixmap_opened,
4705 			 GdkBitmap    *mask_opened,
4706 			 gboolean      is_leaf,
4707 			 gboolean      expanded)
4708 {
4709   gboolean old_leaf;
4710   gboolean old_expanded;
4711 
4712   g_return_if_fail (GTK_IS_CTREE (ctree));
4713   g_return_if_fail (node != NULL);
4714 
4715   old_leaf = GTK_CTREE_ROW (node)->is_leaf;
4716   old_expanded = GTK_CTREE_ROW (node)->expanded;
4717 
4718   if (is_leaf && GTK_CTREE_ROW (node)->children)
4719     {
4720       GtkCTreeNode *work;
4721       GtkCTreeNode *ptr;
4722 
4723       work = GTK_CTREE_ROW (node)->children;
4724       while (work)
4725 	{
4726 	  ptr = work;
4727 	  work = GTK_CTREE_ROW (work)->sibling;
4728 	  gtk_ctree_remove_node (ctree, ptr);
4729 	}
4730     }
4731 
4732   set_node_info (ctree, node, text, spacing, pixmap_closed, mask_closed,
4733 		 pixmap_opened, mask_opened, is_leaf, expanded);
4734 
4735   if (!is_leaf && !old_leaf)
4736     {
4737       GTK_CTREE_ROW (node)->expanded = old_expanded;
4738       if (expanded && !old_expanded)
4739 	gtk_ctree_expand (ctree, node);
4740       else if (!expanded && old_expanded)
4741 	gtk_ctree_collapse (ctree, node);
4742     }
4743 
4744   GTK_CTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded;
4745 
4746   tree_draw_node (ctree, node);
4747 }
4748 
4749 void
gtk_ctree_node_set_shift(GtkCTree * ctree,GtkCTreeNode * node,gint column,gint vertical,gint horizontal)4750 gtk_ctree_node_set_shift (GtkCTree     *ctree,
4751 			  GtkCTreeNode *node,
4752 			  gint          column,
4753 			  gint          vertical,
4754 			  gint          horizontal)
4755 {
4756   GtkCList *clist;
4757   GtkRequisition requisition;
4758   gboolean visible = FALSE;
4759 
4760   g_return_if_fail (GTK_IS_CTREE (ctree));
4761   g_return_if_fail (node != NULL);
4762 
4763   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4764     return;
4765 
4766   clist = GTK_CLIST (ctree);
4767 
4768   if (clist->column[column].auto_resize &&
4769       !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
4770     {
4771       visible = gtk_ctree_is_viewable (ctree, node);
4772       if (visible)
4773 	GTK_CLIST_GET_CLASS (clist)->cell_size_request
4774 	  (clist, &GTK_CTREE_ROW (node)->row, column, &requisition);
4775     }
4776 
4777   GTK_CTREE_ROW (node)->row.cell[column].vertical   = vertical;
4778   GTK_CTREE_ROW (node)->row.cell[column].horizontal = horizontal;
4779 
4780   if (visible)
4781     column_auto_resize (clist, &GTK_CTREE_ROW (node)->row,
4782 			column, requisition.width);
4783 
4784   tree_draw_node (ctree, node);
4785 }
4786 
4787 static void
remove_grab(GtkCList * clist)4788 remove_grab (GtkCList *clist)
4789 {
4790   if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (clist))) &&
4791       GTK_WIDGET_HAS_GRAB (clist))
4792     {
4793       gtk_grab_remove (GTK_WIDGET (clist));
4794       gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (clist)),
4795 				  GDK_CURRENT_TIME);
4796     }
4797 
4798   if (clist->htimer)
4799     {
4800       g_source_remove (clist->htimer);
4801       clist->htimer = 0;
4802     }
4803 
4804   if (clist->vtimer)
4805     {
4806       g_source_remove (clist->vtimer);
4807       clist->vtimer = 0;
4808     }
4809 }
4810 
4811 void
gtk_ctree_node_set_selectable(GtkCTree * ctree,GtkCTreeNode * node,gboolean selectable)4812 gtk_ctree_node_set_selectable (GtkCTree     *ctree,
4813 			       GtkCTreeNode *node,
4814 			       gboolean      selectable)
4815 {
4816   g_return_if_fail (GTK_IS_CTREE (ctree));
4817   g_return_if_fail (node != NULL);
4818 
4819   if (selectable == GTK_CTREE_ROW (node)->row.selectable)
4820     return;
4821 
4822   GTK_CTREE_ROW (node)->row.selectable = selectable;
4823 
4824   if (!selectable && GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
4825     {
4826       GtkCList *clist;
4827 
4828       clist = GTK_CLIST (ctree);
4829 
4830       if (clist->anchor >= 0 &&
4831 	  clist->selection_mode == GTK_SELECTION_MULTIPLE)
4832 	{
4833 	  clist->drag_button = 0;
4834 	  remove_grab (clist);
4835 
4836 	  GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
4837 	}
4838       gtk_ctree_unselect (ctree, node);
4839     }
4840 }
4841 
4842 gboolean
gtk_ctree_node_get_selectable(GtkCTree * ctree,GtkCTreeNode * node)4843 gtk_ctree_node_get_selectable (GtkCTree     *ctree,
4844 			       GtkCTreeNode *node)
4845 {
4846   g_return_val_if_fail (node != NULL, FALSE);
4847 
4848   return GTK_CTREE_ROW (node)->row.selectable;
4849 }
4850 
4851 GtkCellType
gtk_ctree_node_get_cell_type(GtkCTree * ctree,GtkCTreeNode * node,gint column)4852 gtk_ctree_node_get_cell_type (GtkCTree     *ctree,
4853 			      GtkCTreeNode *node,
4854 			      gint          column)
4855 {
4856   g_return_val_if_fail (GTK_IS_CTREE (ctree), -1);
4857   g_return_val_if_fail (node != NULL, -1);
4858 
4859   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4860     return -1;
4861 
4862   return GTK_CTREE_ROW (node)->row.cell[column].type;
4863 }
4864 
4865 gboolean
gtk_ctree_node_get_text(GtkCTree * ctree,GtkCTreeNode * node,gint column,gchar ** text)4866 gtk_ctree_node_get_text (GtkCTree      *ctree,
4867 			 GtkCTreeNode  *node,
4868 			 gint           column,
4869 			 gchar        **text)
4870 {
4871   g_return_val_if_fail (GTK_IS_CTREE (ctree), FALSE);
4872   g_return_val_if_fail (node != NULL, FALSE);
4873 
4874   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4875     return FALSE;
4876 
4877   if (GTK_CTREE_ROW (node)->row.cell[column].type != GTK_CELL_TEXT)
4878     return FALSE;
4879 
4880   if (text)
4881     *text = GTK_CELL_TEXT (GTK_CTREE_ROW (node)->row.cell[column])->text;
4882 
4883   return TRUE;
4884 }
4885 
4886 gboolean
gtk_ctree_node_get_pixmap(GtkCTree * ctree,GtkCTreeNode * node,gint column,GdkPixmap ** pixmap,GdkBitmap ** mask)4887 gtk_ctree_node_get_pixmap (GtkCTree     *ctree,
4888 			   GtkCTreeNode *node,
4889 			   gint          column,
4890 			   GdkPixmap   **pixmap,
4891 			   GdkBitmap   **mask)
4892 {
4893   g_return_val_if_fail (GTK_IS_CTREE (ctree), FALSE);
4894   g_return_val_if_fail (node != NULL, FALSE);
4895 
4896   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4897     return FALSE;
4898 
4899   if (GTK_CTREE_ROW (node)->row.cell[column].type != GTK_CELL_PIXMAP)
4900     return FALSE;
4901 
4902   if (pixmap)
4903     *pixmap = GTK_CELL_PIXMAP (GTK_CTREE_ROW (node)->row.cell[column])->pixmap;
4904   if (mask)
4905     *mask = GTK_CELL_PIXMAP (GTK_CTREE_ROW (node)->row.cell[column])->mask;
4906 
4907   return TRUE;
4908 }
4909 
4910 gboolean
gtk_ctree_node_get_pixtext(GtkCTree * ctree,GtkCTreeNode * node,gint column,gchar ** text,guint8 * spacing,GdkPixmap ** pixmap,GdkBitmap ** mask)4911 gtk_ctree_node_get_pixtext (GtkCTree      *ctree,
4912 			    GtkCTreeNode  *node,
4913 			    gint           column,
4914 			    gchar        **text,
4915 			    guint8        *spacing,
4916 			    GdkPixmap    **pixmap,
4917 			    GdkBitmap    **mask)
4918 {
4919   g_return_val_if_fail (GTK_IS_CTREE (ctree), FALSE);
4920   g_return_val_if_fail (node != NULL, FALSE);
4921 
4922   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
4923     return FALSE;
4924 
4925   if (GTK_CTREE_ROW (node)->row.cell[column].type != GTK_CELL_PIXTEXT)
4926     return FALSE;
4927 
4928   if (text)
4929     *text = GTK_CELL_PIXTEXT (GTK_CTREE_ROW (node)->row.cell[column])->text;
4930   if (spacing)
4931     *spacing = GTK_CELL_PIXTEXT (GTK_CTREE_ROW
4932 				 (node)->row.cell[column])->spacing;
4933   if (pixmap)
4934     *pixmap = GTK_CELL_PIXTEXT (GTK_CTREE_ROW
4935 				(node)->row.cell[column])->pixmap;
4936   if (mask)
4937     *mask = GTK_CELL_PIXTEXT (GTK_CTREE_ROW (node)->row.cell[column])->mask;
4938 
4939   return TRUE;
4940 }
4941 
4942 gboolean
gtk_ctree_get_node_info(GtkCTree * ctree,GtkCTreeNode * node,gchar ** text,guint8 * spacing,GdkPixmap ** pixmap_closed,GdkBitmap ** mask_closed,GdkPixmap ** pixmap_opened,GdkBitmap ** mask_opened,gboolean * is_leaf,gboolean * expanded)4943 gtk_ctree_get_node_info (GtkCTree      *ctree,
4944 			 GtkCTreeNode  *node,
4945 			 gchar        **text,
4946 			 guint8        *spacing,
4947 			 GdkPixmap    **pixmap_closed,
4948 			 GdkBitmap    **mask_closed,
4949 			 GdkPixmap    **pixmap_opened,
4950 			 GdkBitmap    **mask_opened,
4951 			 gboolean      *is_leaf,
4952 			 gboolean      *expanded)
4953 {
4954   g_return_val_if_fail (GTK_IS_CTREE (ctree), FALSE);
4955   g_return_val_if_fail (node != NULL, FALSE);
4956 
4957   if (text)
4958     *text = GTK_CELL_PIXTEXT
4959       (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->text;
4960   if (spacing)
4961     *spacing = GTK_CELL_PIXTEXT
4962       (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->spacing;
4963   if (pixmap_closed)
4964     *pixmap_closed = GTK_CTREE_ROW (node)->pixmap_closed;
4965   if (mask_closed)
4966     *mask_closed = GTK_CTREE_ROW (node)->mask_closed;
4967   if (pixmap_opened)
4968     *pixmap_opened = GTK_CTREE_ROW (node)->pixmap_opened;
4969   if (mask_opened)
4970     *mask_opened = GTK_CTREE_ROW (node)->mask_opened;
4971   if (is_leaf)
4972     *is_leaf = GTK_CTREE_ROW (node)->is_leaf;
4973   if (expanded)
4974     *expanded = GTK_CTREE_ROW (node)->expanded;
4975 
4976   return TRUE;
4977 }
4978 
4979 void
gtk_ctree_node_set_cell_style(GtkCTree * ctree,GtkCTreeNode * node,gint column,GtkStyle * style)4980 gtk_ctree_node_set_cell_style (GtkCTree     *ctree,
4981 			       GtkCTreeNode *node,
4982 			       gint          column,
4983 			       GtkStyle     *style)
4984 {
4985   GtkCList *clist;
4986   GtkRequisition requisition;
4987   gboolean visible = FALSE;
4988 
4989   g_return_if_fail (GTK_IS_CTREE (ctree));
4990   g_return_if_fail (node != NULL);
4991 
4992   clist = GTK_CLIST (ctree);
4993 
4994   if (column < 0 || column >= clist->columns)
4995     return;
4996 
4997   if (GTK_CTREE_ROW (node)->row.cell[column].style == style)
4998     return;
4999 
5000   if (clist->column[column].auto_resize &&
5001       !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
5002     {
5003       visible = gtk_ctree_is_viewable (ctree, node);
5004       if (visible)
5005 	GTK_CLIST_GET_CLASS (clist)->cell_size_request
5006 	  (clist, &GTK_CTREE_ROW (node)->row, column, &requisition);
5007     }
5008 
5009   if (GTK_CTREE_ROW (node)->row.cell[column].style)
5010     {
5011       if (gtk_widget_get_realized (GTK_WIDGET (ctree)))
5012         gtk_style_detach (GTK_CTREE_ROW (node)->row.cell[column].style);
5013       g_object_unref (GTK_CTREE_ROW (node)->row.cell[column].style);
5014     }
5015 
5016   GTK_CTREE_ROW (node)->row.cell[column].style = style;
5017 
5018   if (GTK_CTREE_ROW (node)->row.cell[column].style)
5019     {
5020       g_object_ref (GTK_CTREE_ROW (node)->row.cell[column].style);
5021 
5022       if (gtk_widget_get_realized (GTK_WIDGET (ctree)))
5023         GTK_CTREE_ROW (node)->row.cell[column].style =
5024 	  gtk_style_attach (GTK_CTREE_ROW (node)->row.cell[column].style,
5025 			    clist->clist_window);
5026     }
5027 
5028   if (visible)
5029     column_auto_resize (clist, &GTK_CTREE_ROW (node)->row, column,
5030 			requisition.width);
5031 
5032   tree_draw_node (ctree, node);
5033 }
5034 
5035 GtkStyle *
gtk_ctree_node_get_cell_style(GtkCTree * ctree,GtkCTreeNode * node,gint column)5036 gtk_ctree_node_get_cell_style (GtkCTree     *ctree,
5037 			       GtkCTreeNode *node,
5038 			       gint          column)
5039 {
5040   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
5041   g_return_val_if_fail (node != NULL, NULL);
5042 
5043   if (column < 0 || column >= GTK_CLIST (ctree)->columns)
5044     return NULL;
5045 
5046   return GTK_CTREE_ROW (node)->row.cell[column].style;
5047 }
5048 
5049 void
gtk_ctree_node_set_row_style(GtkCTree * ctree,GtkCTreeNode * node,GtkStyle * style)5050 gtk_ctree_node_set_row_style (GtkCTree     *ctree,
5051 			      GtkCTreeNode *node,
5052 			      GtkStyle     *style)
5053 {
5054   GtkCList *clist;
5055   GtkRequisition requisition;
5056   gboolean visible;
5057   gint *old_width = NULL;
5058   gint i;
5059 
5060   g_return_if_fail (GTK_IS_CTREE (ctree));
5061   g_return_if_fail (node != NULL);
5062 
5063   clist = GTK_CLIST (ctree);
5064 
5065   if (GTK_CTREE_ROW (node)->row.style == style)
5066     return;
5067 
5068   visible = gtk_ctree_is_viewable (ctree, node);
5069   if (visible && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
5070     {
5071       old_width = g_new (gint, clist->columns);
5072       for (i = 0; i < clist->columns; i++)
5073 	if (clist->column[i].auto_resize)
5074 	  {
5075 	    GTK_CLIST_GET_CLASS (clist)->cell_size_request
5076 	      (clist, &GTK_CTREE_ROW (node)->row, i, &requisition);
5077 	    old_width[i] = requisition.width;
5078 	  }
5079     }
5080 
5081   if (GTK_CTREE_ROW (node)->row.style)
5082     {
5083       if (gtk_widget_get_realized (GTK_WIDGET (ctree)))
5084         gtk_style_detach (GTK_CTREE_ROW (node)->row.style);
5085       g_object_unref (GTK_CTREE_ROW (node)->row.style);
5086     }
5087 
5088   GTK_CTREE_ROW (node)->row.style = style;
5089 
5090   if (GTK_CTREE_ROW (node)->row.style)
5091     {
5092       g_object_ref (GTK_CTREE_ROW (node)->row.style);
5093 
5094       if (gtk_widget_get_realized (GTK_WIDGET (ctree)))
5095         GTK_CTREE_ROW (node)->row.style =
5096 	  gtk_style_attach (GTK_CTREE_ROW (node)->row.style,
5097 			    clist->clist_window);
5098     }
5099 
5100   if (visible && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
5101     {
5102       for (i = 0; i < clist->columns; i++)
5103 	if (clist->column[i].auto_resize)
5104 	  column_auto_resize (clist, &GTK_CTREE_ROW (node)->row, i,
5105 			      old_width[i]);
5106       g_free (old_width);
5107     }
5108   tree_draw_node (ctree, node);
5109 }
5110 
5111 GtkStyle *
gtk_ctree_node_get_row_style(GtkCTree * ctree,GtkCTreeNode * node)5112 gtk_ctree_node_get_row_style (GtkCTree     *ctree,
5113 			      GtkCTreeNode *node)
5114 {
5115   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
5116   g_return_val_if_fail (node != NULL, NULL);
5117 
5118   return GTK_CTREE_ROW (node)->row.style;
5119 }
5120 
5121 void
gtk_ctree_node_set_foreground(GtkCTree * ctree,GtkCTreeNode * node,const GdkColor * color)5122 gtk_ctree_node_set_foreground (GtkCTree       *ctree,
5123 			       GtkCTreeNode   *node,
5124 			       const GdkColor *color)
5125 {
5126   g_return_if_fail (GTK_IS_CTREE (ctree));
5127   g_return_if_fail (node != NULL);
5128 
5129   if (color)
5130     {
5131       GTK_CTREE_ROW (node)->row.foreground = *color;
5132       GTK_CTREE_ROW (node)->row.fg_set = TRUE;
5133       if (gtk_widget_get_realized (GTK_WIDGET (ctree)))
5134 	gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (ctree)),
5135                                   &GTK_CTREE_ROW (node)->row.foreground,
5136                                   FALSE, TRUE);
5137     }
5138   else
5139     GTK_CTREE_ROW (node)->row.fg_set = FALSE;
5140 
5141   tree_draw_node (ctree, node);
5142 }
5143 
5144 void
gtk_ctree_node_set_background(GtkCTree * ctree,GtkCTreeNode * node,const GdkColor * color)5145 gtk_ctree_node_set_background (GtkCTree       *ctree,
5146 			       GtkCTreeNode   *node,
5147 			       const GdkColor *color)
5148 {
5149   g_return_if_fail (GTK_IS_CTREE (ctree));
5150   g_return_if_fail (node != NULL);
5151 
5152   if (color)
5153     {
5154       GTK_CTREE_ROW (node)->row.background = *color;
5155       GTK_CTREE_ROW (node)->row.bg_set = TRUE;
5156       if (gtk_widget_get_realized (GTK_WIDGET (ctree)))
5157 	gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (ctree)),
5158                                   &GTK_CTREE_ROW (node)->row.background,
5159                                   FALSE, TRUE);
5160     }
5161   else
5162     GTK_CTREE_ROW (node)->row.bg_set = FALSE;
5163 
5164   tree_draw_node (ctree, node);
5165 }
5166 
5167 void
gtk_ctree_node_set_row_data(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)5168 gtk_ctree_node_set_row_data (GtkCTree     *ctree,
5169 			     GtkCTreeNode *node,
5170 			     gpointer      data)
5171 {
5172   gtk_ctree_node_set_row_data_full (ctree, node, data, NULL);
5173 }
5174 
5175 void
gtk_ctree_node_set_row_data_full(GtkCTree * ctree,GtkCTreeNode * node,gpointer data,GDestroyNotify destroy)5176 gtk_ctree_node_set_row_data_full (GtkCTree       *ctree,
5177 				  GtkCTreeNode   *node,
5178 				  gpointer        data,
5179 				  GDestroyNotify  destroy)
5180 {
5181   GDestroyNotify dnotify;
5182   gpointer ddata;
5183 
5184   g_return_if_fail (GTK_IS_CTREE (ctree));
5185   g_return_if_fail (node != NULL);
5186 
5187   dnotify = GTK_CTREE_ROW (node)->row.destroy;
5188   ddata = GTK_CTREE_ROW (node)->row.data;
5189 
5190   GTK_CTREE_ROW (node)->row.data = data;
5191   GTK_CTREE_ROW (node)->row.destroy = destroy;
5192 
5193   if (dnotify)
5194     dnotify (ddata);
5195 }
5196 
5197 gpointer
gtk_ctree_node_get_row_data(GtkCTree * ctree,GtkCTreeNode * node)5198 gtk_ctree_node_get_row_data (GtkCTree     *ctree,
5199 			     GtkCTreeNode *node)
5200 {
5201   g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL);
5202 
5203   return node ? GTK_CTREE_ROW (node)->row.data : NULL;
5204 }
5205 
5206 void
gtk_ctree_node_moveto(GtkCTree * ctree,GtkCTreeNode * node,gint column,gfloat row_align,gfloat col_align)5207 gtk_ctree_node_moveto (GtkCTree     *ctree,
5208 		       GtkCTreeNode *node,
5209 		       gint          column,
5210 		       gfloat        row_align,
5211 		       gfloat        col_align)
5212 {
5213   gint row = -1;
5214   GtkCList *clist;
5215 
5216   g_return_if_fail (GTK_IS_CTREE (ctree));
5217 
5218   clist = GTK_CLIST (ctree);
5219 
5220   while (node && !gtk_ctree_is_viewable (ctree, node))
5221     node = GTK_CTREE_ROW (node)->parent;
5222 
5223   if (node)
5224     row = g_list_position (clist->row_list, (GList *)node);
5225 
5226   gtk_clist_moveto (clist, row, column, row_align, col_align);
5227 }
5228 
5229 GtkVisibility
gtk_ctree_node_is_visible(GtkCTree * ctree,GtkCTreeNode * node)5230 gtk_ctree_node_is_visible (GtkCTree     *ctree,
5231                            GtkCTreeNode *node)
5232 {
5233   gint row;
5234 
5235   g_return_val_if_fail (ctree != NULL, 0);
5236   g_return_val_if_fail (node != NULL, 0);
5237 
5238   row = g_list_position (GTK_CLIST (ctree)->row_list, (GList*) node);
5239   return gtk_clist_row_is_visible (GTK_CLIST (ctree), row);
5240 }
5241 
5242 
5243 /***********************************************************
5244  *             GtkCTree specific functions                 *
5245  ***********************************************************/
5246 
5247 void
gtk_ctree_set_indent(GtkCTree * ctree,gint indent)5248 gtk_ctree_set_indent (GtkCTree *ctree,
5249                       gint      indent)
5250 {
5251   GtkCList *clist;
5252 
5253   g_return_if_fail (GTK_IS_CTREE (ctree));
5254   g_return_if_fail (indent >= 0);
5255 
5256   if (indent == ctree->tree_indent)
5257     return;
5258 
5259   clist = GTK_CLIST (ctree);
5260   ctree->tree_indent = indent;
5261 
5262   if (clist->column[ctree->tree_column].auto_resize &&
5263       !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
5264     gtk_clist_set_column_width
5265       (clist, ctree->tree_column,
5266        gtk_clist_optimal_column_width (clist, ctree->tree_column));
5267   else
5268     CLIST_REFRESH (ctree);
5269 }
5270 
5271 void
gtk_ctree_set_spacing(GtkCTree * ctree,gint spacing)5272 gtk_ctree_set_spacing (GtkCTree *ctree,
5273 		       gint      spacing)
5274 {
5275   GtkCList *clist;
5276   gint old_spacing;
5277 
5278   g_return_if_fail (GTK_IS_CTREE (ctree));
5279   g_return_if_fail (spacing >= 0);
5280 
5281   if (spacing == ctree->tree_spacing)
5282     return;
5283 
5284   clist = GTK_CLIST (ctree);
5285 
5286   old_spacing = ctree->tree_spacing;
5287   ctree->tree_spacing = spacing;
5288 
5289   if (clist->column[ctree->tree_column].auto_resize &&
5290       !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
5291     gtk_clist_set_column_width (clist, ctree->tree_column,
5292 				clist->column[ctree->tree_column].width +
5293 				spacing - old_spacing);
5294   else
5295     CLIST_REFRESH (ctree);
5296 }
5297 
5298 void
gtk_ctree_set_show_stub(GtkCTree * ctree,gboolean show_stub)5299 gtk_ctree_set_show_stub (GtkCTree *ctree,
5300 			 gboolean  show_stub)
5301 {
5302   g_return_if_fail (GTK_IS_CTREE (ctree));
5303 
5304   show_stub = show_stub != FALSE;
5305 
5306   if (show_stub != ctree->show_stub)
5307     {
5308       GtkCList *clist;
5309 
5310       clist = GTK_CLIST (ctree);
5311       ctree->show_stub = show_stub;
5312 
5313       if (CLIST_UNFROZEN (clist) && clist->rows &&
5314 	  gtk_clist_row_is_visible (clist, 0) != GTK_VISIBILITY_NONE)
5315 	GTK_CLIST_GET_CLASS (clist)->draw_row
5316 	  (clist, NULL, 0, GTK_CLIST_ROW (clist->row_list));
5317     }
5318 }
5319 
5320 void
gtk_ctree_set_line_style(GtkCTree * ctree,GtkCTreeLineStyle line_style)5321 gtk_ctree_set_line_style (GtkCTree          *ctree,
5322 			  GtkCTreeLineStyle  line_style)
5323 {
5324   GtkCList *clist;
5325   GtkCTreeLineStyle old_style;
5326 
5327   g_return_if_fail (GTK_IS_CTREE (ctree));
5328 
5329   if (line_style == ctree->line_style)
5330     return;
5331 
5332   clist = GTK_CLIST (ctree);
5333 
5334   old_style = ctree->line_style;
5335   ctree->line_style = line_style;
5336 
5337   if (clist->column[ctree->tree_column].auto_resize &&
5338       !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
5339     {
5340       if (old_style == GTK_CTREE_LINES_TABBED)
5341 	gtk_clist_set_column_width
5342 	  (clist, ctree->tree_column,
5343 	   clist->column[ctree->tree_column].width - 3);
5344       else if (line_style == GTK_CTREE_LINES_TABBED)
5345 	gtk_clist_set_column_width
5346 	  (clist, ctree->tree_column,
5347 	   clist->column[ctree->tree_column].width + 3);
5348     }
5349 
5350   if (gtk_widget_get_realized (GTK_WIDGET (ctree)))
5351     {
5352       gint8 dashes[] = { 1, 1 };
5353 
5354       switch (line_style)
5355 	{
5356 	case GTK_CTREE_LINES_SOLID:
5357 	  if (gtk_widget_get_realized (GTK_WIDGET (ctree)))
5358 	    gdk_gc_set_line_attributes (ctree->lines_gc, 1, GDK_LINE_SOLID,
5359 					GDK_CAP_BUTT, GDK_JOIN_MITER);
5360 	  break;
5361 	case GTK_CTREE_LINES_DOTTED:
5362 	  if (gtk_widget_get_realized (GTK_WIDGET (ctree)))
5363 	    gdk_gc_set_line_attributes (ctree->lines_gc, 1,
5364 					GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER);
5365 	  gdk_gc_set_dashes (ctree->lines_gc, 0, dashes, G_N_ELEMENTS (dashes));
5366 	  break;
5367 	case GTK_CTREE_LINES_TABBED:
5368 	  if (gtk_widget_get_realized (GTK_WIDGET (ctree)))
5369 	    gdk_gc_set_line_attributes (ctree->lines_gc, 1, GDK_LINE_SOLID,
5370 					GDK_CAP_BUTT, GDK_JOIN_MITER);
5371 	  break;
5372 	case GTK_CTREE_LINES_NONE:
5373 	  break;
5374 	default:
5375 	  return;
5376 	}
5377       CLIST_REFRESH (ctree);
5378     }
5379 }
5380 
5381 void
gtk_ctree_set_expander_style(GtkCTree * ctree,GtkCTreeExpanderStyle expander_style)5382 gtk_ctree_set_expander_style (GtkCTree              *ctree,
5383 			      GtkCTreeExpanderStyle  expander_style)
5384 {
5385   GtkCList *clist;
5386   GtkCTreeExpanderStyle old_style;
5387 
5388   g_return_if_fail (GTK_IS_CTREE (ctree));
5389 
5390   if (expander_style == ctree->expander_style)
5391     return;
5392 
5393   clist = GTK_CLIST (ctree);
5394 
5395   old_style = ctree->expander_style;
5396   ctree->expander_style = expander_style;
5397 
5398   if (clist->column[ctree->tree_column].auto_resize &&
5399       !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist))
5400     {
5401       gint new_width;
5402 
5403       new_width = clist->column[ctree->tree_column].width;
5404       switch (old_style)
5405 	{
5406 	case GTK_CTREE_EXPANDER_NONE:
5407 	  break;
5408 	case GTK_CTREE_EXPANDER_TRIANGLE:
5409 	  new_width -= PM_SIZE + 3;
5410 	  break;
5411 	case GTK_CTREE_EXPANDER_SQUARE:
5412 	case GTK_CTREE_EXPANDER_CIRCULAR:
5413 	  new_width -= PM_SIZE + 1;
5414 	  break;
5415 	}
5416 
5417       switch (expander_style)
5418 	{
5419 	case GTK_CTREE_EXPANDER_NONE:
5420 	  break;
5421 	case GTK_CTREE_EXPANDER_TRIANGLE:
5422 	  new_width += PM_SIZE + 3;
5423 	  break;
5424 	case GTK_CTREE_EXPANDER_SQUARE:
5425 	case GTK_CTREE_EXPANDER_CIRCULAR:
5426 	  new_width += PM_SIZE + 1;
5427 	  break;
5428 	}
5429 
5430       gtk_clist_set_column_width (clist, ctree->tree_column, new_width);
5431     }
5432 
5433   if (GTK_WIDGET_DRAWABLE (clist))
5434     CLIST_REFRESH (clist);
5435 }
5436 
5437 
5438 /***********************************************************
5439  *             Tree sorting functions                      *
5440  ***********************************************************/
5441 
5442 
5443 static void
tree_sort(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)5444 tree_sort (GtkCTree     *ctree,
5445 	   GtkCTreeNode *node,
5446 	   gpointer      data)
5447 {
5448   GtkCTreeNode *list_start;
5449   GtkCTreeNode *cmp;
5450   GtkCTreeNode *work;
5451   GtkCList *clist;
5452 
5453   clist = GTK_CLIST (ctree);
5454 
5455   if (node)
5456     list_start = GTK_CTREE_ROW (node)->children;
5457   else
5458     list_start = GTK_CTREE_NODE (clist->row_list);
5459 
5460   while (list_start)
5461     {
5462       cmp = list_start;
5463       work = GTK_CTREE_ROW (cmp)->sibling;
5464       while (work)
5465 	{
5466 	  if (clist->sort_type == GTK_SORT_ASCENDING)
5467 	    {
5468 	      if (clist->compare
5469 		  (clist, GTK_CTREE_ROW (work), GTK_CTREE_ROW (cmp)) < 0)
5470 		cmp = work;
5471 	    }
5472 	  else
5473 	    {
5474 	      if (clist->compare
5475 		  (clist, GTK_CTREE_ROW (work), GTK_CTREE_ROW (cmp)) > 0)
5476 		cmp = work;
5477 	    }
5478 	  work = GTK_CTREE_ROW (work)->sibling;
5479 	}
5480       if (cmp == list_start)
5481 	list_start = GTK_CTREE_ROW (cmp)->sibling;
5482       else
5483 	{
5484 	  gtk_ctree_unlink (ctree, cmp, FALSE);
5485 	  gtk_ctree_link (ctree, cmp, node, list_start, FALSE);
5486 	}
5487     }
5488 }
5489 
5490 void
gtk_ctree_sort_recursive(GtkCTree * ctree,GtkCTreeNode * node)5491 gtk_ctree_sort_recursive (GtkCTree     *ctree,
5492 			  GtkCTreeNode *node)
5493 {
5494   GtkCList *clist;
5495   GtkCTreeNode *focus_node = NULL;
5496 
5497   g_return_if_fail (GTK_IS_CTREE (ctree));
5498 
5499   clist = GTK_CLIST (ctree);
5500 
5501   gtk_clist_freeze (clist);
5502 
5503   if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
5504     {
5505       GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
5506 
5507       g_list_free (clist->undo_selection);
5508       g_list_free (clist->undo_unselection);
5509       clist->undo_selection = NULL;
5510       clist->undo_unselection = NULL;
5511     }
5512 
5513   if (!node || (node && gtk_ctree_is_viewable (ctree, node)))
5514     focus_node =
5515       GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row));
5516 
5517   gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (tree_sort), NULL);
5518 
5519   if (!node)
5520     tree_sort (ctree, NULL, NULL);
5521 
5522   if (focus_node)
5523     {
5524       clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
5525       clist->undo_anchor = clist->focus_row;
5526     }
5527 
5528   gtk_clist_thaw (clist);
5529 }
5530 
5531 static void
real_sort_list(GtkCList * clist)5532 real_sort_list (GtkCList *clist)
5533 {
5534   gtk_ctree_sort_recursive (GTK_CTREE (clist), NULL);
5535 }
5536 
5537 void
gtk_ctree_sort_node(GtkCTree * ctree,GtkCTreeNode * node)5538 gtk_ctree_sort_node (GtkCTree     *ctree,
5539 		     GtkCTreeNode *node)
5540 {
5541   GtkCList *clist;
5542   GtkCTreeNode *focus_node = NULL;
5543 
5544   g_return_if_fail (GTK_IS_CTREE (ctree));
5545 
5546   clist = GTK_CLIST (ctree);
5547 
5548   gtk_clist_freeze (clist);
5549 
5550   if (clist->selection_mode == GTK_SELECTION_MULTIPLE)
5551     {
5552       GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL);
5553 
5554       g_list_free (clist->undo_selection);
5555       g_list_free (clist->undo_unselection);
5556       clist->undo_selection = NULL;
5557       clist->undo_unselection = NULL;
5558     }
5559 
5560   if (!node || (node && gtk_ctree_is_viewable (ctree, node)))
5561     focus_node = GTK_CTREE_NODE
5562       (g_list_nth (clist->row_list, clist->focus_row));
5563 
5564   tree_sort (ctree, node, NULL);
5565 
5566   if (focus_node)
5567     {
5568       clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node);
5569       clist->undo_anchor = clist->focus_row;
5570     }
5571 
5572   gtk_clist_thaw (clist);
5573 }
5574 
5575 /************************************************************************/
5576 
5577 static void
fake_unselect_all(GtkCList * clist,gint row)5578 fake_unselect_all (GtkCList *clist,
5579 		   gint      row)
5580 {
5581   GList *list;
5582   GList *focus_node = NULL;
5583 
5584   if (row >= 0 && (focus_node = g_list_nth (clist->row_list, row)))
5585     {
5586       if (GTK_CTREE_ROW (focus_node)->row.state == GTK_STATE_NORMAL &&
5587 	  GTK_CTREE_ROW (focus_node)->row.selectable)
5588 	{
5589 	  GTK_CTREE_ROW (focus_node)->row.state = GTK_STATE_SELECTED;
5590 
5591 	  if (CLIST_UNFROZEN (clist) &&
5592 	      gtk_clist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)
5593 	    GTK_CLIST_GET_CLASS (clist)->draw_row (clist, NULL, row,
5594 						  GTK_CLIST_ROW (focus_node));
5595 	}
5596     }
5597 
5598   clist->undo_selection = clist->selection;
5599   clist->selection = NULL;
5600   clist->selection_end = NULL;
5601 
5602   for (list = clist->undo_selection; list; list = list->next)
5603     {
5604       if (list->data == focus_node)
5605 	continue;
5606 
5607       GTK_CTREE_ROW ((GList *)(list->data))->row.state = GTK_STATE_NORMAL;
5608       tree_draw_node (GTK_CTREE (clist), GTK_CTREE_NODE (list->data));
5609     }
5610 }
5611 
5612 static GList *
selection_find(GtkCList * clist,gint row_number,GList * row_list_element)5613 selection_find (GtkCList *clist,
5614 		gint      row_number,
5615 		GList    *row_list_element)
5616 {
5617   return g_list_find (clist->selection, row_list_element);
5618 }
5619 
5620 static void
resync_selection(GtkCList * clist,GdkEvent * event)5621 resync_selection (GtkCList *clist, GdkEvent *event)
5622 {
5623   GtkCTree *ctree;
5624   GList *list;
5625   GtkCTreeNode *node;
5626   gint i;
5627   gint e;
5628   gint row;
5629   gboolean unselect;
5630 
5631   g_return_if_fail (GTK_IS_CTREE (clist));
5632 
5633   if (clist->selection_mode != GTK_SELECTION_MULTIPLE)
5634     return;
5635 
5636   if (clist->anchor < 0 || clist->drag_pos < 0)
5637     return;
5638 
5639   ctree = GTK_CTREE (clist);
5640 
5641   clist->freeze_count++;
5642 
5643   i = MIN (clist->anchor, clist->drag_pos);
5644   e = MAX (clist->anchor, clist->drag_pos);
5645 
5646   if (clist->undo_selection)
5647     {
5648       list = clist->selection;
5649       clist->selection = clist->undo_selection;
5650       clist->selection_end = g_list_last (clist->selection);
5651       clist->undo_selection = list;
5652       list = clist->selection;
5653 
5654       while (list)
5655 	{
5656 	  node = list->data;
5657 	  list = list->next;
5658 
5659 	  unselect = TRUE;
5660 
5661 	  if (gtk_ctree_is_viewable (ctree, node))
5662 	    {
5663 	      row = g_list_position (clist->row_list, (GList *)node);
5664 	      if (row >= i && row <= e)
5665 		unselect = FALSE;
5666 	    }
5667 	  if (unselect && GTK_CTREE_ROW (node)->row.selectable)
5668 	    {
5669 	      GTK_CTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
5670 	      gtk_ctree_unselect (ctree, node);
5671 	      clist->undo_selection = g_list_prepend (clist->undo_selection,
5672 						      node);
5673 	    }
5674 	}
5675     }
5676 
5677   if (clist->anchor < clist->drag_pos)
5678     {
5679       for (node = GTK_CTREE_NODE (g_list_nth (clist->row_list, i)); i <= e;
5680 	   i++, node = GTK_CTREE_NODE_NEXT (node))
5681 	if (GTK_CTREE_ROW (node)->row.selectable)
5682 	  {
5683 	    if (g_list_find (clist->selection, node))
5684 	      {
5685 		if (GTK_CTREE_ROW (node)->row.state == GTK_STATE_NORMAL)
5686 		  {
5687 		    GTK_CTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
5688 		    gtk_ctree_unselect (ctree, node);
5689 		    clist->undo_selection =
5690 		      g_list_prepend (clist->undo_selection, node);
5691 		  }
5692 	      }
5693 	    else if (GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
5694 	      {
5695 		GTK_CTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
5696 		clist->undo_unselection =
5697 		  g_list_prepend (clist->undo_unselection, node);
5698 	      }
5699 	  }
5700     }
5701   else
5702     {
5703       for (node = GTK_CTREE_NODE (g_list_nth (clist->row_list, e)); i <= e;
5704 	   e--, node = GTK_CTREE_NODE_PREV (node))
5705 	if (GTK_CTREE_ROW (node)->row.selectable)
5706 	  {
5707 	    if (g_list_find (clist->selection, node))
5708 	      {
5709 		if (GTK_CTREE_ROW (node)->row.state == GTK_STATE_NORMAL)
5710 		  {
5711 		    GTK_CTREE_ROW (node)->row.state = GTK_STATE_SELECTED;
5712 		    gtk_ctree_unselect (ctree, node);
5713 		    clist->undo_selection =
5714 		      g_list_prepend (clist->undo_selection, node);
5715 		  }
5716 	      }
5717 	    else if (GTK_CTREE_ROW (node)->row.state == GTK_STATE_SELECTED)
5718 	      {
5719 		GTK_CTREE_ROW (node)->row.state = GTK_STATE_NORMAL;
5720 		clist->undo_unselection =
5721 		  g_list_prepend (clist->undo_unselection, node);
5722 	      }
5723 	  }
5724     }
5725 
5726   clist->undo_unselection = g_list_reverse (clist->undo_unselection);
5727   for (list = clist->undo_unselection; list; list = list->next)
5728     gtk_ctree_select (ctree, list->data);
5729 
5730   clist->anchor = -1;
5731   clist->drag_pos = -1;
5732 
5733   if (!CLIST_UNFROZEN (clist))
5734     clist->freeze_count--;
5735 }
5736 
5737 static void
real_undo_selection(GtkCList * clist)5738 real_undo_selection (GtkCList *clist)
5739 {
5740   GtkCTree *ctree;
5741   GList *work;
5742 
5743   g_return_if_fail (GTK_IS_CTREE (clist));
5744 
5745   if (clist->selection_mode != GTK_SELECTION_MULTIPLE)
5746     return;
5747 
5748   if (!(clist->undo_selection || clist->undo_unselection))
5749     {
5750       gtk_clist_unselect_all (clist);
5751       return;
5752     }
5753 
5754   ctree = GTK_CTREE (clist);
5755 
5756   for (work = clist->undo_selection; work; work = work->next)
5757     if (GTK_CTREE_ROW (work->data)->row.selectable)
5758       gtk_ctree_select (ctree, GTK_CTREE_NODE (work->data));
5759 
5760   for (work = clist->undo_unselection; work; work = work->next)
5761     if (GTK_CTREE_ROW (work->data)->row.selectable)
5762       gtk_ctree_unselect (ctree, GTK_CTREE_NODE (work->data));
5763 
5764   if (gtk_widget_has_focus (GTK_WIDGET (clist)) && clist->focus_row != clist->undo_anchor)
5765     {
5766       clist->focus_row = clist->undo_anchor;
5767       gtk_widget_queue_draw (GTK_WIDGET (clist));
5768     }
5769   else
5770     clist->focus_row = clist->undo_anchor;
5771 
5772   clist->undo_anchor = -1;
5773 
5774   g_list_free (clist->undo_selection);
5775   g_list_free (clist->undo_unselection);
5776   clist->undo_selection = NULL;
5777   clist->undo_unselection = NULL;
5778 
5779   if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height >
5780       clist->clist_window_height)
5781     gtk_clist_moveto (clist, clist->focus_row, -1, 1, 0);
5782   else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0)
5783     gtk_clist_moveto (clist, clist->focus_row, -1, 0, 0);
5784 
5785 }
5786 
5787 void
gtk_ctree_set_drag_compare_func(GtkCTree * ctree,GtkCTreeCompareDragFunc cmp_func)5788 gtk_ctree_set_drag_compare_func (GtkCTree                *ctree,
5789 				 GtkCTreeCompareDragFunc  cmp_func)
5790 {
5791   g_return_if_fail (GTK_IS_CTREE (ctree));
5792 
5793   ctree->drag_compare = cmp_func;
5794 }
5795 
5796 static gboolean
check_drag(GtkCTree * ctree,GtkCTreeNode * drag_source,GtkCTreeNode * drag_target,GtkCListDragPos insert_pos)5797 check_drag (GtkCTree        *ctree,
5798 	    GtkCTreeNode    *drag_source,
5799 	    GtkCTreeNode    *drag_target,
5800 	    GtkCListDragPos  insert_pos)
5801 {
5802   g_return_val_if_fail (GTK_IS_CTREE (ctree), FALSE);
5803 
5804   if (drag_source && drag_source != drag_target &&
5805       (!GTK_CTREE_ROW (drag_source)->children ||
5806        !gtk_ctree_is_ancestor (ctree, drag_source, drag_target)))
5807     {
5808       switch (insert_pos)
5809 	{
5810 	case GTK_CLIST_DRAG_NONE:
5811 	  return FALSE;
5812 	case GTK_CLIST_DRAG_AFTER:
5813 	  if (GTK_CTREE_ROW (drag_target)->sibling != drag_source)
5814 	    return (!ctree->drag_compare ||
5815 		    ctree->drag_compare (ctree,
5816 					 drag_source,
5817 					 GTK_CTREE_ROW (drag_target)->parent,
5818 					 GTK_CTREE_ROW (drag_target)->sibling));
5819 	  break;
5820 	case GTK_CLIST_DRAG_BEFORE:
5821 	  if (GTK_CTREE_ROW (drag_source)->sibling != drag_target)
5822 	    return (!ctree->drag_compare ||
5823 		    ctree->drag_compare (ctree,
5824 					 drag_source,
5825 					 GTK_CTREE_ROW (drag_target)->parent,
5826 					 drag_target));
5827 	  break;
5828 	case GTK_CLIST_DRAG_INTO:
5829 	  if (!GTK_CTREE_ROW (drag_target)->is_leaf &&
5830 	      GTK_CTREE_ROW (drag_target)->children != drag_source)
5831 	    return (!ctree->drag_compare ||
5832 		    ctree->drag_compare (ctree,
5833 					 drag_source,
5834 					 drag_target,
5835 					 GTK_CTREE_ROW (drag_target)->children));
5836 	  break;
5837 	}
5838     }
5839   return FALSE;
5840 }
5841 
5842 
5843 
5844 /************************************/
5845 static void
drag_dest_info_destroy(gpointer data)5846 drag_dest_info_destroy (gpointer data)
5847 {
5848   GtkCListDestInfo *info = data;
5849 
5850   g_free (info);
5851 }
5852 
5853 static void
drag_dest_cell(GtkCList * clist,gint x,gint y,GtkCListDestInfo * dest_info)5854 drag_dest_cell (GtkCList         *clist,
5855 		gint              x,
5856 		gint              y,
5857 		GtkCListDestInfo *dest_info)
5858 {
5859   GtkWidget *widget;
5860 
5861   widget = GTK_WIDGET (clist);
5862 
5863   dest_info->insert_pos = GTK_CLIST_DRAG_NONE;
5864 
5865   y -= (GTK_CONTAINER (widget)->border_width +
5866 	widget->style->ythickness + clist->column_title_area.height);
5867   dest_info->cell.row = ROW_FROM_YPIXEL (clist, y);
5868 
5869   if (dest_info->cell.row >= clist->rows)
5870     {
5871       dest_info->cell.row = clist->rows - 1;
5872       y = ROW_TOP_YPIXEL (clist, dest_info->cell.row) + clist->row_height;
5873     }
5874   if (dest_info->cell.row < -1)
5875     dest_info->cell.row = -1;
5876 
5877   x -= GTK_CONTAINER (widget)->border_width + widget->style->xthickness;
5878 
5879   dest_info->cell.column = COLUMN_FROM_XPIXEL (clist, x);
5880 
5881   if (dest_info->cell.row >= 0)
5882     {
5883       gint y_delta;
5884       gint h = 0;
5885 
5886       y_delta = y - ROW_TOP_YPIXEL (clist, dest_info->cell.row);
5887 
5888       if (GTK_CLIST_DRAW_DRAG_RECT(clist) &&
5889 	  !GTK_CTREE_ROW (g_list_nth (clist->row_list,
5890 				      dest_info->cell.row))->is_leaf)
5891 	{
5892 	  dest_info->insert_pos = GTK_CLIST_DRAG_INTO;
5893 	  h = clist->row_height / 4;
5894 	}
5895       else if (GTK_CLIST_DRAW_DRAG_LINE(clist))
5896 	{
5897 	  dest_info->insert_pos = GTK_CLIST_DRAG_BEFORE;
5898 	  h = clist->row_height / 2;
5899 	}
5900 
5901       if (GTK_CLIST_DRAW_DRAG_LINE(clist))
5902 	{
5903 	  if (y_delta < h)
5904 	    dest_info->insert_pos = GTK_CLIST_DRAG_BEFORE;
5905 	  else if (clist->row_height - y_delta < h)
5906 	    dest_info->insert_pos = GTK_CLIST_DRAG_AFTER;
5907 	}
5908     }
5909 }
5910 
5911 static void
gtk_ctree_drag_begin(GtkWidget * widget,GdkDragContext * context)5912 gtk_ctree_drag_begin (GtkWidget	     *widget,
5913 		      GdkDragContext *context)
5914 {
5915   GtkCList *clist;
5916   GtkCTree *ctree;
5917   gboolean use_icons;
5918 
5919   g_return_if_fail (GTK_IS_CTREE (widget));
5920   g_return_if_fail (context != NULL);
5921 
5922   clist = GTK_CLIST (widget);
5923   ctree = GTK_CTREE (widget);
5924 
5925   use_icons = GTK_CLIST_USE_DRAG_ICONS (clist);
5926   GTK_CLIST_UNSET_FLAG (clist, CLIST_USE_DRAG_ICONS);
5927   GTK_WIDGET_CLASS (parent_class)->drag_begin (widget, context);
5928 
5929   if (use_icons)
5930     {
5931       GtkCTreeNode *node;
5932 
5933       GTK_CLIST_SET_FLAG (clist, CLIST_USE_DRAG_ICONS);
5934       node = GTK_CTREE_NODE (g_list_nth (clist->row_list,
5935 					 clist->click_cell.row));
5936       if (node)
5937 	{
5938 	  if (GTK_CELL_PIXTEXT
5939 	      (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap)
5940 	    {
5941 	      gtk_drag_set_icon_pixmap
5942 		(context,
5943 		 gtk_widget_get_colormap (widget),
5944 		 GTK_CELL_PIXTEXT
5945 		 (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap,
5946 		 GTK_CELL_PIXTEXT
5947 		 (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask,
5948 		 -2, -2);
5949 	      return;
5950 	    }
5951 	}
5952       gtk_drag_set_icon_default (context);
5953     }
5954 }
5955 
5956 static gint
gtk_ctree_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time)5957 gtk_ctree_drag_motion (GtkWidget      *widget,
5958 		       GdkDragContext *context,
5959 		       gint            x,
5960 		       gint            y,
5961 		       guint           time)
5962 {
5963   GtkCList *clist;
5964   GtkCTree *ctree;
5965   GtkCListDestInfo new_info;
5966   GtkCListDestInfo *dest_info;
5967 
5968   g_return_val_if_fail (GTK_IS_CTREE (widget), FALSE);
5969 
5970   clist = GTK_CLIST (widget);
5971   ctree = GTK_CTREE (widget);
5972 
5973   dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest");
5974 
5975   if (!dest_info)
5976     {
5977       dest_info = g_new (GtkCListDestInfo, 1);
5978 
5979       dest_info->cell.row    = -1;
5980       dest_info->cell.column = -1;
5981       dest_info->insert_pos  = GTK_CLIST_DRAG_NONE;
5982 
5983       g_dataset_set_data_full (context, "gtk-clist-drag-dest", dest_info,
5984 			       drag_dest_info_destroy);
5985     }
5986 
5987   drag_dest_cell (clist, x, y, &new_info);
5988 
5989   if (GTK_CLIST_REORDERABLE (clist))
5990     {
5991       GList *list;
5992       GdkAtom atom = gdk_atom_intern_static_string ("gtk-clist-drag-reorder");
5993 
5994       list = context->targets;
5995       while (list)
5996 	{
5997 	  if (atom == GDK_POINTER_TO_ATOM (list->data))
5998 	    break;
5999 	  list = list->next;
6000 	}
6001 
6002       if (list)
6003 	{
6004 	  GtkCTreeNode *drag_source;
6005 	  GtkCTreeNode *drag_target;
6006 
6007 	  drag_source = GTK_CTREE_NODE (g_list_nth (clist->row_list,
6008 						    clist->click_cell.row));
6009 	  drag_target = GTK_CTREE_NODE (g_list_nth (clist->row_list,
6010 						    new_info.cell.row));
6011 
6012 	  if (gtk_drag_get_source_widget (context) != widget ||
6013 	      !check_drag (ctree, drag_source, drag_target,
6014 			   new_info.insert_pos))
6015 	    {
6016 	      if (dest_info->cell.row < 0)
6017 		{
6018 		  gdk_drag_status (context, GDK_ACTION_DEFAULT, time);
6019 		  return FALSE;
6020 		}
6021 	      return TRUE;
6022 	    }
6023 
6024 	  if (new_info.cell.row != dest_info->cell.row ||
6025 	      (new_info.cell.row == dest_info->cell.row &&
6026 	       dest_info->insert_pos != new_info.insert_pos))
6027 	    {
6028 	      if (dest_info->cell.row >= 0)
6029 		GTK_CLIST_GET_CLASS (clist)->draw_drag_highlight
6030 		  (clist,
6031 		   g_list_nth (clist->row_list, dest_info->cell.row)->data,
6032 		   dest_info->cell.row, dest_info->insert_pos);
6033 
6034 	      dest_info->insert_pos  = new_info.insert_pos;
6035 	      dest_info->cell.row    = new_info.cell.row;
6036 	      dest_info->cell.column = new_info.cell.column;
6037 
6038 	      GTK_CLIST_GET_CLASS (clist)->draw_drag_highlight
6039 		(clist,
6040 		 g_list_nth (clist->row_list, dest_info->cell.row)->data,
6041 		 dest_info->cell.row, dest_info->insert_pos);
6042 
6043 	      clist->drag_highlight_row = dest_info->cell.row;
6044 	      clist->drag_highlight_pos = dest_info->insert_pos;
6045 
6046 	      gdk_drag_status (context, context->suggested_action, time);
6047 	    }
6048 	  return TRUE;
6049 	}
6050     }
6051 
6052   dest_info->insert_pos  = new_info.insert_pos;
6053   dest_info->cell.row    = new_info.cell.row;
6054   dest_info->cell.column = new_info.cell.column;
6055   return TRUE;
6056 }
6057 
6058 static void
gtk_ctree_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * selection_data,guint info,guint32 time)6059 gtk_ctree_drag_data_received (GtkWidget        *widget,
6060 			      GdkDragContext   *context,
6061 			      gint              x,
6062 			      gint              y,
6063 			      GtkSelectionData *selection_data,
6064 			      guint             info,
6065 			      guint32           time)
6066 {
6067   GtkCTree *ctree;
6068   GtkCList *clist;
6069 
6070   g_return_if_fail (GTK_IS_CTREE (widget));
6071   g_return_if_fail (context != NULL);
6072   g_return_if_fail (selection_data != NULL);
6073 
6074   ctree = GTK_CTREE (widget);
6075   clist = GTK_CLIST (widget);
6076 
6077   if (GTK_CLIST_REORDERABLE (clist) &&
6078       gtk_drag_get_source_widget (context) == widget &&
6079       selection_data->target ==
6080       gdk_atom_intern_static_string ("gtk-clist-drag-reorder") &&
6081       selection_data->format == 8 &&
6082       selection_data->length == sizeof (GtkCListCellInfo))
6083     {
6084       GtkCListCellInfo *source_info;
6085 
6086       source_info = (GtkCListCellInfo *)(selection_data->data);
6087       if (source_info)
6088 	{
6089 	  GtkCListDestInfo dest_info;
6090 	  GtkCTreeNode *source_node;
6091 	  GtkCTreeNode *dest_node;
6092 
6093 	  drag_dest_cell (clist, x, y, &dest_info);
6094 
6095 	  source_node = GTK_CTREE_NODE (g_list_nth (clist->row_list,
6096 						    source_info->row));
6097 	  dest_node = GTK_CTREE_NODE (g_list_nth (clist->row_list,
6098 						  dest_info.cell.row));
6099 
6100 	  if (!source_node || !dest_node)
6101 	    return;
6102 
6103 	  switch (dest_info.insert_pos)
6104 	    {
6105 	    case GTK_CLIST_DRAG_NONE:
6106 	      break;
6107 	    case GTK_CLIST_DRAG_INTO:
6108 	      if (check_drag (ctree, source_node, dest_node,
6109 			      dest_info.insert_pos))
6110 		gtk_ctree_move (ctree, source_node, dest_node,
6111 				GTK_CTREE_ROW (dest_node)->children);
6112 	      g_dataset_remove_data (context, "gtk-clist-drag-dest");
6113 	      break;
6114 	    case GTK_CLIST_DRAG_BEFORE:
6115 	      if (check_drag (ctree, source_node, dest_node,
6116 			      dest_info.insert_pos))
6117 		gtk_ctree_move (ctree, source_node,
6118 				GTK_CTREE_ROW (dest_node)->parent, dest_node);
6119 	      g_dataset_remove_data (context, "gtk-clist-drag-dest");
6120 	      break;
6121 	    case GTK_CLIST_DRAG_AFTER:
6122 	      if (check_drag (ctree, source_node, dest_node,
6123 			      dest_info.insert_pos))
6124 		gtk_ctree_move (ctree, source_node,
6125 				GTK_CTREE_ROW (dest_node)->parent,
6126 				GTK_CTREE_ROW (dest_node)->sibling);
6127 	      g_dataset_remove_data (context, "gtk-clist-drag-dest");
6128 	      break;
6129 	    }
6130 	}
6131     }
6132 }
6133 
6134 GType
gtk_ctree_node_get_type(void)6135 gtk_ctree_node_get_type (void)
6136 {
6137   static GType our_type = 0;
6138 
6139   if (our_type == 0)
6140     our_type = g_pointer_type_register_static ("GtkCTreeNode");
6141 
6142   return our_type;
6143 }
6144 
6145 #include "gtkaliasdef.c"
6146