diff options
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 17 | ||||
-rw-r--r-- | ChangeLog.pre-2-4 | 17 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 17 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 17 | ||||
-rw-r--r-- | gtk/Makefile.am | 34 | ||||
-rw-r--r-- | gtk/gtkmarshalers.list | 1 | ||||
-rw-r--r-- | gtk/gtkradiotoolbutton.c | 147 | ||||
-rw-r--r-- | gtk/gtkradiotoolbutton.h | 62 | ||||
-rw-r--r-- | gtk/gtkseparatortoolitem.c | 90 | ||||
-rw-r--r-- | gtk/gtkseparatortoolitem.h | 50 | ||||
-rw-r--r-- | gtk/gtktoggletoolbutton.c | 244 | ||||
-rw-r--r-- | gtk/gtktoggletoolbutton.h | 68 | ||||
-rw-r--r-- | gtk/gtktoolbar.c | 3242 | ||||
-rw-r--r-- | gtk/gtktoolbar.h | 179 | ||||
-rw-r--r-- | gtk/gtktoolbutton.c | 812 | ||||
-rw-r--r-- | gtk/gtktoolbutton.h | 92 | ||||
-rw-r--r-- | gtk/gtktoolitem.c | 697 | ||||
-rw-r--r-- | gtk/gtktoolitem.h | 110 |
19 files changed, 4654 insertions, 1259 deletions
@@ -1,3 +1,20 @@ +Mon Jun 30 01:20:19 2003 Soeren Sandmann <sandmann@daimi.au.dk> + + * gtkradiotoolbutton.c + * gtkradiotoolbutton.h + * gtktoggletoolbutton.c + * gtktoggletoolbutton.h + * gtktoolbutton.c + * gtktoolbutton.h + * gtktoolitem.c + * gtktoolitem.h + * gtktoolbar.c + * gtktoolbar.h + * gtkseparatortoolitem.c + * gtkseparatortoolitem.h + + New toolbar. + 2003-06-29 Matthias Clasen <maclas@gmx.de> * gtk/gtkwidget.c (gtk_widget_class_init): Remove a duplicate parameter from docs, some more formatting diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index e6b8609b28..19f002d3df 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,20 @@ +Mon Jun 30 01:20:19 2003 Soeren Sandmann <sandmann@daimi.au.dk> + + * gtkradiotoolbutton.c + * gtkradiotoolbutton.h + * gtktoggletoolbutton.c + * gtktoggletoolbutton.h + * gtktoolbutton.c + * gtktoolbutton.h + * gtktoolitem.c + * gtktoolitem.h + * gtktoolbar.c + * gtktoolbar.h + * gtkseparatortoolitem.c + * gtkseparatortoolitem.h + + New toolbar. + 2003-06-29 Matthias Clasen <maclas@gmx.de> * gtk/gtkwidget.c (gtk_widget_class_init): Remove a duplicate parameter from docs, some more formatting diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index e6b8609b28..19f002d3df 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,20 @@ +Mon Jun 30 01:20:19 2003 Soeren Sandmann <sandmann@daimi.au.dk> + + * gtkradiotoolbutton.c + * gtkradiotoolbutton.h + * gtktoggletoolbutton.c + * gtktoggletoolbutton.h + * gtktoolbutton.c + * gtktoolbutton.h + * gtktoolitem.c + * gtktoolitem.h + * gtktoolbar.c + * gtktoolbar.h + * gtkseparatortoolitem.c + * gtkseparatortoolitem.h + + New toolbar. + 2003-06-29 Matthias Clasen <maclas@gmx.de> * gtk/gtkwidget.c (gtk_widget_class_init): Remove a duplicate parameter from docs, some more formatting diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index e6b8609b28..19f002d3df 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,20 @@ +Mon Jun 30 01:20:19 2003 Soeren Sandmann <sandmann@daimi.au.dk> + + * gtkradiotoolbutton.c + * gtkradiotoolbutton.h + * gtktoggletoolbutton.c + * gtktoggletoolbutton.h + * gtktoolbutton.c + * gtktoolbutton.h + * gtktoolitem.c + * gtktoolitem.h + * gtktoolbar.c + * gtktoolbar.h + * gtkseparatortoolitem.c + * gtkseparatortoolitem.h + + New toolbar. + 2003-06-29 Matthias Clasen <maclas@gmx.de> * gtk/gtkwidget.c (gtk_widget_class_init): Remove a duplicate parameter from docs, some more formatting diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index e6b8609b28..19f002d3df 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,20 @@ +Mon Jun 30 01:20:19 2003 Soeren Sandmann <sandmann@daimi.au.dk> + + * gtkradiotoolbutton.c + * gtkradiotoolbutton.h + * gtktoggletoolbutton.c + * gtktoggletoolbutton.h + * gtktoolbutton.c + * gtktoolbutton.h + * gtktoolitem.c + * gtktoolitem.h + * gtktoolbar.c + * gtktoolbar.h + * gtkseparatortoolitem.c + * gtkseparatortoolitem.h + + New toolbar. + 2003-06-29 Matthias Clasen <maclas@gmx.de> * gtk/gtkwidget.c (gtk_widget_class_init): Remove a duplicate parameter from docs, some more formatting diff --git a/gtk/Makefile.am b/gtk/Makefile.am index f7b54a4ff7..494a82d430 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -94,28 +94,27 @@ gtk_public_h_sources = \ gtkalignment.h \ gtkarrow.h \ gtkaspectframe.h \ + gtkbbox.h \ gtkbin.h \ gtkbindings.h \ - gtkbbox.h \ gtkbox.h \ gtkbutton.h \ gtkcalendar.h \ + gtkcelleditable.h \ + gtkcellrenderer.h \ + gtkcellrendererpixbuf.h \ + gtkcellrenderertext.h \ + gtkcellrenderertoggle.h \ gtkcheckbutton.h \ gtkcheckmenuitem.h \ - gtkseparatormenuitem.h \ - gtkclist.h \ gtkclipboard.h \ + gtkclist.h \ gtkcolorsel.h \ gtkcolorseldialog.h \ gtkcombo.h \ gtkcontainer.h \ gtkctree.h \ gtkcurve.h \ - gtkcellrenderer.h \ - gtkcelleditable.h \ - gtkcellrenderertext.h \ - gtkcellrenderertoggle.h \ - gtkcellrendererpixbuf.h \ gtkdebug.h \ gtkdialog.h \ gtkdnd.h \ @@ -162,8 +161,8 @@ gtk_public_h_sources = \ gtkmessagedialog.h \ gtkmisc.h \ gtknotebook.h \ - gtkoldeditable.h \ gtkobject.h \ + gtkoldeditable.h \ gtkoptionmenu.h \ gtkpaned.h \ gtkpixmap.h \ @@ -174,6 +173,7 @@ gtk_public_h_sources = \ gtkprogressbar.h \ gtkradiobutton.h \ gtkradiomenuitem.h \ + gtkradiotoolbutton.h \ gtkrange.h \ gtkrc.h \ gtkruler.h \ @@ -182,16 +182,19 @@ gtk_public_h_sources = \ gtkscrolledwindow.h \ gtkselection.h \ gtkseparator.h \ + gtkseparatormenuitem.h \ + gtkseparatortoolitem.h \ gtksettings.h \ gtksignal.h \ gtksizegroup.h \ gtksocket.h \ gtkspinbutton.h \ - gtkstyle.h \ gtkstatusbar.h \ gtkstock.h \ + gtkstyle.h \ gtktable.h \ gtktearoffmenuitem.h \ + gtktext.h \ gtktextbuffer.h \ gtktextchild.h \ gtktextdisplay.h \ @@ -201,10 +204,12 @@ gtk_public_h_sources = \ gtktexttag.h \ gtktexttagtable.h \ gtktextview.h \ - gtktext.h \ gtktipsquery.h \ gtktogglebutton.h \ + gtktoggletoolbutton.h \ gtktoolbar.h \ + gtktoolbutton.h \ + gtktoolitem.h \ gtktooltips.h \ gtktree.h \ gtktreednd.h \ @@ -249,6 +254,12 @@ gtk_c_sources = \ gtkaccelgroup.c \ gtkaccelmap.c \ gtkaccellabel.c \ + gtkradiotoolbutton.c \ + gtktoggletoolbutton.c \ + gtktoolbar.c \ + gtktoolbutton.c \ + gtkseparatortoolitem.c \ + gtktoolitem.c \ gtkaccessible.c \ gtkadjustment.c \ gtkalignment.c \ @@ -374,7 +385,6 @@ gtk_c_sources = \ gtkthemes.c \ gtktipsquery.c \ gtktogglebutton.c \ - gtktoolbar.c \ gtktooltips.c \ gtktree.c \ gtktreeitem.c \ diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list index a719713dc3..b59820745b 100644 --- a/gtk/gtkmarshalers.list +++ b/gtk/gtkmarshalers.list @@ -29,6 +29,7 @@ BOOLEAN:OBJECT,UINT,FLAGS BOOLEAN:OBJECT,INT,INT,UINT BOOLEAN:OBJECT,STRING,STRING,BOXED BOOLEAN:OBJECT,BOXED,BOXED +BOOLEAN:OBJECT,STRING,STRING BOOLEAN:INT,INT BOOLEAN:VOID BOOLEAN:BOOLEAN diff --git a/gtk/gtkradiotoolbutton.c b/gtk/gtkradiotoolbutton.c new file mode 100644 index 0000000000..46cb83801c --- /dev/null +++ b/gtk/gtkradiotoolbutton.c @@ -0,0 +1,147 @@ +/* gtkradiotoolbutton.c + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * Copyright (C) 2003 Soeren Sandmann <sandmann@daimi.au.dk> + * + * 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 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gtkradiotoolbutton.h" +#include "gtkradiobutton.h" +#include "gtkintl.h" + +static void gtk_radio_tool_button_init (GtkRadioToolButton *button); +static void gtk_radio_tool_button_class_init (GtkRadioToolButtonClass *klass); + +GType +gtk_radio_tool_button_get_type (void) +{ + static GType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (GtkRadioToolButtonClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gtk_radio_tool_button_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (GtkRadioToolButton), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_radio_tool_button_init + }; + + type = g_type_register_static (GTK_TYPE_TOGGLE_TOOL_BUTTON, + "GtkRadioToolButton", &type_info, 0); + } + return type; +} + + +static void +gtk_radio_tool_button_class_init (GtkRadioToolButtonClass *klass) +{ + GtkToolButtonClass *toolbutton_class; + + toolbutton_class = (GtkToolButtonClass *)klass; + + toolbutton_class->button_type = GTK_TYPE_RADIO_BUTTON; +} + +static void +gtk_radio_tool_button_init (GtkRadioToolButton *button) +{ + gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (GTK_TOOL_BUTTON (button)->button), FALSE); +} + +GtkToolItem * +gtk_radio_tool_button_new (GSList *group) +{ + GtkRadioToolButton *button; + + button = g_object_new (GTK_TYPE_RADIO_TOOL_BUTTON, + NULL); + + gtk_radio_tool_button_set_group (button, group); + + return GTK_TOOL_ITEM (button); +} + +GtkToolItem * +gtk_radio_tool_button_new_from_stock (GSList *group, + const gchar *stock_id) +{ + GtkRadioToolButton *button; + + g_return_val_if_fail (stock_id != NULL, NULL); + + button = g_object_new (GTK_TYPE_RADIO_TOOL_BUTTON, + "stock_id", stock_id, + NULL); + + + gtk_radio_tool_button_set_group (button, group); + + return GTK_TOOL_ITEM (button); +} + +GtkToolItem * +gtk_radio_tool_button_new_from_widget (GtkWidget *group, + const gchar *stock_id) +{ + GSList *list = NULL; + + g_return_val_if_fail (GTK_IS_RADIO_TOOL_BUTTON (group), NULL); + + if (group) + list = gtk_radio_tool_button_get_group (GTK_RADIO_TOOL_BUTTON (group)); + + return gtk_radio_tool_button_new_from_stock (list, stock_id); +} + +GtkToolItem * +gtk_radio_tool_button_new_with_stock_from_widget (GtkWidget *group) +{ + GSList *list = NULL; + + g_return_val_if_fail (GTK_IS_RADIO_TOOL_BUTTON (group), NULL); + + if (group) + list = gtk_radio_tool_button_get_group (GTK_RADIO_TOOL_BUTTON (group)); + + return gtk_radio_tool_button_new (list); +} + +GSList * +gtk_radio_tool_button_get_group (GtkRadioToolButton *button) +{ + g_return_val_if_fail (GTK_IS_RADIO_TOOL_BUTTON (button), NULL); + + return gtk_radio_button_get_group (GTK_RADIO_BUTTON (GTK_TOOL_BUTTON (button)->button)); +} + +void +gtk_radio_tool_button_set_group (GtkRadioToolButton *button, + GSList *group) +{ + g_return_if_fail (GTK_IS_RADIO_TOOL_BUTTON (button)); + + gtk_radio_button_set_group (GTK_RADIO_BUTTON (GTK_TOOL_BUTTON (button)->button), group); +} + diff --git a/gtk/gtkradiotoolbutton.h b/gtk/gtkradiotoolbutton.h new file mode 100644 index 0000000000..93bc97b1bd --- /dev/null +++ b/gtk/gtkradiotoolbutton.h @@ -0,0 +1,62 @@ +/* gtkradiotoolbutton.h + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * Copyright (C) 2003 Soeren Sandmann <sandmann@daimi.au.dk> + * + * 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 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTK_RADIO_TOOL_BUTTON_H__ +#define __GTK_RADIO_TOOL_BUTTON_H__ + +#include "gtktoggletoolbutton.h" + +#define GTK_TYPE_RADIO_TOOL_BUTTON (gtk_radio_tool_button_get_type ()) +#define GTK_RADIO_TOOL_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_RADIO_TOOL_BUTTON, GtkRadioToolButton)) +#define GTK_RADIO_TOOL_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_RADIO_TOOL_BUTTON, GtkRadioToolButtonClass)) +#define GTK_IS_RADIO_TOOL_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_RADIO_TOOL_BUTTON)) +#define GTK_IS_RADIO_TOOL_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), GTK_TYPE_RADIO_TOOL_BUTTON)) +#define GTK_RADIO_TOOL_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_RADIO_TOOL_BUTTON, GtkRadioToolButtonClass)) + +typedef struct _GtkRadioToolButton GtkRadioToolButton; +typedef struct _GtkRadioToolButtonClass GtkRadioToolButtonClass; + +struct _GtkRadioToolButton +{ + GtkToggleToolButton parent; +}; + +struct _GtkRadioToolButtonClass +{ + GtkToggleToolButtonClass parent_class; +}; + +GType gtk_radio_tool_button_get_type (void) G_GNUC_CONST; + +GtkToolItem *gtk_radio_tool_button_new (GSList *group); +GtkToolItem *gtk_radio_tool_button_new_from_stock (GSList *group, + const gchar *stock_id); +GtkToolItem *gtk_radio_tool_button_new_from_widget (GtkWidget *group, + const gchar *stock_id); +GtkToolItem *gtk_radio_tool_button_new_with_stock_from_widget (GtkWidget *group); +GSList * gtk_radio_tool_button_get_group (GtkRadioToolButton *button); +void gtk_radio_tool_button_set_group (GtkRadioToolButton *button, + GSList *group); + + + +#endif /* __GTK_RADIO_TOOL_BUTTON_H__ */ diff --git a/gtk/gtkseparatortoolitem.c b/gtk/gtkseparatortoolitem.c new file mode 100644 index 0000000000..52051d6dd5 --- /dev/null +++ b/gtk/gtkseparatortoolitem.c @@ -0,0 +1,90 @@ +/* gtkseparatortoolitem.c + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * + * 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 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gtkseparatormenuitem.h" +#include "gtkseparatortoolitem.h" +#include "gtkintl.h" + +static void gtk_separator_tool_item_class_init (GtkSeparatorToolItemClass*class); + +static void gtk_separator_tool_item_add (GtkContainer *container, + GtkWidget *child); + +static GObjectClass *parent_class = NULL; + + +GType +gtk_separator_tool_item_get_type (void) +{ + static GType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (GtkSeparatorToolItemClass), + (GBaseInitFunc) 0, + (GBaseFinalizeFunc) 0, + (GClassInitFunc) gtk_separator_tool_item_class_init, + (GClassFinalizeFunc) 0, + NULL, + sizeof (GtkSeparatorToolItem), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL, + }; + + type = g_type_register_static (GTK_TYPE_TOOL_ITEM, + "GtkSeparatorToolItem", &type_info, 0); + } + return type; +} + + +static void +gtk_separator_tool_item_class_init (GtkSeparatorToolItemClass *class) +{ + GtkContainerClass *container_class; + GtkToolItemClass *toolitem_class; + + parent_class = g_type_class_peek_parent (class); + container_class = (GtkContainerClass *)class; + toolitem_class = (GtkToolItemClass *)class; + + container_class->add = gtk_separator_tool_item_add; +} + +static void +gtk_separator_tool_item_add (GtkContainer *container, + GtkWidget *child) +{ + g_warning("attempt to add a child to an GtkSeparatorToolItem"); +} + +GtkToolItem * +gtk_separator_tool_item_new (void) +{ + GtkToolItem *self; + + self = g_object_new (GTK_TYPE_SEPARATOR_TOOL_ITEM, + NULL); + + return self; +} diff --git a/gtk/gtkseparatortoolitem.h b/gtk/gtkseparatortoolitem.h new file mode 100644 index 0000000000..dde478c81b --- /dev/null +++ b/gtk/gtkseparatortoolitem.h @@ -0,0 +1,50 @@ +/* gtktoggletoolbutton.h + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * + * 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 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTK_SEPARATOR_TOOL_ITEM_H__ +#define __GTK_SEPARATOR_TOOL_ITEM_H__ + +#include "gtktoolitem.h" + +#define GTK_TYPE_SEPARATOR_TOOL_ITEM (gtk_separator_tool_item_get_type ()) +#define GTK_SEPARATOR_TOOL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SEPARATOR_TOOL_ITEM, GtkSeparatorToolItem)) +#define GTK_SEPARATOR_TOOL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SEPARATOR_TOOL_ITEM, GtkSeparatorToolItemClass)) +#define GTK_IS_SEPARATOR_TOOL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SEPARATOR_TOOL_ITEM)) +#define GTK_IS_SEPARATOR_TOOL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), GTK_TYPE_SEPARATOR_TOOL_ITEM)) +#define GTK_SEPARATOR_TOOL_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_SEPARATOR_TOOL_ITEM, GtkSeparatorToolItemClass)) + +typedef struct _GtkSeparatorToolItem GtkSeparatorToolItem; +typedef struct _GtkSeparatorToolItemClass GtkSeparatorToolItemClass; + +struct _GtkSeparatorToolItem +{ + GtkToolItem parent; +}; + +struct _GtkSeparatorToolItemClass +{ + GtkToolItemClass parent_class; +}; + +GType gtk_separator_tool_item_get_type (void) G_GNUC_CONST; +GtkToolItem *gtk_separator_tool_item_new (void); + +#endif /* __GTK_SEPARATOR_TOOL_ITEM_H__ */ diff --git a/gtk/gtktoggletoolbutton.c b/gtk/gtktoggletoolbutton.c new file mode 100644 index 0000000000..1841d9ff5e --- /dev/null +++ b/gtk/gtktoggletoolbutton.c @@ -0,0 +1,244 @@ +/* gtktoggletoolbutton.c + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * + * 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 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gtktoggletoolbutton.h" +#include "gtkcheckmenuitem.h" +#include "gtklabel.h" +#include "gtktogglebutton.h" +#include "gtkstock.h" +#include "gtkintl.h" + +#define MENU_ID "gtk-toggle-tool-button-menu-id" + +enum { + TOGGLED, + LAST_SIGNAL +}; + +static void gtk_toggle_tool_button_init (GtkToggleToolButton *button); +static void gtk_toggle_tool_button_class_init (GtkToggleToolButtonClass *klass); + +static gboolean gtk_toggle_tool_button_create_menu_proxy (GtkToolItem *button); + +static void button_toggled (GtkWidget *widget, + GtkToggleToolButton *button); +static void menu_item_activated (GtkWidget *widget, + GtkToggleToolButton *button); + +static GObjectClass *parent_class = NULL; +static guint toggle_signals[LAST_SIGNAL] = { 0 }; + +GType +gtk_toggle_tool_button_get_type (void) +{ + static GType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (GtkToggleToolButtonClass), + (GBaseInitFunc) 0, + (GBaseFinalizeFunc) 0, + (GClassInitFunc) gtk_toggle_tool_button_class_init, + (GClassFinalizeFunc) 0, + NULL, + sizeof (GtkToggleToolButton), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_toggle_tool_button_init + }; + + type = g_type_register_static (GTK_TYPE_TOOL_BUTTON, + "GtkToggleToolButton", &type_info, 0); + } + return type; +} + + +static void +gtk_toggle_tool_button_class_init (GtkToggleToolButtonClass *klass) +{ + GObjectClass *object_class; + GtkToolItemClass *toolitem_class; + GtkToolButtonClass *toolbutton_class; + + parent_class = g_type_class_peek_parent (klass); + + object_class = (GObjectClass *)klass; + toolitem_class = (GtkToolItemClass *)klass; + toolbutton_class = (GtkToolButtonClass *)klass; + + toolitem_class->create_menu_proxy = gtk_toggle_tool_button_create_menu_proxy; + toolbutton_class->button_type = GTK_TYPE_TOGGLE_BUTTON; + + toggle_signals[TOGGLED] = + g_signal_new ("toggled", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkToggleToolButtonClass, toggled), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +gtk_toggle_tool_button_init (GtkToggleToolButton *button) +{ + g_signal_connect_object (GTK_TOOL_BUTTON (button)->button, "toggled", + G_CALLBACK (button_toggled), button, 0); +} + +static gboolean +gtk_toggle_tool_button_create_menu_proxy (GtkToolItem *item) +{ + GtkToolButton *tool_button = GTK_TOOL_BUTTON (item); + GtkToggleToolButton *toggle_tool_button = GTK_TOGGLE_TOOL_BUTTON (item); + GtkWidget *menu_item = NULL; + GtkStockItem stock_item; + gboolean use_mnemonic = TRUE; + const char *label = ""; + + if (tool_button->label_widget && GTK_IS_LABEL (tool_button->label_widget)) + label = gtk_label_get_label (GTK_LABEL (tool_button->label_widget)); + else if (tool_button->label_text) + { + label = tool_button->label_text; + use_mnemonic = tool_button->use_underline; + } + else if (tool_button->stock_id && gtk_stock_lookup (tool_button->stock_id, &stock_item)) + label = stock_item.label; + + if (use_mnemonic) + menu_item = gtk_check_menu_item_new_with_mnemonic (label); + else + menu_item = gtk_check_menu_item_new_with_label (label); + + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), + toggle_tool_button->active); + + g_signal_connect_closure_by_id (menu_item, + g_signal_lookup ("activate", G_OBJECT_TYPE (menu_item)), 0, + g_cclosure_new_object (G_CALLBACK (menu_item_activated), + G_OBJECT (toggle_tool_button)), + FALSE); + + gtk_tool_item_set_proxy_menu_item (item, MENU_ID, menu_item); + + return TRUE; +} + +/* There are two activatable widgets, a toggle button and a menu item. + * + * If a widget is activated and the state of the tool button is the same as + * the new state of the activated widget, then the other widget was the one + * that was activated by the user and updated the tool button's state. + * + * If the state of the tool button is not the same as the new state of the + * activated widget, then the activation was activated by the user, and the + * widget needs to make sure the tool button is updated before the other + * widget is activated. This will make sure the other widget a tool button + * in a state that matches its own new state. + */ +static void +menu_item_activated (GtkWidget *menu_item, + GtkToggleToolButton *toggle_tool_button) +{ + GtkToolButton *tool_button = GTK_TOOL_BUTTON (toggle_tool_button); + gboolean menu_active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menu_item)); + + if (toggle_tool_button->active != menu_active) + { + toggle_tool_button->active = menu_active; + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tool_button->button), + toggle_tool_button->active); + + g_signal_emit (G_OBJECT (toggle_tool_button), toggle_signals[TOGGLED], 0); + } +} + +static void +button_toggled (GtkWidget *widget, + GtkToggleToolButton *toggle_tool_button) +{ + gboolean toggle_active = GTK_TOGGLE_BUTTON (widget)->active; + + if (toggle_tool_button->active != toggle_active) + { + GtkWidget *menu_item; + + toggle_tool_button->active = toggle_active; + + if ((menu_item = + gtk_tool_item_get_proxy_menu_item (GTK_TOOL_ITEM (toggle_tool_button), MENU_ID))) + { + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), + toggle_tool_button->active); + } + + g_signal_emit (G_OBJECT (toggle_tool_button), toggle_signals[TOGGLED], 0); + } +} + +GtkToolItem * +gtk_toggle_tool_button_new (void) +{ + GtkToolButton *button; + + button = g_object_new (GTK_TYPE_TOGGLE_TOOL_BUTTON, + NULL); + + return GTK_TOOL_ITEM (button); +} + +GtkToolItem * +gtk_toggle_tool_button_new_from_stock (const gchar *stock_id) +{ + GtkToolButton *button; + + g_return_val_if_fail (stock_id != NULL, NULL); + + button = g_object_new (GTK_TYPE_TOGGLE_TOOL_BUTTON, + "stock_id", stock_id, + NULL); + + return GTK_TOOL_ITEM (button); +} + +void +gtk_toggle_tool_button_set_active (GtkToggleToolButton *button, + gboolean is_active) +{ + g_return_if_fail (GTK_IS_TOGGLE_TOOL_BUTTON (button)); + + is_active = is_active != FALSE; + + if (button->active != is_active) + gtk_button_clicked (GTK_BUTTON (GTK_TOOL_BUTTON (button)->button)); +} + +gboolean +gtk_toggle_tool_button_get_active (GtkToggleToolButton *button) +{ + g_return_val_if_fail (GTK_IS_TOGGLE_TOOL_BUTTON (button), FALSE); + + return button->active; +} diff --git a/gtk/gtktoggletoolbutton.h b/gtk/gtktoggletoolbutton.h new file mode 100644 index 0000000000..5d8e862167 --- /dev/null +++ b/gtk/gtktoggletoolbutton.h @@ -0,0 +1,68 @@ +/* gtktoggletoolbutton.h + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * Copyright (C) 2003 Soeren Sandmann <sandmann@daimi.au.dk> + * + * 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 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTK_TOGGLE_TOOL_BUTTON_H__ +#define __GTK_TOGGLE_TOOL_BUTTON_H__ + +#include "gtktoolbutton.h" + +G_BEGIN_DECLS + +#define GTK_TYPE_TOGGLE_TOOL_BUTTON (gtk_toggle_tool_button_get_type ()) +#define GTK_TOGGLE_TOOL_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_TOGGLE_TOOL_BUTTON, GtkToggleToolButton)) +#define GTK_TOGGLE_TOOL_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_TOGGLE_TOOL_BUTTON, GtkToggleToolButtonClass)) +#define GTK_IS_TOGGLE_TOOL_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_TOGGLE_TOOL_BUTTON)) +#define GTK_IS_TOGGLE_TOOL_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), GTK_TYPE_TOGGLE_TOOL_BUTTON)) +#define GTK_TOGGLE_TOOL_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_TOGGLE_TOOL_BUTTON, GtkToggleToolButtonClass)) + +typedef struct _GtkToggleToolButton GtkToggleToolButton; +typedef struct _GtkToggleToolButtonClass GtkToggleToolButtonClass; + +struct _GtkToggleToolButton +{ + GtkToolButton parent; + + /*< private >*/ + GtkWidget *menu_item; + + guint active : 1; +}; + +struct _GtkToggleToolButtonClass +{ + GtkToolButtonClass parent_class; + + /* signal */ + void (* toggled) (GtkToggleToolButton *button); +}; + +GType gtk_toggle_tool_button_get_type (void) G_GNUC_CONST; +GtkToolItem *gtk_toggle_tool_button_new (void); +GtkToolItem *gtk_toggle_tool_button_new_from_stock (const gchar *stock_id); + +void gtk_toggle_tool_button_set_active (GtkToggleToolButton *button, + gboolean is_active); +gboolean gtk_toggle_tool_button_get_active (GtkToggleToolButton *button); + +G_END_DECLS + +#endif /* __GTK_TOGGLE_TOOL_BUTTON_H__ */ diff --git a/gtk/gtktoolbar.c b/gtk/gtktoolbar.c index df217b99e8..8b4096ed1b 100644 --- a/gtk/gtktoolbar.c +++ b/gtk/gtktoolbar.c @@ -2,6 +2,10 @@ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * GtkToolbar copyright (C) Federico Mena * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * Copyright (C) 2003 Soeren Sandmann <sandmann@daimi.au.dk> + * * 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 @@ -25,22 +29,24 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ -#include <string.h> +#undef GTK_DISABLE_DEPRECATED -#include "gtkbutton.h" -#include "gtktogglebutton.h" +#include "gtkarrow.h" +#include "gtktoolbar.h" +#include "gtkradiotoolbutton.h" +#include "gtkseparatortoolitem.h" +#include "gtkmenu.h" #include "gtkradiobutton.h" -#include "gtklabel.h" -#include "gtkvbox.h" -#include "gtkhbox.h" #include "gtktoolbar.h" +#include "gtkbindings.h" +#include <gdk/gdkkeysyms.h> +#include "gtkmarshalers.h" +#include "gtkmain.h" #include "gtkstock.h" -#include "gtkiconfactory.h" -#include "gtkimage.h" -#include "gtksettings.h" +#include "gtklabel.h" +#include "gtkprivate.h" #include "gtkintl.h" -#include "gtkmarshalers.h" - +#include <string.h> #define DEFAULT_IPADDING 0 #define DEFAULT_SPACE_SIZE 5 @@ -56,175 +62,298 @@ enum { PROP_0, PROP_ORIENTATION, - PROP_TOOLBAR_STYLE + PROP_TOOLBAR_STYLE, + PROP_SHOW_ARROW +}; + +enum { + CHILD_PROP_0, + CHILD_PROP_EXPAND, + CHILD_PROP_HOMOGENEOUS, + CHILD_PROP_PACK_END, }; enum { ORIENTATION_CHANGED, STYLE_CHANGED, + POPUP_CONTEXT_MENU, + MOVE_FOCUS, + FOCUS_ENDS, LAST_SIGNAL }; -typedef struct _GtkToolbarChildSpace GtkToolbarChildSpace; -struct _GtkToolbarChildSpace -{ - GtkToolbarChild child; - - gint alloc_x, alloc_y; -}; - -static void gtk_toolbar_class_init (GtkToolbarClass *class); -static void gtk_toolbar_init (GtkToolbar *toolbar); -static void gtk_toolbar_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_toolbar_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gtk_toolbar_destroy (GtkObject *object); -static gint gtk_toolbar_expose (GtkWidget *widget, - GdkEventExpose *event); -static void gtk_toolbar_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void gtk_toolbar_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static void gtk_toolbar_style_set (GtkWidget *widget, - GtkStyle *prev_style); -static gboolean gtk_toolbar_focus (GtkWidget *widget, - GtkDirectionType dir); -static void gtk_toolbar_screen_changed (GtkWidget *widget, - GdkScreen *previous_screen); -static void gtk_toolbar_show_all (GtkWidget *widget); -static void gtk_toolbar_hide_all (GtkWidget *widget); -static void gtk_toolbar_add (GtkContainer *container, - GtkWidget *widget); -static void gtk_toolbar_remove (GtkContainer *container, - GtkWidget *widget); -static void gtk_toolbar_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data); - -static void gtk_real_toolbar_orientation_changed (GtkToolbar *toolbar, +static void gtk_toolbar_init (GtkToolbar *toolbar); +static void gtk_toolbar_class_init (GtkToolbarClass *klass); + +static void gtk_toolbar_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_toolbar_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static gint gtk_toolbar_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_toolbar_realize (GtkWidget *widget); +static void gtk_toolbar_unrealize (GtkWidget *widget); +static void gtk_toolbar_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_toolbar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_toolbar_style_set (GtkWidget *widget, + GtkStyle *prev_style); +static void gtk_toolbar_direction_changed (GtkWidget *widget, + GtkTextDirection previous_direction); +static gboolean gtk_toolbar_focus (GtkWidget *widget, + GtkDirectionType dir); +static void gtk_toolbar_screen_changed (GtkWidget *widget, + GdkScreen *previous_screen); +static void gtk_toolbar_map (GtkWidget *widget); +static void gtk_toolbar_unmap (GtkWidget *widget); + +static void gtk_toolbar_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time_); +static gboolean gtk_toolbar_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time_); +static void gtk_toolbar_set_child_property (GtkContainer *container, + GtkWidget *child, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_toolbar_get_child_property (GtkContainer *container, + GtkWidget *child, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static void gtk_toolbar_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_toolbar_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_toolbar_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); +static GType gtk_toolbar_child_type (GtkContainer *container); + +static void gtk_toolbar_real_orientation_changed (GtkToolbar *toolbar, GtkOrientation orientation); -static void gtk_real_toolbar_style_changed (GtkToolbar *toolbar, +static void gtk_toolbar_real_style_changed (GtkToolbar *toolbar, GtkToolbarStyle style); -static GtkWidget * gtk_toolbar_internal_insert_element (GtkToolbar *toolbar, - GtkToolbarChildType type, - GtkWidget *widget, - const char *text, - const char *tooltip_text, - const char *tooltip_private_text, - GtkWidget *icon, - GtkSignalFunc callback, - gpointer user_data, - gint position); - -static GtkWidget * gtk_toolbar_internal_insert_item (GtkToolbar *toolbar, - const char *text, - const char *tooltip_text, - const char *tooltip_private_text, - GtkWidget *icon, - GtkSignalFunc callback, - gpointer user_data, - gint position); - -static void gtk_toolbar_update_button_relief (GtkToolbar *toolbar); - -static GtkReliefStyle get_button_relief (GtkToolbar *toolbar); -static gint get_space_size (GtkToolbar *toolbar); -static GtkToolbarSpaceStyle get_space_style (GtkToolbar *toolbar); - +static gboolean gtk_toolbar_move_focus (GtkToolbar *toolbar, + GtkDirectionType dir); +static gboolean gtk_toolbar_focus_ends (GtkToolbar *toolbar, + gboolean home); + +static gboolean gtk_toolbar_button_press (GtkWidget *toolbar, + GdkEventButton *event); +static gboolean gtk_toolbar_arrow_button_press (GtkWidget *button, + GdkEventButton *event, + GtkToolbar *toolbar); +static void gtk_toolbar_arrow_button_clicked (GtkWidget *button, + GtkToolbar *toolbar); +static void gtk_toolbar_update_button_relief (GtkToolbar *toolbar); +static GtkReliefStyle get_button_relief (GtkToolbar *toolbar); +static gint get_space_size (GtkToolbar *toolbar); +static GtkToolbarSpaceStyle get_space_style (GtkToolbar *toolbar); +static gint get_internal_padding (GtkToolbar *toolbar); +static void gtk_toolbar_remove_tool_item (GtkToolbar *toolbar, + GtkToolItem *item); + +static GtkWidget *gtk_toolbar_internal_insert_element (GtkToolbar *toolbar, + GtkToolbarChildType type, + GtkWidget *widget, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data, + gint position, + gboolean use_stock); + + +typedef enum { + DONT_KNOW, + OLD_API, + NEW_API +} ApiMode; + +struct _GtkToolbarPrivate +{ + GList *items; + + GtkWidget *arrow; + GtkWidget *arrow_button; + + gboolean show_arrow; -static GtkContainerClass *parent_class; + gint drop_index; + GdkWindow *drag_highlight; + GtkMenu *menu; -static guint toolbar_signals[LAST_SIGNAL] = { 0 }; + GdkWindow *event_window; + ApiMode api_mode; + GtkSettings *settings; +}; +static GtkContainerClass *parent_class = NULL; +static guint toolbar_signals [LAST_SIGNAL] = { 0 }; GType gtk_toolbar_get_type (void) { - static GType toolbar_type = 0; + static GtkType type = 0; - if (!toolbar_type) + if (!type) { - static const GTypeInfo toolbar_info = - { - sizeof (GtkToolbarClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gtk_toolbar_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GtkToolbar), - 0, /* n_preallocs */ - (GInstanceInitFunc) gtk_toolbar_init, - }; - - toolbar_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkToolbar", - &toolbar_info, 0); + static const GTypeInfo type_info = + { + sizeof (GtkToolbarClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gtk_toolbar_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (GtkToolbar), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_toolbar_init, + }; + + type = g_type_register_static (GTK_TYPE_CONTAINER, + "GtkToolbar", + &type_info, 0); } + + return type; +} + +static void +add_arrow_bindings (GtkBindingSet *binding_set, + guint keysym, + GtkDirectionType dir) +{ + guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left; + + gtk_binding_entry_add_signal (binding_set, keysym, 0, + "move_focus", 1, + GTK_TYPE_DIRECTION_TYPE, dir); + gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0, + "move_focus", 1, + GTK_TYPE_DIRECTION_TYPE, dir); +} - return toolbar_type; +static void +add_ctrl_tab_bindings (GtkBindingSet *binding_set, + GdkModifierType modifiers, + GtkDirectionType direction) +{ + gtk_binding_entry_add_signal (binding_set, + GDK_Tab, GDK_CONTROL_MASK | modifiers, + "move_focus", 1, + GTK_TYPE_DIRECTION_TYPE, direction); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Tab, GDK_CONTROL_MASK | modifiers, + "move_focus", 1, + GTK_TYPE_DIRECTION_TYPE, direction); } static void -gtk_toolbar_class_init (GtkToolbarClass *class) +gtk_toolbar_class_init (GtkToolbarClass *klass) { - GObjectClass *gobject_class; - GtkObjectClass *object_class; + GObjectClass *gobject_class; GtkWidgetClass *widget_class; GtkContainerClass *container_class; + GtkBindingSet *binding_set; - gobject_class = G_OBJECT_CLASS (class); - object_class = (GtkObjectClass *) class; - widget_class = (GtkWidgetClass *) class; - container_class = (GtkContainerClass *) class; - - parent_class = g_type_class_peek_parent (class); - - object_class->destroy = gtk_toolbar_destroy; + parent_class = g_type_class_peek_parent (klass); + + gobject_class = (GObjectClass *)klass; + widget_class = (GtkWidgetClass *)klass; + container_class = (GtkContainerClass *)klass; + gobject_class->set_property = gtk_toolbar_set_property; gobject_class->get_property = gtk_toolbar_get_property; + widget_class->button_press_event = gtk_toolbar_button_press; widget_class->expose_event = gtk_toolbar_expose; widget_class->size_request = gtk_toolbar_size_request; widget_class->size_allocate = gtk_toolbar_size_allocate; widget_class->style_set = gtk_toolbar_style_set; - widget_class->show_all = gtk_toolbar_show_all; - widget_class->hide_all = gtk_toolbar_hide_all; + widget_class->direction_changed = gtk_toolbar_direction_changed; widget_class->focus = gtk_toolbar_focus; widget_class->screen_changed = gtk_toolbar_screen_changed; + widget_class->realize = gtk_toolbar_realize; + widget_class->unrealize = gtk_toolbar_unrealize; + widget_class->map = gtk_toolbar_map; + widget_class->unmap = gtk_toolbar_unmap; + + widget_class->drag_leave = gtk_toolbar_drag_leave; + widget_class->drag_motion = gtk_toolbar_drag_motion; - container_class->add = gtk_toolbar_add; + container_class->add = gtk_toolbar_add; container_class->remove = gtk_toolbar_remove; container_class->forall = gtk_toolbar_forall; + container_class->child_type = gtk_toolbar_child_type; + container_class->get_child_property = gtk_toolbar_get_child_property; + container_class->set_child_property = gtk_toolbar_set_child_property; + + klass->orientation_changed = gtk_toolbar_real_orientation_changed; + klass->style_changed = gtk_toolbar_real_style_changed; - class->orientation_changed = gtk_real_toolbar_orientation_changed; - class->style_changed = gtk_real_toolbar_style_changed; - toolbar_signals[ORIENTATION_CHANGED] = g_signal_new ("orientation_changed", - G_OBJECT_CLASS_TYPE (gobject_class), + G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GtkToolbarClass, orientation_changed), NULL, NULL, - _gtk_marshal_VOID__ENUM, + g_cclosure_marshal_VOID__ENUM, G_TYPE_NONE, 1, GTK_TYPE_ORIENTATION); toolbar_signals[STYLE_CHANGED] = g_signal_new ("style_changed", - G_OBJECT_CLASS_TYPE (gobject_class), + G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GtkToolbarClass, style_changed), NULL, NULL, - _gtk_marshal_VOID__ENUM, + g_cclosure_marshal_VOID__ENUM, G_TYPE_NONE, 1, GTK_TYPE_TOOLBAR_STYLE); - + toolbar_signals[POPUP_CONTEXT_MENU] = + g_signal_new ("popup_context_menu", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkToolbarClass, popup_context_menu), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + toolbar_signals[MOVE_FOCUS] = + _gtk_binding_signal_new ("move_focus", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_CALLBACK (gtk_toolbar_move_focus), + NULL, NULL, + _gtk_marshal_BOOLEAN__ENUM, + G_TYPE_BOOLEAN, 1, + GTK_TYPE_DIRECTION_TYPE); + toolbar_signals[FOCUS_ENDS] = + _gtk_binding_signal_new ("focus_ends", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_CALLBACK (gtk_toolbar_focus_ends), + NULL, NULL, + _gtk_marshal_BOOLEAN__BOOLEAN, + G_TYPE_BOOLEAN, 1, + G_TYPE_BOOLEAN); + + /* properties */ g_object_class_install_property (gobject_class, PROP_ORIENTATION, g_param_spec_enum ("orientation", @@ -233,17 +362,49 @@ gtk_toolbar_class_init (GtkToolbarClass *class) GTK_TYPE_ORIENTATION, GTK_ORIENTATION_HORIZONTAL, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, - PROP_TOOLBAR_STYLE, - g_param_spec_enum ("toolbar_style", + + g_object_class_install_property (gobject_class, + PROP_TOOLBAR_STYLE, + g_param_spec_enum ("toolbar_style", _("Toolbar Style"), _("How to draw the toolbar"), GTK_TYPE_TOOLBAR_STYLE, GTK_TOOLBAR_ICONS, G_PARAM_READWRITE)); - - + g_object_class_install_property (gobject_class, + PROP_SHOW_ARROW, + g_param_spec_boolean ("show_arrow", + _("Show Arrow"), + _("If an arrow should be shown if the toolbar doesn't fit"), + FALSE, + G_PARAM_READWRITE)); + + /* child properties */ + gtk_container_class_install_child_property (container_class, + CHILD_PROP_EXPAND, + g_param_spec_boolean ("expand", + _("Expand"), + _("Whether the item should receive extra space when the toolbar grows"), + TRUE, + G_PARAM_READWRITE)); + + gtk_container_class_install_child_property (container_class, + CHILD_PROP_HOMOGENEOUS, + g_param_spec_boolean ("homogeneous", + _("Homogeneous"), + _("Whether the item should be the same size as other homogeneous items"), + TRUE, + G_PARAM_READWRITE)); + + gtk_container_class_install_child_property (container_class, + CHILD_PROP_PACK_END, + g_param_spec_uint ("pack_end", + _("Pack End"), + _("Whether the item is positioned at the end of the toolbar"), + 0, G_MAXINT, 0, + G_PARAM_READWRITE)); + + /* style properties */ gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("space_size", _("Spacer size"), @@ -252,7 +413,7 @@ gtk_toolbar_class_init (GtkToolbarClass *class) G_MAXINT, DEFAULT_SPACE_SIZE, G_PARAM_READABLE)); - + gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("internal_padding", _("Internal padding"), @@ -261,24 +422,22 @@ gtk_toolbar_class_init (GtkToolbarClass *class) G_MAXINT, DEFAULT_IPADDING, G_PARAM_READABLE)); - + gtk_widget_class_install_style_property (widget_class, g_param_spec_enum ("space_style", _("Space style"), _("Whether spacers are vertical lines or just blank"), GTK_TYPE_TOOLBAR_SPACE_STYLE, DEFAULT_SPACE_STYLE, - G_PARAM_READABLE)); - + gtk_widget_class_install_style_property (widget_class, g_param_spec_enum ("button_relief", - _("Button relief"), - _("Type of bevel around toolbar buttons"), + _("Button relief"), + _("Type of bevel around toolbar buttons"), GTK_TYPE_RELIEF_STYLE, GTK_RELIEF_NONE, G_PARAM_READABLE)); - gtk_widget_class_install_style_property (widget_class, g_param_spec_enum ("shadow_type", _("Shadow type"), @@ -300,115 +459,113 @@ gtk_toolbar_class_init (GtkToolbarClass *class) GTK_TYPE_ICON_SIZE, DEFAULT_ICON_SIZE, G_PARAM_READWRITE)); -} - -static void -style_change_notify (GtkToolbar *toolbar) -{ - if (!toolbar->style_set) - { - /* pretend it was set, then unset, thus reverting to new default */ - toolbar->style_set = TRUE; - gtk_toolbar_unset_style (toolbar); - } -} - -static void -icon_size_change_notify (GtkToolbar *toolbar) -{ - if (!toolbar->icon_size_set) - { - /* pretend it was set, then unset, thus reverting to new default */ - toolbar->icon_size_set = TRUE; - gtk_toolbar_unset_icon_size (toolbar); - } -} -static GtkSettings * -toolbar_get_settings (GtkToolbar *toolbar) -{ - return g_object_get_data (G_OBJECT (toolbar), "gtk-toolbar-settings"); + binding_set = gtk_binding_set_by_class (klass); + + add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT); + add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT); + add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP); + add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN); + + gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0, + "focus_ends", 1, + G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_Home, 0, + "focus_ends", 1, + G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0, + "focus_ends", 1, + G_TYPE_BOOLEAN, FALSE); + gtk_binding_entry_add_signal (binding_set, GDK_End, 0, + "focus_ends", 1, + G_TYPE_BOOLEAN, FALSE); + + add_ctrl_tab_bindings (binding_set, 0, GTK_DIR_RIGHT); + add_ctrl_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_LEFT); + + g_type_class_add_private (gobject_class, sizeof (GtkToolbarPrivate)); } static void -gtk_toolbar_screen_changed (GtkWidget *widget, - GdkScreen *previous_screen) +gtk_toolbar_init (GtkToolbar *toolbar) { - GtkToolbar *toolbar = GTK_TOOLBAR (widget); - GtkSettings *old_settings = toolbar_get_settings (toolbar); - GtkSettings *settings; - - if (gtk_widget_has_screen (GTK_WIDGET (toolbar))) - settings = gtk_widget_get_settings (GTK_WIDGET (toolbar)); - else - settings = NULL; - - if (settings == old_settings) - return; - - if (old_settings) - { - g_signal_handler_disconnect (old_settings, toolbar->style_set_connection); - g_signal_handler_disconnect (old_settings, toolbar->icon_size_connection); + GtkToolbarPrivate *priv; + + GTK_WIDGET_UNSET_FLAGS (toolbar, GTK_CAN_FOCUS); + GTK_WIDGET_SET_FLAGS (toolbar, GTK_NO_WINDOW); - g_object_unref (old_settings); - } + priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); - if (settings) - { - toolbar->style_set_connection = - g_signal_connect_swapped (settings, - "notify::gtk-toolbar-style", - G_CALLBACK (style_change_notify), - toolbar); - - toolbar->icon_size_connection = - g_signal_connect_swapped (settings, - "notify::gtk-toolbar-icon-size", - G_CALLBACK (icon_size_change_notify), - toolbar); + toolbar->orientation = GTK_ORIENTATION_HORIZONTAL; + toolbar->style = DEFAULT_TOOLBAR_STYLE; + toolbar->icon_size = DEFAULT_ICON_SIZE; + toolbar->tooltips = gtk_tooltips_new (); + g_object_ref (toolbar->tooltips); + gtk_object_sink (GTK_OBJECT (toolbar->tooltips)); + + priv->arrow_button = gtk_toggle_button_new (); + g_signal_connect (priv->arrow_button, "button_press_event", + G_CALLBACK (gtk_toolbar_arrow_button_press), toolbar); + g_signal_connect (priv->arrow_button, "clicked", + G_CALLBACK (gtk_toolbar_arrow_button_clicked), toolbar); + gtk_button_set_relief (GTK_BUTTON (priv->arrow_button), + get_button_relief (toolbar)); + + priv->api_mode = DONT_KNOW; + + gtk_button_set_focus_on_click (GTK_BUTTON (priv->arrow_button), FALSE); + + priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); + gtk_widget_show (priv->arrow); + gtk_container_add (GTK_CONTAINER (priv->arrow_button), priv->arrow); + + gtk_widget_set_parent (priv->arrow_button, GTK_WIDGET (toolbar)); + /* which child position a drop will occur at */ + priv->drop_index = -1; + priv->drag_highlight = NULL; - g_object_ref (settings); - g_object_set_data (G_OBJECT (toolbar), "gtk-toolbar-settings", settings); - } - else - g_object_set_data (G_OBJECT (toolbar), "gtk-toolbar-settings", NULL); + priv->menu = NULL; - style_change_notify (toolbar); - icon_size_change_notify (toolbar); + priv->settings = NULL; } -static void -gtk_toolbar_init (GtkToolbar *toolbar) +static gboolean +toolbar_item_visible (GtkToolbar *toolbar, + GtkToolItem *item) { - GTK_WIDGET_SET_FLAGS (toolbar, GTK_NO_WINDOW); - GTK_WIDGET_UNSET_FLAGS (toolbar, GTK_CAN_FOCUS); - - toolbar->num_children = 0; - toolbar->children = NULL; - toolbar->orientation = GTK_ORIENTATION_HORIZONTAL; - toolbar->icon_size = DEFAULT_ICON_SIZE; - toolbar->style = DEFAULT_TOOLBAR_STYLE; - toolbar->tooltips = gtk_tooltips_new (); - g_object_ref (toolbar->tooltips); - gtk_object_sink (GTK_OBJECT (toolbar->tooltips)); + if (GTK_WIDGET_VISIBLE (item) && + ((toolbar->orientation == GTK_ORIENTATION_HORIZONTAL && item->visible_horizontal) || + (toolbar->orientation == GTK_ORIENTATION_VERTICAL && item->visible_vertical))) + { + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + + /* With the old toolbar you could hide a button by calling gtk_widget_hide() + * on it. This doesn't work with the new API because the GtkToolItem will not be + * hidden. + */ + if (priv->api_mode == OLD_API) + { + GtkWidget *bin_child = GTK_BIN (item)->child; + + if (bin_child && !GTK_WIDGET_VISIBLE (bin_child)) + return FALSE; + } + + return TRUE; + } - toolbar->button_maxw = 0; - toolbar->button_maxh = 0; - - toolbar->style_set = FALSE; - toolbar->icon_size_set = FALSE; + return FALSE; } static void -gtk_toolbar_set_property (GObject *object, - guint prop_id, +gtk_toolbar_set_property (GObject *object, + guint prop_id, const GValue *value, GParamSpec *pspec) { GtkToolbar *toolbar = GTK_TOOLBAR (object); - + switch (prop_id) { case PROP_ORIENTATION: @@ -417,17 +574,24 @@ gtk_toolbar_set_property (GObject *object, case PROP_TOOLBAR_STYLE: gtk_toolbar_set_style (toolbar, g_value_get_enum (value)); break; + case PROP_SHOW_ARROW: + gtk_toolbar_set_show_arrow (toolbar, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } } static void -gtk_toolbar_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +gtk_toolbar_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { GtkToolbar *toolbar = GTK_TOOLBAR (object); - + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + switch (prop_id) { case PROP_ORIENTATION: @@ -436,122 +600,153 @@ gtk_toolbar_get_property (GObject *object, case PROP_TOOLBAR_STYLE: g_value_set_enum (value, toolbar->style); break; + case PROP_SHOW_ARROW: + g_value_set_boolean (value, priv->show_arrow); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } -GtkWidget* -gtk_toolbar_new (void) +static void +gtk_toolbar_map (GtkWidget *widget) { - GtkToolbar *toolbar; + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget); - toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL); + GTK_WIDGET_CLASS (parent_class)->map (widget); - return GTK_WIDGET (toolbar); + if (priv->event_window) + gdk_window_show_unraised (priv->event_window); } static void -gtk_toolbar_destroy (GtkObject *object) +gtk_toolbar_unmap (GtkWidget *widget) { - GtkToolbar *toolbar; - GList *children; + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget); - g_return_if_fail (GTK_IS_TOOLBAR (object)); + if (priv->event_window) + gdk_window_hide (priv->event_window); - toolbar = GTK_TOOLBAR (object); - - if (toolbar->tooltips) - { - g_object_unref (toolbar->tooltips); - toolbar->tooltips = NULL; - } - - for (children = toolbar->children; children; children = children->next) - { - GtkToolbarChild *child; - - child = children->data; - - if (child->type != GTK_TOOLBAR_CHILD_SPACE) - { - g_object_ref (child->widget); - gtk_widget_unparent (child->widget); - gtk_widget_destroy (child->widget); - g_object_unref (child->widget); - } - - g_free (child); - } - g_list_free (toolbar->children); - toolbar->children = NULL; - - GTK_OBJECT_CLASS (parent_class)->destroy (object); + GTK_WIDGET_CLASS (parent_class)->unmap (widget); } static void -gtk_toolbar_paint_space_line (GtkWidget *widget, - GdkRectangle *area, - GtkToolbarChild *child) +gtk_toolbar_paint_space_line (GtkWidget *widget, + GdkRectangle *area, + GtkToolItem *item) { GtkToolbar *toolbar; - GtkToolbarChildSpace *child_space; + GtkAllocation *allocation; gint space_size; - g_return_if_fail (GTK_IS_TOOLBAR (widget)); - g_return_if_fail (child != NULL); - g_return_if_fail (child->type == GTK_TOOLBAR_CHILD_SPACE); + g_return_if_fail (GTK_BIN (item)->child == NULL); toolbar = GTK_TOOLBAR (widget); - child_space = (GtkToolbarChildSpace *) child; + allocation = >K_WIDGET (item)->allocation; space_size = get_space_size (toolbar); if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) gtk_paint_vline (widget->style, widget->window, GTK_WIDGET_STATE (widget), area, widget, "toolbar", - child_space->alloc_y + toolbar->button_maxh * + allocation->y + allocation->height * SPACE_LINE_START / SPACE_LINE_DIVISION, - child_space->alloc_y + toolbar->button_maxh * + allocation->y + allocation->height * SPACE_LINE_END / SPACE_LINE_DIVISION, - child_space->alloc_x + - (space_size - - widget->style->xthickness) / 2); - else + allocation->x + (space_size-widget->style->xthickness)/2); + else if (toolbar->orientation == GTK_ORIENTATION_VERTICAL) gtk_paint_hline (widget->style, widget->window, GTK_WIDGET_STATE (widget), area, widget, "toolbar", - child_space->alloc_x + toolbar->button_maxw * + allocation->x + allocation->width * SPACE_LINE_START / SPACE_LINE_DIVISION, - child_space->alloc_x + toolbar->button_maxw * + allocation->x + allocation->width * SPACE_LINE_END / SPACE_LINE_DIVISION, - child_space->alloc_y + - (space_size - - widget->style->ythickness) / 2); + allocation->y + (space_size-widget->style->ythickness)/2); +} + +static void +gtk_toolbar_realize (GtkWidget *widget) +{ + GtkToolbar *toolbar = GTK_TOOLBAR (widget); + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + + GdkWindowAttr attributes; + gint attributes_mask; + gint border_width; + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + border_width = GTK_CONTAINER (widget)->border_width; + + attributes.wclass = GDK_INPUT_ONLY; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x + border_width; + attributes.y = widget->allocation.y + border_width; + attributes.width = widget->allocation.width - border_width * 2; + attributes.height = widget->allocation.height - border_width * 2; + attributes.event_mask = gtk_widget_get_events (widget); + /* FIXME: does GDK_EXPOSURE_MASK make sense for an input-only window? + * If it doesn't, then it should be removed here and in gtkbutton.c, + * gtkmenuitem.c, and maybe other places + */ + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y; + + widget->window = gtk_widget_get_parent_window (widget); + g_object_ref (widget->window); + + priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (priv->event_window, toolbar); +} + +static void +gtk_toolbar_unrealize (GtkWidget *widget) +{ + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget); + + if (priv->drag_highlight) + { + gdk_window_set_user_data (priv->drag_highlight, NULL); + gdk_window_destroy (priv->drag_highlight); + priv->drag_highlight = NULL; + } + + if (priv->event_window) + { + gdk_window_set_user_data (priv->event_window, NULL); + gdk_window_destroy (priv->event_window); + priv->event_window = NULL; + } + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); } static gint gtk_toolbar_expose (GtkWidget *widget, GdkEventExpose *event) { - GtkToolbar *toolbar; - GList *children; - GtkToolbarChild *child; + GtkToolbar *toolbar = GTK_TOOLBAR (widget); + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + + GList *items; gint border_width; - g_return_val_if_fail (GTK_IS_TOOLBAR (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - border_width = GTK_CONTAINER (widget)->border_width; if (GTK_WIDGET_DRAWABLE (widget)) { GtkShadowType shadow_type; - toolbar = GTK_TOOLBAR (widget); - gtk_widget_style_get (widget, "shadow_type", &shadow_type, NULL); gtk_paint_box (widget->style, @@ -559,27 +754,31 @@ gtk_toolbar_expose (GtkWidget *widget, GTK_WIDGET_STATE (widget), shadow_type, &event->area, widget, "toolbar", - widget->allocation.x + border_width, - widget->allocation.y + border_width, + border_width + widget->allocation.x, + border_width + widget->allocation.y, widget->allocation.width - 2 * border_width, widget->allocation.height - 2 * border_width); - - for (children = toolbar->children; children; children = children->next) - { - child = children->data; + } - if (child->type == GTK_TOOLBAR_CHILD_SPACE) - { - if (get_space_style (toolbar) == GTK_TOOLBAR_SPACE_LINE) - gtk_toolbar_paint_space_line (widget, &event->area, child); - } - else - gtk_container_propagate_expose (GTK_CONTAINER (widget), - child->widget, - event); - } + items = priv->items; + while (items) + { + GtkToolItem *item = GTK_TOOL_ITEM (items->data); + + if (GTK_BIN (item)->child) + gtk_container_propagate_expose (GTK_CONTAINER (widget), + GTK_WIDGET (item), + event); + else if (GTK_WIDGET_MAPPED (item) && get_space_style (toolbar) == GTK_TOOLBAR_SPACE_LINE) + gtk_toolbar_paint_space_line (widget, &event->area, item); + + items = items->next; } + gtk_container_propagate_expose (GTK_CONTAINER (widget), + priv->arrow_button, + event); + return FALSE; } @@ -587,297 +786,928 @@ static void gtk_toolbar_size_request (GtkWidget *widget, GtkRequisition *requisition) { - GtkToolbar *toolbar; - GList *children; - GtkToolbarChild *child; - gint nbuttons; - gint button_maxw, button_maxh; - gint widget_maxw, widget_maxh; - GtkRequisition child_requisition; - gint space_size; + GtkToolbar *toolbar = GTK_TOOLBAR (widget); + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + gint space_size = get_space_size (toolbar); + GList *list; + gint max_child_height; + gint max_child_width; + gint max_homogeneous_child_width; + gint max_homogeneous_child_height; + gint homogeneous_size; + gint long_req; + gint pack_end_size; + gint pack_front_size; gint ipadding; - - g_return_if_fail (GTK_IS_TOOLBAR (widget)); - g_return_if_fail (requisition != NULL); + GtkRequisition arrow_requisition; - toolbar = GTK_TOOLBAR (widget); + max_homogeneous_child_width = 0; + max_homogeneous_child_height = 0; + max_child_width = 0; + max_child_height = 0; + for (list = priv->items; list != NULL; list = list->next) + { + GtkRequisition requisition; + GtkToolItem *item = list->data; + + if (!toolbar_item_visible (toolbar, item)) + continue; - requisition->width = GTK_CONTAINER (toolbar)->border_width * 2; - requisition->height = GTK_CONTAINER (toolbar)->border_width * 2; - nbuttons = 0; - button_maxw = 0; - button_maxh = 0; - widget_maxw = 0; - widget_maxh = 0; + gtk_widget_size_request (GTK_WIDGET (item), &requisition); + + max_child_width = MAX (max_child_width, requisition.width); + max_child_height = MAX (max_child_height, requisition.height); - space_size = get_space_size (toolbar); + if (GTK_TOOL_ITEM (item)->homogeneous && GTK_BIN (item)->child) + { + max_homogeneous_child_width = MAX (max_homogeneous_child_width, requisition.width); + max_homogeneous_child_height = MAX (max_homogeneous_child_height, requisition.height); + } + } + + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + homogeneous_size = max_homogeneous_child_width; + else + homogeneous_size = max_homogeneous_child_height; - for (children = toolbar->children; children; children = children->next) + pack_end_size = 0; + pack_front_size = 0; + for (list = priv->items; list != NULL; list = list->next) { - child = children->data; - - switch (child->type) + GtkToolItem *item = list->data; + guint size; + + if (!toolbar_item_visible (toolbar, item)) + continue; + + if (!GTK_BIN (item)->child) + { + size = space_size; + } + else if (item->homogeneous) + { + size = homogeneous_size; + } + else { - case GTK_TOOLBAR_CHILD_SPACE: + GtkRequisition requisition; + + gtk_widget_size_request (GTK_WIDGET (item), &requisition); + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) - requisition->width += space_size; + size = requisition.width; else - requisition->height += space_size; - - break; - - case GTK_TOOLBAR_CHILD_BUTTON: - case GTK_TOOLBAR_CHILD_RADIOBUTTON: - case GTK_TOOLBAR_CHILD_TOGGLEBUTTON: - if (GTK_WIDGET_VISIBLE (child->widget)) - { - gtk_widget_size_request (child->widget, &child_requisition); - - nbuttons++; - button_maxw = MAX (button_maxw, child_requisition.width); - button_maxh = MAX (button_maxh, child_requisition.height); - } + size = requisition.height; + } + + if (item->pack_end) + pack_end_size += size; + else + pack_front_size += size; + } + + if (priv->show_arrow) + { + gtk_widget_size_request (priv->arrow_button, &arrow_requisition); + + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + long_req = arrow_requisition.width; + else + long_req = arrow_requisition.height; - break; + /* There is no point requesting space for the arrow if that would take + * up more space than all the items combined + */ + long_req = MIN (long_req, pack_front_size + pack_end_size); + } + else + { + arrow_requisition.height = 0; + arrow_requisition.width = 0; + + long_req = pack_end_size + pack_front_size; + } + + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + { + requisition->width = long_req; + requisition->height = MAX (max_child_height, arrow_requisition.height); + } + else + { + requisition->height = long_req; + requisition->width = MAX (max_child_width, arrow_requisition.width); + } + + /* Extra spacing */ + ipadding = get_internal_padding (toolbar); - case GTK_TOOLBAR_CHILD_WIDGET: - if (GTK_WIDGET_VISIBLE (child->widget)) - { - gtk_widget_size_request (child->widget, &child_requisition); + requisition->width += 2 * (ipadding + GTK_CONTAINER (toolbar)->border_width); + requisition->height += 2 * (ipadding + GTK_CONTAINER (toolbar)->border_width); + + toolbar->button_maxw = max_homogeneous_child_width; + toolbar->button_maxh = max_homogeneous_child_height; +} - widget_maxw = MAX (widget_maxw, child_requisition.width); - widget_maxh = MAX (widget_maxh, child_requisition.height); +static void +fixup_allocation_for_rtl (gint total_size, + GtkAllocation *allocation) +{ + allocation->x += (total_size - (2 * allocation->x + allocation->width)); +} - if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) - requisition->width += child_requisition.width; - else - requisition->height += child_requisition.height; - } +static void +fixup_allocation_for_vertical (GtkAllocation *allocation) +{ + gint tmp; + + tmp = allocation->x; + allocation->x = allocation->y; + allocation->y = tmp; + + tmp = allocation->width; + allocation->width = allocation->height; + allocation->height = tmp; +} - break; +static gint +get_item_size (GtkToolbar *toolbar, + GtkWidget *child) +{ + GtkRequisition requisition; + GtkToolItem *item = GTK_TOOL_ITEM (child); - default: - g_assert_not_reached (); - } - } + if (!GTK_BIN (item)->child) + return get_space_size (toolbar); + gtk_widget_get_child_requisition (child, &requisition); + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) { - requisition->width += nbuttons * button_maxw; - requisition->height += MAX (button_maxh, widget_maxh); + if (item->homogeneous) + return toolbar->button_maxw; + else + return requisition.width; } else { - requisition->width += MAX (button_maxw, widget_maxw); - requisition->height += nbuttons * button_maxh; + if (item->homogeneous) + return toolbar->button_maxh; + else + return requisition.height; } - - /* Extra spacing */ - gtk_widget_style_get (widget, "internal_padding", &ipadding, NULL); - - requisition->width += 2 * ipadding; - requisition->height += 2 * ipadding; - - toolbar->button_maxw = button_maxw; - toolbar->button_maxh = button_maxh; } static void gtk_toolbar_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { - GtkToolbar *toolbar; - GList *children; - GtkToolbarChild *child; - GtkToolbarChildSpace *child_space; - GtkAllocation alloc; - GtkRequisition child_requisition; - gint x_border_width, y_border_width; + GtkToolbar *toolbar = GTK_TOOLBAR (widget); + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); gint space_size; - gint ipadding; - GtkTextDirection direction; - gint ltr_x = 0; /* Quiet GCC */ - - g_return_if_fail (GTK_IS_TOOLBAR (widget)); - g_return_if_fail (allocation != NULL); + GtkAllocation *allocations; + GtkAllocation arrow_allocation; + gint arrow_size; + gint size, pos, short_size; + GList *list; + gint i; + gboolean need_arrow; + gint n_expand_items; + gint border_width; + gint available_size; + gint n_items; + gint needed_size; + GList *items; + GtkRequisition arrow_requisition; - toolbar = GTK_TOOLBAR (widget); widget->allocation = *allocation; - - direction = gtk_widget_get_direction (widget); - x_border_width = GTK_CONTAINER (toolbar)->border_width; - y_border_width = GTK_CONTAINER (toolbar)->border_width; + space_size = get_space_size (toolbar); + + border_width = GTK_CONTAINER (toolbar)->border_width; - gtk_widget_style_get (widget, "internal_padding", &ipadding, NULL); + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (priv->event_window, + allocation->x + border_width, + allocation->y + border_width, + allocation->width - border_width * 2, + allocation->height - border_width * 2); + } + + border_width += get_internal_padding (toolbar); - x_border_width += ipadding; - y_border_width += ipadding; + gtk_widget_get_child_requisition (GTK_WIDGET (priv->arrow_button), + &arrow_requisition); if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) - ltr_x = allocation->x + x_border_width; + { + available_size = size = allocation->width - 2 * border_width; + short_size = allocation->height - 2 * border_width; + arrow_size = arrow_requisition.width; + } else - alloc.y = allocation->y + y_border_width; + { + available_size = size = allocation->height - 2 * border_width; + short_size = allocation->width - 2 * border_width; + arrow_size = arrow_requisition.height; + } - space_size = get_space_size (toolbar); - - for (children = toolbar->children; children; children = children->next) + n_items = g_list_length (priv->items); + allocations = g_new0 (GtkAllocation, n_items); + + needed_size = 0; + for (list = priv->items; list != NULL; list = list->next) { - child = children->data; + GtkToolItem *item = list->data; + + if (toolbar_item_visible (toolbar, item)) + needed_size += get_item_size (toolbar, GTK_WIDGET (item)); + } - switch (child->type) - { - case GTK_TOOLBAR_CHILD_SPACE: + need_arrow = (needed_size > available_size) && priv->show_arrow; - child_space = (GtkToolbarChildSpace *) child; + if (need_arrow) + size = available_size - arrow_size; + else + size = available_size; - if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) - { - if (direction == GTK_TEXT_DIR_LTR) - child_space->alloc_x = ltr_x; - else - child_space->alloc_x = allocation->width - ltr_x - space_size; - child_space->alloc_y = allocation->y + (allocation->height - toolbar->button_maxh) / 2; - ltr_x += space_size; - } - else + items = g_list_copy (priv->items); + + /* calculate widths of pack end items */ + for (list = g_list_last (items), i = 0; list != NULL; list = list->prev, ++i) + { + GtkToolItem *item = list->data; + GtkAllocation *allocation = &(allocations[n_items - i - 1]); + gint item_size; + + if (!item->pack_end || !toolbar_item_visible (toolbar, item)) + continue; + + item_size = get_item_size (toolbar, GTK_WIDGET (item)); + if (item_size <= size) + { + size -= item_size; + allocation->width = item_size; + item->overflow_item = FALSE; + } + else + { + while (list) { - child_space->alloc_x = allocation->x + (allocation->width - toolbar->button_maxw) / 2; - child_space->alloc_y = alloc.y; - alloc.y += space_size; + item = list->data; + if (item->pack_end) + item->overflow_item = TRUE; + + list = list->prev; } - break; + } + } - case GTK_TOOLBAR_CHILD_BUTTON: - case GTK_TOOLBAR_CHILD_RADIOBUTTON: - case GTK_TOOLBAR_CHILD_TOGGLEBUTTON: - if (!GTK_WIDGET_VISIBLE (child->widget)) - break; + /* calculate widths of pack front items */ + for (list = items, i = 0; list != NULL; list = list->next, ++i) + { + GtkToolItem *item = list->data; + gint item_size; - alloc.width = toolbar->button_maxw; - alloc.height = toolbar->button_maxh; + if (item->pack_end || !toolbar_item_visible (toolbar, item)) + continue; - if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + item_size = get_item_size (toolbar, GTK_WIDGET (item)); + if (item_size <= size) + { + size -= item_size; + allocations[i].width = item_size; + item->overflow_item = FALSE; + } + else + { + while (list) { - if (direction == GTK_TEXT_DIR_LTR) - alloc.x = ltr_x; - else - alloc.x = allocation->width - ltr_x - alloc.width; - alloc.y = allocation->y + (allocation->height - toolbar->button_maxh) / 2; + item = list->data; + if (!item->pack_end) + item->overflow_item = TRUE; + list = list->next; } - else - alloc.x = allocation->x + (allocation->width - toolbar->button_maxw) / 2; - - gtk_widget_size_allocate (child->widget, &alloc); + break; + } + } - if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) - ltr_x += toolbar->button_maxw; - else - alloc.y += toolbar->button_maxh; + if (need_arrow) + { + arrow_allocation.width = arrow_size; + arrow_allocation.height = short_size; + } + + /* expand expandable items */ + n_expand_items = 0; + for (list = priv->items; list != NULL; list = list->next) + { + GtkToolItem *item = list->data; + + if (toolbar_item_visible (toolbar, item) && item->expand && + !item->overflow_item && GTK_BIN (item)->child) + { + n_expand_items++; + } + } + + for (list = items, i = 0; list != NULL; list = list->next, ++i) + { + GtkToolItem *item = list->data; + + if (toolbar_item_visible (toolbar, item) && item->expand && + !item->overflow_item && GTK_BIN (item)->child) + { + gint extra = size / n_expand_items; + if (size % n_expand_items != 0) + extra++; - break; + allocations[i].width += extra; + size -= extra; + n_expand_items--; + } + } - case GTK_TOOLBAR_CHILD_WIDGET: - if (!GTK_WIDGET_VISIBLE (child->widget)) - break; + g_assert (n_expand_items == 0); + + /* position pack front items */ + pos = border_width; + for (list = items, i = 0; list != NULL; list = list->next, ++i) + { + GtkToolItem *item = list->data; + + if (toolbar_item_visible (toolbar, item) && !item->overflow_item && !item->pack_end) + { + allocations[i].x = pos; + allocations[i].y = border_width; + allocations[i].height = short_size; - gtk_widget_get_child_requisition (child->widget, &child_requisition); - - alloc.width = child_requisition.width; - alloc.height = child_requisition.height; + pos += allocations[i].width; + } + } - if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) - { - if (direction == GTK_TEXT_DIR_LTR) - alloc.x = ltr_x; - else - alloc.x = allocation->width - ltr_x - alloc.width; - alloc.y = allocation->y + (allocation->height - child_requisition.height) / 2; - } - else - alloc.x = allocation->x + (allocation->width - child_requisition.width) / 2; + /* position pack end items */ + pos = available_size + border_width; + for (list = g_list_last (items), i = 0; list != NULL; list = list->prev, ++i) + { + GtkToolItem *item = list->data; + + if (toolbar_item_visible (toolbar, item) && !item->overflow_item && item->pack_end) + { + GtkAllocation *allocation = &(allocations[n_items - i - 1]); - gtk_widget_size_allocate (child->widget, &alloc); + allocation->x = pos - allocation->width; + allocation->y = border_width; + allocation->height = short_size; + + pos -= allocation->width; + } + } - if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) - ltr_x += child_requisition.width; - else - alloc.y += child_requisition.height; + /* position arrow */ + if (need_arrow) + { + arrow_allocation.x = pos - arrow_allocation.width; + arrow_allocation.y = border_width; + } + + /* fix up allocations in the vertical or RTL cases */ + if (toolbar->orientation == GTK_ORIENTATION_VERTICAL) + { + for (i = 0; i < n_items; ++i) + fixup_allocation_for_vertical (&(allocations[i])); + + if (need_arrow) + fixup_allocation_for_vertical (&arrow_allocation); + } + else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL) + { + for (i = 0; i < n_items; ++i) + fixup_allocation_for_rtl (available_size, &(allocations[i])); - break; + if (need_arrow) + fixup_allocation_for_rtl (available_size, &arrow_allocation); + } + + /* translate the items by allocation->(x,y) */ + for (i = 0; i < n_items; ++i) + { + allocations[i].x += allocation->x; + allocations[i].y += allocation->y; + } - default: - g_assert_not_reached (); + if (need_arrow) + { + arrow_allocation.x += allocation->x; + arrow_allocation.y += allocation->y; + } + + /* finally allocate the items */ + for (list = items, i = 0; list != NULL; list = list->next, i++) + { + GtkToolItem *item = list->data; + + if (toolbar_item_visible (toolbar, item) && !item->overflow_item) + { + gtk_widget_size_allocate (GTK_WIDGET (item), &(allocations[i])); + gtk_widget_set_child_visible (GTK_WIDGET (item), TRUE); + } + else + { + gtk_widget_set_child_visible (GTK_WIDGET (item), FALSE); } } + + if (need_arrow) + { + gtk_widget_size_allocate (GTK_WIDGET (priv->arrow_button), + &arrow_allocation); + gtk_widget_show (GTK_WIDGET (priv->arrow_button)); + } + else + { + gtk_widget_hide (GTK_WIDGET (priv->arrow_button)); + } + + g_free (allocations); + g_list_free (items); } static void -gtk_toolbar_style_set (GtkWidget *widget, - GtkStyle *prev_style) +gtk_toolbar_style_set (GtkWidget *widget, + GtkStyle *prev_style) { + if (GTK_WIDGET_REALIZED (widget)) + gtk_style_set_background (widget->style, widget->window, widget->state); + if (prev_style) gtk_toolbar_update_button_relief (GTK_TOOLBAR (widget)); } +static void +gtk_toolbar_direction_changed (GtkWidget *widget, + GtkTextDirection previous_dir) +{ + GtkToolbar *toolbar = GTK_TOOLBAR (widget); + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + + if (toolbar->orientation == GTK_ORIENTATION_VERTICAL) + { + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) + gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE); + else + gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_LEFT, GTK_SHADOW_NONE); + } + + GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir); +} + +static GList * +gtk_toolbar_list_children_in_focus_order (GtkToolbar *toolbar, + GtkDirectionType dir) +{ + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + GList *result = NULL; + GList *list; + + for (list = priv->items; list != NULL; list = list->next) + { + GtkToolItem *item = list->data; + if (!item->pack_end) + result = g_list_prepend (result, item); + } + + for (list = priv->items; list != NULL; list = list->next) + { + GtkToolItem *item = list->data; + + if (item->pack_end) + result = g_list_prepend (result, item); + } + + result = g_list_prepend (result, priv->arrow_button); + + if (dir == GTK_DIR_RIGHT || dir == GTK_DIR_DOWN || dir == GTK_DIR_TAB_FORWARD) + result = g_list_reverse (result); + + if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL) + result = g_list_reverse (result); + + return result; +} + +static gboolean +gtk_toolbar_focus_ends (GtkToolbar *toolbar, + gboolean home) +{ + GList *children, *list; + GtkDirectionType dir = home? GTK_DIR_RIGHT : GTK_DIR_LEFT; + + children = gtk_toolbar_list_children_in_focus_order (toolbar, dir); + + if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL) + { + children = g_list_reverse (children); + if (dir == GTK_DIR_RIGHT) + dir = GTK_DIR_LEFT; + else + dir = GTK_DIR_RIGHT; + } + + for (list = children; list != NULL; list = list->next) + { + GtkWidget *child = list->data; + + if (GTK_CONTAINER (toolbar)->focus_child == child) + break; + + if (GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir)) + break; + } + + g_list_free (children); + + return TRUE; +} + +static gboolean +gtk_toolbar_move_focus (GtkToolbar *toolbar, + GtkDirectionType dir) +{ + GList *list; + gboolean try_focus = FALSE; + GList *children = gtk_toolbar_list_children_in_focus_order (toolbar, dir); + + for (list = children; list != NULL; list = list->next) + { + GtkWidget *child = list->data; + + if (try_focus && GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir)) + break; + + if (child == GTK_CONTAINER (toolbar)->focus_child) + try_focus = TRUE; + } + + g_list_free (children); + + return TRUE; +} + +/* The focus handler for the toolbar. It called when the user presses TAB or otherwise + * tries to focus the toolbar. + */ static gboolean -gtk_toolbar_focus (GtkWidget *widget, - GtkDirectionType dir) +gtk_toolbar_focus (GtkWidget *widget, + GtkDirectionType dir) { - /* Focus can't go in toolbars */ + GtkToolbar *toolbar = GTK_TOOLBAR (widget); + GList *children, *list; + + /* if focus is already somewhere inside the toolbar then return FALSE. + * The only way focus can stay inside the toolbar is when the user presses + * arrow keys or Ctrl TAB (both of which are handled by the + * gtk_toolbar_move_focus() keybinding function. + */ + if (GTK_CONTAINER (widget)->focus_child) + return FALSE; + + children = gtk_toolbar_list_children_in_focus_order (toolbar, dir); + + for (list = children; list != NULL; list = list->next) + { + GtkWidget *child = list->data; + + if (GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir)) + return TRUE; + } + + g_list_free (children); return FALSE; } static void -child_show_all (GtkWidget *widget) +style_change_notify (GtkToolbar *toolbar) { - /* Don't show our own children, since that would - * show labels we may intend to hide in icons-only mode - */ - if (!g_object_get_data (G_OBJECT (widget), - "gtk-toolbar-is-child")) - gtk_widget_show_all (widget); + if (!toolbar->style_set) + { + /* pretend it was set, then unset, thus reverting to new default */ + toolbar->style_set = TRUE; + gtk_toolbar_unset_style (toolbar); + } } static void -gtk_toolbar_show_all (GtkWidget *widget) +icon_size_change_notify (GtkToolbar *toolbar) +{ + if (!toolbar->icon_size_set) + { + /* pretend it was set, then unset, thus reverting to new default */ + toolbar->icon_size_set = TRUE; + gtk_toolbar_unset_icon_size (toolbar); + } +} + +static GtkSettings * +toolbar_get_settings (GtkToolbar *toolbar) { - gtk_container_foreach (GTK_CONTAINER (widget), - (GtkCallback) child_show_all, - NULL); - gtk_widget_show (widget); + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + return priv->settings; } static void -child_hide_all (GtkWidget *widget) +gtk_toolbar_screen_changed (GtkWidget *widget, + GdkScreen *previous_screen) { - /* Don't hide our own children, since that would also hide - * widgets that won't be shown again by gtk_toolbar_show_all(). - */ - if (!g_object_get_data (G_OBJECT (widget), - "gtk-toolbar-is-child")) - gtk_widget_hide_all (widget); + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget); + GtkToolbar *toolbar = GTK_TOOLBAR (widget); + GtkSettings *old_settings = toolbar_get_settings (toolbar); + GtkSettings *settings; + + if (gtk_widget_has_screen (GTK_WIDGET (toolbar))) + settings = gtk_widget_get_settings (GTK_WIDGET (toolbar)); + else + settings = NULL; + + if (settings == old_settings) + return; + + if (old_settings) + { + g_signal_handler_disconnect (old_settings, toolbar->style_set_connection); + g_signal_handler_disconnect (old_settings, toolbar->icon_size_connection); + + g_object_unref (old_settings); + } + + if (settings) + { + toolbar->style_set_connection = + g_signal_connect_swapped (settings, + "notify::gtk-toolbar-style", + G_CALLBACK (style_change_notify), + toolbar); + toolbar->icon_size_connection = + g_signal_connect_swapped (settings, + "notify::gtk-toolbar-icon-size", + G_CALLBACK (icon_size_change_notify), + toolbar); + + g_object_ref (settings); + priv->settings = settings; + } + else + priv->settings = NULL; + + style_change_notify (toolbar); + icon_size_change_notify (toolbar); +} + +static void +find_drop_pos (GtkToolbar *toolbar, + gint x, + gint y, + gint *drop_index, + gint *drop_pos) +{ + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + GtkOrientation orientation; + GtkTextDirection direction; + GList *items; + GtkToolItem *item; + gint border_width; + gint best_distance, best_pos, best_index, index; + + orientation = toolbar->orientation; + direction = gtk_widget_get_direction (GTK_WIDGET (toolbar)); + border_width = GTK_CONTAINER (toolbar)->border_width + get_internal_padding (toolbar); + + items = priv->items; + if (!items) + { + *drop_index = 0; + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + if (direction == GTK_TEXT_DIR_LTR) + *drop_pos = border_width; + else + *drop_pos = GTK_WIDGET (toolbar)->allocation.width - border_width; + } + else + { + *drop_pos = border_width; + } + return; + } + + /* initial conditions */ + item = GTK_TOOL_ITEM (items->data); + best_index = 0; + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + if (direction == GTK_TEXT_DIR_LTR) + best_pos = GTK_WIDGET (item)->allocation.x; + else + best_pos = GTK_WIDGET (item)->allocation.x + + GTK_WIDGET (item)->allocation.width; + best_distance = ABS (best_pos - x); + } + else + { + best_pos = GTK_WIDGET (item)->allocation.y; + best_distance = ABS (best_pos - y); + } + + index = 0; + while (items) + { + item = GTK_TOOL_ITEM (items->data); + index++; + if (GTK_WIDGET_DRAWABLE (item) && !item->pack_end) + { + gint pos, distance; + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + if (direction == GTK_TEXT_DIR_LTR) + pos = GTK_WIDGET (item)->allocation.x + + GTK_WIDGET (item)->allocation.width; + else + pos = GTK_WIDGET (item)->allocation.x; + distance = ABS (pos - x); + } + else + { + pos = GTK_WIDGET (item)->allocation.y + + GTK_WIDGET (item)->allocation.height; + distance = ABS (pos - y); + } + if (distance < best_distance) + { + best_index = index; + best_pos = pos; + best_distance = distance; + } + } + items = items->next; + } + *drop_index = best_index; + *drop_pos = best_pos; } static void -gtk_toolbar_hide_all (GtkWidget *widget) +gtk_toolbar_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time_) +{ + GtkToolbar *toolbar = GTK_TOOLBAR (widget); + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + + if (priv->drag_highlight) + { + gdk_window_set_user_data (priv->drag_highlight, NULL); + gdk_window_destroy (priv->drag_highlight); + priv->drag_highlight = NULL; + } + + priv->drop_index = -1; +} + +static gboolean +gtk_toolbar_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time_) { - gtk_container_foreach (GTK_CONTAINER (widget), - (GtkCallback) child_hide_all, - NULL); - gtk_widget_hide (widget); + GtkToolbar *toolbar = GTK_TOOLBAR (widget); + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + gint new_index, new_pos; + + find_drop_pos(toolbar, x, y, &new_index, &new_pos); + + if (!priv->drag_highlight) + { + GdkWindowAttr attributes; + guint attributes_mask; + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK; + attributes.width = 1; + attributes.height = 1; + attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP; + priv->drag_highlight = gdk_window_new (widget->window, + &attributes, attributes_mask); + gdk_window_set_user_data (priv->drag_highlight, widget); + gdk_window_set_background (priv->drag_highlight, + &widget->style->fg[widget->state]); + } + + if (priv->drop_index < 0 || + priv->drop_index != new_index) + { + gint border_width = GTK_CONTAINER (toolbar)->border_width; + priv->drop_index = new_index; + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + { + gdk_window_move_resize (priv->drag_highlight, + widget->allocation.x + new_pos - 1, + widget->allocation.y + border_width, + 2, widget->allocation.height-border_width*2); + } + else + { + gdk_window_move_resize (priv->drag_highlight, + widget->allocation.x + border_width, + widget->allocation.y + new_pos - 1, + widget->allocation.width-border_width*2, 2); + } + } + + gdk_window_show (priv->drag_highlight); + + gdk_drag_status (context, context->suggested_action, time_); + + return TRUE; +} + +static void +gtk_toolbar_get_child_property (GtkContainer *container, + GtkWidget *child, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GtkToolItem *item = GTK_TOOL_ITEM (child); + + switch (property_id) + { + case CHILD_PROP_PACK_END: + g_value_set_boolean (value, item->pack_end); + break; + + case CHILD_PROP_HOMOGENEOUS: + g_value_set_boolean (value, item->homogeneous); + break; + + case CHILD_PROP_EXPAND: + g_value_set_boolean (value, item->expand); + break; + + default: + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); + break; + } +} + +static void +gtk_toolbar_set_child_property (GtkContainer *container, + GtkWidget *child, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + case CHILD_PROP_PACK_END: + gtk_tool_item_set_pack_end (GTK_TOOL_ITEM (child), g_value_get_boolean (value)); + break; + + case CHILD_PROP_HOMOGENEOUS: + gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value)); + break; + + case CHILD_PROP_EXPAND: + gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value)); + break; + + default: + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); + break; + } } static void gtk_toolbar_add (GtkContainer *container, GtkWidget *widget) { + GtkToolbar *toolbar; + g_return_if_fail (GTK_IS_TOOLBAR (container)); g_return_if_fail (widget != NULL); - gtk_toolbar_append_widget (GTK_TOOLBAR (container), widget, NULL, NULL); + toolbar = GTK_TOOLBAR (container); + + if (GTK_IS_TOOL_ITEM (widget)) + gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (widget), 0); + else + gtk_toolbar_append_widget (toolbar, widget, NULL, NULL); } static void @@ -885,187 +1715,568 @@ gtk_toolbar_remove (GtkContainer *container, GtkWidget *widget) { GtkToolbar *toolbar; - GList *children; - GtkToolbarChild *child; - + GtkToolItem *item = NULL; + g_return_if_fail (GTK_IS_TOOLBAR (container)); - g_return_if_fail (widget != NULL); toolbar = GTK_TOOLBAR (container); - for (children = toolbar->children; children; children = children->next) + if (GTK_IS_TOOL_ITEM (widget)) + { + item = GTK_TOOL_ITEM (widget); + } + else + { + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + GList *list; + + for (list = priv->items; list != NULL; list = list->next) + { + if (GTK_BIN (list->data)->child == widget) + { + item = list->data; + break; + } + } + } + + g_return_if_fail (item != NULL); + + gtk_toolbar_remove_tool_item (GTK_TOOLBAR (container), item); +} + +static void +gtk_toolbar_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + GtkToolbar *toolbar = GTK_TOOLBAR (container); + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + GList *items; + + g_return_if_fail (callback != NULL); + + items = priv->items; + + while (items) + { + GtkToolItem *item = GTK_TOOL_ITEM (items->data); + + items = items->next; + + (*callback) (GTK_WIDGET (item), callback_data); + } + + if (include_internals) + (* callback) (priv->arrow_button, callback_data); +} + +static GType +gtk_toolbar_child_type (GtkContainer *container) +{ + return GTK_TYPE_TOOL_ITEM; +} + +static void +gtk_toolbar_reconfigured (GtkToolbar *toolbar) +{ + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + GList *items; + + items = priv->items; + while (items) + { + GtkToolItem *item = GTK_TOOL_ITEM (items->data); + + gtk_tool_item_toolbar_reconfigured (item); + + items = items->next; + } +} + +static void +gtk_toolbar_real_orientation_changed (GtkToolbar *toolbar, + GtkOrientation orientation) +{ + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + if (toolbar->orientation != orientation) + { + toolbar->orientation = orientation; + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE); + else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) + gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE); + else + gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_LEFT, GTK_SHADOW_NONE); + + gtk_toolbar_reconfigured (toolbar); + + gtk_widget_queue_resize (GTK_WIDGET (toolbar)); + g_object_notify (G_OBJECT (toolbar), "orientation"); + } +} + +static void +gtk_toolbar_real_style_changed (GtkToolbar *toolbar, + GtkToolbarStyle style) +{ + if (toolbar->style != style) + { + toolbar->style = style; + + gtk_toolbar_reconfigured (toolbar); + + gtk_widget_queue_resize (GTK_WIDGET (toolbar)); + g_object_notify (G_OBJECT (toolbar), "toolbar_style"); + } +} + +static void +menu_position_func (GtkMenu *menu, + gint *x, + gint *y, + gboolean *push_in, + gpointer user_data) +{ + GtkToolbar *toolbar = GTK_TOOLBAR (user_data); + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + GtkRequisition req; + GtkRequisition menu_req; + + gdk_window_get_origin (GTK_BUTTON (priv->arrow_button)->event_window, x, y); + gtk_widget_size_request (priv->arrow_button, &req); + gtk_widget_size_request (GTK_WIDGET (menu), &menu_req); + + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + { + *y += priv->arrow_button->allocation.height; + if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) + *x += priv->arrow_button->allocation.width - req.width; + else + *x += req.width - menu_req.width; + } + else + { + if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) + *x += priv->arrow_button->allocation.width; + else + *x -= menu_req.width; + *y += priv->arrow_button->allocation.height - req.height; + } + + *push_in = TRUE; +} + +static void +menu_deactivated (GtkWidget *menu, + GtkToolbar *toolbar) +{ + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->arrow_button), FALSE); +} + +static void +remove_item (GtkWidget *menu_item, + gpointer data) +{ + gtk_container_remove (GTK_CONTAINER (menu_item->parent), menu_item); +} + +static void +show_menu (GtkToolbar *toolbar, + GdkEventButton *event) +{ + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + GList *list; + + if (priv->menu) + { + gtk_container_foreach (GTK_CONTAINER (priv->menu), remove_item, NULL); + gtk_widget_destroy (GTK_WIDGET (priv->menu)); + } + + priv->menu = GTK_MENU (gtk_menu_new ()); + g_signal_connect (priv->menu, "deactivate", G_CALLBACK (menu_deactivated), toolbar); + + for (list = priv->items; list != NULL; list = list->next) { - child = children->data; + GtkToolItem *item = list->data; - if ((child->type != GTK_TOOLBAR_CHILD_SPACE) && (child->widget == widget)) + if (toolbar_item_visible (toolbar, item) && item->overflow_item) { - gboolean was_visible; + GtkWidget *menu_item = gtk_tool_item_retrieve_proxy_menu_item (item); + + if (menu_item) + { + g_assert (GTK_IS_MENU_ITEM (menu_item)); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_item); + } + } + } + + gtk_widget_show_all (GTK_WIDGET (priv->menu)); + + gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL, + menu_position_func, toolbar, + event? event->button : 0, event? event->time : gtk_get_current_event_time()); +} + +static void +gtk_toolbar_arrow_button_clicked (GtkWidget *button, + GtkToolbar *toolbar) +{ + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->arrow_button)) && + (!priv->menu || !GTK_WIDGET_VISIBLE (GTK_WIDGET (priv->menu)))) + { + /* We only get here when the button is clicked with the keybaord, + * because mouse button presses result in the menu being shown so + * that priv->menu would be non-NULL and visible. + */ + show_menu (toolbar, NULL); + gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE); + } +} + +static gboolean +gtk_toolbar_arrow_button_press (GtkWidget *button, + GdkEventButton *event, + GtkToolbar *toolbar) +{ + show_menu (toolbar, event); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); + + return TRUE; +} + +static gboolean +gtk_toolbar_button_press (GtkWidget *toolbar, + GdkEventButton *event) +{ + if (event->button == 3) + g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0, NULL); + + return FALSE; +} + +static void +gtk_toolbar_update_button_relief (GtkToolbar *toolbar) +{ + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + + gtk_toolbar_reconfigured (toolbar); + + gtk_button_set_relief (GTK_BUTTON (priv->arrow_button), get_button_relief (toolbar)); +} + +static GtkReliefStyle +get_button_relief (GtkToolbar *toolbar) +{ + GtkReliefStyle button_relief = GTK_RELIEF_NORMAL; + + gtk_widget_ensure_style (GTK_WIDGET (toolbar)); + + gtk_widget_style_get (GTK_WIDGET (toolbar), + "button_relief", &button_relief, + NULL); + + return button_relief; +} + +static gint +get_space_size (GtkToolbar *toolbar) +{ + gint space_size = DEFAULT_SPACE_SIZE; + + gtk_widget_style_get (GTK_WIDGET (toolbar), + "space_size", &space_size, + NULL); + + return space_size; +} + +static GtkToolbarSpaceStyle +get_space_style (GtkToolbar *toolbar) +{ + GtkToolbarSpaceStyle space_style = DEFAULT_SPACE_STYLE; + + gtk_widget_style_get (GTK_WIDGET (toolbar), + "space_style", &space_style, + NULL); + + + return space_style; +} + +static gint +get_internal_padding (GtkToolbar *toolbar) +{ + gint ipadding = 0; + + gtk_widget_style_get (GTK_WIDGET (toolbar), + "internal_padding", &ipadding, + NULL); + + return ipadding; +} + +static gboolean +gtk_toolbar_check_old_api (GtkToolbar *toolbar) +{ + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + + if (priv->api_mode == NEW_API) + { + g_warning ("mixing deprecated and non-deprecated GtkToolbar API is not allowed"); + return FALSE; + } + + priv->api_mode = OLD_API; + return TRUE; +} + +static gboolean +gtk_toolbar_check_new_api (GtkToolbar *toolbar) +{ + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + + if (priv->api_mode == OLD_API) + { + g_warning ("mixing deprecated and non-deprecated GtkToolbar API is not allowed"); + return FALSE; + } + + priv->api_mode = NEW_API; + return TRUE; +} + +static void +gtk_toolbar_insert_tool_item (GtkToolbar *toolbar, + GtkToolItem *item, + gint pos) +{ + GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + + priv->items = g_list_insert (priv->items, item, pos); + toolbar->num_children++; + + gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar)); +} + +static void +gtk_toolbar_remove_tool_item (GtkToolbar *toolbar, + GtkToolItem *item) +{ + GtkToolbarPrivate *priv; + GList *tmp; - was_visible = GTK_WIDGET_VISIBLE (widget); - gtk_widget_unparent (widget); + g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); + g_return_if_fail (GTK_IS_TOOL_ITEM (item)); + + priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + + for (tmp = priv->items; tmp != NULL; tmp = tmp->next) + { + GtkWidget *child = tmp->data; + + if (child == GTK_WIDGET (item)) + { + gboolean was_visible; + + was_visible = GTK_WIDGET_VISIBLE (item); + gtk_widget_unparent (GTK_WIDGET (item)); - toolbar->children = g_list_remove_link (toolbar->children, children); - g_free (child); - g_list_free (children); + priv->items = g_list_remove_link (priv->items, tmp); toolbar->num_children--; - if (was_visible && GTK_WIDGET_VISIBLE (container)) - gtk_widget_queue_resize (GTK_WIDGET (container)); + if (was_visible && GTK_WIDGET_VISIBLE (toolbar)) + gtk_widget_queue_resize (GTK_WIDGET (toolbar)); break; } } } -static void -gtk_toolbar_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data) +GtkWidget * +gtk_toolbar_new (void) { GtkToolbar *toolbar; - GList *children; - GtkToolbarChild *child; - g_return_if_fail (GTK_IS_TOOLBAR (container)); - g_return_if_fail (callback != NULL); + toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL); - toolbar = GTK_TOOLBAR (container); + return GTK_WIDGET (toolbar); +} + +void +gtk_toolbar_insert (GtkToolbar *toolbar, + GtkToolItem *item, + gint pos) +{ + g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); + g_return_if_fail (GTK_IS_TOOL_ITEM (item)); + + if (!gtk_toolbar_check_new_api (toolbar)) + return; + + gtk_toolbar_insert_tool_item (toolbar, item, pos); +} + +gint +gtk_toolbar_get_item_index (GtkToolbar *toolbar, + GtkToolItem *item) +{ + GtkToolbarPrivate *priv; + + g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1); + g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1); + + if (!gtk_toolbar_check_new_api (toolbar)) + return -1; + + priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + g_return_val_if_fail (g_list_find (priv->items, item) != NULL, -1); + + return g_list_index (priv->items, item); +} + +void +gtk_toolbar_set_orientation (GtkToolbar *toolbar, + GtkOrientation orientation) +{ + g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); + + g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0, orientation); +} + +GtkOrientation +gtk_toolbar_get_orientation (GtkToolbar *toolbar) +{ + g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL); + + return toolbar->orientation; +} + +void +gtk_toolbar_set_style (GtkToolbar *toolbar, + GtkToolbarStyle style) +{ + g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); - for (children = toolbar->children; children; children = children->next) + toolbar->style_set = TRUE; + g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style); + + +} + +GtkToolbarStyle +gtk_toolbar_get_style (GtkToolbar *toolbar) +{ + g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE); + + return toolbar->style; +} + +void +gtk_toolbar_unset_style (GtkToolbar *toolbar) +{ + GtkToolbarStyle style; + + g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); + + if (toolbar->style_set) { - child = children->data; + GtkSettings *settings = toolbar_get_settings (toolbar); - if (child->type != GTK_TOOLBAR_CHILD_SPACE) - (*callback) (child->widget, callback_data); + if (settings) + g_object_get (settings, + "gtk-toolbar-style", &style, + NULL); + else + style = DEFAULT_TOOLBAR_STYLE; + + if (style != toolbar->style) + g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style); + + toolbar->style_set = FALSE; } } -GtkWidget * -gtk_toolbar_append_item (GtkToolbar *toolbar, - const char *text, - const char *tooltip_text, - const char *tooltip_private_text, - GtkWidget *icon, - GtkSignalFunc callback, - gpointer user_data) +void +gtk_toolbar_set_tooltips (GtkToolbar *toolbar, + gboolean enable) { - return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON, - NULL, text, - tooltip_text, tooltip_private_text, - icon, callback, user_data, - toolbar->num_children); + g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); + + if (enable) + gtk_tooltips_enable (toolbar->tooltips); + else + gtk_tooltips_disable (toolbar->tooltips); } -GtkWidget * -gtk_toolbar_prepend_item (GtkToolbar *toolbar, - const char *text, - const char *tooltip_text, - const char *tooltip_private_text, - GtkWidget *icon, - GtkSignalFunc callback, - gpointer user_data) +gboolean +gtk_toolbar_get_tooltips (GtkToolbar *toolbar) { - return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON, - NULL, text, - tooltip_text, tooltip_private_text, - icon, callback, user_data, - 0); + g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE); + + return toolbar->tooltips->enabled; } -static GtkWidget * -gtk_toolbar_internal_insert_item (GtkToolbar *toolbar, - const char *text, - const char *tooltip_text, - const char *tooltip_private_text, - GtkWidget *icon, - GtkSignalFunc callback, - gpointer user_data, - gint position) +gint +gtk_toolbar_get_n_items (GtkToolbar *toolbar) { - return gtk_toolbar_internal_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON, - NULL, text, - tooltip_text, tooltip_private_text, - icon, callback, user_data, - position); + GtkToolbarPrivate *priv; + + g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1); + + if (!gtk_toolbar_check_new_api (toolbar)) + return -1; + + priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + + return g_list_length (priv->items); } - -GtkWidget * -gtk_toolbar_insert_item (GtkToolbar *toolbar, - const char *text, - const char *tooltip_text, - const char *tooltip_private_text, - GtkWidget *icon, - GtkSignalFunc callback, - gpointer user_data, - gint position) + +/* + * returns NULL if n is out of range + */ +GtkToolItem * +gtk_toolbar_get_nth_item (GtkToolbar *toolbar, + gint n) { - return gtk_toolbar_internal_insert_item (toolbar, - text, tooltip_text, tooltip_private_text, - icon, callback, user_data, - position); + GtkToolbarPrivate *priv; + + g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL); + + if (!gtk_toolbar_check_new_api (toolbar)) + return NULL; + + priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + + return g_list_nth_data (priv->items, n); } -/** - * gtk_toolbar_set_icon_size: - * @toolbar: A #GtkToolbar - * @icon_size: The #GtkIconSize that stock icons in the toolbar shall have. - * - * This function sets the size of stock icons in the toolbar. You - * can call it both before you add the icons and after they've been - * added. The size you set will override user preferences for the default - * icon size. - **/ void gtk_toolbar_set_icon_size (GtkToolbar *toolbar, GtkIconSize icon_size) { - GList *children; - GtkToolbarChild *child; - GtkImage *image; - gchar *stock_id; - g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); toolbar->icon_size_set = TRUE; - + if (toolbar->icon_size == icon_size) return; - + toolbar->icon_size = icon_size; - for (children = toolbar->children; children; children = children->next) - { - child = children->data; - if ((child->type == GTK_TOOLBAR_CHILD_BUTTON || - child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON || - child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON) && - GTK_IS_IMAGE (child->icon)) - { - image = GTK_IMAGE (child->icon); - if (gtk_image_get_storage_type (image) == GTK_IMAGE_STOCK) - { - gtk_image_get_stock (image, &stock_id, NULL); - stock_id = g_strdup (stock_id); - gtk_image_set_from_stock (image, - stock_id, - icon_size); - g_free (stock_id); - } - } - } - + gtk_toolbar_reconfigured (toolbar); + gtk_widget_queue_resize (GTK_WIDGET (toolbar)); } -/** - * gtk_toolbar_get_icon_size: - * @toolbar: a #GtkToolbar - * - * Retrieves the icon size fo the toolbar. See gtk_toolbar_set_icon_size(). - * - * Return value: the current icon size for the icons on the toolbar. - **/ GtkIconSize gtk_toolbar_get_icon_size (GtkToolbar *toolbar) { @@ -1074,79 +2285,145 @@ gtk_toolbar_get_icon_size (GtkToolbar *toolbar) return toolbar->icon_size; } -/** - * gtk_toolbar_unset_icon_size: - * @toolbar: a #GtkToolbar - * - * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that - * user preferences will be used to determine the icon size. - **/ +GtkReliefStyle +gtk_toolbar_get_relief_style (GtkToolbar *toolbar) +{ + g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_RELIEF_NONE); + + return get_button_relief (toolbar); +} + void -gtk_toolbar_unset_icon_size (GtkToolbar *toolbar) +gtk_toolbar_unset_icon_size (GtkToolbar *toolbar) { GtkIconSize size; + g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); + if (toolbar->icon_size_set) { GtkSettings *settings = toolbar_get_settings (toolbar); if (settings) - g_object_get (settings, - "gtk-toolbar-icon-size", &size, - NULL); + { + g_object_get (settings, + "gtk-toolbar-icon-size", &size, + NULL); + } else size = DEFAULT_ICON_SIZE; if (size != toolbar->icon_size) - gtk_toolbar_set_icon_size (toolbar, size); + gtk_toolbar_set_icon_size (toolbar, size); toolbar->icon_size_set = FALSE; } } -static gchar * -elide_underscores (const gchar *original) +void +gtk_toolbar_set_show_arrow (GtkToolbar *toolbar, + gboolean show_arrow) { - gchar *q, *result; - const gchar *p; - gboolean last_underscore; - - q = result = g_malloc (strlen (original) + 1); - last_underscore = FALSE; + GtkToolbarPrivate *priv; - for (p = original; *p; p++) + g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); + + priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); + show_arrow = show_arrow != FALSE; + + if (priv->show_arrow != show_arrow) { - if (!last_underscore && *p == '_') - last_underscore = TRUE; - else - { - last_underscore = FALSE; - *q++ = *p; - } + priv->show_arrow = show_arrow; + + if (!priv->show_arrow) + gtk_widget_hide (priv->arrow_button); + + gtk_widget_queue_resize (GTK_WIDGET (toolbar)); + g_object_notify (G_OBJECT (toolbar), "show_arrow"); } +} + +gboolean +gtk_toolbar_get_show_arrow (GtkToolbar *toolbar) +{ + GtkToolbarPrivate *priv; + + g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE); + + if (!gtk_toolbar_check_new_api (toolbar)) + return FALSE; - *q = '\0'; + priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); - return result; + return priv->show_arrow; +} + +gint +gtk_toolbar_get_drop_index (GtkToolbar *toolbar, + gint x, + gint y) +{ + gint drop_index, drop_pos; + + g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE); + + if (!gtk_toolbar_check_new_api (toolbar)) + return -1; + + find_drop_pos (toolbar, x, y, &drop_index, &drop_pos); + + return drop_index; +} + +GtkWidget * +gtk_toolbar_append_item (GtkToolbar *toolbar, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data) +{ + return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON, + NULL, text, + tooltip_text, tooltip_private_text, + icon, callback, user_data, + toolbar->num_children); +} + +GtkWidget * +gtk_toolbar_prepend_item (GtkToolbar *toolbar, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data) +{ + return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON, + NULL, text, + tooltip_text, tooltip_private_text, + icon, callback, user_data, + 0); +} + +GtkWidget * +gtk_toolbar_insert_item (GtkToolbar *toolbar, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data, + gint position) +{ + return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON, + NULL, text, + tooltip_text, tooltip_private_text, + icon, callback, user_data, + position); } -/** - * gtk_toolbar_insert_stock: - * @toolbar: A #GtkToolbar - * @stock_id: The id of the stock item you want to insert - * @tooltip_text: The text in the tooltip of the toolbar button - * @tooltip_private_text: The private text of the tooltip - * @callback: The callback called when the toolbar button is clicked. - * @user_data: user data passed to callback - * @position: The position the button shall be inserted at. - * -1 means at the end. - * - * Inserts a stock item at the specified position of the toolbar. If - * @stock_id is not a known stock item ID, it's inserted verbatim, - * except that underscores used to mark mnemonics are removed. - * - * Returns: the inserted widget - */ GtkWidget* gtk_toolbar_insert_stock (GtkToolbar *toolbar, const gchar *stock_id, @@ -1156,38 +2433,13 @@ gtk_toolbar_insert_stock (GtkToolbar *toolbar, gpointer user_data, gint position) { - GtkStockItem item; - GtkWidget *image = NULL; - const gchar *label; - gchar *label_no_mnemonic; - GtkWidget *retval; - - if (gtk_stock_lookup (stock_id, &item)) - { - image = gtk_image_new_from_stock (stock_id, toolbar->icon_size); - label = item.label; - } - else - label = stock_id; - - label_no_mnemonic = elide_underscores (label); - - retval = gtk_toolbar_internal_insert_item (toolbar, - label_no_mnemonic, - tooltip_text, - tooltip_private_text, - image, - callback, - user_data, - position); - - g_free (label_no_mnemonic); - - return retval; + return gtk_toolbar_internal_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON, + NULL, stock_id, + tooltip_text, tooltip_private_text, + NULL, callback, user_data, + position, TRUE); } - - void gtk_toolbar_append_space (GtkToolbar *toolbar) { @@ -1219,62 +2471,33 @@ gtk_toolbar_insert_space (GtkToolbar *toolbar, position); } -/** - * gtk_toolbar_remove_space: - * @toolbar: a #GtkToolbar. - * @position: the index of the space to remove. - * - * Removes a space from the specified position. - **/ void gtk_toolbar_remove_space (GtkToolbar *toolbar, - gint position) + gint position) { - GList *children; - GtkToolbarChild *child; - gint i; - + GtkToolItem *item; + g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); - - i = 0; - for (children = toolbar->children; children; children = children->next) - { - child = children->data; - if (i == position) - { - if (child->type == GTK_TOOLBAR_CHILD_SPACE) - { - toolbar->children = g_list_remove_link (toolbar->children, children); - g_free (child); - g_list_free (children); - toolbar->num_children--; - - gtk_widget_queue_resize (GTK_WIDGET (toolbar)); - } - else - { - g_warning ("Toolbar position %d is not a space", position); - } + if (!gtk_toolbar_check_old_api (toolbar)) + return; + + item = g_list_nth_data (toolbar->children, position); - return; - } + if (!item) + { + g_warning ("Toolbar position %d doesn't exist", position); + return; + } - ++i; + if (GTK_BIN (item)->child) + { + g_warning ("Toolbar position %d is not a space", position); } - g_warning ("Toolbar position %d doesn't exist", position); + gtk_toolbar_remove_tool_item (toolbar, item); } -/** - * gtk_toolbar_append_widget: - * @toolbar: a #GtkToolbar. - * @widget: a #GtkWidget to add to the toolbar. - * @tooltip_text: the element's tooltip. - * @tooltip_private_text: used for context-sensitive help about this toolbar element. - * - * Adds a widget to the end of the given toolbar. - **/ void gtk_toolbar_append_widget (GtkToolbar *toolbar, GtkWidget *widget, @@ -1288,15 +2511,6 @@ gtk_toolbar_append_widget (GtkToolbar *toolbar, toolbar->num_children); } -/** - * gtk_toolbar_prepend_widget: - * @toolbar: a #GtkToolbar. - * @widget: a #GtkWidget to add to the toolbar. - * @tooltip_text: the element's tooltip. - * @tooltip_private_text: used for context-sensitive help about this toolbar element. - * - * Adds a widget to the beginning of the given toolbar. - **/ void gtk_toolbar_prepend_widget (GtkToolbar *toolbar, GtkWidget *widget, @@ -1310,16 +2524,6 @@ gtk_toolbar_prepend_widget (GtkToolbar *toolbar, 0); } -/** - * gtk_toolbar_insert_widget: - * @toolbar: a #GtkToolbar. - * @widget: a #GtkWidget to add to the toolbar. - * @tooltip_text: the element's tooltip. - * @tooltip_private_text: used for context-sensitive help about this toolbar element. - * @position: the number of widgets to insert this widget after. - * - * Inserts a widget in the toolbar at the given position. - **/ void gtk_toolbar_insert_widget (GtkToolbar *toolbar, GtkWidget *widget, @@ -1367,29 +2571,6 @@ gtk_toolbar_prepend_element (GtkToolbar *toolbar, icon, callback, user_data, 0); } -/** - * gtk_toolbar_insert_element: - * @toolbar: a #GtkToolbar. - * @type: a value of type #GtkToolbarChildType that determines what @widget - * will be. - * @widget: a #GtkWidget, or %NULL. - * @text: the element's label. - * @tooltip_text: the element's tooltip. - * @tooltip_private_text: used for context-sensitive help about this toolbar element. - * @icon: a #GtkWidget that provides pictorial representation of the element's function. - * @callback: the function to be executed when the button is pressed. - * @user_data: any data you wish to pass to the callback. - * @position: the number of widgets to insert this element after. - * - * Inserts a new element in the toolbar at the given position. - * - * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element. - * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine - * the radio group for the new element. In all other cases, @widget must - * be %NULL. - * - * Return value: the new toolbar element as a #GtkWidget. - **/ GtkWidget * gtk_toolbar_insert_element (GtkToolbar *toolbar, GtkToolbarChildType type, @@ -1402,85 +2583,64 @@ gtk_toolbar_insert_element (GtkToolbar *toolbar, gpointer user_data, gint position) { - g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL); - if (type == GTK_TOOLBAR_CHILD_WIDGET) - { - g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - } - else if (type != GTK_TOOLBAR_CHILD_RADIOBUTTON) - g_return_val_if_fail (widget == NULL, NULL); - return gtk_toolbar_internal_insert_element (toolbar, type, widget, text, - tooltip_text, tooltip_private_text, - icon, callback, user_data, - position); + tooltip_text, tooltip_private_text, + icon, callback, user_data, position, FALSE); } -static void -set_child_packing_and_visibility(GtkToolbar *toolbar, - GtkToolbarChild *child) +static gchar * +elide_underscores (const gchar *original) { - GtkWidget *box; - gboolean expand; - - box = gtk_bin_get_child (GTK_BIN (child->widget)); - - g_return_if_fail (GTK_IS_BOX (box)); - - if (child->label) - { - expand = (toolbar->style != GTK_TOOLBAR_BOTH); - - gtk_box_set_child_packing (GTK_BOX (box), child->label, - expand, expand, 0, GTK_PACK_END); - - if (toolbar->style != GTK_TOOLBAR_ICONS) - gtk_widget_show (child->label); - else - gtk_widget_hide (child->label); - } + gchar *q, *result; + const gchar *p; + gboolean last_underscore; - if (child->icon) + q = result = g_malloc (strlen (original) + 1); + last_underscore = FALSE; + + for (p = original; *p; p++) { - expand = (toolbar->style != GTK_TOOLBAR_BOTH_HORIZ); - - gtk_box_set_child_packing (GTK_BOX (box), child->icon, - expand, expand, 0, GTK_PACK_END); - - if (toolbar->style != GTK_TOOLBAR_TEXT) - gtk_widget_show (child->icon); + if (!last_underscore && *p == '_') + last_underscore = TRUE; else - gtk_widget_hide (child->icon); + { + last_underscore = FALSE; + *q++ = *p; + } } + + *q = '\0'; + + return result; } static GtkWidget * gtk_toolbar_internal_insert_element (GtkToolbar *toolbar, - GtkToolbarChildType type, - GtkWidget *widget, - const char *text, - const char *tooltip_text, - const char *tooltip_private_text, - GtkWidget *icon, - GtkSignalFunc callback, - gpointer user_data, - gint position) + GtkToolbarChildType type, + GtkWidget *widget, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data, + gint position, + gboolean use_stock) { GtkToolbarChild *child; - GtkWidget *box; - + GtkToolItem *item = NULL; + g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL); + + if (!gtk_toolbar_check_old_api (toolbar)) + return NULL; + if (type == GTK_TOOLBAR_CHILD_WIDGET) - { - g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - } + g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); else if (type != GTK_TOOLBAR_CHILD_RADIOBUTTON) g_return_val_if_fail (widget == NULL, NULL); - if (type == GTK_TOOLBAR_CHILD_SPACE) - child = (GtkToolbarChild *) g_new (GtkToolbarChildSpace, 1); - else - child = g_new (GtkToolbarChild, 1); + child = g_new (GtkToolbarChild, 1); child->type = type; child->icon = NULL; @@ -1489,343 +2649,87 @@ gtk_toolbar_internal_insert_element (GtkToolbar *toolbar, switch (type) { case GTK_TOOLBAR_CHILD_SPACE: + item = gtk_separator_tool_item_new (); child->widget = NULL; - ((GtkToolbarChildSpace *) child)->alloc_x = - ((GtkToolbarChildSpace *) child)->alloc_y = 0; break; case GTK_TOOLBAR_CHILD_WIDGET: + item = gtk_tool_item_new (); child->widget = widget; + gtk_container_add (GTK_CONTAINER (item), child->widget); break; case GTK_TOOLBAR_CHILD_BUTTON: - case GTK_TOOLBAR_CHILD_TOGGLEBUTTON: - case GTK_TOOLBAR_CHILD_RADIOBUTTON: - if (type == GTK_TOOLBAR_CHILD_BUTTON) - { - child->widget = gtk_button_new (); - gtk_button_set_relief (GTK_BUTTON (child->widget), get_button_relief (toolbar)); - } - else if (type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON) - { - child->widget = gtk_toggle_button_new (); - gtk_button_set_relief (GTK_BUTTON (child->widget), get_button_relief (toolbar)); - gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child->widget), - FALSE); - } - else - { - child->widget = gtk_radio_button_new (widget - ? gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget)) - : NULL); - gtk_button_set_relief (GTK_BUTTON (child->widget), get_button_relief (toolbar)); - gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child->widget), FALSE); - } - - GTK_WIDGET_UNSET_FLAGS (child->widget, GTK_CAN_FOCUS); - - if (callback) - g_signal_connect (child->widget, "clicked", - callback, user_data); - - if (toolbar->style == GTK_TOOLBAR_BOTH_HORIZ) - box = gtk_hbox_new (FALSE, 0); - else - box = gtk_vbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (child->widget), box); - gtk_widget_show (box); - - if (text) - { - child->label = gtk_label_new (text); - gtk_container_add (GTK_CONTAINER (box), child->label); - } - - if (icon) - { - child->icon = GTK_WIDGET (icon); - gtk_container_add (GTK_CONTAINER (box), child->icon); - } - - set_child_packing_and_visibility (toolbar, child); - - /* Mark child as ours */ - g_object_set_data (G_OBJECT (child->widget), - "gtk-toolbar-is-child", - GINT_TO_POINTER (TRUE)); - - gtk_widget_show (child->widget); + item = gtk_tool_button_new (); + child->widget = GTK_TOOL_BUTTON (item)->button; break; - - default: - g_assert_not_reached (); - } - - if ((type != GTK_TOOLBAR_CHILD_SPACE) && tooltip_text) - gtk_tooltips_set_tip (toolbar->tooltips, child->widget, - tooltip_text, tooltip_private_text); - - toolbar->children = g_list_insert (toolbar->children, child, position); - toolbar->num_children++; - - if (type != GTK_TOOLBAR_CHILD_SPACE) - gtk_widget_set_parent (child->widget, GTK_WIDGET (toolbar)); - else - gtk_widget_queue_resize (GTK_WIDGET (toolbar)); - - return child->widget; -} - -void -gtk_toolbar_set_orientation (GtkToolbar *toolbar, - GtkOrientation orientation) -{ - g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); - - g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0, orientation); -} - -/** - * gtk_toolbar_get_orientation: - * @toolbar: a #GtkToolbar - * - * Retrieves the current orientation of the toolbar. See - * gtk_toolbar_set_orientation(). - * - * Return value: the orientation - **/ -GtkOrientation -gtk_toolbar_get_orientation (GtkToolbar *toolbar) -{ - g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL); - - return toolbar->orientation; -} - -void -gtk_toolbar_set_style (GtkToolbar *toolbar, - GtkToolbarStyle style) -{ - g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); - - toolbar->style_set = TRUE; - g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style); -} - -/** - * gtk_toolbar_get_style: - * @toolbar: a #GtkToolbar - * - * Retrieves whether the toolbar has text, icons, or both . See - * gtk_toolbar_set_style(). - - * Return value: the current style of @toolbar - **/ -GtkToolbarStyle -gtk_toolbar_get_style (GtkToolbar *toolbar) -{ - g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE); - - return toolbar->style; -} - -/** - * gtk_toolbar_unset_style: - * @toolbar: a #GtkToolbar - * - * Unsets a toolbar style set with gtk_toolbar_set_style(), so that - * user preferences will be used to determine the toolbar style. - **/ -void -gtk_toolbar_unset_style (GtkToolbar *toolbar) -{ - GtkToolbarStyle style; - - g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); - - if (toolbar->style_set) - { - GtkSettings *settings = toolbar_get_settings (toolbar); - - if (settings) - g_object_get (settings, - "gtk-toolbar-style", &style, - NULL); - else - style = DEFAULT_TOOLBAR_STYLE; - - if (style != toolbar->style) - g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style); - toolbar->style_set = FALSE; - } -} - -void -gtk_toolbar_set_tooltips (GtkToolbar *toolbar, - gboolean enable) -{ - g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); - - if (enable) - gtk_tooltips_enable (toolbar->tooltips); - else - gtk_tooltips_disable (toolbar->tooltips); -} - -/** - * gtk_toolbar_get_tooltips: - * @toolbar: a #GtkToolbar - * - * Retrieves whether tooltips are enabled. See - * gtk_toolbar_set_tooltips(). - * - * Return value: %TRUE if tooltips are enabled - **/ -gboolean -gtk_toolbar_get_tooltips (GtkToolbar *toolbar) -{ - g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE); - - return toolbar->tooltips->enabled; -} - -static void -gtk_toolbar_update_button_relief (GtkToolbar *toolbar) -{ - GList *children; - GtkToolbarChild *child; - GtkReliefStyle relief; - - g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); - - relief = get_button_relief (toolbar); - - for (children = toolbar->children; children; children = children->next) - { - child = children->data; - if (child->type == GTK_TOOLBAR_CHILD_BUTTON || - child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON || - child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON) - gtk_button_set_relief (GTK_BUTTON (child->widget), relief); - } -} - -static void -gtk_real_toolbar_orientation_changed (GtkToolbar *toolbar, - GtkOrientation orientation) -{ - g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); + case GTK_TOOLBAR_CHILD_TOGGLEBUTTON: + item = gtk_toggle_tool_button_new (); + child->widget = GTK_TOOL_BUTTON (item)->button; + break; - if (toolbar->orientation != orientation) - { - toolbar->orientation = orientation; - gtk_widget_queue_resize (GTK_WIDGET (toolbar)); - g_object_notify (G_OBJECT (toolbar), "orientation"); + case GTK_TOOLBAR_CHILD_RADIOBUTTON: + item = gtk_radio_tool_button_new (widget + ? gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget)) + : NULL); + child->widget = GTK_TOOL_BUTTON (item)->button; + break; } -} -static void -gtk_real_toolbar_style_changed (GtkToolbar *toolbar, - GtkToolbarStyle style) -{ - GList *children; - GtkToolbarChild *child; - GtkWidget* box; + gtk_widget_show (GTK_WIDGET (item)); - g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); - - if (toolbar->style != style) + if (type == GTK_TOOLBAR_CHILD_BUTTON || + type == GTK_TOOLBAR_CHILD_RADIOBUTTON || + type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON) { - toolbar->style = style; - - for (children = toolbar->children; children; children = children->next) + if (text) { - child = children->data; - - if (child->type == GTK_TOOLBAR_CHILD_BUTTON || - child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON || - child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON) - { - box = gtk_bin_get_child (GTK_BIN (child->widget)); - - if (style == GTK_TOOLBAR_BOTH && GTK_IS_HBOX (box)) - { - GtkWidget *vbox; - - vbox = gtk_vbox_new (FALSE, 0); - - if (child->label) - gtk_widget_reparent (child->label, vbox); - if (child->icon) - gtk_widget_reparent (child->icon, vbox); - - gtk_widget_destroy (box); - gtk_container_add (GTK_CONTAINER (child->widget), vbox); - - gtk_widget_show (vbox); - } - else if (style == GTK_TOOLBAR_BOTH_HORIZ && GTK_IS_VBOX (box)) - { - GtkWidget *hbox; - - hbox = gtk_hbox_new (FALSE, 0); + if (use_stock) + { + GtkStockItem stock_item; + gchar *label_text; - if (child->label) - gtk_widget_reparent (child->label, hbox); - if (child->icon) - gtk_widget_reparent (child->icon, hbox); + gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (item), text); - gtk_widget_destroy (box); - gtk_container_add (GTK_CONTAINER (child->widget), hbox); + gtk_stock_lookup (text, &stock_item); + label_text = elide_underscores (stock_item.label); + child->label = GTK_WIDGET (gtk_label_new (label_text)); + g_free (label_text); + } + else + { + child->label = gtk_label_new (text); + } + gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (item), child->label); + gtk_widget_show (child->label); + } - gtk_widget_show (hbox); - } + if (icon) + { + child->icon = icon; + gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (item), icon); - set_child_packing_and_visibility (toolbar, child); - } + /* Applications depend on the toolbar showing the widget for them */ + gtk_widget_show (GTK_WIDGET (icon)); } - gtk_widget_queue_resize (GTK_WIDGET (toolbar)); - g_object_notify (G_OBJECT (toolbar), "toolbar_style"); + /* + * We need to connect to the button's clicked callback because some + * programs may rely on that the widget in the callback is a GtkButton + */ + if (callback) + g_signal_connect (child->widget, "clicked", + callback, user_data); } -} - - -static GtkReliefStyle -get_button_relief (GtkToolbar *toolbar) -{ - GtkReliefStyle button_relief = GTK_RELIEF_NORMAL; - gtk_widget_ensure_style (GTK_WIDGET (toolbar)); - gtk_widget_style_get (GTK_WIDGET (toolbar), - "button_relief", &button_relief, - NULL); - - return button_relief; -} - -static gint -get_space_size (GtkToolbar *toolbar) -{ - gint space_size = DEFAULT_SPACE_SIZE; - - gtk_widget_style_get (GTK_WIDGET (toolbar), - "space_size", &space_size, - NULL); - - return space_size; -} - -static GtkToolbarSpaceStyle -get_space_style (GtkToolbar *toolbar) -{ - GtkToolbarSpaceStyle space_style = DEFAULT_SPACE_STYLE; - - gtk_widget_style_get (GTK_WIDGET (toolbar), - "space_style", &space_style, - NULL); + if ((type != GTK_TOOLBAR_CHILD_SPACE) && tooltip_text) + gtk_tool_item_set_tooltip (item, toolbar->tooltips, + tooltip_text, tooltip_private_text); + + toolbar->children = g_list_insert (toolbar->children, child, position); + gtk_toolbar_insert_tool_item (toolbar, item, position); - return space_style; + return child->widget; } diff --git a/gtk/gtktoolbar.h b/gtk/gtktoolbar.h index dc3f6d9ddb..87d570383a 100644 --- a/gtk/gtktoolbar.h +++ b/gtk/gtktoolbar.h @@ -2,6 +2,10 @@ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * GtkToolbar copyright (C) Federico Mena * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * Copyright (C) 2003 Soeren Sandmann <sandmann@daimi.au.dk> + * * 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 @@ -28,30 +32,33 @@ #ifndef __GTK_TOOLBAR_H__ #define __GTK_TOOLBAR_H__ - #include <gdk/gdk.h> #include <gtk/gtkcontainer.h> #include <gtk/gtkenums.h> #include <gtk/gtktooltips.h> +#include "gtktoolitem.h" + +#ifndef GTK_DISABLE_DEPRECATED + /* Not needed, retained for compatibility -Yosh */ #include <gtk/gtkpixmap.h> #include <gtk/gtksignal.h> +#endif -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - +G_BEGIN_DECLS -#define GTK_TYPE_TOOLBAR (gtk_toolbar_get_type ()) -#define GTK_TOOLBAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_TOOLBAR, GtkToolbar)) -#define GTK_TOOLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_TOOLBAR, GtkToolbarClass)) -#define GTK_IS_TOOLBAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_TOOLBAR)) -#define GTK_IS_TOOLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_TOOLBAR)) -#define GTK_TOOLBAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_TOOLBAR, GtkToolbarClass)) +#define GTK_TYPE_TOOLBAR (gtk_toolbar_get_type ()) +#define GTK_TOOLBAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_TOOLBAR, GtkToolbar)) +#define GTK_TOOLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_TOOLBAR, GtkToolbarClass)) +#define GTK_IS_TOOLBAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_TOOLBAR)) +#define GTK_IS_TOOLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_TOOLBAR)) +#define GTK_TOOLBAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_TOOLBAR, GtkToolbarClass)) +#define GTK_TOOLBAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_TOOLBAR, GtkToolbarPrivate)) +#ifndef GTK_DISABLE_DEPRECATED typedef enum { GTK_TOOLBAR_CHILD_SPACE, @@ -61,15 +68,7 @@ typedef enum GTK_TOOLBAR_CHILD_WIDGET } GtkToolbarChildType; -typedef enum -{ - GTK_TOOLBAR_SPACE_EMPTY, - GTK_TOOLBAR_SPACE_LINE -} GtkToolbarSpaceStyle; - -typedef struct _GtkToolbarChild GtkToolbarChild; -typedef struct _GtkToolbar GtkToolbar; -typedef struct _GtkToolbarClass GtkToolbarClass; +typedef struct _GtkToolbarChild GtkToolbarChild; struct _GtkToolbarChild { @@ -79,6 +78,18 @@ struct _GtkToolbarChild GtkWidget *label; }; +typedef enum +{ + GTK_TOOLBAR_SPACE_EMPTY, + GTK_TOOLBAR_SPACE_LINE +} GtkToolbarSpaceStyle; + +#endif /* GTK_DISABLE_DEPRECATED */ + +typedef struct _GtkToolbar GtkToolbar; +typedef struct _GtkToolbarClass GtkToolbarClass; +typedef struct _GtkToolbarPrivate GtkToolbarPrivate; + struct _GtkToolbar { GtkContainer container; @@ -90,13 +101,13 @@ struct _GtkToolbar GtkIconSize icon_size; GtkTooltips *tooltips; - - gint button_maxw; - gint button_maxh; + + gint button_maxw; /* maximum width of homogeneous children */ + gint button_maxh; /* maximum height of homogeneous children */ guint style_set_connection; guint icon_size_connection; - + guint style_set : 1; guint icon_size_set : 1; }; @@ -105,45 +116,76 @@ struct _GtkToolbarClass { GtkContainerClass parent_class; - void (* orientation_changed) (GtkToolbar *toolbar, - GtkOrientation orientation); - void (* style_changed) (GtkToolbar *toolbar, - GtkToolbarStyle style); + /* signals */ + void (* orientation_changed) (GtkToolbar *toolbar, + GtkOrientation orientation); + void (* style_changed) (GtkToolbar *toolbar, + GtkToolbarStyle style); + void (* popup_context_menu) (GtkToolbar *toolbar); /* Padding for future expansion */ void (*_gtk_reserved1) (void); void (*_gtk_reserved2) (void); void (*_gtk_reserved3) (void); - void (*_gtk_reserved4) (void); }; - -GType gtk_toolbar_get_type (void) G_GNUC_CONST; -GtkWidget* gtk_toolbar_new (void); - +GType gtk_toolbar_get_type (void) G_GNUC_CONST; +GtkWidget* gtk_toolbar_new (void); + +void gtk_toolbar_insert (GtkToolbar *toolbar, + GtkToolItem *item, + gint pos); +gint gtk_toolbar_get_item_index (GtkToolbar *toolbar, + GtkToolItem *item); +gint gtk_toolbar_get_n_items (GtkToolbar *toolbar); +GtkToolItem * gtk_toolbar_get_nth_item (GtkToolbar *toolbar, + gint n); +gint gtk_toolbar_get_drop_index (GtkToolbar *toolbar, + gint x, + gint y); +void gtk_toolbar_set_show_arrow (GtkToolbar *toolbar, + gboolean show_arrow); +void gtk_toolbar_set_orientation (GtkToolbar *toolbar, + GtkOrientation orientation); +void gtk_toolbar_set_tooltips (GtkToolbar *toolbar, + gboolean enable); +void gtk_toolbar_unset_icon_size (GtkToolbar *toolbar); +gboolean gtk_toolbar_get_show_arrow (GtkToolbar *toolbar); +GtkOrientation gtk_toolbar_get_orientation (GtkToolbar *toolbar); +GtkToolbarStyle gtk_toolbar_get_style (GtkToolbar *toolbar); +GtkIconSize gtk_toolbar_get_icon_size (GtkToolbar *toolbar); +gboolean gtk_toolbar_get_tooltips (GtkToolbar *toolbar); +GtkReliefStyle gtk_toolbar_get_relief_style (GtkToolbar *toolbar); + +#ifndef GTK_DISABLE_DEPRECATED /* Simple button items */ -GtkWidget* gtk_toolbar_append_item (GtkToolbar *toolbar, - const char *text, - const char *tooltip_text, - const char *tooltip_private_text, - GtkWidget *icon, - GtkSignalFunc callback, - gpointer user_data); -GtkWidget* gtk_toolbar_prepend_item (GtkToolbar *toolbar, - const char *text, - const char *tooltip_text, - const char *tooltip_private_text, - GtkWidget *icon, - GtkSignalFunc callback, - gpointer user_data); -GtkWidget* gtk_toolbar_insert_item (GtkToolbar *toolbar, - const char *text, - const char *tooltip_text, - const char *tooltip_private_text, - GtkWidget *icon, - GtkSignalFunc callback, - gpointer user_data, - gint position); +void gtk_toolbar_set_style (GtkToolbar *toolbar, + GtkToolbarStyle style); +void gtk_toolbar_set_icon_size (GtkToolbar *toolbar, + GtkIconSize icon_size); +void gtk_toolbar_unset_style (GtkToolbar *toolbar); +GtkWidget* gtk_toolbar_append_item (GtkToolbar *toolbar, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data); +GtkWidget* gtk_toolbar_prepend_item (GtkToolbar *toolbar, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data); +GtkWidget* gtk_toolbar_insert_item (GtkToolbar *toolbar, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data, + gint position); /* Stock Items */ GtkWidget* gtk_toolbar_insert_stock (GtkToolbar *toolbar, @@ -154,8 +196,6 @@ GtkWidget* gtk_toolbar_insert_stock (GtkToolbar *toolbar, gpointer user_data, gint position); - - /* Space Items */ void gtk_toolbar_append_space (GtkToolbar *toolbar); void gtk_toolbar_prepend_space (GtkToolbar *toolbar); @@ -163,7 +203,6 @@ void gtk_toolbar_insert_space (GtkToolbar *toolbar, gint position); void gtk_toolbar_remove_space (GtkToolbar *toolbar, gint position); - /* Any element type */ GtkWidget* gtk_toolbar_append_element (GtkToolbar *toolbar, GtkToolbarChildType type, @@ -211,25 +250,9 @@ void gtk_toolbar_insert_widget (GtkToolbar *toolbar, const char *tooltip_private_text, gint position); -/* Style functions */ -void gtk_toolbar_set_orientation (GtkToolbar *toolbar, - GtkOrientation orientation); -void gtk_toolbar_set_style (GtkToolbar *toolbar, - GtkToolbarStyle style); -void gtk_toolbar_set_icon_size (GtkToolbar *toolbar, - GtkIconSize icon_size); -void gtk_toolbar_set_tooltips (GtkToolbar *toolbar, - gboolean enable); -void gtk_toolbar_unset_style (GtkToolbar *toolbar); -void gtk_toolbar_unset_icon_size (GtkToolbar *toolbar); - -GtkOrientation gtk_toolbar_get_orientation (GtkToolbar *toolbar); -GtkToolbarStyle gtk_toolbar_get_style (GtkToolbar *toolbar); -GtkIconSize gtk_toolbar_get_icon_size (GtkToolbar *toolbar); -gboolean gtk_toolbar_get_tooltips (GtkToolbar *toolbar); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ +#endif /* GTK_DISABLE_DEPRECATED */ + + +G_END_DECLS #endif /* __GTK_TOOLBAR_H__ */ diff --git a/gtk/gtktoolbutton.c b/gtk/gtktoolbutton.c new file mode 100644 index 0000000000..a5fa3be88e --- /dev/null +++ b/gtk/gtktoolbutton.c @@ -0,0 +1,812 @@ +/* gtktoolbutton.c + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * Copyright (C) 2003 Soeren Sandmann <sandmann@daimi.au.dk> + * + * 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 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gtktoolbutton.h" +#include "gtkbutton.h" +#include "gtkhbox.h" +#include "gtkiconfactory.h" +#include "gtkimage.h" +#include "gtkimagemenuitem.h" +#include "gtklabel.h" +#include "gtkstock.h" +#include "gtkvbox.h" +#include "gtkintl.h" + +#include <string.h> + +#define MENU_ID "gtk-tool-button-menu-id" + +enum { + CLICKED, + LAST_SIGNAL +}; + +enum { + PROP_0, + PROP_LABEL, + PROP_USE_UNDERLINE, + PROP_LABEL_WIDGET, + PROP_STOCK_ID, + PROP_ICON_SET, + PROP_ICON_WIDGET, +}; + +static void gtk_tool_button_init (GtkToolButton *button, + GtkToolButtonClass *klass); +static void gtk_tool_button_class_init (GtkToolButtonClass *klass); +static void gtk_tool_button_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_tool_button_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_tool_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_tool_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void gtk_tool_button_finalize (GObject *object); + +static void gtk_tool_button_toolbar_reconfigured (GtkToolItem *tool_item); +static gboolean gtk_tool_button_create_menu_proxy (GtkToolItem *item); +static void button_clicked (GtkWidget *widget, + GtkToolButton *button); + +static void gtk_tool_button_construct_contents (GtkToolItem *tool_item); + +static GObjectClass *parent_class = NULL; +static guint toolbutton_signals[LAST_SIGNAL] = { 0 }; + +GType +gtk_tool_button_get_type (void) +{ + static GtkType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (GtkToolButtonClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gtk_tool_button_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (GtkToolButton), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_tool_button_init, + }; + + type = g_type_register_static (GTK_TYPE_TOOL_ITEM, + "GtkToolButton", + &type_info, 0); + } + return type; +} + +static void +gtk_tool_button_class_init (GtkToolButtonClass *klass) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkToolItemClass *tool_item_class; + + parent_class = g_type_class_peek_parent (klass); + + object_class = (GObjectClass *)klass; + widget_class = (GtkWidgetClass *)klass; + tool_item_class = (GtkToolItemClass *)klass; + + object_class->set_property = gtk_tool_button_set_property; + object_class->get_property = gtk_tool_button_get_property; + object_class->finalize = gtk_tool_button_finalize; + + widget_class->size_request = gtk_tool_button_size_request; + widget_class->size_allocate = gtk_tool_button_size_allocate; + + tool_item_class->create_menu_proxy = gtk_tool_button_create_menu_proxy; + tool_item_class->toolbar_reconfigured = gtk_tool_button_toolbar_reconfigured; + + klass->button_type = GTK_TYPE_BUTTON; + + g_object_class_install_property (object_class, + PROP_LABEL, + g_param_spec_string ("label", + _("Label"), + _("Text to show in the item."), + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_USE_UNDERLINE, + g_param_spec_boolean ("use_underline", + _("Use underline"), + _("Interpret underlines in the item label"), + FALSE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_LABEL_WIDGET, + g_param_spec_object ("label_widget", + _("Label widget"), + _("Widget to use as the item label"), + GTK_TYPE_WIDGET, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_STOCK_ID, + g_param_spec_string ("stock_id", + _("Stock Id"), + _("The stock icon displayed on the item"), + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_ICON_SET, + g_param_spec_boxed ("icon_set", + _("Icon set"), + _("Icon set to use to draw the item's icon"), + GTK_TYPE_ICON_SET, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_ICON_WIDGET, + g_param_spec_object ("icon_widget", + _("Icon widget"), + _("Icon widget to display in the item"), + GTK_TYPE_WIDGET, + G_PARAM_READWRITE)); + + toolbutton_signals[CLICKED] = + g_signal_new ("clicked", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkToolButtonClass, clicked), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +gtk_tool_button_init (GtkToolButton *button, + GtkToolButtonClass *klass) +{ + GtkToolItem *toolitem = GTK_TOOL_ITEM (button); + + toolitem->homogeneous = TRUE; + + /* create button */ + button->button = g_object_new (klass->button_type, NULL); + gtk_button_set_focus_on_click (button->button, FALSE); + g_signal_connect_object (button->button, "clicked", + G_CALLBACK (button_clicked), button, 0); + + gtk_container_add (GTK_CONTAINER (button), button->button); + gtk_widget_show (button->button); +} + +static void +gtk_tool_button_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkWidget *child = GTK_BIN (widget)->child; + + if (child && GTK_WIDGET_VISIBLE (child)) + { + gtk_widget_size_request (child, requisition); + } + else + { + requisition->width = 0; + requisition->height = 0; + } + + requisition->width += GTK_CONTAINER (widget)->border_width * 2; + requisition->height += GTK_CONTAINER (widget)->border_width * 2; +} + +static void +gtk_tool_button_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkToolItem *toolitem = GTK_TOOL_ITEM (widget); + GtkAllocation child_allocation; + gint border_width; + GtkWidget *child = GTK_BIN (widget)->child; + + widget->allocation = *allocation; + border_width = GTK_CONTAINER (widget)->border_width; + + if (toolitem->drag_window && GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (toolitem->drag_window, + widget->allocation.x + border_width, + widget->allocation.y + border_width, + widget->allocation.width - border_width * 2, + widget->allocation.height - border_width * 2); + + if (child && GTK_WIDGET_VISIBLE (child)) + { + child_allocation.x = allocation->x + border_width; + child_allocation.y = allocation->y + border_width; + child_allocation.width = allocation->width - 2 * border_width; + child_allocation.height = allocation->height - 2 * border_width; + + gtk_widget_size_allocate (child, &child_allocation); + } +} + +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 +gtk_tool_button_construct_contents (GtkToolItem *tool_item) +{ + GtkToolButton *button = GTK_TOOL_BUTTON (tool_item); + GtkWidget *label = NULL; + GtkWidget *icon = NULL; + GtkToolbarStyle style; + gboolean need_label = FALSE; + gboolean need_icon = FALSE; + GtkIconSize icon_size; + GtkWidget *box = NULL; + + if (gtk_tool_item_get_proxy_menu_item (tool_item, MENU_ID)) + { + /* Remove item, so it will be recreated on the next + * create_proxy_menu_item() + */ + gtk_tool_item_set_proxy_menu_item (tool_item, MENU_ID, NULL); + } + + if (button->icon_widget && button->icon_widget->parent) + { + gtk_container_remove (GTK_CONTAINER (button->icon_widget->parent), + button->icon_widget); + } + + if (button->label_widget && button->label_widget->parent) + { + gtk_container_remove (GTK_CONTAINER (button->label_widget->parent), + button->label_widget); + } + + if (GTK_BIN (button->button)->child) + { + gtk_container_remove (GTK_CONTAINER (button->button), + GTK_BIN (button->button)->child); + } + + style = gtk_tool_item_get_toolbar_style (GTK_TOOL_ITEM (button)); + + if (style != GTK_TOOLBAR_TEXT) + need_icon = TRUE; + + if (style != GTK_TOOLBAR_ICONS) + need_label = TRUE; + + if (need_label) + { + if (button->label_widget) + { + label = button->label_widget; + } + else + { + GtkStockItem stock_item; + gboolean elide = TRUE; + gchar *label_text; + + if (button->label_text) + { + label_text = button->label_text; + elide = button->use_underline; + } + else if (button->stock_id && gtk_stock_lookup (button->stock_id, &stock_item)) + label_text = stock_item.label; + else + label_text = ""; + + if (elide) + label_text = elide_underscores (label_text); + else + label_text = g_strdup (label_text); + + label = gtk_label_new (label_text); + + g_free (label_text); + + gtk_widget_show (label); + } + } + + icon_size = gtk_tool_item_get_icon_size (GTK_TOOL_ITEM (button)); + if (need_icon) + { + if (button->icon_set) + { + icon = gtk_image_new_from_icon_set (button->icon_set, icon_size); + gtk_widget_show (icon); + } + else if (button->icon_widget) + { + icon = button->icon_widget; + + if (GTK_IS_IMAGE (icon)) + { + GtkImage *image = GTK_IMAGE (icon); + GtkImageType storage_type = gtk_image_get_storage_type (image); + + if (storage_type == GTK_IMAGE_STOCK) + { + gchar *stock_id; + gtk_image_get_stock (image, &stock_id, NULL); + + icon = gtk_image_new_from_stock (stock_id, icon_size); + gtk_widget_show (icon); + } + else if (storage_type == GTK_IMAGE_ICON_SET) + { + GtkIconSet *icon_set; + gtk_image_get_icon_set (image, &icon_set, NULL); + + icon = gtk_image_new_from_icon_set (icon_set, icon_size); + gtk_widget_show (icon); + } + } + } + else if (button->stock_id) + { + icon = gtk_image_new_from_stock (button->stock_id, icon_size); + gtk_widget_show (icon); + } + } + + switch (style) + { + case GTK_TOOLBAR_ICONS: + if (icon) + gtk_container_add (GTK_CONTAINER (button->button), icon); + break; + + case GTK_TOOLBAR_BOTH: + box = gtk_vbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), icon, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (button->button), box); + break; + + case GTK_TOOLBAR_BOTH_HORIZ: + box = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), icon, FALSE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (button->button), box); + break; + + case GTK_TOOLBAR_TEXT: + gtk_container_add (GTK_CONTAINER (button->button), label); + break; + } + + if (box) + gtk_widget_show (box); + + gtk_button_set_relief (GTK_BUTTON (button->button), + gtk_tool_item_get_relief_style (GTK_TOOL_ITEM (button))); + + gtk_widget_queue_resize (GTK_WIDGET (button)); +} + +static void +gtk_tool_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkToolButton *button = GTK_TOOL_BUTTON (object); + + switch (prop_id) + { + case PROP_LABEL: + gtk_tool_button_set_label (button, g_value_get_string (value)); + break; + case PROP_USE_UNDERLINE: + gtk_tool_button_set_use_underline (button, g_value_get_boolean (value)); + break; + case PROP_LABEL_WIDGET: + gtk_tool_button_set_label_widget (button, g_value_get_object (value)); + break; + case PROP_STOCK_ID: + gtk_tool_button_set_stock_id (button, g_value_get_string (value)); + break; + case PROP_ICON_SET: + gtk_tool_button_set_icon_set (button, g_value_get_boxed (value)); + break; + case PROP_ICON_WIDGET: + gtk_tool_button_set_icon_widget (button, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gtk_tool_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkToolButton *button = GTK_TOOL_BUTTON (object); + + switch (prop_id) + { + case PROP_LABEL: + g_value_set_string (value, gtk_tool_button_get_label (button)); + break; + case PROP_LABEL_WIDGET: + g_value_set_object (value, gtk_tool_button_get_label_widget (button)); + break; + case PROP_USE_UNDERLINE: + g_value_set_boolean (value, gtk_tool_button_get_use_underline (button)); + break; + case PROP_STOCK_ID: + g_value_set_string (value, button->stock_id); + break; + case PROP_ICON_SET: + g_value_set_boxed (value, gtk_tool_button_get_icon_set (button)); + break; + case PROP_ICON_WIDGET: + g_value_set_object (value, button->icon_widget); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gtk_tool_button_finalize (GObject *object) +{ + GtkToolButton *button = GTK_TOOL_BUTTON (object); + + g_free (button->stock_id); + button->stock_id = NULL; + + parent_class->finalize (object); +} + +static gboolean +gtk_tool_button_create_menu_proxy (GtkToolItem *item) +{ + GtkToolButton *button = GTK_TOOL_BUTTON (item); + GtkWidget *menu_item; + GtkWidget *menu_image = NULL; + GtkStockItem stock_item; + gboolean use_mnemonic = TRUE; + const char *label = ""; + + if (button->label_widget && GTK_IS_LABEL (button->label_widget)) + label = gtk_label_get_label (GTK_LABEL (button->label_widget)); + else if (button->label_text) + { + label = button->label_text; + use_mnemonic = button->use_underline; + } + else if (button->stock_id && gtk_stock_lookup (button->stock_id, &stock_item)) + label = stock_item.label; + + if (use_mnemonic) + menu_item = gtk_image_menu_item_new_with_mnemonic (label); + else + menu_item = gtk_image_menu_item_new_with_label (label); + + if (button->icon_set) + { + menu_image = gtk_image_new_from_icon_set (button->icon_set, GTK_ICON_SIZE_MENU); + } + else if (button->icon_widget && GTK_IS_IMAGE (button->icon_widget)) + { + GtkImage *image = GTK_IMAGE (button->icon_widget); + GtkImageType storage_type = gtk_image_get_storage_type (image); + + if (storage_type == GTK_IMAGE_STOCK) + { + gchar *stock_id; + gtk_image_get_stock (image, &stock_id, NULL); + menu_image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU); + } + else if (storage_type == GTK_IMAGE_ICON_SET) + { + GtkIconSet *icon_set; + gtk_image_get_icon_set (image, &icon_set, NULL); + menu_image = gtk_image_new_from_icon_set (icon_set, GTK_ICON_SIZE_MENU); + } + } + else if (button->stock_id) + { + menu_image = gtk_image_new_from_stock (button->stock_id, GTK_ICON_SIZE_MENU); + } + + if (menu_image) + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image); + + g_signal_connect_closure_by_id (menu_item, + g_signal_lookup ("activate", G_OBJECT_TYPE (menu_item)), 0, + g_cclosure_new_object_swap (G_CALLBACK (gtk_button_clicked), + G_OBJECT (GTK_TOOL_BUTTON (button)->button)), + FALSE); + + gtk_tool_item_set_proxy_menu_item (GTK_TOOL_ITEM (button), MENU_ID, menu_item); + + return TRUE; +} + +static void +button_clicked (GtkWidget *widget, + GtkToolButton *button) +{ + g_signal_emit_by_name (button, "clicked"); +} + +static void +gtk_tool_button_toolbar_reconfigured (GtkToolItem *tool_item) +{ + gtk_tool_button_construct_contents (tool_item); +} + +GtkToolItem * +gtk_tool_button_new_from_stock (const gchar *stock_id) +{ + GtkToolButton *button; + + g_return_val_if_fail (stock_id != NULL, NULL); + + button = g_object_new (GTK_TYPE_TOOL_BUTTON, + "stock_id", stock_id, + NULL); + + return GTK_TOOL_ITEM (button); +} + +GtkToolItem * +gtk_tool_button_new (void) +{ + GtkToolButton *button; + + button = g_object_new (GTK_TYPE_TOOL_BUTTON, + NULL); + + return GTK_TOOL_ITEM (button); +} + +void +gtk_tool_button_set_label (GtkToolButton *button, + const gchar *label) +{ + gchar *old_label; + + g_return_if_fail (GTK_IS_TOOL_BUTTON (button)); + + old_label = button->label_text; + + button->label_text = g_strdup (label); + gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button)); + + g_object_notify (G_OBJECT (button), "label"); + + if (old_label) + g_free (old_label); +} + +G_CONST_RETURN gchar * +gtk_tool_button_get_label (GtkToolButton *button) +{ + g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL); + + return button->label_text; +} + +void +gtk_tool_button_set_use_underline (GtkToolButton *button, + gboolean use_underline) +{ + g_return_if_fail (GTK_IS_TOOL_BUTTON (button)); + + use_underline = use_underline != FALSE; + + if (use_underline != button->use_underline) + { + button->use_underline = use_underline; + + gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button)); + + g_object_notify (G_OBJECT (button), "use_underline"); + } +} + +gboolean +gtk_tool_button_get_use_underline (GtkToolButton *button) +{ + g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), FALSE); + + return button->use_underline; +} + +void +gtk_tool_button_set_stock_id (GtkToolButton *button, + const gchar *stock_id) +{ + gchar *old_stock_id; + + g_return_if_fail (GTK_IS_TOOL_BUTTON (button)); + + old_stock_id = button->stock_id; + + button->stock_id = g_strdup (stock_id); + gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button)); + + g_object_notify (G_OBJECT (button), "stock_id"); + + g_free (old_stock_id); +} + +G_CONST_RETURN gchar * +gtk_tool_button_get_stock_id (GtkToolButton *button) +{ + g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL); + + return button->stock_id; +} + +void +gtk_tool_button_set_icon_widget (GtkToolButton *button, + GtkWidget *icon) +{ + g_return_if_fail (GTK_IS_TOOL_BUTTON (button)); + g_return_if_fail (icon == NULL || GTK_IS_WIDGET (icon)); + + if (icon != button->icon_widget) + { + g_object_freeze_notify (G_OBJECT (button)); + + if (button->icon_widget) + g_object_unref (G_OBJECT (button->icon_widget)); + + if (icon) + { + g_object_ref (icon); + gtk_object_sink (GTK_OBJECT (icon)); + } + + button->icon_widget = icon; + + if (button->icon_widget && button->icon_set) + { + gtk_icon_set_unref (button->icon_set); + button->icon_set = NULL; + + g_object_notify (G_OBJECT (button), "icon_set"); + } + + gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button)); + + g_object_notify (G_OBJECT (button), "icon_widget"); + g_object_thaw_notify (G_OBJECT (button)); + } +} + +void +gtk_tool_button_set_label_widget (GtkToolButton *button, + GtkWidget *label_widget) +{ + g_return_if_fail (GTK_IS_TOOL_BUTTON (button)); + g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget)); + + if (label_widget != button->label_widget) + { + if (button->label_widget) + g_object_unref (button->label_widget); + + if (label_widget) + { + g_object_ref (label_widget); + gtk_object_sink (GTK_OBJECT (label_widget)); + } + + button->label_widget = label_widget; + + gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button)); + + g_object_notify (G_OBJECT (button), "label_widget"); + } +} + +GtkWidget * +gtk_tool_button_get_label_widget (GtkToolButton *button) +{ + g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL); + + return button->label_widget; +} + +GtkWidget * +gtk_tool_button_get_icon_widget (GtkToolButton *button) +{ + g_return_val_if_fail (GTK_IS_BUTTON (button), NULL); + + return button->icon_widget; +} + +void +gtk_tool_button_set_icon_set (GtkToolButton *button, + GtkIconSet *icon_set) +{ + g_return_if_fail (GTK_IS_TOOL_BUTTON (button)); + + if (icon_set != button->icon_set) + { + g_object_freeze_notify (G_OBJECT (button)); + + if (button->icon_set) + gtk_icon_set_unref (button->icon_set); + + button->icon_set = icon_set; + + if (button->icon_set && button->icon_widget) + { + g_object_unref (button->icon_widget); + button->icon_widget = NULL; + + g_object_notify (G_OBJECT (button->icon_widget), "icon_widget"); + } + + gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button)); + + g_object_notify (G_OBJECT (button), "icon_set"); + g_object_thaw_notify (G_OBJECT (button)); + } +} + +GtkIconSet * +gtk_tool_button_get_icon_set (GtkToolButton *button) +{ + g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL); + + return button->icon_set; +} diff --git a/gtk/gtktoolbutton.h b/gtk/gtktoolbutton.h new file mode 100644 index 0000000000..72456e894e --- /dev/null +++ b/gtk/gtktoolbutton.h @@ -0,0 +1,92 @@ +/* gtktoolbutton.h + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * Copyright (C) 2003 Soeren Sandmann <sandmann@daimi.au.dk> + * + * 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 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTK_TOOL_BUTTON_H__ +#define __GTK_TOOL_BUTTON_H__ + +#include "gtktoolitem.h" + +G_BEGIN_DECLS + +#define GTK_TYPE_TOOL_BUTTON (gtk_tool_button_get_type ()) +#define GTK_TOOL_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_TOOL_BUTTON, GtkToolButton)) +#define GTK_TOOL_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_TOOL_BUTTON, GtkToolButtonClass)) +#define GTK_IS_TOOL_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_TOOL_BUTTON)) +#define GTK_IS_TOOL_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), GTK_TYPE_TOOL_BUTTON)) +#define GTK_TOOL_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_TOOL_BUTTON, GtkToolButtonClass)) + +typedef struct _GtkToolButton GtkToolButton; +typedef struct _GtkToolButtonClass GtkToolButtonClass; +typedef struct _GtkToolButtonPrivate GtkToolButtonPrivate; + +struct _GtkToolButton +{ + GtkToolItem parent; + + GtkWidget *button; + + gchar *stock_id; + gchar *label_text; + GtkWidget *label_widget; + GtkWidget *icon_widget; + GtkIconSet *icon_set; + + guint use_underline : 1; +}; + +struct _GtkToolButtonClass +{ + GtkToolItemClass parent_class; + + GType button_type; + + /* signal */ + void (* clicked) (GtkToolButton *tool_item); +}; + +GType gtk_tool_button_get_type (void); +GtkToolItem *gtk_tool_button_new (void); +GtkToolItem *gtk_tool_button_new_from_stock (const gchar *stock_id); + +void gtk_tool_button_set_label (GtkToolButton *button, + const gchar *label); +G_CONST_RETURN gchar *gtk_tool_button_get_label (GtkToolButton *button); +void gtk_tool_button_set_use_underline (GtkToolButton *button, + gboolean use_underline); +gboolean gtk_tool_button_get_use_underline (GtkToolButton *button); +void gtk_tool_button_set_stock_id (GtkToolButton *button, + const gchar *stock_id); +G_CONST_RETURN gchar *gtk_tool_button_get_stock_id (GtkToolButton *button); +void gtk_tool_button_set_icon_set (GtkToolButton *button, + GtkIconSet *icon_set); +GtkIconSet * gtk_tool_button_get_icon_set (GtkToolButton *button); +void gtk_tool_button_set_icon_widget (GtkToolButton *button, + GtkWidget *icon); +GtkWidget * gtk_tool_button_get_icon_widget (GtkToolButton *button); + +void gtk_tool_button_set_label_widget (GtkToolButton *button, + GtkWidget *label_widget); +GtkWidget * gtk_tool_button_get_label_widget (GtkToolButton *button); + +G_END_DECLS + +#endif /* __GTK_TOOL_BUTTON_H__ */ diff --git a/gtk/gtktoolitem.c b/gtk/gtktoolitem.c new file mode 100644 index 0000000000..37007e06a7 --- /dev/null +++ b/gtk/gtktoolitem.c @@ -0,0 +1,697 @@ +/* gtktoolitem.c + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * Copyright (C) 2003 Soeren Sandmann <sandmann@daimi.au.dk> + * + * 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 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gtktoolitem.h" +#include "gtkmarshalers.h" +#include "gtktoolbar.h" +#include "gtkseparatormenuitem.h" +#include "gtkintl.h" +#include "gtkmain.h" + +#include <string.h> + +#define MENU_ID "gtk-tool-item-menu-id" + +enum { + CREATE_MENU_PROXY, + TOOLBAR_RECONFIGURED, + SET_TOOLTIP, + LAST_SIGNAL +}; + +enum { + PROP_0, + PROP_VISIBLE_HORIZONTAL, + PROP_VISIBLE_VERTICAL, +}; + +static void gtk_tool_item_init (GtkToolItem *toolitem); +static void gtk_tool_item_class_init (GtkToolItemClass *class); +static void gtk_tool_item_finalize (GObject *object); +static void gtk_tool_item_parent_set (GtkWidget *toolitem, + GtkWidget *parent); +static void gtk_tool_item_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_tool_item_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void gtk_tool_item_realize (GtkWidget *widget); +static void gtk_tool_item_unrealize (GtkWidget *widget); +static void gtk_tool_item_map (GtkWidget *widget); +static void gtk_tool_item_unmap (GtkWidget *widget); +static void gtk_tool_item_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_tool_item_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gboolean gtk_tool_item_real_set_tooltip (GtkToolItem *tool_item, + GtkTooltips *tooltips, + const gchar *tip_text, + const gchar *tip_private); + +static gboolean gtk_tool_item_create_menu_proxy (GtkToolItem *item); + + +static GObjectClass *parent_class = NULL; +static guint toolitem_signals[LAST_SIGNAL] = { 0 }; + +GType +gtk_tool_item_get_type (void) +{ + static GtkType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (GtkToolItemClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gtk_tool_item_class_init, + (GClassFinalizeFunc) NULL, + NULL, + + sizeof (GtkToolItem), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_tool_item_init, + }; + + type = g_type_register_static (GTK_TYPE_BIN, + "GtkToolItem", + &type_info, 0); + } + return type; +} + +static void +gtk_tool_item_class_init (GtkToolItemClass *klass) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + + parent_class = g_type_class_peek_parent (klass); + object_class = (GObjectClass *)klass; + widget_class = (GtkWidgetClass *)klass; + + object_class->set_property = gtk_tool_item_set_property; + object_class->get_property = gtk_tool_item_get_property; + object_class->finalize = gtk_tool_item_finalize; + + widget_class->realize = gtk_tool_item_realize; + widget_class->unrealize = gtk_tool_item_unrealize; + widget_class->map = gtk_tool_item_map; + widget_class->unmap = gtk_tool_item_unmap; + widget_class->size_request = gtk_tool_item_size_request; + widget_class->size_allocate = gtk_tool_item_size_allocate; + widget_class->parent_set = gtk_tool_item_parent_set; + + klass->create_menu_proxy = gtk_tool_item_create_menu_proxy; + klass->set_tooltip = gtk_tool_item_real_set_tooltip; + + g_object_class_install_property (object_class, + PROP_VISIBLE_HORIZONTAL, + g_param_spec_boolean ("visible_horizontal", + _("Visible when horizontal"), + _("Whether the toolbar item is visible when the toolbar is in a horizontal orientation."), + TRUE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_VISIBLE_VERTICAL, + g_param_spec_boolean ("visible_vertical", + _("Visible when vertical"), + _("Whether the toolbar item is visible when the toolbar is in a vertical orientation."), + TRUE, + G_PARAM_READWRITE)); + toolitem_signals[CREATE_MENU_PROXY] = + g_signal_new ("create_menu_proxy", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkToolItemClass, create_menu_proxy), + _gtk_boolean_handled_accumulator, NULL, /* FIXME: use gtk_boolean_handled() when + * we are added to gtk+ + */ + _gtk_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN, 0); + toolitem_signals[TOOLBAR_RECONFIGURED] = + g_signal_new ("toolbar_reconfigured", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkToolItemClass, toolbar_reconfigured), + NULL, NULL, + _gtk_marshal_VOID__VOID, + G_TYPE_NONE, 0); + toolitem_signals[SET_TOOLTIP] = + g_signal_new ("set_tooltip", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkToolItemClass, set_tooltip), + _gtk_boolean_handled_accumulator, NULL, /* FIXME: use gtk_boolean_handled() when + * we are added to gtk+ + */ + _gtk_marshal_BOOLEAN__OBJECT_STRING_STRING, + G_TYPE_BOOLEAN, 3, + GTK_TYPE_TOOLTIPS, + G_TYPE_STRING, + G_TYPE_STRING); +} + +static void +gtk_tool_item_init (GtkToolItem *toolitem) +{ + GTK_WIDGET_UNSET_FLAGS (toolitem, GTK_CAN_FOCUS); + + toolitem->visible_horizontal = TRUE; + toolitem->visible_vertical = TRUE; + toolitem->homogeneous = FALSE; + toolitem->expand = FALSE; +} + +static void +gtk_tool_item_finalize (GObject *object) +{ + GtkToolItem *item = GTK_TOOL_ITEM (object); + + if (item->menu_item) + g_object_unref (item->menu_item); + + if (G_OBJECT_CLASS (parent_class)->finalize) + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gtk_tool_item_parent_set (GtkWidget *toolitem, + GtkWidget *prev_parent) +{ + gtk_tool_item_toolbar_reconfigured (GTK_TOOL_ITEM (toolitem)); +} + +static void +gtk_tool_item_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkToolItem *toolitem = GTK_TOOL_ITEM (object); + + switch (prop_id) + { + case PROP_VISIBLE_HORIZONTAL: + gtk_tool_item_set_visible_horizontal (toolitem, g_value_get_boolean (value)); + break; + case PROP_VISIBLE_VERTICAL: + gtk_tool_item_set_visible_horizontal (toolitem, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gtk_tool_item_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkToolItem *toolitem = GTK_TOOL_ITEM (object); + + switch (prop_id) + { + case PROP_VISIBLE_HORIZONTAL: + g_value_set_boolean (value, toolitem->visible_horizontal); + break; + case PROP_VISIBLE_VERTICAL: + g_value_set_boolean (value, toolitem->visible_vertical); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +create_drag_window (GtkToolItem *toolitem) +{ + GtkWidget *widget; + GdkWindowAttr attributes; + gint attributes_mask, border_width; + + g_return_if_fail (toolitem->use_drag_window == TRUE); + + widget = GTK_WIDGET (toolitem); + border_width = GTK_CONTAINER (toolitem)->border_width; + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x + border_width; + attributes.y = widget->allocation.y + border_width; + attributes.width = widget->allocation.width - border_width * 2; + attributes.height = widget->allocation.height - border_width * 2; + attributes.wclass = GDK_INPUT_ONLY; + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y; + + toolitem->drag_window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (toolitem->drag_window, toolitem); +} + +static void +gtk_tool_item_realize (GtkWidget *widget) +{ + GtkToolItem *toolitem; + + toolitem = GTK_TOOL_ITEM (widget); + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + widget->window = gtk_widget_get_parent_window (widget); + g_object_ref (widget->window); + + if (toolitem->use_drag_window) + create_drag_window(toolitem); + + widget->style = gtk_style_attach (widget->style, widget->window); +} + +static void +destroy_drag_window (GtkToolItem *toolitem) +{ + if (toolitem->drag_window) + { + gdk_window_set_user_data (toolitem->drag_window, NULL); + gdk_window_destroy (toolitem->drag_window); + toolitem->drag_window = NULL; + } +} + +static void +gtk_tool_item_unrealize (GtkWidget *widget) +{ + GtkToolItem *toolitem; + + toolitem = GTK_TOOL_ITEM (widget); + + destroy_drag_window (toolitem); + + GTK_WIDGET_CLASS (parent_class)->unrealize (widget); +} + +static void +gtk_tool_item_map (GtkWidget *widget) +{ + GtkToolItem *toolitem; + + toolitem = GTK_TOOL_ITEM (widget); + GTK_WIDGET_CLASS (parent_class)->map (widget); + if (toolitem->drag_window) + gdk_window_show (toolitem->drag_window); +} + +static void +gtk_tool_item_unmap (GtkWidget *widget) +{ + GtkToolItem *toolitem; + + toolitem = GTK_TOOL_ITEM (widget); + if (toolitem->drag_window) + gdk_window_hide (toolitem->drag_window); + GTK_WIDGET_CLASS (parent_class)->unmap (widget); +} + +static void +gtk_tool_item_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkWidget *child = GTK_BIN (widget)->child; + gint xthickness = widget->style->xthickness; + gint ythickness = widget->style->ythickness; + + if (child && GTK_WIDGET_VISIBLE (child)) + { + gtk_widget_size_request (child, requisition); + } + else + { + requisition->height = 0; + requisition->width = 0; + } + + requisition->width += (xthickness + GTK_CONTAINER (widget)->border_width) * 2; + requisition->height += (ythickness + GTK_CONTAINER (widget)->border_width) * 2; +} + +static void +gtk_tool_item_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkToolItem *toolitem = GTK_TOOL_ITEM (widget); + GtkAllocation child_allocation; + gint border_width; + GtkWidget *child = GTK_BIN (widget)->child; + + widget->allocation = *allocation; + border_width = GTK_CONTAINER (widget)->border_width; + + if (toolitem->drag_window) + gdk_window_move_resize (toolitem->drag_window, + widget->allocation.x + border_width, + widget->allocation.y + border_width, + widget->allocation.width - border_width * 2, + widget->allocation.height - border_width * 2); + + if (child && GTK_WIDGET_VISIBLE (child)) + { + gint xthickness = widget->style->xthickness; + gint ythickness = widget->style->ythickness; + + child_allocation.x = allocation->x + border_width + xthickness; + child_allocation.y = allocation->y + border_width + ythickness; + child_allocation.width = allocation->width - 2 * (xthickness + border_width); + child_allocation.height = allocation->height - 2 * (ythickness + border_width); + + gtk_widget_size_allocate (child, &child_allocation); + } +} + +static gboolean +gtk_tool_item_create_menu_proxy (GtkToolItem *item) +{ + if (!GTK_BIN (item)->child) + { + GtkWidget *menu_item = NULL; + + menu_item = gtk_separator_menu_item_new(); + + gtk_tool_item_set_proxy_menu_item (item, MENU_ID, menu_item); + + return TRUE; + } + + return FALSE; +} + +GtkToolItem * +gtk_tool_item_new (void) +{ + GtkToolItem *item; + + item = g_object_new (GTK_TYPE_TOOL_ITEM, NULL); + + return item; +} + +GtkIconSize +gtk_tool_item_get_icon_size (GtkToolItem *tool_item) +{ + GtkWidget *parent; + + g_return_val_if_fail (GTK_IS_TOOL_ITEM (tool_item), GTK_ICON_SIZE_LARGE_TOOLBAR); + + parent = GTK_WIDGET (tool_item)->parent; + if (!parent || !GTK_IS_TOOLBAR (parent)) + return GTK_ICON_SIZE_LARGE_TOOLBAR; + + return gtk_toolbar_get_icon_size (GTK_TOOLBAR (parent)); +} + +GtkOrientation +gtk_tool_item_get_orientation (GtkToolItem *tool_item) +{ + GtkWidget *parent; + + g_return_val_if_fail (GTK_IS_TOOL_ITEM (tool_item), GTK_ORIENTATION_HORIZONTAL); + + parent = GTK_WIDGET (tool_item)->parent; + if (!parent || !GTK_IS_TOOLBAR (parent)) + return GTK_ORIENTATION_HORIZONTAL; + + return gtk_toolbar_get_orientation (GTK_TOOLBAR (parent)); +} + +GtkToolbarStyle +gtk_tool_item_get_toolbar_style (GtkToolItem *tool_item) +{ + GtkWidget *parent; + + g_return_val_if_fail (GTK_IS_TOOL_ITEM (tool_item), GTK_TOOLBAR_ICONS); + + parent = GTK_WIDGET (tool_item)->parent; + if (!parent || !GTK_IS_TOOLBAR (parent)) + return GTK_TOOLBAR_ICONS; + + return gtk_toolbar_get_style (GTK_TOOLBAR (parent)); +} + +GtkReliefStyle +gtk_tool_item_get_relief_style (GtkToolItem *tool_item) +{ + GtkWidget *parent; + + g_return_val_if_fail (GTK_IS_TOOL_ITEM (tool_item), GTK_RELIEF_NONE); + + parent = GTK_WIDGET (tool_item)->parent; + if (!parent || !GTK_IS_TOOLBAR (parent)) + return GTK_RELIEF_NONE; + + return gtk_toolbar_get_relief_style (GTK_TOOLBAR (parent)); +} + +void +gtk_tool_item_toolbar_reconfigured (GtkToolItem *tool_item) +{ + g_return_if_fail (GTK_IS_TOOL_ITEM (tool_item)); + + g_signal_emit (tool_item, toolitem_signals[TOOLBAR_RECONFIGURED], 0); +} + +void +gtk_tool_item_set_expand (GtkToolItem *tool_item, + gboolean expand) +{ + g_return_if_fail (GTK_IS_TOOL_ITEM (tool_item)); + + expand = expand != FALSE; + + if (tool_item->expand != expand) + { + tool_item->expand = expand; + gtk_widget_child_notify (GTK_WIDGET (tool_item), "expand"); + gtk_widget_queue_resize (GTK_WIDGET (tool_item)); + } +} + +void +gtk_tool_item_set_pack_end (GtkToolItem *tool_item, + gboolean pack_end) +{ + g_return_if_fail (GTK_IS_TOOL_ITEM (tool_item)); + + pack_end = pack_end != FALSE; + + if (tool_item->pack_end != pack_end) + { + tool_item->pack_end = pack_end; + gtk_widget_child_notify (GTK_WIDGET (tool_item), "pack_end"); + gtk_widget_queue_resize (GTK_WIDGET (tool_item)); + } +} + +void +gtk_tool_item_set_homogeneous (GtkToolItem *tool_item, + gboolean homogeneous) +{ + g_return_if_fail (GTK_IS_TOOL_ITEM (tool_item)); + + homogeneous = homogeneous != FALSE; + + if (tool_item->homogeneous != homogeneous) + { + tool_item->homogeneous = homogeneous; + gtk_widget_child_notify (GTK_WIDGET (tool_item), "homogeneous"); + gtk_widget_queue_resize (GTK_WIDGET (tool_item)); + } +} + +static gboolean +gtk_tool_item_real_set_tooltip (GtkToolItem *tool_item, + GtkTooltips *tooltips, + const gchar *tip_text, + const gchar *tip_private) +{ + GtkWidget *child = GTK_BIN (tool_item)->child; + + if (!child) + return FALSE; + + gtk_tooltips_set_tip (tooltips, child, tip_text, tip_private); + + return TRUE; +} + +void +gtk_tool_item_set_tooltip (GtkToolItem *tool_item, + GtkTooltips *tooltips, + const gchar *tip_text, + const gchar *tip_private) +{ + gboolean retval; + + g_return_if_fail (GTK_IS_TOOL_ITEM (tool_item)); + + g_signal_emit (tool_item, toolitem_signals[SET_TOOLTIP], 0, + tooltips, tip_text, tip_private, &retval); +} + +void +gtk_tool_item_set_use_drag_window (GtkToolItem *toolitem, + gboolean use_drag_window) +{ + g_return_if_fail (GTK_IS_TOOL_ITEM (toolitem)); + + use_drag_window = use_drag_window != FALSE; + + if (toolitem->use_drag_window != use_drag_window) + { + toolitem->use_drag_window = use_drag_window; + + if (use_drag_window) + { + if (!toolitem->drag_window && GTK_WIDGET_REALIZED (toolitem)) + { + create_drag_window(toolitem); + if (GTK_WIDGET_MAPPED (toolitem)) + gdk_window_show (toolitem->drag_window); + } + } + else + { + destroy_drag_window (toolitem); + } + } +} + +void +gtk_tool_item_set_visible_horizontal (GtkToolItem *toolitem, + gboolean visible_horizontal) +{ + g_return_if_fail (GTK_IS_TOOL_ITEM (toolitem)); + + visible_horizontal = visible_horizontal != FALSE; + + if (toolitem->visible_horizontal != visible_horizontal) + { + toolitem->visible_horizontal = visible_horizontal; + + g_object_notify (G_OBJECT (toolitem), "visible_horizontal"); + + gtk_widget_queue_resize (GTK_WIDGET (toolitem)); + } +} + +gboolean +gtk_tool_item_get_visible_horizontal (GtkToolItem *toolitem) +{ + g_return_val_if_fail (GTK_IS_TOOL_ITEM (toolitem), FALSE); + + return toolitem->visible_horizontal; +} + +void +gtk_tool_item_set_visible_vertical (GtkToolItem *toolitem, + gboolean visible_vertical) +{ + g_return_if_fail (GTK_IS_TOOL_ITEM (toolitem)); + + visible_vertical = visible_vertical != FALSE; + + if (toolitem->visible_vertical != visible_vertical) + { + toolitem->visible_vertical = visible_vertical; + + g_object_notify (G_OBJECT (toolitem), "visible_vertical"); + + gtk_widget_queue_resize (GTK_WIDGET (toolitem)); + } +} + +gboolean +gtk_tool_item_get_visible_vertical (GtkToolItem *toolitem) +{ + g_return_val_if_fail (GTK_IS_TOOL_ITEM (toolitem), FALSE); + + return toolitem->visible_vertical; +} + +GtkWidget * +gtk_tool_item_retrieve_proxy_menu_item (GtkToolItem *tool_item) +{ + gboolean retval; + + g_return_val_if_fail (GTK_IS_TOOL_ITEM (tool_item), NULL); + + g_signal_emit (tool_item, toolitem_signals[CREATE_MENU_PROXY], 0, &retval); + + return tool_item->menu_item; +} + +GtkWidget * +gtk_tool_item_get_proxy_menu_item (GtkToolItem *tool_item, + const gchar *menu_item_id) +{ + g_return_val_if_fail (GTK_IS_TOOL_ITEM (tool_item), NULL); + g_return_val_if_fail (menu_item_id != NULL, NULL); + + if (tool_item->menu_item_id && strcmp (tool_item->menu_item_id, menu_item_id) == 0) + return tool_item->menu_item; + + return NULL; +} + +void +gtk_tool_item_set_proxy_menu_item (GtkToolItem *tool_item, + const gchar *menu_item_id, + GtkWidget *menu_item) +{ + g_return_if_fail (GTK_IS_TOOL_ITEM (tool_item)); + g_return_if_fail (menu_item == NULL || GTK_IS_MENU_ITEM (menu_item)); + g_return_if_fail (menu_item_id != NULL); + + if (tool_item->menu_item_id) + g_free (tool_item->menu_item_id); + + tool_item->menu_item_id = g_strdup (menu_item_id); + + if (tool_item->menu_item != menu_item) + { + if (tool_item->menu_item) + g_object_unref (G_OBJECT (tool_item->menu_item)); + + if (menu_item) + { + g_object_ref (menu_item); + gtk_object_sink (GTK_OBJECT (menu_item)); + } + + tool_item->menu_item = menu_item; + } +} diff --git a/gtk/gtktoolitem.h b/gtk/gtktoolitem.h new file mode 100644 index 0000000000..d48a7113c7 --- /dev/null +++ b/gtk/gtktoolitem.h @@ -0,0 +1,110 @@ +/* gtktoolitem.c + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * Copyright (C) 2003 Soeren Sandmann <sandmann@daimi.au.dk> + * + * 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 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTK_TOOL_ITEM_H__ +#define __GTK_TOOL_ITEM_H__ + +#include <gtk/gtkbin.h> +#include <gtk/gtktooltips.h> +#include <gtk/gtkmenuitem.h> + +#define GTK_TYPE_TOOL_ITEM (gtk_tool_item_get_type ()) +#define GTK_TOOL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_TOOL_ITEM, GtkToolItem)) +#define GTK_TOOL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_TOOL_ITEM, GtkToolItemClass)) +#define GTK_IS_TOOL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_TOOL_ITEM)) +#define GTK_IS_TOOL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), GTK_TYPE_TOOL_ITEM)) +#define GTK_TOOL_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_TOOL_ITEM, GtkToolItemClass)) + +typedef struct _GtkToolItem GtkToolItem; +typedef struct _GtkToolItemClass GtkToolItemClass; +typedef struct _GtkToolItemPrivate GtkToolItemPrivate; + +struct _GtkToolItem +{ + GtkBin parent; + + /*< private >*/ + gchar *tip_text; + gchar *tip_private; + + GdkWindow *drag_window; + + guint visible_horizontal : 1; + guint visible_vertical : 1; + guint homogeneous : 1; + guint expand : 1; + guint pack_end : 1; + guint use_drag_window : 1; + guint overflow_item : 1; + + GtkWidget *menu_item; + gchar *menu_item_id; +}; + +struct _GtkToolItemClass +{ + GtkBinClass parent_class; + + /* signals */ + gboolean (* create_menu_proxy) (GtkToolItem *tool_item); + void (* toolbar_reconfigured) (GtkToolItem *tool_item); + gboolean (* set_tooltip) (GtkToolItem *tool_item, + GtkTooltips *tooltips, + const gchar *tip_text, + const gchar *tip_private); +}; + +GType gtk_tool_item_get_type (void); +GtkToolItem *gtk_tool_item_new (void); + +void gtk_tool_item_toolbar_reconfigured (GtkToolItem *tool_item); +void gtk_tool_item_set_homogeneous (GtkToolItem *tool_item, + gboolean homogeneous); +void gtk_tool_item_set_expand (GtkToolItem *tool_item, + gboolean expand); +void gtk_tool_item_set_pack_end (GtkToolItem *tool_item, + gboolean pack_end); +void gtk_tool_item_set_tooltip (GtkToolItem *tool_item, + GtkTooltips *tooltips, + const gchar *tip_text, + const gchar *tip_private); +void gtk_tool_item_set_use_drag_window (GtkToolItem *toolitem, + gboolean use_drag_window); +void gtk_tool_item_set_visible_horizontal (GtkToolItem *toolitem, + gboolean visible_horizontal); +gboolean gtk_tool_item_get_visible_horizontal (GtkToolItem *toolitem); +void gtk_tool_item_set_visible_vertical (GtkToolItem *toolitem, + gboolean visible_horizontal); +gboolean gtk_tool_item_get_visible_vertical (GtkToolItem *toolitem); +GtkIconSize gtk_tool_item_get_icon_size (GtkToolItem *tool_item); +GtkOrientation gtk_tool_item_get_orientation (GtkToolItem *tool_item); +GtkToolbarStyle gtk_tool_item_get_toolbar_style (GtkToolItem *tool_item); +GtkReliefStyle gtk_tool_item_get_relief_style (GtkToolItem *tool_item); +GtkWidget * gtk_tool_item_retrieve_proxy_menu_item (GtkToolItem *tool_item); +GtkWidget * gtk_tool_item_get_proxy_menu_item (GtkToolItem *tool_item, + const gchar *menu_item_id); +void gtk_tool_item_set_proxy_menu_item (GtkToolItem *tool_item, + const gchar *menu_item_id, + GtkWidget *menu_item); + + +#endif /* __GTK_TOOL_ITEM_H__ */ |