4a488da7b1
The new singleton holds the shared settings and trash. It is further more used to keep track of all open windows and quits when the last window was closed. It also watches the focus in case you need something like a "current" browser.
562 lines
18 KiB
C
562 lines
18 KiB
C
/*
|
|
Copyright (C) 2007-2008 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 "sokoke.h"
|
|
#include <glib/gi18n.h>
|
|
|
|
G_DEFINE_TYPE (MidoriPanel, midori_panel, GTK_TYPE_HBOX)
|
|
|
|
struct _MidoriPanelPrivate
|
|
{
|
|
GtkWidget* toolbar;
|
|
GtkWidget* toolbar_label;
|
|
GtkWidget* frame;
|
|
GtkWidget* toolbook;
|
|
GtkWidget* notebook;
|
|
GSList* group;
|
|
GtkMenu* menu;
|
|
};
|
|
|
|
#define MIDORI_PANEL_GET_PRIVATE(obj) \
|
|
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
|
|
MIDORI_TYPE_PANEL, MidoriPanelPrivate))
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
|
|
PROP_SHADOW_TYPE,
|
|
PROP_MENU,
|
|
PROP_PAGE
|
|
};
|
|
|
|
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_cb (MidoriPanel* panel)
|
|
{
|
|
gtk_widget_hide (GTK_WIDGET (panel));
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
midori_cclosure_marshal_BOOLEAN__VOID (GClosure* closure,
|
|
GValue* return_value,
|
|
guint n_param_values,
|
|
const GValue* param_values,
|
|
gpointer invocation_hint,
|
|
gpointer marshal_data)
|
|
{
|
|
typedef gboolean(*GMarshalFunc_BOOLEAN__VOID) (gpointer data1,
|
|
gpointer data2);
|
|
register GMarshalFunc_BOOLEAN__VOID callback;
|
|
register GCClosure* cc = (GCClosure*) closure;
|
|
register gpointer data1, data2;
|
|
gboolean v_return;
|
|
|
|
g_return_if_fail (return_value != NULL);
|
|
g_return_if_fail (n_param_values == 1);
|
|
|
|
if (G_CCLOSURE_SWAP_DATA (closure))
|
|
{
|
|
data1 = closure->data;
|
|
data2 = g_value_peek_pointer (param_values + 0);
|
|
}
|
|
else
|
|
{
|
|
data1 = g_value_peek_pointer (param_values + 0);
|
|
data2 = closure->data;
|
|
}
|
|
callback = (GMarshalFunc_BOOLEAN__VOID) (marshal_data
|
|
? marshal_data : cc->callback);
|
|
v_return = callback (data1, data2);
|
|
g_value_set_boolean (return_value, v_return);
|
|
}
|
|
|
|
static void
|
|
midori_panel_class_init (MidoriPanelClass* class)
|
|
{
|
|
|
|
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),
|
|
G_STRUCT_OFFSET (MidoriPanelClass, switch_page),
|
|
0,
|
|
NULL,
|
|
g_cclosure_marshal_VOID__INT,
|
|
G_TYPE_NONE, 1,
|
|
G_TYPE_INT);
|
|
|
|
class->close = midori_panel_close_cb;
|
|
|
|
GObjectClass* 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;
|
|
|
|
GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
|
|
|
|
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));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_MENU,
|
|
g_param_spec_object (
|
|
"menu",
|
|
"Menu",
|
|
_("Menu to hold panel items"),
|
|
GTK_TYPE_MENU,
|
|
G_PARAM_READWRITE));
|
|
|
|
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));
|
|
|
|
g_type_class_add_private (class, sizeof (MidoriPanelPrivate));
|
|
}
|
|
|
|
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 void
|
|
midori_panel_init (MidoriPanel* panel)
|
|
{
|
|
panel->priv = MIDORI_PANEL_GET_PRIVATE (panel);
|
|
|
|
MidoriPanelPrivate* priv = panel->priv;
|
|
|
|
// Create the sidebar
|
|
priv->toolbar = gtk_toolbar_new ();
|
|
gtk_toolbar_set_style (GTK_TOOLBAR (priv->toolbar), GTK_TOOLBAR_BOTH);
|
|
gtk_toolbar_set_icon_size (GTK_TOOLBAR (priv->toolbar),
|
|
GTK_ICON_SIZE_BUTTON);
|
|
gtk_toolbar_set_orientation (GTK_TOOLBAR (priv->toolbar),
|
|
GTK_ORIENTATION_VERTICAL);
|
|
gtk_box_pack_start (GTK_BOX (panel), priv->toolbar, FALSE, FALSE, 0);
|
|
gtk_widget_show_all (priv->toolbar);
|
|
GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
|
|
gtk_box_pack_start (GTK_BOX (panel), vbox, TRUE, TRUE, 0);
|
|
|
|
// Create the titlebar
|
|
GtkWidget* labelbar = gtk_toolbar_new ();
|
|
gtk_toolbar_set_icon_size (GTK_TOOLBAR (labelbar), GTK_ICON_SIZE_MENU);
|
|
gtk_toolbar_set_style (GTK_TOOLBAR (labelbar), GTK_TOOLBAR_ICONS);
|
|
GtkToolItem* toolitem = gtk_tool_item_new ();
|
|
gtk_tool_item_set_expand (toolitem, TRUE);
|
|
priv->toolbar_label = gtk_label_new (NULL);
|
|
gtk_misc_set_alignment (GTK_MISC (priv->toolbar_label), 0, 0.5);
|
|
gtk_container_add (GTK_CONTAINER (toolitem), priv->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_CLOSE);
|
|
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), _("Close panel"));
|
|
sokoke_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);
|
|
gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1);
|
|
gtk_box_pack_start (GTK_BOX (vbox), labelbar, FALSE, FALSE, 0);
|
|
gtk_widget_show_all (vbox);
|
|
|
|
// Create the toolbook
|
|
priv->toolbook = gtk_notebook_new ();
|
|
gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->toolbook), FALSE);
|
|
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->toolbook), FALSE);
|
|
gtk_box_pack_start (GTK_BOX (vbox), priv->toolbook, FALSE, FALSE, 0);
|
|
gtk_widget_show (priv->toolbook);
|
|
|
|
// Create the notebook
|
|
priv->notebook = gtk_notebook_new ();
|
|
gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->notebook), FALSE);
|
|
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE);
|
|
priv->frame = gtk_frame_new (NULL);
|
|
gtk_container_add (GTK_CONTAINER (priv->frame), priv->notebook);
|
|
gtk_box_pack_start (GTK_BOX (vbox), priv->frame, TRUE, TRUE, 0);
|
|
gtk_widget_show_all (priv->frame);
|
|
}
|
|
|
|
static void
|
|
midori_panel_finalize (GObject* object)
|
|
{
|
|
MidoriPanel* panel = MIDORI_PANEL (object);
|
|
MidoriPanelPrivate* priv = panel->priv;
|
|
|
|
if (priv->menu)
|
|
{
|
|
// FIXME: Remove all menu items
|
|
}
|
|
|
|
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);
|
|
MidoriPanelPrivate* priv = panel->priv;
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_SHADOW_TYPE:
|
|
gtk_frame_set_shadow_type (GTK_FRAME (priv->frame),
|
|
g_value_get_enum (value));
|
|
break;
|
|
case PROP_MENU:
|
|
katze_object_assign (priv->menu, g_value_get_object (value));
|
|
// FIXME: Move existing items to the new menu
|
|
break;
|
|
case PROP_PAGE:
|
|
midori_panel_set_current_page (panel, g_value_get_int (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);
|
|
MidoriPanelPrivate* priv = panel->priv;
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_SHADOW_TYPE:
|
|
g_value_set_enum (value,
|
|
gtk_frame_get_shadow_type (GTK_FRAME (priv->frame)));
|
|
break;
|
|
case PROP_MENU:
|
|
g_value_set_object (value, priv->menu);
|
|
break;
|
|
case PROP_PAGE:
|
|
g_value_set_int (value, midori_panel_get_current_page (panel));
|
|
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);
|
|
}
|
|
|
|
static void
|
|
midori_panel_menu_item_activate_cb (GtkWidget* widget,
|
|
MidoriPanel* panel)
|
|
{
|
|
GtkWidget* child = g_object_get_data (G_OBJECT (widget), "page");
|
|
guint n = midori_panel_page_num (panel, child);
|
|
midori_panel_set_current_page (panel, n);
|
|
g_signal_emit (panel, signals[SWITCH_PAGE], 0, n);
|
|
}
|
|
|
|
/**
|
|
* midori_panel_append_page:
|
|
* @panel: a #MidoriPanel
|
|
* @child: the child widget
|
|
* @toolbar: a toolbar widget, or %NULL
|
|
* @icon: a stock ID or icon name, or %NULL
|
|
* @label: a string to use as the label, or %NULL
|
|
*
|
|
* Appends a new page to the panel. If @toolbar is specified it will
|
|
* be packaged above @child.
|
|
*
|
|
* If @icon is an icon name, the according image is used as an
|
|
* icon for this page.
|
|
*
|
|
* If @label is given, it is used as the label of this page.
|
|
*
|
|
* 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,
|
|
GtkWidget* child,
|
|
GtkWidget* toolbar,
|
|
const gchar* icon,
|
|
const gchar* label)
|
|
{
|
|
g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1);
|
|
g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
|
|
g_return_val_if_fail (!toolbar || GTK_IS_WIDGET (toolbar), -1);
|
|
|
|
MidoriPanelPrivate* priv = panel->priv;
|
|
|
|
GtkWidget* 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_FLAGS (scrolled, GTK_CAN_FOCUS);
|
|
gtk_widget_show (scrolled);
|
|
GtkWidget* widget;
|
|
GObjectClass* gobject_class = G_OBJECT_GET_CLASS (child);
|
|
if (GTK_WIDGET_CLASS (gobject_class)->set_scroll_adjustments_signal)
|
|
widget = child;
|
|
else
|
|
{
|
|
widget = gtk_viewport_new (NULL, NULL);
|
|
gtk_widget_show (widget);
|
|
gtk_container_add (GTK_CONTAINER (widget), child);
|
|
}
|
|
gtk_container_add (GTK_CONTAINER (scrolled), widget);
|
|
gtk_container_add (GTK_CONTAINER (priv->notebook), scrolled);
|
|
|
|
if (!toolbar)
|
|
toolbar = gtk_event_box_new ();
|
|
gtk_widget_show (toolbar);
|
|
gtk_container_add (GTK_CONTAINER (priv->toolbook), toolbar);
|
|
|
|
guint n = midori_panel_page_num (panel, child);
|
|
|
|
const gchar* text = label ? label : _("Untitled");
|
|
g_object_set_data (G_OBJECT (child), "label", (gchar*)text);
|
|
|
|
GtkWidget* image;
|
|
GtkToolItem* toolitem = gtk_radio_tool_button_new (priv->group);
|
|
priv->group = gtk_radio_tool_button_get_group (GTK_RADIO_TOOL_BUTTON (
|
|
toolitem));
|
|
gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), text);
|
|
if (icon)
|
|
{
|
|
image = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_BUTTON);
|
|
gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolitem), image);
|
|
}
|
|
g_object_set_data (G_OBJECT (toolitem), "page", child);
|
|
g_signal_connect (toolitem, "clicked",
|
|
G_CALLBACK (midori_panel_menu_item_activate_cb), panel);
|
|
gtk_widget_show_all (GTK_WIDGET (toolitem));
|
|
gtk_toolbar_insert (GTK_TOOLBAR (priv->toolbar), toolitem, -1);
|
|
|
|
if (priv->menu)
|
|
{
|
|
GtkWidget* menuitem = gtk_image_menu_item_new_with_label (text);
|
|
if (icon)
|
|
{
|
|
image = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU);
|
|
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem),
|
|
image);
|
|
}
|
|
gtk_widget_show_all (menuitem);
|
|
g_object_set_data (G_OBJECT (menuitem), "page", child);
|
|
g_signal_connect (menuitem, "activate",
|
|
G_CALLBACK (midori_panel_menu_item_activate_cb),
|
|
panel);
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menuitem);
|
|
}
|
|
|
|
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);
|
|
|
|
MidoriPanelPrivate* priv = panel->priv;
|
|
|
|
return gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
|
|
}
|
|
|
|
static GtkWidget*
|
|
_midori_panel_child_for_scrolled (MidoriPanel* panel,
|
|
GtkWidget* scrolled)
|
|
{
|
|
GtkWidget* 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)
|
|
{
|
|
g_return_val_if_fail (MIDORI_IS_PANEL (panel), NULL);
|
|
|
|
MidoriPanelPrivate* priv = panel->priv;
|
|
|
|
GtkWidget* scrolled = gtk_notebook_get_nth_page (
|
|
GTK_NOTEBOOK (priv->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);
|
|
|
|
MidoriPanelPrivate* priv = panel->priv;
|
|
|
|
return gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
|
|
}
|
|
|
|
static GtkWidget*
|
|
_midori_panel_scrolled_for_child (MidoriPanel* panel,
|
|
GtkWidget* child)
|
|
{
|
|
GtkWidget* 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)
|
|
{
|
|
g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1);
|
|
|
|
MidoriPanelPrivate* priv = panel->priv;
|
|
|
|
GtkWidget* scrolled = _midori_panel_scrolled_for_child (panel, child);
|
|
return gtk_notebook_page_num (GTK_NOTEBOOK (priv->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.
|
|
**/
|
|
void
|
|
midori_panel_set_current_page (MidoriPanel* panel,
|
|
gint n)
|
|
{
|
|
g_return_if_fail (MIDORI_IS_PANEL (panel));
|
|
|
|
MidoriPanelPrivate* priv = panel->priv;
|
|
|
|
gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->toolbook), n);
|
|
gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n);
|
|
GtkWidget* child = midori_panel_get_nth_page (panel, n);
|
|
if (child)
|
|
{
|
|
const gchar* label = g_object_get_data (G_OBJECT (child), "label");
|
|
g_object_set (priv->toolbar_label, "label", label, NULL);
|
|
}
|
|
}
|