]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeitem.c
Make remote bookmarks work better (#354887)
[~andy/gtk] / gtk / gtktreeitem.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #undef GTK_DISABLE_DEPRECATED
28
29 #include <config.h>
30 #include "gtklabel.h"
31 #include "gtkeventbox.h"
32 #include "gtkpixmap.h"
33 #include "gtkmain.h"
34 #include "gtkmarshalers.h"
35 #include "gtksignal.h"
36 #define GTK_ENABLE_BROKEN
37 #include "gtktree.h"
38 #include "gtktreeitem.h"
39 #include "gtkintl.h"
40 #include "gtkalias.h"
41
42 #include "tree_plus.xpm"
43 #include "tree_minus.xpm"
44
45 #define DEFAULT_DELTA 9
46
47 enum {
48   COLLAPSE_TREE,
49   EXPAND_TREE,
50   LAST_SIGNAL
51 };
52
53 typedef struct _GtkTreePixmaps GtkTreePixmaps;
54
55 struct _GtkTreePixmaps {
56   gint refcount;
57   GdkColormap *colormap;
58   
59   GdkPixmap *pixmap_plus;
60   GdkPixmap *pixmap_minus;
61   GdkBitmap *mask_plus;
62   GdkBitmap *mask_minus;
63 };
64
65 static GList *pixmaps = NULL;
66
67 static void gtk_tree_item_class_init (GtkTreeItemClass *klass);
68 static void gtk_tree_item_init       (GtkTreeItem      *tree_item);
69 static void gtk_tree_item_realize       (GtkWidget        *widget);
70 static void gtk_tree_item_size_request  (GtkWidget        *widget,
71                                          GtkRequisition   *requisition);
72 static void gtk_tree_item_size_allocate (GtkWidget        *widget,
73                                          GtkAllocation    *allocation);
74 static void gtk_tree_item_paint         (GtkWidget        *widget,
75                                          GdkRectangle     *area);
76 static gint gtk_tree_item_button_press  (GtkWidget        *widget,
77                                          GdkEventButton   *event);
78 static gint gtk_tree_item_expose        (GtkWidget        *widget,
79                                          GdkEventExpose   *event);
80 static void gtk_tree_item_forall        (GtkContainer    *container,
81                                          gboolean         include_internals,
82                                          GtkCallback      callback,
83                                          gpointer         callback_data);
84
85 static void gtk_real_tree_item_select   (GtkItem          *item);
86 static void gtk_real_tree_item_deselect (GtkItem          *item);
87 static void gtk_real_tree_item_toggle   (GtkItem          *item);
88 static void gtk_real_tree_item_expand   (GtkTreeItem      *item);
89 static void gtk_real_tree_item_collapse (GtkTreeItem      *item);
90 static void gtk_tree_item_destroy        (GtkObject *object);
91 static gint gtk_tree_item_subtree_button_click (GtkWidget *widget);
92 static void gtk_tree_item_subtree_button_changed_state (GtkWidget *widget);
93
94 static void gtk_tree_item_map(GtkWidget*);
95 static void gtk_tree_item_unmap(GtkWidget*);
96
97 static void gtk_tree_item_add_pixmaps    (GtkTreeItem       *tree_item);
98 static void gtk_tree_item_remove_pixmaps (GtkTreeItem       *tree_item);
99
100 static GtkItemClass *parent_class = NULL;
101 static guint tree_item_signals[LAST_SIGNAL] = { 0 };
102
103 GtkType
104 gtk_tree_item_get_type (void)
105 {
106   static GtkType tree_item_type = 0;
107
108   if (!tree_item_type)
109     {
110       static const GtkTypeInfo tree_item_info =
111       {
112         "GtkTreeItem",
113         sizeof (GtkTreeItem),
114         sizeof (GtkTreeItemClass),
115         (GtkClassInitFunc) gtk_tree_item_class_init,
116         (GtkObjectInitFunc) gtk_tree_item_init,
117         /* reserved_1 */ NULL,
118         /* reserved_2 */ NULL,
119         (GtkClassInitFunc) NULL,
120       };
121
122       I_("GtkTreeItem");
123       tree_item_type = gtk_type_unique (gtk_item_get_type (), &tree_item_info);
124     }
125
126   return tree_item_type;
127 }
128
129 static void
130 gtk_tree_item_class_init (GtkTreeItemClass *class)
131 {
132   GtkObjectClass *object_class;
133   GtkWidgetClass *widget_class;
134   GtkContainerClass *container_class;
135   GtkItemClass *item_class;
136
137   parent_class = gtk_type_class (GTK_TYPE_ITEM);
138   
139   object_class = (GtkObjectClass*) class;
140   widget_class = (GtkWidgetClass*) class;
141   item_class = (GtkItemClass*) class;
142   container_class = (GtkContainerClass*) class;
143
144   object_class->destroy = gtk_tree_item_destroy;
145
146   widget_class->realize = gtk_tree_item_realize;
147   widget_class->size_request = gtk_tree_item_size_request;
148   widget_class->size_allocate = gtk_tree_item_size_allocate;
149   widget_class->button_press_event = gtk_tree_item_button_press;
150   widget_class->expose_event = gtk_tree_item_expose;
151   widget_class->map = gtk_tree_item_map;
152   widget_class->unmap = gtk_tree_item_unmap;
153
154   container_class->forall = gtk_tree_item_forall;
155
156   item_class->select = gtk_real_tree_item_select;
157   item_class->deselect = gtk_real_tree_item_deselect;
158   item_class->toggle = gtk_real_tree_item_toggle;
159
160   class->expand = gtk_real_tree_item_expand;
161   class->collapse = gtk_real_tree_item_collapse;
162
163   tree_item_signals[EXPAND_TREE] =
164     gtk_signal_new (I_("expand"),
165                     GTK_RUN_FIRST,
166                     GTK_CLASS_TYPE (object_class),
167                     GTK_SIGNAL_OFFSET (GtkTreeItemClass, expand),
168                     _gtk_marshal_VOID__VOID,
169                     GTK_TYPE_NONE, 0);
170   tree_item_signals[COLLAPSE_TREE] =
171     gtk_signal_new (I_("collapse"),
172                     GTK_RUN_FIRST,
173                     GTK_CLASS_TYPE (object_class),
174                     GTK_SIGNAL_OFFSET (GtkTreeItemClass, collapse),
175                     _gtk_marshal_VOID__VOID,
176                     GTK_TYPE_NONE, 0);
177 }
178
179 /* callback for event box mouse event */
180 static gint
181 gtk_tree_item_subtree_button_click (GtkWidget *widget)
182 {
183   GtkTreeItem* item;
184   
185   g_return_val_if_fail (GTK_IS_EVENT_BOX (widget), FALSE);
186   
187   item = (GtkTreeItem*) gtk_object_get_user_data (GTK_OBJECT (widget));
188   if (!GTK_WIDGET_IS_SENSITIVE (item))
189     return FALSE;
190   
191   if (item->expanded)
192     gtk_tree_item_collapse (item);
193   else
194     gtk_tree_item_expand (item);
195
196   return TRUE;
197 }
198
199 /* callback for event box state changed */
200 static void
201 gtk_tree_item_subtree_button_changed_state (GtkWidget *widget)
202 {
203   g_return_if_fail (GTK_IS_EVENT_BOX (widget));
204   
205   if (GTK_WIDGET_VISIBLE (widget))
206     {
207       
208       if (widget->state == GTK_STATE_NORMAL)
209         gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
210       else
211         gdk_window_set_background (widget->window, &widget->style->bg[widget->state]);
212       
213       if (GTK_WIDGET_DRAWABLE (widget))
214         gdk_window_clear_area (widget->window, 0, 0, 
215                                widget->allocation.width, widget->allocation.height);
216     }
217 }
218
219 static void
220 gtk_tree_item_init (GtkTreeItem *tree_item)
221 {
222   GtkWidget *eventbox, *pixmapwid;
223   
224   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
225
226   tree_item->expanded = FALSE;
227   tree_item->subtree = NULL;
228   GTK_WIDGET_SET_FLAGS (tree_item, GTK_CAN_FOCUS);
229   
230   /* create an event box containing one pixmaps */
231   eventbox = gtk_event_box_new();
232   gtk_widget_set_events (eventbox, GDK_BUTTON_PRESS_MASK);
233   gtk_signal_connect(GTK_OBJECT(eventbox), "state_changed",
234                      (GtkSignalFunc)gtk_tree_item_subtree_button_changed_state, 
235                      (gpointer)NULL);
236   gtk_signal_connect(GTK_OBJECT(eventbox), "realize",
237                      (GtkSignalFunc)gtk_tree_item_subtree_button_changed_state, 
238                      (gpointer)NULL);
239   gtk_signal_connect(GTK_OBJECT(eventbox), "button_press_event",
240                      (GtkSignalFunc)gtk_tree_item_subtree_button_click,
241                      (gpointer)NULL);
242   gtk_object_set_user_data(GTK_OBJECT(eventbox), tree_item);
243   tree_item->pixmaps_box = eventbox;
244
245   /* create pixmap for button '+' */
246   pixmapwid = gtk_type_new (gtk_pixmap_get_type ());
247   if (!tree_item->expanded) 
248     gtk_container_add (GTK_CONTAINER (eventbox), pixmapwid);
249   gtk_widget_show (pixmapwid);
250   tree_item->plus_pix_widget = pixmapwid;
251   g_object_ref_sink (tree_item->plus_pix_widget);
252   
253   /* create pixmap for button '-' */
254   pixmapwid = gtk_type_new (gtk_pixmap_get_type ());
255   if (tree_item->expanded) 
256     gtk_container_add (GTK_CONTAINER (eventbox), pixmapwid);
257   gtk_widget_show (pixmapwid);
258   tree_item->minus_pix_widget = pixmapwid;
259   g_object_ref_sink (tree_item->minus_pix_widget);
260   
261   gtk_widget_set_parent (eventbox, GTK_WIDGET (tree_item));
262 }
263
264
265 GtkWidget*
266 gtk_tree_item_new (void)
267 {
268   GtkWidget *tree_item;
269
270   tree_item = GTK_WIDGET (gtk_type_new (gtk_tree_item_get_type ()));
271
272   return tree_item;
273 }
274
275 GtkWidget*
276 gtk_tree_item_new_with_label (const gchar *label)
277 {
278   GtkWidget *tree_item;
279   GtkWidget *label_widget;
280
281   tree_item = gtk_tree_item_new ();
282   label_widget = gtk_label_new (label);
283   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
284
285   gtk_container_add (GTK_CONTAINER (tree_item), label_widget);
286   gtk_widget_show (label_widget);
287
288
289   return tree_item;
290 }
291
292 void
293 gtk_tree_item_set_subtree (GtkTreeItem *tree_item,
294                            GtkWidget   *subtree)
295 {
296   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
297   g_return_if_fail (GTK_IS_TREE (subtree));
298
299   if (tree_item->subtree)
300     {
301       g_warning("there is already a subtree for this tree item\n");
302       return;
303     }
304
305   tree_item->subtree = subtree; 
306   GTK_TREE (subtree)->tree_owner = GTK_WIDGET (tree_item);
307
308   /* show subtree button */
309   if (tree_item->pixmaps_box)
310     gtk_widget_show (tree_item->pixmaps_box);
311
312   if (tree_item->expanded)
313     gtk_widget_show (subtree);
314   else
315     gtk_widget_hide (subtree);
316
317   gtk_widget_set_parent (subtree, GTK_WIDGET (tree_item)->parent);
318 }
319
320 void
321 gtk_tree_item_select (GtkTreeItem *tree_item)
322 {
323   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
324
325   gtk_item_select (GTK_ITEM (tree_item));
326 }
327
328 void
329 gtk_tree_item_deselect (GtkTreeItem *tree_item)
330 {
331   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
332
333   gtk_item_deselect (GTK_ITEM (tree_item));
334 }
335
336 void
337 gtk_tree_item_expand (GtkTreeItem *tree_item)
338 {
339   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
340
341   gtk_signal_emit (GTK_OBJECT (tree_item), tree_item_signals[EXPAND_TREE], NULL);
342 }
343
344 void
345 gtk_tree_item_collapse (GtkTreeItem *tree_item)
346 {
347   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
348
349   gtk_signal_emit (GTK_OBJECT (tree_item), tree_item_signals[COLLAPSE_TREE], NULL);
350 }
351
352 static void
353 gtk_tree_item_add_pixmaps (GtkTreeItem *tree_item)
354 {
355   GList *tmp_list;
356   GdkColormap *colormap;
357   GtkTreePixmaps *pixmap_node = NULL;
358
359   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
360
361   if (tree_item->pixmaps)
362     return;
363
364   colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_item));
365
366   tmp_list = pixmaps;
367   while (tmp_list)
368     {
369       pixmap_node = (GtkTreePixmaps *)tmp_list->data;
370
371       if (pixmap_node->colormap == colormap)
372         break;
373       
374       tmp_list = tmp_list->next;
375     }
376
377   if (tmp_list)
378     {
379       pixmap_node->refcount++;
380       tree_item->pixmaps = tmp_list;
381     }
382   else
383     {
384       pixmap_node = g_new (GtkTreePixmaps, 1);
385
386       pixmap_node->colormap = colormap;
387       g_object_ref (colormap);
388
389       pixmap_node->refcount = 1;
390
391       /* create pixmaps for plus icon */
392       pixmap_node->pixmap_plus = 
393         gdk_pixmap_create_from_xpm_d (GTK_WIDGET (tree_item)->window,
394                                       &pixmap_node->mask_plus,
395                                       NULL,
396                                       (gchar **)tree_plus);
397       
398       /* create pixmaps for minus icon */
399       pixmap_node->pixmap_minus = 
400         gdk_pixmap_create_from_xpm_d (GTK_WIDGET (tree_item)->window,
401                                       &pixmap_node->mask_minus,
402                                       NULL,
403                                       (gchar **)tree_minus);
404
405       tree_item->pixmaps = pixmaps = g_list_prepend (pixmaps, pixmap_node);
406     }
407   
408   gtk_pixmap_set (GTK_PIXMAP (tree_item->plus_pix_widget), 
409                   pixmap_node->pixmap_plus, pixmap_node->mask_plus);
410   gtk_pixmap_set (GTK_PIXMAP (tree_item->minus_pix_widget), 
411                   pixmap_node->pixmap_minus, pixmap_node->mask_minus);
412 }
413
414 static void
415 gtk_tree_item_remove_pixmaps (GtkTreeItem *tree_item)
416 {
417   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
418
419   if (tree_item->pixmaps)
420     {
421       GtkTreePixmaps *pixmap_node = (GtkTreePixmaps *)tree_item->pixmaps->data;
422       
423       g_assert (pixmap_node->refcount > 0);
424       
425       if (--pixmap_node->refcount == 0)
426         {
427           g_object_unref (pixmap_node->colormap);
428           g_object_unref (pixmap_node->pixmap_plus);
429           g_object_unref (pixmap_node->mask_plus);
430           g_object_unref (pixmap_node->pixmap_minus);
431           g_object_unref (pixmap_node->mask_minus);
432           
433           pixmaps = g_list_remove_link (pixmaps, tree_item->pixmaps);
434           g_list_free_1 (tree_item->pixmaps);
435           g_free (pixmap_node);
436         }
437
438       tree_item->pixmaps = NULL;
439     }
440 }
441
442 static void
443 gtk_tree_item_realize (GtkWidget *widget)
444 {    
445   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
446
447   if (GTK_WIDGET_CLASS (parent_class)->realize)
448     (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
449   
450   gdk_window_set_background (widget->window, 
451                              &widget->style->base[GTK_STATE_NORMAL]);
452
453   gtk_tree_item_add_pixmaps (GTK_TREE_ITEM (widget));
454 }
455
456 static void
457 gtk_tree_item_size_request (GtkWidget      *widget,
458                             GtkRequisition *requisition)
459 {
460   GtkBin *bin;
461   GtkTreeItem* item;
462   GtkRequisition child_requisition;
463
464   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
465   g_return_if_fail (requisition != NULL);
466
467   bin = GTK_BIN (widget);
468   item = GTK_TREE_ITEM(widget);
469
470   requisition->width = (GTK_CONTAINER (widget)->border_width +
471                         widget->style->xthickness) * 2;
472   requisition->height = GTK_CONTAINER (widget)->border_width * 2;
473
474   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
475     {
476       GtkRequisition pix_requisition;
477       
478       gtk_widget_size_request (bin->child, &child_requisition);
479
480       requisition->width += child_requisition.width;
481
482       gtk_widget_size_request (item->pixmaps_box, 
483                                &pix_requisition);
484       requisition->width += pix_requisition.width + DEFAULT_DELTA + 
485         GTK_TREE (widget->parent)->current_indent;
486
487       requisition->height += MAX (child_requisition.height,
488                                   pix_requisition.height);
489     }
490 }
491
492 static void
493 gtk_tree_item_size_allocate (GtkWidget     *widget,
494                              GtkAllocation *allocation)
495 {
496   GtkBin *bin;
497   GtkTreeItem* item;
498   GtkAllocation child_allocation;
499   gint border_width;
500   int temp;
501
502   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
503   g_return_if_fail (allocation != NULL);
504
505   widget->allocation = *allocation;
506   if (GTK_WIDGET_REALIZED (widget))
507     gdk_window_move_resize (widget->window,
508                             allocation->x, allocation->y,
509                             allocation->width, allocation->height);
510
511   bin = GTK_BIN (widget);
512   item = GTK_TREE_ITEM(widget);
513
514   if (bin->child)
515     {
516       border_width = (GTK_CONTAINER (widget)->border_width +
517                       widget->style->xthickness);
518
519       child_allocation.x = border_width + GTK_TREE(widget->parent)->current_indent;
520       child_allocation.y = GTK_CONTAINER (widget)->border_width;
521
522       child_allocation.width = item->pixmaps_box->requisition.width;
523       child_allocation.height = item->pixmaps_box->requisition.height;
524       
525       temp = allocation->height - child_allocation.height;
526       child_allocation.y += ( temp / 2 ) + ( temp % 2 );
527
528       gtk_widget_size_allocate (item->pixmaps_box, &child_allocation);
529
530       child_allocation.y = GTK_CONTAINER (widget)->border_width;
531       child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
532       child_allocation.x += item->pixmaps_box->requisition.width+DEFAULT_DELTA;
533
534       child_allocation.width = 
535         MAX (1, (gint)allocation->width - ((gint)child_allocation.x + border_width));
536
537       gtk_widget_size_allocate (bin->child, &child_allocation);
538     }
539 }
540
541 static void 
542 gtk_tree_item_draw_lines (GtkWidget *widget) 
543 {
544   GtkTreeItem* item;
545   GtkTree* tree;
546   guint lx1, ly1, lx2, ly2;
547   GdkGC* gc;
548
549   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
550
551   item = GTK_TREE_ITEM(widget);
552   tree = GTK_TREE(widget->parent);
553
554   if (!tree->view_line)
555     return;
556
557   gc = widget->style->text_gc[GTK_STATE_NORMAL];
558
559   /* draw vertical line */
560   lx1 = item->pixmaps_box->allocation.width;
561   lx1 = lx2 = ((lx1 / 2) + (lx1 % 2) + 
562                GTK_CONTAINER (widget)->border_width + 1 + tree->current_indent);
563   ly1 = 0;
564   ly2 = widget->allocation.height;
565
566   if (g_list_last (tree->children)->data == widget)
567     ly2 = (ly2 / 2) + (ly2 % 2);
568
569   if (tree != tree->root_tree)
570     gdk_draw_line (widget->window, gc, lx1, ly1, lx2, ly2);
571
572   /* draw vertical line for subtree connecting */
573   if(g_list_last(tree->children)->data != (gpointer)widget)
574     ly2 = (ly2 / 2) + (ly2 % 2);
575   
576   lx2 += DEFAULT_DELTA;
577
578   if (item->subtree && item->expanded)
579     gdk_draw_line (widget->window, gc,
580                    lx2, ly2, lx2, widget->allocation.height);
581
582   /* draw horizontal line */
583   ly1 = ly2;
584   lx2 += 2;
585
586   gdk_draw_line (widget->window, gc, lx1, ly1, lx2, ly2);
587
588   lx2 -= DEFAULT_DELTA+2;
589   ly1 = 0;
590   ly2 = widget->allocation.height;
591
592   if (tree != tree->root_tree)
593     {
594       item = GTK_TREE_ITEM (tree->tree_owner);
595       tree = GTK_TREE (GTK_WIDGET (tree)->parent);
596       while (tree != tree->root_tree)
597         {
598           lx1 = lx2 -= tree->indent_value;
599           
600           if (g_list_last (tree->children)->data != item)
601             gdk_draw_line (widget->window, gc, lx1, ly1, lx2, ly2);
602           item = GTK_TREE_ITEM (tree->tree_owner);
603           tree = GTK_TREE (GTK_WIDGET (tree)->parent);
604         } 
605     }
606 }
607
608 static void
609 gtk_tree_item_paint (GtkWidget    *widget,
610                      GdkRectangle *area)
611 {
612   GdkRectangle child_area, item_area;
613   GtkTreeItem* tree_item;
614
615   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
616   g_return_if_fail (area != NULL);
617
618   /* FIXME: We should honor tree->view_mode, here - I think
619    * the desired effect is that when the mode is VIEW_ITEM,
620    * only the subitem is drawn as selected, not the entire
621    * line. (Like the way that the tree in Windows Explorer
622    * works).
623    */
624   if (GTK_WIDGET_DRAWABLE (widget))
625     {
626       tree_item = GTK_TREE_ITEM(widget);
627
628       if (widget->state == GTK_STATE_NORMAL)
629         {
630           gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
631           gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height);
632         }
633       else 
634         {
635           if (!GTK_WIDGET_IS_SENSITIVE (widget)) 
636             gtk_paint_flat_box(widget->style, widget->window,
637                                widget->state, GTK_SHADOW_NONE,
638                                area, widget, "treeitem",
639                                0, 0, -1, -1);
640           else
641             gtk_paint_flat_box(widget->style, widget->window,
642                                widget->state, GTK_SHADOW_ETCHED_OUT,
643                                area, widget, "treeitem",
644                                0, 0, -1, -1);
645         }
646
647       /* draw left size of tree item */
648       item_area.x = 0;
649       item_area.y = 0;
650       item_area.width = (tree_item->pixmaps_box->allocation.width + DEFAULT_DELTA +
651                          GTK_TREE (widget->parent)->current_indent + 2);
652       item_area.height = widget->allocation.height;
653
654
655       if (gdk_rectangle_intersect(&item_area, area, &child_area)) 
656         {
657           
658           gtk_tree_item_draw_lines(widget);
659
660           if (tree_item->pixmaps_box && 
661               GTK_WIDGET_VISIBLE(tree_item->pixmaps_box) &&
662               gtk_widget_intersect (tree_item->pixmaps_box, area, &child_area))
663             gtk_widget_draw (tree_item->pixmaps_box, &child_area);
664         }
665
666       if (GTK_WIDGET_HAS_FOCUS (widget))
667         gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
668                          NULL, widget, "treeitem",
669                          0, 0,
670                          widget->allocation.width,
671                          widget->allocation.height);
672       
673     }
674 }
675
676 static gint
677 gtk_tree_item_button_press (GtkWidget      *widget,
678                             GdkEventButton *event)
679 {
680
681   g_return_val_if_fail (GTK_IS_TREE_ITEM (widget), FALSE);
682   g_return_val_if_fail (event != NULL, FALSE);
683
684   if (event->type == GDK_BUTTON_PRESS
685         && GTK_WIDGET_IS_SENSITIVE(widget)
686         && !GTK_WIDGET_HAS_FOCUS (widget))
687       gtk_widget_grab_focus (widget);
688
689   return (event->type == GDK_BUTTON_PRESS && GTK_WIDGET_IS_SENSITIVE(widget));
690 }
691
692 static void
693 gtk_tree_item_expose_child (GtkWidget *child,
694                             gpointer   client_data)
695 {
696   struct {
697     GtkWidget *container;
698     GdkEventExpose *event;
699   } *data = client_data;
700
701   if (GTK_WIDGET_DRAWABLE (child) &&
702       GTK_WIDGET_NO_WINDOW (child) &&
703       (child->window == data->event->window))
704     {
705       GdkEvent *child_event = gdk_event_new (GDK_EXPOSE);
706       child_event->expose = *data->event;
707       g_object_ref (child_event->expose.window);
708
709       child_event->expose.region = gtk_widget_region_intersect (child,
710                                                                 data->event->region);
711       if (!gdk_region_empty (child_event->expose.region))
712         {
713           gdk_region_get_clipbox (child_event->expose.region, &child_event->expose.area);
714           gtk_widget_send_expose (child, child_event);
715         }
716       gdk_event_free (child_event);
717     }
718 }
719
720 static gint
721 gtk_tree_item_expose (GtkWidget      *widget,
722                       GdkEventExpose *event)
723 {
724   struct {
725     GtkWidget *container;
726     GdkEventExpose *event;
727   } data;
728   
729   g_return_val_if_fail (GTK_IS_TREE_ITEM (widget), FALSE);
730   g_return_val_if_fail (event != NULL, FALSE);
731
732   if (GTK_WIDGET_DRAWABLE (widget))
733     {
734       gtk_tree_item_paint (widget, &event->area);
735
736       data.container = widget;
737       data.event = event;
738
739       gtk_container_forall (GTK_CONTAINER (widget),
740                             gtk_tree_item_expose_child,
741                             &data);
742    }
743
744   return FALSE;
745 }
746
747 static void
748 gtk_real_tree_item_select (GtkItem *item)
749 {    
750   GtkWidget *widget;
751
752   g_return_if_fail (GTK_IS_TREE_ITEM (item));
753
754   widget = GTK_WIDGET (item);
755
756   gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
757
758   if (!widget->parent || GTK_TREE (widget->parent)->view_mode == GTK_TREE_VIEW_LINE)
759     gtk_widget_set_state (GTK_TREE_ITEM (item)->pixmaps_box, GTK_STATE_SELECTED);
760 }
761
762 static void
763 gtk_real_tree_item_deselect (GtkItem *item)
764 {
765   GtkTreeItem *tree_item;
766   GtkWidget *widget;
767
768   g_return_if_fail (GTK_IS_TREE_ITEM (item));
769
770   tree_item = GTK_TREE_ITEM (item);
771   widget = GTK_WIDGET (item);
772
773   gtk_widget_set_state (widget, GTK_STATE_NORMAL);
774
775   if (!widget->parent || GTK_TREE (widget->parent)->view_mode == GTK_TREE_VIEW_LINE)
776     gtk_widget_set_state (tree_item->pixmaps_box, GTK_STATE_NORMAL);
777 }
778
779 static void
780 gtk_real_tree_item_toggle (GtkItem *item)
781 {
782   g_return_if_fail (GTK_IS_TREE_ITEM (item));
783
784   if(!GTK_WIDGET_IS_SENSITIVE(item))
785     return;
786
787   if (GTK_WIDGET (item)->parent && GTK_IS_TREE (GTK_WIDGET (item)->parent))
788     gtk_tree_select_child (GTK_TREE (GTK_WIDGET (item)->parent),
789                            GTK_WIDGET (item));
790   else
791     {
792       /* Should we really bother with this bit? A listitem not in a list?
793        * -Johannes Keukelaar
794        * yes, always be on the safe side!
795        * -timj
796        */
797       if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED)
798         gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL);
799       else
800         gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
801     }
802 }
803
804 static void
805 gtk_real_tree_item_expand (GtkTreeItem *tree_item)
806 {
807   GtkTree* tree;
808   
809   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
810   
811   if (tree_item->subtree && !tree_item->expanded)
812     {
813       tree = GTK_TREE (GTK_WIDGET (tree_item)->parent); 
814       
815       /* hide subtree widget */
816       gtk_widget_show (tree_item->subtree);
817       
818       /* hide button '+' and show button '-' */
819       if (tree_item->pixmaps_box)
820         {
821           gtk_container_remove (GTK_CONTAINER (tree_item->pixmaps_box), 
822                                 tree_item->plus_pix_widget);
823           gtk_container_add (GTK_CONTAINER (tree_item->pixmaps_box), 
824                              tree_item->minus_pix_widget);
825         }
826       if (tree->root_tree)
827         gtk_widget_queue_resize (GTK_WIDGET (tree->root_tree));
828       tree_item->expanded = TRUE;
829     }
830 }
831
832 static void
833 gtk_real_tree_item_collapse (GtkTreeItem *tree_item)
834 {
835   GtkTree* tree;
836   
837   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
838   
839   if (tree_item->subtree && tree_item->expanded) 
840     {
841       tree = GTK_TREE (GTK_WIDGET (tree_item)->parent);
842       
843       /* hide subtree widget */
844       gtk_widget_hide (tree_item->subtree);
845       
846       /* hide button '-' and show button '+' */
847       if (tree_item->pixmaps_box)
848         {
849           gtk_container_remove (GTK_CONTAINER (tree_item->pixmaps_box), 
850                                 tree_item->minus_pix_widget);
851           gtk_container_add (GTK_CONTAINER (tree_item->pixmaps_box), 
852                              tree_item->plus_pix_widget);
853         }
854       if (tree->root_tree)
855         gtk_widget_queue_resize (GTK_WIDGET (tree->root_tree));
856       tree_item->expanded = FALSE;
857     }
858 }
859
860 static void
861 gtk_tree_item_destroy (GtkObject *object)
862 {
863   GtkTreeItem* item;
864   GtkWidget* child;
865
866   g_return_if_fail (GTK_IS_TREE_ITEM (object));
867
868 #ifdef TREE_DEBUG
869   g_message("+ gtk_tree_item_destroy [object %#x]\n", (int)object);
870 #endif /* TREE_DEBUG */
871
872   item = GTK_TREE_ITEM(object);
873
874   /* free sub tree if it exist */
875   child = item->subtree;
876   if (child)
877     {
878       gtk_widget_ref (child);
879       gtk_widget_unparent (child);
880       gtk_widget_destroy (child);
881       gtk_widget_unref (child);
882       item->subtree = NULL;
883     }
884   
885   /* free pixmaps box */
886   child = item->pixmaps_box;
887   if (child)
888     {
889       gtk_widget_ref (child);
890       gtk_widget_unparent (child);
891       gtk_widget_destroy (child);
892       gtk_widget_unref (child);
893       item->pixmaps_box = NULL;
894     }
895   
896   
897   /* destroy plus pixmap */
898   if (item->plus_pix_widget)
899     {
900       gtk_widget_destroy (item->plus_pix_widget);
901       gtk_widget_unref (item->plus_pix_widget);
902       item->plus_pix_widget = NULL;
903     }
904   
905   /* destroy minus pixmap */
906   if (item->minus_pix_widget)
907     {
908       gtk_widget_destroy (item->minus_pix_widget);
909       gtk_widget_unref (item->minus_pix_widget);
910       item->minus_pix_widget = NULL;
911     }
912   
913   /* By removing the pixmaps here, and not in unrealize, we depend on
914    * the fact that a widget can never change colormap or visual.
915    */
916   gtk_tree_item_remove_pixmaps (item);
917   
918   GTK_OBJECT_CLASS (parent_class)->destroy (object);
919   
920 #ifdef TREE_DEBUG
921   g_message("- gtk_tree_item_destroy\n");
922 #endif /* TREE_DEBUG */
923 }
924
925 void
926 gtk_tree_item_remove_subtree (GtkTreeItem* item) 
927 {
928   g_return_if_fail (GTK_IS_TREE_ITEM(item));
929   g_return_if_fail (item->subtree != NULL);
930   
931   if (GTK_TREE (item->subtree)->children)
932     {
933       /* The following call will remove the children and call
934        * gtk_tree_item_remove_subtree() again. So we are done.
935        */
936       gtk_tree_remove_items (GTK_TREE (item->subtree), 
937                              GTK_TREE (item->subtree)->children);
938       return;
939     }
940
941   if (GTK_WIDGET_MAPPED (item->subtree))
942     gtk_widget_unmap (item->subtree);
943       
944   gtk_widget_unparent (item->subtree);
945   
946   if (item->pixmaps_box)
947     gtk_widget_hide (item->pixmaps_box);
948   
949   item->subtree = NULL;
950
951   if (item->expanded)
952     {
953       item->expanded = FALSE;
954       if (item->pixmaps_box)
955         {
956           gtk_container_remove (GTK_CONTAINER (item->pixmaps_box), 
957                                 item->minus_pix_widget);
958           gtk_container_add (GTK_CONTAINER (item->pixmaps_box), 
959                              item->plus_pix_widget);
960         }
961     }
962 }
963
964 static void
965 gtk_tree_item_map (GtkWidget *widget)
966 {
967   GtkBin *bin;
968   GtkTreeItem* item;
969
970   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
971
972   bin = GTK_BIN (widget);
973   item = GTK_TREE_ITEM(widget);
974
975   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
976
977   if(item->pixmaps_box &&
978      GTK_WIDGET_VISIBLE (item->pixmaps_box) &&
979      !GTK_WIDGET_MAPPED (item->pixmaps_box))
980     gtk_widget_map (item->pixmaps_box);
981
982   if (bin->child &&
983       GTK_WIDGET_VISIBLE (bin->child) &&
984       !GTK_WIDGET_MAPPED (bin->child))
985     gtk_widget_map (bin->child);
986
987   gdk_window_show (widget->window);
988 }
989
990 static void
991 gtk_tree_item_unmap (GtkWidget *widget)
992 {
993   GtkBin *bin;
994   GtkTreeItem* item;
995
996   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
997
998   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
999   bin = GTK_BIN (widget);
1000   item = GTK_TREE_ITEM(widget);
1001
1002   gdk_window_hide (widget->window);
1003
1004   if(item->pixmaps_box &&
1005      GTK_WIDGET_VISIBLE (item->pixmaps_box) &&
1006      GTK_WIDGET_MAPPED (item->pixmaps_box))
1007     gtk_widget_unmap (bin->child);
1008
1009   if (bin->child &&
1010       GTK_WIDGET_VISIBLE (bin->child) &&
1011       GTK_WIDGET_MAPPED (bin->child))
1012     gtk_widget_unmap (bin->child);
1013 }
1014
1015 static void
1016 gtk_tree_item_forall (GtkContainer *container,
1017                       gboolean      include_internals,
1018                       GtkCallback   callback,
1019                       gpointer      callback_data)
1020 {
1021   GtkBin *bin;
1022   GtkTreeItem *tree_item;
1023
1024   g_return_if_fail (GTK_IS_TREE_ITEM (container));
1025   g_return_if_fail (callback != NULL);
1026
1027   bin = GTK_BIN (container);
1028   tree_item = GTK_TREE_ITEM (container);
1029
1030   if (bin->child)
1031     (* callback) (bin->child, callback_data);
1032   if (include_internals && tree_item->subtree)
1033     (* callback) (tree_item->subtree, callback_data);
1034   if (include_internals && tree_item->pixmaps_box)
1035     (* callback) (tree_item->pixmaps_box, callback_data);
1036 }
1037
1038 #define __GTK_TREE_ITEM_C__
1039 #include "gtkaliasdef.c"