midori/midori/midori-panel.c
Christian Dywan 0d2a6cd72f Sort out boxes and scrollables with GTK+ 3.2
There is only GtkBox, neither GtkHBox nor GtkVBox.

Constructors and defaults have changed, we need
to set "orientation" for vertical boxes.

The panel takes care of its pages, and the view
of itself.

gtk_container_add on GtkBox is different to GtkVBox
so we must use gtk_box_pack_start.

GtkScrollable exists as a proper interface now.
2011-11-20 22:14:30 +01:00

1091 lines
35 KiB
C

/*
Copyright (C) 2007-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#include "midori-panel.h"
#include "midori-browser.h"
#include "midori-platform.h"
#include "midori-view.h"
#include "marshal.h"
#include <glib/gi18n.h>
#include "config.h"
#ifdef HAVE_HILDON_2_2
#include <hildon/hildon.h>
#endif
struct _MidoriPanel
{
GtkHBox parent_instance;
GtkWidget* labelbar;
GtkWidget* toolbar;
GtkToolItem* button_align;
GtkWidget* toolbar_label;
GtkWidget* frame;
GtkWidget* toolbook;
GtkWidget* notebook;
GtkActionGroup* action_group;
gboolean show_titles;
gboolean show_controls;
gboolean right_aligned;
gboolean open_panels_in_windows;
};
struct _MidoriPanelClass
{
GtkHBoxClass parent_class;
/* Signals */
gboolean
(*close) (MidoriPanel* panel);
};
G_DEFINE_TYPE (MidoriPanel, midori_panel, GTK_TYPE_HBOX)
enum
{
PROP_0,
PROP_SHADOW_TYPE,
PROP_ACTION_GROUP,
PROP_PAGE,
PROP_SHOW_TITLES,
PROP_SHOW_CONTROLS,
PROP_RIGHT_ALIGNED,
PROP_OPEN_PANELS_IN_WINDOWS,
};
enum {
CLOSE,
SWITCH_PAGE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
static void
midori_panel_finalize (GObject* object);
static void
midori_panel_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec);
static void
midori_panel_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec);
static gboolean
midori_panel_close (MidoriPanel* panel)
{
gtk_widget_hide (GTK_WIDGET (panel));
return FALSE;
}
static void
midori_panel_class_init (MidoriPanelClass* class)
{
GObjectClass* gobject_class;
GParamFlags flags;
signals[CLOSE] = g_signal_new (
"close",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
G_STRUCT_OFFSET (MidoriPanelClass, close),
g_signal_accumulator_true_handled,
NULL,
midori_cclosure_marshal_BOOLEAN__VOID,
G_TYPE_BOOLEAN, 0);
signals[SWITCH_PAGE] = g_signal_new (
"switch-page",
G_TYPE_FROM_CLASS (class),
(GSignalFlags)(G_SIGNAL_RUN_LAST),
0,
0,
NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE, 1,
G_TYPE_INT);
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = midori_panel_finalize;
gobject_class->set_property = midori_panel_set_property;
gobject_class->get_property = midori_panel_get_property;
class->close = midori_panel_close;
flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS;
g_object_class_install_property (gobject_class,
PROP_SHADOW_TYPE,
g_param_spec_enum (
"shadow-type",
"Shadow Type",
"Appearance of the shadow around each panel",
GTK_TYPE_SHADOW_TYPE,
GTK_SHADOW_NONE,
flags));
/**
* MidoriWebSettings:action-group:
*
* This is the action group the panel will add actions
* corresponding to pages to.
*
* Since: 0.2.1
*/
g_object_class_install_property (gobject_class,
PROP_ACTION_GROUP,
g_param_spec_object (
"action-group",
"Action Group",
"The action group the panel will add actions to",
GTK_TYPE_ACTION_GROUP,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_PAGE,
g_param_spec_int (
"page",
"Page",
"The index of the current page",
-1, G_MAXINT, -1,
flags));
/**
* MidoriWebSettings:show-titles:
*
* Whether to show panel titles.
*
* Deprecated: 0.2.3
*/
g_object_class_install_property (gobject_class,
PROP_SHOW_TITLES,
g_param_spec_boolean (
"show-titles",
"Show Titles",
"Whether to show panel titles",
TRUE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* MidoriWebSettings:show-controls:
*
* Whether to show operating controls.
*
* Since: 0.1.9
*
* Deprecated: 0.3.0
*/
g_object_class_install_property (gobject_class,
PROP_SHOW_CONTROLS,
g_param_spec_boolean (
"show-controls",
"Show Controls",
"Whether to show operating controls",
TRUE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* MidoriWebSettings:right-aligned:
*
* Whether to align the panel on the right.
*
* Since: 0.1.3
*/
g_object_class_install_property (gobject_class,
PROP_RIGHT_ALIGNED,
g_param_spec_boolean (
"right-aligned",
"Right aligned",
"Whether the panel is aligned to the right",
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* MidoriWebSettings:open-panels-in-windows:
*
* Whether to open panels in separate windows.
*
* Since: 0.2.2
*/
g_object_class_install_property (gobject_class,
PROP_OPEN_PANELS_IN_WINDOWS,
g_param_spec_boolean (
"open-panels-in-windows",
"Open panels in windows",
"Whether to open panels in standalone windows by default",
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
midori_panel_button_close_clicked_cb (GtkWidget* toolitem,
MidoriPanel* panel)
{
gboolean return_value;
g_signal_emit (panel, signals[CLOSE], 0, &return_value);
}
static GtkToolItem*
midori_panel_construct_tool_item (MidoriPanel* panel,
MidoriViewable* viewable);
static GtkWidget*
_midori_panel_child_for_scrolled (MidoriPanel* panel,
GtkWidget* scrolled);
static gboolean
midori_panel_detached_window_delete_event_cb (GtkWidget* window,
GdkEvent* event,
MidoriPanel* panel)
{
/* FIXME: The panel will not end up at its original position */
/* FIXME: The menuitem may be mispositioned */
GtkWidget* vbox = gtk_bin_get_child (GTK_BIN (window));
GtkWidget* scrolled = g_object_get_data (G_OBJECT (window), "scrolled");
GtkWidget* toolbar = g_object_get_data (G_OBJECT (scrolled), "panel-toolbar");
GtkWidget* menuitem = g_object_get_data (G_OBJECT (scrolled), "panel-menuitem");
GtkWidget* viewable = _midori_panel_child_for_scrolled (panel, scrolled);
GtkToolItem* toolitem;
gint n;
g_object_ref (toolbar);
gtk_container_remove (GTK_CONTAINER (vbox), toolbar);
gtk_container_add (GTK_CONTAINER (panel->toolbook), toolbar);
g_object_unref (toolbar);
g_object_ref (scrolled);
gtk_container_remove (GTK_CONTAINER (vbox), scrolled);
n = gtk_notebook_append_page (GTK_NOTEBOOK (panel->notebook), scrolled, NULL);
g_object_unref (scrolled);
toolitem = midori_panel_construct_tool_item (panel, MIDORI_VIEWABLE (viewable));
if (menuitem)
g_object_set_data (G_OBJECT (menuitem), "toolitem", toolitem);
midori_panel_set_current_page (panel, n);
return FALSE;
}
static void
midori_panel_widget_destroy_cb (GtkWidget* viewable,
GtkWidget* widget)
{
gtk_widget_destroy (widget);
g_signal_handlers_disconnect_by_func (
viewable, midori_panel_widget_destroy_cb, widget);
}
static void
midori_panel_detach_page (MidoriPanel* panel,
gint n)
{
GtkToolItem* toolitem = gtk_toolbar_get_nth_item (
GTK_TOOLBAR (panel->toolbar), n);
const gchar* title = gtk_tool_button_get_label (GTK_TOOL_BUTTON (toolitem));
GtkWidget* toolbar = gtk_notebook_get_nth_page (
GTK_NOTEBOOK (panel->toolbook), n);
GtkWidget* scrolled = gtk_notebook_get_nth_page (
GTK_NOTEBOOK (panel->notebook), n);
GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
#if HAVE_HILDON
GtkWidget* window = hildon_window_new ();
hildon_program_add_window (hildon_program_get_instance (), HILDON_WINDOW (window));
#else
GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
gtk_window_set_default_size (GTK_WINDOW (window), 250, 400);
gtk_window_set_transient_for (GTK_WINDOW (window),
GTK_WINDOW (gtk_widget_get_toplevel (panel->notebook)));
#endif
gtk_widget_show (vbox);
gtk_container_add (GTK_CONTAINER (window), vbox);
g_object_set_data (G_OBJECT (window), "scrolled", scrolled);
gtk_window_set_title (GTK_WINDOW (window), title);
g_signal_handlers_disconnect_by_func (
_midori_panel_child_for_scrolled (panel, scrolled),
midori_panel_widget_destroy_cb, toolitem);
gtk_container_remove (GTK_CONTAINER (panel->toolbar), GTK_WIDGET (toolitem));
g_object_ref (toolbar);
gtk_container_remove (GTK_CONTAINER (panel->toolbook), toolbar);
#if HAVE_HILDON
hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (toolbar));
#else
gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
#endif
g_object_unref (toolbar);
g_object_set_data (G_OBJECT (scrolled), "panel-toolbar", toolbar);
g_object_ref (scrolled);
gtk_container_remove (GTK_CONTAINER (panel->notebook), scrolled);
gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
g_object_unref (scrolled);
midori_panel_set_current_page (panel, n > 0 ? n - 1 : 0);
toolitem = gtk_toolbar_get_nth_item (GTK_TOOLBAR (panel->toolbar),
n > 0 ? n - 1 : 0);
g_signal_connect (window, "delete-event",
G_CALLBACK (midori_panel_detached_window_delete_event_cb), panel);
gtk_widget_show (window);
}
static void
midori_panel_button_align_clicked_cb (GtkWidget* toolitem,
MidoriPanel* panel)
{
midori_panel_set_right_aligned (panel, !panel->right_aligned);
}
static void
midori_panel_destroy_cb (MidoriPanel* panel)
{
/* Destroy pages first, so they don't need special care */
gtk_container_foreach (GTK_CONTAINER (panel->notebook),
(GtkCallback) gtk_widget_destroy, NULL);
}
static void
midori_panel_init (MidoriPanel* panel)
{
GtkWidget* vbox;
GtkWidget* labelbar;
GtkToolItem* toolitem;
panel->action_group = NULL;
panel->show_titles = TRUE;
panel->show_controls = TRUE;
panel->right_aligned = FALSE;
/* Create the sidebar */
panel->toolbar = gtk_toolbar_new ();
gtk_toolbar_set_icon_size (GTK_TOOLBAR (panel->toolbar), GTK_ICON_SIZE_BUTTON);
gtk_toolbar_set_show_arrow (GTK_TOOLBAR (panel->toolbar), FALSE);
gtk_widget_show_all (panel->toolbar);
vbox = gtk_vbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (panel), vbox, TRUE, TRUE, 0);
gtk_box_pack_end (GTK_BOX (vbox), panel->toolbar, FALSE, FALSE, 0);
/* Create the titlebar */
labelbar = gtk_toolbar_new ();
panel->labelbar = labelbar;
gtk_toolbar_set_icon_size (GTK_TOOLBAR (labelbar), GTK_ICON_SIZE_MENU);
gtk_toolbar_set_style (GTK_TOOLBAR (labelbar), GTK_TOOLBAR_ICONS);
toolitem = gtk_tool_item_new ();
gtk_tool_item_set_expand (toolitem, TRUE);
panel->toolbar_label = gtk_label_new (NULL);
gtk_label_set_ellipsize (GTK_LABEL (panel->toolbar_label), PANGO_ELLIPSIZE_END);
gtk_misc_set_alignment (GTK_MISC (panel->toolbar_label), 0, 0.5);
gtk_container_add (GTK_CONTAINER (toolitem), panel->toolbar_label);
gtk_container_set_border_width (GTK_CONTAINER (toolitem), 6);
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1);
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_GO_FORWARD);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem),
_("Align sidepanel to the right"));
gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (toolitem),
_("Align sidepanel to the right"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_panel_button_align_clicked_cb), panel);
#if HAVE_OSX
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, 0);
#else
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1);
#endif
panel->button_align = toolitem;
toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_CLOSE);
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), _("Close panel"));
gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (toolitem), _("Close panel"));
g_signal_connect (toolitem, "clicked",
G_CALLBACK (midori_panel_button_close_clicked_cb), panel);
#if HAVE_OSX
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, 0);
#else
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1);
#endif
gtk_box_pack_start (GTK_BOX (vbox), labelbar, FALSE, FALSE, 0);
gtk_widget_show_all (vbox);
/* Create the toolbook */
panel->toolbook = gtk_notebook_new ();
gtk_notebook_set_show_border (GTK_NOTEBOOK (panel->toolbook), FALSE);
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (panel->toolbook), FALSE);
gtk_box_pack_start (GTK_BOX (vbox), panel->toolbook, FALSE, FALSE, 0);
/* Create the notebook */
panel->notebook = gtk_notebook_new ();
gtk_notebook_set_show_border (GTK_NOTEBOOK (panel->notebook), FALSE);
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (panel->notebook), FALSE);
panel->frame = gtk_frame_new (NULL);
gtk_container_add (GTK_CONTAINER (panel->frame), panel->notebook);
gtk_box_pack_start (GTK_BOX (vbox), panel->frame, TRUE, TRUE, 0);
gtk_widget_show_all (panel->frame);
g_signal_connect (panel, "destroy",
G_CALLBACK (midori_panel_destroy_cb), NULL);
}
static void
midori_panel_finalize (GObject* object)
{
G_OBJECT_CLASS (midori_panel_parent_class)->finalize (object);
}
static void
midori_panel_set_property (GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec)
{
MidoriPanel* panel = MIDORI_PANEL (object);
switch (prop_id)
{
case PROP_SHADOW_TYPE:
gtk_frame_set_shadow_type (GTK_FRAME (panel->frame),
g_value_get_enum (value));
break;
case PROP_ACTION_GROUP:
katze_object_assign (panel->action_group, g_value_dup_object (value));
break;
case PROP_PAGE:
midori_panel_set_current_page (panel, g_value_get_int (value));
break;
case PROP_SHOW_TITLES:
panel->show_titles = g_value_get_boolean (value);
/* Ignore */
break;
case PROP_SHOW_CONTROLS:
panel->show_controls = g_value_get_boolean (value);
break;
case PROP_RIGHT_ALIGNED:
midori_panel_set_right_aligned (panel, g_value_get_boolean (value));
break;
case PROP_OPEN_PANELS_IN_WINDOWS:
panel->open_panels_in_windows = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
midori_panel_get_property (GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec)
{
MidoriPanel* panel = MIDORI_PANEL (object);
switch (prop_id)
{
case PROP_SHADOW_TYPE:
g_value_set_enum (value,
gtk_frame_get_shadow_type (GTK_FRAME (panel->frame)));
break;
case PROP_ACTION_GROUP:
g_value_set_object (value, panel->action_group);
break;
case PROP_PAGE:
g_value_set_int (value, midori_panel_get_current_page (panel));
break;
case PROP_SHOW_TITLES:
g_value_set_boolean (value, panel->show_titles);
break;
case PROP_SHOW_CONTROLS:
g_value_set_boolean (value, panel->show_controls);
break;
case PROP_RIGHT_ALIGNED:
g_value_set_boolean (value, panel->right_aligned);
break;
case PROP_OPEN_PANELS_IN_WINDOWS:
g_value_set_boolean (value, panel->open_panels_in_windows);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* midori_panel_new:
*
* Creates a new empty panel.
*
* Return value: a new #MidoriPanel
**/
GtkWidget*
midori_panel_new (void)
{
MidoriPanel* panel = g_object_new (MIDORI_TYPE_PANEL,
NULL);
return GTK_WIDGET (panel);
}
/**
* midori_panel_set_right_aligned:
* @right_aligned: %TRUE if the panel should be aligned to the right
*
* Determines if the panel should be right aligned.
*
* Since: 0.1.3
**/
void
midori_panel_set_right_aligned (MidoriPanel* panel,
gboolean right_aligned)
{
GtkWidget* box;
g_return_if_fail (MIDORI_IS_PANEL (panel));
box = gtk_widget_get_parent (panel->toolbar);
gtk_box_reorder_child (GTK_BOX (box), panel->toolbar,
right_aligned ? -1 : 0);
gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (panel->button_align),
right_aligned ? GTK_STOCK_GO_BACK : GTK_STOCK_GO_FORWARD);
panel->right_aligned = right_aligned;
gtk_tool_button_set_label (GTK_TOOL_BUTTON (panel->button_align),
!panel->right_aligned ? _("Align sidepanel to the right")
: _("Align sidepanel to the left"));
gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (panel->button_align),
!panel->right_aligned ? _("Align sidepanel to the right")
: _("Align sidepanel to the left"));
g_object_notify (G_OBJECT (panel), "right-aligned");
}
/* Private function, used by MidoriBrowser */
/* static */ GtkWidget*
midori_panel_construct_menu_item (MidoriPanel* panel,
MidoriViewable* viewable)
{
GtkAction* action;
GtkWidget* menuitem;
action = g_object_get_data (G_OBJECT (viewable), "midori-panel-action");
menuitem = gtk_action_create_menu_item (action);
g_object_set_data (G_OBJECT (menuitem), "page", viewable);
if (gtk_widget_get_visible (GTK_WIDGET (viewable)))
gtk_widget_show (menuitem);
return menuitem;
}
static void
midori_panel_viewable_destroy_cb (GtkWidget* viewable,
MidoriPanel* panel)
{
MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (panel));
gint n_pages;
gchar* action_name;
GtkAction* action;
gint i;
i = gtk_notebook_page_num (GTK_NOTEBOOK (panel->notebook),
g_object_get_data (G_OBJECT (viewable), "parent"));
if (i > -1)
gtk_notebook_remove_page (GTK_NOTEBOOK (panel->notebook), i);
g_signal_handlers_disconnect_by_func (
viewable, midori_panel_viewable_destroy_cb, panel);
n_pages = midori_panel_get_n_pages (panel);
if (n_pages > 0 && browser && !g_object_get_data (G_OBJECT (browser), "midori-browser-destroyed"))
midori_panel_set_current_page (panel, (n_pages-1 > i) ? i : n_pages - 1);
action_name = g_strconcat ("PanelPage",
midori_viewable_get_stock_id (MIDORI_VIEWABLE (viewable)), NULL);
action = gtk_action_group_get_action (panel->action_group, action_name);
g_free (action_name);
gtk_action_group_remove_action (panel->action_group, action);
g_object_unref (G_OBJECT (action));
}
static GtkToolItem*
midori_panel_construct_tool_item (MidoriPanel* panel,
MidoriViewable* viewable)
{
GtkAction* action;
GtkWidget* toolitem;
action = g_object_get_data (G_OBJECT (viewable), "midori-panel-action");
toolitem = gtk_action_create_tool_item (action);
g_object_set_data (G_OBJECT (toolitem), "page", viewable);
gtk_toolbar_insert (GTK_TOOLBAR (panel->toolbar), GTK_TOOL_ITEM (toolitem), -1);
g_signal_connect (viewable, "destroy",
G_CALLBACK (midori_panel_widget_destroy_cb), toolitem);
return GTK_TOOL_ITEM (toolitem);
}
static void
midori_panel_action_activate_cb (GtkRadioAction* action,
MidoriPanel* panel)
{
GtkWidget* viewable = g_object_get_data (G_OBJECT (action), "viewable");
gint n = midori_panel_page_num (panel, viewable);
/* If the panel is detached, focus the window */
if (n == -1)
{
GtkWidget* toplevel = gtk_widget_get_toplevel (viewable);
gtk_window_present (GTK_WINDOW (toplevel));
return;
}
if (panel->open_panels_in_windows
&& gtk_radio_action_get_current_value (action)
== katze_object_get_int (action, "value"))
midori_panel_detach_page (panel, n);
else
{
midori_panel_set_current_page (panel, n);
g_signal_emit (panel, signals[SWITCH_PAGE], 0, n);
gtk_widget_show (GTK_WIDGET (panel));
}
}
/**
* midori_panel_append_page:
* @panel: a #MidoriPanel
* @viewable: a viewable widget
* @toolbar: a toolbar widget, or %NULL
* @stock_id: a stock ID
* @label: a string to use as the label
*
* Appends a new page to the panel. If @toolbar is specified it will
* be packed above @viewable.
*
* Since 0.1.3 destroying the @viewable implicitly removes
* the page including the menu and eventual toolbar.
*
* Since 0.2.1 a hidden @viewable will not be shown in the panel.
*
* Since 0.2.1 an action with an accelerator is created implicitly.
*
* In the case of an error, -1 is returned.
*
* Return value: the index of the new page, or -1
**/
gint
midori_panel_append_page (MidoriPanel* panel,
MidoriViewable* viewable)
{
GtkWidget* scrolled;
#if !GTK_CHECK_VERSION (3, 0, 0)
GObjectClass* gobject_class;
#endif
GtkWidget* widget;
GtkWidget* toolbar;
GtkToolItem* toolitem;
guint n;
gchar* action_name;
GtkAction* action;
g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1);
g_return_val_if_fail (MIDORI_IS_VIEWABLE (viewable), -1);
#if GTK_CHECK_VERSION (3, 2, 0)
if (GTK_IS_ORIENTABLE (viewable))
gtk_orientable_set_orientation (GTK_ORIENTABLE (viewable),
GTK_ORIENTATION_VERTICAL);
#endif
if (GTK_IS_SCROLLED_WINDOW (viewable))
scrolled = (GtkWidget*)viewable;
else
{
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_widget_set_can_focus (scrolled, TRUE);
gtk_widget_show (scrolled);
#if GTK_CHECK_VERSION (3, 0, 0)
if (GTK_IS_SCROLLABLE (viewable))
#else
gobject_class = G_OBJECT_GET_CLASS (viewable);
if (GTK_WIDGET_CLASS (gobject_class)->set_scroll_adjustments_signal)
#endif
widget = (GtkWidget*)viewable;
else
{
widget = gtk_viewport_new (NULL, NULL);
gtk_widget_show (widget);
gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (viewable));
}
gtk_container_add (GTK_CONTAINER (scrolled), widget);
}
gtk_container_add (GTK_CONTAINER (panel->notebook), scrolled);
toolbar = midori_viewable_get_toolbar (viewable);
gtk_widget_show (toolbar);
gtk_container_add (GTK_CONTAINER (panel->toolbook), toolbar);
g_signal_connect (viewable, "destroy",
G_CALLBACK (midori_panel_widget_destroy_cb), toolbar);
n = midori_panel_get_n_pages (panel) - 1;
/* FIXME: Use something better than the stock ID */
action_name = g_strconcat ("PanelPage",
midori_viewable_get_stock_id (viewable), NULL);
action = (GtkAction*)gtk_radio_action_new (action_name,
midori_viewable_get_label (viewable),
midori_viewable_get_label (viewable),
midori_viewable_get_stock_id (viewable), n);
g_object_set_data (G_OBJECT (action), "viewable", viewable);
g_signal_connect (action, "activate",
G_CALLBACK (midori_panel_action_activate_cb), panel);
if (panel->action_group)
{
GtkWidget* toplevel = gtk_widget_get_toplevel (GTK_WIDGET (panel));
GSList* groups = gtk_accel_groups_from_object (G_OBJECT (toplevel));
gtk_action_set_accel_group (action, g_slist_nth_data (groups, 0));
gtk_action_group_add_action_with_accel (panel->action_group,
action, NULL);
gtk_action_connect_accelerator (action);
}
if (n > 0)
g_object_set (action, "group", g_object_get_data (
G_OBJECT (midori_panel_get_nth_page (panel, 0)),
"midori-panel-action"), NULL);
g_object_set_data (G_OBJECT (viewable), "midori-panel-action", action);
g_free (action_name);
g_object_set_data (G_OBJECT (viewable), "parent", scrolled);
toolitem = midori_panel_construct_tool_item (panel, viewable);
g_signal_connect (viewable, "destroy",
G_CALLBACK (midori_panel_viewable_destroy_cb), panel);
if (!gtk_widget_get_visible (GTK_WIDGET (viewable)))
{
gtk_widget_hide (scrolled);
gtk_widget_hide (GTK_WIDGET (toolitem));
}
return n;
}
/**
* midori_panel_get_current_page:
* @panel: a #MidoriPanel
*
* Retrieves the index of the currently selected page.
*
* If @panel has no children, -1 is returned.
*
* Return value: the index of the current page, or -1
**/
gint
midori_panel_get_current_page (MidoriPanel* panel)
{
g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1);
return gtk_notebook_get_current_page (GTK_NOTEBOOK (panel->notebook));
}
static GtkWidget*
_midori_panel_child_for_scrolled (MidoriPanel* panel,
GtkWidget* scrolled)
{
GtkWidget* child;
/* This is a lazy hack, we should have a way of determining
whether the scrolled is the actual child. */
if (MIDORI_IS_VIEW (scrolled))
return scrolled;
child = gtk_bin_get_child (GTK_BIN (scrolled));
if (GTK_IS_VIEWPORT (child))
child = gtk_bin_get_child (GTK_BIN (child));
return child;
}
/**
* midori_panel_get_nth_page:
* @panel: a #MidoriPanel
*
* Retrieves the child widget of the nth page.
*
* If @panel has no children, %NULL is returned.
*
* Return value: the child widget of the new page, or %NULL
**/
GtkWidget*
midori_panel_get_nth_page (MidoriPanel* panel,
guint page_num)
{
GtkWidget* scrolled;
g_return_val_if_fail (MIDORI_IS_PANEL (panel), NULL);
scrolled = gtk_notebook_get_nth_page (
GTK_NOTEBOOK (panel->notebook), page_num);
if (scrolled)
return _midori_panel_child_for_scrolled (panel, scrolled);
return NULL;
}
/**
* midori_panel_get_n_pages:
* @panel: a #MidoriPanel
*
* Retrieves the number of pages contained in the panel.
*
* Return value: the number of pages
**/
guint
midori_panel_get_n_pages (MidoriPanel* panel)
{
g_return_val_if_fail (MIDORI_IS_PANEL (panel), 0);
return gtk_notebook_get_n_pages (GTK_NOTEBOOK (panel->notebook));
}
static GtkWidget*
_midori_panel_scrolled_for_child (MidoriPanel* panel,
GtkWidget* child)
{
GtkWidget* scrolled;
/* This is a lazy hack, we should have a way of determining
whether the scrolled is the actual child. */
if (MIDORI_IS_VIEW (child))
return child;
scrolled = gtk_widget_get_parent (GTK_WIDGET (child));
if (GTK_IS_VIEWPORT (scrolled))
scrolled = gtk_widget_get_parent (scrolled);
return scrolled;
}
/**
* midori_panel_page_num:
* @panel: a #MidoriPanel
*
* Retrieves the index of the page associated to @widget.
*
* If @panel has no children, -1 is returned.
*
* Return value: the index of page associated to @widget, or -1
**/
gint
midori_panel_page_num (MidoriPanel* panel,
GtkWidget* child)
{
GtkWidget* scrolled;
g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1);
g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
scrolled = _midori_panel_scrolled_for_child (panel, child);
return gtk_notebook_page_num (GTK_NOTEBOOK (panel->notebook), scrolled);
}
/**
* midori_panel_set_current_page:
* @panel: a #MidoriPanel
* @n: index of the page to switch to, or -1 to mean the last page
*
* Switches to the page with the given index.
*
* The child must be visible, otherwise the underlying GtkNotebook will
* silently ignore the attempt to switch the page.
*
* Since 0.1.8 the "page" property is notifying changes.
*
* Since 0.2.1 switching to hidden pages fails silently.
**/
void
midori_panel_set_current_page (MidoriPanel* panel,
gint n)
{
GtkWidget* viewable;
g_return_if_fail (MIDORI_IS_PANEL (panel));
if ((viewable = midori_panel_get_nth_page (panel, n)))
{
GtkWidget* toolbar;
GList* items;
const gchar* label;
if (!gtk_widget_get_visible (viewable))
return;
gtk_notebook_set_current_page (GTK_NOTEBOOK (panel->toolbook), n);
toolbar = gtk_notebook_get_nth_page (GTK_NOTEBOOK (panel->toolbook), n);
items = gtk_container_get_children (GTK_CONTAINER (toolbar));
sokoke_widget_set_visible (panel->toolbook, items != NULL);
g_list_free (items);
gtk_notebook_set_current_page (GTK_NOTEBOOK (panel->notebook), n);
label = midori_viewable_get_label (MIDORI_VIEWABLE (viewable));
g_object_set (panel->toolbar_label, "label", label, NULL);
g_object_notify (G_OBJECT (panel), "page");
}
}
typedef struct
{
GtkAlignment parent_instance;
gchar* label;
gchar* stock_id;
GtkWidget* toolbar;
} MidoriDummyViewable;
typedef struct
{
GtkAlignmentClass parent_class;
} MidoriDummyViewableClass;
GType midori_dummy_viewable_get_type (void) G_GNUC_CONST;
#define MIDORI_TYPE_DUMMY_VIEWABLE (midori_dummy_viewable_get_type ())
#define MIDORI_DUMMY_VIEWABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
MIDORI_TYPE_DUMMY_VIEWABLE, MidoriDummyViewable))
#define MIDORI_IS_DUMMY_VIEWABLE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_DUMMY_VIEWABLE))
static void
midori_dummy_viewable_iface_init (MidoriViewableIface* iface);
static void
midori_dummy_viewable_finalize (GObject* object);
G_DEFINE_TYPE_WITH_CODE (MidoriDummyViewable, midori_dummy_viewable,
GTK_TYPE_ALIGNMENT,
G_IMPLEMENT_INTERFACE (MIDORI_TYPE_VIEWABLE,
midori_dummy_viewable_iface_init));
static void
midori_dummy_viewable_class_init (MidoriDummyViewableClass* class)
{
GObjectClass* gobject_class;
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = midori_dummy_viewable_finalize;
}
static const gchar*
midori_dummy_viewable_get_label (MidoriViewable* viewable)
{
return MIDORI_DUMMY_VIEWABLE (viewable)->label;
}
static const gchar*
midori_dummy_viewable_get_stock_id (MidoriViewable* viewable)
{
return MIDORI_DUMMY_VIEWABLE (viewable)->stock_id;
}
static GtkWidget*
midori_dummy_viewable_get_toolbar (MidoriViewable* viewable)
{
return MIDORI_DUMMY_VIEWABLE (viewable)->toolbar;
}
static void
midori_dummy_viewable_iface_init (MidoriViewableIface* iface)
{
iface->get_stock_id = midori_dummy_viewable_get_stock_id;
iface->get_label = midori_dummy_viewable_get_label;
iface->get_toolbar = midori_dummy_viewable_get_toolbar;
}
static void
midori_dummy_viewable_init (MidoriDummyViewable* viewable)
{
viewable->stock_id = NULL;
viewable->label = NULL;
viewable->toolbar = NULL;
}
static void
midori_dummy_viewable_finalize (GObject* object)
{
MidoriDummyViewable* viewable = MIDORI_DUMMY_VIEWABLE (object);
katze_assign (viewable->stock_id, NULL);
katze_assign (viewable->label, NULL);
G_OBJECT_CLASS (midori_dummy_viewable_parent_class)->finalize (object);
}
/* static */ GtkWidget*
midori_dummy_viewable_new (const gchar* stock_id,
const gchar* label,
GtkWidget* toolbar)
{
GtkWidget* viewable = g_object_new (MIDORI_TYPE_DUMMY_VIEWABLE, NULL);
MIDORI_DUMMY_VIEWABLE (viewable)->stock_id = g_strdup (stock_id);
MIDORI_DUMMY_VIEWABLE (viewable)->label = g_strdup (label);
MIDORI_DUMMY_VIEWABLE (viewable)->toolbar = toolbar;
return viewable;
}
/**
* midori_panel_append_widget:
* @panel: a #MidoriPanel
* @widget: the child widget
* @stock_id: a stock ID
* @label: a string to use as the label, or %NULL
* @toolbar: a toolbar widget, or %NULL
*
* Appends an arbitrary widget to the panel by wrapping it
* in a #MidoriViewable created on the fly.
*
* Actually implementing #MidoriViewable instead of using
* this convenience is recommended.
*
* Since 0.1.3 destroying the @widget implicitly removes
* the page including the menu and eventual toolbar.
*
* In the case of an error, -1 is returned.
*
* Return value: the index of the new page, or -1
**/
gint
midori_panel_append_widget (MidoriPanel* panel,
GtkWidget* widget,
const gchar* stock_id,
const gchar* label,
GtkWidget* toolbar)
{
GtkWidget* viewable;
g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1);
g_return_val_if_fail (GTK_IS_WIDGET (widget), -1);
g_return_val_if_fail (stock_id != NULL, -1);
g_return_val_if_fail (!toolbar || GTK_IS_WIDGET (toolbar), -1);
viewable = midori_dummy_viewable_new (stock_id, label, toolbar);
gtk_widget_show (viewable);
gtk_container_add (GTK_CONTAINER (viewable), widget);
g_signal_connect (widget, "destroy",
G_CALLBACK (midori_panel_widget_destroy_cb), viewable);
return midori_panel_append_page (panel, MIDORI_VIEWABLE (viewable));
}
/* Private function, used by MidoriBrowser */
void
midori_panel_set_toolbar_style (MidoriPanel* panel,
GtkToolbarStyle style)
{
g_return_if_fail (MIDORI_IS_PANEL (panel));
gtk_toolbar_set_style (GTK_TOOLBAR (panel->toolbar), style);
}