]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtknotebook.c
Clarify the docs. Pointed out by Wolfgang Oertl
[~andy/gtk] / gtk / gtknotebook.c
index cb25de0e6d1187be0711ddbe08817dcce5879a92..b623e15ea31821fffe8f2018359806ee2b6fa7b3 100644 (file)
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
-#include <config.h>
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <gdk/gdkkeysyms.h>
+
+#undef GTK_DISABLE_DEPRECATED
+
 #include "gtknotebook.h"
 #include "gtkmain.h"
 #include "gtkmenu.h"
 #include "gtkmenuitem.h"
 #include "gtklabel.h"
-#include <gdk/gdkkeysyms.h>
-#include <stdio.h>
 #include "gtkintl.h"
 #include "gtkmarshalers.h"
 #include "gtkbindings.h"
 #include "gtkprivate.h"
 #include "gtkdnd.h"
+#include "gtkbuildable.h"
+
 #include "gtkalias.h"
 
 #define SCROLL_DELAY_FACTOR   5
@@ -56,6 +64,7 @@ enum {
   PAGE_REORDERED,
   PAGE_REMOVED,
   PAGE_ADDED,
+  CREATE_WINDOW,
   LAST_SIGNAL
 };
 
@@ -102,6 +111,7 @@ enum {
   PROP_PAGE,
   PROP_ENABLE_POPUP,
   PROP_GROUP_ID,
+  PROP_GROUP,
   PROP_HOMOGENEOUS
 };
 
@@ -156,7 +166,7 @@ typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
 
 struct _GtkNotebookPrivate
 {
-  gint  group_id;
+  gpointer group;
   gint  mouse_x;
   gint  mouse_y;
   gint  pressed_button;
@@ -208,6 +218,8 @@ static void     gtk_notebook_move_focus_out      (GtkNotebook      *notebook,
 static gboolean gtk_notebook_reorder_tab         (GtkNotebook      *notebook,
                                                  GtkDirectionType  direction_type,
                                                  gboolean          move_to_last);
+static void     gtk_notebook_remove_tab_label    (GtkNotebook      *notebook,
+                                                 GtkNotebookPage  *page);
 
 /*** GtkObject Methods ***/
 static void gtk_notebook_destroy             (GtkObject        *object);
@@ -322,6 +334,11 @@ static gint gtk_notebook_real_insert_page    (GtkNotebook      *notebook,
                                              GtkWidget        *menu_label,
                                              gint              position);
 
+static GtkNotebook *gtk_notebook_create_window (GtkNotebook    *notebook,
+                                                GtkWidget      *page,
+                                                gint            x,
+                                                gint            y);
+
 /*** GtkNotebook Private Functions ***/
 static void gtk_notebook_redraw_tabs         (GtkNotebook      *notebook);
 static void gtk_notebook_redraw_arrows       (GtkNotebook      *notebook);
@@ -341,6 +358,8 @@ static GList * gtk_notebook_search_page      (GtkNotebook      *notebook,
                                              GList            *list,
                                              gint              direction,
                                              gboolean          find_visible);
+static void  gtk_notebook_child_reordered    (GtkNotebook      *notebook,
+                                             GtkNotebookPage  *page);
 
 /*** GtkNotebook Drawing Functions ***/
 static void gtk_notebook_paint               (GtkWidget        *widget,
@@ -368,8 +387,7 @@ static void gtk_notebook_real_switch_page    (GtkNotebook      *notebook,
 
 /*** GtkNotebook Page Switch Functions ***/
 static void gtk_notebook_switch_page         (GtkNotebook      *notebook,
-                                             GtkNotebookPage  *page,
-                                             gint              page_num);
+                                             GtkNotebookPage  *page);
 static gint gtk_notebook_page_select         (GtkNotebook      *notebook,
                                              gboolean          move_focus);
 static void gtk_notebook_switch_focus_tab    (GtkNotebook      *notebook,
@@ -411,6 +429,12 @@ static void do_detach_tab  (GtkNotebook *from,
                            gint         x,
                            gint         y);
 
+/* GtkBuildable */
+static void gtk_notebook_buildable_init           (GtkBuildableIface *iface);
+static void gtk_notebook_buildable_add_child      (GtkBuildable *buildable,
+                                                  GtkBuilder   *builder,
+                                                  GObject      *child,
+                                                  const gchar  *type);
 
 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
 static gpointer window_creation_hook_data;
@@ -418,7 +442,9 @@ static GDestroyNotify window_creation_hook_destroy = NULL;
 
 static guint notebook_signals[LAST_SIGNAL] = { 0 };
 
-G_DEFINE_TYPE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER)
+G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+                                               gtk_notebook_buildable_init))
 
 static void
 add_tab_bindings (GtkBindingSet    *binding_set,
@@ -466,6 +492,22 @@ add_reorder_bindings (GtkBindingSet    *binding_set,
                                G_TYPE_BOOLEAN, move_to_last);
 }
 
+static gboolean
+gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
+                                GValue                *return_accu,
+                                const GValue          *handler_return,
+                                gpointer               dummy)
+{
+  gboolean continue_emission;
+  GObject *object;
+
+  object = g_value_get_object (handler_return);
+  g_value_set_object (return_accu, object);
+  continue_emission = !object;
+
+  return continue_emission;
+}
+
 static void
 gtk_notebook_class_init (GtkNotebookClass *class)
 {
@@ -522,15 +564,16 @@ gtk_notebook_class_init (GtkNotebookClass *class)
   class->change_current_page = gtk_notebook_change_current_page;
   class->move_focus_out = gtk_notebook_move_focus_out;
   class->reorder_tab = gtk_notebook_reorder_tab;
+  class->create_window = gtk_notebook_create_window;
   
   g_object_class_install_property (gobject_class,
                                   PROP_PAGE,
                                   g_param_spec_int ("page",
                                                     P_("Page"),
                                                     P_("The index of the current page"),
-                                                    0,
+                                                    -1,
                                                     G_MAXINT,
-                                                    0,
+                                                    -1,
                                                     GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_TAB_POS,
@@ -612,6 +655,20 @@ gtk_notebook_class_init (GtkNotebookClass *class)
                                                     -1,
                                                     GTK_PARAM_READWRITE));
 
+  /**
+   * GtkNotebook:group:
+   *  
+   * Group for tabs drag and drop.
+   *
+   * Since: 2.12
+   */    
+  g_object_class_install_property (gobject_class,
+                                  PROP_GROUP,
+                                  g_param_spec_pointer ("group",
+                                                        P_("Group"),
+                                                        P_("Group for tabs drag and drop"),
+                                                        GTK_PARAM_READWRITE));
+
   gtk_container_class_install_child_property (container_class,
                                              CHILD_PROP_TAB_LABEL,
                                              g_param_spec_string ("tab-label", 
@@ -638,7 +695,7 @@ gtk_notebook_class_init (GtkNotebookClass *class)
                                              g_param_spec_boolean ("tab-expand", 
                                                                    P_("Tab expand"), 
                                                                    P_("Whether to expand the child's tab or not"),
-                                                                   TRUE,
+                                                                   FALSE,
                                                                    GTK_PARAM_READWRITE));
   gtk_container_class_install_child_property (container_class,
                                              CHILD_PROP_TAB_FILL,
@@ -767,7 +824,7 @@ gtk_notebook_class_init (GtkNotebookClass *class)
   /**
    * GtkNotebook:arrow-spacing:
    *
-   * The "arrow-size" property defines the spacing between the scroll
+   * The "arrow-spacing" property defines the spacing between the scroll
    * arrows and the tabs.
    *
    * Since: 2.10
@@ -898,6 +955,39 @@ gtk_notebook_class_init (GtkNotebookClass *class)
                  GTK_TYPE_WIDGET,
                  G_TYPE_UINT);
 
+  /**
+   * GtkNotebook::create-window:
+   * @notebook: the #GtkNotebook emitting the signal
+   * @page: the tab of @notebook that is being detached
+   * @x: the X coordinate where the drop happens
+   * @y: the Y coordinate where the drop happens
+   *
+   * The ::create-window signal is emitted when a detachable
+   * tab is dropped on the root window. 
+   *
+   * A handler for this signal can create a window containing 
+   * a notebook where the tab will be attached. It is also 
+   * responsible for moving/resizing the window and adding the 
+   * necessary properties to the notebook (e.g. the 
+   * #GtkNotebook:group-id ).
+   *
+   * The default handler uses the global window creation hook,
+   * if one has been set with gtk_notebook_set_window_creation_hook().
+   *
+   * Returns: a #GtkNotebook that @page should be added to, or %NULL.
+   *
+   * Since: 2.12
+   */
+  notebook_signals[CREATE_WINDOW] = 
+    g_signal_new (I_("create_window"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkNotebookClass, create_window),
+                  gtk_object_handled_accumulator, NULL,
+                  _gtk_marshal_OBJECT__OBJECT_INT_INT,
+                  GTK_TYPE_NOTEBOOK, 3,
+                  GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
   binding_set = gtk_binding_set_by_class (class);
   gtk_binding_entry_add_signal (binding_set,
                                 GDK_space, 0,
@@ -1000,7 +1090,7 @@ gtk_notebook_init (GtkNotebook *notebook)
   notebook->has_after_previous  = 0;
   notebook->has_after_next      = 1;
 
-  priv->group_id = -1;
+  priv->group = NULL;
   priv->pressed_button = -1;
   priv->dnd_timer = 0;
   priv->switch_tab_timer = 0;
@@ -1011,8 +1101,7 @@ gtk_notebook_init (GtkNotebook *notebook)
   priv->during_detach = FALSE;
   priv->has_scrolled = FALSE;
 
-  gtk_drag_dest_set (GTK_WIDGET (notebook),
-                    GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
+  gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
                     notebook_targets, G_N_ELEMENTS (notebook_targets),
                      GDK_ACTION_MOVE);
 
@@ -1022,6 +1111,36 @@ gtk_notebook_init (GtkNotebook *notebook)
   gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
 }
 
+static void
+gtk_notebook_buildable_init (GtkBuildableIface *iface)
+{
+  iface->add_child = gtk_notebook_buildable_add_child;
+}
+
+static void
+gtk_notebook_buildable_add_child (GtkBuildable  *buildable,
+                                 GtkBuilder    *builder,
+                                 GObject       *child,
+                                 const gchar   *type)
+{
+  GtkNotebook *notebook = GTK_NOTEBOOK (buildable);
+
+  if (type && strcmp (type, "tab") == 0)
+    {
+      GtkWidget * page;
+
+      page = gtk_notebook_get_nth_page (notebook, -1);
+      /* To set the tab label widget, we must have already a child
+       * inside the tab container. */
+      g_assert (page != NULL);
+      gtk_notebook_set_tab_label (notebook, page, GTK_WIDGET (child));
+    }
+  else if (!type)
+    gtk_notebook_append_page (notebook, GTK_WIDGET (child), NULL);
+  else
+    GTK_BUILDER_WARN_INVALID_CHILD_TYPE (notebook, type);
+}
+
 static gboolean
 gtk_notebook_select_page (GtkNotebook *notebook,
                           gboolean     move_focus)
@@ -1101,7 +1220,7 @@ gtk_notebook_change_current_page (GtkNotebook *notebook,
     }
 
   if (current)
-    gtk_notebook_switch_page (notebook, current->data, -1);
+    gtk_notebook_switch_page (notebook, current->data);
   else
     gtk_widget_error_bell (GTK_WIDGET (notebook));
 
@@ -1344,7 +1463,7 @@ gtk_notebook_destroy (GtkObject *object)
 {
   GtkNotebook *notebook = GTK_NOTEBOOK (object);
   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
-  
+
   if (notebook->menu)
     gtk_notebook_popup_disable (notebook);
 
@@ -1411,7 +1530,11 @@ gtk_notebook_set_property (GObject         *object,
     case PROP_GROUP_ID:
       gtk_notebook_set_group_id (notebook, g_value_get_int (value));
       break;
+    case PROP_GROUP:
+      gtk_notebook_set_group (notebook, g_value_get_pointer (value));
+      break;
     default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
     }
 }
@@ -1458,7 +1581,10 @@ gtk_notebook_get_property (GObject         *object,
       g_value_set_uint (value, notebook->tab_vborder);
       break;
     case PROP_GROUP_ID:
-      g_value_set_int (value, priv->group_id);
+      g_value_set_int (value, gtk_notebook_get_group_id (notebook));
+      break;
+    case PROP_GROUP:
+      g_value_set_pointer (value, priv->group);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1559,8 +1685,6 @@ gtk_notebook_map (GtkWidget *widget)
   GtkNotebookPage *page;
   GList *children;
 
-  g_return_if_fail (GTK_IS_NOTEBOOK (widget));
-
   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
 
   notebook = GTK_NOTEBOOK (widget);
@@ -1595,8 +1719,6 @@ gtk_notebook_map (GtkWidget *widget)
 static void
 gtk_notebook_unmap (GtkWidget *widget)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (widget));
-
   stop_scrolling (GTK_NOTEBOOK (widget));
   
   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
@@ -1614,8 +1736,6 @@ gtk_notebook_realize (GtkWidget *widget)
   gint attributes_mask;
   GdkRectangle event_window_pos;
 
-  g_return_if_fail (GTK_IS_NOTEBOOK (widget));
-
   notebook = GTK_NOTEBOOK (widget);
   GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
 
@@ -1650,8 +1770,6 @@ gtk_notebook_unrealize (GtkWidget *widget)
   GtkNotebook *notebook;
   GtkNotebookPrivate *priv;
 
-  g_return_if_fail (GTK_IS_NOTEBOOK (widget));
-
   notebook = GTK_NOTEBOOK (widget);
   priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
 
@@ -1913,7 +2031,7 @@ gtk_notebook_size_request (GtkWidget      *widget,
              page = children->data;
              if (GTK_WIDGET_VISIBLE (page->child))
                {
-                 gtk_notebook_switch_page (notebook, page, -1);
+                 gtk_notebook_switch_page (notebook, page);
                  break;
                }
            }
@@ -1930,7 +2048,7 @@ gtk_notebook_size_request (GtkWidget      *widget,
       if (children)
        {
          notebook->first_tab = children;
-         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
+         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children));
        }
     }
 }
@@ -2023,9 +2141,6 @@ gtk_notebook_expose (GtkWidget      *widget,
   GtkNotebook *notebook;
   GtkNotebookPrivate *priv;
 
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
   notebook = GTK_NOTEBOOK (widget);
   priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
 
@@ -2621,7 +2736,6 @@ hide_drag_window (GtkNotebook        *notebook,
       else
        gtk_widget_unparent (page->tab_label);
 
-      gtk_widget_set_parent_window (page->tab_label, widget->window);
       gtk_widget_set_parent (page->tab_label, widget);
       g_object_unref (page->tab_label);
     }
@@ -2644,7 +2758,7 @@ gtk_notebook_stop_reorder (GtkNotebook *notebook)
   else
     page = notebook->cur_page;
 
-  if (!page)
+  if (!page || !page->tab_label)
     return;
 
   priv->pressed_button = -1;
@@ -2659,7 +2773,8 @@ gtk_notebook_stop_reorder (GtkNotebook *notebook)
          element = get_drop_position (notebook, page->pack);
          old_page_num = g_list_position (notebook->children, notebook->focus_tab);
          page_num = reorder_tab (notebook, element, notebook->focus_tab);
-
+          gtk_notebook_child_reordered (notebook, page);
+          
          if (priv->has_scrolled || old_page_num != page_num)
            g_signal_emit (notebook,
                           notebook_signals[PAGE_REORDERED], 0,
@@ -2690,9 +2805,6 @@ gtk_notebook_button_release (GtkWidget      *widget,
   GtkNotebookPrivate *priv;
   GtkNotebookPage *page;
 
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
   if (event->type != GDK_BUTTON_RELEASE)
     return FALSE;
 
@@ -3117,7 +3229,7 @@ gtk_notebook_drag_end (GtkWidget      *widget,
   gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
 
   if (priv->detached_tab)
-    gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab, -1);
+    gtk_notebook_switch_page (GTK_NOTEBOOK (widget), priv->detached_tab);
 
   GTK_BIN (priv->dnd_window)->child = NULL;
   gtk_widget_destroy (priv->dnd_window);
@@ -3126,6 +3238,18 @@ gtk_notebook_drag_end (GtkWidget      *widget,
   priv->operation = DRAG_OPERATION_NONE;
 }
 
+static GtkNotebook *
+gtk_notebook_create_window (GtkNotebook *notebook,
+                            GtkWidget   *page,
+                            gint         x,
+                            gint         y)
+{
+  if (window_creation_hook)
+    return (* window_creation_hook) (notebook, page, x, y, window_creation_hook_data);
+
+  return NULL;
+}
+
 static gboolean
 gtk_notebook_drag_failed (GtkWidget      *widget,
                          GdkDragContext *context,
@@ -3135,7 +3259,7 @@ gtk_notebook_drag_failed (GtkWidget      *widget,
   if (result == GTK_DRAG_RESULT_NO_TARGET)
     {
       GtkNotebookPrivate *priv;
-      GtkNotebook *notebook, *dest_notebook;
+      GtkNotebook *notebook, *dest_notebook = NULL;
       GdkDisplay *display;
       gint x, y;
 
@@ -3145,10 +3269,9 @@ gtk_notebook_drag_failed (GtkWidget      *widget,
       display = gtk_widget_get_display (widget);
       gdk_display_get_pointer (display, NULL, &x, &y, NULL);
 
-      dest_notebook = (* window_creation_hook) (notebook,
-                                               priv->detached_tab->child,
-                                               x, y,
-                                               window_creation_hook_data);
+      g_signal_emit (notebook, notebook_signals[CREATE_WINDOW], 0,
+                     priv->detached_tab->child, x, y, &dest_notebook);
+
       if (dest_notebook)
        do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
 
@@ -3218,17 +3341,16 @@ gtk_notebook_drag_motion (GtkWidget      *widget,
 
   if (target == tab_target)
     {
-      gint widget_group, source_widget_group;
+      gpointer widget_group, source_widget_group;
       GtkWidget *source_widget;
 
       source_widget = gtk_drag_get_source_widget (context);
       g_assert (source_widget);
 
-      widget_group = gtk_notebook_get_group_id (notebook);
-      source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
+      widget_group = gtk_notebook_get_group (notebook);
+      source_widget_group = gtk_notebook_get_group (GTK_NOTEBOOK (source_widget));
 
-      if (widget_group != -1 &&
-         source_widget_group != -1 &&
+      if (widget_group && source_widget_group &&
          widget_group == source_widget_group &&
          !(widget == GTK_NOTEBOOK (source_widget)->cur_page->child || 
            gtk_widget_is_ancestor (widget, GTK_NOTEBOOK (source_widget)->cur_page->child)))
@@ -3236,19 +3358,18 @@ gtk_notebook_drag_motion (GtkWidget      *widget,
          gdk_drag_status (context, GDK_ACTION_MOVE, time);
          return TRUE;
        }
+      else
+       {
+         /* it's a tab, but doesn't share
+          * ID with this notebook */
+         gdk_drag_status (context, 0, time);
+       }
     }
 
   priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
   x += widget->allocation.x;
   y += widget->allocation.y;
 
-  if (target == tab_target)
-    {
-      /* it's a tab, but doesn't share
-       * ID with this notebook */
-      gdk_drag_status (context, 0, time);
-    }
-
   if (gtk_notebook_get_event_window_position (notebook, &position) &&
       x >= position.x && x <= position.x + position.width &&
       y >= position.y && y <= position.y + position.height)
@@ -3275,7 +3396,7 @@ gtk_notebook_drag_motion (GtkWidget      *widget,
        }
     }
 
-  return TRUE;
+  return (target == tab_target) ? TRUE : FALSE;
 }
 
 static void
@@ -3303,14 +3424,18 @@ gtk_notebook_drag_drop (GtkWidget        *widget,
                        gint              y,
                        guint             time)
 {
-  GdkAtom target;
+  GdkAtom target, tab_target;
 
   target = gtk_drag_dest_find_target (widget, context, NULL);
+  tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
 
-  if (target == GDK_NONE)
-    gtk_drag_finish (context, FALSE, FALSE, time);
+  if (target == tab_target)
+    {
+      gtk_drag_get_data (widget, context, target, time);
+      return TRUE;
+    }
 
-  return TRUE;
+  return FALSE;
 }
 
 static void
@@ -3535,7 +3660,7 @@ gtk_notebook_get_child_property (GtkContainer    *container,
     case CHILD_PROP_TAB_LABEL:
       label = gtk_notebook_get_tab_label (notebook, child);
 
-      if (label && GTK_IS_LABEL (label))
+      if (GTK_IS_LABEL (label))
        g_value_set_string (value, GTK_LABEL (label)->label);
       else
        g_value_set_string (value, NULL);
@@ -3543,7 +3668,7 @@ gtk_notebook_get_child_property (GtkContainer    *container,
     case CHILD_PROP_MENU_LABEL:
       label = gtk_notebook_get_menu_label (notebook, child);
 
-      if (label && GTK_IS_LABEL (label))
+      if (GTK_IS_LABEL (label))
        g_value_set_string (value, GTK_LABEL (label)->label);
       else
        g_value_set_string (value, NULL);
@@ -3584,8 +3709,6 @@ static void
 gtk_notebook_add (GtkContainer *container,
                  GtkWidget    *widget)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (container));
-
   gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget, 
                                 NULL, NULL, -1);
 }
@@ -3599,9 +3722,6 @@ gtk_notebook_remove (GtkContainer *container,
   GList *children;
   gint page_num = 0;
 
-  g_return_if_fail (GTK_IS_NOTEBOOK (container));
-  g_return_if_fail (widget != NULL);
-
   notebook = GTK_NOTEBOOK (container);
 
   children = notebook->children;
@@ -3703,8 +3823,6 @@ gtk_notebook_focus (GtkWidget        *widget,
   gboolean widget_is_focus;
   GtkContainer *container;
 
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
-
   container = GTK_CONTAINER (widget);
   notebook = GTK_NOTEBOOK (container);
 
@@ -3858,9 +3976,6 @@ gtk_notebook_forall (GtkContainer *container,
   GtkNotebook *notebook;
   GList *children;
 
-  g_return_if_fail (GTK_IS_NOTEBOOK (container));
-  g_return_if_fail (callback != NULL);
-
   notebook = GTK_NOTEBOOK (container);
 
   children = notebook->children;
@@ -3912,7 +4027,7 @@ page_visible_cb (GtkWidget  *page,
         }
 
       if (next)
-        gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
+        gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
     }
 }
 
@@ -3926,28 +4041,11 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
   GtkNotebookPage *page;
   gint nchildren;
 
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
-  g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
-  g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
-  g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
-
   gtk_widget_freeze_child_notify (child);
-  
-  page = g_new (GtkNotebookPage, 1);
+
+  page = g_slice_new0 (GtkNotebookPage);
   page->child = child;
-  page->last_focus_child = NULL;
-  page->requisition.width = 0;
-  page->requisition.height = 0;
-  page->allocation.x = 0;
-  page->allocation.y = 0;
-  page->allocation.width = 0;
-  page->allocation.height = 0;
-  page->default_menu = FALSE;
-  page->default_tab = FALSE;
-  page->mnemonic_activate_signal = 0;
-  page->reorderable = FALSE;
-  page->detachable = FALSE;
-   
+
   nchildren = g_list_length (notebook->children);
   if ((position < 0) || (position > nchildren))
     position = nchildren;
@@ -3958,7 +4056,7 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
     {
       page->default_tab = TRUE;
       if (notebook->show_tabs)
-       tab_label = gtk_label_new ("");
+       tab_label = gtk_label_new (NULL);
     }
   page->tab_label = tab_label;
   page->menu_label = menu_label;
@@ -3971,9 +4069,6 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
   else  
     g_object_ref_sink (page->menu_label);
 
-  /* child visible will be turned on by switch_page below */
-  gtk_widget_set_child_visible (child, FALSE);
-
   if (notebook->menu)
     gtk_notebook_menu_item_create (notebook,
                                   g_list_find (notebook->children, page));
@@ -3987,6 +4082,10 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
   if (!notebook->first_tab)
     notebook->first_tab = notebook->children;
 
+  /* child visible will be turned on by switch_page below */
+  if (notebook->cur_page != page)
+    gtk_widget_set_child_visible (child, FALSE);
+
   if (tab_label)
     {
       if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
@@ -4012,8 +4111,9 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
 
   if (!notebook->cur_page)
     {
-      gtk_notebook_switch_page (notebook, page, 0);
-      gtk_notebook_switch_focus_tab (notebook, NULL);
+      gtk_notebook_switch_page (notebook, page);
+      /* focus_tab is set in the switch_page method */
+      gtk_notebook_switch_focus_tab (notebook, notebook->focus_tab);
     }
 
   gtk_notebook_update_tab_states (notebook);
@@ -4222,21 +4322,24 @@ gtk_notebook_real_remove (GtkNotebook *notebook,
   GtkNotebookPage *page;
   GList * next_list;
   gint need_resize = FALSE;
+  GtkWidget *tab_label;
 
   gboolean destroying;
 
   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
   destroying = GTK_OBJECT_FLAGS (notebook) & GTK_IN_DESTRUCTION;
   
-  next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
+  next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
   if (!next_list)
-    next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
+    next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
+
+  notebook->children = g_list_remove_link (notebook->children, list);
 
   if (notebook->cur_page == list->data)
     { 
       notebook->cur_page = NULL;
       if (next_list && !destroying)
-       gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
+       gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
     }
 
   if (priv->detached_tab == list->data)
@@ -4256,8 +4359,16 @@ gtk_notebook_real_remove (GtkNotebook *notebook,
 
   gtk_widget_unparent (page->child);
 
-  gtk_notebook_remove_tab_label (notebook, page);
-  
+  tab_label = page->tab_label;
+  if (tab_label)
+    {
+      g_object_ref (tab_label);
+      gtk_notebook_remove_tab_label (notebook, page);
+      if (destroying)
+        gtk_widget_destroy (tab_label);
+      g_object_unref (tab_label);
+    } 
+
   if (notebook->menu)
     {
       gtk_container_remove (GTK_CONTAINER (notebook->menu), 
@@ -4267,7 +4378,6 @@ gtk_notebook_real_remove (GtkNotebook *notebook,
   if (!page->default_menu)
     g_object_unref (page->menu_label);
   
-  notebook->children = g_list_remove_link (notebook->children, list);
   g_list_free (list);
 
   if (page->last_focus_child)
@@ -4276,7 +4386,7 @@ gtk_notebook_real_remove (GtkNotebook *notebook,
       page->last_focus_child = NULL;
     }
   
-  g_free (page);
+  g_slice_free (GtkNotebookPage, page);
 
   gtk_notebook_update_labels (notebook);
   if (need_resize)
@@ -4291,6 +4401,9 @@ gtk_notebook_update_labels (GtkNotebook *notebook)
   gchar string[32];
   gint page_num = 1;
 
+  if (!notebook->show_tabs && !notebook->menu)
+    return;
+
   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
        list;
        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
@@ -4320,9 +4433,9 @@ gtk_notebook_update_labels (GtkNotebook *notebook)
        }
       if (notebook->menu && page->default_menu)
        {
-         if (page->tab_label && GTK_IS_LABEL (page->tab_label))
+         if (GTK_IS_LABEL (page->tab_label))
            gtk_label_set_text (GTK_LABEL (page->menu_label),
-                          GTK_LABEL (page->tab_label)->label);
+                                GTK_LABEL (page->tab_label)->label);
          else
            gtk_label_set_text (GTK_LABEL (page->menu_label), string);
        }
@@ -4336,9 +4449,6 @@ gtk_notebook_real_page_position (GtkNotebook *notebook,
   GList *work;
   gint count_start;
 
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
-  g_return_val_if_fail (list != NULL, -1);
-
   for (work = notebook->children, count_start = 0;
        work && work != list; work = work->next)
     if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
@@ -4363,8 +4473,6 @@ gtk_notebook_search_page (GtkNotebook *notebook,
   GList *old_list = NULL;
   gint flag = 0;
 
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
-
   switch (direction)
     {
     case STEP_PREV:
@@ -4443,9 +4551,6 @@ gtk_notebook_paint (GtkWidget    *widget,
   gboolean is_rtl;
   gint tab_pos;
    
-  g_return_if_fail (GTK_IS_NOTEBOOK (widget));
-  g_return_if_fail (area != NULL);
-
   if (!GTK_WIDGET_DRAWABLE (widget))
     return;
 
@@ -4576,10 +4681,6 @@ gtk_notebook_draw_tab (GtkNotebook     *notebook,
   GdkWindow *window;
   GtkWidget *widget;
   
-  g_return_if_fail (notebook != NULL);
-  g_return_if_fail (page != NULL);
-  g_return_if_fail (area != NULL);
-
   if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
       !GTK_WIDGET_MAPPED (page->tab_label) ||
       (page->allocation.width == 0) || (page->allocation.height == 0))
@@ -4663,7 +4764,7 @@ gtk_notebook_draw_arrow (GtkNotebook      *notebook,
 
       if (notebook->focus_tab &&
          !gtk_notebook_search_page (notebook, notebook->focus_tab,
-                                     left? STEP_PREV : STEP_NEXT, TRUE))
+                                    left ? STEP_PREV : STEP_NEXT, TRUE))
        {
          shadow_type = GTK_SHADOW_ETCHED_IN;
          state_type = GTK_STATE_INSENSITIVE;
@@ -5664,9 +5765,6 @@ gtk_notebook_real_switch_page (GtkNotebook     *notebook,
                               GtkNotebookPage *page,
                               guint            page_num)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-  g_return_if_fail (page != NULL);
-
   if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
     return;
 
@@ -5710,17 +5808,14 @@ gtk_notebook_real_switch_page (GtkNotebook     *notebook,
  */
 static void
 gtk_notebook_switch_page (GtkNotebook     *notebook,
-                         GtkNotebookPage *page,
-                         gint             page_num)
+                         GtkNotebookPage *page)
 { 
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-  g_return_if_fail (page != NULL);
+  guint page_num;
+
   if (notebook->cur_page == page)
     return;
 
-  if (page_num < 0)
-    page_num = g_list_index (notebook->children, page);
+  page_num = g_list_index (notebook->children, page);
 
   g_signal_emit (notebook,
                 notebook_signals[SWITCH_PAGE],
@@ -5737,13 +5832,11 @@ gtk_notebook_page_select (GtkNotebook *notebook,
   GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
   gint tab_pos = get_effective_tab_pos (notebook);
 
-  g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
-
   if (!notebook->focus_tab)
     return FALSE;
 
   page = notebook->focus_tab->data;
-  gtk_notebook_switch_page (notebook, page, -1);
+  gtk_notebook_switch_page (notebook, page);
 
   if (move_focus)
     {
@@ -5776,8 +5869,6 @@ gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
   GList *old_child;
   GtkNotebookPage *page;
 
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-
   if (notebook->focus_tab == new_child)
     return;
 
@@ -5796,8 +5887,7 @@ gtk_notebook_switch_focus_tab (GtkNotebook *notebook,
   else
     gtk_notebook_pages_allocate (notebook);
 
-  gtk_notebook_switch_page (notebook, page,
-                           g_list_index (notebook->children, page));
+  gtk_notebook_switch_page (notebook, page);
 }
 
 static void
@@ -5808,9 +5898,6 @@ gtk_notebook_menu_switch_page (GtkWidget       *widget,
   GList *children;
   guint page_num;
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (page != NULL);
-
   notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
                           (GTK_MENU (widget->parent)));
 
@@ -5848,7 +5935,7 @@ gtk_notebook_menu_item_create (GtkNotebook *notebook,
   page = list->data;
   if (page->default_menu)
     {
-      if (page->tab_label && GTK_IS_LABEL (page->tab_label))
+      if (GTK_IS_LABEL (page->tab_label))
        page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
       else
        page->menu_label = gtk_label_new ("");
@@ -5880,8 +5967,6 @@ gtk_notebook_menu_detacher (GtkWidget *widget,
 {
   GtkNotebook *notebook;
 
-  g_return_if_fail (GTK_IS_NOTEBOOK (widget));
-
   notebook = GTK_NOTEBOOK (widget);
   g_return_if_fail (notebook->menu == (GtkWidget*) menu);
 
@@ -5899,8 +5984,6 @@ static void
 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
                                            gboolean     homogeneous)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-
   if (homogeneous == notebook->homogeneous)
     return;
 
@@ -5914,8 +5997,6 @@ static void
 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
                                      guint        border_width)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-
   notebook->tab_hborder = border_width;
   notebook->tab_vborder = border_width;
 
@@ -5932,8 +6013,6 @@ static void
 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
                                       guint        tab_hborder)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-
   if (notebook->tab_hborder == tab_hborder)
     return;
 
@@ -5949,8 +6028,6 @@ static void
 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
                                       guint        tab_vborder)
 {
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-
   if (notebook->tab_vborder == tab_vborder)
     return;
 
@@ -6136,7 +6213,7 @@ gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
       GtkNotebookPage *page = list->data;
 
       gtk_widget_grab_focus (GTK_WIDGET (notebook));   /* Do this first to avoid focusing new page */
-      gtk_notebook_switch_page (notebook, page,  -1);
+      gtk_notebook_switch_page (notebook, page);
       focus_tabs_in (notebook);
     }
 
@@ -6242,7 +6319,7 @@ gtk_notebook_get_current_page (GtkNotebook *notebook)
 /**
  * gtk_notebook_get_nth_page:
  * @notebook: a #GtkNotebook
- * @page_num: the index of a page in the noteobok, or -1
+ * @page_num: the index of a page in the notebook, or -1
  *            to get the last page.
  * 
  * Returns the child widget contained in page number @page_num.
@@ -6350,15 +6427,12 @@ gtk_notebook_set_current_page (GtkNotebook *notebook,
 
   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
 
-  if (page_num >= 0)
-    list = g_list_nth (notebook->children, page_num);
-  else
-    list = g_list_last (notebook->children);
-
-  page_num = g_list_index (notebook->children, list);
+  if (page_num < 0)
+    page_num = g_list_length (notebook->children) - 1;
 
+  list = g_list_nth (notebook->children, page_num);
   if (list)
-    gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
+    gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
 }
 
 /**
@@ -6383,7 +6457,7 @@ gtk_notebook_next_page (GtkNotebook *notebook)
   if (!list)
     return;
 
-  gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
+  gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
 }
 
 /**
@@ -6408,7 +6482,7 @@ gtk_notebook_prev_page (GtkNotebook *notebook)
   if (!list)
     return;
 
-  gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
+  gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
 }
 
 /* Public GtkNotebook/Tab Style Functions
@@ -6897,10 +6971,10 @@ gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
  * Retrieves the text of the tab label for the page containing
  *    @child.
  *
- * Returns value: the text of the tab label, or %NULL if the
- *                tab label widget is not a #GtkLabel. The
- *                string is owned by the widget and must not
- *                be freed.
+ * Return value: the text of the tab label, or %NULL if the
+ *               tab label widget is not a #GtkLabel. The
+ *               string is owned by the widget and must not
+ *               be freed.
  **/
 G_CONST_RETURN gchar *
 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
@@ -6913,7 +6987,7 @@ gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
 
   tab_label = gtk_notebook_get_tab_label (notebook, child);
 
-  if (tab_label && GTK_IS_LABEL (tab_label))
+  if (GTK_IS_LABEL (tab_label))
     return gtk_label_get_text (GTK_LABEL (tab_label));
   else
     return NULL;
@@ -7031,11 +7105,11 @@ gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
  * Retrieves the text of the menu label for the page containing
  *    @child.
  *
- * Returns value: the text of the tab label, or %NULL if the
- *                widget does not have a menu label other than
- *                the default menu label, or the menu label widget
- *                is not a #GtkLabel. The string is owned by
- *                the widget and must not be freed.
+ * Return value: the text of the tab label, or %NULL if the
+ *               widget does not have a menu label other than
+ *               the default menu label, or the menu label widget
+ *               is not a #GtkLabel. The string is owned by
+ *               the widget and must not be freed.
  **/
 G_CONST_RETURN gchar *
 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
@@ -7048,7 +7122,7 @@ gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
  
   menu_label = gtk_notebook_get_menu_label (notebook, child);
 
-  if (menu_label && GTK_IS_LABEL (menu_label))
+  if (GTK_IS_LABEL (menu_label))
     return gtk_label_get_text (GTK_LABEL (menu_label));
   else
     return NULL;
@@ -7264,10 +7338,36 @@ gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc  func,
  * not be able to exchange tabs with any other notebook.
  * 
  * Since: 2.10
- **/
+ * Deprecated: 2.12: use gtk_notebook_set_group() instead.
+ */
 void
 gtk_notebook_set_group_id (GtkNotebook *notebook,
                           gint         group_id)
+{
+  gpointer group;
+
+  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
+
+  /* add 1 to get rid of the -1/NULL difference */
+  group = GINT_TO_POINTER (group_id + 1);
+  gtk_notebook_set_group (notebook, group);
+}
+
+/**
+ * gtk_notebook_set_group:
+ * @notebook: a #GtkNotebook
+ * @group: a pointer to identify the notebook group, or %NULL to unset it
+ *
+ * Sets a group identificator pointer for @notebook, notebooks sharing
+ * the same group identificator pointer will be able to exchange tabs
+ * via drag and drop. A notebook with a %NULL group identificator will
+ * not be able to exchange tabs with any other notebook.
+ * 
+ * Since: 2.12
+ */
+void
+gtk_notebook_set_group (GtkNotebook *notebook,
+                       gpointer     group)
 {
   GtkNotebookPrivate *priv;
 
@@ -7275,10 +7375,11 @@ gtk_notebook_set_group_id (GtkNotebook *notebook,
 
   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
 
-  if (priv->group_id != group_id)
+  if (priv->group != group)
     {
-      priv->group_id = group_id;
+      priv->group = group;
       g_object_notify (G_OBJECT (notebook), "group-id");
+      g_object_notify (G_OBJECT (notebook), "group");
     }
 }
 
@@ -7291,7 +7392,8 @@ gtk_notebook_set_group_id (GtkNotebook *notebook,
  * Return Value: the group identificator, or -1 if none is set.
  *
  * Since: 2.10
- **/
+ * Deprecated: 2.12: use gtk_notebook_get_group() instead.
+ */
 gint
 gtk_notebook_get_group_id (GtkNotebook *notebook)
 {
@@ -7300,7 +7402,30 @@ gtk_notebook_get_group_id (GtkNotebook *notebook)
   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
 
   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
-  return priv->group_id;
+
+  /* substract 1 to get rid of the -1/NULL difference */
+  return GPOINTER_TO_INT (priv->group) - 1;
+}
+
+/**
+ * gtk_notebook_get_group:
+ * @notebook: a #GtkNotebook
+ * 
+ * Gets the current group identificator pointer for @notebook.
+ * 
+ * Return Value: the group identificator, or %NULL if none is set.
+ *
+ * Since: 2.12
+ **/
+gpointer
+gtk_notebook_get_group (GtkNotebook *notebook)
+{
+  GtkNotebookPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
+
+  priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+  return priv->group;
 }
 
 /**
@@ -7407,8 +7532,7 @@ gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
  * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
  * will fill the selection with a GtkWidget** pointing to the child
  * widget that corresponds to the dropped tab.
- *
- * <informalexample><programlisting>
+ * |[
  *  static void
  *  on_drop_zone_drag_data_received (GtkWidget        *widget,
  *                                   GdkDragContext   *context,
@@ -7428,7 +7552,7 @@ gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
  *    process_widget (*child);
  *    gtk_container_remove (GTK_CONTAINER (notebook), *child);
  *  }
- * </programlisting></informalexample>
+ * ]|
  *
  * If you want a notebook to accept drags from other widgets,
  * you will have to set your own DnD code to do it.