#include "gtkmarshalers.h"
#include "gtkbindings.h"
#include "gtkprivate.h"
-#include "gtkalias.h"
#include "gtkdnd.h"
+#include "gtkalias.h"
-
-#define ARROW_SIZE 12
-#define ARROW_SPACING 0
#define SCROLL_DELAY_FACTOR 5
#define SCROLL_THRESHOLD 12
#define DND_THRESHOLD_MULTIPLIER 4
+#define FRAMES_PER_SECOND 45
+#define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
enum {
SWITCH_PAGE,
#define PAGE_TOP_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y)
#define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
#define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
+#define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (((GtkNotebookPage *) (_page_))->tab_label->parent == ((GtkWidget *) (_notebook_)))
struct _GtkNotebookPage
{
gint mouse_y;
gint pressed_button;
guint dnd_timer;
+ guint switch_tab_timer;
+
+ gint drag_begin_x;
+ gint drag_begin_y;
+
+ gint drag_offset_x;
+ gint drag_offset_y;
+
+ GtkWidget *dnd_window;
GtkTargetList *source_targets;
- gboolean during_detach;
- gboolean has_scrolled;
+ GtkNotebookDragOperation operation;
+ GdkWindow *drag_window;
+ gint drag_window_x;
+ gint drag_window_y;
+ GtkNotebookPage *detached_tab;
+
+ guint32 timestamp;
+
+ guint during_reorder : 1;
+ guint during_detach : 1;
+ guint has_scrolled : 1;
};
-static const GtkTargetEntry notebook_targets[] = {
+static const GtkTargetEntry notebook_source_targets [] = {
{ "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
{ "application/x-rootwindow-drop", 0, 1 }
};
+static const GtkTargetEntry notebook_dest_targets[] = {
+ { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 }
+};
+
#ifdef G_DISABLE_CHECKS
#define CHECK_FIND_CHILD(notebook, child) \
gtk_notebook_find_child (notebook, child, G_STRLOC)
#endif
/*** GtkNotebook Methods ***/
-static void gtk_notebook_class_init (GtkNotebookClass *klass);
-static void gtk_notebook_init (GtkNotebook *notebook);
-
static gboolean gtk_notebook_select_page (GtkNotebook *notebook,
gboolean move_focus);
static gboolean gtk_notebook_focus_tab (GtkNotebook *notebook,
static gint gtk_notebook_button_release (GtkWidget *widget,
GdkEventButton *event);
static gboolean gtk_notebook_popup_menu (GtkWidget *widget);
-static gint gtk_notebook_enter_notify (GtkWidget *widget,
- GdkEventCrossing *event);
static gint gtk_notebook_leave_notify (GtkWidget *widget,
GdkEventCrossing *event);
static gint gtk_notebook_motion_notify (GtkWidget *widget,
/*** Drag and drop Methods ***/
static void gtk_notebook_drag_begin (GtkWidget *widget,
GdkDragContext *context);
+static void gtk_notebook_drag_end (GtkWidget *widget,
+ GdkDragContext *context);
static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
guint time);
+static void gtk_notebook_drag_leave (GtkWidget *widget,
+ GdkDragContext *context,
+ guint time);
static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
GdkDragContext *context,
gint x,
GList *list);
static void gtk_notebook_update_labels (GtkNotebook *notebook);
static gint gtk_notebook_timer (GtkNotebook *notebook);
+static void gtk_notebook_set_scroll_timer (GtkNotebook *notebook);
static gint gtk_notebook_page_compare (gconstpointer a,
gconstpointer b);
static GList* gtk_notebook_find_child (GtkNotebook *notebook,
GtkNotebookArrow arrow);
/*** GtkNotebook Size Allocate Functions ***/
-static void gtk_notebook_pages_allocate (GtkNotebook *notebook,
- GtkNotebookDragOperation operation);
+static void gtk_notebook_pages_allocate (GtkNotebook *notebook);
static void gtk_notebook_page_allocate (GtkNotebook *notebook,
- GtkNotebookPage *page,
- GtkAllocation *allocation);
+ GtkNotebookPage *page);
static void gtk_notebook_calc_tabs (GtkNotebook *notebook,
GList *start,
GList **end,
static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
static gpointer window_creation_hook_data;
+static GDestroyNotify window_creation_hook_destroy = NULL;
-static GtkContainerClass *parent_class = NULL;
static guint notebook_signals[LAST_SIGNAL] = { 0 };
-GType
-gtk_notebook_get_type (void)
-{
- static GType notebook_type = 0;
-
- if (!notebook_type)
- {
- static const GTypeInfo notebook_info =
- {
- sizeof (GtkNotebookClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) gtk_notebook_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GtkNotebook),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gtk_notebook_init,
- };
-
- notebook_type = g_type_register_static (GTK_TYPE_CONTAINER, I_("GtkNotebook"),
- ¬ebook_info, 0);
- }
-
- return notebook_type;
-}
+G_DEFINE_TYPE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER)
static void
add_tab_bindings (GtkBindingSet *binding_set,
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
GtkBindingSet *binding_set;
- parent_class = g_type_class_peek_parent (class);
-
gobject_class->set_property = gtk_notebook_set_property;
gobject_class->get_property = gtk_notebook_get_property;
object_class->destroy = gtk_notebook_destroy;
widget_class->button_press_event = gtk_notebook_button_press;
widget_class->button_release_event = gtk_notebook_button_release;
widget_class->popup_menu = gtk_notebook_popup_menu;
- widget_class->enter_notify_event = gtk_notebook_enter_notify;
widget_class->leave_notify_event = gtk_notebook_leave_notify;
widget_class->motion_notify_event = gtk_notebook_motion_notify;
widget_class->grab_notify = gtk_notebook_grab_notify;
widget_class->focus = gtk_notebook_focus;
widget_class->style_set = gtk_notebook_style_set;
widget_class->drag_begin = gtk_notebook_drag_begin;
+ widget_class->drag_end = gtk_notebook_drag_end;
widget_class->drag_motion = gtk_notebook_drag_motion;
+ widget_class->drag_leave = gtk_notebook_drag_leave;
widget_class->drag_drop = gtk_notebook_drag_drop;
widget_class->drag_data_get = gtk_notebook_drag_data_get;
widget_class->drag_data_received = gtk_notebook_drag_data_received;
1,
GTK_PARAM_READABLE));
+ /**
+ * GtkNotebook:arrow-spacing:
+ *
+ * The "arrow-size" property defines the spacing between the scroll
+ * arrows and the tabs.
+ *
+ * Since: 2.10
+ */
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_int ("arrow-spacing",
+ _("Arrow spacing"),
+ _("Scroll arrow spacing"),
+ 0,
+ G_MAXINT,
+ 0,
+ GTK_PARAM_READABLE));
+
notebook_signals[SWITCH_PAGE] =
g_signal_new (I_("switch_page"),
G_TYPE_FROM_CLASS (gobject_class),
* @page_num: the @child page number
*
* the ::page-removed signal is emitted in the notebook
- * right before a page is removed from the notebook.
+ * right after a page is removed from the notebook.
*
* Since: 2.10
**/
GTK_TYPE_WIDGET,
G_TYPE_UINT);
/**
- * GtkNotebook::page-attached:
+ * GtkNotebook::page-added:
* @notebook: the #GtkNotebook
* @child: the child #GtkWidget affected
* @page_num: the new page number for @child
priv->group_id = -1;
priv->pressed_button = -1;
priv->dnd_timer = 0;
- priv->source_targets = gtk_target_list_new (notebook_targets,
- G_N_ELEMENTS (notebook_targets));
+ priv->switch_tab_timer = 0;
+ priv->source_targets = gtk_target_list_new (notebook_source_targets,
+ G_N_ELEMENTS (notebook_source_targets));
+ priv->operation = DRAG_OPERATION_NONE;
+ priv->detached_tab = NULL;
+ priv->during_detach = FALSE;
+ priv->has_scrolled = FALSE;
gtk_drag_dest_set (GTK_WIDGET (notebook),
GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
- notebook_targets, G_N_ELEMENTS (notebook_targets),
+ notebook_dest_targets, G_N_ELEMENTS (notebook_dest_targets),
GDK_ACTION_MOVE);
+
+ gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
}
static gboolean
while (offset != 0)
{
- current = gtk_notebook_search_page (notebook, current, offset < 0 ? STEP_PREV : STEP_NEXT, TRUE);
+ current = gtk_notebook_search_page (notebook, current,
+ offset < 0 ? STEP_PREV : STEP_NEXT,
+ TRUE);
+
+ if (!current)
+ {
+ gboolean wrap_around;
+
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
+ "gtk-keynav-wrap-around", &wrap_around,
+ NULL);
+
+ if (wrap_around)
+ current = gtk_notebook_search_page (notebook, NULL,
+ offset < 0 ? STEP_PREV : STEP_NEXT,
+ TRUE);
+ else
+ break;
+ }
+
offset += offset < 0 ? 1 : -1;
}
if (current)
gtk_notebook_switch_page (notebook, current->data, -1);
else
- gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
+ gtk_widget_error_bell (GTK_WIDGET (notebook));
}
static GtkDirectionType
return notebook->tab_pos;
}
+static gint
+get_tab_gap_pos (GtkNotebook *notebook)
+{
+ gint tab_pos = get_effective_tab_pos (notebook);
+ gint gap_side = GTK_POS_BOTTOM;
+
+ switch (tab_pos)
+ {
+ case GTK_POS_TOP:
+ gap_side = GTK_POS_BOTTOM;
+ break;
+ case GTK_POS_BOTTOM:
+ gap_side = GTK_POS_TOP;
+ break;
+ case GTK_POS_LEFT:
+ gap_side = GTK_POS_RIGHT;
+ break;
+ case GTK_POS_RIGHT:
+ gap_side = GTK_POS_LEFT;
+ break;
+ }
+
+ return gap_side;
+}
+
static void
gtk_notebook_move_focus_out (GtkNotebook *notebook,
GtkDirectionType direction_type)
{
GList *elem;
+ if (position == tab)
+ return g_list_position (notebook->children, tab);
+
/* check that we aren't inserting the tab in the
* same relative position, taking packing into account */
elem = (position) ? position->prev : g_list_last (notebook->children);
- while (elem && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
+ while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
elem = elem->prev;
if (elem == tab)
GList *last, *child;
gint page_num;
+ if (!gtk_widget_is_focus (GTK_WIDGET (notebook)))
+ return;
+
if (!notebook->cur_page ||
!notebook->cur_page->reorderable)
return;
else
page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
- gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
+ gtk_notebook_pages_allocate (notebook);
g_signal_emit (notebook,
notebook_signals[PAGE_REORDERED],
gtk_target_list_unref (priv->source_targets);
priv->source_targets = NULL;
}
-
- GTK_OBJECT_CLASS (parent_class)->destroy (object);
+
+ if (priv->switch_tab_timer)
+ {
+ g_source_remove (priv->switch_tab_timer);
+ priv->switch_tab_timer = 0;
+ }
+
+ GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
}
static void
* gtk_notebook_button_press
* gtk_notebook_button_release
* gtk_notebook_popup_menu
- * gtk_notebook_enter_notify
* gtk_notebook_leave_notify
* gtk_notebook_motion_notify
* gtk_notebook_focus_in
* gtk_notebook_draw_focus
* gtk_notebook_style_set
* gtk_notebook_drag_begin
+ * gtk_notebook_drag_end
* gtk_notebook_drag_motion
* gtk_notebook_drag_drop
* gtk_notebook_drag_data_get
gtk_widget_map (notebook->cur_page->child);
if (notebook->scrollable)
- gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
+ gtk_notebook_pages_allocate (notebook);
else
{
children = notebook->children;
gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
- GTK_WIDGET_CLASS (parent_class)->unmap (widget);
+ GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
}
static void
attributes.event_mask = gtk_widget_get_events (widget);
attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
- GDK_BUTTON1_MOTION_MASK |
+ GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
GDK_SCROLL_MASK);
attributes_mask = GDK_WA_X | GDK_WA_Y;
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);
gdk_window_set_user_data (notebook->event_window, NULL);
gdk_window_destroy (notebook->event_window);
notebook->event_window = NULL;
- if (GTK_WIDGET_CLASS (parent_class)->unrealize)
- (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+ if (priv->drag_window)
+ {
+ gdk_window_set_user_data (priv->drag_window, NULL);
+ gdk_window_destroy (priv->drag_window);
+ priv->drag_window = NULL;
+ }
+
+ if (GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize)
+ (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize) (widget);
}
static void
gint focus_width;
gint tab_overlap;
gint tab_curvature;
+ gint arrow_spacing;
+ gint scroll_arrow_hlength;
+ gint scroll_arrow_vlength;
gtk_widget_style_get (widget,
"focus-line-width", &focus_width,
"tab-overlap", &tab_overlap,
"tab-curvature", &tab_curvature,
+ "arrow-spacing", &arrow_spacing,
+ "scroll-arrow-hlength", &scroll_arrow_hlength,
+ "scroll-arrow-vlength", &scroll_arrow_vlength,
NULL);
-
+
widget->requisition.width = 0;
widget->requisition.height = 0;
if (notebook->scrollable && vis_pages > 1 &&
widget->requisition.width < tab_width)
- tab_height = MAX (tab_height, ARROW_SIZE);
+ tab_height = MAX (tab_height, scroll_arrow_hlength);
padding = 2 * (tab_curvature + focus_width +
notebook->tab_hborder) - tab_overlap;
if (notebook->scrollable && vis_pages > 1 &&
widget->requisition.width < tab_width)
- tab_width = tab_max + 2 * (ARROW_SIZE + ARROW_SPACING);
+ tab_width = tab_max + 2 * (scroll_arrow_hlength + arrow_spacing);
if (notebook->homogeneous && !notebook->scrollable)
widget->requisition.width = MAX (widget->requisition.width,
if (notebook->scrollable && vis_pages > 1 &&
widget->requisition.height < tab_height)
- tab_width = MAX (tab_width, ARROW_SPACING + 2 * ARROW_SIZE);
+ tab_width = MAX (tab_width,
+ arrow_spacing + 2 * scroll_arrow_vlength);
padding = 2 * (tab_curvature + focus_width +
notebook->tab_vborder) - tab_overlap;
if (notebook->scrollable && vis_pages > 1 &&
widget->requisition.height < tab_height)
- tab_height = tab_max + ARROW_SIZE + ARROW_SPACING;
+ tab_height = tab_max + scroll_arrow_vlength + arrow_spacing;
widget->requisition.width += tab_width;
GtkAllocation *allocation)
{
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
- gint vis_pages = 0;
gint tab_pos = get_effective_tab_pos (notebook);
widget->allocation = *allocation;
children = children->next;
if (GTK_WIDGET_VISIBLE (page->child))
- {
- gtk_widget_size_allocate (page->child, &child_allocation);
- vis_pages++;
- }
+ gtk_widget_size_allocate (page->child, &child_allocation);
}
- gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
+ gtk_notebook_pages_allocate (notebook);
}
}
GdkEventExpose *event)
{
GtkNotebook *notebook;
+ GtkNotebookPrivate *priv;
GdkRectangle child_area;
-
+
g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
- if (GTK_WIDGET_DRAWABLE (widget))
+ notebook = GTK_NOTEBOOK (widget);
+ priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
+
+ if (event->window == priv->drag_window)
{
- notebook = GTK_NOTEBOOK (widget);
+ GdkRectangle area = { 0, };
+ gdk_drawable_get_size (priv->drag_window,
+ &area.width, &area.height);
+ gtk_notebook_draw_tab (notebook,
+ notebook->cur_page,
+ &area);
+ }
+ else if (GTK_WIDGET_DRAWABLE (widget))
+ {
gtk_notebook_paint (widget, &event->area);
if (notebook->show_tabs)
{
if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
{
- rectangle->width = ARROW_SIZE;
- rectangle->height = ARROW_SIZE;
+ gint scroll_arrow_hlength;
+ gint scroll_arrow_vlength;
+
+ gtk_widget_style_get (GTK_WIDGET (notebook),
+ "scroll-arrow-hlength", &scroll_arrow_hlength,
+ "scroll-arrow-vlength", &scroll_arrow_vlength,
+ NULL);
switch (notebook->tab_pos)
{
case GTK_POS_LEFT:
case GTK_POS_RIGHT:
+ rectangle->width = scroll_arrow_vlength;
+ rectangle->height = scroll_arrow_vlength;
+
if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
(!before && (notebook->has_after_previous != notebook->has_after_next)))
rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
if (!before)
rectangle->y += event_window_pos.height - rectangle->height;
break;
+
case GTK_POS_TOP:
case GTK_POS_BOTTOM:
+ rectangle->width = scroll_arrow_hlength;
+ rectangle->height = scroll_arrow_hlength;
+
if (before)
{
if (left || !notebook->has_before_previous)
x0 = x - arrow_rect.x;
y0 = y - arrow_rect.y;
-
+
if (y0 >= 0 && y0 < arrow_rect.height &&
x0 >= 0 && x0 < arrow_rect.width)
return arrow[i];
is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
left = (ARROW_IS_LEFT (arrow) && !is_rtl) ||
(!ARROW_IS_LEFT (arrow) && is_rtl);
-
+
if (!notebook->focus_tab ||
gtk_notebook_search_page (notebook, notebook->focus_tab,
left ? STEP_PREV : STEP_NEXT,
static gboolean
gtk_notebook_arrow_button_press (GtkNotebook *notebook,
GtkNotebookArrow arrow,
- GdkEventButton *event)
+ gint button)
{
GtkWidget *widget = GTK_WIDGET (notebook);
gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
if (!GTK_WIDGET_HAS_FOCUS (widget))
gtk_widget_grab_focus (widget);
- notebook->button = event->button;
+ notebook->button = button;
notebook->click_child = arrow;
-
- if (event->button == 1)
+
+ if (button == 1)
{
gtk_notebook_do_arrow (notebook, arrow);
-
- if (!notebook->timer)
- {
- GtkSettings *settings = gtk_widget_get_settings (widget);
- guint timeout;
-
- g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
-
- notebook->timer = g_timeout_add (timeout,
- (GSourceFunc) gtk_notebook_timer,
- (gpointer) notebook);
- notebook->need_timer = TRUE;
- }
+ gtk_notebook_set_scroll_timer (notebook);
}
- else if (event->button == 2)
+ else if (button == 2)
gtk_notebook_page_select (notebook, TRUE);
- else if (event->button == 3)
+ else if (button == 3)
gtk_notebook_switch_focus_tab (notebook,
gtk_notebook_search_page (notebook,
NULL,
while (window && window != widget->window)
{
gint window_x, window_y;
-
+
gdk_window_get_position (window, &window_x, &window_y);
tx += window_x;
ty += window_y;
return TRUE;
}
+static GList*
+get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
+{
+ GtkNotebookPage *page;
+ GList *children = notebook->children;
+
+ while (children)
+ {
+ page = children->data;
+
+ if (GTK_WIDGET_VISIBLE (page->child) &&
+ page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
+ (x >= page->allocation.x) &&
+ (y >= page->allocation.y) &&
+ (x <= (page->allocation.x + page->allocation.width)) &&
+ (y <= (page->allocation.y + page->allocation.height)))
+ return children;
+
+ children = children->next;
+ }
+
+ return NULL;
+}
+
static gboolean
gtk_notebook_button_press (GtkWidget *widget,
GdkEventButton *event)
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
GtkNotebookPage *page;
- GList *children;
+ GList *tab;
GtkNotebookArrow arrow;
- gint num;
gint x, y;
if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
arrow = gtk_notebook_get_arrow (notebook, x, y);
if (arrow)
- return gtk_notebook_arrow_button_press (notebook, arrow, event);
+ return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
if (event->button == 3 && notebook->menu)
{
return FALSE;
notebook->button = event->button;
- num = 0;
- children = notebook->children;
- while (children)
+ if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
{
- page = children->data;
-
- if (GTK_WIDGET_VISIBLE (page->child) &&
- page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
- (x >= page->allocation.x) &&
- (y >= page->allocation.y) &&
- (x <= (page->allocation.x + page->allocation.width)) &&
- (y <= (page->allocation.y + page->allocation.height)))
- {
- gboolean page_changed = page != notebook->cur_page;
- gboolean was_focus = gtk_widget_is_focus (widget);
-
- gtk_notebook_switch_focus_tab (notebook, children);
- gtk_widget_grab_focus (widget);
-
- if (page_changed && !was_focus)
- gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
-
- /* save press to possibly begin a drag */
- if (page->reorderable || page->detachable)
- {
- priv->during_detach = FALSE;
- priv->pressed_button = event->button;
- gtk_grab_add (widget);
- }
+ gboolean page_changed, was_focus;
- break;
+ page = tab->data;
+ page_changed = page != notebook->cur_page;
+ was_focus = gtk_widget_is_focus (widget);
+
+ gtk_notebook_switch_focus_tab (notebook, tab);
+ gtk_widget_grab_focus (widget);
+
+ if (page_changed && !was_focus)
+ gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
+
+ /* save press to possibly begin a drag */
+ if (page->reorderable || page->detachable)
+ {
+ priv->during_detach = FALSE;
+ priv->during_reorder = FALSE;
+ priv->pressed_button = event->button;
+
+ gdk_window_get_pointer (widget->window,
+ &priv->mouse_x,
+ &priv->mouse_y,
+ NULL);
+
+ priv->drag_begin_x = priv->mouse_x;
+ priv->drag_begin_y = priv->mouse_y;
+ priv->drag_offset_x = priv->drag_begin_x - page->allocation.x;
+ priv->drag_offset_y = priv->drag_begin_y - page->allocation.y;
}
- children = children->next;
- num++;
}
return TRUE;
static GList*
get_drop_position (GtkNotebook *notebook,
- guint pack,
- gint x,
- gint y)
+ guint pack)
{
- GList *children;
+ GtkNotebookPrivate *priv;
+ GList *children, *last_child;
GtkNotebookPage *page;
gboolean is_rtl;
-
+ gint x, y;
+
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+ x = priv->mouse_x;
+ y = priv->mouse_y;
+
is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
children = notebook->children;
+ last_child = NULL;
while (children)
{
page = children->data;
- if (GTK_WIDGET_VISIBLE (page->child) &&
+ if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
+ GTK_WIDGET_VISIBLE (page->child) &&
page->tab_label &&
GTK_WIDGET_MAPPED (page->tab_label) &&
page->pack == pack)
break;
}
+
+ last_child = children->next;
}
children = children->next;
}
- return NULL;
+ return last_child;
}
-static gint
-gtk_notebook_button_release (GtkWidget *widget,
- GdkEventButton *event)
+static void
+show_drag_window (GtkNotebook *notebook,
+ GtkNotebookPrivate *priv,
+ GtkNotebookPage *page)
{
- GtkNotebook *notebook;
- GtkNotebookPrivate *priv;
- GList *element;
- gint old_page_num, page_num;
+ GtkWidget *widget = GTK_WIDGET (notebook);
- g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
+ if (!priv->drag_window)
+ {
+ GdkWindowAttr attributes;
+ guint attributes_mask;
+
+ attributes.x = page->allocation.x;
+ attributes.y = page->allocation.y;
+ attributes.width = page->allocation.width;
+ attributes.height = page->allocation.height;
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+ priv->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget),
+ &attributes,
+ attributes_mask);
+ gdk_window_set_user_data (priv->drag_window, widget);
+ }
- if (event->type != GDK_BUTTON_RELEASE)
- return FALSE;
+ g_object_ref (page->tab_label);
+ gtk_widget_unparent (page->tab_label);
+ gtk_widget_set_parent_window (page->tab_label, priv->drag_window);
+ gtk_widget_set_parent (page->tab_label, widget);
+ g_object_unref (page->tab_label);
- notebook = GTK_NOTEBOOK (widget);
- priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+ gdk_window_show (priv->drag_window);
- if (notebook->cur_page->reorderable &&
- event->button == priv->pressed_button)
+ /* the grab will dissapear when the window is hidden */
+ gdk_pointer_grab (priv->drag_window,
+ FALSE,
+ GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
+ NULL, NULL, GDK_CURRENT_TIME);
+}
+
+/* This function undoes the reparenting that happens both when drag_window
+ * is shown for reordering and when the DnD icon is shown for detaching
+ */
+static void
+hide_drag_window (GtkNotebook *notebook,
+ GtkNotebookPrivate *priv,
+ GtkNotebookPage *page)
+{
+ GtkWidget *widget = GTK_WIDGET (notebook);
+ GtkWidget *parent = page->tab_label->parent;
+
+ if (page->tab_label->window != widget->window ||
+ !NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
{
- gtk_grab_remove (widget);
- priv->pressed_button = -1;
+ g_object_ref (page->tab_label);
+
+ if (GTK_IS_WINDOW (parent))
+ {
+ /* parent widget is the drag window */
+ gtk_container_remove (GTK_CONTAINER (parent), page->tab_label);
+ }
+ 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);
+ }
- if (!priv->during_detach)
+ if (priv->drag_window &&
+ gdk_window_is_visible (priv->drag_window))
+ gdk_window_hide (priv->drag_window);
+}
+
+static void
+gtk_notebook_stop_reorder (GtkNotebook *notebook)
+{
+ GtkNotebookPrivate *priv;
+ GtkNotebookPage *page;
+
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+ page = notebook->cur_page;
+
+ if (!page)
+ return;
+
+ priv->pressed_button = -1;
+
+ if (page->reorderable || page->detachable)
+ {
+ if (priv->during_reorder)
{
- element = get_drop_position (notebook,
- notebook->cur_page->pack,
- PAGE_MIDDLE_X (notebook->cur_page),
- PAGE_MIDDLE_Y (notebook->cur_page));
+ gint old_page_num, page_num;
+ GList *element;
+
+ 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);
- if (priv->has_scrolled ||
- old_page_num != page_num)
+ if (priv->has_scrolled || old_page_num != page_num)
g_signal_emit (notebook,
notebook_signals[PAGE_REORDERED], 0,
- ((GtkNotebookPage *) notebook->focus_tab->data)->child,
- page_num);
+ page->child, page_num);
priv->has_scrolled = FALSE;
+ priv->during_reorder = FALSE;
}
- gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
+ hide_drag_window (notebook, priv, page);
+
+ priv->operation = DRAG_OPERATION_NONE;
+ gtk_notebook_pages_allocate (notebook);
if (priv->dnd_timer)
{
priv->dnd_timer = 0;
}
}
-
- if (event->button == notebook->button)
- {
- stop_scrolling (notebook);
-
- return TRUE;
- }
- else
- return FALSE;
}
static gint
-gtk_notebook_enter_notify (GtkWidget *widget,
- GdkEventCrossing *event)
+gtk_notebook_button_release (GtkWidget *widget,
+ GdkEventButton *event)
{
GtkNotebook *notebook;
- GtkNotebookArrow arrow;
- gint x, y;
+ GtkNotebookPrivate *priv;
+ GtkNotebookPage *page;
g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
- notebook = GTK_NOTEBOOK (widget);
-
- if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
+ if (event->type != GDK_BUTTON_RELEASE)
return FALSE;
- arrow = gtk_notebook_get_arrow (notebook, x, y);
+ notebook = GTK_NOTEBOOK (widget);
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+ page = notebook->cur_page;
- if (arrow != notebook->in_child)
- {
- notebook->in_child = arrow;
- gtk_notebook_redraw_arrows (notebook);
+ if (!priv->during_detach &&
+ page->reorderable &&
+ event->button == priv->pressed_button)
+ gtk_notebook_stop_reorder (notebook);
+ if (event->button == notebook->button)
+ {
+ stop_scrolling (notebook);
return TRUE;
}
-
- return TRUE;
+ else
+ return FALSE;
}
static gint
if (notebook->tab_pos == GTK_POS_TOP ||
notebook->tab_pos == GTK_POS_BOTTOM)
{
+ gint x;
+
is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+ x = priv->mouse_x - widget->allocation.x;
- if (priv->mouse_x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
+ if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
- else if (priv->mouse_x < SCROLL_THRESHOLD + container->border_width)
+ else if (x < SCROLL_THRESHOLD + container->border_width)
return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
else
return POINTER_BETWEEN;
}
else
{
- if (priv->mouse_y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
+ gint y;
+
+ y = priv->mouse_y - widget->allocation.y;
+ if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
return POINTER_AFTER;
- else if (priv->mouse_y < SCROLL_THRESHOLD + container->border_width)
+ else if (y < SCROLL_THRESHOLD + container->border_width)
return POINTER_BEFORE;
else
return POINTER_BETWEEN;
priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
pointer_position = get_pointer_position (notebook);
- element = get_drop_position (notebook,
- notebook->cur_page->pack,
- PAGE_MIDDLE_X (notebook->cur_page),
- PAGE_MIDDLE_Y (notebook->cur_page));
-
+ element = get_drop_position (notebook, notebook->cur_page->pack);
reorder_tab (notebook, element, notebook->focus_tab);
-
first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
(pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
TRUE);
if (first_tab)
{
notebook->first_tab = first_tab;
- gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_REORDER);
+ gtk_notebook_pages_allocate (notebook);
+
+ gdk_window_move_resize (priv->drag_window,
+ priv->drag_window_x,
+ priv->drag_window_y,
+ notebook->cur_page->allocation.width,
+ notebook->cur_page->allocation.height);
+ gdk_window_raise (priv->drag_window);
}
return TRUE;
gint current_y)
{
GtkWidget *widget;
- gint dnd_threshold, width, height;
+ gint dnd_threshold;
GdkRectangle rectangle = { 0, }; /* shut up gcc */
GtkSettings *settings;
settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
- gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &width, &height);
-
/* we want a large threshold */
dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
- rectangle.x = - dnd_threshold;
- rectangle.width = width + 2 * dnd_threshold;
- rectangle.y = - dnd_threshold;
- rectangle.height = height + 2 * dnd_threshold;
+ gdk_window_get_position (notebook->event_window, &rectangle.x, &rectangle.y);
+ gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &rectangle.width, &rectangle.height);
+
+ rectangle.x -= dnd_threshold;
+ rectangle.width += 2 * dnd_threshold;
+ rectangle.y -= dnd_threshold;
+ rectangle.height += 2 * dnd_threshold;
return (current_x < rectangle.x ||
current_x > rectangle.x + rectangle.width ||
{
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+ GtkNotebookPage *page;
+ GtkNotebookArrow arrow;
GtkNotebookPointerPosition pointer_position;
GtkSettings *settings;
- guint timeout;
- GList *element;
+ guint timeout;
- if (priv->pressed_button == -1)
- return FALSE;
+ page = notebook->cur_page;
- if (!notebook->cur_page)
+ if (!page)
return FALSE;
- priv->mouse_x = (gint) event->x;
- priv->mouse_y = (gint) event->y;
-
- if (notebook->cur_page->detachable &&
- check_threshold (notebook, priv->mouse_x, priv->mouse_y))
+ if (!(event->state & GDK_BUTTON1_MASK) &&
+ priv->pressed_button != -1)
{
- /* move the page to the current position */
- element = get_drop_position (notebook,
- notebook->cur_page->pack,
- PAGE_MIDDLE_X (notebook->cur_page),
- PAGE_MIDDLE_Y (notebook->cur_page));
- reorder_tab (notebook, element, notebook->focus_tab);
+ gtk_notebook_stop_reorder (notebook);
+ stop_scrolling (notebook);
+ }
+
+ if (event->time < priv->timestamp + MSECS_BETWEEN_UPDATES)
+ return FALSE;
+
+ priv->timestamp = event->time;
+ gdk_window_get_pointer (widget->window,
+ &priv->mouse_x,
+ &priv->mouse_y,
+ NULL);
+
+ arrow = gtk_notebook_get_arrow (notebook, priv->mouse_x, priv->mouse_y);
+ if (arrow != notebook->in_child)
+ {
+ notebook->in_child = arrow;
+ gtk_notebook_redraw_arrows (notebook);
+ }
+
+ if (priv->pressed_button == -1)
+ return FALSE;
+
+ if (page->detachable &&
+ check_threshold (notebook, priv->mouse_x, priv->mouse_y))
+ {
+ priv->detached_tab = notebook->cur_page;
priv->during_detach = TRUE;
gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
return TRUE;
}
- if (notebook->cur_page->reorderable)
+ if (page->reorderable &&
+ (priv->during_reorder ||
+ gtk_drag_check_threshold (widget, priv->drag_begin_x, priv->drag_begin_y, priv->mouse_x, priv->mouse_y)))
{
+ priv->during_reorder = TRUE;
pointer_position = get_pointer_position (notebook);
- if (pointer_position != POINTER_BETWEEN &&
+ if (event->window == priv->drag_window &&
+ pointer_position != POINTER_BETWEEN &&
gtk_notebook_show_arrows (notebook))
{
+ /* scroll tabs */
if (!priv->dnd_timer)
{
priv->has_scrolled = TRUE;
settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
- priv->dnd_timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
- (GSourceFunc) scroll_notebook_timer,
+ priv->dnd_timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
+ scroll_notebook_timer,
(gpointer) notebook);
}
}
}
}
- gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_REORDER);
+ if (event->window == priv->drag_window ||
+ priv->operation != DRAG_OPERATION_REORDER)
+ {
+ /* the drag operation is beginning, create the window */
+ if (priv->operation != DRAG_OPERATION_REORDER)
+ {
+ priv->operation = DRAG_OPERATION_REORDER;
+ show_drag_window (notebook, priv, page);
+ }
+
+ gtk_notebook_pages_allocate (notebook);
+ gdk_window_move_resize (priv->drag_window,
+ priv->drag_window_x,
+ priv->drag_window_y,
+ page->allocation.width,
+ page->allocation.height);
+ }
}
return TRUE;
gtk_notebook_grab_notify (GtkWidget *widget,
gboolean was_grabbed)
{
+ GtkNotebook *notebook = GTK_NOTEBOOK (widget);
+
if (!was_grabbed)
- stop_scrolling (GTK_NOTEBOOK (widget));
+ {
+ gtk_notebook_stop_reorder (notebook);
+ stop_scrolling (notebook);
+ }
}
static void
notebook->has_after_previous = has_after_previous;
notebook->has_after_next = has_after_next;
- (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous);
+ (* GTK_WIDGET_CLASS (gtk_notebook_parent_class)->style_set) (widget, previous);
+}
+
+static gboolean
+on_drag_icon_expose (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer data)
+{
+ GtkWidget *notebook, *child = GTK_WIDGET (data);
+ GtkRequisition requisition;
+ gint gap_pos;
+
+ notebook = GTK_WIDGET (data);
+ child = GTK_BIN (widget)->child;
+ gtk_widget_size_request (widget, &requisition);
+ gap_pos = get_tab_gap_pos (GTK_NOTEBOOK (notebook));
+
+ gtk_paint_extension (notebook->style, widget->window,
+ GTK_STATE_NORMAL, GTK_SHADOW_OUT,
+ NULL, widget, "tab",
+ 0, 0,
+ requisition.width, requisition.height,
+ gap_pos);
+ if (child)
+ gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
+
+ return TRUE;
}
static void
GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
GtkNotebook *notebook = (GtkNotebook*) widget;
GtkWidget *tab_label;
- GdkPixmap *pixmap;
if (priv->dnd_timer)
{
priv->dnd_timer = 0;
}
- tab_label = notebook->cur_page->tab_label;
+ priv->operation = DRAG_OPERATION_DETACH;
+ gtk_notebook_pages_allocate (notebook);
+
+ tab_label = priv->detached_tab->tab_label;
+
+ hide_drag_window (notebook, priv, notebook->cur_page);
+ g_object_ref (tab_label);
+ gtk_widget_unparent (tab_label);
- pixmap = gdk_pixmap_new (tab_label->window,
- tab_label->allocation.width + 2,
- tab_label->allocation.height + 2,
- -1);
+ priv->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
+ gtk_container_add (GTK_CONTAINER (priv->dnd_window), tab_label);
+ gtk_widget_set_size_request (priv->dnd_window,
+ priv->detached_tab->allocation.width,
+ priv->detached_tab->allocation.height);
+ g_object_unref (tab_label);
+
+ g_signal_connect (G_OBJECT (priv->dnd_window), "expose-event",
+ G_CALLBACK (on_drag_icon_expose), notebook);
+
+ gtk_drag_set_icon_widget (context, priv->dnd_window, -2, -2);
+}
+
+static void
+gtk_notebook_drag_end (GtkWidget *widget,
+ GdkDragContext *context)
+{
+ GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
- gdk_draw_drawable (pixmap,
- tab_label->style->base_gc [GTK_WIDGET_STATE (widget)],
- tab_label->window,
- tab_label->allocation.x,
- tab_label->allocation.y,
- 1, 1, -1, -1);
+ gtk_notebook_stop_reorder (GTK_NOTEBOOK (widget));
- gdk_draw_rectangle (pixmap,
- widget->style->black_gc,
- FALSE,
- 0, 0,
- tab_label->allocation.width + 1,
- tab_label->allocation.height + 1);
+ GTK_BIN (priv->dnd_window)->child = NULL;
+ gtk_widget_destroy (priv->dnd_window);
+ priv->dnd_window = NULL;
- gtk_drag_set_icon_pixmap (context,
- gdk_drawable_get_colormap (pixmap),
- pixmap,
- NULL,
- -2, -2);
+ priv->operation = DRAG_OPERATION_NONE;
+}
+
+static gboolean
+gtk_notebook_switch_tab_timeout (gpointer data)
+{
+ GtkNotebook *notebook;
+ GtkNotebookPrivate *priv;
+ GList *tab;
+ gint x, y;
+
+ notebook = GTK_NOTEBOOK (data);
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+
+ priv->switch_tab_timer = 0;
+ x = priv->mouse_x;
+ y = priv->mouse_y;
+
+ if ((tab = get_tab_at_pos (notebook, x, y)) != NULL)
+ {
+ /* FIXME: hack, we don't want the
+ * focus to move fom the source widget
+ */
+ notebook->child_has_focus = FALSE;
+ gtk_notebook_switch_focus_tab (notebook, tab);
+ }
- gtk_notebook_pages_allocate (GTK_NOTEBOOK (widget), DRAG_OPERATION_DETACH);
+ return FALSE;
}
static gboolean
gint y,
guint time)
{
- GtkWidget *source_widget;
- gint widget_group, source_widget_group;
-
- source_widget = gtk_drag_get_source_widget (context);
-
- g_assert (source_widget);
+ GtkNotebook *notebook;
+ GtkNotebookPrivate *priv;
+ GdkRectangle position;
+ GtkSettings *settings;
+ GtkNotebookArrow arrow;
+ guint timeout;
+ GdkAtom target, tab_target;
+
+ notebook = GTK_NOTEBOOK (widget);
+ arrow = gtk_notebook_get_arrow (notebook,
+ x + widget->allocation.x,
+ y + widget->allocation.y);
+ if (arrow)
+ {
+ notebook->click_child = arrow;
+ gtk_notebook_set_scroll_timer (notebook);
+ gdk_drag_status (context, 0, time);
+ return TRUE;
+ }
- widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (widget));
- source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
+ stop_scrolling (notebook);
+ target = gtk_drag_dest_find_target (widget, context, NULL);
+ tab_target = gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB");
+
+ if (target == tab_target)
+ {
+ gint widget_group, source_widget_group;
+ GtkWidget *source_widget;
- if (widget_group != -1 &&
- source_widget_group != -1 &&
- widget_group == source_widget_group)
- return TRUE;
+ source_widget = gtk_drag_get_source_widget (context);
+ g_assert (source_widget);
- gdk_drag_status (context, 0, time);
+ widget_group = gtk_notebook_get_group_id (notebook);
+ source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
- return FALSE;
+ if (widget_group != -1 &&
+ source_widget_group != -1 &&
+ 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)))
+ {
+ gdk_drag_status (context, GDK_ACTION_MOVE, time);
+ return TRUE;
+ }
+ }
+
+ 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)
+ {
+ priv->mouse_x = x;
+ priv->mouse_y = y;
+
+ if (!priv->switch_tab_timer)
+ {
+ settings = gtk_widget_get_settings (widget);
+
+ g_object_get (settings, "gtk-timeout-expand", &timeout, NULL);
+ priv->switch_tab_timer = gdk_threads_add_timeout (timeout,
+ gtk_notebook_switch_tab_timeout,
+ widget);
+ }
+ }
+ else
+ {
+ if (priv->switch_tab_timer)
+ {
+ g_source_remove (priv->switch_tab_timer);
+ priv->switch_tab_timer = 0;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+gtk_notebook_drag_leave (GtkWidget *widget,
+ GdkDragContext *context,
+ guint time)
+{
+ GtkNotebookPrivate *priv;
+
+ priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
+
+ if (priv->switch_tab_timer)
+ {
+ g_source_remove (priv->switch_tab_timer);
+ priv->switch_tab_timer = 0;
+ }
+
+ stop_scrolling (GTK_NOTEBOOK (widget));
}
static gboolean
static void
do_detach_tab (GtkNotebook *from,
GtkNotebook *to,
- GtkNotebookPage *page_info,
+ GtkWidget *child,
gint x,
gint y)
{
- GtkWidget *child, *tab_label, *menu_label;
+ GtkNotebookPrivate *priv;
+ GtkWidget *tab_label, *menu_label;
gboolean tab_expand, tab_fill, reorderable, detachable;
GList *element;
guint tab_pack;
gint page_num;
- menu_label = tab_label = child = NULL;
+ menu_label = gtk_notebook_get_menu_label (from, child);
- if (page_info->menu_label)
- menu_label = g_object_ref (page_info->menu_label);
+ if (menu_label)
+ g_object_ref (menu_label);
- if (page_info->tab_label)
- tab_label = g_object_ref (page_info->tab_label);
+ tab_label = gtk_notebook_get_tab_label (from, child);
+
+ if (tab_label)
+ g_object_ref (tab_label);
- if (page_info->child)
- child = g_object_ref (page_info->child);
+ g_object_ref (child);
- /* preserve properties */
- tab_expand = page_info->expand;
- tab_fill = page_info->fill;
- tab_pack = page_info->pack;
- reorderable = page_info->reorderable;
- detachable = page_info->detachable;
+ gtk_container_child_get (GTK_CONTAINER (from),
+ child,
+ "tab-expand", &tab_expand,
+ "tab-fill", &tab_fill,
+ "tab-pack", &tab_pack,
+ "reorderable", &reorderable,
+ "detachable", &detachable,
+ NULL);
gtk_container_remove (GTK_CONTAINER (from), child);
- element = get_drop_position (to,
- tab_pack,
- GTK_WIDGET (to)->allocation.x + x,
- GTK_WIDGET (to)->allocation.y + y);
+ priv = GTK_NOTEBOOK_GET_PRIVATE (to);
+ priv->mouse_x = x + GTK_WIDGET (to)->allocation.x;
+ priv->mouse_y = y + GTK_WIDGET (to)->allocation.y;
+ element = get_drop_position (to, tab_pack);
page_num = g_list_position (to->children, element);
gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
guint time)
{
GtkNotebook *dest_notebook, *notebook;
- gint page_num;
+ GtkNotebookPrivate *priv;
if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") &&
(data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") ||
return;
notebook = GTK_NOTEBOOK (widget);
- page_num = g_list_index (notebook->children, notebook->cur_page);
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
{
gtk_selection_data_set (data,
data->target,
8,
- (void*) notebook->cur_page,
- sizeof (GtkNotebookPage));
+ (void*) &priv->detached_tab->child,
+ sizeof (gpointer));
}
else
{
gdk_display_get_pointer (display, NULL, &x, &y, NULL);
dest_notebook = (* window_creation_hook) (notebook,
- notebook->cur_page->child,
+ priv->detached_tab->child,
x, y,
window_creation_hook_data);
-
if (dest_notebook)
- do_detach_tab (notebook, dest_notebook, notebook->cur_page, 0, 0);
+ do_detach_tab (notebook, dest_notebook, priv->detached_tab->child, 0, 0);
}
}
{
GtkNotebook *notebook;
GtkWidget *source_widget;
- GtkNotebookPage *page_info;
+ GtkWidget **child;
notebook = GTK_NOTEBOOK (widget);
source_widget = gtk_drag_get_source_widget (context);
if (source_widget &&
data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
{
- page_info = (void*) data->data;
+ child = (void*) data->data;
- do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, page_info, x, y);
+ do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y);
gtk_drag_finish (context, TRUE, FALSE, time);
}
-
- gtk_drag_finish (context, FALSE, FALSE, time);
+ else
+ gtk_drag_finish (context, FALSE, FALSE, time);
}
/* Private GtkContainer Methods :
page_num++;
children = children->next;
}
+
+ if (children == NULL)
+ return;
+
+ g_object_ref (widget);
+
+ gtk_notebook_real_remove (notebook, children);
g_signal_emit (notebook,
notebook_signals[PAGE_REMOVED],
0,
widget,
page_num);
-
- gtk_notebook_real_remove (notebook, children);
+
+ g_object_unref (widget);
}
static gboolean
new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
search_direction, TRUE);
+ if (!new_page)
+ {
+ gboolean wrap_around;
+
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (notebook)),
+ "gtk-keynav-wrap-around", &wrap_around,
+ NULL);
+
+ if (wrap_around)
+ new_page = gtk_notebook_search_page (notebook, NULL,
+ search_direction, TRUE);
+ }
+
if (new_page)
gtk_notebook_switch_focus_tab (notebook, new_page);
else
- gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
-
+ gtk_widget_error_bell (GTK_WIDGET (notebook));
+
return TRUE;
}
}
}
- parent_class->set_focus_child (container, child);
+ GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
}
static void
page = children->data;
children = children->next;
(* callback) (page->child, callback_data);
+
if (include_internals)
{
if (page->tab_label)
GParamSpec *arg,
gpointer data)
{
- GtkNotebook *notebook = (GtkNotebook *)data;
+ GtkNotebook *notebook = (GtkNotebook *) data;
GList *list;
GList *next = NULL;
gtk_widget_show (tab_label);
else
gtk_widget_hide (tab_label);
+
+ page->mnemonic_activate_signal =
+ g_signal_connect (tab_label,
+ "mnemonic_activate",
+ G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
+ notebook);
}
+ page->notify_visible_handler = g_signal_connect (child, "notify::visible",
+ G_CALLBACK (page_visible_cb), notebook);
+
+ g_signal_emit (notebook,
+ notebook_signals[PAGE_ADDED],
+ 0,
+ child,
+ position);
+
if (!notebook->cur_page)
{
gtk_notebook_switch_page (notebook, page, 0);
gtk_notebook_switch_focus_tab (notebook, NULL);
}
- page->notify_visible_handler = g_signal_connect (G_OBJECT (child), "notify::visible",
- G_CALLBACK (page_visible_cb), notebook);
gtk_notebook_update_tab_states (notebook);
- if (tab_label)
- page->mnemonic_activate_signal =
- g_signal_connect (tab_label,
- "mnemonic_activate",
- G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
- notebook);
-
gtk_widget_child_notify (child, "tab-expand");
gtk_widget_child_notify (child, "tab-fill");
gtk_widget_child_notify (child, "tab-pack");
gtk_widget_child_notify (child, "position");
gtk_widget_thaw_child_notify (child);
- g_signal_emit (notebook,
- notebook_signals[PAGE_ADDED],
- 0,
- child,
- position);
-
return position;
}
* gtk_notebook_real_remove
* gtk_notebook_update_labels
* gtk_notebook_timer
+ * gtk_notebook_set_scroll_timer
* gtk_notebook_page_compare
* gtk_notebook_real_page_position
* gtk_notebook_search_page
switch (tab_pos)
{
case GTK_POS_BOTTOM:
- redraw_rect.y = (widget->allocation.height - border -
- page->allocation.height -
- widget->style->ythickness);
+ redraw_rect.y = widget->allocation.height - border -
+ page->allocation.height - widget->style->ythickness;
+
if (page != notebook->cur_page)
redraw_rect.y -= widget->style->ythickness;
/* fall through */
case GTK_POS_TOP:
redraw_rect.width = widget->allocation.width - 2 * border;
- redraw_rect.height = (page->allocation.height +
- widget->style->ythickness);
+ redraw_rect.height = page->allocation.height + widget->style->ythickness;
+
if (page != notebook->cur_page)
redraw_rect.height += widget->style->ythickness;
break;
case GTK_POS_RIGHT:
- redraw_rect.x = (widget->allocation.width - border -
- page->allocation.width -
- widget->style->xthickness);
+ redraw_rect.x = widget->allocation.width - border -
+ page->allocation.width - widget->style->xthickness;
+
if (page != notebook->cur_page)
redraw_rect.x -= widget->style->xthickness;
/* fall through */
case GTK_POS_LEFT:
- redraw_rect.width = (page->allocation.width +
- widget->style->xthickness);
+ redraw_rect.width = page->allocation.width + widget->style->xthickness;
redraw_rect.height = widget->allocation.height - 2 * border;
+
if (page != notebook->cur_page)
redraw_rect.width += widget->style->xthickness;
break;
}
}
-static gint
+static gboolean
gtk_notebook_timer (GtkNotebook *notebook)
{
gboolean retval = FALSE;
- GDK_THREADS_ENTER ();
-
if (notebook->timer)
{
gtk_notebook_do_arrow (notebook, notebook->click_child);
g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
notebook->need_timer = FALSE;
- notebook->timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
+ notebook->timer = gdk_threads_add_timeout (timeout * SCROLL_DELAY_FACTOR,
(GSourceFunc) gtk_notebook_timer,
(gpointer) notebook);
}
retval = TRUE;
}
- GDK_THREADS_LEAVE ();
-
return retval;
}
+static void
+gtk_notebook_set_scroll_timer (GtkNotebook *notebook)
+{
+ GtkWidget *widget = GTK_WIDGET (notebook);
+
+ if (!notebook->timer)
+ {
+ GtkSettings *settings = gtk_widget_get_settings (widget);
+ guint timeout;
+
+ g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
+
+ notebook->timer = gdk_threads_add_timeout (timeout,
+ (GSourceFunc) gtk_notebook_timer,
+ (gpointer) notebook);
+ notebook->need_timer = TRUE;
+ }
+}
+
static gint
gtk_notebook_page_compare (gconstpointer a,
gconstpointer b)
gtk_notebook_real_remove (GtkNotebook *notebook,
GList *list)
{
+ GtkNotebookPrivate *priv;
GtkNotebookPage *page;
GList * next_list;
gint need_resize = FALSE;
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);
gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
}
+ if (priv->detached_tab == list->data)
+ priv->detached_tab = NULL;
+
if (list == notebook->first_tab)
notebook->first_tab = next_list;
if (list == notebook->focus_tab && !destroying)
{
page = list->data;
if (page->pack == flag &&
- (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
+ (!find_visible ||
+ (GTK_WIDGET_VISIBLE (page->child) &&
+ (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
return list;
old_list = list;
list = list->next;
{
page = list->data;
if (page->pack != flag &&
- (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
+ (!find_visible ||
+ (GTK_WIDGET_VISIBLE (page->child) &&
+ (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
return list;
old_list = list;
list = list->prev;
GdkRectangle *area)
{
GtkNotebook *notebook;
+ GtkNotebookPrivate *priv;
GtkNotebookPage *page;
GList *children;
gboolean showarrow;
return;
notebook = GTK_NOTEBOOK (widget);
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
tab_pos = get_effective_tab_pos (notebook);
return;
}
+ if (!notebook->first_tab)
+ notebook->first_tab = notebook->children;
- if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
+ if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
+ !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
+ page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
+ else
+ page = notebook->cur_page;
+
+ switch (tab_pos)
{
- page = notebook->first_tab->data;
+ case GTK_POS_TOP:
+ y += page->allocation.height;
+ /* fall thru */
+ case GTK_POS_BOTTOM:
+ height -= page->allocation.height;
+ break;
+ case GTK_POS_LEFT:
+ x += page->allocation.width;
+ /* fall thru */
+ case GTK_POS_RIGHT:
+ width -= page->allocation.width;
+ break;
+ }
- switch (tab_pos)
- {
- case GTK_POS_TOP:
- y += page->allocation.height + widget->style->ythickness;
- case GTK_POS_BOTTOM:
- height -= page->allocation.height + widget->style->ythickness;
- break;
- case GTK_POS_LEFT:
- x += page->allocation.width + widget->style->xthickness;
- case GTK_POS_RIGHT:
- width -= page->allocation.width + widget->style->xthickness;
- break;
- }
- gtk_paint_box (widget->style, widget->window,
- GTK_STATE_NORMAL, GTK_SHADOW_OUT,
- area, widget, "notebook",
- x, y, width, height);
+ if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
+ !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
+ {
+ gap_x = 0;
+ gap_width = 0;
}
else
{
switch (tab_pos)
{
case GTK_POS_TOP:
- y += notebook->cur_page->allocation.height;
case GTK_POS_BOTTOM:
- height -= notebook->cur_page->allocation.height;
- break;
- case GTK_POS_LEFT:
- x += notebook->cur_page->allocation.width;
- case GTK_POS_RIGHT:
- width -= notebook->cur_page->allocation.width;
- break;
- }
+ if (priv->operation == DRAG_OPERATION_REORDER)
+ gap_x = priv->drag_window_x - widget->allocation.x - border_width;
+ else
+ gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
- switch (tab_pos)
- {
- case GTK_POS_TOP:
- case GTK_POS_BOTTOM:
- gap_x = (notebook->cur_page->allocation.x - widget->allocation.x - border_width);
gap_width = notebook->cur_page->allocation.width;
step = is_rtl ? STEP_NEXT : STEP_PREV;
break;
case GTK_POS_LEFT:
case GTK_POS_RIGHT:
- gap_x = (notebook->cur_page->allocation.y - widget->allocation.y - border_width);
+ if (priv->operation == DRAG_OPERATION_REORDER)
+ gap_x = priv->drag_window_y - border_width - widget->allocation.y;
+ else
+ gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
+
gap_width = notebook->cur_page->allocation.height;
step = STEP_PREV;
break;
}
- gtk_paint_box_gap (widget->style, widget->window,
- GTK_STATE_NORMAL, GTK_SHADOW_OUT,
- area, widget, "notebook",
- x, y, width, height,
- tab_pos, gap_x, gap_width);
}
+ gtk_paint_box_gap (widget->style, widget->window,
+ GTK_STATE_NORMAL, GTK_SHADOW_OUT,
+ area, widget, "notebook",
+ x, y, width, height,
+ tab_pos, gap_x, gap_width);
showarrow = FALSE;
children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
GtkNotebookPage *page,
GdkRectangle *area)
{
+ GtkNotebookPrivate *priv;
GdkRectangle child_area;
GdkRectangle page_area;
GtkStateType state_type;
GtkPositionType gap_side;
- gint tab_pos = get_effective_tab_pos (notebook);
+ GdkWindow *window;
+ GtkWidget *widget;
g_return_if_fail (notebook != NULL);
g_return_if_fail (page != NULL);
g_return_if_fail (area != NULL);
- if (!GTK_WIDGET_MAPPED (page->tab_label) ||
+ if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
+ !GTK_WIDGET_MAPPED (page->tab_label) ||
(page->allocation.width == 0) || (page->allocation.height == 0))
return;
+ widget = GTK_WIDGET (notebook);
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+
+ if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
+ window = priv->drag_window;
+ else
+ window = widget->window;
+
page_area.x = page->allocation.x;
page_area.y = page->allocation.y;
page_area.width = page->allocation.width;
if (gdk_rectangle_intersect (&page_area, area, &child_area))
{
- GtkWidget *widget;
+ gap_side = get_tab_gap_pos (notebook);
- widget = GTK_WIDGET (notebook);
- gap_side = 0;
- switch (tab_pos)
- {
- case GTK_POS_TOP:
- gap_side = GTK_POS_BOTTOM;
- break;
- case GTK_POS_BOTTOM:
- gap_side = GTK_POS_TOP;
- break;
- case GTK_POS_LEFT:
- gap_side = GTK_POS_RIGHT;
- break;
- case GTK_POS_RIGHT:
- gap_side = GTK_POS_LEFT;
- break;
- }
-
if (notebook->cur_page == page)
state_type = GTK_STATE_NORMAL;
else
state_type = GTK_STATE_ACTIVE;
- gtk_paint_extension(widget->style, widget->window,
- state_type, GTK_SHADOW_OUT,
- area, widget, "tab",
- page_area.x, page_area.y,
- page_area.width, page_area.height,
- gap_side);
+
+ gtk_paint_extension (widget->style, window,
+ state_type, GTK_SHADOW_OUT,
+ area, widget, "tab",
+ page_area.x, page_area.y,
+ page_area.width, page_area.height,
+ gap_side);
+
if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
notebook->focus_tab && (notebook->focus_tab->data == page))
{
gint focus_width;
-
+
gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
-
- gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
+
+ gtk_paint_focus (widget->style, window, GTK_WIDGET_STATE (widget),
area, widget, "tab",
page->tab_label->allocation.x - focus_width,
page->tab_label->allocation.y - focus_width,
page->tab_label->allocation.width + 2 * focus_width,
page->tab_label->allocation.height + 2 * focus_width);
}
+
if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
GTK_WIDGET_DRAWABLE (page->tab_label))
{
GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
/* This is a lame hack since all this code needs rewriting anyhow */
-
expose_event->expose.window = g_object_ref (page->tab_label->window);
expose_event->expose.area = child_area;
expose_event->expose.region = gdk_region_rectangle (&child_area);
expose_event->expose.send_event = TRUE;
expose_event->expose.count = 0;
- gtk_container_propagate_expose (GTK_CONTAINER (notebook), page->tab_label, (GdkEventExpose *)expose_event);
-
+ gtk_widget_send_expose (page->tab_label, expose_event);
gdk_event_free (expose_event);
- }
+ }
}
}
if (GTK_WIDGET_DRAWABLE (notebook))
{
+ gint scroll_arrow_hlength;
+ gint scroll_arrow_vlength;
+ gint arrow_size;
+
+ gtk_widget_style_get (widget,
+ "scroll-arrow-hlength", &scroll_arrow_hlength,
+ "scroll-arrow-vlength", &scroll_arrow_vlength,
+ NULL);
+
if (notebook->in_child == nbarrow)
{
if (notebook->click_child == nbarrow)
if (notebook->tab_pos == GTK_POS_LEFT ||
notebook->tab_pos == GTK_POS_RIGHT)
- arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
+ {
+ arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
+ arrow_size = scroll_arrow_vlength;
+ }
else
- arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
-
+ {
+ arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
+ arrow_size = scroll_arrow_hlength;
+ }
+
gtk_paint_arrow (widget->style, widget->window, state_type,
shadow_type, NULL, widget, "notebook",
arrow, TRUE, arrow_rect.x, arrow_rect.y,
- ARROW_SIZE, ARROW_SIZE);
- }
-}
-
-static void
-get_notebook_tabs_space (GtkNotebook *notebook, gint *min, gint *max)
-{
- GtkWidget *widget = (GtkWidget *) notebook;
- GtkContainer *container = (GtkContainer *) notebook;
-
- if (notebook->tab_pos == GTK_POS_TOP ||
- notebook->tab_pos == GTK_POS_BOTTOM)
- {
- *min = widget->allocation.x + container->border_width;
- *max = widget->allocation.x + widget->allocation.width - container->border_width;
-
- if (gtk_notebook_show_arrows (notebook))
- {
- if (notebook->has_after_previous)
- *max -= ARROW_SPACING + ARROW_SIZE;
- if (notebook->has_after_next)
- *max -= ARROW_SPACING + ARROW_SIZE;
- if (notebook->has_before_previous)
- *min += ARROW_SPACING + ARROW_SIZE;
- if (notebook->has_before_next)
- *min += ARROW_SPACING + ARROW_SIZE;
- }
- }
- else
- {
- *min = widget->allocation.y + container->border_width;
- *max = widget->allocation.y + widget->allocation.height - container->border_width;
-
- if (gtk_notebook_show_arrows (notebook))
- {
- if (notebook->has_after_previous || notebook->has_after_next)
- *max -= ARROW_SPACING + ARROW_SIZE;
- if (notebook->has_before_previous || notebook->has_before_next)
- *min += ARROW_SPACING + ARROW_SIZE;
- }
+ arrow_size, arrow_size);
}
}
/* Private GtkNotebook Size Allocate Functions:
*
+ * gtk_notebook_tab_space
+ * gtk_notebook_calculate_shown_tabs
+ * gtk_notebook_calculate_tabs_allocation
* gtk_notebook_pages_allocate
* gtk_notebook_page_allocate
* gtk_notebook_calc_tabs
*/
static void
-gtk_notebook_pages_allocate (GtkNotebook *notebook,
- GtkNotebookDragOperation operation)
+gtk_notebook_tab_space (GtkNotebook *notebook,
+ gboolean *show_arrows,
+ gint *min,
+ gint *max,
+ gint *tab_space)
{
- GtkWidget *widget = GTK_WIDGET (notebook);
- GtkContainer *container = GTK_CONTAINER (notebook);
- GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
- GtkNotebookPage *page = NULL;
- GtkAllocation *allocation = &widget->allocation;
- GtkAllocation child_allocation;
- GList *children = NULL;
- GList *last_child = NULL;
- gboolean showarrow = FALSE;
- gint tab_space = 0;
- gint delta;
- gint i;
- gint n = 1;
- gint old_fill = 0;
- gint new_fill = 0;
+ GtkNotebookPrivate *priv;
+ GtkWidget *widget;
+ GList *children;
gint tab_pos = get_effective_tab_pos (notebook);
- gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL &&
- (tab_pos == GTK_POS_TOP || tab_pos == GTK_POS_BOTTOM));
gint tab_overlap;
- gint memo_x, anchor_x, anchor_y;
- gint min, max, top_y, bottom_y, left_x, right_x;
- gboolean packing_changed = FALSE;
- gboolean gap_left = FALSE;
+ gint arrow_spacing;
+ gint scroll_arrow_hlength;
+ gint scroll_arrow_vlength;
- if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
- return;
-
- gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
+ widget = GTK_WIDGET (notebook);
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+ children = notebook->children;
- child_allocation.x = widget->allocation.x + container->border_width;
- child_allocation.y = widget->allocation.y + container->border_width;
+ gtk_widget_style_get (GTK_WIDGET (notebook),
+ "arrow-spacing", &arrow_spacing,
+ "scroll-arrow-hlength", &scroll_arrow_hlength,
+ "scroll-arrow-vlength", &scroll_arrow_vlength,
+ NULL);
switch (tab_pos)
{
- case GTK_POS_BOTTOM:
- child_allocation.y = (widget->allocation.y +
- allocation->height -
- notebook->cur_page->requisition.height -
- container->border_width);
- /* fall through */
case GTK_POS_TOP:
- child_allocation.height = notebook->cur_page->requisition.height;
+ case GTK_POS_BOTTOM:
+ *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
+ *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
+
+ while (children)
+ {
+ GtkNotebookPage *page;
+
+ page = children->data;
+ children = children->next;
+
+ if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
+ GTK_WIDGET_VISIBLE (page->child))
+ *tab_space += page->requisition.width;
+ }
break;
-
case GTK_POS_RIGHT:
- child_allocation.x = (widget->allocation.x +
- allocation->width -
- notebook->cur_page->requisition.width -
- container->border_width);
- /* fall through */
case GTK_POS_LEFT:
- child_allocation.width = notebook->cur_page->requisition.width;
+ *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
+ *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
+
+ while (children)
+ {
+ GtkNotebookPage *page;
+
+ page = children->data;
+ children = children->next;
+
+ if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
+ GTK_WIDGET_VISIBLE (page->child))
+ *tab_space += page->requisition.height;
+ }
break;
}
- if (notebook->scrollable)
+ if (!notebook->scrollable)
+ *show_arrows = FALSE;
+ else
{
- GList *focus_tab;
-
- children = notebook->children;
-
- if (notebook->focus_tab)
- focus_tab = notebook->focus_tab;
- else if (notebook->first_tab)
- focus_tab = notebook->first_tab;
- else
- focus_tab = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
+ gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
switch (tab_pos)
{
case GTK_POS_TOP:
case GTK_POS_BOTTOM:
- while (children)
+ if (*tab_space > *max - *min - tab_overlap)
{
- page = children->data;
- children = children->next;
+ *show_arrows = TRUE;
- if (GTK_WIDGET_VISIBLE (page->child))
- tab_space += page->requisition.width;
- }
+ /* take arrows into account */
+ *tab_space = widget->allocation.width - tab_overlap -
+ 2 * GTK_CONTAINER (notebook)->border_width;
- if (tab_space >
- allocation->width - 2 * container->border_width - tab_overlap)
- {
- showarrow = TRUE;
- page = focus_tab->data;
-
- tab_space = allocation->width - tab_overlap -
- page->requisition.width - 2 * container->border_width;
if (notebook->has_after_previous)
- tab_space -= ARROW_SPACING + ARROW_SIZE;
+ {
+ *tab_space -= arrow_spacing + scroll_arrow_hlength;
+ *max -= arrow_spacing + scroll_arrow_hlength;
+ }
+
if (notebook->has_after_next)
- tab_space -= ARROW_SPACING + ARROW_SIZE;
+ {
+ *tab_space -= arrow_spacing + scroll_arrow_hlength;
+ *max -= arrow_spacing + scroll_arrow_hlength;
+ }
+
if (notebook->has_before_previous)
{
- tab_space -= ARROW_SPACING + ARROW_SIZE;
- child_allocation.x += ARROW_SPACING + ARROW_SIZE;
+ *tab_space -= arrow_spacing + scroll_arrow_hlength;
+ *min += arrow_spacing + scroll_arrow_hlength;
}
+
if (notebook->has_before_next)
{
- tab_space -= ARROW_SPACING + ARROW_SIZE;
- child_allocation.x += ARROW_SPACING + ARROW_SIZE;
+ *tab_space -= arrow_spacing + scroll_arrow_hlength;
+ *min += arrow_spacing + scroll_arrow_hlength;
}
}
break;
case GTK_POS_LEFT:
case GTK_POS_RIGHT:
- while (children)
+ if (*tab_space > *max - *min - tab_overlap)
{
- page = children->data;
- children = children->next;
+ *show_arrows = TRUE;
+
+ /* take arrows into account */
+ *tab_space = widget->allocation.height -
+ tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
- if (GTK_WIDGET_VISIBLE (page->child))
- tab_space += page->requisition.height;
- }
- if (tab_space >
- (allocation->height - 2 * container->border_width - tab_overlap))
- {
- showarrow = TRUE;
- page = focus_tab->data;
- tab_space = allocation->height
- - tab_overlap - 2 * container->border_width
- - page->requisition.height;
if (notebook->has_after_previous || notebook->has_after_next)
- tab_space -= ARROW_SPACING + ARROW_SIZE;
+ {
+ *tab_space -= arrow_spacing + scroll_arrow_vlength;
+ *max -= arrow_spacing + scroll_arrow_vlength;
+ }
+
if (notebook->has_before_previous || notebook->has_before_next)
{
- tab_space -= ARROW_SPACING + ARROW_SIZE;
- child_allocation.y += ARROW_SPACING + ARROW_SIZE;
+ *tab_space -= arrow_spacing + scroll_arrow_vlength;
+ *min += arrow_spacing + scroll_arrow_vlength;
}
}
break;
}
- if (showarrow) /* first_tab <- focus_tab */
+ }
+}
+
+static void
+gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
+ gboolean show_arrows,
+ gint min,
+ gint max,
+ gint tab_space,
+ GList **last_child,
+ gint *n,
+ gint *remaining_space)
+{
+ GtkWidget *widget;
+ GtkContainer *container;
+ GList *children;
+ GtkNotebookPage *page;
+ gint tab_pos, tab_overlap;
+
+ widget = GTK_WIDGET (notebook);
+ container = GTK_CONTAINER (notebook);
+ gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
+ tab_pos = get_effective_tab_pos (notebook);
+
+ if (show_arrows) /* first_tab <- focus_tab */
+ {
+ *remaining_space = tab_space;
+
+ if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
+ GTK_WIDGET_VISIBLE (notebook->cur_page->child))
+ {
+ gtk_notebook_calc_tabs (notebook,
+ notebook->focus_tab,
+ &(notebook->focus_tab),
+ remaining_space, STEP_NEXT);
+ }
+
+ if (*remaining_space <= 0)
+ {
+ /* show 1 tab */
+ notebook->first_tab = notebook->focus_tab;
+ *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
+ STEP_NEXT, TRUE);
+ }
+ else
{
- if (tab_space <= 0)
+ children = NULL;
+
+ if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
+ {
+ /* Is first_tab really predecessor of focus_tab? */
+ page = notebook->first_tab->data;
+ if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
+ GTK_WIDGET_VISIBLE (page->child))
+ for (children = notebook->focus_tab;
+ children && children != notebook->first_tab;
+ children = gtk_notebook_search_page (notebook,
+ children,
+ STEP_PREV,
+ TRUE));
+ }
+
+ if (!children)
{
- notebook->first_tab = focus_tab;
- last_child = gtk_notebook_search_page (notebook, focus_tab,
- STEP_NEXT, TRUE);
+ if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
+ notebook->first_tab = notebook->focus_tab;
+ else
+ notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
+ STEP_NEXT, TRUE);
}
else
+ /* calculate shown tabs counting backwards from the focus tab */
+ gtk_notebook_calc_tabs (notebook,
+ gtk_notebook_search_page (notebook,
+ notebook->focus_tab,
+ STEP_PREV,
+ TRUE),
+ &(notebook->first_tab), remaining_space,
+ STEP_PREV);
+
+ if (*remaining_space < 0)
{
+ notebook->first_tab =
+ gtk_notebook_search_page (notebook, notebook->first_tab,
+ STEP_NEXT, TRUE);
+ if (!notebook->first_tab)
+ notebook->first_tab = notebook->focus_tab;
+
+ *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
+ STEP_NEXT, TRUE);
+ }
+ else /* focus_tab -> end */
+ {
+ if (!notebook->first_tab)
+ notebook->first_tab = gtk_notebook_search_page (notebook,
+ NULL,
+ STEP_NEXT,
+ TRUE);
children = NULL;
- if (notebook->first_tab && notebook->first_tab != focus_tab)
- {
- /* Is first_tab really predecessor of focus_tab ? */
- page = notebook->first_tab->data;
- if (GTK_WIDGET_VISIBLE (page->child))
- for (children = focus_tab;
- children && children != notebook->first_tab;
- children = gtk_notebook_search_page (notebook,
- children,
- STEP_PREV,
- TRUE));
- }
- if (!children)
- notebook->first_tab = focus_tab;
- else
- gtk_notebook_calc_tabs (notebook,
- gtk_notebook_search_page (notebook,
- focus_tab,
- STEP_PREV,
- TRUE),
- &(notebook->first_tab), &tab_space,
- STEP_PREV);
-
- if (tab_space <= 0)
- {
- notebook->first_tab =
- gtk_notebook_search_page (notebook, notebook->first_tab,
- STEP_NEXT, TRUE);
- if (!notebook->first_tab)
- notebook->first_tab = focus_tab;
- last_child = gtk_notebook_search_page (notebook, focus_tab,
- STEP_NEXT, TRUE);
- }
- else /* focus_tab -> end */
+ gtk_notebook_calc_tabs (notebook,
+ gtk_notebook_search_page (notebook,
+ notebook->focus_tab,
+ STEP_NEXT,
+ TRUE),
+ &children, remaining_space, STEP_NEXT);
+
+ if (*remaining_space <= 0)
+ *last_child = children;
+ else /* start <- first_tab */
{
- if (!notebook->first_tab)
- notebook->first_tab = gtk_notebook_search_page (notebook,
- NULL,
- STEP_NEXT,
- TRUE);
+ *last_child = NULL;
children = NULL;
+
gtk_notebook_calc_tabs (notebook,
gtk_notebook_search_page (notebook,
- focus_tab,
- STEP_NEXT,
+ notebook->first_tab,
+ STEP_PREV,
TRUE),
- &children, &tab_space, STEP_NEXT);
-
- if (tab_space <= 0)
- last_child = children;
- else /* start <- first_tab */
- {
- last_child = NULL;
- children = NULL;
- gtk_notebook_calc_tabs
- (notebook,
- gtk_notebook_search_page (notebook,
- notebook->first_tab,
- STEP_PREV,
- TRUE),
- &children, &tab_space, STEP_PREV);
- notebook->first_tab = gtk_notebook_search_page(notebook,
- children,
- STEP_NEXT,
- TRUE);
- }
+ &children, remaining_space, STEP_PREV);
+
+ if (*remaining_space == 0)
+ notebook->first_tab = children;
+ else
+ notebook->first_tab = gtk_notebook_search_page(notebook,
+ children,
+ STEP_NEXT,
+ TRUE);
}
}
+ }
- if (tab_space < 0)
- {
- tab_space = -tab_space;
- n = 0;
- for (children = notebook->first_tab;
- children && children != last_child;
- children = gtk_notebook_search_page (notebook, children,
- STEP_NEXT, TRUE))
- n++;
- }
- else
- tab_space = 0;
+ if (*remaining_space < 0)
+ {
+ /* calculate number of tabs */
+ *remaining_space = - (*remaining_space);
+ *n = 0;
- /*unmap all non-visible tabs*/
- for (children = gtk_notebook_search_page (notebook, NULL,
- STEP_NEXT, TRUE);
- children && children != notebook->first_tab;
+ for (children = notebook->first_tab;
+ children && children != *last_child;
children = gtk_notebook_search_page (notebook, children,
STEP_NEXT, TRUE))
- {
- page = children->data;
- if (page->tab_label)
- gtk_widget_set_child_visible (page->tab_label, FALSE);
- }
- for (children = last_child; children;
- children = gtk_notebook_search_page (notebook, children,
- STEP_NEXT, TRUE))
- {
- page = children->data;
- if (page->tab_label)
- gtk_widget_set_child_visible (page->tab_label, FALSE);
- }
+ (*n)++;
}
- else /* !showarrow */
+ else
+ *remaining_space = 0;
+
+ /* unmap all non-visible tabs */
+ for (children = gtk_notebook_search_page (notebook, NULL,
+ STEP_NEXT, TRUE);
+ children && children != notebook->first_tab;
+ children = gtk_notebook_search_page (notebook, children,
+ STEP_NEXT, TRUE))
{
- notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
- STEP_NEXT, TRUE);
- tab_space = 0;
+ page = children->data;
+
+ if (page->tab_label &&
+ NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
+ gtk_widget_set_child_visible (page->tab_label, FALSE);
}
- }
- if (!showarrow)
+ for (children = *last_child; children;
+ children = gtk_notebook_search_page (notebook, children,
+ STEP_NEXT, TRUE))
+ {
+ page = children->data;
+
+ if (page->tab_label &&
+ NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
+ gtk_widget_set_child_visible (page->tab_label, FALSE);
+ }
+ }
+ else /* !show_arrows */
{
gint c = 0;
+ *n = 0;
+
+ *remaining_space = max - min - tab_overlap - tab_space;
+ children = notebook->children;
+ notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
+ STEP_NEXT, TRUE);
+ while (children)
+ {
+ page = children->data;
+ children = children->next;
+
+ if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
+ !GTK_WIDGET_VISIBLE (page->child))
+ continue;
+
+ c++;
+
+ if (page->expand)
+ (*n)++;
+ }
+
+ /* if notebook is homogeneous, all tabs are expanded */
+ if (notebook->homogeneous && *n)
+ *n = c;
+ }
+}
+
+static gboolean
+get_allocate_at_bottom (GtkWidget *widget,
+ gint search_direction)
+{
+ gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
+ gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
+
+ switch (tab_pos)
+ {
+ case GTK_POS_TOP:
+ case GTK_POS_BOTTOM:
+ if (!is_rtl)
+ return (search_direction == STEP_PREV);
+ else
+ return (search_direction == STEP_NEXT);
+
+ break;
+ case GTK_POS_RIGHT:
+ case GTK_POS_LEFT:
+ return (search_direction == STEP_PREV);
+ break;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+gtk_notebook_calculate_tabs_allocation (GtkNotebook *notebook,
+ GList **children,
+ GList *last_child,
+ gboolean showarrow,
+ gint direction,
+ gint *remaining_space,
+ gint *expanded_tabs,
+ gint min,
+ gint max)
+{
+ GtkWidget *widget;
+ GtkContainer *container;
+ GtkNotebookPrivate *priv;
+ GtkNotebookPage *page;
+ gboolean allocate_at_bottom;
+ gint tab_overlap, tab_pos, tab_extra_space;
+ gint left_x, right_x, top_y, bottom_y, anchor;
+ gint xthickness, ythickness;
+ gboolean gap_left, packing_changed;
+ GtkAllocation child_allocation = { 0, };
+ gboolean allocation_changed = FALSE;
+
+ widget = GTK_WIDGET (notebook);
+ container = GTK_CONTAINER (notebook);
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+ gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
+ tab_pos = get_effective_tab_pos (notebook);
+ allocate_at_bottom = get_allocate_at_bottom (widget, direction);
+ anchor = 0;
- n = 0;
- children = notebook->children;
- switch (tab_pos)
- {
- case GTK_POS_TOP:
- case GTK_POS_BOTTOM:
- while (children)
- {
- page = children->data;
- children = children->next;
+ child_allocation.x = widget->allocation.x + container->border_width;
+ child_allocation.y = widget->allocation.y + container->border_width;
- if (GTK_WIDGET_VISIBLE (page->child))
- {
- c++;
- tab_space += page->requisition.width;
- if (page->expand)
- n++;
- }
- }
- tab_space -= allocation->width;
- break;
- case GTK_POS_LEFT:
- case GTK_POS_RIGHT:
- while (children)
- {
- page = children->data;
- children = children->next;
+ xthickness = widget->style->xthickness;
+ ythickness = widget->style->ythickness;
- if (GTK_WIDGET_VISIBLE (page->child))
- {
- c++;
- tab_space += page->requisition.height;
- if (page->expand)
- n++;
- }
- }
- tab_space -= allocation->height;
- }
- tab_space += 2 * container->border_width + tab_overlap;
- tab_space *= -1;
- notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
- STEP_NEXT, TRUE);
- if (notebook->homogeneous && n)
- n = c;
+ switch (tab_pos)
+ {
+ case GTK_POS_BOTTOM:
+ child_allocation.y = widget->allocation.y + widget->allocation.height -
+ notebook->cur_page->requisition.height - container->border_width;
+ /* fall through */
+ case GTK_POS_TOP:
+ child_allocation.x = (allocate_at_bottom) ? max : min;
+ child_allocation.height = notebook->cur_page->requisition.height;
+ anchor = child_allocation.x;
+ break;
+
+ case GTK_POS_RIGHT:
+ child_allocation.x = widget->allocation.x + widget->allocation.width -
+ notebook->cur_page->requisition.width - container->border_width;
+ /* fall through */
+ case GTK_POS_LEFT:
+ child_allocation.y = (allocate_at_bottom) ? max : min;
+ child_allocation.width = notebook->cur_page->requisition.width;
+ anchor = child_allocation.y;
+ break;
}
-
- children = notebook->first_tab;
- i = 1;
-
- memo_x = child_allocation.x;
- if (notebook->children && is_rtl)
- {
- child_allocation.x = (allocation->x + allocation->width -
- container->border_width);
- if (showarrow)
- {
- if (notebook->has_after_previous)
- child_allocation.x -= ARROW_SPACING + ARROW_SIZE;
- if (notebook->has_after_next)
- child_allocation.x -= ARROW_SPACING + ARROW_SIZE;
- }
- }
-
- get_notebook_tabs_space (notebook, &min, &max);
- anchor_x = child_allocation.x;
- anchor_y = child_allocation.y;
- left_x = CLAMP (widget->allocation.x + priv->mouse_x - notebook->cur_page->allocation.width / 2,
+ left_x = CLAMP (priv->mouse_x - priv->drag_offset_x,
min, max - notebook->cur_page->allocation.width);
- top_y = CLAMP (widget->allocation.y + priv->mouse_y - notebook->cur_page->allocation.height / 2,
+ top_y = CLAMP (priv->mouse_y - priv->drag_offset_y,
min, max - notebook->cur_page->allocation.height);
right_x = left_x + notebook->cur_page->allocation.width;
bottom_y = top_y + notebook->cur_page->allocation.height;
+ gap_left = packing_changed = FALSE;
- while (children)
+ while (*children && *children != last_child)
{
- if (children == last_child)
- {
- /* FIXME double check */
- goto done;
- }
-
- page = children->data;
+ page = (*children)->data;
- if (page->pack != GTK_PACK_START)
+ if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
{
if (!showarrow)
break;
- else if (operation == DRAG_OPERATION_REORDER)
+ else if (priv->operation == DRAG_OPERATION_REORDER)
packing_changed = TRUE;
}
- children = gtk_notebook_search_page (notebook, children, STEP_NEXT,TRUE);
+ if (direction == STEP_NEXT)
+ *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
+ else
+ {
+ *children = (*children)->next;
+
+ if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
+ continue;
+ }
+
+ if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
+ continue;
- delta = 0;
- if (n && (showarrow || page->expand || notebook->homogeneous))
+ tab_extra_space = 0;
+ if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
{
- new_fill = (tab_space * i++) / n;
- delta = new_fill - old_fill;
- old_fill = new_fill;
+ tab_extra_space = *remaining_space / *expanded_tabs;
+ *remaining_space -= tab_extra_space;
+ (*expanded_tabs)--;
}
switch (tab_pos)
{
case GTK_POS_TOP:
case GTK_POS_BOTTOM:
- child_allocation.width = (page->requisition.width +
- tab_overlap + delta);
+ child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
/* make sure that the reordered tab doesn't go past the last position */
- if (operation == DRAG_OPERATION_REORDER &&
+ if (priv->operation == DRAG_OPERATION_REORDER &&
!gap_left && packing_changed)
{
- if (!is_rtl)
+ if (!allocate_at_bottom)
{
- if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor_x) ||
- (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor_x))
+ if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
+ (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
{
- left_x = notebook->cur_page->allocation.x = anchor_x;
- gtk_notebook_page_allocate (notebook, notebook->cur_page,
- ¬ebook->cur_page->allocation);
-
- anchor_x += notebook->cur_page->allocation.width - tab_overlap;
+ left_x = priv->drag_window_x = anchor;
+ anchor += notebook->cur_page->allocation.width - tab_overlap;
}
}
else
{
- if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor_x) ||
- (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor_x))
+ if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
+ (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
{
- anchor_x -= notebook->cur_page->allocation.width;
-
- left_x = notebook->cur_page->allocation.x = anchor_x;
- gtk_notebook_page_allocate (notebook, notebook->cur_page,
- ¬ebook->cur_page->allocation);
-
- anchor_x += tab_overlap;
+ anchor -= notebook->cur_page->allocation.width;
+ left_x = priv->drag_window_x = anchor;
+ anchor += tab_overlap;
}
}
gap_left = TRUE;
}
- if (operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
- child_allocation.x = left_x;
+ if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
+ {
+ priv->drag_window_x = left_x;
+ priv->drag_window_y = child_allocation.y;
+ }
else
{
- if (is_rtl)
- anchor_x -= child_allocation.width;
+ if (allocate_at_bottom)
+ anchor -= child_allocation.width;
- if (operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
+ if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
{
- if (!is_rtl &&
- left_x >= anchor_x &&
- left_x <= anchor_x + child_allocation.width / 2)
- anchor_x += notebook->cur_page->allocation.width - tab_overlap;
- else if (is_rtl &&
- right_x > anchor_x + child_allocation.width / 2 &&
- right_x <= anchor_x + child_allocation.width)
- anchor_x -= notebook->cur_page->allocation.width - tab_overlap;
+ if (!allocate_at_bottom &&
+ left_x >= anchor &&
+ left_x <= anchor + child_allocation.width / 2)
+ anchor += notebook->cur_page->allocation.width - tab_overlap;
+ else if (allocate_at_bottom &&
+ right_x >= anchor + child_allocation.width / 2 &&
+ right_x <= anchor + child_allocation.width)
+ anchor -= notebook->cur_page->allocation.width - tab_overlap;
}
-
- child_allocation.x = anchor_x;
+
+ child_allocation.x = anchor;
}
break;
case GTK_POS_LEFT:
case GTK_POS_RIGHT:
- child_allocation.height = (page->requisition.height +
- tab_overlap + delta);
+ child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
/* make sure that the reordered tab doesn't go past the last position */
- if (operation == DRAG_OPERATION_REORDER &&
+ if (priv->operation == DRAG_OPERATION_REORDER &&
!gap_left && packing_changed)
{
- if ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor_y) ||
- (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor_y))
+ if (!allocate_at_bottom &&
+ ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
+ (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
{
- top_y = notebook->cur_page->allocation.y = anchor_y;
- gtk_notebook_page_allocate (notebook, notebook->cur_page,
- ¬ebook->cur_page->allocation);
-
- anchor_y += notebook->cur_page->allocation.height - tab_overlap;
+ top_y = priv->drag_window_y = anchor;
+ anchor += notebook->cur_page->allocation.height - tab_overlap;
}
gap_left = TRUE;
}
- if (operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
- child_allocation.y = top_y;
+ if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
+ {
+ priv->drag_window_x = child_allocation.x;
+ priv->drag_window_y = top_y;
+ }
else
{
- if (operation == DRAG_OPERATION_REORDER &&
- page->pack == notebook->cur_page->pack &&
- top_y >= anchor_y &&
- top_y <= anchor_y + child_allocation.height / 2)
- anchor_y += notebook->cur_page->allocation.height - tab_overlap;
-
- child_allocation.y = anchor_y;
+ if (allocate_at_bottom)
+ anchor -= child_allocation.height;
+
+ if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
+ {
+ if (!allocate_at_bottom &&
+ top_y >= anchor &&
+ top_y <= anchor + child_allocation.height / 2)
+ anchor += notebook->cur_page->allocation.height - tab_overlap;
+ else if (allocate_at_bottom &&
+ bottom_y >= anchor + child_allocation.height / 2 &&
+ bottom_y <= anchor + child_allocation.height)
+ anchor -= notebook->cur_page->allocation.height - tab_overlap;
+ }
+
+ child_allocation.y = anchor;
}
break;
}
- gtk_notebook_page_allocate (notebook, page, &child_allocation);
+ if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
+ (page->allocation.x != child_allocation.x ||
+ page->allocation.y != child_allocation.y ||
+ page->allocation.width != child_allocation.width ||
+ page->allocation.height != child_allocation.height))
+ allocation_changed = TRUE;
+
+ page->allocation = child_allocation;
+
+ if (page == notebook->cur_page)
+ {
+ if (priv->operation == DRAG_OPERATION_REORDER ||
+ priv->operation == DRAG_OPERATION_DETACH)
+ {
+ /* needs to be allocated at 0,0
+ * to be shown in the drag window */
+ page->allocation.x = 0;
+ page->allocation.y = 0;
+ }
+ }
+ else
+ {
+ switch (tab_pos)
+ {
+ case GTK_POS_TOP:
+ page->allocation.y += ythickness;
+ /* fall through */
+ case GTK_POS_BOTTOM:
+ page->allocation.height = MAX (1, page->allocation.height - ythickness);
+ break;
+ case GTK_POS_LEFT:
+ page->allocation.x += xthickness;
+ /* fall through */
+ case GTK_POS_RIGHT:
+ page->allocation.width = MAX (1, page->allocation.width - xthickness);
+ break;
+ }
+ }
+ /* calculate whether to leave a gap based on reorder operation or not */
switch (tab_pos)
{
case GTK_POS_TOP:
case GTK_POS_BOTTOM:
- if (operation != DRAG_OPERATION_REORDER ||
- (operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
+ if (priv->operation != DRAG_OPERATION_REORDER ||
+ (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
{
- if (operation == DRAG_OPERATION_REORDER)
+ if (priv->operation == DRAG_OPERATION_REORDER)
{
if (page->pack == notebook->cur_page->pack &&
- !is_rtl &&
- left_x > anchor_x + child_allocation.width / 2 &&
- left_x <= anchor_x + child_allocation.width)
- anchor_x += notebook->cur_page->allocation.width - tab_overlap;
+ !allocate_at_bottom &&
+ left_x > anchor + child_allocation.width / 2 &&
+ left_x <= anchor + child_allocation.width)
+ anchor += notebook->cur_page->allocation.width - tab_overlap;
else if (page->pack == notebook->cur_page->pack &&
- is_rtl &&
- right_x >= anchor_x &&
- right_x <= anchor_x + child_allocation.width / 2)
- anchor_x -= notebook->cur_page->allocation.width - tab_overlap;
+ allocate_at_bottom &&
+ right_x >= anchor &&
+ right_x <= anchor + child_allocation.width / 2)
+ anchor -= notebook->cur_page->allocation.width - tab_overlap;
}
- if (!is_rtl)
- anchor_x += child_allocation.width - tab_overlap;
+ if (!allocate_at_bottom)
+ anchor += child_allocation.width - tab_overlap;
else
- anchor_x += tab_overlap;
+ anchor += tab_overlap;
}
break;
case GTK_POS_LEFT:
case GTK_POS_RIGHT:
- if (operation != DRAG_OPERATION_REORDER ||
- (operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
+ if (priv->operation != DRAG_OPERATION_REORDER ||
+ (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
{
- if (operation == DRAG_OPERATION_REORDER &&
- page->pack == notebook->cur_page->pack &&
- page != notebook->cur_page &&
- top_y > anchor_y + child_allocation.height / 2 &&
- top_y <= anchor_y + child_allocation.height)
- anchor_y += notebook->cur_page->allocation.height - tab_overlap;
-
- anchor_y += child_allocation.height - tab_overlap;
+ if (priv->operation == DRAG_OPERATION_REORDER)
+ {
+ if (page->pack == notebook->cur_page->pack &&
+ !allocate_at_bottom &&
+ top_y >= anchor + child_allocation.height / 2 &&
+ top_y <= anchor + child_allocation.height)
+ anchor += notebook->cur_page->allocation.height - tab_overlap;
+ else if (page->pack == notebook->cur_page->pack &&
+ allocate_at_bottom &&
+ bottom_y >= anchor &&
+ bottom_y <= anchor + child_allocation.height / 2)
+ anchor -= notebook->cur_page->allocation.height - tab_overlap;
+ }
+
+ if (!allocate_at_bottom)
+ anchor += child_allocation.height - tab_overlap;
+ else
+ anchor += tab_overlap;
}
break;
}
+ /* set child visible */
if (page->tab_label)
gtk_widget_set_child_visible (page->tab_label, TRUE);
}
- /* don't move the tab past the last position */
- if (operation == DRAG_OPERATION_REORDER &&
- notebook->cur_page->pack == GTK_PACK_START)
+ /* Don't move the current tab past the last position during tabs reordering */
+ if (children &&
+ priv->operation == DRAG_OPERATION_REORDER &&
+ ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
+ ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
{
switch (tab_pos)
{
case GTK_POS_TOP:
case GTK_POS_BOTTOM:
- if ((!is_rtl && PAGE_LEFT_X (notebook->cur_page) > anchor_x) ||
- (is_rtl && PAGE_RIGHT_X (notebook->cur_page) < anchor_x))
- {
- if (is_rtl)
- anchor_x -= notebook->cur_page->allocation.width;
+ if (allocate_at_bottom)
+ anchor -= notebook->cur_page->allocation.width;
- notebook->cur_page->allocation.x = anchor_x;
- gtk_notebook_page_allocate (notebook, notebook->cur_page,
- ¬ebook->cur_page->allocation);
- }
+ if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
+ (allocate_at_bottom && priv->drag_window_x < anchor))
+ priv->drag_window_x = anchor;
break;
case GTK_POS_LEFT:
case GTK_POS_RIGHT:
- if (PAGE_TOP_Y (notebook->cur_page) > anchor_y)
- {
- notebook->cur_page->allocation.y = anchor_y;
- gtk_notebook_page_allocate (notebook, notebook->cur_page,
- ¬ebook->cur_page->allocation);
- }
- break;
- }
- }
-
- if (children)
- {
- children = notebook->children;
+ if (allocate_at_bottom)
+ anchor -= notebook->cur_page->allocation.height;
- switch (tab_pos)
- {
- case GTK_POS_TOP:
- case GTK_POS_BOTTOM:
- if (!is_rtl)
- anchor_x = (allocation->x + allocation->width -
- container->border_width);
- else
- anchor_x = memo_x;
- break;
- case GTK_POS_LEFT:
- case GTK_POS_RIGHT:
- anchor_y = (allocation->y + allocation->height -
- container->border_width);
+ if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
+ (allocate_at_bottom && priv->drag_window_y < anchor))
+ priv->drag_window_y = anchor;
break;
}
+ }
- while (children != last_child)
- {
- page = children->data;
- children = children->next;
-
- if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
- continue;
-
- delta = 0;
- if (n && (page->expand || notebook->homogeneous))
- {
- new_fill = (tab_space * i++) / n;
- delta = new_fill - old_fill;
- old_fill = new_fill;
- }
-
- switch (tab_pos)
- {
- case GTK_POS_TOP:
- case GTK_POS_BOTTOM:
- child_allocation.width = (page->requisition.width +
- tab_overlap + delta);
-
- if (operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
- child_allocation.x = left_x;
- else
- {
- if (!is_rtl)
- anchor_x -= child_allocation.width;
-
- if (operation == DRAG_OPERATION_REORDER)
- {
- if (page->pack == notebook->cur_page->pack &&
- is_rtl &&
- left_x >= anchor_x &&
- left_x <= anchor_x + child_allocation.width / 2)
- anchor_x += notebook->cur_page->allocation.width - tab_overlap;
- else if (page->pack == notebook->cur_page->pack &&
- !is_rtl &&
- right_x > anchor_x + child_allocation.width / 2 &&
- right_x <= anchor_x + child_allocation.width)
- anchor_x -= notebook->cur_page->allocation.width - tab_overlap;
- }
-
- child_allocation.x = anchor_x;
- }
+ return allocation_changed;
+}
- break;
- case GTK_POS_LEFT:
- case GTK_POS_RIGHT:
- child_allocation.height = (page->requisition.height +
- tab_overlap + delta);
+static void
+gtk_notebook_pages_allocate (GtkNotebook *notebook)
+{
+ GList *children = NULL;
+ GList *last_child = NULL;
+ gboolean showarrow = FALSE;
+ gint tab_space, min, max, remaining_space;
+ gint expanded_tabs, operation;
- if (operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
- child_allocation.y = top_y;
- else
- {
- anchor_y -= child_allocation.height;
-
- if (operation == DRAG_OPERATION_REORDER &&
- page->pack == notebook->cur_page->pack &&
- bottom_y > anchor_y + child_allocation.height / 2 &&
- bottom_y <= anchor_y + child_allocation.height)
- anchor_y -= notebook->cur_page->allocation.height - tab_overlap;
-
- child_allocation.y = anchor_y;
- }
+ if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
+ return;
- break;
- }
+ min = max = tab_space = remaining_space = 0;
+ expanded_tabs = 1;
- gtk_notebook_page_allocate (notebook, page, &child_allocation);
+ gtk_notebook_tab_space (notebook, &showarrow,
+ &min, &max, &tab_space);
- switch (tab_pos)
- {
- case GTK_POS_TOP:
- case GTK_POS_BOTTOM:
- if (operation != DRAG_OPERATION_REORDER ||
- (operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
- {
- if (operation == DRAG_OPERATION_REORDER)
- {
- if (page->pack == notebook->cur_page->pack &&
- is_rtl &&
- left_x > anchor_x + child_allocation.width / 2 &&
- left_x <= anchor_x + child_allocation.width)
- anchor_x += notebook->cur_page->allocation.width - tab_overlap;
- else if (page->pack == notebook->cur_page->pack &&
- !is_rtl &&
- right_x >= anchor_x &&
- right_x <= anchor_x + child_allocation.width / 2)
- anchor_x -= notebook->cur_page->allocation.width - tab_overlap;
- }
-
- if (!is_rtl)
- anchor_x += tab_overlap;
- else
- anchor_x += child_allocation.width - tab_overlap;
- }
+ gtk_notebook_calculate_shown_tabs (notebook, showarrow,
+ min, max, tab_space, &last_child,
+ &expanded_tabs, &remaining_space);
- break;
- case GTK_POS_LEFT:
- case GTK_POS_RIGHT:
- if (operation != DRAG_OPERATION_REORDER ||
- (operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
- {
- if (operation == DRAG_OPERATION_REORDER &&
- page->pack == notebook->cur_page->pack &&
- page != notebook->cur_page &&
- bottom_y >= anchor_y &&
- bottom_y <= anchor_y + child_allocation.height / 2)
- anchor_y -= notebook->cur_page->allocation.height - tab_overlap;
-
- anchor_y += tab_overlap;
- }
+ children = notebook->first_tab;
+ gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
+ showarrow, STEP_NEXT,
+ &remaining_space, &expanded_tabs, min, max);
+ if (children && children != last_child)
+ {
+ children = notebook->children;
+ gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
+ showarrow, STEP_PREV,
+ &remaining_space, &expanded_tabs, min, max);
+ }
- break;
- }
+ children = notebook->children;
- if (page->tab_label)
- gtk_widget_set_child_visible (page->tab_label, TRUE);
- }
+ while (children)
+ {
+ gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
+ children = children->next;
+ }
- /* don't move the tab past the last position */
- if (operation == DRAG_OPERATION_REORDER &&
- notebook->cur_page->pack == GTK_PACK_END)
- {
- switch (tab_pos)
- {
- case GTK_POS_TOP:
- case GTK_POS_BOTTOM:
- if ((!is_rtl && PAGE_RIGHT_X (notebook->cur_page) < anchor_x) ||
- (is_rtl && PAGE_LEFT_X (notebook->cur_page) > anchor_x))
- {
- if (!is_rtl)
- anchor_x -= notebook->cur_page->allocation.width;
+ operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
- notebook->cur_page->allocation.x = anchor_x;
- gtk_notebook_page_allocate (notebook, notebook->cur_page,
- ¬ebook->cur_page->allocation);
- }
- break;
- case GTK_POS_LEFT:
- case GTK_POS_RIGHT:
- if (PAGE_BOTTOM_Y (notebook->cur_page) < anchor_y)
- {
- anchor_y -= notebook->cur_page->allocation.height;
- notebook->cur_page->allocation.y = anchor_y;
- gtk_notebook_page_allocate (notebook, notebook->cur_page,
- ¬ebook->cur_page->allocation);
- }
- break;
- }
- }
- }
+ if (!notebook->first_tab)
+ notebook->first_tab = notebook->children;
- done:
- gtk_notebook_redraw_tabs (notebook);
+ gtk_notebook_redraw_tabs (notebook);
}
static void
gtk_notebook_page_allocate (GtkNotebook *notebook,
- GtkNotebookPage *page,
- GtkAllocation *allocation)
+ GtkNotebookPage *page)
{
GtkWidget *widget = GTK_WIDGET (notebook);
GtkAllocation child_allocation;
gint tab_curvature;
gint tab_pos = get_effective_tab_pos (notebook);
- gtk_widget_style_get (widget,
- "focus-line-width", &focus_width,
- "tab-curvature", &tab_curvature,
- NULL);
-
+ if (!page->tab_label)
+ return;
+
xthickness = widget->style->xthickness;
ythickness = widget->style->ythickness;
- page->allocation = *allocation;
gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
-
- if (notebook->cur_page != page)
- {
- switch (tab_pos)
- {
- case GTK_POS_TOP:
- page->allocation.y += ythickness;
- case GTK_POS_BOTTOM:
- page->allocation.height = MAX (1, page->allocation.height - ythickness);
- break;
- case GTK_POS_LEFT:
- page->allocation.x += xthickness;
- case GTK_POS_RIGHT:
- page->allocation.width = MAX (1, page->allocation.width - xthickness);
- break;
- }
- }
-
+ gtk_widget_style_get (widget,
+ "focus-line-width", &focus_width,
+ "tab-curvature", &tab_curvature,
+ NULL);
switch (tab_pos)
{
case GTK_POS_TOP:
padding = tab_curvature + focus_width + notebook->tab_hborder;
if (page->fill)
{
- child_allocation.x = (xthickness + focus_width +
- notebook->tab_hborder);
- child_allocation.width = MAX (1, (page->allocation.width -
- 2 * child_allocation.x));
+ child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
+ child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
child_allocation.x += page->allocation.x;
}
else
{
- child_allocation.x = (page->allocation.x +
- (page->allocation.width -
- tab_requisition.width) / 2);
+ child_allocation.x = page->allocation.x +
+ (page->allocation.width - tab_requisition.width) / 2;
+
child_allocation.width = tab_requisition.width;
}
- child_allocation.y = (notebook->tab_vborder + focus_width +
- page->allocation.y);
+
+ child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
+
if (tab_pos == GTK_POS_TOP)
child_allocation.y += ythickness;
- child_allocation.height = MAX (1, (((gint) page->allocation.height) - ythickness -
+
+ child_allocation.height = MAX (1, (page->allocation.height - ythickness -
2 * (notebook->tab_vborder + focus_width)));
break;
case GTK_POS_LEFT:
}
else
{
- child_allocation.y = (page->allocation.y + (page->allocation.height -
- tab_requisition.height) / 2);
+ child_allocation.y = page->allocation.y +
+ (page->allocation.height - tab_requisition.height) / 2;
+
child_allocation.height = tab_requisition.height;
}
- child_allocation.x = page->allocation.x + notebook->tab_hborder + focus_width;
+
+ child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
+
if (tab_pos == GTK_POS_LEFT)
child_allocation.x += xthickness;
- child_allocation.width = MAX (1, (((gint) page->allocation.width) - xthickness -
+
+ child_allocation.width = MAX (1, (page->allocation.width - xthickness -
2 * (notebook->tab_hborder + focus_width)));
break;
}
- if (page->tab_label)
- gtk_widget_size_allocate (page->tab_label, &child_allocation);
+ gtk_widget_size_allocate (page->tab_label, &child_allocation);
}
static void
-gtk_notebook_calc_tabs (GtkNotebook *notebook,
- GList *start,
+gtk_notebook_calc_tabs (GtkNotebook *notebook,
+ GList *start,
GList **end,
gint *tab_space,
guint direction)
GtkNotebookPage *page = NULL;
GList *children;
GList *last_list = NULL;
+ GList *last_calculated_child = NULL;
gboolean pack;
gint tab_pos = get_effective_tab_pos (notebook);
+ guint real_direction;
if (!start)
return;
children = start;
pack = GTK_NOTEBOOK_PAGE (start)->pack;
if (pack == GTK_PACK_END)
- direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
+ real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
+ else
+ real_direction = direction;
while (1)
{
while (children)
{
page = children->data;
- if (GTK_WIDGET_VISIBLE (page->child))
+ if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
+ GTK_WIDGET_VISIBLE (page->child))
{
if (page->pack == pack)
{
{
*tab_space = - (*tab_space +
page->requisition.width);
+
+ if (*tab_space == 0 && direction == STEP_PREV)
+ children = last_calculated_child;
+
*end = children;
}
return;
}
+
+ last_calculated_child = children;
}
last_list = children;
}
- if (direction == STEP_NEXT)
+ if (real_direction == STEP_NEXT)
children = children->next;
else
children = children->prev;
while (children)
{
page = children->data;
- if (GTK_WIDGET_VISIBLE (page->child))
+ if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
+ GTK_WIDGET_VISIBLE (page->child))
{
if (page->pack == pack)
{
{
*tab_space = - (*tab_space +
page->requisition.height);
+
+ if (*tab_space == 0 && direction == STEP_PREV)
+ children = last_calculated_child;
+
*end = children;
}
return;
}
+
+ last_calculated_child = children;
}
last_list = children;
}
- if (direction == STEP_NEXT)
+ if (real_direction == STEP_NEXT)
children = children->next;
else
children = children->prev;
}
break;
}
- if (direction == STEP_PREV)
+ if (real_direction == STEP_PREV)
return;
pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
- direction = STEP_PREV;
+ real_direction = STEP_PREV;
children = last_list;
}
}
if (GTK_WIDGET_MAPPED (page->tab_label))
gtk_notebook_redraw_tabs (notebook);
else
- gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
+ gtk_notebook_pages_allocate (notebook);
gtk_notebook_switch_page (notebook, page,
g_list_index (notebook->children, page));
gtk_notebook_menu_label_unparent (GtkWidget *widget,
gpointer data)
{
- gtk_widget_unparent (GTK_BIN(widget)->child);
- GTK_BIN(widget)->child = NULL;
+ gtk_widget_unparent (GTK_BIN (widget)->child);
+ GTK_BIN (widget)->child = NULL;
}
static void
* than the number of pages in the notebook, nothing
* will be done.
*
- * Switches to the page number @page_num.
- **/
+ * Switches to the page number @page_num.
+ *
+ * Note that due to historical reasons, GtkNotebook refuses
+ * to switch to a page unless the child widget is visible.
+ * Therefore, it is recommended to show child widgets before
+ * adding them to a notebook.
+ */
void
gtk_notebook_set_current_page (GtkNotebook *notebook,
gint page_num)
gtk_widget_child_notify (child, "tab-pack");
gtk_widget_child_notify (child, "position");
if (notebook->show_tabs)
- gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
+ gtk_notebook_pages_allocate (notebook);
gtk_widget_thaw_child_notify (child);
}
gtk_widget_child_notify (child, "position");
if (notebook->show_tabs)
- gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
+ gtk_notebook_pages_allocate (notebook);
gtk_widget_thaw_child_notify (child);
/**
* gtk_notebook_set_window_creation_hook:
- * @func: the #GtkNotebookWindowCreationFunc, or NULL
- * @data: user data for @func.
+ * @func: the #GtkNotebookWindowCreationFunc, or %NULL
+ * @data: user data for @func
+ * @destroy: Destroy notifier for @data, or %NULL
*
* Installs a global function used to create a window
* when a detached tab is dropped in an empty area.
**/
void
gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc func,
- gpointer data)
+ gpointer data,
+ GDestroyNotify destroy)
{
+ if (window_creation_hook_destroy)
+ window_creation_hook_destroy (window_creation_hook_data);
+
window_creation_hook = func;
window_creation_hook_data = data;
+ window_creation_hook_destroy = destroy;
}
/**
*
* Gets whether the tab can be reordered via drag and drop or not.
*
- * Return Value: TRUE if the tab is reorderable.
+ * Return Value: %TRUE if the tab is reorderable.
+ *
+ * Since: 2.10
**/
gboolean
gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
* @child: a child #GtkWidget
* @detachable: whether the tab is detachable or not
*
- * Sets whether the tab can be detached from @notebook to another notebook.
+ * Sets whether the tab can be detached from @notebook to another
+ * notebook or widget.
*
* Note that 2 notebooks must share a common group identificator
- * (see gtk_notebook_set_group_id ()) to allow tabs interchange between them.
+ * (see gtk_notebook_set_group_id ()) to allow automatic tabs
+ * interchange between them.
+ *
+ * If you want a widget to interact with a notebook through DnD
+ * (i.e.: accept dragged tabs from it) it must be set as a drop
+ * 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,
+ * gint x,
+ * gint y,
+ * GtkSelectionData *selection_data,
+ * guint info,
+ * guint time,
+ * gpointer user_data)
+ * {
+ * GtkWidget *notebook;
+ * GtkWidget **child;
+ *
+ * notebook = gtk_drag_get_source_widget (context);
+ * child = (void*) selection_data->data;
+ *
+ * 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.
*
* Since: 2.10
**/
void
gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
- GtkWidget *child,
- gboolean detachable)
+ GtkWidget *child,
+ gboolean detachable)
{
GList *list;