summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2009-11-08 21:25:05 -0500
committerMatthias Clasen <mclasen@redhat.com>2009-11-08 21:28:17 -0500
commitc7e4a1a012042ab711f04458df3ee517bdf6aa1c (patch)
tree8c5fe28468f5b228063dd45c9276296d67689bf1
parent38f7383c7a10fe98ce4a29086a6722f40a429424 (diff)
downloadgtk+-c7e4a1a012042ab711f04458df3ee517bdf6aa1c.tar.gz
Add an 'action area' to GtkNotebook
Add support for putting widgets in the tab area, before or after the tabs. This was requested a long time ago in bug 116650. The implementation is the work of Johannes Schmid.
-rw-r--r--docs/reference/gtk/gtk-sections.txt4
-rw-r--r--gtk/gtk.symbols2
-rw-r--r--gtk/gtknotebook.c436
-rw-r--r--gtk/gtknotebook.h6
4 files changed, 403 insertions, 45 deletions
diff --git a/docs/reference/gtk/gtk-sections.txt b/docs/reference/gtk/gtk-sections.txt
index 4d8495ae01..d5d3e05f3a 100644
--- a/docs/reference/gtk/gtk-sections.txt
+++ b/docs/reference/gtk/gtk-sections.txt
@@ -2732,8 +2732,12 @@ gtk_notebook_set_group_id
gtk_notebook_get_group_id
gtk_notebook_set_group
gtk_notebook_get_group
+gtk_notebook_set_action_widget
+gtk_notebook_get_action_widget
GtkNotebookWindowCreationFunc
gtk_notebook_set_window_creation_hook
+gtk_notebook_set_action_widget
+gtk_notebook_get_action_widget
<SUBSECTION Standard>
GTK_NOTEBOOK
GTK_IS_NOTEBOOK
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 4b39bded36..c1b1e2261b 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -2674,6 +2674,8 @@ gtk_notebook_get_tab_reorderable
gtk_notebook_set_tab_reorderable
gtk_notebook_get_tab_detachable
gtk_notebook_set_tab_detachable
+gtk_notebook_get_action_widget
+gtk_notebook_set_action_widget
#endif
#endif
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index 4d88d01a1a..2fd8ab06e7 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -127,6 +127,12 @@ enum {
CHILD_PROP_DETACHABLE
};
+enum {
+ ACTION_WIDGET_START,
+ ACTION_WIDGET_END,
+ N_ACTION_WIDGETS
+};
+
#define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
/* some useful defines for calculating coords */
@@ -194,6 +200,8 @@ struct _GtkNotebookPrivate
guint32 timestamp;
+ GtkWidget *action_widget[N_ACTION_WIDGETS];
+
guint during_reorder : 1;
guint during_detach : 1;
guint has_scrolled : 1;
@@ -1627,11 +1635,14 @@ static gboolean
gtk_notebook_get_event_window_position (GtkNotebook *notebook,
GdkRectangle *rectangle)
{
+ GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
GtkWidget *widget = GTK_WIDGET (notebook);
gint border_width = GTK_CONTAINER (notebook)->border_width;
GtkNotebookPage *visible_page = NULL;
GList *tmp_list;
gint tab_pos = get_effective_tab_pos (notebook);
+ gboolean is_rtl;
+ gint i;
for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
{
@@ -1647,9 +1658,10 @@ gtk_notebook_get_event_window_position (GtkNotebook *notebook,
{
if (rectangle)
{
+ is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
rectangle->x = widget->allocation.x + border_width;
rectangle->y = widget->allocation.y + border_width;
-
+
switch (tab_pos)
{
case GTK_POS_TOP:
@@ -1658,6 +1670,18 @@ gtk_notebook_get_event_window_position (GtkNotebook *notebook,
rectangle->height = visible_page->requisition.height;
if (tab_pos == GTK_POS_BOTTOM)
rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
+
+ for (i = 0; i < N_ACTION_WIDGETS; i++)
+ {
+ if (priv->action_widget[i] &&
+ GTK_WIDGET_VISIBLE (priv->action_widget[i]))
+ {
+ rectangle->width -= priv->action_widget[i]->allocation.width;
+ if ((!is_rtl && i == ACTION_WIDGET_START) ||
+ (is_rtl && i == ACTION_WIDGET_END))
+ rectangle->x += priv->action_widget[i]->allocation.width;
+ }
+ }
break;
case GTK_POS_LEFT:
case GTK_POS_RIGHT:
@@ -1665,7 +1689,19 @@ gtk_notebook_get_event_window_position (GtkNotebook *notebook,
rectangle->height = widget->allocation.height - 2 * border_width;
if (tab_pos == GTK_POS_RIGHT)
rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
- break;
+
+ for (i = 0; i < N_ACTION_WIDGETS; i++)
+ {
+ if (priv->action_widget[i] &&
+ GTK_WIDGET_VISIBLE (priv->action_widget[i]))
+ {
+ rectangle->height -= priv->action_widget[i]->allocation.height;
+
+ if (i == ACTION_WIDGET_START)
+ rectangle->y += priv->action_widget[i]->allocation.height;
+ }
+ }
+ break;
}
}
@@ -1686,19 +1722,33 @@ gtk_notebook_get_event_window_position (GtkNotebook *notebook,
static void
gtk_notebook_map (GtkWidget *widget)
{
+ GtkNotebookPrivate *priv;
GtkNotebook *notebook;
GtkNotebookPage *page;
GList *children;
+ gint i;
GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
notebook = GTK_NOTEBOOK (widget);
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
if (notebook->cur_page &&
GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
!GTK_WIDGET_MAPPED (notebook->cur_page->child))
gtk_widget_map (notebook->cur_page->child);
+ if (notebook->show_tabs)
+ {
+ for (i = 0; i < 2; i++)
+ {
+ if (priv->action_widget[i] &&
+ GTK_WIDGET_VISIBLE (priv->action_widget[i]) &&
+ !GTK_WIDGET_MAPPED (priv->action_widget[i]))
+ gtk_widget_map (priv->action_widget[i]);
+ }
+ }
+
if (notebook->scrollable)
gtk_notebook_pages_allocate (notebook);
else
@@ -1796,10 +1846,12 @@ static void
gtk_notebook_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
+ GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
GtkNotebookPage *page;
GList *children;
GtkRequisition child_requisition;
+ GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
gboolean switch_page = FALSE;
gint vis_pages;
gint focus_width;
@@ -1861,6 +1913,7 @@ gtk_notebook_size_request (GtkWidget *widget,
gint tab_height = 0;
gint tab_max = 0;
gint padding;
+ gint i;
for (children = notebook->children; children;
children = children->next)
@@ -1908,6 +1961,16 @@ gtk_notebook_size_request (GtkWidget *widget,
if (vis_pages)
{
+ for (i = 0; i < N_ACTION_WIDGETS; i++)
+ {
+ if (priv->action_widget[i])
+ {
+ gtk_widget_size_request (priv->action_widget[i], &action_widget_requisition[i]);
+ action_widget_requisition[i].width += widget->style->xthickness;
+ action_widget_requisition[i].height += widget->style->ythickness;
+ }
+ }
+
switch (notebook->tab_pos)
{
case GTK_POS_TOP:
@@ -1919,6 +1982,9 @@ gtk_notebook_size_request (GtkWidget *widget,
widget->requisition.width < tab_width)
tab_height = MAX (tab_height, scroll_arrow_hlength);
+ tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_START].height);
+ tab_height = MAX (tab_height, action_widget_requisition[ACTION_WIDGET_END].height);
+
padding = 2 * (tab_curvature + focus_width +
notebook->tab_hborder) - tab_overlap;
tab_max += padding;
@@ -1951,6 +2017,8 @@ gtk_notebook_size_request (GtkWidget *widget,
widget->requisition.width = MAX (widget->requisition.width,
tab_width + tab_overlap);
+ widget->requisition.width += action_widget_requisition[ACTION_WIDGET_START].width;
+ widget->requisition.width += action_widget_requisition[ACTION_WIDGET_END].width;
widget->requisition.height += tab_height;
break;
case GTK_POS_LEFT:
@@ -1963,6 +2031,9 @@ gtk_notebook_size_request (GtkWidget *widget,
tab_width = MAX (tab_width,
arrow_spacing + 2 * scroll_arrow_vlength);
+ tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_START].width);
+ tab_width = MAX (tab_width, action_widget_requisition[ACTION_WIDGET_END].width);
+
padding = 2 * (tab_curvature + focus_width +
notebook->tab_vborder) - tab_overlap;
tab_max += padding;
@@ -1975,7 +2046,7 @@ gtk_notebook_size_request (GtkWidget *widget,
if (!GTK_WIDGET_VISIBLE (page->child))
continue;
- page->requisition.width = tab_width;
+ page->requisition.width = tab_width;
if (notebook->homogeneous)
page->requisition.height = tab_max;
@@ -1989,8 +2060,6 @@ gtk_notebook_size_request (GtkWidget *widget,
widget->requisition.height < tab_height)
tab_height = tab_max + (2 * scroll_arrow_vlength + arrow_spacing);
- widget->requisition.width += tab_width;
-
if (notebook->homogeneous && !notebook->scrollable)
widget->requisition.height =
MAX (widget->requisition.height,
@@ -2005,6 +2074,10 @@ gtk_notebook_size_request (GtkWidget *widget,
widget->requisition.height = MAX (widget->requisition.height,
vis_pages * tab_max +
tab_overlap);
+
+ widget->requisition.height += action_widget_requisition[ACTION_WIDGET_START].height;
+ widget->requisition.height += action_widget_requisition[ACTION_WIDGET_END].height;
+ widget->requisition.width += tab_width;
break;
}
}
@@ -2061,9 +2134,14 @@ static void
gtk_notebook_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
+ GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
gint tab_pos = get_effective_tab_pos (notebook);
+ gboolean is_rtl;
+ gint focus_width;
+ gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
+
widget->allocation = *allocation;
if (GTK_WIDGET_REALIZED (widget))
{
@@ -2087,6 +2165,7 @@ gtk_notebook_size_allocate (GtkWidget *widget,
GtkNotebookPage *page;
GtkAllocation child_allocation;
GList *children;
+ gint i;
child_allocation.x = widget->allocation.x + border_width;
child_allocation.y = widget->allocation.y + border_width;
@@ -2121,6 +2200,55 @@ gtk_notebook_size_allocate (GtkWidget *widget,
notebook->cur_page->requisition.width);
break;
}
+
+ for (i = 0; i < N_ACTION_WIDGETS; i++)
+ {
+ GtkAllocation widget_allocation;
+
+ if (!priv->action_widget[i])
+ continue;
+
+ widget_allocation.x = widget->allocation.x + border_width;
+ widget_allocation.y = widget->allocation.y + border_width;
+ is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+
+ switch (tab_pos)
+ {
+ case GTK_POS_BOTTOM:
+ widget_allocation.y +=
+ widget->allocation.height - 2 * border_width - notebook->cur_page->requisition.height;
+ /* fall through */
+ case GTK_POS_TOP:
+ widget_allocation.width = priv->action_widget[i]->requisition.width;
+ widget_allocation.height = notebook->cur_page->requisition.height - widget->style->ythickness;
+
+ if ((i == ACTION_WIDGET_START && is_rtl) ||
+ (i == ACTION_WIDGET_END && !is_rtl))
+ widget_allocation.x +=
+ widget->allocation.width - 2 * border_width -
+ priv->action_widget[i]->requisition.width;
+ if (tab_pos == GTK_POS_TOP) /* no fall through */
+ widget_allocation.y += 2 * focus_width;
+ break;
+ case GTK_POS_RIGHT:
+ widget_allocation.x +=
+ widget->allocation.width - 2 * border_width - notebook->cur_page->requisition.width;
+ /* fall through */
+ case GTK_POS_LEFT:
+ widget_allocation.height = priv->action_widget[i]->requisition.height;
+ widget_allocation.width = notebook->cur_page->requisition.width - widget->style->xthickness;
+
+ if (i == ACTION_WIDGET_END)
+ widget_allocation.y +=
+ widget->allocation.height - 2 * border_width -
+ priv->action_widget[i]->requisition.height;
+ if (tab_pos == GTK_POS_LEFT) /* no fall through */
+ widget_allocation.x += 2 * focus_width;
+ break;
+ }
+
+ gtk_widget_size_allocate (priv->action_widget[i], &widget_allocation);
+ }
}
}
@@ -2144,6 +2272,7 @@ gtk_notebook_expose (GtkWidget *widget,
{
GtkNotebook *notebook;
GtkNotebookPrivate *priv;
+ gint i;
notebook = GTK_NOTEBOOK (widget);
priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
@@ -2201,6 +2330,16 @@ gtk_notebook_expose (GtkWidget *widget,
gtk_container_propagate_expose (GTK_CONTAINER (notebook),
notebook->cur_page->child,
event);
+ if (notebook->show_tabs)
+ {
+ for (i = 0; i < N_ACTION_WIDGETS; i++)
+ {
+ if (priv->action_widget[i] &&
+ GTK_WIDGET_DRAWABLE (priv->action_widget[i]))
+ gtk_container_propagate_expose (GTK_CONTAINER (notebook),
+ priv->action_widget[i], event);
+ }
+ }
}
return FALSE;
@@ -2423,21 +2562,29 @@ static gboolean
gtk_notebook_scroll (GtkWidget *widget,
GdkEventScroll *event)
{
+ GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
-
- GtkWidget* child;
- GtkWidget* originator;
+ GtkWidget *child, *event_widget;
+ gint i;
if (!notebook->cur_page)
return FALSE;
child = notebook->cur_page->child;
- originator = gtk_get_event_widget ((GdkEvent *)event);
+ event_widget = gtk_get_event_widget ((GdkEvent *)event);
/* ignore scroll events from the content of the page */
- if (!originator || gtk_widget_is_ancestor (originator, child) || originator == child)
+ if (!event_widget || gtk_widget_is_ancestor (event_widget, child) || event_widget == child)
return FALSE;
-
+
+ /* nor from the action area */
+ for (i = 0; i < 2; i++)
+ {
+ if (event_widget == priv->action_widget[i] ||
+ gtk_widget_is_ancestor (event_widget, priv->action_widget[i]))
+ return FALSE;
+ }
+
switch (event->direction)
{
case GDK_SCROLL_RIGHT:
@@ -2857,24 +3004,27 @@ static GtkNotebookPointerPosition
get_pointer_position (GtkNotebook *notebook)
{
GtkWidget *widget = (GtkWidget *) notebook;
- GtkContainer *container = (GtkContainer *) notebook;
GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+ gint wx, wy, width, height;
gboolean is_rtl;
if (!notebook->scrollable)
return POINTER_BETWEEN;
+ gdk_window_get_position (notebook->event_window, &wx, &wy);
+ gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &width, &height);
+
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;
+ x = priv->mouse_x - wx;
- if (x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
+ if (x > width - SCROLL_THRESHOLD)
return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
- else if (x < SCROLL_THRESHOLD + container->border_width)
+ else if (x < SCROLL_THRESHOLD)
return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
else
return POINTER_BETWEEN;
@@ -2883,10 +3033,10 @@ get_pointer_position (GtkNotebook *notebook)
{
gint y;
- y = priv->mouse_y - widget->allocation.y;
- if (y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
+ y = priv->mouse_y - wy;
+ if (y > height - SCROLL_THRESHOLD)
return POINTER_AFTER;
- else if (y < SCROLL_THRESHOLD + container->border_width)
+ else if (y < SCROLL_THRESHOLD)
return POINTER_BEFORE;
else
return POINTER_BETWEEN;
@@ -3813,8 +3963,8 @@ focus_tabs_move (GtkNotebook *notebook,
}
static gboolean
-focus_child_in (GtkNotebook *notebook,
- GtkDirectionType direction)
+focus_child_in (GtkNotebook *notebook,
+ GtkDirectionType direction)
{
if (notebook->cur_page)
return gtk_widget_child_focus (notebook->cur_page->child, direction);
@@ -3822,22 +3972,52 @@ focus_child_in (GtkNotebook *notebook,
return FALSE;
}
+static gboolean
+focus_action_in (GtkNotebook *notebook,
+ gint action,
+ GtkDirectionType direction)
+{
+ GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+
+ if (priv->action_widget[action] &&
+ GTK_WIDGET_VISIBLE (priv->action_widget[action]))
+ return gtk_widget_child_focus (priv->action_widget[action], direction);
+ else
+ return FALSE;
+}
+
/* Focus in the notebook can either be on the pages, or on
- * the tabs.
+ * the tabs or on the action_widgets.
*/
static gint
gtk_notebook_focus (GtkWidget *widget,
GtkDirectionType direction)
{
+ GtkNotebookPrivate *priv;
GtkWidget *old_focus_child;
GtkNotebook *notebook;
GtkDirectionType effective_direction;
+ gint first_action;
+ gint last_action;
gboolean widget_is_focus;
GtkContainer *container;
container = GTK_CONTAINER (widget);
notebook = GTK_NOTEBOOK (container);
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+
+ if (notebook->tab_pos == GTK_POS_TOP ||
+ notebook->tab_pos == GTK_POS_LEFT)
+ {
+ first_action = ACTION_WIDGET_START;
+ last_action = ACTION_WIDGET_END;
+ }
+ else
+ {
+ first_action = ACTION_WIDGET_END;
+ last_action = ACTION_WIDGET_START;
+ }
if (notebook->focus_out)
{
@@ -3846,42 +4026,104 @@ gtk_notebook_focus (GtkWidget *widget,
}
widget_is_focus = gtk_widget_is_focus (widget);
- old_focus_child = container->focus_child;
+ old_focus_child = container->focus_child;
effective_direction = get_effective_direction (notebook, direction);
- if (old_focus_child) /* Focus on page child */
+ if (old_focus_child) /* Focus on page child or action widget */
{
if (gtk_widget_child_focus (old_focus_child, direction))
return TRUE;
-
- switch (effective_direction)
+
+ if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
{
- case GTK_DIR_TAB_BACKWARD:
- case GTK_DIR_UP:
- /* Focus onto the tabs */
- return focus_tabs_in (notebook);
- case GTK_DIR_DOWN:
- case GTK_DIR_TAB_FORWARD:
- case GTK_DIR_LEFT:
- case GTK_DIR_RIGHT:
- return FALSE;
+ switch (effective_direction)
+ {
+ case GTK_DIR_DOWN:
+ return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
+ case GTK_DIR_RIGHT:
+ return focus_tabs_in (notebook);
+ case GTK_DIR_LEFT:
+ return FALSE;
+ case GTK_DIR_UP:
+ return FALSE;
+ default:
+ switch (direction)
+ {
+ case GTK_DIR_TAB_FORWARD:
+ if ((notebook->tab_pos == GTK_POS_RIGHT || notebook->tab_pos == GTK_POS_BOTTOM) &&
+ focus_child_in (notebook, direction))
+ return TRUE;
+ return focus_tabs_in (notebook);
+ case GTK_DIR_TAB_BACKWARD:
+ return FALSE;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ }
+ else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
+ {
+ switch (effective_direction)
+ {
+ case GTK_DIR_DOWN:
+ return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
+ case GTK_DIR_RIGHT:
+ return FALSE;
+ case GTK_DIR_LEFT:
+ return focus_tabs_in (notebook);
+ case GTK_DIR_UP:
+ return FALSE;
+ default:
+ switch (direction)
+ {
+ case GTK_DIR_TAB_FORWARD:
+ return FALSE;
+ case GTK_DIR_TAB_BACKWARD:
+ if ((notebook->tab_pos == GTK_POS_TOP || notebook->tab_pos == GTK_POS_LEFT) &&
+ focus_child_in (notebook, direction))
+ return TRUE;
+ return focus_tabs_in (notebook);
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ }
+ else
+ {
+ switch (effective_direction)
+ {
+ case GTK_DIR_TAB_BACKWARD:
+ case GTK_DIR_UP:
+ /* Focus onto the tabs */
+ return focus_tabs_in (notebook);
+ case GTK_DIR_DOWN:
+ case GTK_DIR_LEFT:
+ case GTK_DIR_RIGHT:
+ return FALSE;
+ case GTK_DIR_TAB_FORWARD:
+ return focus_action_in (notebook, last_action, direction);
+ }
}
}
else if (widget_is_focus) /* Focus was on tabs */
{
switch (effective_direction)
{
- case GTK_DIR_TAB_BACKWARD:
- case GTK_DIR_UP:
+ case GTK_DIR_TAB_BACKWARD:
+ return focus_action_in (notebook, first_action, direction);
+ case GTK_DIR_UP:
return FALSE;
- case GTK_DIR_TAB_FORWARD:
+ case GTK_DIR_TAB_FORWARD:
+ if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
+ return TRUE;
+ return focus_action_in (notebook, last_action, direction);
case GTK_DIR_DOWN:
/* We use TAB_FORWARD rather than direction so that we focus a more
* predictable widget for the user; users may be using arrow focusing
* in this situation even if they don't usually use arrow focusing.
*/
- return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
+ return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
case GTK_DIR_LEFT:
return focus_tabs_move (notebook, direction, STEP_PREV);
case GTK_DIR_RIGHT:
@@ -3894,18 +4136,25 @@ gtk_notebook_focus (GtkWidget *widget,
{
case GTK_DIR_TAB_FORWARD:
case GTK_DIR_DOWN:
+ if (focus_action_in (notebook, first_action, direction))
+ return TRUE;
if (focus_tabs_in (notebook))
return TRUE;
+ if (focus_action_in (notebook, last_action, direction))
+ return TRUE;
if (focus_child_in (notebook, direction))
return TRUE;
return FALSE;
case GTK_DIR_TAB_BACKWARD:
- case GTK_DIR_UP:
+ if (focus_action_in (notebook, last_action, direction))
+ return TRUE;
if (focus_child_in (notebook, direction))
return TRUE;
if (focus_tabs_in (notebook))
return TRUE;
- return FALSE;
+ if (focus_action_in (notebook, first_action, direction))
+ return TRUE;
+ case GTK_DIR_UP:
case GTK_DIR_LEFT:
case GTK_DIR_RIGHT:
return focus_child_in (notebook, direction);
@@ -3914,7 +4163,7 @@ gtk_notebook_focus (GtkWidget *widget,
g_assert_not_reached ();
return FALSE;
-}
+}
static void
gtk_notebook_set_focus_child (GtkContainer *container,
@@ -3988,10 +4237,13 @@ gtk_notebook_forall (GtkContainer *container,
GtkCallback callback,
gpointer callback_data)
{
+ GtkNotebookPrivate *priv;
GtkNotebook *notebook;
GList *children;
+ gint i;
notebook = GTK_NOTEBOOK (container);
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
children = notebook->children;
while (children)
@@ -4008,6 +4260,12 @@ gtk_notebook_forall (GtkContainer *container,
(* callback) (page->tab_label, callback_data);
}
}
+
+ for (i = 0; i < N_ACTION_WIDGETS; i++)
+ {
+ if (priv->action_widget[i])
+ (* callback) (priv->action_widget[i], callback_data);
+ }
}
static GType
@@ -4831,10 +5089,13 @@ gtk_notebook_tab_space (GtkNotebook *notebook,
gint arrow_spacing;
gint scroll_arrow_hlength;
gint scroll_arrow_vlength;
+ gboolean is_rtl;
+ gint i;
widget = GTK_WIDGET (notebook);
priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
children = notebook->children;
+ is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
gtk_widget_style_get (GTK_WIDGET (notebook),
"arrow-spacing", &arrow_spacing,
@@ -4849,6 +5110,18 @@ gtk_notebook_tab_space (GtkNotebook *notebook,
*min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
*max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
+ for (i = 0; i < N_ACTION_WIDGETS; i++)
+ {
+ if (priv->action_widget[i])
+ {
+ if ((i == ACTION_WIDGET_START && !is_rtl) ||
+ (i == ACTION_WIDGET_END && is_rtl))
+ *min += priv->action_widget[i]->allocation.width + widget->style->xthickness;
+ else
+ *max -= priv->action_widget[i]->allocation.width + widget->style->xthickness;
+ }
+ }
+
while (children)
{
GtkNotebookPage *page;
@@ -4866,6 +5139,17 @@ gtk_notebook_tab_space (GtkNotebook *notebook,
*min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
*max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
+ for (i = 0; i < N_ACTION_WIDGETS; i++)
+ {
+ if (priv->action_widget[i])
+ {
+ if (i == ACTION_WIDGET_START)
+ *min += priv->action_widget[i]->allocation.height + widget->style->ythickness;
+ else
+ *max -= priv->action_widget[i]->allocation.height + widget->style->ythickness;
+ }
+ }
+
while (children)
{
GtkNotebookPage *page;
@@ -4895,8 +5179,7 @@ gtk_notebook_tab_space (GtkNotebook *notebook,
*show_arrows = TRUE;
/* take arrows into account */
- *tab_space = widget->allocation.width - tab_overlap -
- 2 * GTK_CONTAINER (notebook)->border_width;
+ *tab_space = *max - *min - tab_overlap;
if (notebook->has_after_previous)
{
@@ -4930,8 +5213,7 @@ gtk_notebook_tab_space (GtkNotebook *notebook,
*show_arrows = TRUE;
/* take arrows into account */
- *tab_space = widget->allocation.height -
- tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
+ *tab_space = *max - *min - tab_overlap;
if (notebook->has_after_previous || notebook->has_after_next)
{
@@ -7623,5 +7905,69 @@ gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
}
}
+/**
+ * gtk_notebook_get_action_widget:
+ * @notebook: a #GtkNotebook
+ * @pack_type: pack type of the action widget to receive
+ *
+ * Gets one of the action widgets. See gtk_notebook_set_action_widget().
+ *
+ * Returns: The action widget with the given @pack_type or
+ * %NULL when this action widget has not been set
+ *
+ * Since: 2.20
+ */
+GtkWidget*
+gtk_notebook_get_action_widget (GtkNotebook *notebook,
+ GtkPackType pack_type)
+{
+ GtkNotebookPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
+
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+ return priv->action_widget[pack_type];
+}
+
+/**
+ * gtk_notebook_set_action_widget:
+ * @notebook: a #GtkNotebook
+ * @widget: a #GtkWidget
+ * @pack_type: pack type of the action widget
+ *
+ * Adds @widget as action_widget to the notebook tab space. Depending
+ * on the pack type the widget will be added before or after the tabs
+ *
+ * Since: 2.20
+ */
+void
+gtk_notebook_set_action_widget (GtkNotebook *notebook,
+ GtkWidget *widget,
+ GtkPackType pack_type)
+{
+ GtkNotebookPrivate *priv;
+
+ g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
+ g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
+ g_return_if_fail (!widget || widget->parent == NULL);
+
+ priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
+
+ if (priv->action_widget[pack_type])
+ gtk_widget_unparent (priv->action_widget[pack_type]);
+
+ priv->action_widget[pack_type] = widget;
+
+ if (widget)
+ {
+ gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
+
+ if (GTK_WIDGET_REALIZED (GTK_WIDGET (notebook)))
+ gtk_widget_realize (widget);
+ }
+
+ gtk_widget_queue_resize (GTK_WIDGET (notebook));
+}
+
#define __GTK_NOTEBOOK_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtknotebook.h b/gtk/gtknotebook.h
index 41bbe66979..0a14a75617 100644
--- a/gtk/gtknotebook.h
+++ b/gtk/gtknotebook.h
@@ -287,6 +287,12 @@ void gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
GtkWidget *child,
gboolean detachable);
+GtkWidget* gtk_notebook_get_action_widget (GtkNotebook *notebook,
+ GtkPackType pack_type);
+void gtk_notebook_set_action_widget (GtkNotebook *notebook,
+ GtkWidget *widget,
+ GtkPackType pack_type);
+
#ifndef GTK_DISABLE_DEPRECATED
#define gtk_notebook_current_page gtk_notebook_get_current_page
#define gtk_notebook_set_page gtk_notebook_set_current_page