]> Pileus Git - ~andy/gtk/blob - gtk/gtknotebook.c
fecef3b6b8370ac038fe27a75e320af4622403f8
[~andy/gtk] / gtk / gtknotebook.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 #include "gtknotebook.h"
28 #include "gtksignal.h"
29 #include "gtkmain.h"
30 #include "gtkmenu.h"
31 #include "gtkmenuitem.h"
32 #include "gtklabel.h"
33 #include <gdk/gdkkeysyms.h>
34 #include <stdio.h>
35 #include "gtkintl.h"
36
37
38 #define TAB_OVERLAP    2
39 #define TAB_CURVATURE  1
40 #define ARROW_SIZE     12
41 #define ARROW_SPACING  0
42 #define FOCUS_WIDTH    1
43 #define NOTEBOOK_INIT_SCROLL_DELAY (200)
44 #define NOTEBOOK_SCROLL_DELAY      (100)
45
46
47 enum {
48   SWITCH_PAGE,
49   LAST_SIGNAL
50 };
51
52 enum {
53   STEP_PREV,
54   STEP_NEXT
55 };
56
57 enum {
58   ARG_0,
59   ARG_TAB_POS,
60   ARG_SHOW_TABS,
61   ARG_SHOW_BORDER,
62   ARG_SCROLLABLE,
63   ARG_TAB_BORDER,
64   ARG_TAB_HBORDER,
65   ARG_TAB_VBORDER,
66   ARG_PAGE,
67   ARG_ENABLE_POPUP,
68   ARG_HOMOGENEOUS
69 };
70
71 enum {
72   CHILD_ARG_0,
73   CHILD_ARG_TAB_LABEL,
74   CHILD_ARG_MENU_LABEL,
75   CHILD_ARG_POSITION,
76   CHILD_ARG_TAB_EXPAND,
77   CHILD_ARG_TAB_FILL,
78   CHILD_ARG_TAB_PACK
79 };
80
81 #define GTK_NOTEBOOK_PAGE(_glist_)         ((GtkNotebookPage *)((GList *)(_glist_))->data)
82
83 struct _GtkNotebookPage
84 {
85   GtkWidget *child;
86   GtkWidget *tab_label;
87   GtkWidget *menu_label;
88
89   guint default_menu : 1;       /* If true, we create the menu label ourself */
90   guint default_tab  : 1;       /* If true, we create the tab label ourself */
91   guint expand       : 1;
92   guint fill         : 1;
93   guint pack         : 1;
94
95   GtkRequisition requisition;
96   GtkAllocation allocation;
97 };
98
99 #ifdef G_DISABLE_CHECKS
100 #define CHECK_FIND_CHILD(notebook, child)                           \
101  gtk_notebook_find_child(notebook, child,                           \
102                          G_GNUC_PRETTY_FUNCTION)
103 #else
104 #define CHECK_FIND_CHILD(notebook, child)                           \
105  gtk_notebook_find_child(notebook, child, NULL)
106 #endif
107  
108 /*** GtkNotebook Methods ***/
109 static void gtk_notebook_class_init          (GtkNotebookClass *klass);
110 static void gtk_notebook_init                (GtkNotebook      *notebook);
111
112 /*** GtkObject Methods ***/
113 static void gtk_notebook_destroy             (GtkObject        *object);
114 static void gtk_notebook_set_arg             (GtkObject        *object,
115                                               GtkArg           *arg,
116                                               guint             arg_id);
117 static void gtk_notebook_get_arg             (GtkObject        *object,
118                                               GtkArg           *arg,
119                                               guint             arg_id);
120
121 /*** GtkWidget Methods ***/
122 static void gtk_notebook_map                 (GtkWidget        *widget);
123 static void gtk_notebook_unmap               (GtkWidget        *widget);
124 static void gtk_notebook_realize             (GtkWidget        *widget);
125 static void gtk_notebook_unrealize           (GtkWidget        *widget);
126 static void gtk_notebook_size_request        (GtkWidget        *widget,
127                                               GtkRequisition   *requisition);
128 static void gtk_notebook_size_allocate       (GtkWidget        *widget,
129                                               GtkAllocation    *allocation);
130 static gint gtk_notebook_expose              (GtkWidget        *widget,
131                                               GdkEventExpose   *event);
132 static gint gtk_notebook_button_press        (GtkWidget        *widget,
133                                               GdkEventButton   *event);
134 static gint gtk_notebook_button_release      (GtkWidget        *widget,
135                                               GdkEventButton   *event);
136 static gint gtk_notebook_enter_notify        (GtkWidget        *widget,
137                                               GdkEventCrossing *event);
138 static gint gtk_notebook_leave_notify        (GtkWidget        *widget,
139                                               GdkEventCrossing *event);
140 static gint gtk_notebook_motion_notify       (GtkWidget        *widget,
141                                               GdkEventMotion   *event);
142 static gint gtk_notebook_key_press           (GtkWidget        *widget,
143                                               GdkEventKey      *event);
144 static gint gtk_notebook_focus_in            (GtkWidget        *widget,
145                                               GdkEventFocus    *event);
146 static gint gtk_notebook_focus_out           (GtkWidget        *widget,
147                                               GdkEventFocus    *event);
148 static void gtk_notebook_draw_focus          (GtkWidget        *widget);
149 static void gtk_notebook_style_set           (GtkWidget        *widget,
150                                               GtkStyle         *previous_style);
151
152 /*** GtkContainer Methods ***/
153 static void gtk_notebook_set_child_arg       (GtkContainer     *container,
154                                               GtkWidget        *child,
155                                               GtkArg           *arg,
156                                               guint             arg_id);
157 static void gtk_notebook_get_child_arg       (GtkContainer     *container,
158                                               GtkWidget        *child,
159                                               GtkArg           *arg,
160                                               guint             arg_id);
161 static void gtk_notebook_add                 (GtkContainer     *container,
162                                               GtkWidget        *widget);
163 static void gtk_notebook_remove              (GtkContainer     *container,
164                                               GtkWidget        *widget);
165 static gint gtk_notebook_focus               (GtkContainer     *container,
166                                               GtkDirectionType  direction);
167 static void gtk_notebook_set_focus_child     (GtkContainer     *container,
168                                               GtkWidget        *child);
169 static GtkType gtk_notebook_child_type       (GtkContainer     *container);
170 static void gtk_notebook_forall              (GtkContainer     *container,
171                                               gboolean          include_internals,
172                                               GtkCallback       callback,
173                                               gpointer          callback_data);
174
175 /*** GtkNotebook Private Functions ***/
176 static void gtk_notebook_panel_realize       (GtkNotebook      *notebook);
177 static void gtk_notebook_redraw_tabs         (GtkNotebook      *notebook);
178 static void gtk_notebook_redraw_arrows       (GtkNotebook      *notebook);
179 static void gtk_notebook_focus_changed       (GtkNotebook      *notebook,
180                                               GtkNotebookPage  *old_page);
181 static void gtk_notebook_real_remove         (GtkNotebook      *notebook,
182                                               GList            *list);
183 static void gtk_notebook_update_labels       (GtkNotebook      *notebook);
184 static gint gtk_notebook_timer               (GtkNotebook      *notebook);
185 static gint gtk_notebook_page_compare        (gconstpointer     a,
186                                               gconstpointer     b);
187 static GList *gtk_notebook_find_child        (GtkNotebook      *notebook,
188                                               GtkWidget        *child,
189                                               const gchar      *function);
190 static gint  gtk_notebook_real_page_position (GtkNotebook      *notebook,
191                                               GList            *list);
192 static GList * gtk_notebook_search_page      (GtkNotebook      *notebook,
193                                               GList            *list,
194                                               gint              direction,
195                                               gboolean          find_visible);
196
197 /*** GtkNotebook Drawing Functions ***/
198 static void gtk_notebook_paint               (GtkWidget        *widget,
199                                               GdkRectangle     *area);
200 static void gtk_notebook_draw_tab            (GtkNotebook      *notebook,
201                                               GtkNotebookPage  *page,
202                                               GdkRectangle     *area);
203 static void gtk_notebook_draw_arrow          (GtkNotebook      *notebook,
204                                               guint             arrow);
205 static void gtk_notebook_set_shape           (GtkNotebook      *notebook);
206
207 /*** GtkNotebook Size Allocate Functions ***/
208 static void gtk_notebook_pages_allocate      (GtkNotebook      *notebook);
209 static void gtk_notebook_page_allocate       (GtkNotebook      *notebook,
210                                               GtkNotebookPage  *page,
211                                               GtkAllocation    *allocation);
212 static void gtk_notebook_calc_tabs           (GtkNotebook      *notebook,
213                                               GList            *start,
214                                               GList           **end,
215                                               gint             *tab_space,
216                                               guint             direction);
217
218 /*** GtkNotebook Page Switch Methods ***/
219 static void gtk_notebook_real_switch_page    (GtkNotebook      *notebook,
220                                               GtkNotebookPage  *page,
221                                               guint             page_num);
222
223 /*** GtkNotebook Page Switch Functions ***/
224 static void gtk_notebook_switch_page         (GtkNotebook      *notebook,
225                                               GtkNotebookPage  *page,
226                                               gint              page_num);
227 static gint gtk_notebook_page_select         (GtkNotebook      *notebook,
228                                               gboolean          move_focus);
229 static void gtk_notebook_switch_focus_tab    (GtkNotebook      *notebook,
230                                               GList            *new_child);
231 static void gtk_notebook_menu_switch_page    (GtkWidget        *widget,
232                                               GtkNotebookPage  *page);
233
234 /*** GtkNotebook Menu Functions ***/
235 static void gtk_notebook_menu_item_create    (GtkNotebook      *notebook,
236                                               GList            *list);
237 static void gtk_notebook_menu_label_unparent (GtkWidget        *widget,
238                                               gpointer          data);
239 static void gtk_notebook_menu_detacher       (GtkWidget        *widget,
240                                               GtkMenu          *menu);
241
242
243 static GtkContainerClass *parent_class = NULL;
244 static guint notebook_signals[LAST_SIGNAL] = { 0 };
245
246 GtkType
247 gtk_notebook_get_type (void)
248 {
249   static GtkType notebook_type = 0;
250
251   if (!notebook_type)
252     {
253       static const GtkTypeInfo notebook_info =
254       {
255         "GtkNotebook",
256         sizeof (GtkNotebook),
257         sizeof (GtkNotebookClass),
258         (GtkClassInitFunc) gtk_notebook_class_init,
259         (GtkObjectInitFunc) gtk_notebook_init,
260         /* reserved_1 */ NULL,
261         /* reserved_2 */ NULL,
262         (GtkClassInitFunc) NULL,
263       };
264
265       notebook_type = gtk_type_unique (gtk_container_get_type (), &notebook_info);
266     }
267
268   return notebook_type;
269 }
270
271 static void
272 gtk_notebook_class_init (GtkNotebookClass *class)
273 {
274   GtkObjectClass *object_class;
275   GtkWidgetClass *widget_class;
276   GtkContainerClass *container_class;
277
278   object_class = (GtkObjectClass*) class;
279   widget_class = (GtkWidgetClass*) class;
280   container_class = (GtkContainerClass*) class;
281   parent_class = gtk_type_class (gtk_container_get_type ());
282
283
284   object_class->set_arg = gtk_notebook_set_arg;
285   object_class->get_arg = gtk_notebook_get_arg;
286   object_class->destroy = gtk_notebook_destroy;
287
288   widget_class->map = gtk_notebook_map;
289   widget_class->unmap = gtk_notebook_unmap;
290   widget_class->realize = gtk_notebook_realize;
291   widget_class->unrealize = gtk_notebook_unrealize;
292   widget_class->size_request = gtk_notebook_size_request;
293   widget_class->size_allocate = gtk_notebook_size_allocate;
294   widget_class->expose_event = gtk_notebook_expose;
295   widget_class->button_press_event = gtk_notebook_button_press;
296   widget_class->button_release_event = gtk_notebook_button_release;
297   widget_class->enter_notify_event = gtk_notebook_enter_notify;
298   widget_class->leave_notify_event = gtk_notebook_leave_notify;
299   widget_class->motion_notify_event = gtk_notebook_motion_notify;
300   widget_class->key_press_event = gtk_notebook_key_press;
301   widget_class->focus_in_event = gtk_notebook_focus_in;
302   widget_class->focus_out_event = gtk_notebook_focus_out;
303   widget_class->draw_focus = gtk_notebook_draw_focus;
304   widget_class->style_set = gtk_notebook_style_set;
305    
306   container_class->add = gtk_notebook_add;
307   container_class->remove = gtk_notebook_remove;
308   container_class->forall = gtk_notebook_forall;
309   container_class->focus = gtk_notebook_focus;
310   container_class->set_focus_child = gtk_notebook_set_focus_child;
311   container_class->get_child_arg = gtk_notebook_get_child_arg;
312   container_class->set_child_arg = gtk_notebook_set_child_arg;
313   container_class->child_type = gtk_notebook_child_type;
314
315   class->switch_page = gtk_notebook_real_switch_page;
316
317   gtk_object_add_arg_type ("GtkNotebook::page", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_PAGE);
318   gtk_object_add_arg_type ("GtkNotebook::tab_pos", GTK_TYPE_POSITION_TYPE, GTK_ARG_READWRITE, ARG_TAB_POS);
319   gtk_object_add_arg_type ("GtkNotebook::tab_border", GTK_TYPE_UINT, GTK_ARG_WRITABLE, ARG_TAB_BORDER);
320   gtk_object_add_arg_type ("GtkNotebook::tab_hborder", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_TAB_HBORDER);
321   gtk_object_add_arg_type ("GtkNotebook::tab_vborder", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_TAB_VBORDER);
322   gtk_object_add_arg_type ("GtkNotebook::show_tabs", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_SHOW_TABS);
323   gtk_object_add_arg_type ("GtkNotebook::show_border", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_SHOW_BORDER);
324   gtk_object_add_arg_type ("GtkNotebook::scrollable", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_SCROLLABLE);
325   gtk_object_add_arg_type ("GtkNotebook::enable_popup", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_ENABLE_POPUP);
326   gtk_object_add_arg_type ("GtkNotebook::homogeneous", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HOMOGENEOUS);
327
328   gtk_container_add_child_arg_type ("GtkNotebook::tab_label", GTK_TYPE_STRING, GTK_ARG_READWRITE, CHILD_ARG_TAB_LABEL);
329   gtk_container_add_child_arg_type ("GtkNotebook::menu_label", GTK_TYPE_STRING, GTK_ARG_READWRITE, CHILD_ARG_MENU_LABEL);
330   gtk_container_add_child_arg_type ("GtkNotebook::position", GTK_TYPE_INT, GTK_ARG_READWRITE, CHILD_ARG_POSITION);
331   gtk_container_add_child_arg_type ("GtkNotebook::tab_fill", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_TAB_FILL);
332   gtk_container_add_child_arg_type ("GtkNotebook::tab_pack", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_TAB_PACK);
333
334   notebook_signals[SWITCH_PAGE] =
335     gtk_signal_new ("switch_page",
336                     GTK_RUN_LAST,
337                     GTK_CLASS_TYPE (object_class),
338                     GTK_SIGNAL_OFFSET (GtkNotebookClass, switch_page),
339                     gtk_marshal_VOID__POINTER_UINT,
340                     GTK_TYPE_NONE, 2,
341                     GTK_TYPE_POINTER,
342                     GTK_TYPE_UINT);
343 }
344
345 static void
346 gtk_notebook_init (GtkNotebook *notebook)
347 {
348   GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS | GTK_RECEIVES_DEFAULT);
349   GTK_WIDGET_UNSET_FLAGS (notebook, GTK_NO_WINDOW);
350
351   notebook->cur_page = NULL;
352   notebook->children = NULL;
353   notebook->first_tab = NULL;
354   notebook->focus_tab = NULL;
355   notebook->panel = NULL;
356   notebook->menu = NULL;
357
358   notebook->tab_hborder = 2;
359   notebook->tab_vborder = 2;
360
361   notebook->show_tabs = TRUE;
362   notebook->show_border = TRUE;
363   notebook->tab_pos = GTK_POS_TOP;
364   notebook->scrollable = FALSE;
365   notebook->in_child = 0;
366   notebook->click_child = 0;
367   notebook->button = 0;
368   notebook->need_timer = 0;
369   notebook->child_has_focus = FALSE;
370   notebook->have_visible_child = FALSE;
371 }
372
373 /**
374  * gtk_notebook_new:
375  * @void: 
376  * 
377  * Creates a new #GtkNotebook widget with no pages.
378
379  * Return value: the newly created #GtkNotebook
380  **/
381 GtkWidget*
382 gtk_notebook_new (void)
383 {
384   return GTK_WIDGET (gtk_type_new (gtk_notebook_get_type ()));
385 }
386
387 /* Private GtkObject Methods :
388  * 
389  * gtk_notebook_destroy
390  * gtk_notebook_set_arg
391  * gtk_notebook_get_arg
392  */
393 static void
394 gtk_notebook_destroy (GtkObject *object)
395 {
396   GtkNotebook *notebook;
397   
398   g_return_if_fail (object != NULL);
399   g_return_if_fail (GTK_IS_NOTEBOOK (object));
400
401   notebook = GTK_NOTEBOOK (object);
402
403   if (notebook->menu)
404     gtk_notebook_popup_disable (notebook);
405
406   GTK_OBJECT_CLASS (parent_class)->destroy (object);
407 }
408
409 static void
410 gtk_notebook_set_arg (GtkObject *object,
411                       GtkArg    *arg,
412                       guint      arg_id)
413 {
414   GtkNotebook *notebook;
415
416   notebook = GTK_NOTEBOOK (object);
417
418   switch (arg_id)
419     {
420     case ARG_SHOW_TABS:
421       gtk_notebook_set_show_tabs (notebook, GTK_VALUE_BOOL (*arg));
422       break;
423     case ARG_SHOW_BORDER:
424       gtk_notebook_set_show_border (notebook, GTK_VALUE_BOOL (*arg));
425       break;
426     case ARG_SCROLLABLE:
427       gtk_notebook_set_scrollable (notebook, GTK_VALUE_BOOL (*arg));
428       break;
429     case ARG_ENABLE_POPUP:
430       if (GTK_VALUE_BOOL (*arg))
431         gtk_notebook_popup_enable (notebook);
432       else
433         gtk_notebook_popup_disable (notebook);
434       break;
435     case ARG_HOMOGENEOUS:
436       gtk_notebook_set_homogeneous_tabs (notebook, GTK_VALUE_BOOL (*arg));
437       break;  
438     case ARG_PAGE:
439       gtk_notebook_set_page (notebook, GTK_VALUE_INT (*arg));
440       break;
441     case ARG_TAB_POS:
442       gtk_notebook_set_tab_pos (notebook, GTK_VALUE_ENUM (*arg));
443       break;
444     case ARG_TAB_BORDER:
445       gtk_notebook_set_tab_border (notebook, GTK_VALUE_UINT (*arg));
446       break;
447     case ARG_TAB_HBORDER:
448       gtk_notebook_set_tab_hborder (notebook, GTK_VALUE_UINT (*arg));
449       break;
450     case ARG_TAB_VBORDER:
451       gtk_notebook_set_tab_vborder (notebook, GTK_VALUE_UINT (*arg));
452       break;
453     default:
454       break;
455     }
456 }
457
458 static void
459 gtk_notebook_get_arg (GtkObject *object,
460                       GtkArg    *arg,
461                       guint      arg_id)
462 {
463   GtkNotebook *notebook;
464
465   notebook = GTK_NOTEBOOK (object);
466
467   switch (arg_id)
468     {
469     case ARG_SHOW_TABS:
470       GTK_VALUE_BOOL (*arg) = notebook->show_tabs;
471       break;
472     case ARG_SHOW_BORDER:
473       GTK_VALUE_BOOL (*arg) = notebook->show_border;
474       break;
475     case ARG_SCROLLABLE:
476       GTK_VALUE_BOOL (*arg) = notebook->scrollable;
477       break;
478     case ARG_ENABLE_POPUP:
479       GTK_VALUE_BOOL (*arg) = notebook->menu != NULL;
480       break;
481     case ARG_HOMOGENEOUS:
482       GTK_VALUE_BOOL (*arg) = notebook->homogeneous;
483       break;
484     case ARG_PAGE:
485       GTK_VALUE_INT (*arg) = gtk_notebook_get_current_page (notebook);
486       break;
487     case ARG_TAB_POS:
488       GTK_VALUE_ENUM (*arg) = notebook->tab_pos;
489       break;
490     case ARG_TAB_HBORDER:
491       GTK_VALUE_UINT (*arg) = notebook->tab_hborder;
492       break;
493     case ARG_TAB_VBORDER:
494       GTK_VALUE_UINT (*arg) = notebook->tab_vborder;
495       break;
496     default:
497       arg->type = GTK_TYPE_INVALID;
498       break;
499     }
500 }
501
502 /* Private GtkWidget Methods :
503  * 
504  * gtk_notebook_map
505  * gtk_notebook_unmap
506  * gtk_notebook_realize
507  * gtk_notebook_size_request
508  * gtk_notebook_size_allocate
509  * gtk_notebook_expose
510  * gtk_notebook_button_press
511  * gtk_notebook_button_release
512  * gtk_notebook_enter_notify
513  * gtk_notebook_leave_notify
514  * gtk_notebook_motion_notify
515  * gtk_notebook_key_press
516  * gtk_notebook_focus_in
517  * gtk_notebook_focus_out
518  * gtk_notebook_draw_focus
519  * gtk_notebook_style_set
520  */
521 static void
522 gtk_notebook_map (GtkWidget *widget)
523 {
524   GtkNotebook *notebook;
525   GtkNotebookPage *page;
526   GList *children;
527
528   g_return_if_fail (widget != NULL);
529   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
530
531   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
532
533   notebook = GTK_NOTEBOOK (widget);
534
535   if (notebook->cur_page && 
536       GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
537       !GTK_WIDGET_MAPPED (notebook->cur_page->child))
538     gtk_widget_map (notebook->cur_page->child);
539
540   if (notebook->scrollable)
541     gtk_notebook_pages_allocate (notebook);
542   else
543     {
544       children = notebook->children;
545
546       while (children)
547         {
548           page = children->data;
549           children = children->next;
550
551           if (page->tab_label &&
552               GTK_WIDGET_VISIBLE (page->tab_label) &&
553               !GTK_WIDGET_MAPPED (page->tab_label))
554             gtk_widget_map (page->tab_label);
555         }
556     }
557
558   gdk_window_show (widget->window);
559 }
560
561 static void
562 gtk_notebook_unmap (GtkWidget *widget)
563 {
564   g_return_if_fail (widget != NULL);
565   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
566
567   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
568   gdk_window_hide (widget->window);
569   if (GTK_NOTEBOOK (widget)->panel)
570     gdk_window_hide (GTK_NOTEBOOK (widget)->panel);
571 }
572
573 static void
574 gtk_notebook_realize (GtkWidget *widget)
575 {
576   GtkNotebook *notebook;
577   GdkWindowAttr attributes;
578   gint attributes_mask;
579
580   g_return_if_fail (widget != NULL);
581   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
582
583   notebook = GTK_NOTEBOOK (widget);
584   GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
585
586   attributes.window_type = GDK_WINDOW_CHILD;
587   attributes.x = widget->allocation.x;
588   attributes.y = widget->allocation.y;
589   attributes.width = widget->allocation.width;
590   attributes.height = widget->allocation.height;
591   attributes.wclass = GDK_INPUT_OUTPUT;
592   attributes.visual = gtk_widget_get_visual (widget);
593   attributes.colormap = gtk_widget_get_colormap (widget);
594   attributes.event_mask = gtk_widget_get_events (widget);
595   attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
596                             GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK);
597
598   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
599
600   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
601   gdk_window_set_user_data (widget->window, notebook);
602
603   widget->style = gtk_style_attach (widget->style, widget->window);
604   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
605
606   gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
607   if (notebook->scrollable)
608     gtk_notebook_panel_realize (notebook);
609 }
610
611 static void
612 gtk_notebook_unrealize (GtkWidget *widget)
613 {
614   GtkNotebook *notebook;
615
616   g_return_if_fail (widget != NULL);
617   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
618
619   notebook = GTK_NOTEBOOK (widget);
620
621   if (notebook->panel)
622     {
623       gdk_window_set_user_data (notebook->panel, NULL);
624       gdk_window_destroy (notebook->panel);
625       notebook->panel = NULL;
626     }
627
628   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
629     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
630 }
631
632 static void
633 gtk_notebook_size_request (GtkWidget      *widget,
634                            GtkRequisition *requisition)
635 {
636   GtkNotebook *notebook;
637   GtkNotebookPage *page;
638   GList *children;
639   GtkRequisition child_requisition;
640   gboolean switch_page = FALSE;
641   gint vis_pages;
642
643   g_return_if_fail (widget != NULL);
644   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
645   g_return_if_fail (requisition != NULL);
646
647   notebook = GTK_NOTEBOOK (widget);
648   widget->requisition.width = 0;
649   widget->requisition.height = 0;
650
651   for (children = notebook->children, vis_pages = 0; children;
652        children = children->next)
653     {
654       page = children->data;
655
656       if (GTK_WIDGET_VISIBLE (page->child))
657         {
658           vis_pages++;
659           gtk_widget_size_request (page->child, &child_requisition);
660           
661           widget->requisition.width = MAX (widget->requisition.width,
662                                            child_requisition.width);
663           widget->requisition.height = MAX (widget->requisition.height,
664                                             child_requisition.height);
665
666           if (GTK_WIDGET_MAPPED (page->child) && page != notebook->cur_page)
667             gtk_widget_unmap (page->child);
668           if (notebook->menu && page->menu_label->parent &&
669               !GTK_WIDGET_VISIBLE (page->menu_label->parent))
670             gtk_widget_show (page->menu_label->parent);
671         }
672       else
673         {
674           if (page == notebook->cur_page)
675             switch_page = TRUE;
676           if (notebook->menu && page->menu_label->parent &&
677               GTK_WIDGET_VISIBLE (page->menu_label->parent))
678             gtk_widget_hide (page->menu_label->parent);
679         }
680     }
681
682   if (notebook->show_border || notebook->show_tabs)
683     {
684       widget->requisition.width += widget->style->xthickness * 2;
685       widget->requisition.height += widget->style->ythickness * 2;
686
687       if (notebook->show_tabs)
688         {
689           gint tab_width = 0;
690           gint tab_height = 0;
691           gint tab_max = 0;
692           gint padding;
693           
694           for (children = notebook->children; children;
695                children = children->next)
696             {
697               page = children->data;
698               
699               if (GTK_WIDGET_VISIBLE (page->child))
700                 {
701                   if (!GTK_WIDGET_VISIBLE (page->tab_label))
702                     gtk_widget_show (page->tab_label);
703
704                   gtk_widget_size_request (page->tab_label,
705                                            &child_requisition);
706
707                   page->requisition.width = 
708                     child_requisition.width +
709                     2 * widget->style->xthickness;
710                   page->requisition.height = 
711                     child_requisition.height +
712                     2 * widget->style->ythickness;
713                   
714                   switch (notebook->tab_pos)
715                     {
716                     case GTK_POS_TOP:
717                     case GTK_POS_BOTTOM:
718                       page->requisition.height += 2 * (notebook->tab_vborder +
719                                                        FOCUS_WIDTH);
720                       tab_height = MAX (tab_height, page->requisition.height);
721                       tab_max = MAX (tab_max, page->requisition.width);
722                       break;
723                     case GTK_POS_LEFT:
724                     case GTK_POS_RIGHT:
725                       page->requisition.width += 2 * (notebook->tab_hborder +
726                                                       FOCUS_WIDTH);
727                       tab_width = MAX (tab_width, page->requisition.width);
728                       tab_max = MAX (tab_max, page->requisition.height);
729                       break;
730                     }
731                 }
732               else if (GTK_WIDGET_VISIBLE (page->tab_label))
733                 gtk_widget_hide (page->tab_label);
734             }
735
736           children = notebook->children;
737
738           if (vis_pages)
739             {
740               switch (notebook->tab_pos)
741                 {
742                 case GTK_POS_TOP:
743                 case GTK_POS_BOTTOM:
744                   if (tab_height == 0)
745                     break;
746
747                   if (notebook->scrollable && vis_pages > 1 && 
748                       widget->requisition.width < tab_width)
749                     tab_height = MAX (tab_height, ARROW_SIZE);
750
751                   padding = 2 * (TAB_CURVATURE + FOCUS_WIDTH +
752                                  notebook->tab_hborder) - TAB_OVERLAP;
753                   tab_max += padding;
754                   while (children)
755                     {
756                       page = children->data;
757                       children = children->next;
758                   
759                       if (!GTK_WIDGET_VISIBLE (page->child))
760                         continue;
761
762                       if (notebook->homogeneous)
763                         page->requisition.width = tab_max;
764                       else
765                         page->requisition.width += padding;
766
767                       tab_width += page->requisition.width;
768                       page->requisition.height = tab_height;
769                     }
770
771                   if (notebook->scrollable && vis_pages > 1 &&
772                       widget->requisition.width < tab_width)
773                     tab_width = tab_max + 2 * (ARROW_SIZE + ARROW_SPACING);
774
775                   if (notebook->homogeneous && !notebook->scrollable)
776                     widget->requisition.width = MAX (widget->requisition.width,
777                                                      vis_pages * tab_max +
778                                                      TAB_OVERLAP);
779                   else
780                     widget->requisition.width = MAX (widget->requisition.width,
781                                                      tab_width + TAB_OVERLAP);
782
783                   widget->requisition.height += tab_height;
784                   break;
785                 case GTK_POS_LEFT:
786                 case GTK_POS_RIGHT:
787                   if (tab_width == 0)
788                     break;
789
790                   if (notebook->scrollable && vis_pages > 1 && 
791                       widget->requisition.height < tab_height)
792                     tab_width = MAX (tab_width, ARROW_SPACING +2 * ARROW_SIZE);
793
794                   padding = 2 * (TAB_CURVATURE + FOCUS_WIDTH +
795                                  notebook->tab_vborder) - TAB_OVERLAP;
796                   tab_max += padding;
797
798                   while (children)
799                     {
800                       page = children->data;
801                       children = children->next;
802
803                       if (!GTK_WIDGET_VISIBLE (page->child))
804                         continue;
805
806                       page->requisition.width   = tab_width;
807
808                       if (notebook->homogeneous)
809                         page->requisition.height = tab_max;
810                       else
811                         page->requisition.height += padding;
812
813                       tab_height += page->requisition.height;
814                     }
815
816                   if (notebook->scrollable && vis_pages > 1 && 
817                       widget->requisition.height < tab_height)
818                     tab_height = tab_max + ARROW_SIZE + ARROW_SPACING;
819
820                   widget->requisition.width += tab_width;
821
822                   if (notebook->homogeneous && !notebook->scrollable)
823                     widget->requisition.height =
824                       MAX (widget->requisition.height,
825                            vis_pages * tab_max + TAB_OVERLAP);
826                   else
827                     widget->requisition.height =
828                       MAX (widget->requisition.height,
829                            tab_height + TAB_OVERLAP);
830
831                   if (!notebook->homogeneous || notebook->scrollable)
832                     vis_pages = 1;
833                   widget->requisition.height = MAX (widget->requisition.height,
834                                                     vis_pages * tab_max +
835                                                     TAB_OVERLAP);
836                   break;
837                 }
838             }
839         }
840       else
841         {
842           for (children = notebook->children; children;
843                children = children->next)
844             {
845               page = children->data;
846               
847               if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
848                 gtk_widget_hide (page->tab_label);
849             }
850         }
851     }
852
853   widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
854   widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
855
856   if (switch_page)
857     {
858       if (vis_pages)
859         {
860           for (children = notebook->children; children;
861                children = children->next)
862             {
863               page = children->data;
864               if (GTK_WIDGET_VISIBLE (page->child))
865                 {
866                   gtk_notebook_switch_page (notebook, page, -1);
867                   break;
868                 }
869             }
870         }
871       else if (GTK_WIDGET_VISIBLE (widget))
872         {
873           widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
874           widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
875         }
876     }
877   if (vis_pages && !notebook->cur_page)
878     {
879       children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
880       if (children)
881         {
882           notebook->first_tab = children;
883           gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
884         }
885     }
886 }
887
888 static void
889 gtk_notebook_size_allocate (GtkWidget     *widget,
890                             GtkAllocation *allocation)
891 {
892   GtkNotebook *notebook;
893   GtkNotebookPage *page;
894   GtkAllocation child_allocation;
895   GList *children;
896
897   g_return_if_fail (widget != NULL);
898   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
899   g_return_if_fail (allocation != NULL);
900
901   widget->allocation = *allocation;
902   if (GTK_WIDGET_REALIZED (widget))
903     gdk_window_move_resize (widget->window,
904                             allocation->x, allocation->y,
905                             allocation->width, allocation->height);
906
907   notebook = GTK_NOTEBOOK (widget);
908   if (notebook->children)
909     {
910       child_allocation.x = GTK_CONTAINER (widget)->border_width;
911       child_allocation.y = GTK_CONTAINER (widget)->border_width;
912       child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
913       child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
914
915       if (notebook->show_tabs || notebook->show_border)
916         {
917           child_allocation.x += widget->style->xthickness;
918           child_allocation.y += widget->style->ythickness;
919           child_allocation.width = MAX (1, (gint)child_allocation.width -
920                                         (gint) widget->style->xthickness * 2);
921           child_allocation.height = MAX (1, (gint)child_allocation.height -
922                                          (gint) widget->style->ythickness * 2);
923
924           if (notebook->show_tabs && notebook->children && notebook->cur_page)
925             {
926               switch (notebook->tab_pos)
927                 {
928                 case GTK_POS_TOP:
929                   child_allocation.y += notebook->cur_page->requisition.height;
930                 case GTK_POS_BOTTOM:
931                   child_allocation.height =
932                     MAX (1, (gint)child_allocation.height -
933                          (gint)notebook->cur_page->requisition.height);
934                   break;
935                 case GTK_POS_LEFT:
936                   child_allocation.x += notebook->cur_page->requisition.width;
937                 case GTK_POS_RIGHT:
938                   child_allocation.width =
939                     MAX (1, (gint)child_allocation.width -
940                          (gint)notebook->cur_page->requisition.width);
941                   break;
942                 }
943             }
944         }
945
946       children = notebook->children;
947       while (children)
948         {
949           page = children->data;
950           children = children->next;
951           
952           if (GTK_WIDGET_VISIBLE (page->child))
953             gtk_widget_size_allocate (page->child, &child_allocation);
954         }
955
956       gtk_notebook_pages_allocate (notebook);
957     }
958    gtk_notebook_set_shape (notebook);
959 }
960
961 static gint
962 gtk_notebook_expose (GtkWidget      *widget,
963                      GdkEventExpose *event)
964 {
965   GtkNotebook *notebook;
966   GdkEventExpose child_event;
967   GdkRectangle child_area;
968    
969   g_return_val_if_fail (widget != NULL, FALSE);
970   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
971   g_return_val_if_fail (event != NULL, FALSE);
972
973   if (GTK_WIDGET_DRAWABLE (widget))
974     {
975       notebook = GTK_NOTEBOOK (widget);
976
977       gtk_notebook_paint (widget, &event->area);
978       if (notebook->show_tabs)
979         {
980           if (notebook->cur_page && 
981               gtk_widget_intersect (notebook->cur_page->tab_label, 
982                                     &event->area, &child_area))
983             gtk_widget_draw_focus (widget);
984         }
985
986       child_event = *event;
987       if (notebook->cur_page && 
988           GTK_WIDGET_NO_WINDOW (notebook->cur_page->child) &&
989           gtk_widget_intersect (notebook->cur_page->child, &event->area, 
990                                 &child_event.area))
991         gtk_widget_event (notebook->cur_page->child, (GdkEvent*) &child_event);
992     }
993
994   return FALSE;
995 }
996
997 static gboolean
998 gtk_notebook_arrow_button_press (GtkNotebook    *notebook,
999                                  GdkEventButton *event)
1000 {
1001   GtkWidget *widget = GTK_WIDGET (notebook);
1002   
1003   GtkArrowType arrow = event->x <= ARROW_SIZE + ARROW_SPACING / 2 ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT;
1004
1005   if (!GTK_WIDGET_HAS_FOCUS (widget))
1006     gtk_widget_grab_focus (widget);
1007   
1008   notebook->button = event->button;
1009   notebook->click_child = arrow;
1010   
1011   if (event->button == 1)
1012     {
1013       if (!notebook->focus_tab ||
1014           gtk_notebook_search_page (notebook, notebook->focus_tab,
1015                                     arrow == GTK_ARROW_LEFT ? STEP_PREV : STEP_NEXT,
1016                                     TRUE))
1017         gtk_container_focus (GTK_CONTAINER (notebook),
1018                              arrow == GTK_ARROW_LEFT ? GTK_DIR_LEFT : GTK_DIR_RIGHT);
1019       
1020       if (!notebook->timer)
1021         {
1022           notebook->timer = gtk_timeout_add 
1023             (NOTEBOOK_INIT_SCROLL_DELAY, 
1024              (GtkFunction) gtk_notebook_timer, (gpointer) notebook);
1025           notebook->need_timer = TRUE;
1026         }
1027     }
1028   else if (event->button == 2)
1029     gtk_notebook_page_select (notebook, TRUE);
1030   else if (event->button == 3)
1031     gtk_notebook_switch_focus_tab (notebook,
1032                                    gtk_notebook_search_page (notebook,
1033                                                              NULL,
1034                                                              arrow == GTK_ARROW_LEFT ? STEP_NEXT : STEP_PREV,
1035                                                              TRUE));
1036   gtk_notebook_redraw_arrows (notebook);
1037
1038   return TRUE;
1039 }
1040
1041 static gboolean
1042 gtk_notebook_button_press (GtkWidget      *widget,
1043                            GdkEventButton *event)
1044 {
1045   GtkNotebook *notebook;
1046   GtkNotebookPage *page;
1047   GList *children;
1048   gint num;
1049
1050   g_return_val_if_fail (widget != NULL, FALSE);
1051   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1052   g_return_val_if_fail (event != NULL, FALSE);
1053
1054   notebook = GTK_NOTEBOOK (widget);
1055
1056   if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
1057       notebook->button)
1058     return FALSE;
1059
1060   if (event->window == notebook->panel)
1061     {
1062       return gtk_notebook_arrow_button_press (notebook, event);
1063     }
1064   else if (event->window == widget->window)
1065     {
1066       if (event->button == 3 && notebook->menu)
1067         {
1068           gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL, 
1069                           NULL, NULL, 3, event->time);
1070           return TRUE;
1071         }
1072
1073       num = 0;
1074       children = notebook->children;
1075       while (children)
1076         {
1077           page = children->data;
1078           
1079           if (GTK_WIDGET_VISIBLE (page->child) &&
1080               page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
1081               (event->x >= page->allocation.x) &&
1082               (event->y >= page->allocation.y) &&
1083               (event->x <= (page->allocation.x + page->allocation.width)) &&
1084               (event->y <= (page->allocation.y + page->allocation.height)))
1085             {
1086               if (page == notebook->cur_page && notebook->focus_tab &&
1087                   notebook->focus_tab != children &&
1088                   GTK_WIDGET_HAS_FOCUS (notebook))
1089                 {
1090                   GtkNotebookPage *old_page;
1091
1092                   notebook->child_has_focus = FALSE;
1093                   old_page = (GtkNotebookPage *)
1094                               (notebook->focus_tab->data);
1095                   gtk_notebook_switch_focus_tab (notebook, children);
1096                   gtk_notebook_focus_changed (notebook, old_page);
1097                 }
1098               else
1099                 {
1100                   gtk_notebook_switch_focus_tab (notebook, children);
1101                   gtk_widget_grab_focus (widget);
1102                   gtk_notebook_switch_page (notebook, page, num);
1103                 }
1104               break;
1105             }
1106           children = children->next;
1107           num++;
1108         }
1109       if (!children && !GTK_WIDGET_HAS_FOCUS (widget))
1110         gtk_widget_grab_focus (widget);
1111     }
1112    
1113   return TRUE;
1114 }
1115
1116 static gint
1117 gtk_notebook_button_release (GtkWidget      *widget,
1118                              GdkEventButton *event)
1119 {
1120   GtkNotebook *notebook;
1121
1122   g_return_val_if_fail (widget != NULL, FALSE);
1123   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1124   g_return_val_if_fail (event != NULL, FALSE);
1125
1126   if (event->type != GDK_BUTTON_RELEASE)
1127     return FALSE;
1128
1129   notebook = GTK_NOTEBOOK (widget);
1130
1131   if (event->button == notebook->button)
1132     {
1133       guint click_child;
1134
1135       if (notebook->timer)
1136         {
1137           gtk_timeout_remove (notebook->timer);
1138           notebook->timer = 0;
1139           notebook->need_timer = FALSE;
1140         }
1141       click_child = notebook->click_child;
1142       notebook->click_child = 0;
1143       notebook->button = 0;
1144       gtk_notebook_redraw_arrows (notebook);
1145       
1146     }
1147   return FALSE;
1148 }
1149
1150 static gint
1151 gtk_notebook_enter_notify (GtkWidget        *widget,
1152                            GdkEventCrossing *event)
1153 {
1154   GtkNotebook *notebook;
1155
1156   g_return_val_if_fail (widget != NULL, FALSE);
1157   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1158   g_return_val_if_fail (event != NULL, FALSE);
1159
1160   notebook = GTK_NOTEBOOK (widget);
1161
1162   if (event->window == notebook->panel)
1163     {
1164       gint x;
1165       gint y;
1166
1167       gdk_window_get_pointer (notebook->panel, &x, &y, NULL);
1168
1169       if (x <= ARROW_SIZE + ARROW_SPACING / 2)
1170         notebook->in_child = GTK_ARROW_LEFT;
1171       else
1172         notebook->in_child = GTK_ARROW_RIGHT;
1173
1174       gtk_notebook_redraw_arrows (notebook);
1175     }
1176
1177   return FALSE;
1178 }
1179
1180 static gint
1181 gtk_notebook_leave_notify (GtkWidget        *widget,
1182                            GdkEventCrossing *event)
1183 {
1184   GtkNotebook *notebook;
1185
1186   g_return_val_if_fail (widget != NULL, FALSE);
1187   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1188   g_return_val_if_fail (event != NULL, FALSE);
1189
1190   notebook = GTK_NOTEBOOK (widget);
1191
1192   if (event->window == notebook->panel)
1193     gtk_notebook_redraw_arrows (notebook);
1194
1195   return FALSE;
1196 }
1197
1198 static gint
1199 gtk_notebook_motion_notify (GtkWidget      *widget,
1200                             GdkEventMotion *event)
1201 {
1202   GtkNotebook *notebook;
1203
1204   g_return_val_if_fail (widget != NULL, FALSE);
1205   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1206   g_return_val_if_fail (event != NULL, FALSE);
1207
1208   notebook = GTK_NOTEBOOK (widget);
1209   
1210   if (notebook->button)
1211     return FALSE;
1212
1213   if (event->window == notebook->panel)
1214     {
1215       gint x;
1216       GtkArrowType old_child = notebook->in_child;
1217       
1218       x = event->x;
1219       if (event->is_hint)
1220         gdk_window_get_pointer (notebook->panel, &x, NULL, NULL);
1221
1222       if (x <= ARROW_SIZE + ARROW_SPACING / 2)
1223         notebook->in_child = GTK_ARROW_LEFT;
1224       else
1225         notebook->in_child = GTK_ARROW_RIGHT;
1226
1227       if (old_child != notebook->in_child)
1228         gtk_notebook_redraw_arrows (notebook);  
1229     }
1230   
1231   return FALSE;
1232 }
1233
1234 static gint
1235 gtk_notebook_key_press (GtkWidget   *widget,
1236                         GdkEventKey *event)
1237 {
1238   GtkNotebook *notebook;
1239   GList *list;
1240
1241   g_return_val_if_fail (widget != NULL, FALSE);
1242   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1243   g_return_val_if_fail (event != NULL, FALSE);
1244
1245   notebook = GTK_NOTEBOOK (widget);
1246
1247   if (!notebook->children || !notebook->show_tabs)
1248     return FALSE;
1249
1250   switch (event->keyval)
1251     {
1252     case GDK_Home:
1253       list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1254       if (list)
1255         gtk_notebook_switch_focus_tab (notebook, list);
1256       return TRUE;
1257     case GDK_End:
1258       list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1259       if (list)
1260         gtk_notebook_switch_focus_tab (notebook, list);
1261       return TRUE;
1262     case GDK_Return:
1263       gtk_notebook_page_select (GTK_NOTEBOOK (widget), TRUE);
1264       return TRUE;
1265     case GDK_space:
1266       gtk_notebook_page_select (GTK_NOTEBOOK (widget), FALSE);
1267       return TRUE;
1268     }
1269
1270   return FALSE;
1271 }
1272
1273 static gint
1274 gtk_notebook_focus_in (GtkWidget     *widget,
1275                        GdkEventFocus *event)
1276 {
1277   g_return_val_if_fail (widget != NULL, FALSE);
1278   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1279   g_return_val_if_fail (event != NULL, FALSE);
1280
1281   GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
1282   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1283   gtk_widget_draw_focus (widget);
1284
1285   return FALSE;
1286 }
1287
1288 static gint
1289 gtk_notebook_focus_out (GtkWidget     *widget,
1290                         GdkEventFocus *event)
1291 {
1292   g_return_val_if_fail (widget != NULL, FALSE);
1293   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1294   g_return_val_if_fail (event != NULL, FALSE);
1295
1296   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
1297   gtk_widget_draw_focus (widget);
1298
1299   return FALSE;
1300 }
1301
1302 static void
1303 gtk_notebook_draw_focus (GtkWidget *widget)
1304 {
1305   GtkNotebook *notebook;
1306
1307   g_return_if_fail (widget != NULL);
1308   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1309
1310   notebook = GTK_NOTEBOOK (widget);
1311
1312   if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
1313       notebook->focus_tab)
1314     {
1315       GtkNotebookPage *page;
1316       GdkRectangle area;
1317
1318       page = notebook->focus_tab->data;
1319
1320       area.x = page->tab_label->allocation.x - 1;
1321       area.y = page->tab_label->allocation.y - 1;
1322       area.width = page->tab_label->allocation.width + 2;
1323       area.height = page->tab_label->allocation.height + 2;
1324
1325       gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
1326     }
1327 }
1328
1329 static void
1330 gtk_notebook_style_set (GtkWidget *widget,
1331                         GtkStyle  *previous_style)
1332 {
1333   if (GTK_WIDGET_REALIZED (widget) &&
1334       !GTK_WIDGET_NO_WINDOW (widget))
1335     {
1336       gtk_style_set_background (widget->style, widget->window, widget->state);
1337       if (GTK_WIDGET_DRAWABLE (widget))
1338         gdk_window_clear (widget->window);
1339     }
1340
1341   gtk_notebook_set_shape (GTK_NOTEBOOK(widget));
1342 }
1343
1344 /* Private GtkContainer Methods :
1345  * 
1346  * gtk_notebook_set_child_arg
1347  * gtk_notebook_get_child_arg
1348  * gtk_notebook_add
1349  * gtk_notebook_remove
1350  * gtk_notebook_focus
1351  * gtk_notebook_set_focus_child
1352  * gtk_notebook_child_type
1353  * gtk_notebook_forall
1354  */
1355 static void
1356 gtk_notebook_set_child_arg (GtkContainer     *container,
1357                             GtkWidget        *child,
1358                             GtkArg           *arg,
1359                             guint             arg_id)
1360 {
1361   gboolean expand;
1362   gboolean fill;
1363   GtkPackType pack_type;
1364
1365   switch (arg_id)
1366     {
1367     case CHILD_ARG_TAB_LABEL:
1368       /* a NULL pointer indicates a default_tab setting, otherwise
1369        * we need to set the associated label
1370        */
1371       gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
1372                                        GTK_VALUE_STRING(*arg));
1373       break;
1374     case CHILD_ARG_MENU_LABEL:
1375       gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
1376                                         GTK_VALUE_STRING (*arg));
1377       break;
1378     case CHILD_ARG_POSITION:
1379       gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
1380                                   GTK_VALUE_INT (*arg));
1381       break;
1382     case CHILD_ARG_TAB_EXPAND:
1383       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1384                                             &expand, &fill, &pack_type);
1385       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
1386                                           GTK_VALUE_BOOL (*arg),
1387                                           fill, pack_type);
1388       break;
1389     case CHILD_ARG_TAB_FILL:
1390       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1391                                             &expand, &fill, &pack_type);
1392       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
1393                                           expand,
1394                                           GTK_VALUE_BOOL (*arg),
1395                                           pack_type);
1396       break;
1397     case CHILD_ARG_TAB_PACK:
1398       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1399                                             &expand, &fill, &pack_type);
1400       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
1401                                           expand, fill,
1402                                           GTK_VALUE_BOOL (*arg));
1403       break;
1404     default:
1405       break;
1406     }
1407 }
1408
1409 static void
1410 gtk_notebook_get_child_arg (GtkContainer     *container,
1411                             GtkWidget        *child,
1412                             GtkArg           *arg,
1413                             guint             arg_id)
1414 {
1415   GList *list;
1416   GtkNotebook *notebook;
1417   GtkWidget *label;
1418   gboolean expand;
1419   gboolean fill;
1420   GtkPackType pack_type;
1421
1422   notebook = GTK_NOTEBOOK (container);
1423
1424   arg->type = GTK_TYPE_INVALID;
1425   
1426   list = CHECK_FIND_CHILD (notebook, child);
1427   if (!list)  
1428     {
1429       arg->type = GTK_TYPE_INVALID;
1430       return;
1431     }
1432
1433   switch (arg_id)
1434     {
1435     case CHILD_ARG_TAB_LABEL:
1436       label = gtk_notebook_get_tab_label (notebook, child);
1437
1438       if (label && GTK_IS_LABEL (label))
1439         GTK_VALUE_STRING (*arg) = g_strdup (GTK_LABEL (label)->label);
1440       else
1441         GTK_VALUE_STRING (*arg) = NULL;
1442       break;
1443     case CHILD_ARG_MENU_LABEL:
1444       label = gtk_notebook_get_menu_label (notebook, child);
1445
1446       if (label && GTK_IS_LABEL (label))
1447         GTK_VALUE_STRING (*arg) = g_strdup (GTK_LABEL (label)->label);
1448       else
1449         GTK_VALUE_STRING (*arg) = NULL;
1450       break;
1451     case CHILD_ARG_POSITION:
1452       GTK_VALUE_INT (*arg) = g_list_position (notebook->children, list);
1453       break;
1454     case CHILD_ARG_TAB_EXPAND:
1455         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1456                                               &expand, NULL, NULL);
1457         GTK_VALUE_BOOL (*arg) = expand;
1458       break;
1459     case CHILD_ARG_TAB_FILL:
1460         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1461                                               NULL, &fill, NULL);
1462         GTK_VALUE_BOOL (*arg) = fill;
1463       break;
1464     case CHILD_ARG_TAB_PACK:
1465         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1466                                               NULL, NULL, &pack_type);
1467         GTK_VALUE_BOOL (*arg) = pack_type;
1468       break;
1469     default:
1470       arg->type = GTK_TYPE_INVALID;
1471       break;
1472     }
1473 }
1474
1475 static void
1476 gtk_notebook_add (GtkContainer *container,
1477                   GtkWidget    *widget)
1478 {
1479   g_return_if_fail (container != NULL);
1480   g_return_if_fail (GTK_IS_NOTEBOOK (container));
1481
1482   gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget, 
1483                                  NULL, NULL, -1);
1484 }
1485
1486 static void
1487 gtk_notebook_remove (GtkContainer *container,
1488                      GtkWidget    *widget)
1489 {
1490   GtkNotebook *notebook;
1491   GtkNotebookPage *page;
1492   GList *children;
1493   guint page_num;
1494
1495   g_return_if_fail (container != NULL);
1496   g_return_if_fail (GTK_IS_NOTEBOOK (container));
1497   g_return_if_fail (widget != NULL);
1498
1499   notebook = GTK_NOTEBOOK (container);
1500
1501   children = notebook->children;
1502   page_num = 0;
1503   while (children)
1504     {
1505       page = children->data;
1506       if (page->child == widget)
1507         {
1508           gtk_notebook_real_remove (notebook, children);
1509           break;
1510         }
1511       page_num++;
1512       children = children->next;
1513     }
1514 }
1515
1516 static gboolean
1517 focus_tabs_in (GtkNotebook *notebook)
1518 {
1519   if (notebook->cur_page)
1520     {
1521       gtk_widget_grab_focus (GTK_WIDGET (notebook));
1522
1523       gtk_notebook_switch_focus_tab (notebook,
1524                                      g_list_find (notebook->children,
1525                                                   notebook->cur_page));
1526
1527       return TRUE;
1528     }
1529   else
1530     return FALSE;
1531 }
1532
1533 static gboolean
1534 focus_tabs_move (GtkNotebook     *notebook,
1535                  GtkDirectionType direction,
1536                  gint             search_direction)
1537 {
1538   GList *new_page;
1539
1540   new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
1541                                        search_direction, TRUE);
1542   if (!new_page)
1543     new_page = (search_direction == STEP_NEXT) ?
1544                  notebook->children :
1545                  g_list_last (notebook->children);
1546
1547   gtk_notebook_switch_focus_tab (notebook, new_page);
1548   
1549   return TRUE;
1550 }
1551
1552 static gboolean
1553 focus_child_in (GtkNotebook     *notebook,
1554                 GtkDirectionType direction)
1555 {
1556   if (GTK_WIDGET_DRAWABLE (notebook->cur_page->child) &&
1557       GTK_WIDGET_IS_SENSITIVE (notebook->cur_page->child))
1558     {
1559       if (GTK_IS_CONTAINER (notebook->cur_page->child))
1560         {
1561           if (gtk_container_focus (GTK_CONTAINER (notebook->cur_page->child), direction))
1562             return TRUE;
1563         }
1564       else if (GTK_WIDGET_CAN_FOCUS (notebook->cur_page->child))
1565         {
1566           gtk_widget_grab_focus (notebook->cur_page->child);
1567           return TRUE;
1568         }
1569     }
1570   return FALSE;
1571 }
1572
1573 /* Focus in the notebook can either be on the pages, or on
1574  * the tabs.
1575  */
1576 static gint
1577 gtk_notebook_focus (GtkContainer     *container,
1578                     GtkDirectionType  direction)
1579 {
1580   GtkWidget *old_focus_child;
1581   GtkNotebook *notebook;
1582   GtkDirectionType effective_direction;
1583
1584   /* Remap the directions into the effective direction it would be for a
1585    * GTK_POS_TOP notebook
1586    */
1587 #define D(rest) GTK_DIR_##rest
1588
1589   static const GtkDirectionType translate_direction[4][6] = {
1590     /* LEFT */   { D(TAB_FORWARD),  D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP),   D(DOWN) },
1591     /* RIGHT */  { D(TAB_BACKWARD), D(TAB_FORWARD),  D(LEFT), D(RIGHT), D(DOWN), D(UP)   },
1592     /* TOP */    { D(TAB_FORWARD),  D(TAB_BACKWARD), D(UP),   D(DOWN),  D(LEFT), D(RIGHT) },
1593     /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD),  D(DOWN), D(UP),    D(LEFT), D(RIGHT) },
1594   };
1595
1596 #undef D  
1597
1598   gboolean widget_is_focus;
1599
1600   g_return_val_if_fail (container != NULL, FALSE);
1601   g_return_val_if_fail (GTK_IS_NOTEBOOK (container), FALSE);
1602
1603   notebook = GTK_NOTEBOOK (container);
1604
1605   widget_is_focus = gtk_widget_is_focus (GTK_WIDGET (container));
1606   old_focus_child = container->focus_child; 
1607
1608   effective_direction = translate_direction[notebook->tab_pos][direction];
1609
1610   if (old_focus_child &&
1611       GTK_IS_CONTAINER (old_focus_child) &&
1612       GTK_WIDGET_DRAWABLE (old_focus_child) &&
1613       GTK_WIDGET_IS_SENSITIVE (old_focus_child) &&
1614       gtk_container_focus (GTK_CONTAINER (old_focus_child), direction))
1615     return TRUE;
1616
1617   if (old_focus_child)          /* Focus on page child */
1618     {
1619       switch (effective_direction)
1620         {
1621         case GTK_DIR_TAB_BACKWARD:
1622         case GTK_DIR_UP:
1623           /* Focus onto the tabs */
1624           if (notebook->show_tabs)
1625             return focus_tabs_in (notebook);
1626           else
1627             return FALSE;
1628         case GTK_DIR_DOWN:
1629         case GTK_DIR_TAB_FORWARD:
1630         case GTK_DIR_LEFT:
1631         case GTK_DIR_RIGHT:
1632           return FALSE;
1633         }
1634     }
1635   else if (widget_is_focus)     /* Focus was on tabs */
1636     {
1637       switch (effective_direction)
1638         {
1639         case GTK_DIR_TAB_BACKWARD:
1640         case GTK_DIR_UP:
1641           return FALSE;
1642         case GTK_DIR_TAB_FORWARD:
1643         case GTK_DIR_DOWN:
1644           return focus_child_in (notebook, direction);
1645         case GTK_DIR_LEFT:
1646           return focus_tabs_move (notebook, direction, STEP_PREV);
1647         case GTK_DIR_RIGHT:
1648           return focus_tabs_move (notebook, direction, STEP_NEXT);
1649         }
1650     }
1651   else /* Focus was not on widget */
1652     {
1653       switch (effective_direction)
1654         {
1655         case GTK_DIR_TAB_FORWARD:
1656         case GTK_DIR_DOWN:
1657           if (focus_tabs_in (notebook))
1658             return TRUE;
1659           if (focus_child_in (notebook, direction))
1660             return TRUE;
1661           return FALSE;
1662         case GTK_DIR_TAB_BACKWARD:
1663         case GTK_DIR_UP:
1664           if (focus_child_in (notebook, direction))
1665             return TRUE;
1666           if (focus_tabs_in (notebook))
1667             return TRUE;
1668           return FALSE;
1669         case GTK_DIR_LEFT:
1670         case GTK_DIR_RIGHT:
1671           return focus_child_in (notebook, direction);
1672         }
1673     }
1674
1675   g_assert_not_reached ();
1676   return FALSE;
1677 }  
1678   
1679 static void
1680 gtk_notebook_set_focus_child (GtkContainer *container,
1681                               GtkWidget    *child)
1682 {
1683   GtkNotebook *notebook;
1684
1685   g_return_if_fail (container != NULL);
1686   g_return_if_fail (GTK_IS_NOTEBOOK (container));
1687   
1688   if (child)
1689     {
1690       g_return_if_fail (GTK_IS_WIDGET (child));
1691
1692       notebook = GTK_NOTEBOOK (container);
1693
1694       notebook->child_has_focus = TRUE;
1695       if (!notebook->focus_tab)
1696         {
1697           GList *children;
1698           GtkNotebookPage *page;
1699
1700           children = notebook->children;
1701           while (children)
1702             {
1703               page = children->data;
1704               if (page->child == child || page->tab_label == child)
1705                 gtk_notebook_switch_focus_tab (notebook, children);
1706               children = children->next;
1707             }
1708         }
1709     }
1710   parent_class->set_focus_child (container, child);
1711 }
1712
1713 static void
1714 gtk_notebook_forall (GtkContainer *container,
1715                      gboolean      include_internals,
1716                      GtkCallback   callback,
1717                      gpointer      callback_data)
1718 {
1719   GtkNotebook *notebook;
1720   GList *children;
1721
1722   g_return_if_fail (container != NULL);
1723   g_return_if_fail (GTK_IS_NOTEBOOK (container));
1724   g_return_if_fail (callback != NULL);
1725
1726   notebook = GTK_NOTEBOOK (container);
1727
1728   children = notebook->children;
1729   while (children)
1730     {
1731       GtkNotebookPage *page;
1732       
1733       page = children->data;
1734       children = children->next;
1735       (* callback) (page->child, callback_data);
1736       if (include_internals)
1737         {
1738           if (page->tab_label)
1739             (* callback) (page->tab_label, callback_data);
1740           if (page->menu_label)
1741             (* callback) (page->menu_label, callback_data);
1742         }
1743     }
1744 }
1745
1746 static GtkType
1747 gtk_notebook_child_type (GtkContainer     *container)
1748 {
1749   return GTK_TYPE_WIDGET;
1750 }
1751
1752 /* Private GtkNotebook Functions:
1753  *
1754  * gtk_notebook_panel_realize
1755  * gtk_notebook_redraw_tabs
1756  * gtk_notebook_focus_changed
1757  * gtk_notebook_real_remove
1758  * gtk_notebook_update_labels
1759  * gtk_notebook_timer
1760  * gtk_notebook_page_compare
1761  * gtk_notebook_real_page_position
1762  * gtk_notebook_search_page
1763  */
1764 static void
1765 gtk_notebook_panel_realize (GtkNotebook *notebook)
1766 {
1767   GtkWidget *widget;
1768   GdkWindowAttr attributes;
1769   gint attributes_mask;
1770   
1771   g_return_if_fail (notebook != NULL);
1772   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
1773   
1774   widget = GTK_WIDGET (notebook);
1775   
1776   attributes.window_type = GDK_WINDOW_CHILD;
1777   attributes.wclass = GDK_INPUT_OUTPUT;
1778   attributes.visual = gtk_widget_get_visual (widget);
1779   attributes.colormap = gtk_widget_get_colormap (widget);
1780   attributes.event_mask = gtk_widget_get_events (widget);
1781   attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK 
1782     | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
1783     | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
1784   
1785   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1786
1787   attributes.width = 2 * ARROW_SIZE + ARROW_SPACING;
1788   attributes.height = ARROW_SIZE;
1789
1790   attributes.x = (widget->allocation.width - attributes.width - 
1791                   GTK_CONTAINER (notebook)->border_width);
1792   attributes.y = (widget->allocation.height - ARROW_SIZE -
1793                   GTK_CONTAINER (notebook)->border_width);
1794   if (notebook->tab_pos == GTK_POS_TOP)
1795     attributes.y = GTK_CONTAINER (notebook)->border_width;
1796   else if (notebook->tab_pos == GTK_POS_LEFT)
1797     attributes.x = (widget->allocation.x +
1798                     GTK_CONTAINER (notebook)->border_width);
1799
1800   notebook->panel = gdk_window_new (widget->window, &attributes, 
1801                                     attributes_mask);
1802   gtk_style_set_background (widget->style, notebook->panel, 
1803                             GTK_STATE_NORMAL);
1804   gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
1805   gdk_window_set_user_data (notebook->panel, widget);
1806 }
1807
1808 static void
1809 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
1810 {
1811   GtkWidget *widget;
1812   GtkNotebookPage *page;
1813   GdkRectangle redraw_rect;
1814   gint border;
1815
1816   widget = GTK_WIDGET (notebook);
1817   border = GTK_CONTAINER (notebook)->border_width;
1818
1819   if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
1820     return;
1821
1822   page = notebook->first_tab->data;
1823
1824   redraw_rect.x = border;
1825   redraw_rect.y = border;
1826
1827   switch (notebook->tab_pos)
1828     {
1829     case GTK_POS_BOTTOM:
1830       redraw_rect.y = (widget->allocation.height - border -
1831                        page->allocation.height -
1832                        widget->style->ythickness);
1833       if (page != notebook->cur_page)
1834         redraw_rect.y -= widget->style->ythickness;
1835       /* fall through */
1836     case GTK_POS_TOP:
1837       redraw_rect.width = widget->allocation.width - 2 * border;
1838       redraw_rect.height = (page->allocation.height +
1839                             widget->style->ythickness);
1840       if (page != notebook->cur_page)
1841         redraw_rect.height += widget->style->ythickness;
1842       break;
1843     case GTK_POS_RIGHT:
1844       redraw_rect.x = (widget->allocation.width - border -
1845                        page->allocation.width -
1846                        widget->style->xthickness);
1847       if (page != notebook->cur_page)
1848         redraw_rect.x -= widget->style->xthickness;
1849       /* fall through */
1850     case GTK_POS_LEFT:
1851       redraw_rect.width = (page->allocation.width +
1852                            widget->style->xthickness);
1853       redraw_rect.height = widget->allocation.height - 2 * border;
1854       if (page != notebook->cur_page)
1855         redraw_rect.width += widget->style->xthickness;
1856       break;
1857     }
1858
1859   gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
1860 }
1861
1862 static void
1863 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
1864 {
1865   if (GTK_WIDGET_MAPPED (notebook) && notebook->panel)
1866     gdk_window_invalidate_rect (notebook->panel, NULL, FALSE);
1867 }
1868
1869 static void
1870 gtk_notebook_focus_changed (GtkNotebook     *notebook,
1871                             GtkNotebookPage *old_page)
1872 {
1873   g_return_if_fail (notebook != NULL);
1874   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
1875
1876   if (GTK_WIDGET_DRAWABLE (notebook) && notebook->show_tabs) 
1877     {
1878       GdkRectangle area;
1879
1880       if (notebook->focus_tab)
1881         {
1882           GtkNotebookPage *page;
1883
1884           page = notebook->focus_tab->data;
1885
1886           area.x = page->tab_label->allocation.x - 1;
1887           area.y = page->tab_label->allocation.y - 1;
1888           area.width = page->tab_label->allocation.width + 2;
1889           area.height = page->tab_label->allocation.height + 2;
1890
1891           gtk_notebook_draw_tab (notebook, page, &area);
1892         }
1893
1894       if (old_page)
1895         {
1896           area.x = old_page->tab_label->allocation.x - 1;
1897           area.y = old_page->tab_label->allocation.y - 1;
1898           area.width = old_page->tab_label->allocation.width + 2;
1899           area.height = old_page->tab_label->allocation.height + 2;
1900
1901           gtk_notebook_draw_tab (notebook, old_page, &area);
1902         }
1903     }
1904 }
1905
1906 static gint
1907 gtk_notebook_timer (GtkNotebook *notebook)
1908 {
1909   gboolean retval = FALSE;
1910
1911   GDK_THREADS_ENTER ();
1912   
1913   if (notebook->timer)
1914     {
1915       if (notebook->click_child == GTK_ARROW_LEFT)
1916         {
1917           if (!notebook->focus_tab ||
1918               gtk_notebook_search_page (notebook, notebook->focus_tab,
1919                                         STEP_PREV, TRUE))
1920             gtk_container_focus (GTK_CONTAINER (notebook), GTK_DIR_LEFT);
1921         }
1922       else if (notebook->click_child == GTK_ARROW_RIGHT)
1923         {
1924           if (!notebook->focus_tab ||
1925               gtk_notebook_search_page (notebook, notebook->focus_tab,
1926                                         STEP_NEXT, TRUE))
1927             gtk_container_focus (GTK_CONTAINER (notebook), GTK_DIR_RIGHT);
1928         }
1929       if (notebook->need_timer) 
1930         {
1931           notebook->need_timer = FALSE;
1932           notebook->timer = gtk_timeout_add (NOTEBOOK_SCROLL_DELAY,
1933                                              (GtkFunction) gtk_notebook_timer, 
1934                                              (gpointer) notebook);
1935         }
1936       else
1937         retval = TRUE;
1938     }
1939
1940   GDK_THREADS_LEAVE ();
1941
1942   return retval;
1943 }
1944
1945 static gint
1946 gtk_notebook_page_compare (gconstpointer a,
1947                            gconstpointer b)
1948 {
1949   return (((GtkNotebookPage *) a)->child != b);
1950 }
1951
1952 static GList *
1953 gtk_notebook_find_child (GtkNotebook      *notebook,
1954                          GtkWidget        *child,
1955                          const gchar      *function)
1956 {
1957   GList *list = g_list_find_custom (notebook->children, child,
1958                                     gtk_notebook_page_compare);
1959
1960 #ifndef G_DISABLE_CHECKS
1961   if (!list)
1962     g_warning ("child argument to '%s' does not refer to the contents of a notebook page",
1963                function);
1964 #endif
1965
1966   return list;
1967 }
1968
1969 static void
1970 gtk_notebook_real_remove (GtkNotebook *notebook,
1971                           GList       *list)
1972 {
1973   GtkNotebookPage *page;
1974   GList * next_list;
1975   gint need_resize = FALSE;
1976
1977   next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
1978   if (!next_list)
1979     next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
1980
1981   if (notebook->cur_page == list->data)
1982     { 
1983       notebook->cur_page = NULL;
1984       if (next_list)
1985         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
1986     }
1987
1988   if (list == notebook->first_tab)
1989     notebook->first_tab = next_list;
1990   if (list == notebook->focus_tab)
1991     gtk_notebook_switch_focus_tab (notebook, next_list);
1992
1993   page = list->data;
1994
1995   if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
1996     need_resize = TRUE;
1997
1998   gtk_widget_unparent (page->child);
1999
2000   if (page->tab_label)
2001     gtk_widget_unparent (page->tab_label);
2002
2003   if (notebook->menu)
2004     {
2005       gtk_container_remove (GTK_CONTAINER (notebook->menu), 
2006                             page->menu_label->parent);
2007       gtk_widget_queue_resize (notebook->menu);
2008     }
2009   if (!page->default_menu)
2010     gtk_widget_unref (page->menu_label);
2011   
2012   notebook->children = g_list_remove_link (notebook->children, list);
2013   g_list_free (list);
2014   g_free (page);
2015
2016   gtk_notebook_update_labels (notebook);
2017   if (need_resize)
2018     gtk_widget_queue_resize (GTK_WIDGET (notebook));
2019 }
2020
2021 static void
2022 gtk_notebook_update_labels (GtkNotebook *notebook)
2023 {
2024   GtkNotebookPage *page;
2025   GList *list;
2026   gchar string[32];
2027   gint page_num = 1;
2028
2029   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
2030        list;
2031        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
2032     {
2033       page = list->data;
2034       g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
2035       if (notebook->show_tabs)
2036         {
2037           if (page->default_tab)
2038             {
2039               if (!page->tab_label)
2040                 {
2041                   page->tab_label = gtk_label_new (string);
2042                   gtk_widget_set_parent (page->tab_label,
2043                                          GTK_WIDGET (notebook));
2044                 }
2045               else
2046                 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
2047             }
2048
2049           if (GTK_WIDGET_VISIBLE (page->child) &&
2050               !GTK_WIDGET_VISIBLE (page->tab_label))
2051             gtk_widget_show (page->tab_label);
2052           else if (!GTK_WIDGET_VISIBLE (page->child) &&
2053                    GTK_WIDGET_VISIBLE (page->tab_label))
2054             gtk_widget_hide (page->tab_label);
2055         }
2056       if (notebook->menu && page->default_menu)
2057         {
2058           if (page->tab_label && GTK_IS_LABEL (page->tab_label))
2059             gtk_label_set_text (GTK_LABEL (page->menu_label),
2060                            GTK_LABEL (page->tab_label)->label);
2061           else
2062             gtk_label_set_text (GTK_LABEL (page->menu_label), string);
2063         }
2064     }  
2065 }
2066
2067 static gint
2068 gtk_notebook_real_page_position (GtkNotebook *notebook,
2069                                  GList       *list)
2070 {
2071   GList *work;
2072   gint count_start;
2073
2074   g_return_val_if_fail (notebook != NULL, -1);
2075   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
2076   g_return_val_if_fail (list != NULL, -1);
2077
2078   for (work = notebook->children, count_start = 0;
2079        work && work != list; work = work->next)
2080     if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
2081       count_start++;
2082
2083   if (!work)
2084     return -1;
2085
2086   if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
2087     return count_start;
2088
2089   return (count_start + g_list_length (list) - 1);
2090 }
2091
2092 static GList *
2093 gtk_notebook_search_page (GtkNotebook *notebook,
2094                           GList       *list,
2095                           gint         direction,
2096                           gboolean     find_visible)
2097 {
2098   GtkNotebookPage *page = NULL;
2099   GList *old_list = NULL;
2100   gint flag = 0;
2101
2102   g_return_val_if_fail (notebook != NULL, NULL);
2103   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
2104
2105   switch (direction)
2106     {
2107     case STEP_PREV:
2108       flag = GTK_PACK_END;
2109       break;
2110
2111     case STEP_NEXT:
2112       flag = GTK_PACK_START;
2113       break;
2114     }
2115
2116   if (list)
2117     page = list->data;
2118
2119   if (!page || page->pack == flag)
2120     {
2121       if (list)
2122         {
2123           old_list = list;
2124           list = list->next;
2125         }
2126       else
2127         list = notebook->children;
2128
2129       while (list)
2130         {
2131           page = list->data;
2132           if (page->pack == flag &&
2133               (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
2134             return list;
2135           old_list = list;
2136           list = list->next;
2137         }
2138       list = old_list;
2139     }
2140   else
2141     {
2142       old_list = list;
2143       list = list->prev;
2144     }
2145   while (list)
2146     {
2147       page = list->data;
2148       if (page->pack != flag &&
2149           (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
2150         return list;
2151       old_list = list;
2152       list = list->prev;
2153     }
2154   return NULL;
2155 }
2156
2157 /* Private GtkNotebook Drawing Functions:
2158  *
2159  * gtk_notebook_paint
2160  * gtk_notebook_draw_tab
2161  * gtk_notebook_draw_arrow
2162  * gtk_notebook_set_shape
2163  */
2164 static void
2165 gtk_notebook_paint (GtkWidget    *widget,
2166                     GdkRectangle *area)
2167 {
2168   GtkNotebook *notebook;
2169   GtkNotebookPage *page;
2170   GList *children;
2171   gboolean showarrow;
2172   gint width, height;
2173   gint x, y;
2174   gint gap_x = 0, gap_width = 0;
2175    
2176   g_return_if_fail (widget != NULL);
2177   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
2178   g_return_if_fail (area != NULL);
2179
2180   if (!GTK_WIDGET_DRAWABLE (widget))
2181     return;
2182
2183   notebook = GTK_NOTEBOOK (widget);
2184
2185   if ((!notebook->show_tabs && !notebook->show_border) ||
2186       !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
2187     {
2188       gdk_window_clear_area (widget->window,
2189                              area->x, area->y,
2190                              area->width, area->height);
2191       return;
2192     }
2193
2194   x = GTK_CONTAINER (widget)->border_width;
2195   y = GTK_CONTAINER (widget)->border_width;
2196   width = widget->allocation.width - x * 2;
2197   height = widget->allocation.height - y * 2;
2198
2199   if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
2200     {
2201       gtk_paint_box (widget->style, widget->window,
2202                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2203                      area, widget, "notebook",
2204                      x, y, width, height);
2205       return;
2206     }
2207
2208
2209   if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
2210     {
2211       page = notebook->first_tab->data;
2212
2213       switch (notebook->tab_pos)
2214         {
2215         case GTK_POS_TOP:
2216           y += page->allocation.height + widget->style->ythickness;
2217         case GTK_POS_BOTTOM:
2218           height -= page->allocation.height + widget->style->ythickness;
2219           break;
2220         case GTK_POS_LEFT:
2221           x += page->allocation.width + widget->style->xthickness;
2222         case GTK_POS_RIGHT:
2223           width -= page->allocation.width + widget->style->xthickness;
2224           break;
2225         }
2226       gtk_paint_box (widget->style, widget->window,
2227                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2228                      area, widget, "notebook",
2229                      x, y, width, height);
2230     }
2231   else
2232     {
2233       switch (notebook->tab_pos)
2234         {
2235         case GTK_POS_TOP:
2236           y += notebook->cur_page->allocation.height;
2237         case GTK_POS_BOTTOM:
2238           height -= notebook->cur_page->allocation.height;
2239           break;
2240         case GTK_POS_LEFT:
2241           x += notebook->cur_page->allocation.width;
2242         case GTK_POS_RIGHT:
2243           width -= notebook->cur_page->allocation.width;
2244           break;
2245         }
2246
2247       switch (notebook->tab_pos)
2248         {
2249         case GTK_POS_TOP:
2250           gap_x = (notebook->cur_page->allocation.x -
2251                    GTK_CONTAINER(notebook)->border_width);
2252           gap_width = notebook->cur_page->allocation.width;
2253           break;
2254         case GTK_POS_BOTTOM:
2255           gap_x = (notebook->cur_page->allocation.x -
2256                    GTK_CONTAINER(notebook)->border_width);
2257           gap_width = notebook->cur_page->allocation.width;
2258           break;
2259         case GTK_POS_LEFT:
2260           gap_x = (notebook->cur_page->allocation.y -
2261                    GTK_CONTAINER(notebook)->border_width);
2262           gap_width = notebook->cur_page->allocation.height;
2263           break;
2264         case GTK_POS_RIGHT:
2265           gap_x = (notebook->cur_page->allocation.y -
2266                    GTK_CONTAINER(notebook)->border_width);
2267           gap_width = notebook->cur_page->allocation.height;
2268           break;
2269         }
2270       gtk_paint_box_gap(widget->style, widget->window,
2271                         GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2272                         area, widget, "notebook",
2273                         x, y, width, height,
2274                         notebook->tab_pos, gap_x, gap_width);
2275     }
2276
2277   showarrow = FALSE;
2278   children = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
2279   while (children)
2280     {
2281       page = children->data;
2282       children = gtk_notebook_search_page (notebook, children,
2283                                            STEP_PREV, TRUE);
2284       if (!GTK_WIDGET_VISIBLE (page->child))
2285         continue;
2286       if (!GTK_WIDGET_MAPPED (page->tab_label))
2287         showarrow = TRUE;
2288       else if (page != notebook->cur_page)
2289         gtk_notebook_draw_tab (notebook, page, area);
2290     }
2291
2292   if (showarrow && notebook->scrollable) 
2293     {
2294       gtk_notebook_draw_arrow (notebook, GTK_ARROW_LEFT);
2295       gtk_notebook_draw_arrow (notebook, GTK_ARROW_RIGHT);
2296     }
2297   gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
2298 }
2299
2300 static void
2301 gtk_notebook_draw_tab (GtkNotebook     *notebook,
2302                        GtkNotebookPage *page,
2303                        GdkRectangle    *area)
2304 {
2305   GdkRectangle child_area;
2306   GdkRectangle page_area;
2307   GtkStateType state_type;
2308   GtkPositionType gap_side;
2309   
2310   g_return_if_fail (notebook != NULL);
2311   g_return_if_fail (page != NULL);
2312   g_return_if_fail (area != NULL);
2313
2314   if (!GTK_WIDGET_MAPPED (page->tab_label) ||
2315       (page->allocation.width == 0) || (page->allocation.height == 0))
2316     return;
2317
2318   page_area.x = page->allocation.x;
2319   page_area.y = page->allocation.y;
2320   page_area.width = page->allocation.width;
2321   page_area.height = page->allocation.height;
2322
2323   if (gdk_rectangle_intersect (&page_area, area, &child_area))
2324     {
2325       GtkWidget *widget;
2326
2327       widget = GTK_WIDGET (notebook);
2328       gap_side = 0;
2329       switch (notebook->tab_pos)
2330         {
2331         case GTK_POS_TOP:
2332           gap_side = GTK_POS_BOTTOM;
2333           break;
2334         case GTK_POS_BOTTOM:
2335           gap_side = GTK_POS_TOP;
2336           break;
2337         case GTK_POS_LEFT:
2338           gap_side = GTK_POS_RIGHT;
2339           break;
2340         case GTK_POS_RIGHT:
2341           gap_side = GTK_POS_LEFT;
2342           break;
2343         }
2344       
2345       if (notebook->cur_page == page)
2346         state_type = GTK_STATE_NORMAL;
2347       else 
2348         state_type = GTK_STATE_ACTIVE;
2349       gtk_paint_extension(widget->style, widget->window,
2350                           state_type, GTK_SHADOW_OUT,
2351                           area, widget, "tab",
2352                           page_area.x, page_area.y,
2353                           page_area.width, page_area.height,
2354                           gap_side);
2355       if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
2356           notebook->focus_tab && (notebook->focus_tab->data == page))
2357         {
2358           gtk_paint_focus (widget->style, widget->window,
2359                            area, widget, "tab",
2360                            page->tab_label->allocation.x - 1,
2361                            page->tab_label->allocation.y - 1,
2362                            page->tab_label->allocation.width + 1,
2363                            page->tab_label->allocation.height + 1);
2364         }
2365       if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
2366           GTK_WIDGET_DRAWABLE (page->tab_label))
2367         {
2368           GdkEventExpose expose_event;
2369
2370           /* This is a lame hack since all this code needs rewriting anyhow */
2371           
2372           expose_event.window = page->tab_label->window;
2373           expose_event.area = child_area;
2374           expose_event.send_event = TRUE;
2375           expose_event.type = GDK_EXPOSE;
2376           expose_event.count = 0;
2377           
2378           gtk_widget_event (page->tab_label,
2379                             (GdkEvent*)&expose_event);
2380         }
2381     }
2382 }
2383
2384 static void
2385 gtk_notebook_draw_arrow (GtkNotebook *notebook,
2386                          guint        arrow)
2387 {
2388   GtkStateType state_type;
2389   GtkShadowType shadow_type;
2390   GtkWidget *widget;
2391
2392   g_return_if_fail (notebook != NULL);
2393   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
2394
2395   widget = GTK_WIDGET(notebook);
2396
2397   if (GTK_WIDGET_DRAWABLE (notebook))
2398     {
2399       if (notebook->in_child == arrow)
2400         {
2401           if (notebook->click_child == arrow)
2402             state_type = GTK_STATE_ACTIVE;
2403           else
2404             state_type = GTK_STATE_PRELIGHT;
2405         }
2406       else
2407         state_type = GTK_STATE_NORMAL;
2408
2409       if (notebook->click_child == arrow)
2410         shadow_type = GTK_SHADOW_IN;
2411       else
2412         shadow_type = GTK_SHADOW_OUT;
2413
2414       if (arrow == GTK_ARROW_LEFT)
2415         {
2416           if (notebook->focus_tab &&
2417               !gtk_notebook_search_page (notebook, notebook->focus_tab,
2418                                          STEP_PREV, TRUE))
2419             {
2420               shadow_type = GTK_SHADOW_ETCHED_IN;
2421               state_type = GTK_STATE_NORMAL;
2422             }
2423
2424           if (notebook->tab_pos == GTK_POS_LEFT ||
2425               notebook->tab_pos == GTK_POS_RIGHT)
2426             arrow = GTK_ARROW_UP;
2427
2428           gdk_window_clear_area (notebook->panel, 0, 0, ARROW_SIZE, ARROW_SIZE);
2429           gtk_paint_arrow (widget->style, notebook->panel, state_type, 
2430                            shadow_type, NULL, GTK_WIDGET(notebook), "notebook",
2431                            arrow, TRUE, 
2432                            0, 0, ARROW_SIZE, ARROW_SIZE);
2433         }
2434       else
2435         {
2436           if (notebook->focus_tab &&
2437               !gtk_notebook_search_page (notebook, notebook->focus_tab,
2438                                          STEP_NEXT, TRUE))
2439             {
2440               shadow_type = GTK_SHADOW_ETCHED_IN;
2441               state_type = GTK_STATE_NORMAL;
2442             }
2443
2444           if (notebook->tab_pos == GTK_POS_LEFT ||
2445               notebook->tab_pos == GTK_POS_RIGHT)
2446             arrow = GTK_ARROW_DOWN;
2447
2448            gdk_window_clear_area(notebook->panel, ARROW_SIZE + ARROW_SPACING, 
2449                                  0, ARROW_SIZE, ARROW_SIZE);
2450            gtk_paint_arrow (widget->style, notebook->panel, state_type, 
2451                             shadow_type, NULL, GTK_WIDGET(notebook), "notebook",
2452                             arrow, TRUE, ARROW_SIZE + ARROW_SPACING,
2453                             0, ARROW_SIZE, ARROW_SIZE);
2454         }
2455     }
2456 }
2457
2458 static void
2459 gtk_notebook_set_shape (GtkNotebook *notebook)
2460 {
2461   GtkWidget       *widget = NULL;
2462   GdkPixmap       *pm = NULL;
2463   GdkGC           *pmgc = NULL;
2464   GdkColor         col;
2465   gint             x, y, width, height, w, h, depth;
2466   GtkNotebookPage *page;
2467   GList           *children;
2468
2469   if (!GTK_WIDGET(notebook)->window)
2470     return;
2471
2472   widget = GTK_WIDGET(notebook);
2473
2474   w = widget->allocation.width;
2475   h = widget->allocation.height;
2476
2477   pm = gdk_pixmap_new (widget->window, w, h, 1);
2478   pmgc = gdk_gc_new (pm);
2479
2480   /* clear the shape mask */
2481   col.pixel = 0;
2482   gdk_gc_set_foreground(pmgc, &col);
2483   gdk_draw_rectangle(pm, pmgc, TRUE, 0, 0, w, h);
2484
2485   col.pixel = 1;
2486   gdk_gc_set_foreground(pmgc, &col);
2487
2488   /* draw the shape for the notebook page itself */
2489   x = GTK_CONTAINER(notebook)->border_width;
2490   y = GTK_CONTAINER(notebook)->border_width;
2491   width = widget->allocation.width - x * 2;
2492   height = widget->allocation.height - y * 2;
2493
2494   if (notebook->show_tabs && notebook->children)
2495     {
2496       if (!(notebook->show_tabs))
2497         {
2498           page = notebook->first_tab->data;
2499           switch (notebook->tab_pos)
2500             {
2501             case GTK_POS_TOP:
2502               y += page->allocation.height +
2503                 widget->style->ythickness;
2504             case GTK_POS_BOTTOM:
2505               height -= page->allocation.height +
2506                 widget->style->ythickness;
2507               break;
2508             case GTK_POS_LEFT:
2509               x += page->allocation.width +
2510                 widget->style->xthickness;
2511             case GTK_POS_RIGHT:
2512               width -= page->allocation.width +
2513                 widget->style->xthickness;
2514               break;
2515             }
2516         }
2517       else
2518         {
2519           if (notebook->cur_page)
2520             page = notebook->cur_page;
2521           else
2522             page = notebook->children->data;
2523
2524           if (!GTK_WIDGET_MAPPED (page->tab_label))
2525             {
2526               if (notebook->tab_pos == GTK_POS_LEFT)
2527                 {
2528                   x -= widget->style->xthickness * 2;
2529                   width += widget->style->xthickness * 2;
2530                 }
2531               else if (notebook->tab_pos == GTK_POS_RIGHT)
2532                 width += widget->style->xthickness * 2;
2533             }
2534           switch (notebook->tab_pos)
2535             {
2536             case GTK_POS_TOP:
2537               y += page->allocation.height;
2538             case GTK_POS_BOTTOM:
2539               height -= page->allocation.height;
2540               break;
2541             case GTK_POS_LEFT:
2542               x += page->allocation.width;
2543             case GTK_POS_RIGHT:
2544               width -= page->allocation.width;
2545               break;
2546             }
2547         }
2548     }
2549   gdk_draw_rectangle(pm, pmgc, TRUE, x, y, width, height);
2550
2551   /* if theres an area for scrollign arrows draw the shape for them */
2552   if (notebook->panel)
2553     {
2554       gdk_window_get_geometry(notebook->panel, &x, &y, &width, &height, &depth);
2555       gdk_draw_rectangle(pm, pmgc, TRUE, x, y, width, height);
2556     }
2557
2558   /* draw the shapes of all the children */
2559   if (notebook->show_tabs)
2560     {
2561       children = notebook->children;
2562       while (children)
2563         {
2564           page = children->data;
2565           if (GTK_WIDGET_MAPPED (page->tab_label))
2566             {
2567               x = page->allocation.x;
2568               y = page->allocation.y;
2569               width = page->allocation.width;
2570               height = page->allocation.height;
2571               gdk_draw_rectangle(pm, pmgc, TRUE, x, y, width, height);
2572             }
2573           children = children->next;
2574         }
2575     }
2576
2577   /* set the mask */
2578   gdk_window_shape_combine_mask(widget->window, pm, 0, 0);
2579   gdk_pixmap_unref(pm);
2580   gdk_gc_destroy(pmgc);
2581 }
2582
2583 /* Private GtkNotebook Size Allocate Functions:
2584  *
2585  * gtk_notebook_pages_allocate
2586  * gtk_notebook_page_allocate
2587  * gtk_notebook_calc_tabs
2588  */
2589 static void
2590 gtk_notebook_pages_allocate (GtkNotebook   *notebook)
2591 {
2592   GtkWidget    *widget = GTK_WIDGET (notebook);
2593   GtkContainer *container = GTK_CONTAINER (notebook);
2594   GtkNotebookPage *page = NULL;
2595   GtkAllocation *allocation = &widget->allocation;
2596   GtkAllocation child_allocation;
2597   GList *children = NULL;
2598   GList *last_child = NULL;
2599   gboolean showarrow = FALSE;
2600   gint tab_space = 0; 
2601   gint delta; 
2602   gint x = 0;
2603   gint y = 0;
2604   gint i;
2605   gint n = 1;
2606   gint old_fill = 0;
2607   gint new_fill = 0;
2608
2609   if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
2610     return;
2611
2612   child_allocation.x = container->border_width;
2613   child_allocation.y = container->border_width;
2614
2615   switch (notebook->tab_pos)
2616     {
2617     case GTK_POS_BOTTOM:
2618       child_allocation.y = (allocation->height -
2619                             notebook->cur_page->requisition.height -
2620                             container->border_width);
2621       /* fall through */
2622     case GTK_POS_TOP:
2623       child_allocation.height = notebook->cur_page->requisition.height;
2624       break;
2625       
2626     case GTK_POS_RIGHT:
2627       child_allocation.x = (allocation->width -
2628                             notebook->cur_page->requisition.width -
2629                             container->border_width);
2630       /* fall through */
2631     case GTK_POS_LEFT:
2632       child_allocation.width = notebook->cur_page->requisition.width;
2633       break;
2634     }
2635   
2636   if (notebook->scrollable) 
2637     {
2638       GList *focus_tab;
2639       
2640       children = notebook->children;
2641       
2642       if (notebook->focus_tab)
2643         focus_tab = notebook->focus_tab;
2644       else if (notebook->first_tab)
2645         focus_tab = notebook->first_tab;
2646       else
2647         focus_tab = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2648
2649       switch (notebook->tab_pos)
2650         {
2651         case GTK_POS_TOP:
2652         case GTK_POS_BOTTOM:
2653           while (children)
2654             {
2655               page = children->data;
2656               children = children->next;
2657
2658               if (GTK_WIDGET_VISIBLE (page->child))
2659                 tab_space += page->requisition.width;
2660             }
2661           if (tab_space >
2662               allocation->width - 2 * container->border_width - TAB_OVERLAP) 
2663             {
2664               showarrow = TRUE;
2665               page = focus_tab->data; 
2666
2667               tab_space = (allocation->width - TAB_OVERLAP -
2668                            page->requisition.width -
2669                            2 * (container->border_width + ARROW_SPACING +
2670                                 ARROW_SIZE));
2671               x = (allocation->width - 2 * ARROW_SIZE - ARROW_SPACING -
2672                    container->border_width);
2673
2674               page = notebook->children->data;
2675               if (notebook->tab_pos == GTK_POS_TOP)
2676                 y = (container->border_width +
2677                      (page->requisition.height - ARROW_SIZE) / 2);
2678               else
2679                 y = (allocation->height - container->border_width - 
2680                      ARROW_SIZE - (page->requisition.height - ARROW_SIZE) / 2);
2681             }
2682           break;
2683         case GTK_POS_LEFT:
2684         case GTK_POS_RIGHT:
2685           while (children)
2686             {
2687               page = children->data;
2688               children = children->next;
2689
2690               if (GTK_WIDGET_VISIBLE (page->child))
2691                 tab_space += page->requisition.height;
2692             }
2693           if (tab_space >
2694               (allocation->height - 2 * container->border_width - TAB_OVERLAP))
2695             {
2696               showarrow = TRUE;
2697               page = focus_tab->data; 
2698               tab_space = (allocation->height -
2699                            ARROW_SIZE - ARROW_SPACING - TAB_OVERLAP -
2700                            2 * container->border_width -
2701                            page->requisition.height);
2702               y = allocation->height - container->border_width - ARROW_SIZE;  
2703
2704               page = notebook->children->data;
2705               if (notebook->tab_pos == GTK_POS_LEFT)
2706                 x = (container->border_width +
2707                      (page->requisition.width -
2708                       (2 * ARROW_SIZE - ARROW_SPACING)) / 2); 
2709               else
2710                 x = (allocation->width - container->border_width -
2711                      (2 * ARROW_SIZE - ARROW_SPACING) -
2712                      (page->requisition.width -
2713                       (2 * ARROW_SIZE - ARROW_SPACING)) / 2);
2714             }
2715           break;
2716         }
2717       if (showarrow) /* first_tab <- focus_tab */
2718         { 
2719           if (tab_space <= 0)
2720             {
2721               notebook->first_tab = focus_tab;
2722               last_child = gtk_notebook_search_page (notebook, focus_tab,
2723                                                      STEP_NEXT, TRUE);
2724             }
2725           else
2726             {
2727               children = NULL;
2728               if (notebook->first_tab && notebook->first_tab != focus_tab)
2729                 {
2730                   /* Is first_tab really predecessor of focus_tab  ? */
2731                   page = notebook->first_tab->data;
2732                   if (GTK_WIDGET_VISIBLE (page->child))
2733                     for (children = focus_tab;
2734                          children && children != notebook->first_tab;
2735                          children = gtk_notebook_search_page (notebook,
2736                                                               children,
2737                                                               STEP_PREV,
2738                                                               TRUE));
2739                 }
2740               if (!children)
2741                 notebook->first_tab = focus_tab;
2742               else
2743                 gtk_notebook_calc_tabs (notebook,
2744                                         gtk_notebook_search_page (notebook,
2745                                                                   focus_tab,
2746                                                                   STEP_PREV,
2747                                                                   TRUE), 
2748                                         &(notebook->first_tab), &tab_space,
2749                                         STEP_PREV);
2750
2751               if (tab_space <= 0)
2752                 {
2753                   notebook->first_tab =
2754                     gtk_notebook_search_page (notebook, notebook->first_tab,
2755                                               STEP_NEXT, TRUE);
2756                   if (!notebook->first_tab)
2757                     notebook->first_tab = focus_tab;
2758                   last_child = gtk_notebook_search_page (notebook, focus_tab,
2759                                                          STEP_NEXT, TRUE); 
2760                 }
2761               else /* focus_tab -> end */   
2762                 {
2763                   if (!notebook->first_tab)
2764                     notebook->first_tab = gtk_notebook_search_page (notebook,
2765                                                                     NULL,
2766                                                                     STEP_NEXT,
2767                                                                     TRUE);
2768                   children = NULL;
2769                   gtk_notebook_calc_tabs (notebook,
2770                                           gtk_notebook_search_page (notebook,
2771                                                                     focus_tab,
2772                                                                     STEP_NEXT,
2773                                                                     TRUE),
2774                                           &children, &tab_space, STEP_NEXT);
2775
2776                   if (tab_space <= 0) 
2777                     last_child = children;
2778                   else /* start <- first_tab */
2779                     {
2780                       last_child = NULL;
2781                       children = NULL;
2782                       gtk_notebook_calc_tabs
2783                         (notebook,
2784                          gtk_notebook_search_page (notebook,
2785                                                    notebook->first_tab,
2786                                                    STEP_PREV,
2787                                                    TRUE),
2788                          &children, &tab_space, STEP_PREV);
2789                       notebook->first_tab = gtk_notebook_search_page(notebook,
2790                                                                      children,
2791                                                                      STEP_NEXT,
2792                                                                      TRUE);
2793                     }
2794                 }
2795             }
2796
2797           if (GTK_WIDGET_REALIZED (notebook))
2798             {
2799               gdk_window_move (notebook->panel, x, y);
2800               gdk_window_show (notebook->panel);
2801             }
2802
2803           if (tab_space < 0) 
2804             {
2805               tab_space = -tab_space;
2806               n = 0;
2807               for (children = notebook->first_tab;
2808                    children && children != last_child;
2809                    children = gtk_notebook_search_page (notebook, children,
2810                                                         STEP_NEXT, TRUE))
2811                 n++;
2812             }
2813           else 
2814             tab_space = 0;
2815
2816           /*unmap all non-visible tabs*/
2817           for (children = gtk_notebook_search_page (notebook, NULL,
2818                                                     STEP_NEXT, TRUE);
2819                children && children != notebook->first_tab;
2820                children = gtk_notebook_search_page (notebook, children,
2821                                                     STEP_NEXT, TRUE))
2822             {
2823               page = children->data;
2824               if (page->tab_label && GTK_WIDGET_MAPPED (page->tab_label))
2825                 gtk_widget_unmap (page->tab_label);
2826             }
2827           for (children = last_child; children;
2828                children = gtk_notebook_search_page (notebook, children,
2829                                                     STEP_NEXT, TRUE))
2830             {
2831               page = children->data;
2832               if (page->tab_label && GTK_WIDGET_MAPPED (page->tab_label))
2833                 gtk_widget_unmap (page->tab_label);
2834             }
2835         }
2836       else /* !showarrow */
2837         {
2838           notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
2839                                                           STEP_NEXT, TRUE);
2840           tab_space = 0;
2841           if (GTK_WIDGET_REALIZED (notebook))
2842             gdk_window_hide (notebook->panel);
2843         }
2844     }
2845
2846   if (!showarrow)
2847     {
2848       gint c = 0;
2849
2850       n = 0;
2851       children = notebook->children;
2852       switch (notebook->tab_pos)
2853         {
2854         case GTK_POS_TOP:
2855         case GTK_POS_BOTTOM:
2856           while (children)
2857             {
2858               page = children->data;
2859               children = children->next;
2860
2861               if (GTK_WIDGET_VISIBLE (page->child))
2862                 {
2863                   c++;
2864                   tab_space += page->requisition.width;
2865                   if (page->expand)
2866                     n++;
2867                 }
2868             }
2869           tab_space -= allocation->width;
2870           break;
2871         case GTK_POS_LEFT:
2872         case GTK_POS_RIGHT:
2873           while (children)
2874             {
2875               page = children->data;
2876               children = children->next;
2877
2878               if (GTK_WIDGET_VISIBLE (page->child))
2879                 {
2880                   c++;
2881                   tab_space += page->requisition.height;
2882                   if (page->expand)
2883                     n++;
2884                 }
2885             }
2886           tab_space -= allocation->height;
2887         }
2888       tab_space += 2 * container->border_width + TAB_OVERLAP;
2889       tab_space *= -1;
2890       notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
2891                                                       STEP_NEXT, TRUE);
2892       if (notebook->homogeneous && n)
2893         n = c;
2894     }
2895   
2896   children = notebook->first_tab;
2897   i = 1;
2898   while (children)
2899     {
2900       if (children == last_child)
2901         {
2902           /* FIXME double check */
2903           goto done;
2904         }
2905
2906       page = children->data;
2907       if (!showarrow && page->pack != GTK_PACK_START)
2908         break;
2909       children = gtk_notebook_search_page (notebook, children, STEP_NEXT,TRUE);
2910       
2911       delta = 0;
2912       if (n && (showarrow || page->expand || notebook->homogeneous))
2913         {
2914           new_fill = (tab_space * i++) / n;
2915           delta = new_fill - old_fill;
2916           old_fill = new_fill;
2917         }
2918       
2919       switch (notebook->tab_pos)
2920         {
2921         case GTK_POS_TOP:
2922         case GTK_POS_BOTTOM:
2923           child_allocation.width = (page->requisition.width +
2924                                     TAB_OVERLAP + delta);
2925           break;
2926         case GTK_POS_LEFT:
2927         case GTK_POS_RIGHT:
2928           child_allocation.height = (page->requisition.height +
2929                                      TAB_OVERLAP + delta);
2930           break;
2931         }
2932
2933       gtk_notebook_page_allocate (notebook, page, &child_allocation);
2934           
2935       switch (notebook->tab_pos)
2936         {
2937         case GTK_POS_TOP:
2938         case GTK_POS_BOTTOM:
2939           child_allocation.x += child_allocation.width - TAB_OVERLAP;
2940           break;
2941         case GTK_POS_LEFT:
2942         case GTK_POS_RIGHT:
2943           child_allocation.y += child_allocation.height - TAB_OVERLAP;
2944           break;
2945         }
2946
2947       if (GTK_WIDGET_REALIZED (notebook) &&
2948           page->tab_label && !GTK_WIDGET_MAPPED (page->tab_label))
2949         {
2950           if (GTK_WIDGET_VISIBLE (page->tab_label))
2951             gtk_widget_map (page->tab_label);
2952           else
2953             gtk_widget_show (page->tab_label);
2954         }
2955     }
2956
2957   if (children)
2958     {
2959       children = notebook->children;
2960       switch (notebook->tab_pos)
2961         {
2962         case GTK_POS_TOP:
2963         case GTK_POS_BOTTOM:
2964           child_allocation.x = (allocation->x + allocation->width -
2965                                 container->border_width);
2966           break;
2967         case GTK_POS_LEFT:
2968         case GTK_POS_RIGHT:
2969           child_allocation.y = (allocation->y + allocation->height -
2970                                 container->border_width);
2971           break;
2972         }
2973
2974       while (children != last_child)
2975         {
2976           page = children->data;
2977           children = children->next;
2978
2979           if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
2980             continue;
2981
2982           delta = 0;
2983           if (n && (page->expand || notebook->homogeneous))
2984             {
2985               new_fill = (tab_space * i++) / n;
2986               delta = new_fill - old_fill;
2987               old_fill = new_fill;
2988             }
2989
2990           switch (notebook->tab_pos)
2991             {
2992             case GTK_POS_TOP:
2993             case GTK_POS_BOTTOM:
2994               child_allocation.width = (page->requisition.width +
2995                                         TAB_OVERLAP + delta);
2996               child_allocation.x -= child_allocation.width;
2997               break;
2998             case GTK_POS_LEFT:
2999             case GTK_POS_RIGHT:
3000               child_allocation.height = (page->requisition.height +
3001                                          TAB_OVERLAP + delta);
3002               child_allocation.y -= child_allocation.height;
3003               break;
3004             }
3005
3006           gtk_notebook_page_allocate (notebook, page, &child_allocation);
3007
3008           switch (notebook->tab_pos)
3009             {
3010             case GTK_POS_TOP:
3011             case GTK_POS_BOTTOM:
3012               child_allocation.x += TAB_OVERLAP;
3013               break;
3014             case GTK_POS_LEFT:
3015             case GTK_POS_RIGHT:
3016               child_allocation.y += TAB_OVERLAP;
3017               break;
3018             }
3019
3020           if (GTK_WIDGET_REALIZED (notebook) && page->tab_label &&
3021               !GTK_WIDGET_MAPPED (page->tab_label))
3022             {
3023               if (GTK_WIDGET_VISIBLE (page->tab_label))
3024                 gtk_widget_map (page->tab_label);
3025               else
3026                 gtk_widget_show (page->tab_label);
3027             }
3028         }
3029     }
3030
3031  done:
3032   gtk_notebook_set_shape (notebook);
3033   gtk_notebook_redraw_tabs (notebook);  
3034 }
3035
3036 static void
3037 gtk_notebook_page_allocate (GtkNotebook     *notebook,
3038                             GtkNotebookPage *page,
3039                             GtkAllocation   *allocation)
3040 {
3041   GtkWidget *widget;
3042   GtkAllocation child_allocation;
3043   GtkRequisition tab_requisition;
3044   gint xthickness;
3045   gint ythickness;
3046   gint padding;
3047
3048   g_return_if_fail (notebook != NULL);
3049   g_return_if_fail (page != NULL);
3050   g_return_if_fail (allocation != NULL);
3051
3052   widget = GTK_WIDGET (notebook);
3053
3054   xthickness = widget->style->xthickness;
3055   ythickness = widget->style->ythickness;
3056
3057   /* If the size of the notebook tabs change, we need to queue
3058    * a redraw on the tab area
3059    */
3060   if ((allocation->width != page->allocation.width) ||
3061       (allocation->height != page->allocation.height))
3062     {
3063       gint x, y, width, height, border_width;
3064
3065       border_width = GTK_CONTAINER (notebook)->border_width;
3066
3067       switch (notebook->tab_pos)
3068        {
3069        case GTK_POS_TOP:
3070          width = widget->allocation.width;
3071          height = MAX (page->allocation.height, allocation->height) + ythickness;
3072          x = 0;                              
3073          y = border_width;
3074          break;
3075
3076        case GTK_POS_BOTTOM:
3077          width = widget->allocation.width + xthickness;
3078          height = MAX (page->allocation.height, allocation->height) + ythickness;
3079          x = 0;                              
3080          y = widget->allocation.height - height - border_width;
3081          break;
3082
3083        case GTK_POS_LEFT:
3084          width = MAX (page->allocation.width, allocation->width) + xthickness;
3085          height = widget->allocation.height;
3086          x = border_width;
3087          y = 0;
3088          break;
3089
3090        case GTK_POS_RIGHT:
3091        default:                /* quiet gcc */
3092          width = MAX (page->allocation.width, allocation->width) + xthickness;
3093          height = widget->allocation.height;
3094          x = widget->allocation.width - width - border_width;
3095          y = 0;
3096          break;
3097        }
3098
3099       gtk_widget_queue_clear_area (widget, x, y, width, height);
3100     }
3101
3102   page->allocation = *allocation;
3103   gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
3104
3105   if (notebook->cur_page != page)
3106     {
3107       switch (notebook->tab_pos)
3108         {
3109         case GTK_POS_TOP:
3110           page->allocation.y += ythickness;
3111         case GTK_POS_BOTTOM:
3112           if (page->allocation.height > ythickness)
3113             page->allocation.height -= ythickness;
3114           break;
3115         case GTK_POS_LEFT:
3116           page->allocation.x += xthickness;
3117         case GTK_POS_RIGHT:
3118           if (page->allocation.width > xthickness)
3119             page->allocation.width -= xthickness;
3120           break;
3121         }
3122     }
3123
3124   switch (notebook->tab_pos)
3125     {
3126     case GTK_POS_TOP:
3127     case GTK_POS_BOTTOM:
3128       padding = TAB_CURVATURE + FOCUS_WIDTH + notebook->tab_hborder;
3129       if (page->fill)
3130         {
3131           child_allocation.x = (xthickness + FOCUS_WIDTH +
3132                                 notebook->tab_hborder);
3133           child_allocation.width = MAX (1, (((gint) page->allocation.width) -
3134                                             2 * child_allocation.x));
3135           child_allocation.x += page->allocation.x;
3136         }
3137       else
3138         {
3139           child_allocation.x = (page->allocation.x +
3140                                 (page->allocation.width -
3141                                  tab_requisition.width) / 2);
3142           child_allocation.width = tab_requisition.width;
3143         }
3144       child_allocation.y = (notebook->tab_vborder + FOCUS_WIDTH +
3145                             page->allocation.y);
3146       if (notebook->tab_pos == GTK_POS_TOP)
3147         child_allocation.y += ythickness;
3148       child_allocation.height = MAX (1, (((gint) page->allocation.height) - ythickness -
3149                                          2 * (notebook->tab_vborder + FOCUS_WIDTH)));
3150       break;
3151     case GTK_POS_LEFT:
3152     case GTK_POS_RIGHT:
3153       padding = TAB_CURVATURE + FOCUS_WIDTH + notebook->tab_vborder;
3154       if (page->fill)
3155         {
3156           child_allocation.y = ythickness + padding;
3157           child_allocation.height = MAX (1, (((gint) page->allocation.height) -
3158                                              2 * child_allocation.y));
3159           child_allocation.y += page->allocation.y;
3160         }
3161       else
3162         {
3163           child_allocation.y = (page->allocation.y + (page->allocation.height -
3164                                                       tab_requisition.height) / 2);
3165           child_allocation.height = tab_requisition.height;
3166         }
3167       child_allocation.x = page->allocation.x + notebook->tab_hborder + FOCUS_WIDTH;
3168       if (notebook->tab_pos == GTK_POS_LEFT)
3169         child_allocation.x += xthickness;
3170       child_allocation.width = MAX (1, (((gint) page->allocation.width) - xthickness -
3171                                         2 * (notebook->tab_hborder + FOCUS_WIDTH)));
3172       break;
3173     }
3174
3175   if (page->tab_label)
3176     gtk_widget_size_allocate (page->tab_label, &child_allocation);
3177 }
3178
3179 static void 
3180 gtk_notebook_calc_tabs (GtkNotebook  *notebook, 
3181                         GList        *start, 
3182                         GList       **end,
3183                         gint         *tab_space,
3184                         guint         direction)
3185 {
3186   GtkNotebookPage *page = NULL;
3187   GList *children;
3188   GList *last_list = NULL;
3189   gboolean pack;
3190
3191   if (!start)
3192     return;
3193
3194   children = start;
3195   pack = GTK_NOTEBOOK_PAGE (start)->pack;
3196   if (pack == GTK_PACK_END)
3197     direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
3198
3199   while (1)
3200     {
3201       switch (notebook->tab_pos)
3202         {
3203         case GTK_POS_TOP:
3204         case GTK_POS_BOTTOM:
3205           while (children)
3206             {
3207               page = children->data;
3208               if (GTK_WIDGET_VISIBLE (page->child))
3209                 {
3210                   if (page->pack == pack)
3211                     {
3212                       *tab_space -= page->requisition.width;
3213                       if (*tab_space < 0 || children == *end)
3214                         {
3215                           if (*tab_space < 0) 
3216                             {
3217                               *tab_space = - (*tab_space +
3218                                               page->requisition.width);
3219                               *end = children;
3220                             }
3221                           return;
3222                         }
3223                     }
3224                   last_list = children;
3225                 }
3226               if (direction == STEP_NEXT)
3227                 children = children->next;
3228               else
3229                 children = children->prev;
3230             }
3231           break;
3232         case GTK_POS_LEFT:
3233         case GTK_POS_RIGHT:
3234           while (children)
3235             {
3236               page = children->data;
3237               if (GTK_WIDGET_VISIBLE (page->child))
3238                 {
3239                   if (page->pack == pack)
3240                     {
3241                       *tab_space -= page->requisition.height;
3242                       if (*tab_space < 0 || children == *end)
3243                         {
3244                           if (*tab_space < 0)
3245                             {
3246                               *tab_space = - (*tab_space +
3247                                               page->requisition.height);
3248                               *end = children;
3249                             }
3250                           return;
3251                         }
3252                     }
3253                   last_list = children;
3254                 }
3255               if (direction == STEP_NEXT)
3256                 children = children->next;
3257               else
3258                 children = children->prev;
3259             }
3260           break;
3261         }
3262       if (direction == STEP_PREV)
3263         return;
3264       pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
3265       direction = STEP_PREV;
3266       children = last_list;
3267     }
3268 }
3269
3270 /* Private GtkNotebook Page Switch Methods:
3271  *
3272  * gtk_notebook_real_switch_page
3273  */
3274 static void
3275 gtk_notebook_real_switch_page (GtkNotebook     *notebook,
3276                                GtkNotebookPage *page,
3277                                guint            page_num)
3278 {
3279   g_return_if_fail (notebook != NULL);
3280   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3281   g_return_if_fail (page != NULL);
3282
3283   if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
3284     return;
3285
3286   if (notebook->cur_page && GTK_WIDGET_MAPPED (notebook->cur_page->child))
3287     gtk_widget_unmap (notebook->cur_page->child);
3288   
3289   notebook->cur_page = page;
3290
3291   if (!notebook->focus_tab ||
3292       notebook->focus_tab->data != (gpointer) notebook->cur_page)
3293     notebook->focus_tab = 
3294       g_list_find (notebook->children, notebook->cur_page);
3295
3296   if (GTK_WIDGET_MAPPED (notebook))
3297     gtk_widget_map (notebook->cur_page->child);
3298
3299   gtk_widget_queue_resize (GTK_WIDGET (notebook));
3300 }
3301
3302 /* Private GtkNotebook Page Switch Functions:
3303  *
3304  * gtk_notebook_switch_page
3305  * gtk_notebook_page_select
3306  * gtk_notebook_switch_focus_tab
3307  * gtk_notebook_menu_switch_page
3308  */
3309 static void
3310 gtk_notebook_switch_page (GtkNotebook     *notebook,
3311                           GtkNotebookPage *page,
3312                           gint             page_num)
3313
3314   g_return_if_fail (notebook != NULL);
3315   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3316   g_return_if_fail (page != NULL);
3317  
3318   if (notebook->cur_page == page)
3319     return;
3320
3321   if (page_num < 0)
3322     page_num = g_list_index (notebook->children, page);
3323
3324   gtk_signal_emit (GTK_OBJECT (notebook), 
3325                    notebook_signals[SWITCH_PAGE], 
3326                    page,
3327                    page_num);
3328 }
3329
3330 static gint
3331 gtk_notebook_page_select (GtkNotebook *notebook,
3332                           gboolean     move_focus)
3333 {
3334   GtkNotebookPage *page;
3335   GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
3336
3337   g_return_val_if_fail (notebook != NULL, FALSE);
3338   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
3339
3340   if (!notebook->focus_tab)
3341     return FALSE;
3342
3343   page = notebook->focus_tab->data;
3344   gtk_notebook_switch_page (notebook, page, -1);
3345
3346   if (move_focus)
3347     {
3348       switch (notebook->tab_pos)
3349         {
3350         case GTK_POS_TOP:
3351           dir = GTK_DIR_DOWN;
3352           break;
3353         case GTK_POS_BOTTOM:
3354           dir = GTK_DIR_UP;
3355           break;
3356         case GTK_POS_LEFT:
3357           dir = GTK_DIR_RIGHT;
3358           break;
3359         case GTK_POS_RIGHT:
3360           dir = GTK_DIR_LEFT;
3361           break;
3362         }
3363       
3364       if (GTK_WIDGET_VISIBLE (page->child))
3365         {
3366           if (GTK_IS_CONTAINER (page->child))
3367             {
3368               if (gtk_container_focus (GTK_CONTAINER (page->child), 
3369                                        dir))
3370                 return TRUE;
3371             }
3372           else if (GTK_WIDGET_CAN_FOCUS (page->child))
3373             {
3374               gtk_widget_grab_focus (page->child);
3375               return TRUE;
3376             }
3377         }
3378     }
3379   return FALSE;
3380 }
3381
3382 static void
3383 gtk_notebook_switch_focus_tab (GtkNotebook *notebook, 
3384                                GList       *new_child)
3385 {
3386   GList *old_child;
3387   GtkNotebookPage *old_page = NULL;
3388   GtkNotebookPage *page;
3389
3390   g_return_if_fail (notebook != NULL);
3391   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3392
3393   if (notebook->focus_tab == new_child)
3394     return;
3395
3396   old_child = notebook->focus_tab;
3397   notebook->focus_tab = new_child;
3398
3399   if (notebook->scrollable && GTK_WIDGET_DRAWABLE (notebook))
3400     gtk_notebook_redraw_arrows (notebook);
3401
3402   if (!notebook->show_tabs || !notebook->focus_tab)
3403     return;
3404
3405   if (old_child)
3406     old_page = old_child->data;
3407
3408   page = notebook->focus_tab->data;
3409   if (GTK_WIDGET_MAPPED (page->tab_label))
3410     gtk_notebook_focus_changed (notebook, old_page);
3411   else
3412     gtk_notebook_pages_allocate (notebook);
3413
3414   gtk_notebook_set_shape (notebook);
3415 }
3416
3417 static void
3418 gtk_notebook_menu_switch_page (GtkWidget       *widget,
3419                                GtkNotebookPage *page)
3420 {
3421   GtkNotebook *notebook;
3422   GList *children;
3423   guint page_num;
3424
3425   g_return_if_fail (widget != NULL);
3426   g_return_if_fail (page != NULL);
3427
3428   notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
3429                            (GTK_MENU (widget->parent)));
3430
3431   if (notebook->cur_page == page)
3432     return;
3433
3434   page_num = 0;
3435   children = notebook->children;
3436   while (children && children->data != page)
3437     {
3438       children = children->next;
3439       page_num++;
3440     }
3441
3442   gtk_signal_emit (GTK_OBJECT (notebook), 
3443                    notebook_signals[SWITCH_PAGE], 
3444                    page,
3445                    page_num);
3446 }
3447
3448 /* Private GtkNotebook Menu Functions:
3449  *
3450  * gtk_notebook_menu_item_create
3451  * gtk_notebook_menu_label_unparent
3452  * gtk_notebook_menu_detacher
3453  */
3454 static void
3455 gtk_notebook_menu_item_create (GtkNotebook *notebook, 
3456                                GList       *list)
3457 {       
3458   GtkNotebookPage *page;
3459   GtkWidget *menu_item;
3460
3461   page = list->data;
3462   if (page->default_menu)
3463     {
3464       if (page->tab_label && GTK_IS_LABEL (page->tab_label))
3465         page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
3466       else
3467         page->menu_label = gtk_label_new ("");
3468       gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
3469     }
3470
3471   gtk_widget_show (page->menu_label);
3472   menu_item = gtk_menu_item_new ();
3473   gtk_widget_lock_accelerators (menu_item);
3474   gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
3475   gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
3476                          gtk_notebook_real_page_position (notebook, list));
3477   gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
3478                       GTK_SIGNAL_FUNC (gtk_notebook_menu_switch_page), page);
3479   if (GTK_WIDGET_VISIBLE (page->child))
3480     gtk_widget_show (menu_item);
3481 }
3482
3483 static void
3484 gtk_notebook_menu_label_unparent (GtkWidget *widget, 
3485                                   gpointer  data)
3486 {
3487   gtk_widget_unparent (GTK_BIN(widget)->child);
3488   GTK_BIN(widget)->child = NULL;
3489 }
3490
3491 static void
3492 gtk_notebook_menu_detacher (GtkWidget *widget,
3493                             GtkMenu   *menu)
3494 {
3495   GtkNotebook *notebook;
3496
3497   g_return_if_fail (widget != NULL);
3498   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
3499
3500   notebook = GTK_NOTEBOOK (widget);
3501   g_return_if_fail (notebook->menu == (GtkWidget*) menu);
3502
3503   notebook->menu = NULL;
3504 }
3505
3506 /* Public GtkNotebook Page Insert/Remove Methods :
3507  *
3508  * gtk_notebook_append_page
3509  * gtk_notebook_append_page_menu
3510  * gtk_notebook_prepend_page
3511  * gtk_notebook_prepend_page_menu
3512  * gtk_notebook_insert_page
3513  * gtk_notebook_insert_page_menu
3514  * gtk_notebook_remove_page
3515  */
3516 /**
3517  * gtk_notebook_append_page:
3518  * @notebook: a #GtkNotebook
3519  * @child: the #GtkWidget to use as the contents of the page.
3520  * @tab_label: the #GtkWidget to be used as the label for the page,
3521  *             or %NULL to use the default label, 'page N'.
3522  * 
3523  * Appends a page to @notebook.
3524  **/
3525 void
3526 gtk_notebook_append_page (GtkNotebook *notebook,
3527                           GtkWidget   *child,
3528                           GtkWidget   *tab_label)
3529 {
3530   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3531   g_return_if_fail (GTK_IS_WIDGET (child));
3532   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3533   
3534   gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
3535 }
3536
3537 /**
3538  * gtk_notebook_append_page_menu:
3539  * @notebook: a #GtkNotebook
3540  * @child: the #GtkWidget to use as the contents of the page.
3541  * @tab_label: the #GtkWidget to be used as the label for the page,
3542  *             or %NULL to use the default label, 'page N'.
3543  * @menu_label: the widget to use as a label for the page-switch
3544  *              menu, if that is enabled. If %NULL, and @tab_label
3545  *              is a #GtkLabel or %NULL, then the menu label will be
3546  *              a newly created label with the same text as @tab_label;
3547  *              If @tab_label is not a #GtkLabel, @menu_label must be
3548  *              specified if the page-switch menu is to be used.
3549  * 
3550  * Appends a page to @notebook, specifying the widget to use as the
3551  * label in the popup menu.
3552  **/
3553 void
3554 gtk_notebook_append_page_menu (GtkNotebook *notebook,
3555                                GtkWidget   *child,
3556                                GtkWidget   *tab_label,
3557                                GtkWidget   *menu_label)
3558 {
3559   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3560   g_return_if_fail (GTK_IS_WIDGET (child));
3561   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3562   g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
3563   
3564   gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
3565 }
3566
3567 /**
3568  * gtk_notebook_prepend_page:
3569  * @notebook: a #GtkNotebook
3570  * @child: the #GtkWidget to use as the contents of the page.
3571  * @tab_label: the #GtkWidget to be used as the label for the page,
3572  *             or %NULL to use the default label, 'page N'.
3573  *
3574  * Prepends a page to @noteobook.
3575  **/
3576 void
3577 gtk_notebook_prepend_page (GtkNotebook *notebook,
3578                            GtkWidget   *child,
3579                            GtkWidget   *tab_label)
3580 {
3581   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3582   g_return_if_fail (GTK_IS_WIDGET (child));
3583   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3584   
3585   gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
3586 }
3587
3588 /**
3589  * gtk_notebook_prepend_page_menu:
3590  * @notebook: a #GtkNotebook
3591  * @child: the #GtkWidget to use as the contents of the page.
3592  * @tab_label: the #GtkWidget to be used as the label for the page,
3593  *             or %NULL to use the default label, 'page N'.
3594  * @menu_label: the widget to use as a label for the page-switch
3595  *              menu, if that is enabled. If %NULL, and @tab_label
3596  *              is a #GtkLabel or %NULL, then the menu label will be
3597  *              a newly created label with the same text as @tab_label;
3598  *              If @tab_label is not a #GtkLabel, @menu_label must be
3599  *              specified if the page-switch menu is to be used.
3600  * 
3601  * Prepends a page to @notebook, specifying the widget to use as the
3602  * label in the popup menu.
3603  **/
3604 void
3605 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
3606                                 GtkWidget   *child,
3607                                 GtkWidget   *tab_label,
3608                                 GtkWidget   *menu_label)
3609 {
3610   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3611   g_return_if_fail (GTK_IS_WIDGET (child));
3612   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3613   g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
3614   
3615   gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
3616 }
3617
3618 /**
3619  * gtk_notebook_insert_page:
3620  * @notebook: a #GtkNotebook
3621  * @child: the #GtkWidget to use as the contents of the page.
3622  * @tab_label: the #GtkWidget to be used as the label for the page,
3623  *             or %NULL to use the default label, 'page N'.
3624  * @position: the index (starting at 0) at which to insert the page,
3625  *            or -1 to append the page after all other pages.
3626  * 
3627  * Insert a page into @notebook at the given position
3628  **/
3629 void
3630 gtk_notebook_insert_page (GtkNotebook *notebook,
3631                           GtkWidget   *child,
3632                           GtkWidget   *tab_label,
3633                           gint         position)
3634 {
3635   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3636   g_return_if_fail (GTK_IS_WIDGET (child));
3637   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3638   
3639   gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
3640 }
3641
3642 /**
3643  * gtk_notebook_insert_page_menu:
3644  * @notebook: a #GtkNotebook
3645  * @child: the #GtkWidget to use as the contents of the page.
3646  * @tab_label: the #GtkWidget to be used as the label for the page,
3647  *             or %NULL to use the default label, 'page N'.
3648  * @menu_label: the widget to use as a label for the page-switch
3649  *              menu, if that is enabled. If %NULL, and @tab_label
3650  *              is a #GtkLabel or %NULL, then the menu label will be
3651  *              a newly created label with the same text as @tab_label;
3652  *              If @tab_label is not a #GtkLabel, @menu_label must be
3653  *              specified if the page-switch menu is to be used.
3654  * @position: the index (starting at 0) at which to insert the page,
3655  *            or -1 to append the page after all other pages.
3656  * 
3657  * Insert a page into @notebook at the given position, specifying
3658  * the widget to use as the label in the popup menu.
3659  **/
3660 void
3661 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
3662                                GtkWidget   *child,
3663                                GtkWidget   *tab_label,
3664                                GtkWidget   *menu_label,
3665                                gint         position)
3666 {
3667   GtkNotebookPage *page;
3668   gint nchildren;
3669
3670   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3671   g_return_if_fail (GTK_IS_WIDGET (child));
3672   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3673   g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
3674
3675   page = g_new (GtkNotebookPage, 1);
3676   page->child = child;
3677   page->requisition.width = 0;
3678   page->requisition.height = 0;
3679   page->allocation.x = 0;
3680   page->allocation.y = 0;
3681   page->allocation.width = 0;
3682   page->allocation.height = 0;
3683   page->default_menu = FALSE;
3684   page->default_tab = FALSE;
3685    
3686   nchildren = g_list_length (notebook->children);
3687   if ((position < 0) || (position > nchildren))
3688     position = nchildren;
3689
3690   notebook->children = g_list_insert (notebook->children, page, position);
3691
3692   if (!tab_label)
3693     {
3694       page->default_tab = TRUE;
3695       if (notebook->show_tabs)
3696         tab_label = gtk_label_new ("");
3697     }
3698   page->tab_label = tab_label;
3699   page->menu_label = menu_label;
3700   page->expand = FALSE;
3701   page->fill = TRUE;
3702   page->pack = GTK_PACK_START;
3703
3704   if (!menu_label)
3705     page->default_menu = TRUE;
3706   else  
3707     {
3708       gtk_widget_ref (page->menu_label);
3709       gtk_object_sink (GTK_OBJECT (page->menu_label));
3710     }
3711
3712   if (notebook->menu)
3713     gtk_notebook_menu_item_create (notebook,
3714                                    g_list_find (notebook->children, page));
3715
3716   gtk_notebook_update_labels (notebook);
3717
3718   if (!notebook->first_tab)
3719     notebook->first_tab = notebook->children;
3720
3721   gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3722   if (tab_label)
3723     gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3724
3725   if (!notebook->cur_page)
3726     {
3727       gtk_notebook_switch_page (notebook, page, 0);
3728       gtk_notebook_switch_focus_tab (notebook, NULL);
3729     }
3730
3731   if (GTK_WIDGET_REALIZED (child->parent))
3732     gtk_widget_realize (child);
3733
3734   if (GTK_WIDGET_VISIBLE (notebook))
3735     {
3736       if (GTK_WIDGET_VISIBLE (child))
3737         {
3738           if (GTK_WIDGET_MAPPED (notebook) &&
3739               !GTK_WIDGET_MAPPED (child) &&
3740               notebook->cur_page == page)
3741             gtk_widget_map (child);
3742           
3743           gtk_widget_queue_resize (child);
3744         }
3745
3746       if (tab_label)
3747         {
3748           if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3749             {
3750               if (!GTK_WIDGET_VISIBLE (tab_label))
3751                 gtk_widget_show (tab_label);
3752               
3753               if (GTK_WIDGET_REALIZED (notebook) &&
3754                   !GTK_WIDGET_REALIZED (tab_label))
3755                 gtk_widget_realize (tab_label);
3756               
3757               if (GTK_WIDGET_MAPPED (notebook) &&
3758                   !GTK_WIDGET_MAPPED (tab_label))
3759                 gtk_widget_map (tab_label);
3760             }
3761           else if (GTK_WIDGET_VISIBLE (tab_label))
3762             gtk_widget_hide (tab_label);
3763         }
3764     }
3765 }
3766
3767 /**
3768  * gtk_notebook_remove_page:
3769  * @notebook: a #GtkNotebook.
3770  * @page_num: the index of a notebook page, starting
3771  *            from 0. If -1, the last page will
3772  *            be removed.
3773  * 
3774  * Removes a page from the notebook given its index
3775  * in the notebook.
3776  **/
3777 void
3778 gtk_notebook_remove_page (GtkNotebook *notebook,
3779                           gint         page_num)
3780 {
3781   GList *list;
3782   
3783   g_return_if_fail (notebook != NULL);
3784   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3785   
3786   if (page_num >= 0)
3787     {
3788       list = g_list_nth (notebook->children, page_num);
3789       if (list)
3790         gtk_notebook_real_remove (notebook, list);
3791     }
3792   else
3793     {
3794       list = g_list_last (notebook->children);
3795       if (list)
3796         gtk_notebook_real_remove (notebook, list);
3797     }
3798 }
3799
3800 /* Public GtkNotebook Page Switch Methods :
3801  * gtk_notebook_get_current_page
3802  * gtk_notebook_page_num
3803  * gtk_notebook_set_page
3804  * gtk_notebook_next_page
3805  * gtk_notebook_prev_page
3806  */
3807 /**
3808  * gtk_notebook_get_current_page:
3809  * @notebook: a #GtkNotebook
3810  * 
3811  * Returns the page number of the current page.
3812  * 
3813  * Return value: the index (starting from 0) of the current
3814  * page in the notebook. If the notebook has no pages, then
3815  * -1 will be returned.
3816  **/
3817 gint
3818 gtk_notebook_get_current_page (GtkNotebook *notebook)
3819 {
3820   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3821
3822   if (!notebook->cur_page)
3823     return -1;
3824
3825   return g_list_index (notebook->children, notebook->cur_page);
3826 }
3827
3828 /**
3829  * gtk_notebook_get_nth_page:
3830  * @notebook: a #GtkNotebook
3831  * @page_num: the index of a page in the noteobok
3832  * 
3833  * Returns the child widget contained in page number @page_num.
3834  * 
3835  * Return value: the child widget, or %NULL if @page_num is
3836  * out of bounds.
3837  **/
3838 GtkWidget*
3839 gtk_notebook_get_nth_page (GtkNotebook *notebook,
3840                            gint         page_num)
3841 {
3842   GtkNotebookPage *page;
3843
3844   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
3845
3846   page = g_list_nth_data (notebook->children, page_num);
3847
3848   if (page)
3849     return page->child;
3850
3851   return NULL;
3852 }
3853
3854 /**
3855  * gtk_notebook_page_num:
3856  * @notebook: a #GtkNotebook
3857  * @child: a #GtkWidget
3858  * 
3859  * Finds the index of the page which contains the given child
3860  * widget.
3861  * 
3862  * Return value: the index of the page containing @child, or
3863  *   -1 if @child is not in the notebook.
3864  **/
3865 gint
3866 gtk_notebook_page_num (GtkNotebook      *notebook,
3867                        GtkWidget        *child)
3868 {
3869   GList *children;
3870   gint num;
3871
3872   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3873
3874   num = 0;
3875   children = notebook->children;
3876   while (children)
3877     {
3878       GtkNotebookPage *page =  children->data;
3879       
3880       if (page->child == child)
3881         return num;
3882
3883       children = children->next;
3884       num++;
3885     }
3886
3887   return -1;
3888 }
3889
3890 /**
3891  * gtk_notebook_set_page:
3892  * @notebook: a #GtkNotebook
3893  * @page_num: index of the page to switch to, starting from 0.
3894  *            If negative, or greater than the number of pages
3895  *            in the notebook the last page will be used.
3896  *                
3897  * Switches to the page number @page_num.
3898  **/
3899 void
3900 gtk_notebook_set_page (GtkNotebook *notebook,
3901                        gint         page_num)
3902 {
3903   GList *list;
3904
3905   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3906
3907   if (page_num >= 0)
3908     list = g_list_nth (notebook->children, page_num);
3909   else
3910     list = g_list_last (notebook->children);
3911
3912   page_num = g_list_index (notebook->children, list);
3913
3914   if (list)
3915     gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
3916 }
3917
3918 /**
3919  * gtk_notebook_next_page:
3920  * @notebook: a #GtkNotebook
3921  * 
3922  * Switches to the next page. Nothing happens if the current page is
3923  * the last page.
3924  **/
3925 void
3926 gtk_notebook_next_page (GtkNotebook *notebook)
3927 {
3928   GList *list;
3929
3930   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3931
3932   list = g_list_find (notebook->children, notebook->cur_page);
3933   if (!list)
3934     return;
3935
3936   list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3937   if (!list)
3938     return;
3939
3940   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
3941 }
3942
3943 /**
3944  * gtk_notebook_prev_page:
3945  * @notebook: a #GtkNotebook
3946  * 
3947  * Switches to the previous page. Nothing happens if the current page
3948  * is the first page.
3949  **/
3950 void
3951 gtk_notebook_prev_page (GtkNotebook *notebook)
3952 {
3953   GList *list;
3954
3955   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3956
3957   list = g_list_find (notebook->children, notebook->cur_page);
3958   if (!list)
3959     return;
3960
3961   list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3962   if (!list)
3963     return;
3964
3965   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
3966 }
3967
3968 /* Public GtkNotebook/Tab Style Functions
3969  *
3970  * gtk_notebook_set_show_border
3971  * gtk_notebook_set_show_tabs
3972  * gtk_notebook_set_tab_pos
3973  * gtk_notebook_set_homogeneous_tabs
3974  * gtk_notebook_set_tab_border
3975  * gtk_notebook_set_tab_hborder
3976  * gtk_notebook_set_tab_vborder
3977  * gtk_notebook_set_scrollable
3978  */
3979 /**
3980  * gtk_notebook_set_show_border:
3981  * @notebook: a #GtkNotebook
3982  * @show_border: %TRUE if a bevel should be drawn around the notebook.
3983  * 
3984  * Sets whether a bevel will be drawn around the notebook pages.
3985  * this is only has an effect when the tabs are not shown.
3986  * See gtk_notebook_set_show_tabs().
3987  **/
3988 void
3989 gtk_notebook_set_show_border (GtkNotebook *notebook,
3990                               gboolean     show_border)
3991 {
3992   g_return_if_fail (notebook != NULL);
3993   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3994
3995   if (notebook->show_border != show_border)
3996     {
3997       notebook->show_border = show_border;
3998
3999       if (GTK_WIDGET_VISIBLE (notebook))
4000         gtk_widget_queue_resize (GTK_WIDGET (notebook));
4001     }
4002 }
4003
4004 /**
4005  * gtk_notebook_set_show_tabs:
4006  * @notebook: a #GtkNotebook
4007  * @show_tabs: %TRUE if the tabs should be shown.
4008  * 
4009  * Sets whether to show the tabs for the notebook or not.
4010  **/
4011 void
4012 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
4013                             gboolean     show_tabs)
4014 {
4015   GtkNotebookPage *page;
4016   GList *children;
4017
4018   g_return_if_fail (notebook != NULL);
4019   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4020
4021   show_tabs = show_tabs != FALSE;
4022
4023   if (notebook->show_tabs == show_tabs)
4024     return;
4025
4026   notebook->show_tabs = show_tabs;
4027   children = notebook->children;
4028
4029   if (!show_tabs)
4030     {
4031       GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
4032       
4033       while (children)
4034         {
4035           page = children->data;
4036           children = children->next;
4037           if (page->default_tab)
4038             {
4039               gtk_widget_destroy (page->tab_label);
4040               page->tab_label = NULL;
4041             }
4042           else
4043             gtk_widget_hide (page->tab_label);
4044         }
4045       
4046       if (notebook->panel)
4047         gdk_window_hide (notebook->panel);
4048     }
4049   else
4050     {
4051       GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
4052       gtk_notebook_update_labels (notebook);
4053     }
4054   gtk_widget_queue_resize (GTK_WIDGET (notebook));
4055 }
4056
4057 /**
4058  * gtk_notebook_set_tab_pos:
4059  * @notebook: 
4060  * @pos: 
4061  * 
4062  * Sets the edge at which the tabs for switching pages in the
4063  * notebook are drawn.
4064  **/
4065 void
4066 gtk_notebook_set_tab_pos (GtkNotebook     *notebook,
4067                           GtkPositionType  pos)
4068 {
4069   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4070
4071   if (notebook->tab_pos != pos)
4072     {
4073       notebook->tab_pos = pos;
4074       if (GTK_WIDGET_VISIBLE (notebook))
4075         gtk_widget_queue_resize (GTK_WIDGET (notebook));
4076     }
4077 }
4078
4079 /**
4080  * gtk_notebook_set_homogeneous_tabs:
4081  * @notebook: a #GtkNotebook
4082  * @homogeneous: %TRUE if all tabs should be the same size.
4083  * 
4084  * Sets whether the tabs must have all the same size or not.
4085  **/
4086 void
4087 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
4088                                    gboolean     homogeneous)
4089 {
4090   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4091
4092   if (homogeneous == notebook->homogeneous)
4093     return;
4094
4095   notebook->homogeneous = homogeneous;
4096   gtk_widget_queue_resize (GTK_WIDGET (notebook));
4097 }
4098
4099 /**
4100  * gtk_notebook_set_tab_border:
4101  * @notebook: a #GtkNotebook
4102  * @tab_border: %TRUE if there should be a border around the
4103  *              tab labels.
4104  * 
4105  * Sets whether there should be a border around the tab labels
4106  * in a notebook. This is equivalent to calling
4107  * gtk_notebook_set_tab_hborder (@notebook, @tab_border) followed
4108  * by gtk_noteobok_set_tab_vborder (@notebook, @tab_border).
4109  **/
4110 void
4111 gtk_notebook_set_tab_border (GtkNotebook *notebook,
4112                              guint        tab_border)
4113 {
4114   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4115
4116   notebook->tab_hborder = tab_border;
4117   notebook->tab_vborder = tab_border;
4118
4119   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
4120     gtk_widget_queue_resize (GTK_WIDGET (notebook));
4121 }
4122
4123 /**
4124  * gtk_notebook_set_tab_hborder:
4125  * @notebook: a #GtkNotebook
4126  * @tab_vborder: %TRUE if the notebook tabs should have
4127  *               a vertical border.
4128  * 
4129  * Sets whether the tabs should have a vertical border.
4130  **/
4131 void
4132 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
4133                               guint        tab_hborder)
4134 {
4135   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4136
4137   if (notebook->tab_hborder == tab_hborder)
4138     return;
4139
4140   notebook->tab_hborder = tab_hborder;
4141
4142   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
4143     gtk_widget_queue_resize (GTK_WIDGET (notebook));
4144 }
4145
4146 /**
4147  * gtk_notebook_set_tab_vborder:
4148  * @notebook: a #GtkNotebook
4149  * @tab_vborder: %TRUE if the notebook tabs should have
4150  *               a vertical border.
4151  * 
4152  * Sets whether the tabs should have a vertical border.
4153  **/
4154 void
4155 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
4156                               guint        tab_vborder)
4157 {
4158   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4159
4160   if (notebook->tab_vborder == tab_vborder)
4161     return;
4162
4163   notebook->tab_vborder = tab_vborder;
4164
4165   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
4166     gtk_widget_queue_resize (GTK_WIDGET (notebook));
4167 }
4168
4169 /**
4170  * gtk_notebook_set_scrollable:
4171  * @notebook: a #GtkNotebook
4172  * @scrollable: %TRUE if scroll arrows should be added
4173  * 
4174  * Sets whether the tab label area will have arrows for scrolling if
4175  * there are too many tabs to fit in the area.
4176
4177  **/
4178 void
4179 gtk_notebook_set_scrollable (GtkNotebook *notebook,
4180                              gboolean     scrollable)
4181 {
4182   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4183
4184   scrollable = (scrollable != FALSE);
4185
4186   if (scrollable != notebook->scrollable)
4187     {
4188       notebook->scrollable = scrollable;
4189
4190       if (GTK_WIDGET_REALIZED (notebook))
4191         {
4192           if (scrollable)
4193             {
4194               gtk_notebook_panel_realize (notebook);
4195             }
4196           else if (notebook->panel)
4197             {
4198               gdk_window_set_user_data (notebook->panel, NULL);
4199               gdk_window_destroy (notebook->panel);
4200               notebook->panel = NULL;
4201             }
4202         }
4203
4204       if (GTK_WIDGET_VISIBLE (notebook))
4205         gtk_widget_queue_resize (GTK_WIDGET (notebook));
4206     }
4207 }
4208
4209 /* Public GtkNotebook Popup Menu Methods:
4210  *
4211  * gtk_notebook_popup_enable
4212  * gtk_notebook_popup_disable
4213  */
4214
4215
4216 /**
4217  * gtk_notebook_popup_enable:
4218  * @notebook: a #GtkNotebook
4219  * 
4220  * Enables the popup menu: if the user clicks with the right mouse button on
4221  * the bookmarks, a menu with all the pages will be popped up.
4222  **/
4223 void
4224 gtk_notebook_popup_enable (GtkNotebook *notebook)
4225 {
4226   GList *list;
4227
4228   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4229
4230   if (notebook->menu)
4231     return;
4232
4233   notebook->menu = gtk_menu_new ();
4234   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4235        list;
4236        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4237     gtk_notebook_menu_item_create (notebook, list);
4238
4239   gtk_notebook_update_labels (notebook);
4240   gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
4241                              GTK_WIDGET (notebook),
4242                              gtk_notebook_menu_detacher);
4243 }
4244
4245 /**
4246  * gtk_notebook_popup_disable:
4247  * @notebook: a #GtkNotebook
4248  * 
4249  * Disables the popup menu.
4250  **/
4251 void       
4252 gtk_notebook_popup_disable  (GtkNotebook *notebook)
4253 {
4254   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4255
4256   if (!notebook->menu)
4257     return;
4258
4259   gtk_container_foreach (GTK_CONTAINER (notebook->menu),
4260                          (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
4261   gtk_widget_destroy (notebook->menu);
4262 }
4263
4264 /* Public GtkNotebook Page Properties Functions:
4265  *
4266  * gtk_notebook_get_tab_label
4267  * gtk_notebook_set_tab_label
4268  * gtk_notebook_set_tab_label_text
4269  * gtk_notebook_get_menu_label
4270  * gtk_notebook_set_menu_label
4271  * gtk_notebook_set_menu_label_text
4272  * gtk_notebook_set_tab_label_packing
4273  * gtk_notebook_query_tab_label_packing
4274  */
4275
4276 /**
4277  * gtk_notebook_get_tab_label:
4278  * @notebook: a #GtkNotebook
4279  * @child: the page
4280  * 
4281  * Returns the tab label widget for the page @child. %NULL is returned
4282  * if @child is not in @notebook or if no tab label has specifically
4283  * been set for @child.
4284  * 
4285  * Return value: the tab label
4286  **/
4287 GtkWidget *
4288 gtk_notebook_get_tab_label (GtkNotebook *notebook,
4289                             GtkWidget   *child)
4290 {
4291   GList *list;
4292
4293   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4294   g_return_val_if_fail (child != NULL, NULL);
4295
4296   list = CHECK_FIND_CHILD (notebook, child);
4297   if (!list)  
4298     return NULL;
4299
4300   if (GTK_NOTEBOOK_PAGE (list)->default_tab)
4301     return NULL;
4302
4303   return GTK_NOTEBOOK_PAGE (list)->tab_label;
4304 }  
4305
4306 /**
4307  * gtk_notebook_set_tab_label:
4308  * @notebook: a #GtkNotebook
4309  * @child: the page
4310  * @tab_label: the tab label widget to use, or %NULL for default tab
4311  *             label.
4312  * 
4313  * Changes the tab label for @child. If %NULL is specified
4314  * for @tab_label, then the page will have the label 'page N'.
4315  **/
4316 void
4317 gtk_notebook_set_tab_label (GtkNotebook *notebook,
4318                             GtkWidget   *child,
4319                             GtkWidget   *tab_label)
4320 {
4321   GtkNotebookPage *page;
4322   GList *list;
4323
4324   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4325   g_return_if_fail (child != NULL);
4326
4327   list = CHECK_FIND_CHILD (notebook, child);
4328   if (!list)  
4329     return;
4330
4331   /* a NULL pointer indicates a default_tab setting, otherwise
4332    * we need to set the associated label
4333    */
4334   page = list->data;
4335   if (page->tab_label)
4336     gtk_widget_unparent (page->tab_label);
4337
4338   if (tab_label)
4339     {
4340       page->default_tab = FALSE;
4341       page->tab_label = tab_label;
4342       gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
4343     }
4344   else
4345     {
4346       page->default_tab = TRUE;
4347       page->tab_label = NULL;
4348
4349       if (notebook->show_tabs)
4350         {
4351           gchar string[32];
4352
4353           g_snprintf (string, sizeof(string), _("Page %u"), 
4354                       gtk_notebook_real_page_position (notebook, list));
4355           page->tab_label = gtk_label_new (string);
4356           gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
4357         }
4358     }
4359
4360   if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4361     {
4362       gtk_widget_show (page->tab_label);
4363       gtk_widget_queue_resize (GTK_WIDGET (notebook));
4364     }
4365 }
4366
4367 /**
4368  * gtk_notebook_set_tab_label_text:
4369  * @notebook: a #GtkNotebook
4370  * @child: the page
4371  * @tab_label: the label text
4372  * 
4373  * Creates a new label and sets it as the tab label for the page
4374  * containing @child.
4375  **/
4376 void
4377 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
4378                                  GtkWidget   *child,
4379                                  const gchar *tab_text)
4380 {
4381   GtkWidget *tab_label = NULL;
4382
4383   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4384
4385   if (tab_text)
4386     tab_label = gtk_label_new (tab_text);
4387   gtk_notebook_set_tab_label (notebook, child, tab_label);
4388 }
4389
4390 /**
4391  * gtk_notebook_get_menu_label:
4392  * @notebook: a #GtkNotebook
4393  * @child: the page
4394  * 
4395  * Returns the menu label of the page containing @child. NULL is
4396  * returned if @child is not in @notebook or NULL if it has the
4397  * default menu label.
4398  * 
4399  * Return value: the menu label
4400  **/
4401 GtkWidget*
4402 gtk_notebook_get_menu_label (GtkNotebook *notebook,
4403                              GtkWidget   *child)
4404 {
4405   GList *list;
4406
4407   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4408   g_return_val_if_fail (child != NULL, NULL);
4409
4410   list = CHECK_FIND_CHILD (notebook, child);
4411   if (!list)  
4412     return NULL;
4413
4414   if (GTK_NOTEBOOK_PAGE (list)->default_menu)
4415     return NULL;
4416
4417   return GTK_NOTEBOOK_PAGE (list)->menu_label;
4418 }  
4419
4420 /**
4421  * gtk_notebook_set_menu_label:
4422  * @notebook: a #GtkNotebook
4423  * @child: the child widget
4424  * @menu_label: the menu label, or NULL for default
4425  * 
4426  * Changes the menu label for the page containing @child. 
4427  **/
4428 void
4429 gtk_notebook_set_menu_label (GtkNotebook *notebook,
4430                              GtkWidget   *child,
4431                              GtkWidget   *menu_label)
4432 {
4433   GtkNotebookPage *page;
4434   GList *list;
4435
4436   g_return_if_fail (notebook != NULL);
4437   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4438   g_return_if_fail (child != NULL);
4439
4440   list = CHECK_FIND_CHILD (notebook, child);
4441   if (!list)  
4442     return;
4443
4444   page = list->data;
4445   if (page->menu_label)
4446     {
4447       if (notebook->menu)
4448         gtk_container_remove (GTK_CONTAINER (notebook->menu), 
4449                               page->menu_label->parent);
4450
4451       if (!page->default_menu)
4452         gtk_widget_unref (page->menu_label);
4453     }
4454
4455   if (menu_label)
4456     {
4457       page->menu_label = menu_label;
4458       gtk_widget_ref (page->menu_label);
4459       gtk_object_sink (GTK_OBJECT(page->menu_label));
4460       page->default_menu = FALSE;
4461     }
4462   else
4463     page->default_menu = TRUE;
4464
4465   if (notebook->menu)
4466     gtk_notebook_menu_item_create (notebook, list);
4467 }
4468
4469 /**
4470  * gtk_notebook_set_menu_label_text:
4471  * @notebook: a #GtkNotebook
4472  * @child: the child widget
4473  * @menu_text: the label text
4474  * 
4475  * Creates a new label and sets it as the menu label of @child.
4476  **/
4477 void
4478 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
4479                                   GtkWidget   *child,
4480                                   const gchar *menu_text)
4481 {
4482   GtkWidget *menu_label = NULL;
4483
4484   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4485
4486   if (menu_text)
4487     menu_label = gtk_label_new (menu_text);
4488   gtk_notebook_set_menu_label (notebook, child, menu_label);
4489 }
4490
4491 /* Helper function called when pages are reordered
4492  */
4493 static void
4494 gtk_notebook_child_reordered (GtkNotebook     *notebook,
4495                               GtkNotebookPage *page)
4496 {
4497   if (notebook->menu)
4498     {
4499       GtkWidget *menu_item;
4500       
4501       menu_item = page->menu_label->parent;
4502       gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
4503       gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
4504       gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
4505     }
4506   
4507   gtk_notebook_update_labels (notebook);
4508 }
4509
4510 /**
4511  * gtk_notebook_set_tab_label_packing:
4512  * @notebook: a #GtkNotebook
4513  * @child: the child widget
4514  * @expand: whether to expand the bookmark or not
4515  * @fill: whether the bookmark should fill the allocated area or not
4516  * @pack_type: the position of the bookmark
4517  * 
4518  * Sets the packing parameters for the tab label of the page
4519  * containing @child. See gtk_box_pack_start() for the exact meaning
4520  * of the parameters.
4521  **/
4522 void
4523 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
4524                                     GtkWidget   *child,
4525                                     gboolean     expand,
4526                                     gboolean     fill,
4527                                     GtkPackType  pack_type)
4528 {
4529   GtkNotebookPage *page;
4530   GList *list;
4531
4532   g_return_if_fail (notebook != NULL);
4533   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4534   g_return_if_fail (child != NULL);
4535
4536   list = CHECK_FIND_CHILD (notebook, child);
4537   if (!list)  
4538     return;
4539
4540   page = list->data;
4541   if (page->pack == pack_type && page->expand == expand && page->fill == fill)
4542     return;
4543
4544   page->expand = expand;
4545   page->fill = fill;
4546
4547   if (page->pack != pack_type)
4548     {
4549       page->pack = pack_type;
4550       gtk_notebook_child_reordered (notebook, page);
4551     }
4552
4553   if (!notebook->show_tabs)
4554     return;
4555
4556   gtk_notebook_pages_allocate (notebook);
4557 }  
4558
4559 /**
4560  * gtk_notebook_query_tab_label_packing:
4561  * @notebook: a #GtkNotebook
4562  * @child: the page
4563  * @expand: location to store the expand value (or NULL)
4564  * @fill: location to store the fill value (or NULL)
4565  * @pack_type: location to store the pack_type (or NULL)
4566  * 
4567  * Query the packing attributes for the tab label of the page
4568  * containing @child.
4569  **/
4570 void
4571 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
4572                                       GtkWidget   *child,
4573                                       gboolean    *expand,
4574                                       gboolean    *fill,
4575                                       GtkPackType *pack_type)
4576 {
4577   GList *list;
4578
4579   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4580   g_return_if_fail (child != NULL);
4581
4582   list = CHECK_FIND_CHILD (notebook, child);
4583   if (!list)
4584     return;
4585
4586   if (expand)
4587     *expand = GTK_NOTEBOOK_PAGE (list)->expand;
4588   if (fill)
4589     *fill = GTK_NOTEBOOK_PAGE (list)->fill;
4590   if (pack_type)
4591     *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
4592 }
4593
4594 /**
4595  * gtk_notebook_reorder_child:
4596  * @notebook: a #GtkNotebook
4597  * @child: the child to move
4598  * @position: the new position
4599  * 
4600  * Reorders the page containing @child, so that it appears in position
4601  * @position. Out of bounds @position will be clamped.
4602  **/
4603 void
4604 gtk_notebook_reorder_child (GtkNotebook *notebook,
4605                             GtkWidget   *child,
4606                             gint         position)
4607 {
4608   GList *list, *new_list;
4609   GtkNotebookPage *page;
4610   gint old_pos;
4611
4612   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4613   g_return_if_fail (GTK_IS_WIDGET (child));
4614
4615   list = CHECK_FIND_CHILD (notebook, child);
4616   if (!list)
4617     return;
4618
4619   old_pos = g_list_position (notebook->children, list);
4620
4621   if (old_pos == position)
4622     return;
4623
4624   page = list->data;
4625   notebook->children = g_list_delete_link (notebook->children, list);
4626
4627   position = CLAMP (position, 0, g_list_length (notebook->children));
4628
4629   notebook->children = g_list_insert (notebook->children, page, position);
4630   new_list = g_list_nth (notebook->children, position);
4631
4632   /* Fix up GList references in GtkNotebook structure */
4633   if (notebook->first_tab == list)
4634     notebook->first_tab = new_list;
4635   if (notebook->focus_tab == list)
4636     notebook->focus_tab = new_list;
4637
4638   /* Move around the menu items if necesary */
4639   gtk_notebook_child_reordered (notebook, page);
4640
4641   if (notebook->show_tabs)
4642     gtk_notebook_pages_allocate (notebook);
4643 }