[evolution-patches] head, cal/contacts: hookable popup menu for e source selector




This changes:
- e-source-selector to do popup events differently, so they're more re-usable
- tasks/calendar/addressbook to use e-popup for the source-selector popup menus
- makes them use e-error for 'delete this source' boxes (higifying them).

Only issues might be that the source target contains usable info, but it should contain enough for a start.

some of the documentation comments are busted, but eh, thats the way it goes.

--
Michael Zucchi <notzed ximian com>
"born to die, live to work, it's all downhill from here"
Novell's Evolution and Free Software Developer
Index: addressbook/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/addressbook/ChangeLog,v
retrieving revision 1.1839
diff -u -p -r1.1839 ChangeLog
--- addressbook/ChangeLog	29 Sep 2004 19:48:02 -0000	1.1839
+++ addressbook/ChangeLog	1 Oct 2004 07:40:23 -0000
@@ -1,3 +1,21 @@
+2004-10-01  Not Zed  <NotZed Ximian com>
+
+	* util/eab-popup.[ch]: addressbook popup driver.
+
+	* gui/component/addressbook-view.c (delete_addressbook_cb): use
+	e-error for the message prompt.  don't bother keeping it around,
+	it can never be re-sensitised anyway.
+	(book_removed): no longer destroy the original dialogue.
+
+	* addressbook-errors.xml: add ask-delete for deleting
+	addressbooks.
+
+	* gui/component/addressbook-view.c (addressbook_view_init):
+	connect to popup_event rather than fill_popup_menu now.
+	(fill_popup_menu_callback): renamed to popup_event_callback,
+	changed to use epopup.
+	(add_popup_menu_item): remove, no longer needed.
+
 2004-09-29  Not Zed  <NotZed Ximian com>
 
 	Fixes bug #66520.
Index: addressbook/addressbook-errors.xml
===================================================================
RCS file: /cvs/gnome/evolution/addressbook/addressbook-errors.xml,v
retrieving revision 1.3
diff -u -p -r1.3 addressbook-errors.xml
--- addressbook/addressbook-errors.xml	24 Sep 2004 04:50:00 -0000	1.3
+++ addressbook/addressbook-errors.xml	1 Oct 2004 07:40:23 -0000
@@ -32,6 +32,13 @@
   <primary>Could not remove addressbook.</primary>
  </error>
 
+ <error id="ask-delete-addressbook" type="question" modal="true" default="GTK_RESPONSE_CANCEL">
+  <primary>Delete address book '{0}'?</primary>
+  <secondary>This address book will be removed permanently.</secondary>
+  <button stock="gtk-cancel" response="GTK_RESPONSE_CANCEL"/>
+  <button stock="gtk-delete" response="GTK_RESPONSE_YES"/>
+ </error>
+
  <error id="edit-categories" type="error">
   <primary>Category editor not available.</primary>
  </error>
Index: addressbook/addressbook-errors.xml.h
===================================================================
RCS file: /cvs/gnome/evolution/addressbook/addressbook-errors.xml.h,v
retrieving revision 1.3
diff -u -p -r1.3 addressbook-errors.xml.h
--- addressbook/addressbook-errors.xml.h	24 Sep 2004 04:50:00 -0000	1.3
+++ addressbook/addressbook-errors.xml.h	1 Oct 2004 07:40:23 -0000
@@ -18,6 +18,10 @@ char *s = N_("Could not get schema infor
 char *s = N_("LDAP server did not respond with valid schema information.");
 /* addressbook:remove-addressbook primary */
 char *s = N_("Could not remove addressbook.");
+/* addressbook:ask-delete-addressbook primary */
+char *s = N_("Delete address book '{0}'?");
+/* addressbook:ask-delete-addressbook secondary */
+char *s = N_("This address book will be removed permanently.");
 /* addressbook:edit-categories primary */
 char *s = N_("Category editor not available.");
 /* addressbook:generic-error primary */
Index: addressbook/gui/component/addressbook-view.c
===================================================================
RCS file: /cvs/gnome/evolution/addressbook/gui/component/addressbook-view.c,v
retrieving revision 1.19
diff -u -p -r1.19 addressbook-view.c
--- addressbook/gui/component/addressbook-view.c	30 Aug 2004 04:27:17 -0000	1.19
+++ addressbook/gui/component/addressbook-view.c	1 Oct 2004 07:40:23 -0000
@@ -60,6 +60,7 @@
 #include "addressbook/gui/merging/eab-contact-merging.h"
 #include "addressbook/printing/e-contact-print.h"
 #include "addressbook/util/eab-book-util.h"
+#include "addressbook/util/eab-popup.h"
 
 #define PARENT_TYPE G_TYPE_OBJECT
 static GObjectClass *parent_class = NULL;
@@ -614,45 +615,10 @@ load_primary_selection (AddressbookView 
 }
 
 /* Folder popup menu callbacks */
-
-static void
-add_popup_menu_item (GtkMenu *menu, const char *label, const char *pixmap,
-		     GCallback callback, gpointer user_data, gboolean sensitive)
-{
-	GtkWidget *item, *image;
-
-	if (pixmap) {
-		item = gtk_image_menu_item_new_with_label (label);
-
-		/* load the image */
-		if (g_file_test (pixmap, G_FILE_TEST_EXISTS))
-			image = gtk_image_new_from_file (pixmap);
-		else
-			image = gtk_image_new_from_stock (pixmap, GTK_ICON_SIZE_MENU);
-
-		if (image) {
-			gtk_widget_show (image);
-			gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
-		}
-	} else {
-		item = gtk_menu_item_new_with_label (label);
-	}
-
-	if (callback)
-		g_signal_connect (G_OBJECT (item), "activate", callback, user_data);
-
-	if (!sensitive)
-		gtk_widget_set_sensitive (item, FALSE);
-
-	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-	gtk_widget_show (item);
-}
-
 typedef struct {
 	AddressbookView *view;
 	ESource *selected_source;
 	GtkWidget *toplevel;
-	GtkWidget *dialog;
 } BookRemovedClosure;
 
 static void
@@ -662,7 +628,6 @@ book_removed (EBook *book, EBookStatus s
 	AddressbookView *view = closure->view;
 	AddressbookViewPrivate *priv = view->priv;
 	ESource *source = closure->selected_source;
-	GtkWidget *dialog = closure->dialog;
 	GtkWidget *toplevel = closure->toplevel;
 
 	g_free (closure);
@@ -685,73 +650,54 @@ book_removed (EBook *book, EBookStatus s
 			     "addressbook:remove-addressbook",
 			     NULL);
 	}
-
-	gtk_widget_destroy (dialog);
 }
 
 static void
-delete_addressbook_cb (GtkWidget *widget, AddressbookView *view)
+delete_addressbook_cb(EPopup *ep, EPopupItem *pitem, void *data)
 {
+	AddressbookView *view = data;
 	AddressbookViewPrivate *priv = view->priv;
 	ESource *selected_source;
-	GtkWidget *dialog;
 	EBook  *book;
 	GError *error = NULL;
+	GtkWindow *toplevel;
 
 	selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (priv->selector));
 	if (!selected_source)
 		return;
 
-	/* Create the confirmation dialog */
-	dialog = gtk_message_dialog_new (
-		GTK_WINDOW (gtk_widget_get_toplevel (widget)),
-		GTK_DIALOG_MODAL,
-		GTK_MESSAGE_QUESTION,
-		GTK_BUTTONS_YES_NO,
-		_("Address book '%s' will be removed. Are you sure you want to continue?"),
-		e_source_peek_name (selected_source));
-#if !GTK_CHECK_VERSION (2,4,0)
-	gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
-#endif
+	toplevel = (GtkWindow *)gtk_widget_get_toplevel(ep->target->widget);
 
-	if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_YES) {
-		gtk_widget_destroy (dialog);
+	if (e_error_run(toplevel, "addressbook:ask-delete-addressbook", e_source_peek_name(selected_source)) != GTK_RESPONSE_YES)
 		return;
-	}
 
 	/* Remove local data */
 	book = e_book_new (selected_source, &error);
 	if (book) {
 		BookRemovedClosure *closure = g_new (BookRemovedClosure, 1);
 
-		closure->toplevel = gtk_widget_get_toplevel (widget);
+		closure->toplevel = (GtkWidget *)toplevel;
 		closure->view = view;
 		closure->selected_source = selected_source;
-		closure->dialog = dialog;
 
 		if (e_book_async_remove (book, book_removed, closure)) {
-			e_error_run (GTK_WINDOW (gtk_widget_get_toplevel (widget)),
-				     "addressbook:remove-addressbook",
-				     NULL);
-
+			e_error_run (toplevel, "addressbook:remove-addressbook", NULL);
 			g_free (closure);
-
 			g_object_unref (book);
 		}
 	}
-
-	gtk_widget_set_sensitive (dialog, FALSE);
 }
 
 static void
-new_addressbook_cb (GtkWidget *widget, AddressbookView *view)
+new_addressbook_cb(EPopup *ep, EPopupItem *pitem, void *data)
 {
-	addressbook_config_create_new_source (gtk_widget_get_toplevel (widget));
+	addressbook_config_create_new_source (gtk_widget_get_toplevel(ep->target->widget));
 }
 
 static void
-edit_addressbook_cb (GtkWidget *widget, AddressbookView *view)
+edit_addressbook_cb(EPopup *ep, EPopupItem *pitem, void *data)
 {
+	AddressbookView *view = data;
 	AddressbookViewPrivate *priv = view->priv;
 	ESource *selected_source;
 	const char *uid;
@@ -769,7 +715,7 @@ edit_addressbook_cb (GtkWidget *widget, 
 		char *uid_copy = g_strdup (uid);
 
 		closure = g_new (EditorUidClosure, 1);
-		closure->editor = addressbook_config_edit_source (gtk_widget_get_toplevel (widget), selected_source);
+		closure->editor = addressbook_config_edit_source (gtk_widget_get_toplevel(ep->target->widget), selected_source);
 		closure->uid = uid_copy;
 		closure->view = view;
 
@@ -794,25 +740,41 @@ primary_source_selection_changed_callbac
 	save_primary_selection (view);
 }
 
+static EPopupItem abv_source_popups[] = {
+	{ E_POPUP_ITEM, "10.new", N_("New Address Book"), new_addressbook_cb, NULL, NULL, 0 },
+	{ E_POPUP_ITEM, "20.delete", N_("Delete"), delete_addressbook_cb, NULL, "stock_delete", EAB_POPUP_SOURCE_USER|EAB_POPUP_SOURCE_PRIMARY },
+	{ E_POPUP_ITEM, "30.properties", N_("Properties..."), edit_addressbook_cb, NULL, NULL, EAB_POPUP_SOURCE_PRIMARY },
+};
 
 static void
-fill_popup_menu_callback (ESourceSelector *selector, GtkMenu *menu, AddressbookView *view)
+abv_source_popup_free(EPopup *ep, GSList *list, void *data)
 {
-	AddressbookViewPrivate *priv = view->priv;
-	gboolean sensitive;
-	gboolean local_addressbook;
-	ESource *selected_source;
-	char *uri;
+	g_slist_free(list);
+}
 
-	selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (priv->selector));
-	sensitive = selected_source ? TRUE : FALSE;
+static gboolean
+popup_event_callback(ESourceSelector *selector, ESource *source, GdkEventButton *event, AddressbookView *view)
+{
+	EABPopup *ep;
+	EABPopupTargetSource *t;
+	GSList *menus = NULL;
+	int i;
+	GtkMenu *menu;
+
+	ep = eab_popup_new("com.novell.evolution.addressbook.source.popup");
+	t = eab_popup_target_new_source(ep, selector);
+	t->target.widget = (GtkWidget *)view->priv->notebook;
+
+	for (i=0;i<sizeof(abv_source_popups)/sizeof(abv_source_popups[0]);i++)
+		menus = g_slist_prepend(menus, &abv_source_popups[i]);
+
+	e_popup_add_items((EPopup *)ep, menus, abv_source_popup_free, view);
+
+	/* visibility is disabled, we only disable menu items */
+	menu = e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0, t->target.mask);
+	gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event?event->button:0, event?event->time:gtk_get_current_event_time());
 
-	uri = e_source_peek_relative_uri (selected_source);
-	local_addressbook = (uri && !strcmp ("system", uri));
-		
-	add_popup_menu_item (menu, _("New Address Book"), NULL, G_CALLBACK (new_addressbook_cb), view, TRUE);
-	add_popup_menu_item (menu, _("Delete"), GTK_STOCK_DELETE, G_CALLBACK (delete_addressbook_cb), view, sensitive && !local_addressbook);
-	add_popup_menu_item (menu, _("Properties..."), NULL, G_CALLBACK (edit_addressbook_cb), view, sensitive);
+	return TRUE;
 }
 
 static gboolean
@@ -978,15 +940,13 @@ selector_tree_drag_data_received (GtkWid
 {
 	GtkTreePath *path = NULL;
 	GtkTreeViewDropPosition pos;
-	gpointer source, target = NULL;
+	gpointer target = NULL;
 	GtkTreeModel *model;
 	GtkTreeIter iter;
 	gboolean success = FALSE;
-
 	EBook *source_book, *target_book;
 	MergeContext *merge_context;
 	GList *contactlist;
-	GList *l;
 
 	if (!gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
 						x, y, &path, &pos))
@@ -1170,8 +1130,8 @@ addressbook_view_init (AddressbookView *
 	g_signal_connect_object (priv->selector, "primary_selection_changed",
 				 G_CALLBACK (primary_source_selection_changed_callback),
 				 G_OBJECT (view), 0);
-	g_signal_connect_object (priv->selector, "fill_popup_menu",
-				 G_CALLBACK (fill_popup_menu_callback),
+	g_signal_connect_object (priv->selector, "popup_event",
+				 G_CALLBACK (popup_event_callback),
 				 G_OBJECT (view), 0);
 
 	load_primary_selection (view);
Index: addressbook/util/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution/addressbook/util/Makefile.am,v
retrieving revision 1.7
diff -u -p -r1.7 Makefile.am
--- addressbook/util/Makefile.am	9 Apr 2004 17:25:49 -0000	1.7
+++ addressbook/util/Makefile.am	1 Oct 2004 07:40:23 -0000
@@ -17,7 +17,9 @@ libeabutil_la_SOURCES =					\
 	e-destination.c					\
 	e-destination.h					\
 	eab-book-util.c					\
-	eab-book-util.h
+	eab-book-util.h					\
+	eab-popup.c					\
+	eab-popup.h
 
 libeabutil_la_LIBADD =					\
 	$(top_builddir)/camel/libcamel.la		\
Index: addressbook/util/eab-popup.c
===================================================================
RCS file: addressbook/util/eab-popup.c
diff -N addressbook/util/eab-popup.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ addressbook/util/eab-popup.c	1 Oct 2004 07:40:24 -0000
@@ -0,0 +1,241 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ *  Authors: Michael Zucchi <notzed ximian com>
+ *
+ *  Copyright 2004 Novell, Inc. (www.novell.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib.h>
+
+#include "eab-popup.h"
+#include "widgets/misc/e-source-selector.h"
+
+static GObjectClass *eabp_parent;
+
+static void
+eabp_init(GObject *o)
+{
+	/*EABPopup *eabp = (EABPopup *)o; */
+}
+
+static void
+eabp_finalise(GObject *o)
+{
+	((GObjectClass *)eabp_parent)->finalize(o);
+}
+
+static void
+eabp_target_free(EPopup *ep, EPopupTarget *t)
+{
+	switch (t->type) {
+	case EAB_POPUP_TARGET_SELECT: {
+		EABPopupTargetSelect *s = (EABPopupTargetSelect *)t;
+
+		/* FIXME: implement */
+		s = s;
+		break; }
+	case EAB_POPUP_TARGET_SOURCE: {
+		EABPopupTargetSource *s = (EABPopupTargetSource *)t;
+
+		g_object_unref(s->selector);
+		break; }
+	}
+
+	((EPopupClass *)eabp_parent)->target_free(ep, t);
+}
+
+static void
+eabp_class_init(GObjectClass *klass)
+{
+	klass->finalize = eabp_finalise;
+	((EPopupClass *)klass)->target_free = eabp_target_free;
+}
+
+GType
+eab_popup_get_type(void)
+{
+	static GType type = 0;
+
+	if (type == 0) {
+		static const GTypeInfo info = {
+			sizeof(EABPopupClass),
+			NULL, NULL,
+			(GClassInitFunc)eabp_class_init,
+			NULL, NULL,
+			sizeof(EABPopup), 0,
+			(GInstanceInitFunc)eabp_init
+		};
+		eabp_parent = g_type_class_ref(e_popup_get_type());
+		type = g_type_register_static(e_popup_get_type(), "EABPopup", &info, 0);
+	}
+
+	return type;
+}
+
+EABPopup *eab_popup_new(const char *menuid)
+{
+	EABPopup *eabp = g_object_new(eab_popup_get_type(), 0);
+
+	e_popup_construct(&eabp->popup, menuid);
+
+	return eabp;
+}
+
+/**
+ * eab_popup_target_new_select:
+ * 
+ * Create a new selection popup target.
+ * 
+ * Return value: 
+ **/
+EABPopupTargetSelect *
+eab_popup_target_new_select(EABPopup *eabp)
+{
+	EABPopupTargetSelect *t = e_popup_target_new(&eabp->popup, EAB_POPUP_TARGET_SELECT, sizeof(*t));
+	guint32 mask = ~0;
+
+	/* FIXME: impelement */
+
+	t->target.mask = mask;
+
+	return t;
+}
+
+EABPopupTargetSource *
+eab_popup_target_new_source(EABPopup *eabp, ESourceSelector *selector)
+{
+	EABPopupTargetSource *t = e_popup_target_new(&eabp->popup, EAB_POPUP_TARGET_SOURCE, sizeof(*t));
+	guint32 mask = ~0;
+	const char *source_uri;
+	ESource *source;
+
+	/* TODO: this is duplicated for calendar and tasks too */
+
+	t->selector = selector;
+	g_object_ref(selector);
+
+	/* TODO: perhaps we need to copy this so it doesn't change during the lifecycle */
+	source = e_source_selector_peek_primary_selection(selector);
+	if (source)
+		mask &= ~EAB_POPUP_SOURCE_PRIMARY;
+
+	/* FIXME Gross hack, should have a property or something */
+	source_uri = e_source_peek_relative_uri(source);
+	if (source_uri && !strcmp("system", source_uri))
+		mask &= ~EAB_POPUP_SOURCE_SYSTEM;
+	else
+		mask &= ~EAB_POPUP_SOURCE_USER;
+
+	t->target.mask = mask;
+
+	return t;
+}
+
+/* ********************************************************************** */
+/* Popup menu plugin handler */
+
+/*
+<e-plugin
+  class="com.ximian.mail.plugin.popup:1.0"
+  id="com.ximian.mail.plugin.popup.iteab:1.0"
+  type="shlib"
+  location="/opt/gnome2/lib/camel/1.0/libcamelimap.so"
+  name="imap"
+  description="IMAP4 and IMAP4v1 mail store">
+  <hook class="com.ximian.mail.popupMenu:1.0"
+        handler="HandlePopup">
+  <menu id="any" target="select">
+   <iteab
+    type="iteab|toggle|radio|image|submenu|bar"
+    active
+    path="foo/bar"
+    label="label"
+    icon="foo"
+    mask="select_one"
+    activate="eabp_view_eabacs"/>
+  </menu>
+  </extension>
+
+*/
+
+static void *eabph_parent_class;
+#define eabph ((EABPopupHook *)eph)
+
+static const EPopupHookTargetMask eabph_select_masks[] = {
+	{ "one", EAB_POPUP_SELECT_ONE },
+	{ "many", EAB_POPUP_SELECT_MANY },
+	{ 0 }
+};
+
+static const EPopupHookTargetMask eabph_source_masks[] = {
+	{ "primary", EAB_POPUP_SOURCE_PRIMARY },
+	{ "system", EAB_POPUP_SOURCE_SYSTEM },
+	{ 0 }
+};
+
+static const EPopupHookTargetMap eabph_targets[] = {
+	{ "select", EAB_POPUP_TARGET_SELECT, eabph_select_masks },
+	{ "source", EAB_POPUP_TARGET_SOURCE, eabph_source_masks },
+	{ 0 }
+};
+
+static void
+eabph_finalise(GObject *o)
+{
+	/*EPluginHook *eph = (EPluginHook *)o;*/
+
+	((GObjectClass *)eabph_parent_class)->finalize(o);
+}
+
+static void
+eabph_class_init(EPluginHookClass *klass)
+{
+	int i;
+
+	((GObjectClass *)klass)->finalize = eabph_finalise;
+	((EPluginHookClass *)klass)->id = "com.ximian.evolution.addressbook.popup:1.0";
+
+	for (i=0;eabph_targets[i].type;i++)
+		e_popup_hook_class_add_target_map((EPopupHookClass *)klass, &eabph_targets[i]);
+
+	((EPopupHookClass *)klass)->popup_class = g_type_class_ref(eab_popup_get_type());
+}
+
+GType
+eab_popup_hook_get_type(void)
+{
+	static GType type = 0;
+	
+	if (!type) {
+		static const GTypeInfo info = {
+			sizeof(EABPopupHookClass), NULL, NULL, (GClassInitFunc) eabph_class_init, NULL, NULL,
+			sizeof(EABPopupHook), 0, (GInstanceInitFunc) NULL,
+		};
+
+		eabph_parent_class = g_type_class_ref(e_popup_hook_get_type());
+		type = g_type_register_static(e_popup_hook_get_type(), "EABPopupHook", &info, 0);
+	}
+	
+	return type;
+}
Index: addressbook/util/eab-popup.h
===================================================================
RCS file: addressbook/util/eab-popup.h
diff -N addressbook/util/eab-popup.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ addressbook/util/eab-popup.h	1 Oct 2004 07:40:24 -0000
@@ -0,0 +1,146 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ *  Authors: Michael Zucchi <notzed ximian com>
+ *
+ *  Copyright 2004 Novell, Inc. (www.novell.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __EAB_POPUP_H__
+#define __EAB_POPUP_H__
+
+#include <glib-object.h>
+
+#include "e-util/e-popup.h"
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+typedef struct _EABPopup EABPopup;
+typedef struct _EABPopupClass EABPopupClass;
+
+/**
+ * enum _eab_popup_target_t - A list of mail popup target types.
+ * 
+ * @EAB_POPUP_TARGET_SELECT: A selection of cards
+ * @EAB_POPUP_TARGET_SOURCE: A source selection.
+ *
+ * Defines the value of the targetid for all EABPopup target types.
+ **/
+enum _eab_popup_target_t {
+	EAB_POPUP_TARGET_SELECT,
+	EAB_POPUP_TARGET_SOURCE,
+};
+
+/**
+ * enum _eab_popup_target_select_t - EABPopupTargetSelect qualifiers.
+ * 
+ * @EAB_POPUP_SELECT_ONE: Only one item is selected.
+ * @EAB_POPUP_SELECT_MANY: One ore more items are selected.
+ * 
+ **/
+enum _eab_popup_target_select_t {
+	EAB_POPUP_SELECT_ONE                = 1<<1,
+	EAB_POPUP_SELECT_MANY               = 1<<2,
+};
+
+/**
+ * enum _eab_popup_target_source_t - EABPopupTargetSource qualifiers.
+ * 
+ * @EAB_POPUP_SOURCE_PRIMARY: Has a primary selection.
+ * @EAB_POPUP_SOURCE_SYSTEM: Is a 'system' folder.
+ * 
+ **/
+enum _eab_popup_target_source_t {
+	EAB_POPUP_SOURCE_PRIMARY = 1<<0,
+	EAB_POPUP_SOURCE_SYSTEM = 1<<1,	/* system folder */
+	EAB_POPUP_SOURCE_USER = 1<<2, /* user folder (!system) */
+};
+
+typedef struct _EABPopupTargetSelect EABPopupTargetSelect;
+typedef struct _EABPopupTargetSource EABPopupTargetSource;
+
+/**
+ * struct _EABPopupTargetSelect - A list of address cards.
+ * 
+ * @target: Superclass.
+ *
+ * Used to represent a selection of cards as context for a popup
+ * menu.  All items may be NULL if the current view has no active
+ * folder selected.
+ *
+ * FIXME: impelemnt me
+ **/
+struct _EABPopupTargetSelect {
+	EPopupTarget target;
+};
+
+/**
+ * struct _EABPopupTargetSource - A source target.
+ * 
+ * @target: Superclass.
+ * @selector: Selector holding the source selection.
+ *
+ * This target is used to represent a source selection.
+ **/
+struct _EABPopupTargetSource {
+	EPopupTarget target;
+
+	struct _ESourceSelector *selector;
+};
+
+typedef struct _EPopupItem EABPopupItem;
+
+/* The object */
+struct _EABPopup {
+	EPopup popup;
+
+	struct _EABPopupPrivate *priv;
+};
+
+struct _EABPopupClass {
+	EPopupClass popup_class;
+};
+
+GType eab_popup_get_type(void);
+
+EABPopup *eab_popup_new(const char *menuid);
+
+EABPopupTargetSelect *eab_popup_target_new_select(EABPopup *eabp);
+EABPopupTargetSource *eab_popup_target_new_source(EABPopup *eabp, struct _ESourceSelector *selector);
+
+/* ********************************************************************** */
+
+typedef struct _EABPopupHook EABPopupHook;
+typedef struct _EABPopupHookClass EABPopupHookClass;
+
+struct _EABPopupHook {
+	EPopupHook hook;
+};
+
+struct _EABPopupHookClass {
+	EPopupHookClass hook_class;
+};
+
+GType eab_popup_hook_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __EAB_POPUP_H__ */
Index: calendar/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/calendar/ChangeLog,v
retrieving revision 1.2521
diff -u -p -r1.2521 ChangeLog
--- calendar/ChangeLog	29 Sep 2004 16:45:51 -0000	1.2521
+++ calendar/ChangeLog	1 Oct 2004 07:40:26 -0000
@@ -1,3 +1,36 @@
+2004-10-01  Not Zed  <NotZed Ximian com>
+
+	* gui/tasks-component.c (create_component_view): cast warning
+	away.
+	(create_component_view): connect to popup_event rather than
+	fill_popup_menu.
+
+	* gui/calendar-component.c (create_component_view): cast a warning
+	away.
+
+	* calendar-errors.xml: add prompt-delete-task-list.
+
+	* gui/tasks-component.c (fill_popup_menu_cb): renamed to
+	popup_event_cb, make use e-cal-popup.
+	(edit_task_list_cb, new_task_list_cb, delete_task_list_cb) 
+	(copy_task_list_cb): deja-vu.  update for api.
+	(add_popup_menu_item): killed. murdered. drawn and quatered.
+	(delete_task_list_cb): use e-error for the delete prompt.
+
+	* gui/calendar-component.c (create_component_view): hook onto
+	popup event instead of fill_popup_menu.
+
+	* calendar-errors.xml: added prompt-delete-calendar.
+
+	* gui/calendar-component.c (fill_popup_menu_cb): rename to
+	popup_event_cb, make use e-cal-popup.
+	(edit_calendar_cb, new_calendar_cb, delete_calendar_cb) 
+	(copy_calendar_cb): fix for api changes.
+	(add_popup_menu_item): removed.
+	(delete_calendar_cb): use e-error for the delete thing.
+
+	* gui/e-cal-popup.[ch]: calendar popup driver.
+
 2004-09-29  Rodrigo Moya <rodrigo novell com>
 
 	Fixes #64683
Index: calendar/calendar-errors.xml
===================================================================
RCS file: /cvs/gnome/evolution/calendar/calendar-errors.xml,v
retrieving revision 1.2
diff -u -p -r1.2 calendar-errors.xml
--- calendar/calendar-errors.xml	6 Aug 2004 10:05:23 -0000	1.2
+++ calendar/calendar-errors.xml	1 Oct 2004 07:40:26 -0000
@@ -163,4 +163,18 @@
   <secondary>Your calendars will not be available until Evolution is restarted.</secondary>
  </error>
 
+ <error id="prompt-delete-calendar" type="question" modal="true" default="GTK_RESPONSE_CANCEL">
+  <primary>Delete calendar '{0}'?</primary>
+  <secondary>This calendar will be removed permanently.</secondary>
+  <button stock="gtk-cancel" response="GTK_RESPONSE_CANCEL"/>
+  <button stock="gtk-delete" response="GTK_RESPONSE_YES"/>
+ </error>
+
+ <error id="prompt-delete-task-list" type="question" modal="true" default="GTK_RESPONSE_CANCEL">
+  <primary>Delete task list '{0}'?</primary>
+  <secondary>This task list will be removed permanently.</secondary>
+  <button stock="gtk-cancel" response="GTK_RESPONSE_CANCEL"/>
+  <button stock="gtk-delete" response="GTK_RESPONSE_YES"/>
+ </error>
+
 </error-list>
Index: calendar/calendar-errors.xml.h
===================================================================
RCS file: /cvs/gnome/evolution/calendar/calendar-errors.xml.h,v
retrieving revision 1.3
diff -u -p -r1.3 calendar-errors.xml.h
--- calendar/calendar-errors.xml.h	13 Aug 2004 20:05:55 -0000	1.3
+++ calendar/calendar-errors.xml.h	1 Oct 2004 07:40:26 -0000
@@ -112,3 +112,11 @@ char *s = N_("Your tasks will not be ava
 char *s = N_("The Evolution calendar has quit unexpectedly.");
 /* calendar:calendar-crashed secondary */
 char *s = N_("Your calendars will not be available until Evolution is restarted.");
+/* calendar:prompt-delete-calendar primary */
+char *s = N_("Delete calendar '{0}'?");
+/* calendar:prompt-delete-calendar secondary */
+char *s = N_("This calendar will be removed permanently.");
+/* calendar:prompt-delete-task-list primary */
+char *s = N_("Delete task list '{0}'?");
+/* calendar:prompt-delete-task-list secondary */
+char *s = N_("This task list will be removed permanently.");
Index: calendar/gui/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/Makefile.am,v
retrieving revision 1.297
diff -u -p -r1.297 Makefile.am
--- calendar/gui/Makefile.am	9 Jul 2004 11:18:53 -0000	1.297
+++ calendar/gui/Makefile.am	1 Oct 2004 07:40:26 -0000
@@ -122,6 +122,8 @@ libevolution_calendar_la_SOURCES =		\
 	e-cal-model-tasks.h			\
 	e-cal-model.c				\
 	e-cal-model.h				\
+	e-cal-popup.h				\
+	e-cal-popup.c				\
 	e-calendar-view.c			\
 	e-calendar-view.h			\
 	e-cal-list-view.c			\
Index: calendar/gui/calendar-component.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/calendar-component.c,v
retrieving revision 1.183
diff -u -p -r1.183 calendar-component.c
--- calendar/gui/calendar-component.c	23 Sep 2004 13:10:56 -0000	1.183
+++ calendar/gui/calendar-component.c	1 Oct 2004 07:40:26 -0000
@@ -51,7 +51,9 @@
 #include "dialogs/event-editor.h"
 #include "widgets/misc/e-source-selector.h"
 #include "widgets/misc/e-info-label.h"
+#include "widgets/misc/e-error.h"
 #include "e-util/e-icon-factory.h"
+#include "e-cal-popup.h"
 
 /* IDs for user creatable items */
 #define CREATE_EVENT_ID        "event"
@@ -308,133 +310,110 @@ update_primary_task_selection (CalendarC
 
 /* Callbacks.  */
 static void
-add_popup_menu_item (GtkMenu *menu, const char *label, const char *icon_name,
-		     GCallback callback, gpointer user_data, gboolean sensitive)
-{
-	GtkWidget *item, *image;
-	GdkPixbuf *pixbuf;
-
-	if (icon_name) {
-		item = gtk_image_menu_item_new_with_label (label);
-
-		/* load the image */
-		pixbuf = e_icon_factory_get_icon (icon_name, E_ICON_SIZE_MENU);
-		image = gtk_image_new_from_pixbuf (pixbuf);
-
-		if (image) {
-			gtk_widget_show (image);
-			gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
-		}
-	} else {
-		item = gtk_menu_item_new_with_label (label);
-	}
-
-	if (callback)
-		g_signal_connect (G_OBJECT (item), "activate", callback, user_data);
-
-	if (!sensitive)
-		gtk_widget_set_sensitive (item, FALSE);
-
-	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-	gtk_widget_show (item);
-}
-
-static void
-copy_calendar_cb (GtkWidget *widget, CalendarComponentView *component_view)
+copy_calendar_cb (EPopup *ep, EPopupItem *pitem, void *data)
 {
+	CalendarComponentView *component_view = data;
 	ESource *selected_source;
 	
 	selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
 	if (!selected_source)
 		return;
 
-	copy_source_dialog (GTK_WINDOW (gtk_widget_get_toplevel (widget)), selected_source, E_CAL_SOURCE_TYPE_EVENT);
+	copy_source_dialog (GTK_WINDOW (gtk_widget_get_toplevel (ep->target->widget)), selected_source, E_CAL_SOURCE_TYPE_EVENT);
 }
 
 static void
-delete_calendar_cb (GtkWidget *widget, CalendarComponentView *component_view)
+delete_calendar_cb (EPopup *ep, EPopupItem *pitem, void *data)
 {
+	CalendarComponentView *component_view = data;
 	ESource *selected_source;
-	GtkWidget *dialog;
+	ECal *cal;
+	char *uri;
 
 	selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
 	if (!selected_source)
 		return;
 
-	/* create the confirmation dialog */
-	dialog = gtk_message_dialog_new (
-		GTK_WINDOW (gtk_widget_get_toplevel (widget)),
-		GTK_DIALOG_MODAL,
-		GTK_MESSAGE_QUESTION,
-		GTK_BUTTONS_YES_NO,
-		_("Calendar '%s' will be removed. Are you sure you want to continue?"),
-		e_source_peek_name (selected_source));
-	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES) {
-		ECal *cal;
-		char *uri;
-
-		/* first, ask the backend to remove the calendar */
-		uri = e_source_get_uri (selected_source);
-		cal = e_cal_model_get_client_for_uri (gnome_calendar_get_calendar_model (component_view->calendar), uri);
-		if (!cal)
-			cal = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_EVENT);
-		g_free (uri);
-		if (cal) {
-			if (e_cal_remove (cal, NULL)) {
-				if (e_source_selector_source_is_selected (E_SOURCE_SELECTOR (component_view->source_selector),
-									  selected_source)) {
-					gnome_calendar_remove_source (component_view->calendar, E_CAL_SOURCE_TYPE_EVENT, selected_source);
-					e_source_selector_unselect_source (E_SOURCE_SELECTOR (component_view->source_selector),
-									   selected_source);
-				}
-		
-				e_source_group_remove_source (e_source_peek_group (selected_source), selected_source);
-				e_source_list_sync (component_view->source_list, NULL);
+	if (e_error_run((GtkWindow *)gtk_widget_get_toplevel(ep->target->widget),
+			"calendar:prompt-delete-calendar", e_source_peek_name(selected_source)) != GTK_RESPONSE_YES)
+		return;
+
+	/* first, ask the backend to remove the calendar */
+	uri = e_source_get_uri (selected_source);
+	cal = e_cal_model_get_client_for_uri (gnome_calendar_get_calendar_model (component_view->calendar), uri);
+	if (!cal)
+		cal = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_EVENT);
+	g_free (uri);
+	if (cal) {
+		if (e_cal_remove (cal, NULL)) {
+			if (e_source_selector_source_is_selected (E_SOURCE_SELECTOR (component_view->source_selector),
+								  selected_source)) {
+				gnome_calendar_remove_source (component_view->calendar, E_CAL_SOURCE_TYPE_EVENT, selected_source);
+				e_source_selector_unselect_source (E_SOURCE_SELECTOR (component_view->source_selector),
+								   selected_source);
 			}
+			
+			e_source_group_remove_source (e_source_peek_group (selected_source), selected_source);
+			e_source_list_sync (component_view->source_list, NULL);
 		}
 	}
-
-	gtk_widget_destroy (dialog);
 }
 
 static void
-new_calendar_cb (GtkWidget *widget, CalendarComponentView *component_view)
+new_calendar_cb (EPopup *ep, EPopupItem *pitem, void *data)
 {
-	calendar_setup_new_calendar (GTK_WINDOW (gtk_widget_get_toplevel (widget)));
+	calendar_setup_new_calendar (GTK_WINDOW (gtk_widget_get_toplevel(ep->target->widget)));
 }
 
 static void
-edit_calendar_cb (GtkWidget *widget, CalendarComponentView *component_view)
+edit_calendar_cb (EPopup *ep, EPopupItem *pitem, void *data)
 {
+	CalendarComponentView *component_view = data;
 	ESource *selected_source;
 
 	selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
 	if (!selected_source)
 		return;
 
-	calendar_setup_edit_calendar (GTK_WINDOW (gtk_widget_get_toplevel (widget)), selected_source);
+	calendar_setup_edit_calendar (GTK_WINDOW (gtk_widget_get_toplevel(ep->target->widget)), selected_source);
 }
 
+static EPopupItem ecc_source_popups[] = {
+	{ E_POPUP_ITEM, "10.new", N_("New Calendar"), new_calendar_cb, NULL, "stock_calendar", 0 },
+	{ E_POPUP_ITEM, "15.copy", N_("Copy"), copy_calendar_cb, NULL, "stock_folder-copy", E_CAL_POPUP_SOURCE_PRIMARY },
+	{ E_POPUP_ITEM, "20.delete", N_("Delete"), delete_calendar_cb, NULL, "stock_delete", E_CAL_POPUP_SOURCE_USER|E_CAL_POPUP_SOURCE_PRIMARY },
+	{ E_POPUP_ITEM, "30.properties", N_("Properties..."), edit_calendar_cb, NULL, NULL, E_CAL_POPUP_SOURCE_PRIMARY },
+};
+
 static void
-fill_popup_menu_cb (ESourceSelector *selector, GtkMenu *menu, CalendarComponentView *component_view)
+ecc_source_popup_free(EPopup *ep, GSList *list, void *data)
 {
-	ESource *source;
-	gboolean sensitive, system;
-	const char *source_uri;
-	
-	source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
-	sensitive =  source ? TRUE : FALSE;
+	g_slist_free(list);
+}
 
-	/* FIXME Gross hack, should have a property or something */
-	source_uri = e_source_peek_relative_uri (source);
-	system = source_uri && !strcmp ("system", source_uri);
-	
-	add_popup_menu_item (menu, _("New Calendar"), "stock_calendar",
-			     G_CALLBACK (new_calendar_cb), component_view, TRUE);
-	add_popup_menu_item (menu, _("Copy"), "stock_folder-copy",
-			     G_CALLBACK (copy_calendar_cb), component_view, sensitive);
-	add_popup_menu_item (menu, _("Delete"), "stock_delete", G_CALLBACK (delete_calendar_cb), component_view, sensitive && !system); 
-	add_popup_menu_item (menu, _("Properties..."), NULL, G_CALLBACK (edit_calendar_cb), component_view, sensitive);
+static gboolean
+popup_event_cb(ESourceSelector *selector, ESource *insource, GdkEventButton *event, CalendarComponentView *component_view)
+{
+	ECalPopup *ep;
+	ECalPopupTargetSource *t;
+	GSList *menus = NULL;
+	int i;
+	GtkMenu *menu;
+
+	ep = e_cal_popup_new("com.novell.evolution.calendar.source.popup");
+	t = e_cal_popup_target_new_source(ep, selector);
+	t->target.widget = (GtkWidget *)component_view->calendar;
+
+	for (i=0;i<sizeof(ecc_source_popups)/sizeof(ecc_source_popups[0]);i++)
+		menus = g_slist_prepend(menus, &ecc_source_popups[i]);
+
+	e_popup_add_items((EPopup *)ep, menus, ecc_source_popup_free, component_view);
+
+	/* visibility is disabled, we only disable menu items */
+	menu = e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0, t->target.mask);
+	gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event?event->button:0, event?event->time:gtk_get_current_event_time());
+
+	return TRUE;
 }
 
 static void
@@ -1057,7 +1036,7 @@ create_component_view (CalendarComponent
 	
 	/* Create sidebar selector */
 	component_view->source_selector = e_source_selector_new (calendar_component->priv->source_list);
-	e_source_selector_set_select_new (component_view->source_selector, TRUE);
+	e_source_selector_set_select_new ((ESourceSelector *)component_view->source_selector, TRUE);
 
 	g_signal_connect (component_view->source_selector, "drag-motion", G_CALLBACK (selector_tree_drag_motion), 
 			  calendar_component);
@@ -1124,8 +1103,8 @@ create_component_view (CalendarComponent
 			  G_CALLBACK (source_selection_changed_cb), component_view);
 	g_signal_connect (component_view->source_selector, "primary_selection_changed",
 			  G_CALLBACK (primary_source_selection_changed_cb), component_view);
-	g_signal_connect (component_view->source_selector, "fill_popup_menu",
-			  G_CALLBACK (fill_popup_menu_cb), component_view);
+	g_signal_connect (component_view->source_selector, "popup_event",
+			  G_CALLBACK (popup_event_cb), component_view);
 
 	/* Set up the "new" item handler */
 	component_view->creatable_items_handler = e_user_creatable_items_handler_new ("calendar", create_local_item_cb, calendar_component);
Index: calendar/gui/e-cal-popup.c
===================================================================
RCS file: calendar/gui/e-cal-popup.c
diff -N calendar/gui/e-cal-popup.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/e-cal-popup.c	1 Oct 2004 07:40:27 -0000
@@ -0,0 +1,241 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ *  Authors: Michael Zucchi <notzed ximian com>
+ *
+ *  Copyright 2004 Novell, Inc. (www.novell.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib.h>
+
+#include "e-cal-popup.h"
+#include "widgets/misc/e-source-selector.h"
+
+static GObjectClass *ecalp_parent;
+
+static void
+ecalp_init(GObject *o)
+{
+	/*ECalPopup *eabp = (ECalPopup *)o; */
+}
+
+static void
+ecalp_finalise(GObject *o)
+{
+	((GObjectClass *)ecalp_parent)->finalize(o);
+}
+
+static void
+ecalp_target_free(EPopup *ep, EPopupTarget *t)
+{
+	switch (t->type) {
+	case E_CAL_POPUP_TARGET_SELECT: {
+		ECalPopupTargetSelect *s = (ECalPopupTargetSelect *)t;
+
+		/* FIXME: implement */
+		s = s;
+		break; }
+	case E_CAL_POPUP_TARGET_SOURCE: {
+		ECalPopupTargetSource *s = (ECalPopupTargetSource *)t;
+
+		g_object_unref(s->selector);
+		break; }
+	}
+
+	((EPopupClass *)ecalp_parent)->target_free(ep, t);
+}
+
+static void
+ecalp_class_init(GObjectClass *klass)
+{
+	klass->finalize = ecalp_finalise;
+	((EPopupClass *)klass)->target_free = ecalp_target_free;
+}
+
+GType
+e_cal_popup_get_type(void)
+{
+	static GType type = 0;
+
+	if (type == 0) {
+		static const GTypeInfo info = {
+			sizeof(ECalPopupClass),
+			NULL, NULL,
+			(GClassInitFunc)ecalp_class_init,
+			NULL, NULL,
+			sizeof(ECalPopup), 0,
+			(GInstanceInitFunc)ecalp_init
+		};
+		ecalp_parent = g_type_class_ref(e_popup_get_type());
+		type = g_type_register_static(e_popup_get_type(), "ECalPopup", &info, 0);
+	}
+
+	return type;
+}
+
+ECalPopup *e_cal_popup_new(const char *menuid)
+{
+	ECalPopup *eabp = g_object_new(e_cal_popup_get_type(), 0);
+
+	e_popup_construct(&eabp->popup, menuid);
+
+	return eabp;
+}
+
+/**
+ * e_cal_popup_target_new_select:
+ * 
+ * Create a new selection popup target.
+ * 
+ * Return value: 
+ **/
+ECalPopupTargetSelect *
+e_cal_popup_target_new_select(ECalPopup *eabp)
+{
+	ECalPopupTargetSelect *t = e_popup_target_new(&eabp->popup, E_CAL_POPUP_TARGET_SELECT, sizeof(*t));
+	guint32 mask = ~0;
+
+	/* FIXME: impelement */
+
+	t->target.mask = mask;
+
+	return t;
+}
+
+ECalPopupTargetSource *
+e_cal_popup_target_new_source(ECalPopup *eabp, ESourceSelector *selector)
+{
+	ECalPopupTargetSource *t = e_popup_target_new(&eabp->popup, E_CAL_POPUP_TARGET_SOURCE, sizeof(*t));
+	guint32 mask = ~0;
+	const char *source_uri;
+	ESource *source;
+
+	/* TODO: this is duplicated for addressbook too */
+
+	t->selector = selector;
+	g_object_ref(selector);
+
+	/* TODO: perhaps we need to copy this so it doesn't change during the lifecycle */
+	source = e_source_selector_peek_primary_selection(selector);
+	if (source)
+		mask &= ~E_CAL_POPUP_SOURCE_PRIMARY;
+
+	/* FIXME Gross hack, should have a property or something */
+	source_uri = e_source_peek_relative_uri(source);
+	if (source_uri && !strcmp("system", source_uri))
+		mask &= ~E_CAL_POPUP_SOURCE_SYSTEM;
+	else
+		mask &= ~E_CAL_POPUP_SOURCE_USER;
+
+	t->target.mask = mask;
+
+	return t;
+}
+
+/* ********************************************************************** */
+/* Popup menu plugin handler */
+
+/*
+<e-plugin
+  class="com.ximian.mail.plugin.popup:1.0"
+  id="com.ximian.mail.plugin.popup.iteab:1.0"
+  type="shlib"
+  location="/opt/gnome2/lib/camel/1.0/libcamelimap.so"
+  name="imap"
+  description="IMAP4 and IMAP4v1 mail store">
+  <hook class="com.ximian.mail.popupMenu:1.0"
+        handler="HandlePopup">
+  <menu id="any" target="select">
+   <iteab
+    type="iteab|toggle|radio|image|submenu|bar"
+    active
+    path="foo/bar"
+    label="label"
+    icon="foo"
+    mask="select_one"
+    activate="ecalp_view_eabacs"/>
+  </menu>
+  </extension>
+
+*/
+
+static void *ecalph_parent_class;
+#define ecalph ((ECalPopupHook *)eph)
+
+static const EPopupHookTargetMask ecalph_select_masks[] = {
+	{ "one", E_CAL_POPUP_SELECT_ONE },
+	{ "many", E_CAL_POPUP_SELECT_MANY },
+	{ 0 }
+};
+
+static const EPopupHookTargetMask ecalph_source_masks[] = {
+	{ "primary", E_CAL_POPUP_SOURCE_PRIMARY },
+	{ "system", E_CAL_POPUP_SOURCE_SYSTEM },
+	{ 0 }
+};
+
+static const EPopupHookTargetMap ecalph_targets[] = {
+	{ "select", E_CAL_POPUP_TARGET_SELECT, ecalph_select_masks },
+	{ "source", E_CAL_POPUP_TARGET_SOURCE, ecalph_source_masks },
+	{ 0 }
+};
+
+static void
+ecalph_finalise(GObject *o)
+{
+	/*EPluginHook *eph = (EPluginHook *)o;*/
+
+	((GObjectClass *)ecalph_parent_class)->finalize(o);
+}
+
+static void
+ecalph_class_init(EPluginHookClass *klass)
+{
+	int i;
+
+	((GObjectClass *)klass)->finalize = ecalph_finalise;
+	((EPluginHookClass *)klass)->id = "com.ximian.evolution.addressbook.popup:1.0";
+
+	for (i=0;ecalph_targets[i].type;i++)
+		e_popup_hook_class_add_target_map((EPopupHookClass *)klass, &ecalph_targets[i]);
+
+	((EPopupHookClass *)klass)->popup_class = g_type_class_ref(e_cal_popup_get_type());
+}
+
+GType
+e_cal_popup_hook_get_type(void)
+{
+	static GType type = 0;
+	
+	if (!type) {
+		static const GTypeInfo info = {
+			sizeof(ECalPopupHookClass), NULL, NULL, (GClassInitFunc) ecalph_class_init, NULL, NULL,
+			sizeof(ECalPopupHook), 0, (GInstanceInitFunc) NULL,
+		};
+
+		ecalph_parent_class = g_type_class_ref(e_popup_hook_get_type());
+		type = g_type_register_static(e_popup_hook_get_type(), "ECalPopupHook", &info, 0);
+	}
+	
+	return type;
+}
Index: calendar/gui/e-cal-popup.h
===================================================================
RCS file: calendar/gui/e-cal-popup.h
diff -N calendar/gui/e-cal-popup.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ calendar/gui/e-cal-popup.h	1 Oct 2004 07:40:27 -0000
@@ -0,0 +1,145 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ *  Authors: Michael Zucchi <notzed ximian com>
+ *
+ *  Copyright 2004 Novell, Inc. (www.novell.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __E_CAL_POPUP_H__
+#define __E_CAL_POPUP_H__
+
+#include <glib-object.h>
+
+#include "e-util/e-popup.h"
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+typedef struct _ECalPopup ECalPopup;
+typedef struct _ECalPopupClass ECalPopupClass;
+
+/**
+ * enum _e_cal_popup_target_t - A list of mail popup target types.
+ * 
+ * @E_CAL_POPUP_TARGET_SELECT: A selection of cards
+ * @E_CAL_POPUP_TARGET_SOURCE: A source selection.
+ *
+ * Defines the value of the targetid for all ECalPopup target types.
+ **/
+enum _e_cal_popup_target_t {
+	E_CAL_POPUP_TARGET_SELECT,
+	E_CAL_POPUP_TARGET_SOURCE,
+};
+
+/**
+ * enum _e_cal_popup_target_select_t - ECalPopupTargetSelect qualifiers.
+ * 
+ * @E_CAL_POPUP_SELECT_ONE: Only one item is selected.
+ * @E_CAL_POPUP_SELECT_MANY: One ore more items are selected.
+ * 
+ **/
+enum _e_cal_popup_target_select_t {
+	E_CAL_POPUP_SELECT_ONE                = 1<<1,
+	E_CAL_POPUP_SELECT_MANY               = 1<<2,
+};
+
+/**
+ * enum _e_cal_popup_target_source_t - ECalPopupTargetSource qualifiers.
+ * 
+ * @E_CAL_POPUP_SOURCE_PRIMARY: Has a primary selection.
+ * @E_CAL_POPUP_SOURCE_SYSTEM: Is a 'system' folder.
+ * 
+ **/
+enum _e_cal_popup_target_source_t {
+	E_CAL_POPUP_SOURCE_PRIMARY = 1<<0,
+	E_CAL_POPUP_SOURCE_SYSTEM = 1<<1,	/* system folder */
+	E_CAL_POPUP_SOURCE_USER = 1<<2, /* user folder (!system) */
+};
+
+typedef struct _ECalPopupTargetSelect ECalPopupTargetSelect;
+typedef struct _ECalPopupTargetSource ECalPopupTargetSource;
+
+/**
+ * struct _ECalPopupTargetSelect - A list of address cards.
+ * 
+ * @target: Superclass.
+ *
+ * Used to represent a selection of appointments as context for a popup
+ * menu.
+ *
+ * FIXME: impelemnt me
+ **/
+struct _ECalPopupTargetSelect {
+	EPopupTarget target;
+};
+
+/**
+ * struct _ECalPopupTargetSource - A source target.
+ * 
+ * @target: Superclass.
+ * @selector: Selector holding the source selection.
+ *
+ * This target is used to represent a source selection.
+ **/
+struct _ECalPopupTargetSource {
+	EPopupTarget target;
+
+	struct _ESourceSelector *selector;
+};
+
+typedef struct _EPopupItem ECalPopupItem;
+
+/* The object */
+struct _ECalPopup {
+	EPopup popup;
+
+	struct _ECalPopupPrivate *priv;
+};
+
+struct _ECalPopupClass {
+	EPopupClass popup_class;
+};
+
+GType e_cal_popup_get_type(void);
+
+ECalPopup *e_cal_popup_new(const char *menuid);
+
+ECalPopupTargetSelect *e_cal_popup_target_new_select(ECalPopup *eabp);
+ECalPopupTargetSource *e_cal_popup_target_new_source(ECalPopup *eabp, struct _ESourceSelector *selector);
+
+/* ********************************************************************** */
+
+typedef struct _ECalPopupHook ECalPopupHook;
+typedef struct _ECalPopupHookClass ECalPopupHookClass;
+
+struct _ECalPopupHook {
+	EPopupHook hook;
+};
+
+struct _ECalPopupHookClass {
+	EPopupHookClass hook_class;
+};
+
+GType e_cal_popup_hook_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __E_CAL_POPUP_H__ */
Index: calendar/gui/tasks-component.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/tasks-component.c,v
retrieving revision 1.74
diff -u -p -r1.74 tasks-component.c
--- calendar/gui/tasks-component.c	23 Sep 2004 13:10:57 -0000	1.74
+++ calendar/gui/tasks-component.c	1 Oct 2004 07:40:27 -0000
@@ -40,6 +40,7 @@
 #include "migration.h"
 #include "comp-util.h"
 #include "calendar-config.h"
+#include "e-cal-popup.h"
 #include "common/authentication.h"
 #include "dialogs/calendar-setup.h"
 #include "dialogs/comp-editor.h"
@@ -47,6 +48,7 @@
 #include "dialogs/task-editor.h"
 #include "widgets/misc/e-source-selector.h"
 #include "widgets/misc/e-info-label.h"
+#include "widgets/misc/e-error.h"
 #include "e-util/e-icon-factory.h"
 
 #define CREATE_TASK_ID               "task"
@@ -252,137 +254,112 @@ update_primary_selection (TasksComponent
 
 /* Callbacks.  */
 static void
-add_popup_menu_item (GtkMenu *menu, const char *label, const char *icon_name,
-		     GCallback callback, gpointer user_data, gboolean sensitive)
-{
-	GtkWidget *item, *image;
-	GdkPixbuf *pixbuf;
-
-	if (icon_name) {
-		item = gtk_image_menu_item_new_with_label (label);
-
-		/* load the image */
-		pixbuf = e_icon_factory_get_icon (icon_name, E_ICON_SIZE_MENU);
-		image = gtk_image_new_from_pixbuf (pixbuf);
-
-		if (image) {
-			gtk_widget_show (image);
-			gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
-		}
-	} else {
-		item = gtk_menu_item_new_with_label (label);
-	}
-
-	if (callback)
-		g_signal_connect (G_OBJECT (item), "activate", callback, user_data);
-
-	if (!sensitive)
-		gtk_widget_set_sensitive (item, FALSE);
-
-	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-	gtk_widget_show (item);
-}
-
-static void
-copy_task_list_cb (GtkWidget *widget, TasksComponentView *component_view)
+copy_task_list_cb (EPopup *ep, EPopupItem *pitem, void *data)
 {
+	TasksComponentView *component_view = data;
 	ESource *selected_source;
 	
 	selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
 	if (!selected_source)
 		return;
 
-	copy_source_dialog (GTK_WINDOW (gtk_widget_get_toplevel (widget)), selected_source, E_CAL_SOURCE_TYPE_TODO);
+	copy_source_dialog (GTK_WINDOW (gtk_widget_get_toplevel(ep->target->widget)), selected_source, E_CAL_SOURCE_TYPE_TODO);
 }
 
 static void
-delete_task_list_cb (GtkWidget *widget, TasksComponentView *component_view)
+delete_task_list_cb (EPopup *ep, EPopupItem *pitem, void *data)
 {
+	TasksComponentView *component_view = data;
 	ESource *selected_source;
-	GtkWidget *dialog;
+	ECal *cal;
+	char *uri;
 
 	selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
 	if (!selected_source)
 		return;
 
-	/* create the confirmation dialog */
-	dialog = gtk_message_dialog_new (
-		GTK_WINDOW (gtk_widget_get_toplevel (widget)),
-		GTK_DIALOG_MODAL,
-		GTK_MESSAGE_QUESTION,
-		GTK_BUTTONS_YES_NO,
-		_("Task List '%s' will be removed. Are you sure you want to continue?"),
-		e_source_peek_name (selected_source));
-	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES) {
-		ECal *cal;
-		char *uri;
-
-		/* first, ask the backend to remove the task list */
-		uri = e_source_get_uri (selected_source);
-		cal = e_cal_model_get_client_for_uri (
-			e_calendar_table_get_model (E_CALENDAR_TABLE (e_tasks_get_calendar_table (component_view->tasks))),
-			uri);
-		if (!cal)
-			cal = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_TODO);
-		g_free (uri);
-		if (cal) {
-			if (e_cal_remove (cal, NULL)) {
-				if (e_source_selector_source_is_selected (E_SOURCE_SELECTOR (component_view->source_selector),
-									  selected_source)) {
-					e_tasks_remove_todo_source (component_view->tasks, selected_source);
-					e_source_selector_unselect_source (E_SOURCE_SELECTOR (component_view->source_selector),
-									   selected_source);
-				}
+	if (e_error_run((GtkWindow *)gtk_widget_get_toplevel(ep->target->widget),
+			"calendar:prompt-delete-task-list", e_source_peek_name(selected_source)) != GTK_RESPONSE_YES)
+		return;
 
-				e_source_group_remove_source (e_source_peek_group (selected_source), selected_source);
-				e_source_list_sync (component_view->source_list, NULL);
+	/* first, ask the backend to remove the task list */
+	uri = e_source_get_uri (selected_source);
+	cal = e_cal_model_get_client_for_uri (
+		e_calendar_table_get_model (E_CALENDAR_TABLE (e_tasks_get_calendar_table (component_view->tasks))),
+		uri);
+	if (!cal)
+		cal = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_TODO);
+	g_free (uri);
+	if (cal) {
+		if (e_cal_remove (cal, NULL)) {
+			if (e_source_selector_source_is_selected (E_SOURCE_SELECTOR (component_view->source_selector),
+								  selected_source)) {
+				e_tasks_remove_todo_source (component_view->tasks, selected_source);
+				e_source_selector_unselect_source (E_SOURCE_SELECTOR (component_view->source_selector),
+								   selected_source);
 			}
+			
+			e_source_group_remove_source (e_source_peek_group (selected_source), selected_source);
+			e_source_list_sync (component_view->source_list, NULL);
 		}
 	}
-
-	gtk_widget_destroy (dialog);
 }
 
 static void
-new_task_list_cb (GtkWidget *widget, TasksComponentView *component_view)
+new_task_list_cb (EPopup *ep, EPopupItem *pitem, void *data)
 {
-	calendar_setup_new_task_list (GTK_WINDOW (gtk_widget_get_toplevel (widget)));
+	calendar_setup_new_task_list (GTK_WINDOW (gtk_widget_get_toplevel(ep->target->widget)));
 }
 
 static void
-edit_task_list_cb (GtkWidget *widget, TasksComponentView *component_view)
+edit_task_list_cb (EPopup *ep, EPopupItem *pitem, void *data)
 {
+	TasksComponentView *component_view = data;
 	ESource *selected_source;
 
 	selected_source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
 	if (!selected_source)
 		return;
 
-	calendar_setup_edit_task_list (GTK_WINDOW (gtk_widget_get_toplevel (widget)), selected_source);
+	calendar_setup_edit_task_list (GTK_WINDOW (gtk_widget_get_toplevel(ep->target->widget)), selected_source);
 }
 
+static EPopupItem etc_source_popups[] = {
+	{ E_POPUP_ITEM, "10.new", N_("New Task List"), new_task_list_cb, NULL, "stock_todo", 0 },
+	{ E_POPUP_ITEM, "15.copy", N_("Copy"), copy_task_list_cb, NULL, "stock_folder-copy", E_CAL_POPUP_SOURCE_PRIMARY },
+	{ E_POPUP_ITEM, "20.delete", N_("Delete"), delete_task_list_cb, NULL, "stock_delete", E_CAL_POPUP_SOURCE_USER|E_CAL_POPUP_SOURCE_PRIMARY },
+	{ E_POPUP_ITEM, "30.properties", N_("Properties..."), edit_task_list_cb, NULL, NULL, E_CAL_POPUP_SOURCE_PRIMARY },
+};
+
 static void
-fill_popup_menu_cb (ESourceSelector *selector, GtkMenu *menu, TasksComponentView *component_view)
+etc_source_popup_free(EPopup *ep, GSList *list, void *data)
 {
-	ESource *source;
-	gboolean sensitive, system;
-	const char *source_uri;
-	
-	source = e_source_selector_peek_primary_selection (E_SOURCE_SELECTOR (component_view->source_selector));
-	sensitive =  source ? TRUE : FALSE;
+	g_slist_free(list);
+}
 
-	/* FIXME Gross hack, should have a property or something */
-	source_uri = e_source_peek_relative_uri (source);
-	system = source_uri && !strcmp ("system", source_uri);
-
-	add_popup_menu_item (menu, _("New Task List"), "stock_todo",
-			     G_CALLBACK (new_task_list_cb), component_view, TRUE);
-	add_popup_menu_item (menu, _("Copy"), "stock_folder-copy",
-			     G_CALLBACK (copy_task_list_cb), component_view, sensitive);
-	add_popup_menu_item (menu, _("Delete"), "stock_delete", G_CALLBACK (delete_task_list_cb),
-			     component_view, sensitive && !system);
-	add_popup_menu_item (menu, _("Properties..."), NULL, G_CALLBACK (edit_task_list_cb),
-			     component_view, sensitive);
+static gboolean
+popup_event_cb(ESourceSelector *selector, ESource *insource, GdkEventButton *event, TasksComponentView *component_view)
+{
+	ECalPopup *ep;
+	ECalPopupTargetSource *t;
+	GSList *menus = NULL;
+	int i;
+	GtkMenu *menu;
+
+	ep = e_cal_popup_new("com.novell.evolution.tasks.source.popup");
+	t = e_cal_popup_target_new_source(ep, selector);
+	t->target.widget = (GtkWidget *)component_view->tasks;
+
+	for (i=0;i<sizeof(etc_source_popups)/sizeof(etc_source_popups[0]);i++)
+		menus = g_slist_prepend(menus, &etc_source_popups[i]);
+
+	e_popup_add_items((EPopup *)ep, menus, etc_source_popup_free, component_view);
+
+	/* visibility is disabled, we only disable menu items */
+	menu = e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0, t->target.mask);
+	gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event?event->button:0, event?event->time:gtk_get_current_event_time());
+
+	return TRUE;
 }
 
 static void
@@ -867,7 +844,7 @@ create_component_view (TasksComponent *t
 	
 	/* Create sidebar selector */
 	component_view->source_selector = e_source_selector_new (tasks_component->priv->source_list);
-	e_source_selector_set_select_new (component_view->source_selector, TRUE);
+	e_source_selector_set_select_new ((ESourceSelector *)component_view->source_selector, TRUE);
 
 	g_signal_connect (component_view->source_selector, "drag-motion", G_CALLBACK (selector_tree_drag_motion), 
 			  tasks_component);
@@ -936,8 +913,8 @@ create_component_view (TasksComponent *t
 			  G_CALLBACK (source_selection_changed_cb), component_view);
 	g_signal_connect (component_view->source_selector, "primary_selection_changed",
 			  G_CALLBACK (primary_source_selection_changed_cb), component_view);
-	g_signal_connect (component_view->source_selector, "fill_popup_menu",
-			  G_CALLBACK (fill_popup_menu_cb), component_view);
+	g_signal_connect (component_view->source_selector, "popup_event",
+			  G_CALLBACK (popup_event_cb), component_view);
 
 	/* Set up the "new" item handler */
 	component_view->creatable_items_handler = e_user_creatable_items_handler_new ("tasks", create_local_item_cb, tasks_component);
Index: widgets/misc/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/widgets/misc/ChangeLog,v
retrieving revision 1.325
diff -u -p -r1.325 ChangeLog
--- widgets/misc/ChangeLog	13 Sep 2004 16:24:32 -0000	1.325
+++ widgets/misc/ChangeLog	1 Oct 2004 07:40:28 -0000
@@ -1,3 +1,12 @@
+2004-10-01  Not Zed  <NotZed Ximian com>
+
+	* e-util-marshal.list: added boolean object boxed.
+
+	* e-source-selector.c (class_init): add new 'popup event' signal,
+	to replace fill_popup_menu.
+	(selector_button_press_event): emit a POPUP_EVENT rather than a
+	FILL_POPUP_MENU.
+
 2004-09-13  Rodney Dawes  <dobey novell com>
 
 	* e-multi-config-dialog.c (impl_response):
Index: widgets/misc/e-source-selector.c
===================================================================
RCS file: /cvs/gnome/evolution/widgets/misc/e-source-selector.c,v
retrieving revision 1.22
diff -u -p -r1.22 e-source-selector.c
--- widgets/misc/e-source-selector.c	20 Jul 2004 16:36:43 -0000	1.22
+++ widgets/misc/e-source-selector.c	1 Oct 2004 07:40:28 -0000
@@ -67,7 +67,7 @@ typedef struct {
 enum {
 	SELECTION_CHANGED,
 	PRIMARY_SELECTION_CHANGED,
-	FILL_POPUP_MENU,
+	POPUP_EVENT,
 	NUM_SIGNALS
 };
 static unsigned int signals[NUM_SIGNALS] = { 0 };
@@ -579,10 +579,10 @@ static gboolean
 selector_button_press_event (GtkWidget *widget, GdkEventButton *event, ESourceSelector *selector)
 {
 	ESourceSelectorPrivate *priv = selector->priv;
-	GtkWidget *menu;
 	GtkTreePath *path;
 	ESource *source = NULL;
-	
+	gboolean res = FALSE;
+
 	priv->toggled_last = FALSE;
 	
 	/* only process right-clicks */
@@ -596,7 +596,8 @@ selector_button_press_event (GtkWidget *
 		
 		if (gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->tree_store), &iter, path)) {
 			gtk_tree_model_get (GTK_TREE_MODEL (priv->tree_store), &iter, 0, &data, -1);
-			
+
+			/* TODO: we could still emit a popup event for this and let the callee decide? */
 			if (E_IS_SOURCE_GROUP (data)) {
 				g_object_unref (data);
 				
@@ -607,19 +608,15 @@ selector_button_press_event (GtkWidget *
 		}
 	}
 
-	if (source) {
+	if (source)
 		e_source_selector_set_primary_selection (selector, source);
-		g_object_unref (source);
-	}
-	
-	/* create the menu */
-	menu = gtk_menu_new ();
-	g_signal_emit (G_OBJECT (selector), signals[FILL_POPUP_MENU], 0, GTK_MENU (menu));
 
-	/* popup the menu */
-	gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, event->button, event->time);
+	g_signal_emit(selector, signals[POPUP_EVENT], 0, source, event, &res);
 
-	return TRUE;
+	if (source)
+		g_object_unref (source);
+
+	return res;
 }
 
 /* GObject methods.  */
@@ -666,6 +663,15 @@ impl_finalize (GObject *object)
 
 
 /* Initialization.  */
+static gboolean
+ess_bool_accumulator(GSignalInvocationHint *ihint, GValue *out, const GValue *in, void *data)
+{
+	gboolean val = g_value_get_boolean(in);
+
+	g_value_set_boolean(out, val);
+
+	return !val;
+}
 
 static void
 class_init (ESourceSelectorClass *class)
@@ -694,14 +700,15 @@ class_init (ESourceSelectorClass *class)
 			      NULL, NULL,
 			      e_util_marshal_VOID__VOID,
 			      G_TYPE_NONE, 0);
-	signals[FILL_POPUP_MENU] =
-		g_signal_new ("fill_popup_menu",
+	signals[POPUP_EVENT] =
+		g_signal_new ("popup_event",
 			      G_OBJECT_CLASS_TYPE (object_class),
 			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (ESourceSelectorClass, fill_popup_menu),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__OBJECT,
-			      G_TYPE_NONE, 1, G_TYPE_OBJECT);
+			      G_STRUCT_OFFSET (ESourceSelectorClass, popup_event),
+			      ess_bool_accumulator, NULL,
+			      e_util_marshal_BOOLEAN__OBJECT_BOXED,
+			      G_TYPE_BOOLEAN, 2, G_TYPE_OBJECT,
+			      GDK_TYPE_EVENT|G_SIGNAL_TYPE_STATIC_SCOPE);
 }
 
 static void
Index: widgets/misc/e-source-selector.h
===================================================================
RCS file: /cvs/gnome/evolution/widgets/misc/e-source-selector.h,v
retrieving revision 1.7
diff -u -p -r1.7 e-source-selector.h
--- widgets/misc/e-source-selector.h	20 Jul 2004 16:36:43 -0000	1.7
+++ widgets/misc/e-source-selector.h	1 Oct 2004 07:40:28 -0000
@@ -50,7 +50,7 @@ struct _ESourceSelectorClass {
 
 	void (* selection_changed) (ESourceSelector *selector);
 	void (* primary_selection_changed) (ESourceSelector *selector);
-	void (* fill_popup_menu) (ESourceSelector *selector, GtkMenu *menu);
+	gboolean (*popup_event)(ESourceSelector *selector, ESource *primary, GdkEventButton *event);
 };
 
 
Index: widgets/misc/e-util-marshal.list
===================================================================
RCS file: /cvs/gnome/evolution/widgets/misc/e-util-marshal.list,v
retrieving revision 1.2
diff -u -p -r1.2 e-util-marshal.list
--- widgets/misc/e-util-marshal.list	1 Dec 2003 02:55:47 -0000	1.2
+++ widgets/misc/e-util-marshal.list	1 Oct 2004 07:40:28 -0000
@@ -1,3 +1,4 @@
 NONE:NONE
 NONE:INT
 NONE:POINTER
+BOOLEAN:OBJECT,BOXED


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]