]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeitem.c
Fix make check:
[~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
31 #include "gtklabel.h"
32 #include "gtkeventbox.h"
33 #include "gtkpixmap.h"
34 #include "gtkmain.h"
35 #include "gtkmarshalers.h"
36 #include "gtksignal.h"
37 #define GTK_ENABLE_BROKEN
38 #include "gtktree.h"
39 #include "gtktreeitem.h"
40 #include "gtkintl.h"
41
42 #include "gtkalias.h"
43
44 #include "tree_plus.xpm"
45 #include "tree_minus.xpm"
46
47 #define DEFAULT_DELTA 9
48
49 enum {
50   COLLAPSE_TREE,
51   EXPAND_TREE,
52   LAST_SIGNAL
53 };
54
55 typedef struct _GtkTreePixmaps GtkTreePixmaps;
56
57 struct _GtkTreePixmaps {
58   gint refcount;
59   GdkColormap *colormap;
60   
61   GdkPixmap *pixmap_plus;
62   GdkPixmap *pixmap_minus;
63   GdkBitmap *mask_plus;
64   GdkBitmap *mask_minus;
65 };
66
67 static GList *pixmaps = NULL;
68
69 static void gtk_tree_item_class_init (GtkTreeItemClass *klass);
70 static void gtk_tree_item_init       (GtkTreeItem      *tree_item);
71 static void gtk_tree_item_realize       (GtkWidget        *widget);
72 static void gtk_tree_item_size_request  (GtkWidget        *widget,
73                                          GtkRequisition   *requisition);
74 static void gtk_tree_item_size_allocate (GtkWidget        *widget,
75                                          GtkAllocation    *allocation);
76 static void gtk_tree_item_paint         (GtkWidget        *widget,
77                                          GdkRectangle     *area);
78 static gint gtk_tree_item_button_press  (GtkWidget        *widget,
79                                          GdkEventButton   *event);
80 static gint gtk_tree_item_expose        (GtkWidget        *widget,
81                                          GdkEventExpose   *event);
82 static void gtk_tree_item_forall        (GtkContainer    *container,
83                                          gboolean         include_internals,
84                                          GtkCallback      callback,
85                                          gpointer         callback_data);
86
87 static void gtk_real_tree_item_select   (GtkItem          *item);
88 static void gtk_real_tree_item_deselect (GtkItem          *item);
89 static void gtk_real_tree_item_toggle   (GtkItem          *item);
90 static void gtk_real_tree_item_expand   (GtkTreeItem      *item);
91 static void gtk_real_tree_item_collapse (GtkTreeItem      *item);
92 static void gtk_tree_item_destroy        (GtkObject *object);
93 static gint gtk_tree_item_subtree_button_click (GtkWidget *widget);
94 static void gtk_tree_item_subtree_button_changed_state (GtkWidget *widget);
95
96 static void gtk_tree_item_map(GtkWidget*);
97 static void gtk_tree_item_unmap(GtkWidget*);
98
99 static void gtk_tree_item_add_pixmaps    (GtkTreeItem       *tree_item);
100 static void gtk_tree_item_remove_pixmaps (GtkTreeItem       *tree_item);
101
102 static GtkItemClass *parent_class = NULL;
103 static guint tree_item_signals[LAST_SIGNAL] = { 0 };
104
105 GtkType
106 gtk_tree_item_get_type (void)
107 {
108   static GtkType tree_item_type = 0;
109
110   if (!tree_item_type)
111     {
112       static const GtkTypeInfo tree_item_info =
113       {
114         "GtkTreeItem",
115         sizeof (GtkTreeItem),
116         sizeof (GtkTreeItemClass),
117         (GtkClassInitFunc) gtk_tree_item_class_init,
118         (GtkObjectInitFunc) gtk_tree_item_init,
119         /* reserved_1 */ NULL,
120         /* reserved_2 */ NULL,
121         (GtkClassInitFunc) NULL,
122       };
123
124       I_("GtkTreeItem");
125       tree_item_type = gtk_type_unique (gtk_item_get_type (), &tree_item_info);
126     }
127
128   return tree_item_type;
129 }
130
131 static void
132 gtk_tree_item_class_init (GtkTreeItemClass *class)
133 {
134   GtkObjectClass *object_class;
135   GtkWidgetClass *widget_class;
136   GtkContainerClass *container_class;
137   GtkItemClass *item_class;
138
139   parent_class = gtk_type_class (GTK_TYPE_ITEM);
140   
141   object_class = (GtkObjectClass*) class;
142   widget_class = (GtkWidgetClass*) class;
143   item_class = (GtkItemClass*) class;
144   container_class = (GtkContainerClass*) class;
145
146   object_class->destroy = gtk_tree_item_destroy;
147
148   widget_class->realize = gtk_tree_item_realize;
149   widget_class->size_request = gtk_tree_item_size_request;
150   widget_class->size_allocate = gtk_tree_item_size_allocate;
151   widget_class->button_press_event = gtk_tree_item_button_press;
152   widget_class->expose_event = gtk_tree_item_expose;
153   widget_class->map = gtk_tree_item_map;
154   widget_class->unmap = gtk_tree_item_unmap;
155
156   container_class->forall = gtk_tree_item_forall;
157
158   item_class->select = gtk_real_tree_item_select;
159   item_class->deselect = gtk_real_tree_item_deselect;
160   item_class->toggle = gtk_real_tree_item_toggle;
161
162   class->expand = gtk_real_tree_item_expand;
163   class->collapse = gtk_real_tree_item_collapse;
164
165   tree_item_signals[EXPAND_TREE] =
166     gtk_signal_new (I_("expand"),
167                     GTK_RUN_FIRST,
168                     GTK_CLASS_TYPE (object_class),
169                     GTK_SIGNAL_OFFSET (GtkTreeItemClass, expand),
170                     _gtk_marshal_VOID__VOID,
171                     GTK_TYPE_NONE, 0);
172   tree_item_signals[COLLAPSE_TREE] =
173     gtk_signal_new (I_("collapse"),
174                     GTK_RUN_FIRST,
175                     GTK_CLASS_TYPE (object_class),
176                     GTK_SIGNAL_OFFSET (GtkTreeItemClass, collapse),
177                     _gtk_marshal_VOID__VOID,
178                     GTK_TYPE_NONE, 0);
179 }
180
181 /* callback for event box mouse event */
182 static gint
183 gtk_tree_item_subtree_button_click (GtkWidget *widget)
184 {
185   GtkTreeItem* item;
186   
187   g_return_val_if_fail (GTK_IS_EVENT_BOX (widget), FALSE);
188   
189   item = (GtkTreeItem*) gtk_object_get_user_data (GTK_OBJECT (widget));
190   if (!GTK_WIDGET_IS_SENSITIVE (item))
191     return FALSE;
192   
193   if (item->expanded)
194     gtk_tree_item_collapse (item);
195   else
196     gtk_tree_item_expand (item);
197
198   return TRUE;
199 }
200
201 /* callback for event box state changed */
202 static void
203 gtk_tree_item_subtree_button_changed_state (GtkWidget *widget)
204 {
205   g_return_if_fail (GTK_IS_EVENT_BOX (widget));
206   
207   if (GTK_WIDGET_VISIBLE (widget))
208     {
209       
210       if (widget->state == GTK_STATE_NORMAL)
211         gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
212       else
213         gdk_window_set_background (widget->window, &widget->style->bg[widget->state]);
214       
215       if (GTK_WIDGET_DRAWABLE (widget))
216         gdk_window_clear_area (widget->window, 0, 0, 
217                                widget->allocation.width, widget->allocation.height);
218     }
219 }
220
221 static void
222 gtk_tree_item_init (GtkTreeItem *tree_item)
223 {
224   GtkWidget *eventbox, *pixmapwid;
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   if (GTK_WIDGET_CLASS (parent_class)->realize)
446     (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
447   
448   gdk_window_set_background (widget->window, 
449                              &widget->style->base[GTK_STATE_NORMAL]);
450
451   gtk_tree_item_add_pixmaps (GTK_TREE_ITEM (widget));
452 }
453
454 static void
455 gtk_tree_item_size_request (GtkWidget      *widget,
456                             GtkRequisition *requisition)
457 {
458   GtkBin *bin = GTK_BIN (widget);
459   GtkTreeItem *item = GTK_TREE_ITEM (widget);
460   GtkRequisition child_requisition;
461
462   requisition->width = (GTK_CONTAINER (widget)->border_width +
463                         widget->style->xthickness) * 2;
464   requisition->height = GTK_CONTAINER (widget)->border_width * 2;
465
466   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
467     {
468       GtkRequisition pix_requisition;
469       
470       gtk_widget_size_request (bin->child, &child_requisition);
471
472       requisition->width += child_requisition.width;
473
474       gtk_widget_size_request (item->pixmaps_box, 
475                                &pix_requisition);
476       requisition->width += pix_requisition.width + DEFAULT_DELTA + 
477         GTK_TREE (widget->parent)->current_indent;
478
479       requisition->height += MAX (child_requisition.height,
480                                   pix_requisition.height);
481     }
482 }
483
484 static void
485 gtk_tree_item_size_allocate (GtkWidget     *widget,
486                              GtkAllocation *allocation)
487 {
488   GtkBin *bin = GTK_BIN (widget);
489   GtkTreeItem *item = GTK_TREE_ITEM (widget);
490   GtkAllocation child_allocation;
491   gint border_width;
492   int temp;
493
494   widget->allocation = *allocation;
495   if (GTK_WIDGET_REALIZED (widget))
496     gdk_window_move_resize (widget->window,
497                             allocation->x, allocation->y,
498                             allocation->width, allocation->height);
499
500   if (bin->child)
501     {
502       border_width = (GTK_CONTAINER (widget)->border_width +
503                       widget->style->xthickness);
504
505       child_allocation.x = border_width + GTK_TREE(widget->parent)->current_indent;
506       child_allocation.y = GTK_CONTAINER (widget)->border_width;
507
508       child_allocation.width = item->pixmaps_box->requisition.width;
509       child_allocation.height = item->pixmaps_box->requisition.height;
510       
511       temp = allocation->height - child_allocation.height;
512       child_allocation.y += ( temp / 2 ) + ( temp % 2 );
513
514       gtk_widget_size_allocate (item->pixmaps_box, &child_allocation);
515
516       child_allocation.y = GTK_CONTAINER (widget)->border_width;
517       child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
518       child_allocation.x += item->pixmaps_box->requisition.width+DEFAULT_DELTA;
519
520       child_allocation.width = 
521         MAX (1, (gint)allocation->width - ((gint)child_allocation.x + border_width));
522
523       gtk_widget_size_allocate (bin->child, &child_allocation);
524     }
525 }
526
527 static void 
528 gtk_tree_item_draw_lines (GtkWidget *widget) 
529 {
530   GtkTreeItem* item;
531   GtkTree* tree;
532   guint lx1, ly1, lx2, ly2;
533   GdkGC* gc;
534
535   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
536
537   item = GTK_TREE_ITEM(widget);
538   tree = GTK_TREE(widget->parent);
539
540   if (!tree->view_line)
541     return;
542
543   gc = widget->style->text_gc[GTK_STATE_NORMAL];
544
545   /* draw vertical line */
546   lx1 = item->pixmaps_box->allocation.width;
547   lx1 = lx2 = ((lx1 / 2) + (lx1 % 2) + 
548                GTK_CONTAINER (widget)->border_width + 1 + tree->current_indent);
549   ly1 = 0;
550   ly2 = widget->allocation.height;
551
552   if (g_list_last (tree->children)->data == widget)
553     ly2 = (ly2 / 2) + (ly2 % 2);
554
555   if (tree != tree->root_tree)
556     gdk_draw_line (widget->window, gc, lx1, ly1, lx2, ly2);
557
558   /* draw vertical line for subtree connecting */
559   if(g_list_last(tree->children)->data != (gpointer)widget)
560     ly2 = (ly2 / 2) + (ly2 % 2);
561   
562   lx2 += DEFAULT_DELTA;
563
564   if (item->subtree && item->expanded)
565     gdk_draw_line (widget->window, gc,
566                    lx2, ly2, lx2, widget->allocation.height);
567
568   /* draw horizontal line */
569   ly1 = ly2;
570   lx2 += 2;
571
572   gdk_draw_line (widget->window, gc, lx1, ly1, lx2, ly2);
573
574   lx2 -= DEFAULT_DELTA+2;
575   ly1 = 0;
576   ly2 = widget->allocation.height;
577
578   if (tree != tree->root_tree)
579     {
580       item = GTK_TREE_ITEM (tree->tree_owner);
581       tree = GTK_TREE (GTK_WIDGET (tree)->parent);
582       while (tree != tree->root_tree)
583         {
584           lx1 = lx2 -= tree->indent_value;
585           
586           if (g_list_last (tree->children)->data != item)
587             gdk_draw_line (widget->window, gc, lx1, ly1, lx2, ly2);
588           item = GTK_TREE_ITEM (tree->tree_owner);
589           tree = GTK_TREE (GTK_WIDGET (tree)->parent);
590         } 
591     }
592 }
593
594 static void
595 gtk_tree_item_paint (GtkWidget    *widget,
596                      GdkRectangle *area)
597 {
598   GdkRectangle child_area, item_area;
599   GtkTreeItem* tree_item;
600
601   /* FIXME: We should honor tree->view_mode, here - I think
602    * the desired effect is that when the mode is VIEW_ITEM,
603    * only the subitem is drawn as selected, not the entire
604    * line. (Like the way that the tree in Windows Explorer
605    * works).
606    */
607   if (GTK_WIDGET_DRAWABLE (widget))
608     {
609       tree_item = GTK_TREE_ITEM(widget);
610
611       if (widget->state == GTK_STATE_NORMAL)
612         {
613           gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
614           gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height);
615         }
616       else 
617         {
618           if (!GTK_WIDGET_IS_SENSITIVE (widget)) 
619             gtk_paint_flat_box(widget->style, widget->window,
620                                widget->state, GTK_SHADOW_NONE,
621                                area, widget, "treeitem",
622                                0, 0, -1, -1);
623           else
624             gtk_paint_flat_box(widget->style, widget->window,
625                                widget->state, GTK_SHADOW_ETCHED_OUT,
626                                area, widget, "treeitem",
627                                0, 0, -1, -1);
628         }
629
630       /* draw left size of tree item */
631       item_area.x = 0;
632       item_area.y = 0;
633       item_area.width = (tree_item->pixmaps_box->allocation.width + DEFAULT_DELTA +
634                          GTK_TREE (widget->parent)->current_indent + 2);
635       item_area.height = widget->allocation.height;
636
637
638       if (gdk_rectangle_intersect(&item_area, area, &child_area)) 
639         {
640           
641           gtk_tree_item_draw_lines(widget);
642
643           if (tree_item->pixmaps_box && 
644               GTK_WIDGET_VISIBLE(tree_item->pixmaps_box) &&
645               gtk_widget_intersect (tree_item->pixmaps_box, area, &child_area))
646             gtk_widget_draw (tree_item->pixmaps_box, &child_area);
647         }
648
649       if (GTK_WIDGET_HAS_FOCUS (widget))
650         gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
651                          NULL, widget, "treeitem",
652                          0, 0,
653                          widget->allocation.width,
654                          widget->allocation.height);
655       
656     }
657 }
658
659 static gint
660 gtk_tree_item_button_press (GtkWidget      *widget,
661                             GdkEventButton *event)
662 {
663   if (event->type == GDK_BUTTON_PRESS
664         && GTK_WIDGET_IS_SENSITIVE(widget)
665         && !GTK_WIDGET_HAS_FOCUS (widget))
666       gtk_widget_grab_focus (widget);
667
668   return (event->type == GDK_BUTTON_PRESS && GTK_WIDGET_IS_SENSITIVE(widget));
669 }
670
671 static void
672 gtk_tree_item_expose_child (GtkWidget *child,
673                             gpointer   client_data)
674 {
675   struct {
676     GtkWidget *container;
677     GdkEventExpose *event;
678   } *data = client_data;
679
680   if (GTK_WIDGET_DRAWABLE (child) &&
681       GTK_WIDGET_NO_WINDOW (child) &&
682       (child->window == data->event->window))
683     {
684       GdkEvent *child_event = gdk_event_new (GDK_EXPOSE);
685       child_event->expose = *data->event;
686       g_object_ref (child_event->expose.window);
687
688       child_event->expose.region = gtk_widget_region_intersect (child,
689                                                                 data->event->region);
690       if (!gdk_region_empty (child_event->expose.region))
691         {
692           gdk_region_get_clipbox (child_event->expose.region, &child_event->expose.area);
693           gtk_widget_send_expose (child, child_event);
694         }
695       gdk_event_free (child_event);
696     }
697 }
698
699 static gint
700 gtk_tree_item_expose (GtkWidget      *widget,
701                       GdkEventExpose *event)
702 {
703   struct {
704     GtkWidget *container;
705     GdkEventExpose *event;
706   } data;
707
708   if (GTK_WIDGET_DRAWABLE (widget))
709     {
710       gtk_tree_item_paint (widget, &event->area);
711
712       data.container = widget;
713       data.event = event;
714
715       gtk_container_forall (GTK_CONTAINER (widget),
716                             gtk_tree_item_expose_child,
717                             &data);
718    }
719
720   return FALSE;
721 }
722
723 static void
724 gtk_real_tree_item_select (GtkItem *item)
725 {
726   GtkWidget *widget;
727
728   g_return_if_fail (GTK_IS_TREE_ITEM (item));
729
730   widget = GTK_WIDGET (item);
731
732   gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
733
734   if (!widget->parent || GTK_TREE (widget->parent)->view_mode == GTK_TREE_VIEW_LINE)
735     gtk_widget_set_state (GTK_TREE_ITEM (item)->pixmaps_box, GTK_STATE_SELECTED);
736 }
737
738 static void
739 gtk_real_tree_item_deselect (GtkItem *item)
740 {
741   GtkTreeItem *tree_item;
742   GtkWidget *widget;
743
744   g_return_if_fail (GTK_IS_TREE_ITEM (item));
745
746   tree_item = GTK_TREE_ITEM (item);
747   widget = GTK_WIDGET (item);
748
749   gtk_widget_set_state (widget, GTK_STATE_NORMAL);
750
751   if (!widget->parent || GTK_TREE (widget->parent)->view_mode == GTK_TREE_VIEW_LINE)
752     gtk_widget_set_state (tree_item->pixmaps_box, GTK_STATE_NORMAL);
753 }
754
755 static void
756 gtk_real_tree_item_toggle (GtkItem *item)
757 {
758   g_return_if_fail (GTK_IS_TREE_ITEM (item));
759
760   if(!GTK_WIDGET_IS_SENSITIVE(item))
761     return;
762
763   if (GTK_IS_TREE (GTK_WIDGET (item)->parent))
764     gtk_tree_select_child (GTK_TREE (GTK_WIDGET (item)->parent),
765                            GTK_WIDGET (item));
766   else
767     {
768       /* Should we really bother with this bit? A listitem not in a list?
769        * -Johannes Keukelaar
770        * yes, always be on the safe side!
771        * -timj
772        */
773       if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED)
774         gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL);
775       else
776         gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
777     }
778 }
779
780 static void
781 gtk_real_tree_item_expand (GtkTreeItem *tree_item)
782 {
783   GtkTree* tree;
784   
785   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
786   
787   if (tree_item->subtree && !tree_item->expanded)
788     {
789       tree = GTK_TREE (GTK_WIDGET (tree_item)->parent); 
790       
791       /* hide subtree widget */
792       gtk_widget_show (tree_item->subtree);
793       
794       /* hide button '+' and show button '-' */
795       if (tree_item->pixmaps_box)
796         {
797           gtk_container_remove (GTK_CONTAINER (tree_item->pixmaps_box), 
798                                 tree_item->plus_pix_widget);
799           gtk_container_add (GTK_CONTAINER (tree_item->pixmaps_box), 
800                              tree_item->minus_pix_widget);
801         }
802       if (tree->root_tree)
803         gtk_widget_queue_resize (GTK_WIDGET (tree->root_tree));
804       tree_item->expanded = TRUE;
805     }
806 }
807
808 static void
809 gtk_real_tree_item_collapse (GtkTreeItem *tree_item)
810 {
811   GtkTree* tree;
812   
813   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
814   
815   if (tree_item->subtree && tree_item->expanded) 
816     {
817       tree = GTK_TREE (GTK_WIDGET (tree_item)->parent);
818       
819       /* hide subtree widget */
820       gtk_widget_hide (tree_item->subtree);
821       
822       /* hide button '-' and show button '+' */
823       if (tree_item->pixmaps_box)
824         {
825           gtk_container_remove (GTK_CONTAINER (tree_item->pixmaps_box), 
826                                 tree_item->minus_pix_widget);
827           gtk_container_add (GTK_CONTAINER (tree_item->pixmaps_box), 
828                              tree_item->plus_pix_widget);
829         }
830       if (tree->root_tree)
831         gtk_widget_queue_resize (GTK_WIDGET (tree->root_tree));
832       tree_item->expanded = FALSE;
833     }
834 }
835
836 static void
837 gtk_tree_item_destroy (GtkObject *object)
838 {
839   GtkTreeItem* item = GTK_TREE_ITEM(object);
840   GtkWidget* child;
841
842 #ifdef TREE_DEBUG
843   g_message("+ gtk_tree_item_destroy [object %#x]\n", (int)object);
844 #endif /* TREE_DEBUG */
845
846   /* free sub tree if it exist */
847   child = item->subtree;
848   if (child)
849     {
850       gtk_widget_ref (child);
851       gtk_widget_unparent (child);
852       gtk_widget_destroy (child);
853       g_object_unref (child);
854       item->subtree = NULL;
855     }
856   
857   /* free pixmaps box */
858   child = item->pixmaps_box;
859   if (child)
860     {
861       gtk_widget_ref (child);
862       gtk_widget_unparent (child);
863       gtk_widget_destroy (child);
864       g_object_unref (child);
865       item->pixmaps_box = NULL;
866     }
867   
868   
869   /* destroy plus pixmap */
870   if (item->plus_pix_widget)
871     {
872       gtk_widget_destroy (item->plus_pix_widget);
873       g_object_unref (item->plus_pix_widget);
874       item->plus_pix_widget = NULL;
875     }
876   
877   /* destroy minus pixmap */
878   if (item->minus_pix_widget)
879     {
880       gtk_widget_destroy (item->minus_pix_widget);
881       g_object_unref (item->minus_pix_widget);
882       item->minus_pix_widget = NULL;
883     }
884   
885   /* By removing the pixmaps here, and not in unrealize, we depend on
886    * the fact that a widget can never change colormap or visual.
887    */
888   gtk_tree_item_remove_pixmaps (item);
889   
890   GTK_OBJECT_CLASS (parent_class)->destroy (object);
891   
892 #ifdef TREE_DEBUG
893   g_message("- gtk_tree_item_destroy\n");
894 #endif /* TREE_DEBUG */
895 }
896
897 void
898 gtk_tree_item_remove_subtree (GtkTreeItem* item) 
899 {
900   g_return_if_fail (GTK_IS_TREE_ITEM(item));
901   g_return_if_fail (item->subtree != NULL);
902   
903   if (GTK_TREE (item->subtree)->children)
904     {
905       /* The following call will remove the children and call
906        * gtk_tree_item_remove_subtree() again. So we are done.
907        */
908       gtk_tree_remove_items (GTK_TREE (item->subtree), 
909                              GTK_TREE (item->subtree)->children);
910       return;
911     }
912
913   if (GTK_WIDGET_MAPPED (item->subtree))
914     gtk_widget_unmap (item->subtree);
915       
916   gtk_widget_unparent (item->subtree);
917   
918   if (item->pixmaps_box)
919     gtk_widget_hide (item->pixmaps_box);
920   
921   item->subtree = NULL;
922
923   if (item->expanded)
924     {
925       item->expanded = FALSE;
926       if (item->pixmaps_box)
927         {
928           gtk_container_remove (GTK_CONTAINER (item->pixmaps_box), 
929                                 item->minus_pix_widget);
930           gtk_container_add (GTK_CONTAINER (item->pixmaps_box), 
931                              item->plus_pix_widget);
932         }
933     }
934 }
935
936 static void
937 gtk_tree_item_map (GtkWidget *widget)
938 {
939   GtkBin *bin = GTK_BIN (widget);
940   GtkTreeItem* item = GTK_TREE_ITEM(widget);
941
942   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
943
944   if(item->pixmaps_box &&
945      GTK_WIDGET_VISIBLE (item->pixmaps_box) &&
946      !GTK_WIDGET_MAPPED (item->pixmaps_box))
947     gtk_widget_map (item->pixmaps_box);
948
949   if (bin->child &&
950       GTK_WIDGET_VISIBLE (bin->child) &&
951       !GTK_WIDGET_MAPPED (bin->child))
952     gtk_widget_map (bin->child);
953
954   gdk_window_show (widget->window);
955 }
956
957 static void
958 gtk_tree_item_unmap (GtkWidget *widget)
959 {
960   GtkBin *bin = GTK_BIN (widget);
961   GtkTreeItem* item = GTK_TREE_ITEM(widget);
962
963   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
964
965   gdk_window_hide (widget->window);
966
967   if(item->pixmaps_box &&
968      GTK_WIDGET_VISIBLE (item->pixmaps_box) &&
969      GTK_WIDGET_MAPPED (item->pixmaps_box))
970     gtk_widget_unmap (bin->child);
971
972   if (bin->child &&
973       GTK_WIDGET_VISIBLE (bin->child) &&
974       GTK_WIDGET_MAPPED (bin->child))
975     gtk_widget_unmap (bin->child);
976 }
977
978 static void
979 gtk_tree_item_forall (GtkContainer *container,
980                       gboolean      include_internals,
981                       GtkCallback   callback,
982                       gpointer      callback_data)
983 {
984   GtkBin *bin = GTK_BIN (container);
985   GtkTreeItem *tree_item = GTK_TREE_ITEM (container);
986
987   if (bin->child)
988     (* callback) (bin->child, callback_data);
989   if (include_internals && tree_item->subtree)
990     (* callback) (tree_item->subtree, callback_data);
991   if (include_internals && tree_item->pixmaps_box)
992     (* callback) (tree_item->pixmaps_box, callback_data);
993 }
994
995 #define __GTK_TREE_ITEM_C__
996 #include "gtkaliasdef.c"