debug-manager: Remove weak pointer when needed
[anjuta.git] / libanjuta / anjuta-tabber.c
blob0065c3f20520f74831c631566ec8a5a43bc54866
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-notebook-tabber
4 * Copyright (C) Johannes Schmid 2010 <jhs@gnome.org>
5 *
6 * anjuta-notebook-tabber is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * anjuta-notebook-tabber is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "anjuta-tabber.h"
22 /**
23 * SECTION:anjuta-tabber
24 * @title: AnjutaTabber
25 * @short_description: Tab widget
26 * @see_also:
27 * @stability: Unstable
28 * @include: libanjuta/anjuta-tabber.h
31 struct _AnjutaTabberPriv
33 GtkNotebook* notebook;
34 GList* children;
35 gint active_page;
37 GdkWindow* event_window;
40 enum
42 PROP_0,
43 PROP_NOTEBOOK
46 #define ANJUTA_TABBER_GET_PRIVATE(o) \
47 (G_TYPE_INSTANCE_GET_PRIVATE ((o), ANJUTA_TYPE_TABBER, AnjutaTabberPriv))
50 G_DEFINE_TYPE (AnjutaTabber, anjuta_tabber, GTK_TYPE_CONTAINER);
52 static void
53 anjuta_tabber_init (AnjutaTabber *object)
55 AnjutaTabber* tabber = ANJUTA_TABBER (object);
56 AnjutaTabberPriv* priv;
58 GtkStyleContext* context;
60 tabber->priv = ANJUTA_TABBER_GET_PRIVATE (tabber);
61 priv = tabber->priv;
63 priv->children = NULL;
64 priv->active_page = 0;
66 gtk_widget_set_has_window (GTK_WIDGET(tabber), FALSE);
68 context = gtk_widget_get_style_context (GTK_WIDGET (tabber));
69 gtk_style_context_add_class (context, GTK_STYLE_CLASS_NOTEBOOK);
70 gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP);
73 /**
74 * anjuta_tabber_notebook_page_removed:
76 * Called when a page is removed from the associated notebook. Removes
77 * the tab for this page
79 static void
80 anjuta_tabber_notebook_page_removed (GtkNotebook* notebook,
81 GtkWidget* notebook_child,
82 gint page_num,
83 AnjutaTabber* tabber)
85 GtkWidget* child = g_list_nth_data (tabber->priv->children, page_num);
86 gtk_container_remove (GTK_CONTAINER (tabber), child);
89 static void
90 anjuta_tabber_notebook_switch_page (GtkNotebook* notebook,
91 GtkWidget* page,
92 guint page_num,
93 AnjutaTabber* tabber)
95 tabber->priv->active_page = page_num;
96 gtk_widget_queue_draw (GTK_WIDGET (tabber));
99 static void
100 anjuta_tabber_finalize (GObject *object)
102 G_OBJECT_CLASS (anjuta_tabber_parent_class)->finalize (object);
105 static void
106 anjuta_tabber_dispose (GObject *object)
108 AnjutaTabber* tabber = ANJUTA_TABBER (object);
109 g_signal_handlers_disconnect_by_func (tabber->priv->notebook,
110 anjuta_tabber_notebook_page_removed,
111 object);
112 g_signal_handlers_disconnect_by_func (tabber->priv->notebook,
113 anjuta_tabber_notebook_switch_page,
114 object);
116 G_OBJECT_CLASS (anjuta_tabber_parent_class)->dispose (object);
120 * anjuta_tabber_connect_notebook:
122 * Connect signals to associated notebook
125 static void
126 anjuta_tabber_connect_notebook (AnjutaTabber* tabber)
128 g_signal_connect (tabber->priv->notebook, "page-removed",
129 G_CALLBACK(anjuta_tabber_notebook_page_removed), tabber);
130 g_signal_connect (tabber->priv->notebook, "switch-page",
131 G_CALLBACK(anjuta_tabber_notebook_switch_page), tabber);
134 static void
135 anjuta_tabber_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
137 g_return_if_fail (ANJUTA_IS_TABBER (object));
139 AnjutaTabber* tabber = ANJUTA_TABBER (object);
141 switch (prop_id)
143 case PROP_NOTEBOOK:
144 tabber->priv->notebook = g_value_get_object (value);
145 anjuta_tabber_connect_notebook (tabber);
146 break;
147 default:
148 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
149 break;
153 static void
154 anjuta_tabber_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
156 g_return_if_fail (ANJUTA_IS_TABBER (object));
158 switch (prop_id)
160 case PROP_NOTEBOOK:
161 g_value_set_object (value, object);
162 break;
163 default:
164 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
165 break;
169 static GtkRegionFlags
170 anjuta_tabber_get_region_flags (AnjutaTabber* tabber, gint page_num)
172 GtkRegionFlags flags = 0;
174 if ((page_num + 1) % 2 == 0)
175 flags |= GTK_REGION_EVEN;
176 else
177 flags |= GTK_REGION_ODD;
179 if (page_num == 1)
180 flags |= GTK_REGION_FIRST;
182 if (page_num == (g_list_length (tabber->priv->children) - 1))
183 flags |= GTK_REGION_LAST;
185 return flags;
188 static void
189 anjuta_tabber_setup_style_context (AnjutaTabber* tabber, GtkStyleContext* context,
190 GList* child, GtkStateFlags* state_flags,
191 GtkRegionFlags* region_flags)
193 gint page_num;
194 gboolean current;
195 GtkRegionFlags region;
196 GtkStateFlags state;
198 page_num = g_list_position (tabber->priv->children, child);
199 current = page_num == tabber->priv->active_page;
201 region = anjuta_tabber_get_region_flags (tabber, page_num);
203 gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, region);
205 if (gtk_widget_get_direction (GTK_WIDGET (tabber)) == GTK_TEXT_DIR_LTR)
206 gtk_style_context_set_junction_sides (context,
207 GTK_JUNCTION_CORNER_TOPLEFT);
208 else
209 gtk_style_context_set_junction_sides (context,
210 GTK_JUNCTION_CORNER_TOPRIGHT);
212 state = gtk_style_context_get_state (context);
213 if (current)
214 state |= GTK_STATE_FLAG_ACTIVE;
215 else
216 state &= ~GTK_STATE_FLAG_ACTIVE;
217 gtk_style_context_set_state (context, state);
219 if (state_flags)
220 *state_flags = state;
221 if (region_flags)
222 *region_flags = region;
225 static void
226 anjuta_tabber_get_preferred_width (GtkWidget* widget,
227 gint* minimum,
228 gint* preferred)
230 g_return_if_fail (ANJUTA_IS_TABBER (widget));
232 AnjutaTabber* tabber = ANJUTA_TABBER (widget);
233 GtkStyleContext* context;
234 GList* child;
235 gint focus_width;
236 gint focus_pad;
237 gint tab_curvature;
238 gint tab_overlap;
240 *minimum = 0;
241 *preferred = 0;
243 gtk_widget_style_get (GTK_WIDGET (tabber->priv->notebook),
244 "focus-line-width", &focus_width,
245 "focus-padding", &focus_pad,
246 "tab-curvature", &tab_curvature,
247 "tab-overlap", &tab_overlap,
248 NULL);
250 context = gtk_widget_get_style_context (widget);
252 for (child = tabber->priv->children; child != NULL; child = g_list_next (child))
254 GtkStateFlags state;
255 GtkBorder tab_padding;
256 gint xpadding;
257 gint child_min;
258 gint child_preferred;
259 gint extra_space = 2 * (tab_curvature - tab_overlap);
261 /* Get the padding of the tab */
262 gtk_style_context_save (context);
263 anjuta_tabber_setup_style_context (tabber, context, child, &state, NULL);
264 gtk_style_context_get_padding (context, state, &tab_padding);
265 gtk_style_context_restore (context);
267 xpadding = 2 * (focus_width + focus_pad) + tab_padding.left + tab_padding.right;
269 if (child->prev == NULL)
270 extra_space += tab_overlap;
271 if (child->next == NULL)
272 extra_space += tab_overlap;
274 gtk_widget_get_preferred_width (GTK_WIDGET (child->data), &child_min, &child_preferred);
275 if (minimum)
277 *minimum += child_min + xpadding + extra_space;
279 if (preferred)
281 *preferred += child_preferred + xpadding + extra_space;
286 static void
287 anjuta_tabber_get_preferred_height (GtkWidget* widget,
288 gint* minimum,
289 gint* preferred)
291 g_return_if_fail (ANJUTA_IS_TABBER (widget));
293 AnjutaTabber* tabber = ANJUTA_TABBER (widget);
294 GtkStyleContext* context;
295 GList* child;
296 gint focus_width;
297 gint focus_pad;
299 gtk_widget_style_get (GTK_WIDGET (tabber),
300 "focus-line-width", &focus_width,
301 "focus-padding", &focus_pad,
302 NULL);
304 context = gtk_widget_get_style_context (widget);
306 for (child = tabber->priv->children; child != NULL; child = g_list_next (child))
308 GtkStateFlags state;
309 GtkBorder tab_padding;
310 gint ypadding;
311 gint child_min;
312 gint child_preferred;
314 /* Get the padding of the tab */
315 gtk_style_context_save (context);
316 anjuta_tabber_setup_style_context (tabber, context, child, &state, NULL);
317 gtk_style_context_get_padding (context, state, &tab_padding);
318 gtk_style_context_restore (context);
320 ypadding = 2 * (focus_width + focus_pad) + tab_padding.top + tab_padding.bottom;
322 gtk_widget_get_preferred_height (GTK_WIDGET (child->data), &child_min, &child_preferred);
323 if (minimum)
325 *minimum = MAX(*minimum, child_min + ypadding);
327 if (preferred)
329 *preferred = MAX(*preferred, child_preferred + ypadding);
335 static void
336 anjuta_tabber_size_allocate(GtkWidget* widget, GtkAllocation* allocation)
338 g_return_if_fail (ANJUTA_IS_TABBER (widget));
339 AnjutaTabber* tabber = ANJUTA_TABBER (widget);
341 GtkStyleContext* context;
342 GList* child;
343 gint focus_width;
344 gint focus_pad;
345 gint tab_curvature;
346 gint tab_overlap;
347 gint n_children = g_list_length (tabber->priv->children);
348 gint x;
349 gint focus_space;
350 gint tab_space;
352 context = gtk_widget_get_style_context (widget);
354 gtk_widget_style_get (GTK_WIDGET (tabber),
355 "focus-line-width", &focus_width,
356 "focus-padding", &focus_pad,
357 "tab-curvature", &tab_curvature,
358 "tab-overlap", &tab_overlap,
359 NULL);
361 focus_space = focus_width + focus_pad;
362 tab_space = tab_curvature - tab_overlap;
364 gtk_widget_set_allocation (widget, allocation);
366 switch (gtk_widget_get_direction (widget))
368 case GTK_TEXT_DIR_RTL:
369 x = allocation->x + allocation->width;
370 break;
371 case GTK_TEXT_DIR_LTR:
372 default:
373 x = allocation->x;
376 if (gtk_widget_get_realized (widget))
378 gdk_window_move_resize (tabber->priv->event_window,
379 allocation->x, allocation->y,
380 allocation->width, allocation->height);
381 if (gtk_widget_get_mapped (widget))
382 gdk_window_show_unraised (tabber->priv->event_window);
385 if (n_children > 0)
387 gint total_space;
388 gint total_width;
389 gboolean use_natural = FALSE;
390 gint child_equal;
391 gint extra_space = 0;
392 gint real_width = allocation->width;
394 /* Calculate the total space that is used for padding/overlap */
395 total_space = 2 * tab_curvature
396 + 2 * tab_space * (n_children - 1)
397 + 2 * focus_space * n_children;
399 for (child = tabber->priv->children; child != NULL; child = g_list_next (child))
401 GtkStateFlags state;
402 GtkBorder tab_padding;
404 /* Get the padding of the tab */
405 gtk_style_context_save (context);
406 anjuta_tabber_setup_style_context (tabber, context, child, &state, NULL);
407 gtk_style_context_get_padding (context, state, &tab_padding);
408 gtk_style_context_restore (context);
410 total_space += tab_padding.left + tab_padding.right;
413 /* Check if we have enough space for all widgets natural size */
414 child_equal = (real_width - total_space) / n_children;
416 if (child_equal < 0)
417 return;
419 /* Calculate the total width of the tabs */
420 total_width = total_space;
421 for (child = tabber->priv->children; child != NULL; child = g_list_next (child))
423 GtkWidget* child_widget = GTK_WIDGET (child->data);
424 gint natural;
426 gtk_widget_get_preferred_width (child_widget, NULL,
427 &natural);
429 total_width += natural;
431 if (natural < child_equal)
432 extra_space += child_equal - natural;
435 use_natural = (total_width <= real_width);
436 child_equal += extra_space / n_children;
438 for (child = tabber->priv->children; child != NULL; child = g_list_next (child))
440 GtkWidget* child_widget = GTK_WIDGET (child->data);
441 GtkStateFlags state;
442 GtkBorder tab_padding, active_padding;
443 GtkAllocation child_alloc;
444 gint natural;
445 gint minimal;
446 gint begin_tab = tab_space;
447 gint end_tab = tab_space;
449 /* Get the padding of the tab */
450 gtk_style_context_save (context);
451 anjuta_tabber_setup_style_context (tabber, context, child, &state, NULL);
452 gtk_style_context_get_padding (context, state, &tab_padding);
453 gtk_style_context_get_padding (context, state | GTK_STATE_ACTIVE, &active_padding);
454 gtk_style_context_restore (context);
456 if (child->prev == NULL)
457 begin_tab = tab_curvature;
458 if (child->next == NULL)
459 end_tab = tab_curvature;
461 gtk_widget_get_preferred_width (child_widget, &minimal,
462 &natural);
464 if (use_natural)
466 child_alloc.width = natural;
468 else
470 if (natural < child_equal)
471 child_alloc.width = natural;
472 else
473 child_alloc.width = child_equal;
475 /* The active pad is by definition at least the same height
476 * as the inactive one. Therefore we always use the padding of the
477 * active tab to calculate the height and y position of the child.
479 child_alloc.height = allocation->height - 2 * focus_space
480 - active_padding.top - active_padding.bottom;
481 child_alloc.y = allocation->y + focus_space + active_padding.top;
483 switch (gtk_widget_get_direction (widget))
485 case GTK_TEXT_DIR_RTL:
486 child_alloc.x = x - focus_space - tab_padding.right
487 - begin_tab - child_alloc.width;
488 x = child_alloc.x - focus_space - tab_padding.left - end_tab;
489 break;
490 case GTK_TEXT_DIR_LTR:
491 default:
492 child_alloc.x = x + focus_space + tab_padding.left + begin_tab;
493 x = child_alloc.x + child_alloc.width + focus_space
494 + tab_padding.right + end_tab;
497 gtk_widget_size_allocate (child_widget, &child_alloc);
502 static void
503 anjuta_tabber_draw_tab (AnjutaTabber* tabber, cairo_t* cr, GList* child)
505 GtkWidget* widget = GTK_WIDGET (tabber);
506 GtkWidget* tab = GTK_WIDGET (child->data);
508 gboolean current;
509 gint focus_width;
510 gint focus_pad;
511 gint tab_curvature;
512 gint tab_overlap;
513 gint focus_space;
514 gint tab_begin;
515 gint tab_end;
517 GtkStateFlags state;
518 GtkRegionFlags region_flags;
519 GtkBorder tab_padding;
520 GtkAllocation alloc;
521 GtkAllocation widget_alloc;
523 GtkStyleContext* context = gtk_widget_get_style_context (widget);
525 current = g_list_position (tabber->priv->children, child) == tabber->priv->active_page;
527 gtk_widget_style_get (widget,
528 "focus-line-width", &focus_width,
529 "focus-padding", &focus_pad,
530 "tab-curvature", &tab_curvature,
531 "tab-overlap", &tab_overlap,
532 NULL);
534 focus_space = focus_pad + focus_width;
536 /* Get border/padding for tab */
537 gtk_style_context_save (context);
538 anjuta_tabber_setup_style_context (tabber, context, child, &state, &region_flags);
539 gtk_style_context_get_padding (context, state, &tab_padding);
541 gtk_widget_get_allocation (widget, &widget_alloc);
542 gtk_widget_get_allocation (tab, &alloc);
544 tab_begin = tab_curvature - tab_overlap;
545 tab_end = tab_curvature - tab_overlap;
547 if (region_flags | GTK_REGION_FIRST)
548 tab_begin += tab_overlap;
549 if (region_flags | GTK_REGION_LAST)
550 tab_end += tab_overlap;
552 alloc.x -= widget_alloc.x;
553 alloc.x -= tab_begin;
554 alloc.x -= focus_space + tab_padding.left;
555 alloc.y -= widget_alloc.y;
556 alloc.y -= focus_space + tab_padding.top;
557 alloc.width += 2 * focus_space + tab_padding.left + tab_padding.right
558 + tab_begin + tab_end;
559 alloc.height += 2 * focus_space + tab_padding.top + tab_padding.bottom;
561 gtk_render_extension (context,
563 alloc.x,
564 alloc.y,
565 alloc.width,
566 alloc.height,
567 GTK_POS_BOTTOM);
569 if (gtk_widget_has_focus (widget) &&
570 current)
572 GtkAllocation allocation;
574 gtk_widget_get_allocation (tab, &allocation);
576 gtk_render_focus (context, cr,
577 allocation.x - focus_space,
578 allocation.y - focus_space,
579 allocation.width + 2 * focus_space,
580 allocation.height + 2 * focus_space);
583 gtk_style_context_restore (context);
586 static gboolean
587 anjuta_tabber_draw (GtkWidget* widget, cairo_t* cr)
589 AnjutaTabber* tabber;
590 GList* current_tab;
591 GList* child;
593 g_return_val_if_fail (ANJUTA_IS_TABBER (widget), FALSE);
595 tabber = ANJUTA_TABBER (widget);
597 if (!tabber->priv->children)
598 return TRUE;
600 current_tab = g_list_nth (tabber->priv->children, tabber->priv->active_page);
602 /* Draw the current tab last since it overlaps the others */
603 for (child = tabber->priv->children; child != current_tab; child = g_list_next (child))
605 anjuta_tabber_draw_tab (tabber, cr, child);
607 for (child = g_list_last (tabber->priv->children); child != current_tab; child = g_list_previous (child))
609 anjuta_tabber_draw_tab (tabber, cr, child);
611 anjuta_tabber_draw_tab (tabber, cr, current_tab);
613 return GTK_WIDGET_CLASS (anjuta_tabber_parent_class)->draw (widget, cr);
617 * anjuta_tabber_get_widget_coordinates:
618 * @widget: widget for the coordinates
619 * @event: event to get coordinates from
620 * @x: return location for x coordinate
621 * @y: return location for y coordinate
623 * Returns: %TRUE if coordinates were set, %FALSE otherwise
625 static gboolean
626 anjuta_tabber_get_widget_coordinates (GtkWidget *widget,
627 GdkEvent *event,
628 gint *x,
629 gint *y)
631 GdkWindow *window = ((GdkEventAny *)event)->window;
632 gdouble tx, ty;
634 if (!gdk_event_get_coords (event, &tx, &ty))
635 return FALSE;
637 while (window && window != gtk_widget_get_window (widget))
639 gint window_x, window_y;
641 gdk_window_get_position (window, &window_x, &window_y);
642 tx += window_x;
643 ty += window_y;
645 window = gdk_window_get_parent (window);
648 if (window)
650 *x = tx;
651 *y = ty;
653 return TRUE;
655 else
656 return FALSE;
659 static gboolean
660 anjuta_tabber_button_press_event (GtkWidget* widget, GdkEventButton* event)
662 AnjutaTabber* tabber = ANJUTA_TABBER (widget);
663 GList* child;
665 if (event->button == 1)
667 gint x, y;
668 if (!anjuta_tabber_get_widget_coordinates (widget, (GdkEvent*) event, &x, &y))
669 return FALSE;
671 for (child = tabber->priv->children; child != NULL; child = g_list_next (child))
673 GtkAllocation alloc;
674 gtk_widget_get_allocation (GTK_WIDGET (child->data), &alloc);
676 if (alloc.x <= x && (alloc.x + alloc.width) >= x &&
677 alloc.y <= y && (alloc.y + alloc.height) >= y)
679 gint page = g_list_position (tabber->priv->children, child);
680 gtk_notebook_set_current_page (tabber->priv->notebook, page);
681 return TRUE;
686 return FALSE;
689 static void
690 anjuta_tabber_realize (GtkWidget *widget)
692 GdkWindow* window;
693 GdkWindowAttr attributes;
694 GtkAllocation allocation;
695 AnjutaTabber* tabber = ANJUTA_TABBER (widget);
697 gtk_widget_set_realized (widget, TRUE);
699 window = gtk_widget_get_parent_window (widget);
700 gtk_widget_set_window (widget, window);
701 g_object_ref (window);
703 gtk_widget_get_allocation (widget, &allocation);
705 attributes.window_type = GDK_WINDOW_CHILD;
706 attributes.x = allocation.x;
707 attributes.y = allocation.y;
708 attributes.width = allocation.width;
709 attributes.height = allocation.height;
710 attributes.wclass = GDK_INPUT_ONLY;
711 attributes.event_mask = gtk_widget_get_events (widget);
712 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK);
714 tabber->priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
715 &attributes, GDK_WA_X | GDK_WA_Y);
716 gdk_window_set_user_data (tabber->priv->event_window, tabber);
719 static void
720 anjuta_tabber_unrealize (GtkWidget *widget)
722 AnjutaTabber* tabber = ANJUTA_TABBER (widget);
723 gdk_window_set_user_data (tabber->priv->event_window, NULL);
724 gdk_window_destroy (tabber->priv->event_window);
725 tabber->priv->event_window = NULL;
727 GTK_WIDGET_CLASS (anjuta_tabber_parent_class)->unrealize (widget);
730 static void
731 anjuta_tabber_map (GtkWidget* widget)
733 AnjutaTabber* tabber = ANJUTA_TABBER (widget);
734 gtk_widget_set_mapped (widget, TRUE);
736 gdk_window_show_unraised (tabber->priv->event_window);
738 GTK_WIDGET_CLASS (anjuta_tabber_parent_class)->map (widget);
741 static void
742 anjuta_tabber_unmap (GtkWidget* widget)
744 AnjutaTabber* tabber = ANJUTA_TABBER (widget);
746 gtk_widget_set_mapped (widget, FALSE);
747 gdk_window_hide (tabber->priv->event_window);
749 GTK_WIDGET_CLASS (anjuta_tabber_parent_class)->unmap (widget);
753 static void
754 anjuta_tabber_add (GtkContainer* container, GtkWidget* widget)
756 g_return_if_fail (ANJUTA_IS_TABBER (container));
757 g_return_if_fail (GTK_IS_WIDGET (widget));
759 AnjutaTabber* tabber = ANJUTA_TABBER (container);
760 gboolean visible = gtk_widget_get_visible (widget);
762 tabber->priv->children = g_list_append (tabber->priv->children, widget);
763 gtk_widget_set_parent (widget, GTK_WIDGET (tabber));
764 if (visible)
766 gtk_container_resize_children (GTK_CONTAINER (tabber));
767 gtk_widget_queue_resize (widget);
771 static void
772 anjuta_tabber_remove (GtkContainer* container, GtkWidget* widget)
774 g_return_if_fail (ANJUTA_IS_TABBER (container));
775 g_return_if_fail (GTK_IS_WIDGET (widget));
777 AnjutaTabber* tabber = ANJUTA_TABBER (container);
778 gboolean visible = gtk_widget_get_visible (widget);
780 gtk_widget_unparent (widget);
781 tabber->priv->children = g_list_remove (tabber->priv->children, widget);
783 if (tabber->priv->active_page > 0)
784 tabber->priv->active_page--;
786 if (visible)
787 gtk_widget_queue_resize (GTK_WIDGET (tabber));
790 static void
791 anjuta_tabber_forall (GtkContainer* container,
792 gboolean include_internals,
793 GtkCallback callback,
794 gpointer callback_data)
796 g_return_if_fail (ANJUTA_IS_TABBER (container));
797 AnjutaTabber* tabber = ANJUTA_TABBER (container);
798 GList* child;
799 for (child = tabber->priv->children; child != NULL; child = g_list_next (child))
801 (* callback) (GTK_WIDGET(child->data), callback_data);
805 static GtkWidgetPath*
806 anjuta_tabber_get_path_for_child (GtkContainer* container,
807 GtkWidget* widget)
809 AnjutaTabber* tabber = ANJUTA_TABBER (container);
811 GtkWidgetPath* path;
812 gint page_num;;
813 gint tabber_pos;
815 path = GTK_CONTAINER_CLASS (anjuta_tabber_parent_class)->get_path_for_child (container, widget);
817 page_num = g_list_index (tabber->priv->children, widget);
818 if (page_num == -1)
819 return path;
821 tabber_pos = gtk_widget_path_length (path) - 2;
822 gtk_widget_path_iter_add_region (path, tabber_pos, GTK_STYLE_REGION_TAB,
823 anjuta_tabber_get_region_flags (tabber, page_num));
824 return path;
827 static void
828 anjuta_tabber_class_init (AnjutaTabberClass *klass)
830 GObjectClass* object_class = G_OBJECT_CLASS (klass);
831 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
832 GtkContainerClass* container_class = GTK_CONTAINER_CLASS (klass);
834 object_class->finalize = anjuta_tabber_finalize;
835 object_class->dispose = anjuta_tabber_dispose;
836 object_class->set_property = anjuta_tabber_set_property;
837 object_class->get_property = anjuta_tabber_get_property;
839 widget_class->get_preferred_height = anjuta_tabber_get_preferred_height;
840 widget_class->get_preferred_width = anjuta_tabber_get_preferred_width;
841 widget_class->size_allocate = anjuta_tabber_size_allocate;
842 widget_class->draw = anjuta_tabber_draw;
843 widget_class->button_press_event = anjuta_tabber_button_press_event;
844 widget_class->realize = anjuta_tabber_realize;
845 widget_class->unrealize = anjuta_tabber_unrealize;
846 widget_class->map = anjuta_tabber_map;
847 widget_class->unmap = anjuta_tabber_unmap;
849 container_class->add = anjuta_tabber_add;
850 container_class->remove = anjuta_tabber_remove;
851 container_class->forall = anjuta_tabber_forall;
852 container_class->get_path_for_child = anjuta_tabber_get_path_for_child;
854 g_object_class_install_property (object_class,
855 PROP_NOTEBOOK,
856 g_param_spec_object ("notebook",
857 "a GtkNotebook",
858 "GtkNotebook the tabber is associated with",
859 G_TYPE_OBJECT,
860 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
862 /* Install some notebook properties */
863 gtk_widget_class_install_style_property (widget_class,
864 g_param_spec_int ("tab-overlap", "", "",
865 G_MININT,
866 G_MAXINT,
868 G_PARAM_READABLE));
869 gtk_widget_class_install_style_property (widget_class,
870 g_param_spec_int ("tab-curvature", "", "",
872 G_MAXINT,
874 G_PARAM_READABLE));
876 g_type_class_add_private (klass, sizeof (AnjutaTabberPriv));
880 * anjuta_tabber_new:
881 * @notebook: the GtkNotebook the tabber should be associated with
883 * Creates a new AnjutaTabber widget
885 * Returns: newly created AnjutaTabber widget
887 GtkWidget* anjuta_tabber_new (GtkNotebook* notebook)
889 GtkWidget* tabber;
890 tabber = GTK_WIDGET (g_object_new (ANJUTA_TYPE_TABBER, "notebook", notebook, NULL));
892 return tabber;
896 * anjuta_tabber_add_tab:
897 * @tabber: a AnjutaTabber widget
898 * @tab_label: widget used as tab label
900 * Adds a tab to the AnjutaTabber widget
902 void anjuta_tabber_add_tab (AnjutaTabber* tabber, GtkWidget* tab_label)
904 gtk_container_add (GTK_CONTAINER (tabber), tab_label);