1 --- gtk+-2.6.4/gtk/gtknotebook.c 2004-09-27 06:43:55.000000000 +0300
2 +++ gtk+-2.6.4/gtk/gtknotebook.c 2005-04-06 16:19:37.033908352 +0300
6 #define TAB_CURVATURE 1
8 +#define ARROW_WIDTH 20
9 +#define ARROW_HEIGHT 27
10 #define ARROW_SPACING 0
11 -#define NOTEBOOK_INIT_SCROLL_DELAY (200)
12 -#define NOTEBOOK_SCROLL_DELAY (100)
13 +#define LABEL_PADDING 0
31 static void gtk_notebook_update_labels (GtkNotebook *notebook);
32 -static gint gtk_notebook_timer (GtkNotebook *notebook);
33 +static gint gtk_notebook_timer (GtkNotebook *notebook );
34 static gint gtk_notebook_page_compare (gconstpointer a,
36 static GList* gtk_notebook_find_child (GtkNotebook *notebook,
38 g_param_spec_boolean ("scrollable",
40 P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
44 g_object_class_install_property (gobject_class,
50 + /* Hildon: for adding paddings to the inner borders of the visible page */
51 + gtk_widget_class_install_style_property (widget_class,
52 + g_param_spec_int ("inner_left_border",
53 + _("Inner left border of the visible page"),
54 + _("Width of inner left border of the visible page"),
59 + gtk_widget_class_install_style_property (widget_class,
60 + g_param_spec_int ("inner_right_border",
61 + _("Inner right border of the visible page"),
62 + _("Width of inner right border of the visible page"),
68 + /* Hildon: previously hardcoded constants ARROW_WIDTH, ARROW_HEIGHT,
69 + ARROW_SPACING, TAB_OVERLAP and TAB_CURVATURE are now style properties */
70 + gtk_widget_class_install_style_property (widget_class,
71 + g_param_spec_int ("arrow-width",
73 + _("Scroll arrow width"),
78 + gtk_widget_class_install_style_property (widget_class,
79 + g_param_spec_int ("arrow-height",
81 + _("Scroll arrow height"),
86 + gtk_widget_class_install_style_property (widget_class,
87 + g_param_spec_int ("arrow-spacing",
89 + _("Scroll arrow spacing"),
94 + gtk_widget_class_install_style_property (widget_class,
95 + g_param_spec_int ("tab-overlap",
101 + G_PARAM_READABLE));
102 + gtk_widget_class_install_style_property (widget_class,
103 + g_param_spec_int ("tab-curvature",
104 + _("Tab curvature"),
105 + _("Tab curvature"),
109 + G_PARAM_READABLE));
110 + gtk_widget_class_install_style_property (widget_class,
111 + g_param_spec_int ("label-padding",
112 + _("Label padding"),
113 + _("Label padding"),
117 + G_PARAM_READABLE));
119 notebook_signals[SWITCH_PAGE] =
120 g_signal_new ("switch_page",
121 G_TYPE_FROM_CLASS (gobject_class),
122 @@ -705,11 +776,10 @@
123 notebook->show_tabs = TRUE;
124 notebook->show_border = TRUE;
125 notebook->tab_pos = GTK_POS_TOP;
126 - notebook->scrollable = FALSE;
127 + notebook->scrollable = TRUE;
128 notebook->in_child = 0;
129 notebook->click_child = 0;
130 notebook->button = 0;
131 - notebook->need_timer = 0;
132 notebook->child_has_focus = FALSE;
133 notebook->have_visible_child = FALSE;
134 notebook->focus_out = FALSE;
135 @@ -1189,9 +1259,18 @@
136 GtkRequisition child_requisition;
137 gboolean switch_page = FALSE;
140 + gint focus_width, label_padding;
141 + gint arrow_width, arrow_height, arrow_spacing, tab_overlap, tab_curvature;
143 - gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
144 + gtk_widget_style_get (widget,
145 + "focus-line-width", &focus_width,
146 + "arrow-width", &arrow_width,
147 + "arrow-height", &arrow_height,
148 + "arrow-spacing", &arrow_spacing,
149 + "tab-overlap", &tab_overlap,
150 + "tab-curvature", &tab_curvature,
151 + "label-padding", &label_padding,
154 widget->requisition.width = 0;
155 widget->requisition.height = 0;
156 @@ -1229,6 +1308,22 @@
158 widget->requisition.width += widget->style->xthickness * 2;
159 widget->requisition.height += widget->style->ythickness * 2;
161 + /* Hildon kludge: inner border paddings */
162 + if (notebook->children && notebook->show_border)
164 + gint inner_left_border, inner_right_border;
166 + gtk_widget_style_get (widget,
167 + "inner_left_border",
168 + &inner_left_border,
169 + "inner_right_border",
170 + &inner_right_border,
173 + widget->requisition.width += inner_left_border + inner_right_border;
177 if (notebook->show_tabs)
179 @@ -1249,6 +1344,7 @@
181 gtk_widget_size_request (page->tab_label,
183 + child_requisition.width += 2 * label_padding;
185 page->requisition.width =
186 child_requisition.width +
187 @@ -1292,10 +1388,10 @@
189 if (notebook->scrollable && vis_pages > 1 &&
190 widget->requisition.width < tab_width)
191 - tab_height = MAX (tab_height, ARROW_SIZE);
192 + tab_height = MAX (tab_height, arrow_height);
194 - padding = 2 * (TAB_CURVATURE + focus_width +
195 - notebook->tab_hborder) - TAB_OVERLAP;
196 + padding = 2 * (tab_curvature + focus_width +
197 + notebook->tab_hborder) - tab_overlap;
201 @@ -1316,15 +1412,15 @@
203 if (notebook->scrollable && vis_pages > 1 &&
204 widget->requisition.width < tab_width)
205 - tab_width = tab_max + 2 * (ARROW_SIZE + ARROW_SPACING);
206 + tab_width = tab_max + 2 * (arrow_width + arrow_spacing);
208 if (notebook->homogeneous && !notebook->scrollable)
209 widget->requisition.width = MAX (widget->requisition.width,
210 vis_pages * tab_max +
214 widget->requisition.width = MAX (widget->requisition.width,
215 - tab_width + TAB_OVERLAP);
216 + tab_width + tab_overlap);
218 widget->requisition.height += tab_height;
220 @@ -1335,10 +1431,10 @@
222 if (notebook->scrollable && vis_pages > 1 &&
223 widget->requisition.height < tab_height)
224 - tab_width = MAX (tab_width, ARROW_SPACING + 2 * ARROW_SIZE);
225 + tab_width = MAX (tab_width, arrow_spacing + 2 * arrow_width);
227 - padding = 2 * (TAB_CURVATURE + focus_width +
228 - notebook->tab_vborder) - TAB_OVERLAP;
229 + padding = 2 * (tab_curvature + focus_width +
230 + notebook->tab_vborder) - tab_overlap;
234 @@ -1361,24 +1457,24 @@
236 if (notebook->scrollable && vis_pages > 1 &&
237 widget->requisition.height < tab_height)
238 - tab_height = tab_max + ARROW_SIZE + ARROW_SPACING;
239 + tab_height = tab_max + arrow_height + arrow_spacing;
241 widget->requisition.width += tab_width;
243 if (notebook->homogeneous && !notebook->scrollable)
244 widget->requisition.height =
245 MAX (widget->requisition.height,
246 - vis_pages * tab_max + TAB_OVERLAP);
247 + vis_pages * tab_max + tab_overlap);
249 widget->requisition.height =
250 MAX (widget->requisition.height,
251 - tab_height + TAB_OVERLAP);
252 + tab_height + tab_overlap);
254 if (!notebook->homogeneous || notebook->scrollable)
256 widget->requisition.height = MAX (widget->requisition.height,
257 vis_pages * tab_max +
263 @@ -1499,7 +1595,26 @@
267 + /* Hildon kludge: inner border paddings */
268 + if (notebook->show_border)
270 + gint inner_left_border, inner_right_border;
272 + gtk_widget_style_get (widget,
273 + "inner_left_border",
274 + &inner_left_border,
275 + "inner_right_border",
276 + &inner_right_border,
279 + child_allocation.x += inner_left_border;
280 + child_allocation.width -= inner_left_border + inner_right_border;
281 + if (child_allocation.width < 0)
282 + child_allocation.width = 0;
285 children = notebook->children;
289 page = children->data;
290 @@ -1580,11 +1695,18 @@
291 GdkRectangle event_window_pos;
292 gboolean before = ARROW_IS_BEFORE (arrow);
293 gboolean left = ARROW_IS_LEFT (arrow);
294 + gint arrow_width, arrow_height, arrow_spacing;
296 + gtk_widget_style_get (GTK_WIDGET(notebook),
297 + "arrow-width", &arrow_width,
298 + "arrow-height", &arrow_height,
299 + "arrow-spacing", &arrow_spacing,
302 if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
304 - rectangle->width = ARROW_SIZE;
305 - rectangle->height = ARROW_SIZE;
306 + rectangle->width = arrow_width;
307 + rectangle->height = arrow_height;
309 switch (notebook->tab_pos)
311 @@ -1602,6 +1724,8 @@
312 rectangle->y += event_window_pos.height - rectangle->height;
315 + arrow_spacing = - arrow_spacing;
320 @@ -1617,7 +1741,11 @@
322 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
324 - rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
325 + rectangle->y = event_window_pos.y;
326 + if (arrow_spacing > 0)
327 + rectangle->y += arrow_spacing;
329 + rectangle->y += (event_window_pos.height - rectangle->height) / 2;
333 @@ -1696,6 +1824,10 @@
334 gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
335 gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
336 (!ARROW_IS_LEFT (arrow) && is_rtl);
337 + GtkSettings *settings = gtk_settings_get_default ();
340 + g_object_get (settings, "gtk-initial-timeout", &timeout, NULL);
342 if (!GTK_WIDGET_HAS_FOCUS (widget))
343 gtk_widget_grab_focus (widget);
344 @@ -1706,14 +1838,14 @@
345 if (event->button == 1)
347 gtk_notebook_do_arrow (notebook, arrow);
350 if (!notebook->timer)
352 - notebook->timer = g_timeout_add (NOTEBOOK_INIT_SCROLL_DELAY,
353 - (GSourceFunc) gtk_notebook_timer,
354 - (gpointer) notebook);
355 - notebook->need_timer = TRUE;
358 + notebook->timer = g_timeout_add (timeout,
359 + (GSourceFunc) gtk_notebook_timer,
360 + (gpointer) notebook);
361 + notebook->need_timer = TRUE;
364 else if (event->button == 2)
365 gtk_notebook_page_select (notebook, TRUE);
366 @@ -1862,7 +1994,7 @@
368 stop_scrolling (GtkNotebook *notebook)
370 - if (notebook->timer)
371 + if (notebook->timer)
373 g_source_remove (notebook->timer);
375 @@ -2343,9 +2475,9 @@
377 return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
379 - return focus_tabs_move (notebook, direction, STEP_PREV);
380 + return focus_tabs_move (notebook, direction, STEP_PREV_CYCLE);
382 - return focus_tabs_move (notebook, direction, STEP_NEXT);
383 + return focus_tabs_move (notebook, direction, STEP_NEXT_CYCLE);
386 else /* Focus was not on widget */
387 @@ -2481,7 +2613,6 @@
388 * gtk_notebook_redraw_tabs
389 * gtk_notebook_real_remove
390 * gtk_notebook_update_labels
391 - * gtk_notebook_timer
392 * gtk_notebook_page_compare
393 * gtk_notebook_real_page_position
394 * gtk_notebook_search_page
395 @@ -2574,22 +2705,27 @@
396 gtk_notebook_timer (GtkNotebook *notebook)
398 gboolean retval = FALSE;
400 + GtkSettings *settings;
402 GDK_THREADS_ENTER ();
404 + settings = gtk_settings_get_default ();
405 + g_object_get (settings, "gtk-update-timeout", &timeout, NULL);
409 gtk_notebook_do_arrow (notebook, notebook->click_child);
411 - if (notebook->need_timer)
413 - notebook->need_timer = FALSE;
414 - notebook->timer = g_timeout_add (NOTEBOOK_SCROLL_DELAY,
415 - (GSourceFunc) gtk_notebook_timer,
416 - (gpointer) notebook);
418 + if (notebook->need_timer)
420 + notebook->need_timer = FALSE;
421 + notebook->timer = g_timeout_add (timeout,
422 + (GSourceFunc) gtk_notebook_timer,
423 + (gpointer) notebook);
430 GDK_THREADS_LEAVE ();
431 @@ -2781,10 +2917,12 @@
435 + case STEP_PREV_CYCLE:
440 + case STEP_NEXT_CYCLE:
441 flag = GTK_PACK_START;
444 @@ -2827,6 +2965,37 @@
449 + /* Hildon hack: keyboard navigation should cycle around */
450 + if (direction == STEP_PREV_CYCLE)
452 + /* find and return the last (visible) page */
453 + list = g_list_last (notebook->children);
459 + if (GTK_WIDGET_VISIBLE (page->child))
464 + if (direction == STEP_NEXT_CYCLE)
466 + /* find and return the first (visible) page */
467 + list = g_list_first (notebook->children);
473 + if (GTK_WIDGET_VISIBLE (page->child))
482 @@ -2850,6 +3019,7 @@
483 gint gap_x = 0, gap_width = 0, step = STEP_PREV;
486 + gboolean paint_box_gap = FALSE;
488 g_return_if_fail (GTK_IS_NOTEBOOK (widget));
489 g_return_if_fail (area != NULL);
490 @@ -2933,15 +3103,37 @@
494 - gtk_paint_box_gap (widget->style, widget->window,
495 - GTK_STATE_NORMAL, GTK_SHADOW_OUT,
496 - area, widget, "notebook",
497 - x, y, width, height,
498 - tab_pos, gap_x, gap_width);
500 + /* hildon hack to postpone painting until it
501 + is known if scroll arrows will be drawn */
502 + paint_box_gap = TRUE;
505 + /* first, figure out if arrows should be drawn */
507 children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
508 + while (children && !showarrow)
510 + page = children->data;
511 + children = gtk_notebook_search_page (notebook, children,
513 + if (!GTK_WIDGET_MAPPED (page->tab_label))
517 + /* then draw content area frame */
519 + gtk_paint_box_gap (widget->style, widget->window,
520 + GTK_STATE_NORMAL, GTK_SHADOW_OUT,
522 + (showarrow && notebook->scrollable)
523 + ? "notebook_show_arrow"
525 + x, y, width, height,
526 + tab_pos, gap_x, gap_width);
528 + /* and finally draw tabs */
529 + children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
532 page = children->data;
533 @@ -3069,10 +3261,15 @@
534 GdkRectangle arrow_rect;
536 gboolean is_rtl, left;
537 + gint arrow_width, arrow_height;
539 gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
541 widget = GTK_WIDGET (notebook);
542 + gtk_widget_style_get (widget,
543 + "arrow-width", &arrow_width,
544 + "arrow-height", &arrow_height,
547 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
548 left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
549 @@ -3112,7 +3309,7 @@
550 gtk_paint_arrow (widget->style, widget->window, state_type,
551 shadow_type, NULL, widget, "notebook",
552 arrow, TRUE, arrow_rect.x, arrow_rect.y,
553 - ARROW_SIZE, ARROW_SIZE);
554 + arrow_width, arrow_height);
558 @@ -3143,13 +3340,25 @@
559 gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL &&
560 (tab_pos == GTK_POS_TOP || tab_pos == GTK_POS_BOTTOM));
562 + gboolean truncate = FALSE;
563 + gint arrow_width, arrow_height, arrow_spacing, tab_overlap;
564 + gint total_width, ideal_tab_width, n_expanding_tabs;
566 if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
569 + gtk_widget_style_get (widget,
570 + "arrow-width", &arrow_width,
571 + "arrow-height", &arrow_height,
572 + "arrow-spacing", &arrow_spacing,
573 + "tab-overlap", &tab_overlap,
576 child_allocation.x = widget->allocation.x + container->border_width;
577 child_allocation.y = widget->allocation.y + container->border_width;
579 + total_width = allocation->width - 2 * container->border_width - tab_overlap;
584 @@ -3198,27 +3407,26 @@
585 if (GTK_WIDGET_VISIBLE (page->child))
586 tab_space += page->requisition.width;
589 - allocation->width - 2 * container->border_width - TAB_OVERLAP)
590 + if (tab_space > total_width)
593 page = focus_tab->data;
595 - tab_space = allocation->width - TAB_OVERLAP -
596 + tab_space = allocation->width - tab_overlap -
597 page->requisition.width - 2 * container->border_width;
598 if (notebook->has_after_previous)
599 - tab_space -= ARROW_SPACING + ARROW_SIZE;
600 + tab_space -= arrow_spacing + arrow_width;
601 if (notebook->has_after_next)
602 - tab_space -= ARROW_SPACING + ARROW_SIZE;
603 + tab_space -= arrow_spacing + arrow_width;
604 if (notebook->has_before_previous)
606 - tab_space -= ARROW_SPACING + ARROW_SIZE;
607 - child_allocation.x += ARROW_SPACING + ARROW_SIZE;
608 + tab_space -= arrow_spacing + arrow_width;
609 + child_allocation.x += arrow_spacing + arrow_width;
611 if (notebook->has_before_next)
613 - tab_space -= ARROW_SPACING + ARROW_SIZE;
614 - child_allocation.x += ARROW_SPACING + ARROW_SIZE;
615 + tab_space -= arrow_spacing + arrow_width;
616 + child_allocation.x += arrow_spacing + arrow_width;
620 @@ -3233,19 +3441,19 @@
621 tab_space += page->requisition.height;
624 - (allocation->height - 2 * container->border_width - TAB_OVERLAP))
625 + (allocation->height - 2 * container->border_width - tab_overlap))
628 page = focus_tab->data;
629 tab_space = allocation->height
630 - - TAB_OVERLAP - 2 * container->border_width
631 + - tab_overlap - 2 * container->border_width
632 - page->requisition.height;
633 if (notebook->has_after_previous || notebook->has_after_next)
634 - tab_space -= ARROW_SPACING + ARROW_SIZE;
635 + tab_space -= arrow_spacing + arrow_height;
636 if (notebook->has_before_previous || notebook->has_before_next)
638 - tab_space -= ARROW_SPACING + ARROW_SIZE;
639 - child_allocation.y += ARROW_SPACING + ARROW_SIZE;
640 + tab_space -= arrow_spacing + arrow_height;
641 + child_allocation.y += arrow_spacing + arrow_height;
645 @@ -3257,6 +3465,10 @@
646 notebook->first_tab = focus_tab;
647 last_child = gtk_notebook_search_page (notebook, focus_tab,
650 + /* Hildon: there is only one visible tab label
651 + and it doesn't fit unless it is truncated */
656 @@ -3413,7 +3625,7 @@
658 tab_space -= allocation->height;
660 - tab_space += 2 * container->border_width + TAB_OVERLAP;
661 + tab_space += 2 * container->border_width + tab_overlap;
663 notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
665 @@ -3432,12 +3644,29 @@
668 if (notebook->has_after_previous)
669 - child_allocation.x -= ARROW_SPACING + ARROW_SIZE;
670 + child_allocation.x -= arrow_spacing + arrow_width;
671 if (notebook->has_after_next)
672 - child_allocation.x -= ARROW_SPACING + ARROW_SIZE;
673 + child_allocation.x -= arrow_spacing + arrow_width;
677 + ideal_tab_width = (total_width / n);
678 + n_expanding_tabs = 0;
682 + if (children == last_child)
685 + page = children->data;
686 + children = gtk_notebook_search_page (notebook, children, STEP_NEXT,TRUE);
688 + if (page->requisition.width <= ideal_tab_width)
689 + n_expanding_tabs++;
692 + children = notebook->first_tab;
696 if (children == last_child)
697 @@ -3452,9 +3681,11 @@
698 children = gtk_notebook_search_page (notebook, children, STEP_NEXT,TRUE);
701 - if (n && (showarrow || page->expand || notebook->homogeneous))
703 + if (n && (showarrow || page->expand || notebook->homogeneous) &&
704 + (page->requisition.width <= ideal_tab_width))
706 - new_fill = (tab_space * i++) / n;
707 + new_fill = (tab_space * i++) / n_expanding_tabs;
708 delta = new_fill - old_fill;
711 @@ -3463,15 +3694,18 @@
718 child_allocation.width = (page->requisition.width +
719 - TAB_OVERLAP + delta);
720 + tab_overlap + delta);
722 child_allocation.x -= child_allocation.width;
726 child_allocation.height = (page->requisition.height +
727 - TAB_OVERLAP + delta);
728 + tab_overlap + delta);
732 @@ -3482,13 +3716,13 @@
736 - child_allocation.x += child_allocation.width - TAB_OVERLAP;
737 + child_allocation.x += child_allocation.width - tab_overlap;
739 - child_allocation.x += TAB_OVERLAP;
740 + child_allocation.x += tab_overlap;
744 - child_allocation.y += child_allocation.height - TAB_OVERLAP;
745 + child_allocation.y += child_allocation.height - tab_overlap;
749 @@ -3538,14 +3772,14 @@
752 child_allocation.width = (page->requisition.width +
753 - TAB_OVERLAP + delta);
754 + tab_overlap + delta);
756 child_allocation.x -= child_allocation.width;
760 child_allocation.height = (page->requisition.height +
761 - TAB_OVERLAP + delta);
762 + tab_overlap + delta);
763 child_allocation.y -= child_allocation.height;
766 @@ -3557,13 +3791,13 @@
770 - child_allocation.x += TAB_OVERLAP;
771 + child_allocation.x += tab_overlap;
773 - child_allocation.x += child_allocation.width - TAB_OVERLAP;
774 + child_allocation.x += child_allocation.width - tab_overlap;
778 - child_allocation.y += TAB_OVERLAP;
779 + child_allocation.y += tab_overlap;
783 @@ -3589,8 +3823,12 @@
786 gint tab_pos = get_effective_tab_pos (notebook);
787 + gint tab_curvature;
789 - gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
790 + gtk_widget_style_get (widget,
791 + "focus-line-width", &focus_width,
792 + "tab-curvature", &tab_curvature,
795 xthickness = widget->style->xthickness;
796 ythickness = widget->style->ythickness;
797 @@ -3621,7 +3859,7 @@
801 - padding = TAB_CURVATURE + focus_width + notebook->tab_hborder;
802 + padding = tab_curvature + focus_width + notebook->tab_hborder;
805 child_allocation.x = (xthickness + focus_width +
806 @@ -3646,7 +3884,7 @@
810 - padding = TAB_CURVATURE + focus_width + notebook->tab_vborder;
811 + padding = tab_curvature + focus_width + notebook->tab_vborder;
814 child_allocation.y = ythickness + padding;
815 @@ -4340,7 +4578,7 @@
817 page->tab_label = tab_label;
818 page->menu_label = menu_label;
819 - page->expand = FALSE;
820 + page->expand = TRUE;
822 page->pack = GTK_PACK_START;
824 @@ -5046,6 +5284,7 @@
826 page->default_tab = FALSE;
827 page->tab_label = tab_label;
829 gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));