1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* e-source-option-menu.c
4 * Copyright (C) 2003 Novell, Inc.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU Lesser General Public
8 * License as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
20 * Author: Ettore Perazzoli <ettore@ximian.com>
27 #include <gtk/gtkmenu.h>
28 #include <gtk/gtkmenuitem.h>
29 #include <gtk/gtkimagemenuitem.h>
31 #include "e-source-option-menu.h"
33 /* We set data on each menu item specifying the corresponding ESource using this key. */
34 #define MENU_ITEM_SOURCE_DATA_ID "ESourceOptionMenu:Source"
37 struct _ESourceOptionMenuPrivate {
38 ESourceList *source_list;
40 ESource *selected_source;
44 ESourceOptionMenu *option_menu;
46 ESource *found_source;
48 } ForeachMenuItemData;
55 static guint signals[NUM_SIGNALS] = { 0 };
57 G_DEFINE_TYPE (ESourceOptionMenu, e_source_option_menu, GTK_TYPE_OPTION_MENU)
59 /* Selecting a source. */
61 select_source_foreach_menu_item (GtkWidget *menu_item,
62 ForeachMenuItemData *data)
64 ESource *source = gtk_object_get_data (GTK_OBJECT (menu_item), MENU_ITEM_SOURCE_DATA_ID);
66 if (data->found_source)
69 if (source && e_source_equal (source, data->source)) {
70 data->found_source = source;
71 gtk_option_menu_set_history (GTK_OPTION_MENU (data->option_menu), data->i);
78 select_source (ESourceOptionMenu *menu,
81 ForeachMenuItemData *foreach_data;
83 foreach_data = g_new0 (ForeachMenuItemData, 1);
84 foreach_data->option_menu = menu;
85 foreach_data->source = source;
87 gtk_container_foreach (GTK_CONTAINER (GTK_OPTION_MENU (menu)->menu),
88 (GtkCallback) select_source_foreach_menu_item, foreach_data);
90 if (foreach_data->found_source) {
91 menu->priv->selected_source = foreach_data->found_source;
92 g_signal_emit (menu, signals[SOURCE_SELECTED], 0, foreach_data->found_source);
95 g_free (foreach_data);
102 menu_item_activate_callback (GtkMenuItem *menu_item,
103 ESourceOptionMenu *option_menu)
105 ESource *source = gtk_object_get_data (GTK_OBJECT (menu_item), MENU_ITEM_SOURCE_DATA_ID);
108 select_source (option_menu, source);
112 /* Functions to keep the menu in sync with the ESourceList. */
115 populate (ESourceOptionMenu *option_menu)
117 GtkWidget *menu = gtk_menu_new ();
118 GSList *groups = e_source_list_peek_groups (option_menu->priv->source_list);
120 ESource *first_source = NULL;
121 int first_source_item = -1;
122 int selected_item = -1;
126 for (p = groups; p != NULL; p = p->next) {
127 ESourceGroup *group = E_SOURCE_GROUP (p->data);
128 GtkWidget *item1 = gtk_menu_item_new_with_label (e_source_group_peek_name (group));
131 gtk_widget_set_sensitive (item1, FALSE);
132 gtk_widget_show (item1);
133 gtk_menu_append (GTK_MENU (menu), item1);
137 for (q = e_source_group_peek_sources (group); q != NULL; q = q->next) {
138 ESource *source = E_SOURCE (q->data);
139 char *label = g_strconcat (" ", e_source_peek_name (source), NULL);
140 const char *colour = e_source_peek_color_spec (source);
141 GtkWidget *item2 = gtk_image_menu_item_new_with_label (label);
149 pixmap = gdk_pixmap_new (gdk_get_default_root_window (), 16, 16, -1);
150 gdk_color_parse (colour, &c);
151 gdk_colormap_alloc_color (gdk_colormap_get_system(), &c, FALSE, TRUE);
153 gc = gdk_gc_new (gdk_get_default_root_window ());
154 gdk_gc_set_foreground (gc, &c);
155 gdk_draw_rectangle (pixmap, gc, TRUE, 0, 0, 16, 16);
158 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item2), gtk_image_new_from_pixmap (pixmap, NULL));
161 gtk_object_set_data_full (GTK_OBJECT (item2), MENU_ITEM_SOURCE_DATA_ID, source,
162 (GtkDestroyNotify) g_object_unref);
163 g_object_ref (source);
165 g_signal_connect (item2, "activate", G_CALLBACK (menu_item_activate_callback), option_menu);
167 gtk_widget_show (item2);
168 gtk_menu_append (GTK_MENU (menu), item2);
170 if (first_source_item == -1) {
171 first_source_item = i;
172 first_source = source;
175 if (source == option_menu->priv->selected_source)
182 gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
184 if (selected_item != -1) {
185 gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), selected_item);
187 if (option_menu->priv->selected_source != NULL)
188 g_object_unref (option_menu->priv->selected_source);
189 option_menu->priv->selected_source = first_source;
190 if (option_menu->priv->selected_source != NULL)
191 g_object_ref (option_menu->priv->selected_source);
193 gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), first_source_item);
199 source_list_changed_callback (ESourceList *list,
200 ESourceOptionMenu *menu)
206 connect_signals (ESourceOptionMenu *menu)
208 g_signal_connect_object (menu->priv->source_list, "changed",
209 G_CALLBACK (source_list_changed_callback), G_OBJECT (menu), 0);
213 /* GObject methods. */
216 e_source_option_menu_dispose (GObject *object)
218 ESourceOptionMenuPrivate *priv = E_SOURCE_OPTION_MENU (object)->priv;
220 if (priv->source_list != NULL) {
221 g_object_unref (priv->source_list);
222 priv->source_list = NULL;
225 if (priv->selected_source != NULL) {
226 g_object_unref (priv->selected_source);
227 priv->selected_source = NULL;
230 (* G_OBJECT_CLASS (e_source_option_menu_parent_class)->dispose) (object);
234 e_source_option_menu_finalize (GObject *object)
236 ESourceOptionMenuPrivate *priv = E_SOURCE_OPTION_MENU (object)->priv;
240 (* G_OBJECT_CLASS (e_source_option_menu_parent_class)->finalize) (object);
244 /* Initialization. */
247 e_source_option_menu_class_init (ESourceOptionMenuClass *class)
249 GObjectClass *object_class = G_OBJECT_CLASS (class);
251 object_class->dispose = e_source_option_menu_dispose;
252 object_class->finalize = e_source_option_menu_finalize;
254 signals[SOURCE_SELECTED] =
255 g_signal_new ("source_selected",
256 G_OBJECT_CLASS_TYPE (object_class),
258 G_STRUCT_OFFSET (ESourceOptionMenuClass, source_selected),
260 g_cclosure_marshal_VOID__POINTER,
266 e_source_option_menu_init (ESourceOptionMenu *source_option_menu)
268 ESourceOptionMenuPrivate *priv;
270 priv = g_new0 (ESourceOptionMenuPrivate, 1);
272 source_option_menu->priv = priv;
276 /* Public methods. */
279 * e_source_option_menu_new:
280 * @source_list: an #ESourceList to choose from
282 * Creates a new #ESourceOptionMenu widget that lets the user pick
283 * an #ESource from the provided #ESourceList.
285 * Return value: A new #ESourceOptionMenu.
288 e_source_option_menu_new (ESourceList *source_list)
290 ESourceOptionMenu *menu;
292 g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), NULL);
294 menu = g_object_new (e_source_option_menu_get_type (), NULL);
296 menu->priv->source_list = source_list;
297 g_object_ref (source_list);
299 connect_signals (menu);
302 return GTK_WIDGET (menu);
306 * e_source_option_menu_peek_selected:
307 * @menu: an #ESourceOptionMenu
309 * Return value: The selected #ESource, or %NULL if none was selected.
312 e_source_option_menu_peek_selected (ESourceOptionMenu *menu)
314 g_return_val_if_fail (E_IS_SOURCE_OPTION_MENU (menu), NULL);
316 return menu->priv->selected_source;
320 * e_source_option_menu_select:
321 * @menu: an #ESourceOptionMenu
322 * @source: an #ESource to select
324 * Programmatically selects a source in @menu. @source must be present
325 * in @menu's #ESourceList.
328 e_source_option_menu_select (ESourceOptionMenu *menu,
331 g_return_if_fail (E_IS_SOURCE_OPTION_MENU (menu));
332 g_return_if_fail (E_IS_SOURCE (source));
334 select_source (menu, source);