0d2a6cd72f
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.
1091 lines
35 KiB
C
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);
|
|
}
|
|
|