diff options
Diffstat (limited to 'lib/toolbar/ephy-tb-button.c')
-rw-r--r-- | lib/toolbar/ephy-tb-button.c | 746 |
1 files changed, 746 insertions, 0 deletions
diff --git a/lib/toolbar/ephy-tb-button.c b/lib/toolbar/ephy-tb-button.c new file mode 100644 index 000000000..4b251a094 --- /dev/null +++ b/lib/toolbar/ephy-tb-button.c @@ -0,0 +1,746 @@ +/* + * Copyright (C) 2002 Ricardo Fernández Pascual + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ephy-tb-button.h" +#include "ephy-gobject-misc.h" +#include "ephy-gui.h" +#include "ephy-marshal.h" +#include "eel-gconf-extensions.h" + +#include <libgnome/gnome-i18n.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkalignment.h> +#include <gtk/gtktoolbar.h> +#include <bonobo/bonobo-ui-toolbar.h> +#include <string.h> + +#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC); +//#define DEBUG_MSG(x) g_print x +#define DEBUG_MSG(x) + +/** + * Private data + */ +struct _EphyTbButtonPrivate +{ + gchar *label; + GtkWidget *image; + gboolean use_stock; + gchar *tooltip_text; + GtkMenu *menu; + GtkWidget *arrow_widget; + gboolean sensitive; + + GtkWidget *button; + GtkBox *button_box; + GtkLabel *label_wid; + gboolean priority; + + gboolean in_bonobo_toobar; + + GtkReliefStyle button_relief; + GtkOrientation orientation; + GtkToolbarStyle style_gtk; + BonoboUIToolbarStyle style_bonobo; + GtkIconSize icon_size; // TODO + gboolean show_tooltips; + GtkTooltips *tooltips; +}; + +/** + * Private functions, only availble from this file + */ +static void ephy_tb_button_class_init (EphyTbButtonClass *klass); +static void ephy_tb_button_init (EphyTbButton *b); +static void ephy_tb_button_finalize_impl (GObject *o); +static void ephy_tb_button_build (EphyTbButton *b); +static void ephy_tb_button_empty (EphyTbButton *b); +static void ephy_tb_button_parent_set_cb (GtkWidget *widget, GtkObject *old_parent, + EphyTbButton *tb); +static void ephy_tb_button_gtk_orientation_changed_cb (GtkToolbar *toolbar, GtkOrientation orientation, + EphyTbButton *b); +static void ephy_tb_button_gtk_style_changed_cb (GtkToolbar *toolbar, GtkToolbarStyle style, + EphyTbButton *b); +static void ephy_tb_button_bonobo_set_orientation_cb (BonoboUIToolbar *toolbar, GtkOrientation orientation, + EphyTbButton *b); +static void ephy_tb_button_bonobo_set_style_cb (BonoboUIToolbar *toolbar, EphyTbButton *b); +static gboolean ephy_tb_button_arrow_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, + EphyTbButton *b); +static gboolean ephy_tb_button_arrow_button_press_event_cb (GtkWidget *widget, GdkEventButton *event, + EphyTbButton *b); +static gboolean ephy_tb_button_button_button_press_event_cb (GtkWidget *widget, GdkEventButton *event, + EphyTbButton *b); +static void ephy_tb_button_button_popup_menu_cb (GtkWidget *w, EphyTbButton *b); +static void ephy_tb_button_menu_deactivated_cb (GtkMenuShell *ms, EphyTbButton *b); + + +static gpointer gtk_hbox_class; + +enum EphyTbButtonSignalsEnum { + EPHY_TB_BUTTON_MENU_ACTIVATED, + EPHY_TB_BUTTON_LAST_SIGNAL +}; +static gint EphyTbButtonSignals[EPHY_TB_BUTTON_LAST_SIGNAL]; + +/** + * TbButton object + */ + +MAKE_GET_TYPE (ephy_tb_button, "EphyTbButton", EphyTbButton, ephy_tb_button_class_init, + ephy_tb_button_init, GTK_TYPE_HBOX); + +static void +ephy_tb_button_class_init (EphyTbButtonClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = ephy_tb_button_finalize_impl; + gtk_hbox_class = g_type_class_peek_parent (klass); + + EphyTbButtonSignals[EPHY_TB_BUTTON_MENU_ACTIVATED] = g_signal_new ( + "menu-activated", G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, + G_STRUCT_OFFSET (EphyTbButtonClass, menu_activated), + NULL, NULL, + ephy_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +ephy_tb_button_init (EphyTbButton *tb) +{ + EphyTbButtonPrivate *p = g_new0 (EphyTbButtonPrivate, 1); + tb->priv = p; + p->label = g_strdup (""); + p->tooltip_text = g_strdup (""); + + p->button_relief = GTK_RELIEF_NORMAL; + p->orientation = GTK_ORIENTATION_HORIZONTAL; + p->style_gtk = GTK_TOOLBAR_BOTH_HORIZ; + p->style_bonobo = BONOBO_UI_TOOLBAR_STYLE_PRIORITY_TEXT; + p->icon_size = GTK_ICON_SIZE_LARGE_TOOLBAR; + p->show_tooltips = TRUE; + + g_signal_connect (tb, "parent-set", + G_CALLBACK (ephy_tb_button_parent_set_cb), tb); +} + +EphyTbButton * +ephy_tb_button_new (void) +{ + EphyTbButton *ret = g_object_new (EPHY_TYPE_TB_BUTTON, NULL); + return ret; +} + +static void +ephy_tb_button_finalize_impl (GObject *o) +{ + EphyTbButton *it = EPHY_TB_BUTTON (o); + EphyTbButtonPrivate *p = it->priv; + + ephy_tb_button_empty (it); + + if (p->image) + { + g_object_unref (p->image); + } + + if (p->tooltips) + { + g_object_unref (p->tooltips); + } + + if (p->menu) + { + g_object_unref (p->menu); + } + + if (p->arrow_widget) + { + g_object_unref (p->arrow_widget); + } + + g_free (p); + + DEBUG_MSG (("EphyTbButton finalized\n")); + + G_OBJECT_CLASS (gtk_hbox_class)->finalize (o); +} + +void +ephy_tb_button_set_label (EphyTbButton *b, const gchar *text) +{ + EphyTbButtonPrivate *p = b->priv; + g_free (p->label); + p->label = g_strdup (text); + DEBUG_MSG (("EphyTbButton label set to '%s'\n", p->label)); + if (!p->label_wid || p->use_stock) + { + ephy_tb_button_build (b); + } + else + { + gtk_label_set_text (p->label_wid, p->label); + } +} + +void +ephy_tb_button_set_tooltip_text (EphyTbButton *b, const gchar *text) +{ + EphyTbButtonPrivate *p = b->priv; + g_free (p->tooltip_text); + p->tooltip_text = g_strdup (text); + + if (!p->tooltips || !p->button) + { + ephy_tb_button_build (b); + } + else + { + gtk_tooltips_set_tip (p->tooltips, p->button, + p->tooltip_text, p->tooltip_text); + } +} + +/* this function comes directly from gtktoolbar.c */ +static gchar * +elide_underscores (const gchar *original) +{ + gchar *q, *result; + const gchar *p; + gboolean last_underscore; + + q = result = g_malloc (strlen (original) + 1); + last_underscore = FALSE; + + for (p = original; *p; p++) + { + if (!last_underscore && *p == '_') + { + last_underscore = TRUE; + } + else + { + last_underscore = FALSE; + *q++ = *p; + } + } + + *q = '\0'; + + return result; +} + +static void +ephy_tb_button_build (EphyTbButton *b) +{ + EphyTbButtonPrivate *p = b->priv; + GtkWidget *align; + GtkWidget *image; + GtkStockItem stock_item; + gboolean really_use_stock = p->use_stock && gtk_stock_lookup (p->label, &stock_item); + gboolean show_image = p->label[0] == '\0' + || (p->in_bonobo_toobar && p->style_bonobo != BONOBO_UI_TOOLBAR_STYLE_TEXT_ONLY) + || (!p->in_bonobo_toobar && p->style_gtk != GTK_TOOLBAR_TEXT); + gboolean show_label = !show_image + || (p->priority && ((p->in_bonobo_toobar && p->style_bonobo == BONOBO_UI_TOOLBAR_STYLE_PRIORITY_TEXT) + || (!p->in_bonobo_toobar && p->style_gtk == GTK_TOOLBAR_BOTH_HORIZ))) + || (!p->in_bonobo_toobar + && (p->style_gtk == GTK_TOOLBAR_BOTH + || p->style_gtk == GTK_TOOLBAR_TEXT + /* CHECK: what about GTK_TOOLBAR_BOTH_HORIZ? */ )) + || (p->in_bonobo_toobar + && (p->style_bonobo == BONOBO_UI_TOOLBAR_STYLE_ICONS_AND_TEXT + || p->style_bonobo == BONOBO_UI_TOOLBAR_STYLE_TEXT_ONLY)); + + ephy_tb_button_empty (b); + + if (!p->button) + { + p->button = gtk_button_new (); + g_object_ref (p->button); + gtk_widget_show (p->button); + gtk_box_pack_start_defaults (GTK_BOX (b), p->button); + } + + gtk_button_set_relief (GTK_BUTTON (p->button), p->button_relief); + gtk_widget_set_sensitive (p->button, p->sensitive); + if (p->tooltips) + { + gtk_tooltips_set_tip (p->tooltips, p->button, + p->tooltip_text, p->tooltip_text); + } + g_signal_connect (p->button, "button_press_event", + G_CALLBACK (ephy_tb_button_button_button_press_event_cb), b); + g_signal_connect (p->button, "popup_menu", + G_CALLBACK (ephy_tb_button_button_popup_menu_cb), b); + + align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); + gtk_widget_show (align); + gtk_container_add (GTK_CONTAINER (p->button), align); + + if ((p->in_bonobo_toobar && p->style_bonobo == BONOBO_UI_TOOLBAR_STYLE_ICONS_AND_TEXT) + || (!p->in_bonobo_toobar && p->style_gtk == GTK_TOOLBAR_BOTH) + || p->orientation == GTK_ORIENTATION_VERTICAL) + { + p->button_box = GTK_BOX (gtk_vbox_new (FALSE, 2)); + } + else + { + p->button_box = GTK_BOX (gtk_hbox_new (FALSE, 2)); + } + g_object_ref (p->button_box); + gtk_widget_show (GTK_WIDGET (p->button_box)); + gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET (p->button_box)); + + if (!p->image && really_use_stock && show_image) + { + image = gtk_image_new_from_stock (p->label, p->icon_size); + } + else + { + image = p->image; + } + + if (image) + { + if (show_image) + { + gtk_box_pack_start_defaults (p->button_box, GTK_WIDGET (image)); + gtk_widget_show (image); + } + } + else + { + show_label = TRUE; + } + + if (show_label) + { + p->label_wid = GTK_LABEL (gtk_label_new (p->label)); + g_object_ref (p->label_wid); + + if (really_use_stock) + { + gchar *l = elide_underscores (stock_item.label); + gtk_label_set_text (p->label_wid, l); + g_free (l); + } + + gtk_widget_show (GTK_WIDGET (p->label_wid)); + gtk_box_pack_end_defaults (p->button_box, GTK_WIDGET (p->label_wid)); + } + + DEBUG_MSG (("EphyTbButton built, label='%s'\n", p->label)); +} + +void +ephy_tb_button_set_priority (EphyTbButton *b, gboolean priority) +{ + EphyTbButtonPrivate *p = b->priv; + if (p->priority != priority) + { + p->priority = priority; + ephy_tb_button_build (b); + } +} + +void +ephy_tb_button_set_image (EphyTbButton *b, GtkWidget *image) +{ + EphyTbButtonPrivate *p = b->priv; + if (p->image) + { + g_object_unref (p->image); + } + p->image = image ? g_object_ref (image) : NULL; + ephy_tb_button_build (b); +} + +void +ephy_tb_button_set_show_arrow (EphyTbButton *b, gboolean value) +{ + EphyTbButtonPrivate *p = b->priv; + + if (p->arrow_widget && !value) + { + if (p->arrow_widget->parent == GTK_WIDGET (b)) + { + gtk_container_remove (GTK_CONTAINER (b), p->arrow_widget); + } + g_object_unref (p->arrow_widget); + p->arrow_widget = NULL; + } + else if (!p->arrow_widget && value) + { + p->arrow_widget = gtk_toggle_button_new (); + gtk_button_set_relief (GTK_BUTTON (p->arrow_widget), GTK_RELIEF_NONE); + + gtk_container_add (GTK_CONTAINER (p->arrow_widget), + gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT)); + + g_object_ref (p->arrow_widget); + gtk_object_sink (GTK_OBJECT (p->arrow_widget)); + + g_signal_connect (p->arrow_widget, "key_press_event", + G_CALLBACK (ephy_tb_button_arrow_key_press_event_cb), + b); + + g_signal_connect (p->arrow_widget, "button_press_event", + G_CALLBACK (ephy_tb_button_arrow_button_press_event_cb), + b); + + gtk_widget_show_all (p->arrow_widget); + gtk_box_pack_end_defaults (GTK_BOX (b), p->arrow_widget); + gtk_widget_set_sensitive (p->arrow_widget, value); + } +} + +void +ephy_tb_button_set_enable_menu (EphyTbButton *b, gboolean value) +{ + EphyTbButtonPrivate *p = b->priv; + if (value && !p->menu) + { + p->menu = GTK_MENU (gtk_menu_new ()); + g_signal_connect (p->menu, "deactivate", + G_CALLBACK (ephy_tb_button_menu_deactivated_cb), b); + } + else if (!value && p->menu) + { + g_object_unref (p->menu); + p->menu = FALSE; + } + +} + +GtkMenuShell * +ephy_tb_button_get_menu (EphyTbButton *b) +{ + EphyTbButtonPrivate *p = b->priv; + return p->menu ? GTK_MENU_SHELL (p->menu) : NULL; +} + +GtkButton * +ephy_tb_button_get_button (EphyTbButton *b) +{ + EphyTbButtonPrivate *p = b->priv; + if (!p->button) + { + ephy_tb_button_build (b); + } + return GTK_BUTTON (p->button); +} + +void +ephy_tb_button_set_use_stock (EphyTbButton *b, gboolean value) +{ + EphyTbButtonPrivate *p = b->priv; + if (value != p->use_stock) + { + p->use_stock = value; + ephy_tb_button_build (b); + } +} + +static void +ephy_tb_button_empty (EphyTbButton *b) +{ + EphyTbButtonPrivate *p = b->priv; + + if (p->button) + { + if (GTK_BIN (p->button)->child) + { + gtk_container_remove (GTK_CONTAINER (p->button), GTK_BIN (p->button)->child); + } + } + + if (p->button_box) + { + g_object_unref (p->button_box); + p->button_box = NULL; + } + + if (p->label_wid) + { + g_object_unref (p->label_wid); + p->label_wid = NULL; + } +} + +static void +ephy_tb_button_parent_set_cb (GtkWidget *widget, GtkObject *old_parent, EphyTbButton *tb) +{ + EphyTbButtonPrivate *p = tb->priv; + GtkWidget *new_parent = widget->parent; + + DEBUG_MSG (("EphyTbButton parent changed (widget=%p, button=%p, old=%p, new=%p)\n", + widget, tb, old_parent, new_parent)); + + if (new_parent) + { + GtkToolbar *gtktb = NULL; + BonoboUIToolbar *btb = NULL; + while (new_parent && !gtktb && !btb) + { + DEBUG_MSG (("new_parent ia a %s\n", g_type_name_from_instance ((void *) new_parent))); + + if (GTK_IS_TOOLBAR (new_parent)) + { + gtktb = GTK_TOOLBAR (new_parent); + } + else if (BONOBO_IS_UI_TOOLBAR (new_parent)) + { + btb = BONOBO_UI_TOOLBAR (new_parent); + } + else + { + g_signal_connect (new_parent, "parent_set", + G_CALLBACK (ephy_tb_button_parent_set_cb), tb); + } + new_parent = new_parent->parent; + } + + if (gtktb) + { + DEBUG_MSG (("EphyTbButton getting style from a GtkToolbar (%p)\n", gtktb)); + p->in_bonobo_toobar = FALSE; + + gtk_widget_ensure_style (GTK_WIDGET (gtktb)); + gtk_widget_style_get (GTK_WIDGET (gtktb), "button_relief", &p->button_relief, NULL); + + p->orientation = gtk_toolbar_get_orientation (gtktb); + p->style_gtk = gtk_toolbar_get_style (gtktb); + p->icon_size = gtk_toolbar_get_icon_size (gtktb); + p->show_tooltips = gtk_toolbar_get_tooltips (gtktb); + + if (p->tooltips) + { + g_object_unref (p->tooltips); + } + p->tooltips = gtk_tooltips_new (); + if (p->show_tooltips) + { + gtk_tooltips_enable (p->tooltips); + } + else + { + gtk_tooltips_disable (p->tooltips); + } + g_object_ref (p->tooltips); + gtk_object_sink (GTK_OBJECT (p->tooltips)); + + g_signal_connect (gtktb, "orientation-changed", + G_CALLBACK (ephy_tb_button_gtk_orientation_changed_cb), tb); + g_signal_connect (gtktb, "style-changed", + G_CALLBACK (ephy_tb_button_gtk_style_changed_cb), tb); + + ephy_tb_button_build (tb); + } + + if (btb) + { + DEBUG_MSG (("EphyTbButton getting style from a BonoboUIToolbar (%p)\n", btb)); + p->in_bonobo_toobar = TRUE; + + p->button_relief = GTK_RELIEF_NONE; + + p->orientation = bonobo_ui_toolbar_get_orientation (btb); + p->style_bonobo = bonobo_ui_toolbar_get_style (btb); + //p->icon_size = ???; + p->show_tooltips = TRUE; + + if (p->tooltips) + { + g_object_unref (p->tooltips); + } + p->tooltips = bonobo_ui_toolbar_get_tooltips (btb); + g_object_ref (p->tooltips); + + g_signal_connect (btb, "set-orientation", + G_CALLBACK (ephy_tb_button_bonobo_set_orientation_cb), tb); + g_signal_connect (btb, "set-style", + G_CALLBACK (ephy_tb_button_bonobo_set_style_cb), tb); + + ephy_tb_button_build (tb); + } + } + else + { + while (old_parent) + { + g_signal_handlers_disconnect_matched (old_parent, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, tb); + if (GTK_IS_WIDGET (old_parent)) + { + old_parent = GTK_WIDGET (old_parent)->parent + ? GTK_OBJECT (GTK_WIDGET (old_parent)->parent) + : NULL; + } + else + { + old_parent = NULL; + } + } + } +} + +static void +ephy_tb_button_gtk_orientation_changed_cb (GtkToolbar *toolbar, GtkOrientation orientation, EphyTbButton *b) +{ + EphyTbButtonPrivate *p = b->priv; + if (p->orientation != orientation) + { + p->orientation = orientation; + ephy_tb_button_build (b); + } +} + +static void +ephy_tb_button_gtk_style_changed_cb (GtkToolbar *toolbar, GtkToolbarStyle style, EphyTbButton *b) +{ + EphyTbButtonPrivate *p = b->priv; + if (p->style_gtk != style) + { + p->style_gtk = style; + ephy_tb_button_build (b); + } +} + +static void +ephy_tb_button_bonobo_set_orientation_cb (BonoboUIToolbar *toolbar, GtkOrientation orientation, EphyTbButton *b) +{ + EphyTbButtonPrivate *p = b->priv; + if (p->orientation != orientation) + { + p->orientation = orientation; + ephy_tb_button_build (b); + } +} + +static void +ephy_tb_button_bonobo_set_style_cb (BonoboUIToolbar *toolbar, EphyTbButton *b) +{ + EphyTbButtonPrivate *p = b->priv; + BonoboUIToolbarStyle style = bonobo_ui_toolbar_get_style (toolbar); + if (style != p->style_bonobo) + { + p->style_bonobo = style; + ephy_tb_button_build (b); + } +} + +static void +ephy_tb_button_popup_menu_under_arrow (EphyTbButton *b, GdkEventButton *event) +{ + EphyTbButtonPrivate *p = b->priv; + + if (p->menu) + { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p->arrow_widget), TRUE); + g_signal_emit (b, EphyTbButtonSignals[EPHY_TB_BUTTON_MENU_ACTIVATED], 0); + gtk_menu_popup (p->menu, NULL, NULL, ephy_gui_menu_position_under_widget, p->arrow_widget, + event ? event->button : 0, + event ? event->time : gtk_get_current_event_time ()); + } +} + +static void +ephy_tb_button_menu_deactivated_cb (GtkMenuShell *ms, EphyTbButton *b) +{ + EphyTbButtonPrivate *p = b->priv; + if (p->arrow_widget) + { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p->arrow_widget), FALSE); + } +} + +static gboolean +ephy_tb_button_arrow_button_press_event_cb (GtkWidget *widget, GdkEventButton *event, EphyTbButton *b) +{ + ephy_tb_button_popup_menu_under_arrow (b, event); + return TRUE; +} + +static gboolean +ephy_tb_button_arrow_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, EphyTbButton *b) +{ + if (event->keyval == GDK_space + || event->keyval == GDK_KP_Space + || event->keyval == GDK_Return + || event->keyval == GDK_KP_Enter + || event->keyval == GDK_Menu) + { + ephy_tb_button_popup_menu_under_arrow (b, NULL); + } + + return FALSE; +} + +static gboolean +ephy_tb_button_button_button_press_event_cb (GtkWidget *widget, GdkEventButton *event, + EphyTbButton *b) +{ + EphyTbButtonPrivate *p = b->priv; + + if (event->button == 3 && p->menu) + { + g_signal_emit (b, EphyTbButtonSignals[EPHY_TB_BUTTON_MENU_ACTIVATED], 0); + gtk_menu_popup (p->menu, NULL, NULL, NULL, b, + event ? event->button : 0, + event ? event->time : gtk_get_current_event_time ()); + return TRUE; + } + + return FALSE; +} + +static void +ephy_tb_button_button_popup_menu_cb (GtkWidget *w, EphyTbButton *b) +{ + EphyTbButtonPrivate *p = b->priv; + + g_signal_emit (b, EphyTbButtonSignals[EPHY_TB_BUTTON_MENU_ACTIVATED], 0); + gtk_menu_popup (p->menu, NULL, NULL, + ephy_gui_menu_position_under_widget, b, 0, gtk_get_current_event_time ()); +} + +void +ephy_tb_button_set_sensitivity (EphyTbButton *b, gboolean value) +{ + EphyTbButtonPrivate *p = b->priv; + + p->sensitive = value; + + if (!p->button) + { + ephy_tb_button_build (b); + } + else + { + gtk_widget_set_sensitive (p->button, value); + if (p->arrow_widget) + { + gtk_widget_set_sensitive (p->arrow_widget, value); + } + } +} + |