source: trunk/third/gtk/gtk/gtkctree.c @ 15781

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