]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeitem.c
Deprecate widget flag: GTK_WIDGET_VISIBLE
[~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 (GTK_WIDGET (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_get_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_is_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                      G_CALLBACK (gtk_tree_item_subtree_button_changed_state),
235                      (gpointer)NULL);
236   gtk_signal_connect(GTK_OBJECT(eventbox), "realize",
237                      G_CALLBACK (gtk_tree_item_subtree_button_changed_state),
238                      (gpointer)NULL);
239   gtk_signal_connect(GTK_OBJECT(eventbox), "button-press-event",
240                      G_CALLBACK (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   GTK_WIDGET_CLASS (parent_class)->realize (widget);
446
447   gdk_window_set_background (widget->window, 
448                              &widget->style->base[GTK_STATE_NORMAL]);
449
450   gtk_tree_item_add_pixmaps (GTK_TREE_ITEM (widget));
451 }
452
453 static void
454 gtk_tree_item_size_request (GtkWidget      *widget,
455                             GtkRequisition *requisition)
456 {
457   GtkBin *bin = GTK_BIN (widget);
458   GtkTreeItem *item = GTK_TREE_ITEM (widget);
459   GtkRequisition child_requisition;
460
461   requisition->width = (GTK_CONTAINER (widget)->border_width +
462                         widget->style->xthickness) * 2;
463   requisition->height = GTK_CONTAINER (widget)->border_width * 2;
464
465   if (bin->child && gtk_widget_get_visible (bin->child))
466     {
467       GtkRequisition pix_requisition;
468       
469       gtk_widget_size_request (bin->child, &child_requisition);
470
471       requisition->width += child_requisition.width;
472
473       gtk_widget_size_request (item->pixmaps_box, 
474                                &pix_requisition);
475       requisition->width += pix_requisition.width + DEFAULT_DELTA + 
476         GTK_TREE (widget->parent)->current_indent;
477
478       requisition->height += MAX (child_requisition.height,
479                                   pix_requisition.height);
480     }
481 }
482
483 static void
484 gtk_tree_item_size_allocate (GtkWidget     *widget,
485                              GtkAllocation *allocation)
486 {
487   GtkBin *bin = GTK_BIN (widget);
488   GtkTreeItem *item = GTK_TREE_ITEM (widget);
489   GtkAllocation child_allocation;
490   gint border_width;
491   int temp;
492
493   widget->allocation = *allocation;
494   if (GTK_WIDGET_REALIZED (widget))
495     gdk_window_move_resize (widget->window,
496                             allocation->x, allocation->y,
497                             allocation->width, allocation->height);
498
499   if (bin->child)
500     {
501       border_width = (GTK_CONTAINER (widget)->border_width +
502                       widget->style->xthickness);
503
504       child_allocation.x = border_width + GTK_TREE(widget->parent)->current_indent;
505       child_allocation.y = GTK_CONTAINER (widget)->border_width;
506
507       child_allocation.width = item->pixmaps_box->requisition.width;
508       child_allocation.height = item->pixmaps_box->requisition.height;
509       
510       temp = allocation->height - child_allocation.height;
511       child_allocation.y += ( temp / 2 ) + ( temp % 2 );
512
513       gtk_widget_size_allocate (item->pixmaps_box, &child_allocation);
514
515       child_allocation.y = GTK_CONTAINER (widget)->border_width;
516       child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
517       child_allocation.x += item->pixmaps_box->requisition.width+DEFAULT_DELTA;
518
519       child_allocation.width = 
520         MAX (1, (gint)allocation->width - ((gint)child_allocation.x + border_width));
521
522       gtk_widget_size_allocate (bin->child, &child_allocation);
523     }
524 }
525
526 static void 
527 gtk_tree_item_draw_lines (GtkWidget *widget) 
528 {
529   GtkTreeItem* item;
530   GtkTree* tree;
531   guint lx1, ly1, lx2, ly2;
532   GdkGC* gc;
533
534   g_return_if_fail (GTK_IS_TREE_ITEM (widget));
535
536   item = GTK_TREE_ITEM(widget);
537   tree = GTK_TREE(widget->parent);
538
539   if (!tree->view_line)
540     return;
541
542   gc = widget->style->text_gc[GTK_STATE_NORMAL];
543
544   /* draw vertical line */
545   lx1 = item->pixmaps_box->allocation.width;
546   lx1 = lx2 = ((lx1 / 2) + (lx1 % 2) + 
547                GTK_CONTAINER (widget)->border_width + 1 + tree->current_indent);
548   ly1 = 0;
549   ly2 = widget->allocation.height;
550
551   if (g_list_last (tree->children)->data == widget)
552     ly2 = (ly2 / 2) + (ly2 % 2);
553
554   if (tree != tree->root_tree)
555     gdk_draw_line (widget->window, gc, lx1, ly1, lx2, ly2);
556
557   /* draw vertical line for subtree connecting */
558   if(g_list_last(tree->children)->data != (gpointer)widget)
559     ly2 = (ly2 / 2) + (ly2 % 2);
560   
561   lx2 += DEFAULT_DELTA;
562
563   if (item->subtree && item->expanded)
564     gdk_draw_line (widget->window, gc,
565                    lx2, ly2, lx2, widget->allocation.height);
566
567   /* draw horizontal line */
568   ly1 = ly2;
569   lx2 += 2;
570
571   gdk_draw_line (widget->window, gc, lx1, ly1, lx2, ly2);
572
573   lx2 -= DEFAULT_DELTA+2;
574   ly1 = 0;
575   ly2 = widget->allocation.height;
576
577   if (tree != tree->root_tree)
578     {
579       item = GTK_TREE_ITEM (tree->tree_owner);
580       tree = GTK_TREE (GTK_WIDGET (tree)->parent);
581       while (tree != tree->root_tree)
582         {
583           lx1 = lx2 -= tree->indent_value;
584           
585           if (g_list_last (tree->children)->data != item)
586             gdk_draw_line (widget->window, gc, lx1, ly1, lx2, ly2);
587           item = GTK_TREE_ITEM (tree->tree_owner);
588           tree = GTK_TREE (GTK_WIDGET (tree)->parent);
589         } 
590     }
591 }
592
593 static void
594 gtk_tree_item_paint (GtkWidget    *widget,
595                      GdkRectangle *area)
596 {
597   GdkRectangle child_area, item_area;
598   GtkTreeItem* tree_item;
599
600   /* FIXME: We should honor tree->view_mode, here - I think
601    * the desired effect is that when the mode is VIEW_ITEM,
602    * only the subitem is drawn as selected, not the entire
603    * line. (Like the way that the tree in Windows Explorer
604    * works).
605    */
606   if (gtk_widget_is_drawable (widget))
607     {
608       tree_item = GTK_TREE_ITEM(widget);
609
610       if (widget->state == GTK_STATE_NORMAL)
611         {
612           gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
613           gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height);
614         }
615       else 
616         {
617           if (!gtk_widget_is_sensitive (widget))
618             gtk_paint_flat_box(widget->style, widget->window,
619                                widget->state, GTK_SHADOW_NONE,
620                                area, widget, "treeitem",
621                                0, 0, -1, -1);
622           else
623             gtk_paint_flat_box(widget->style, widget->window,
624                                widget->state, GTK_SHADOW_ETCHED_OUT,
625                                area, widget, "treeitem",
626                                0, 0, -1, -1);
627         }
628
629       /* draw left size of tree item */
630       item_area.x = 0;
631       item_area.y = 0;
632       item_area.width = (tree_item->pixmaps_box->allocation.width + DEFAULT_DELTA +
633                          GTK_TREE (widget->parent)->current_indent + 2);
634       item_area.height = widget->allocation.height;
635
636
637       if (gdk_rectangle_intersect(&item_area, area, &child_area)) 
638         {
639           
640           gtk_tree_item_draw_lines(widget);
641
642           if (tree_item->pixmaps_box && 
643               gtk_widget_get_visible(tree_item->pixmaps_box) &&
644               gtk_widget_intersect (tree_item->pixmaps_box, area, &child_area))
645             {
646               gtk_widget_queue_draw_area (tree_item->pixmaps_box,
647                                           child_area.x, child_area.y,
648                                           child_area.width, child_area.height);
649               gdk_window_process_updates (tree_item->pixmaps_box->window, TRUE);
650             }
651         }
652
653       if (gtk_widget_has_focus (widget))
654         gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
655                          NULL, widget, "treeitem",
656                          0, 0,
657                          widget->allocation.width,
658                          widget->allocation.height);
659       
660     }
661 }
662
663 static gint
664 gtk_tree_item_button_press (GtkWidget      *widget,
665                             GdkEventButton *event)
666 {
667   if (event->type == GDK_BUTTON_PRESS
668       && gtk_widget_is_sensitive(widget)
669       && !gtk_widget_has_focus (widget))
670     gtk_widget_grab_focus (widget);
671
672   return (event->type == GDK_BUTTON_PRESS && gtk_widget_is_sensitive(widget));
673 }
674
675 static void
676 gtk_tree_item_expose_child (GtkWidget *child,
677                             gpointer   client_data)
678 {
679   struct {
680     GtkWidget *container;
681     GdkEventExpose *event;
682   } *data = client_data;
683
684   if (gtk_widget_is_drawable (child) &&
685       !gtk_widget_get_has_window (child) &&
686       (child->window == data->event->window))
687     {
688       GdkEvent *child_event = gdk_event_new (GDK_EXPOSE);
689       child_event->expose = *data->event;
690       g_object_ref (child_event->expose.window);
691
692       child_event->expose.region = gtk_widget_region_intersect (child,
693                                                                 data->event->region);
694       if (!gdk_region_empty (child_event->expose.region))
695         {
696           gdk_region_get_clipbox (child_event->expose.region, &child_event->expose.area);
697           gtk_widget_send_expose (child, child_event);
698         }
699       gdk_event_free (child_event);
700     }
701 }
702
703 static gint
704 gtk_tree_item_expose (GtkWidget      *widget,
705                       GdkEventExpose *event)
706 {
707   struct {
708     GtkWidget *container;
709     GdkEventExpose *event;
710   } data;
711
712   if (gtk_widget_is_drawable (widget))
713     {
714       gtk_tree_item_paint (widget, &event->area);
715
716       data.container = widget;
717       data.event = event;
718
719       gtk_container_forall (GTK_CONTAINER (widget),
720                             gtk_tree_item_expose_child,
721                             &data);
722    }
723
724   return FALSE;
725 }
726
727 static void
728 gtk_real_tree_item_select (GtkItem *item)
729 {
730   GtkWidget *widget;
731
732   g_return_if_fail (GTK_IS_TREE_ITEM (item));
733
734   widget = GTK_WIDGET (item);
735
736   gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
737
738   if (!widget->parent || GTK_TREE (widget->parent)->view_mode == GTK_TREE_VIEW_LINE)
739     gtk_widget_set_state (GTK_TREE_ITEM (item)->pixmaps_box, GTK_STATE_SELECTED);
740 }
741
742 static void
743 gtk_real_tree_item_deselect (GtkItem *item)
744 {
745   GtkTreeItem *tree_item;
746   GtkWidget *widget;
747
748   g_return_if_fail (GTK_IS_TREE_ITEM (item));
749
750   tree_item = GTK_TREE_ITEM (item);
751   widget = GTK_WIDGET (item);
752
753   gtk_widget_set_state (widget, GTK_STATE_NORMAL);
754
755   if (!widget->parent || GTK_TREE (widget->parent)->view_mode == GTK_TREE_VIEW_LINE)
756     gtk_widget_set_state (tree_item->pixmaps_box, GTK_STATE_NORMAL);
757 }
758
759 static void
760 gtk_real_tree_item_toggle (GtkItem *item)
761 {
762   g_return_if_fail (GTK_IS_TREE_ITEM (item));
763
764   if(!gtk_widget_is_sensitive(GTK_WIDGET (item)))
765     return;
766
767   if (GTK_IS_TREE (GTK_WIDGET (item)->parent))
768     gtk_tree_select_child (GTK_TREE (GTK_WIDGET (item)->parent),
769                            GTK_WIDGET (item));
770   else
771     {
772       /* Should we really bother with this bit? A listitem not in a list?
773        * -Johannes Keukelaar
774        * yes, always be on the safe side!
775        * -timj
776        */
777       if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED)
778         gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL);
779       else
780         gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
781     }
782 }
783
784 static void
785 gtk_real_tree_item_expand (GtkTreeItem *tree_item)
786 {
787   GtkTree* tree;
788   
789   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
790   
791   if (tree_item->subtree && !tree_item->expanded)
792     {
793       tree = GTK_TREE (GTK_WIDGET (tree_item)->parent); 
794       
795       /* hide subtree widget */
796       gtk_widget_show (tree_item->subtree);
797       
798       /* hide button '+' and show button '-' */
799       if (tree_item->pixmaps_box)
800         {
801           gtk_container_remove (GTK_CONTAINER (tree_item->pixmaps_box), 
802                                 tree_item->plus_pix_widget);
803           gtk_container_add (GTK_CONTAINER (tree_item->pixmaps_box), 
804                              tree_item->minus_pix_widget);
805         }
806       if (tree->root_tree)
807         gtk_widget_queue_resize (GTK_WIDGET (tree->root_tree));
808       tree_item->expanded = TRUE;
809     }
810 }
811
812 static void
813 gtk_real_tree_item_collapse (GtkTreeItem *tree_item)
814 {
815   GtkTree* tree;
816   
817   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
818   
819   if (tree_item->subtree && tree_item->expanded) 
820     {
821       tree = GTK_TREE (GTK_WIDGET (tree_item)->parent);
822       
823       /* hide subtree widget */
824       gtk_widget_hide (tree_item->subtree);
825       
826       /* hide button '-' and show button '+' */
827       if (tree_item->pixmaps_box)
828         {
829           gtk_container_remove (GTK_CONTAINER (tree_item->pixmaps_box), 
830                                 tree_item->minus_pix_widget);
831           gtk_container_add (GTK_CONTAINER (tree_item->pixmaps_box), 
832                              tree_item->plus_pix_widget);
833         }
834       if (tree->root_tree)
835         gtk_widget_queue_resize (GTK_WIDGET (tree->root_tree));
836       tree_item->expanded = FALSE;
837     }
838 }
839
840 static void
841 gtk_tree_item_destroy (GtkObject *object)
842 {
843   GtkTreeItem* item = GTK_TREE_ITEM(object);
844   GtkWidget* child;
845
846 #ifdef TREE_DEBUG
847   g_message("+ gtk_tree_item_destroy [object %#x]\n", (int)object);
848 #endif /* TREE_DEBUG */
849
850   /* free sub tree if it exist */
851   child = item->subtree;
852   if (child)
853     {
854       g_object_ref (child);
855       gtk_widget_unparent (child);
856       gtk_widget_destroy (child);
857       g_object_unref (child);
858       item->subtree = NULL;
859     }
860   
861   /* free pixmaps box */
862   child = item->pixmaps_box;
863   if (child)
864     {
865       g_object_ref (child);
866       gtk_widget_unparent (child);
867       gtk_widget_destroy (child);
868       g_object_unref (child);
869       item->pixmaps_box = NULL;
870     }
871   
872   
873   /* destroy plus pixmap */
874   if (item->plus_pix_widget)
875     {
876       gtk_widget_destroy (item->plus_pix_widget);
877       g_object_unref (item->plus_pix_widget);
878       item->plus_pix_widget = NULL;
879     }
880   
881   /* destroy minus pixmap */
882   if (item->minus_pix_widget)
883     {
884       gtk_widget_destroy (item->minus_pix_widget);
885       g_object_unref (item->minus_pix_widget);
886       item->minus_pix_widget = NULL;
887     }
888   
889   /* By removing the pixmaps here, and not in unrealize, we depend on
890    * the fact that a widget can never change colormap or visual.
891    */
892   gtk_tree_item_remove_pixmaps (item);
893   
894   GTK_OBJECT_CLASS (parent_class)->destroy (object);
895   
896 #ifdef TREE_DEBUG
897   g_message("- gtk_tree_item_destroy\n");
898 #endif /* TREE_DEBUG */
899 }
900
901 void
902 gtk_tree_item_remove_subtree (GtkTreeItem* item) 
903 {
904   g_return_if_fail (GTK_IS_TREE_ITEM(item));
905   g_return_if_fail (item->subtree != NULL);
906   
907   if (GTK_TREE (item->subtree)->children)
908     {
909       /* The following call will remove the children and call
910        * gtk_tree_item_remove_subtree() again. So we are done.
911        */
912       gtk_tree_remove_items (GTK_TREE (item->subtree), 
913                              GTK_TREE (item->subtree)->children);
914       return;
915     }
916
917   if (GTK_WIDGET_MAPPED (item->subtree))
918     gtk_widget_unmap (item->subtree);
919       
920   gtk_widget_unparent (item->subtree);
921   
922   if (item->pixmaps_box)
923     gtk_widget_hide (item->pixmaps_box);
924   
925   item->subtree = NULL;
926
927   if (item->expanded)
928     {
929       item->expanded = FALSE;
930       if (item->pixmaps_box)
931         {
932           gtk_container_remove (GTK_CONTAINER (item->pixmaps_box), 
933                                 item->minus_pix_widget);
934           gtk_container_add (GTK_CONTAINER (item->pixmaps_box), 
935                              item->plus_pix_widget);
936         }
937     }
938 }
939
940 static void
941 gtk_tree_item_map (GtkWidget *widget)
942 {
943   GtkBin *bin = GTK_BIN (widget);
944   GtkTreeItem* item = GTK_TREE_ITEM(widget);
945
946   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
947
948   if(item->pixmaps_box &&
949      gtk_widget_get_visible (item->pixmaps_box) &&
950      !GTK_WIDGET_MAPPED (item->pixmaps_box))
951     gtk_widget_map (item->pixmaps_box);
952
953   if (bin->child &&
954       gtk_widget_get_visible (bin->child) &&
955       !GTK_WIDGET_MAPPED (bin->child))
956     gtk_widget_map (bin->child);
957
958   gdk_window_show (widget->window);
959 }
960
961 static void
962 gtk_tree_item_unmap (GtkWidget *widget)
963 {
964   GtkBin *bin = GTK_BIN (widget);
965   GtkTreeItem* item = GTK_TREE_ITEM(widget);
966
967   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
968
969   gdk_window_hide (widget->window);
970
971   if(item->pixmaps_box &&
972      gtk_widget_get_visible (item->pixmaps_box) &&
973      GTK_WIDGET_MAPPED (item->pixmaps_box))
974     gtk_widget_unmap (bin->child);
975
976   if (bin->child &&
977       gtk_widget_get_visible (bin->child) &&
978       GTK_WIDGET_MAPPED (bin->child))
979     gtk_widget_unmap (bin->child);
980 }
981
982 static void
983 gtk_tree_item_forall (GtkContainer *container,
984                       gboolean      include_internals,
985                       GtkCallback   callback,
986                       gpointer      callback_data)
987 {
988   GtkBin *bin = GTK_BIN (container);
989   GtkTreeItem *tree_item = GTK_TREE_ITEM (container);
990
991   if (bin->child)
992     (* callback) (bin->child, callback_data);
993   if (include_internals && tree_item->subtree)
994     (* callback) (tree_item->subtree, callback_data);
995   if (include_internals && tree_item->pixmaps_box)
996     (* callback) (tree_item->pixmaps_box, callback_data);
997 }
998
999 #define __GTK_TREE_ITEM_C__
1000 #include "gtkaliasdef.c"