evolution r34981 - in branches/mbarnes-composer: . addressbook/gui/widgets calendar/gui composer mail
- From: mbarnes svn gnome org
- To: svn-commits-list gnome org
- Subject: evolution r34981 - in branches/mbarnes-composer: . addressbook/gui/widgets calendar/gui composer mail
- Date: Sat, 9 Feb 2008 21:54:03 +0000 (GMT)
Author: mbarnes
Date: Sat Feb 9 21:54:02 2008
New Revision: 34981
URL: http://svn.gnome.org/viewvc/evolution?rev=34981&view=rev
Log:
Replace the composer's Bonobo interface with a straight-forward API and
adapt the addressbook and calendar to use it. Not surprisingly, a whole
bunch of complexity falls out.
Add GConfBridge to source control and bind the "current folder" GConf key
to the HTML editor's "current folder" GObject property.
Start destroying e-msg-composer-select-file.[ch]. Clean these functions
up and move them into e-msg-composer.c.
Added:
branches/mbarnes-composer/composer/gconf-bridge.c
branches/mbarnes-composer/composer/gconf-bridge.h
Removed:
branches/mbarnes-composer/composer/Composer.idl
branches/mbarnes-composer/composer/Evolution-Composer.idl
branches/mbarnes-composer/composer/evolution-composer.c
branches/mbarnes-composer/composer/evolution-composer.h
branches/mbarnes-composer/composer/listener.c
branches/mbarnes-composer/composer/listener.h
Modified:
branches/mbarnes-composer/addressbook/gui/widgets/Makefile.am
branches/mbarnes-composer/addressbook/gui/widgets/eab-gui-util.c
branches/mbarnes-composer/calendar/gui/Makefile.am
branches/mbarnes-composer/calendar/gui/itip-utils.c
branches/mbarnes-composer/composer/Makefile.am
branches/mbarnes-composer/composer/e-composer-actions.c
branches/mbarnes-composer/composer/e-composer-private.h
branches/mbarnes-composer/composer/e-msg-composer-select-file.c
branches/mbarnes-composer/composer/e-msg-composer-select-file.h
branches/mbarnes-composer/composer/e-msg-composer.c
branches/mbarnes-composer/composer/e-msg-composer.h
branches/mbarnes-composer/configure.in
branches/mbarnes-composer/mail/em-composer-utils.c
branches/mbarnes-composer/mail/mail-component-factory.c
Modified: branches/mbarnes-composer/addressbook/gui/widgets/Makefile.am
==============================================================================
--- branches/mbarnes-composer/addressbook/gui/widgets/Makefile.am (original)
+++ branches/mbarnes-composer/addressbook/gui/widgets/Makefile.am Sat Feb 9 21:54:02 2008
@@ -16,23 +16,6 @@
-I$(top_builddir)/shell \
$(EVOLUTION_ADDRESSBOOK_CFLAGS)
-CORBA_COMPOSER_SOURCE_H = \
- Evolution-Composer.h
-CORBA_COMPOSER_SOURCE_C = \
- Evolution-Composer-common.c \
- Evolution-Composer-skels.c \
- Evolution-Composer-stubs.c
-CORBA_COMPOSER_IDL = $(srcdir)/../../../composer/Evolution-Composer.idl
-
-$(CORBA_COMPOSER_SOURCE_H): $(CORBA_COMPOSER_IDL)
- $(ORBIT_IDL) -I $(srcdir) $(IDL_INCLUDES) $(CORBA_COMPOSER_IDL)
-
-$(CORBA_COMPOSER_SOURCE_C): $(CORBA_COMPOSER_SOURCE_H)
-
-CORBA_SOURCE_H = $(CORBA_COMPOSER_SOURCE_H)
-CORBA_SOURCE_C = $(CORBA_COMPOSER_SOURCE_C)
-CORBA_SOURCE = $(CORBA_SOURCE_H) $(CORBA_SOURCE_C)
-
noinst_LTLIBRARIES = \
libeabwidgets.la
@@ -44,7 +27,6 @@
eab-popup.h
libeabwidgets_la_SOURCES = \
- $(CORBA_SOURCE) \
$(MARSHAL_GENERATED) \
eab-config.c \
eab-contact-display.c \
@@ -82,7 +64,7 @@
MARSHAL_GENERATED = eab-marshal.c eab-marshal.h
@EVO_MARSHAL_RULE@
-BUILT_SOURCES = $(CORBA_SOURCE) $(MARSHAL_GENERATED)
+BUILT_SOURCES = $(MARSHAL_GENERATED)
CLEANFILES = $(BUILT_SOURCES)
dist-hook:
Modified: branches/mbarnes-composer/addressbook/gui/widgets/eab-gui-util.c
==============================================================================
--- branches/mbarnes-composer/addressbook/gui/widgets/eab-gui-util.c (original)
+++ branches/mbarnes-composer/addressbook/gui/widgets/eab-gui-util.c Sat Feb 9 21:54:02 2008
@@ -39,6 +39,7 @@
#include <e-util/e-icon-factory.h>
#include "eab-contact-merging.h"
#include <gnome.h>
+#include <composer/e-msg-composer.h>
/* we link to camel for decoding quoted printable email addresses */
#include <camel/camel-mime-utils.h>
@@ -766,174 +767,76 @@
addressbook_load (dest, got_book_cb, process);
}
-#include <Evolution-Composer.h>
-
-#define COMPOSER_OAFID "OAFIID:GNOME_Evolution_Mail_Composer:" BASE_VERSION
-
typedef struct {
EContact *contact;
int email_num; /* if the contact is a person (not a list), the email address to use */
} ContactAndEmailNum;
static void
-eab_send_to_contact_and_email_num_list (GList *c)
+eab_send_to_contact_and_email_num_list (GList *contact_list)
{
- GNOME_Evolution_Composer composer_server;
- CORBA_Environment ev;
- GNOME_Evolution_Composer_RecipientList *to_list, *cc_list, *bcc_list;
- CORBA_char *subject;
- int to_i, bcc_i;
- GList *iter;
- gint to_length = 0, bcc_length = 0;
+ EMsgComposer *composer;
+ EComposerHeaderTable *table;
+ GPtrArray *to_array;
+ GPtrArray *bcc_array;
+
+ union {
+ gpointer *pdata;
+ EDestination **destinations;
+ } convert;
- if (c == NULL)
+ if (contact_list == NULL)
return;
- CORBA_exception_init (&ev);
+ composer = e_msg_composer_new ();
+ table = e_msg_composer_get_header_table (composer);
- composer_server = bonobo_activation_activate_from_id (COMPOSER_OAFID, 0, NULL, &ev);
+ to_array = g_ptr_array_new ();
+ bcc_array = g_ptr_array_new ();
- /* Figure out how many addresses of each kind we have. */
- for (iter = c; iter != NULL; iter = g_list_next (iter)) {
- ContactAndEmailNum *ce = iter->data;
+ /* Sort contacts into "To" and "Bcc" destinations. */
+ while (contact_list != NULL) {
+ ContactAndEmailNum *ce = contact_list->data;
EContact *contact = ce->contact;
- GList *emails = e_contact_get (contact, E_CONTACT_EMAIL);
- if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
- gint len = g_list_length (emails);
- if (e_contact_get (contact, E_CONTACT_LIST_SHOW_ADDRESSES))
- to_length += len;
- else
- bcc_length += len;
- } else {
- if (emails != NULL)
- ++to_length;
- }
- g_list_foreach (emails, (GFunc)g_free, NULL);
- g_list_free (emails);
- }
+ EDestination *destination;
- /* Now I have to make a CORBA sequences that represents a recipient list with
- the right number of entries, for the contacts. */
- to_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- to_list->_maximum = to_length;
- to_list->_length = to_length;
- if (to_length > 0) {
- to_list->_buffer = CORBA_sequence_GNOME_Evolution_Composer_Recipient_allocbuf (to_length);
- }
-
- cc_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- cc_list->_maximum = cc_list->_length = 0;
+ destination = e_destination_new ();
+ e_destination_set_contact (destination, contact, 0);
- bcc_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- bcc_list->_maximum = bcc_length;
- bcc_list->_length = bcc_length;
- if (bcc_length > 0) {
- bcc_list->_buffer = CORBA_sequence_GNOME_Evolution_Composer_Recipient_allocbuf (bcc_length);
- }
-
- to_i = 0;
- bcc_i = 0;
- while (c != NULL) {
- ContactAndEmailNum *ce = c->data;
- EContact *contact = ce->contact;
- int nth = ce->email_num;
- char *name, *addr;
- gboolean is_list, is_hidden;
- GNOME_Evolution_Composer_Recipient *recipient;
- GList *emails = e_contact_get (contact, E_CONTACT_EMAIL);
- GList *iterator;
-
- if (emails != NULL) {
- is_list = e_contact_get (contact, E_CONTACT_IS_LIST) != NULL;
- is_hidden = is_list && !e_contact_get (contact, E_CONTACT_LIST_SHOW_ADDRESSES);
-
- if (is_list) {
- for (iterator = emails; iterator; iterator = iterator->next) {
-
- if (is_hidden) {
- recipient = &(bcc_list->_buffer[bcc_i]);
- ++bcc_i;
- } else {
- recipient = &(to_list->_buffer[to_i]);
- ++to_i;
- }
-
- name = NULL;
- addr = NULL;
- if (iterator && iterator->data) {
- /* XXX we should probably try to get the name from the attribute parameter here.. */
- addr = g_strdup ((char*)iterator->data);
- }
-
- recipient->name = CORBA_string_dup (name ? name : "");
- recipient->address = CORBA_string_dup (addr ? addr : "");
-
- g_free (name);
- g_free (addr);
- }
- }
- else {
- EContactName *contact_name = e_contact_get (contact, E_CONTACT_NAME);
- int length = g_list_length (emails);
-
- if (is_hidden) {
- recipient = &(bcc_list->_buffer[bcc_i]);
- ++bcc_i;
- } else {
- recipient = &(to_list->_buffer[to_i]);
- ++to_i;
- }
-
- if (nth >= length)
- nth = 0;
-
- if (contact_name) {
- name = e_contact_name_to_string (contact_name);
- e_contact_name_free (contact_name);
- }
- else
- name = NULL;
-
- addr = g_strdup (g_list_nth_data (emails, nth));
-
-
- recipient->name = CORBA_string_dup (name ? name : "");
- recipient->address = CORBA_string_dup (addr ? addr : "");
-
- g_free (name);
- g_free (addr);
- }
-
- g_list_foreach (emails, (GFunc)g_free, NULL);
- g_list_free (emails);
- }
-
- c = c->next;
- }
-
- subject = CORBA_string_dup ("");
-
- GNOME_Evolution_Composer_setHeaders (composer_server, "", to_list, cc_list, bcc_list, subject, &ev);
- if (ev._major != CORBA_NO_EXCEPTION) {
- g_printerr ("gui/e-meeting-edit.c: I couldn't set the composer headers via CORBA! Aagh.\n");
- CORBA_exception_free (&ev);
- return;
- }
-
- CORBA_free (to_list);
- CORBA_free (cc_list);
- CORBA_free (bcc_list);
- CORBA_free (subject);
-
- GNOME_Evolution_Composer_show (composer_server, &ev);
-
- if (ev._major != CORBA_NO_EXCEPTION) {
- g_printerr ("gui/e-meeting-edit.c: I couldn't show the composer via CORBA! Aagh.\n");
- CORBA_exception_free (&ev);
- return;
- }
+ if (e_destination_is_evolution_list (destination)) {
+ if (e_destination_list_show_addresses (destination))
+ g_ptr_array_add (to_array, destination);
+ else
+ g_ptr_array_add (bcc_array, destination);
+ } else
+ g_ptr_array_add (to_array, destination);
+
+ contact_list = g_list_next (contact_list);
+ }
+
+ /* Add sentinels to each array. */
+ g_ptr_array_add (to_array, NULL);
+ g_ptr_array_add (bcc_array, NULL);
+
+ /* XXX Acrobatics like this make me question whether NULL-terminated
+ * arrays are really the best argument type for passing a list of
+ * destinations to the header table. */
+
+ /* Add "To" destinations. */
+ convert.pdata = to_array->pdata;
+ e_composer_header_table_set_destinations_to (
+ table, convert.destinations);
+ g_ptr_array_free (to_array, FALSE);
+ e_destination_freev (convert.destinations);
+
+ /* Add "Bcc" destinations. */
+ convert.pdata = bcc_array->pdata;
+ e_composer_header_table_set_destinations_bcc (
+ table, convert.destinations);
+ g_ptr_array_free (bcc_array, FALSE);
+ e_destination_freev (convert.destinations);
- CORBA_exception_free (&ev);
+ gtk_widget_show (GTK_WIDGET (composer));
}
static const char *
@@ -958,75 +861,48 @@
static void
eab_send_contact_list_as_attachment (GList *contacts)
{
- GNOME_Evolution_Composer composer_server;
- CORBA_Environment ev;
- CORBA_char *content_type, *filename, *description;
- GNOME_Evolution_Composer_AttachmentData *attach_data;
- CORBA_boolean show_inline;
- char *tempstr;
- GNOME_Evolution_Composer_RecipientList *to_list, *cc_list, *bcc_list;
- CORBA_char *subject;
+ EMsgComposer *composer;
+ EComposerHeaderTable *table;
+ CamelMimePart *attachment;
+ gchar *data;
if (contacts == NULL)
return;
- CORBA_exception_init (&ev);
-
- composer_server = bonobo_activation_activate_from_id (COMPOSER_OAFID, 0, NULL, &ev);
-
-
+ composer = e_msg_composer_new ();
+ table = e_msg_composer_get_header_table (composer);
- content_type = CORBA_string_dup ("text/x-vcard");
- filename = CORBA_string_dup ("");
+ attachment = camel_mime_part_new ();
+ data = eab_contact_list_to_string (contacts);
- if (contacts->next) {
- description = CORBA_string_dup (_("Multiple vCards"));
- } else {
- char *file_as = e_contact_get (E_CONTACT (contacts->data), E_CONTACT_FILE_AS);
- tempstr = g_strdup_printf (_("vCard for %s"), file_as);
- description = CORBA_string_dup (tempstr);
- g_free (tempstr);
- g_free (file_as);
- }
+ camel_mime_part_set_content (
+ attachment, data, strlen (data), "text/x-vcard");
- show_inline = FALSE;
+ if (contacts->next != NULL)
+ camel_mime_part_set_description (
+ attachment, _("Multiple vCards"));
+ else {
+ EContact *contact = contacts->data;
+ const gchar *file_as;
+ gchar *description;
- tempstr = eab_contact_list_to_string (contacts);
- attach_data = GNOME_Evolution_Composer_AttachmentData__alloc();
- attach_data->_maximum = attach_data->_length = strlen (tempstr);
- attach_data->_buffer = CORBA_sequence_CORBA_char_allocbuf (attach_data->_length);
- memcpy (attach_data->_buffer, tempstr, attach_data->_length);
- g_free (tempstr);
-
- GNOME_Evolution_Composer_attachData (composer_server,
- content_type, filename, description,
- show_inline, attach_data,
- &ev);
-
- if (ev._major != CORBA_NO_EXCEPTION) {
- g_printerr ("gui/e-meeting-edit.c: I couldn't attach data to the composer via CORBA! Aagh.\n");
- CORBA_exception_free (&ev);
- return;
+ file_as = e_contact_get_const (contact, E_CONTACT_FILE_AS);
+ description = g_strdup_printf (_("vCard for %s"), file_as);
+ camel_mime_part_set_description (attachment, description);
+ g_free (description);
}
- CORBA_free (content_type);
- CORBA_free (filename);
- CORBA_free (description);
- CORBA_free (attach_data);
-
- to_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- to_list->_maximum = to_list->_length = 0;
-
- cc_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- cc_list->_maximum = cc_list->_length = 0;
+ camel_mime_part_set_disposition (attachment, "attachment");
- bcc_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- bcc_list->_maximum = bcc_list->_length = 0;
+ e_msg_composer_attach (composer, attachment);
+ camel_object_unref (attachment);
- if (!contacts || contacts->next) {
- subject = CORBA_string_dup (_("Contact information"));
- } else {
+ if (contacts->next != NULL)
+ e_composer_header_table_set_subject (
+ table, _("Contact information"));
+ else {
EContact *contact = contacts->data;
+ gchar *tempstr;
const gchar *tempstr2;
gchar *tempfree = NULL;
@@ -1052,27 +928,14 @@
tempstr = g_strdup_printf (_("Contact information"));
else
tempstr = g_strdup_printf (_("Contact information for %s"), tempstr2);
- subject = CORBA_string_dup (tempstr);
- g_free (tempstr);
- g_free (tempfree);
- }
- GNOME_Evolution_Composer_setHeaders (composer_server, "", to_list, cc_list, bcc_list, subject, &ev);
+ e_composer_header_table_set_subject (table, tempstr);
- CORBA_free (to_list);
- CORBA_free (cc_list);
- CORBA_free (bcc_list);
- CORBA_free (subject);
-
- GNOME_Evolution_Composer_show (composer_server, &ev);
-
- if (ev._major != CORBA_NO_EXCEPTION) {
- g_printerr ("gui/e-meeting-edit.c: I couldn't show the composer via CORBA! Aagh.\n");
- CORBA_exception_free (&ev);
- return;
+ g_free (tempstr);
+ g_free (tempfree);
}
- CORBA_exception_free (&ev);
+ gtk_widget_show (GTK_WIDGET (composer));
}
void
Modified: branches/mbarnes-composer/calendar/gui/Makefile.am
==============================================================================
--- branches/mbarnes-composer/calendar/gui/Makefile.am (original)
+++ branches/mbarnes-composer/calendar/gui/Makefile.am Sat Feb 9 21:54:02 2008
@@ -5,7 +5,6 @@
## CORBA stuff
IDLS = \
- $(top_srcdir)/composer/Evolution-Composer.idl \
$(top_srcdir)/calendar/idl/evolution-calendar.idl
CALENDAR_IDL_GENERATED_H = \
@@ -21,23 +20,6 @@
$(top_srcdir)/calendar/idl/evolution-calendar.idl
$(CALENDAR_IDL_GENERATED_C): $(CALENDAR_IDL_GENERATED_H)
-# Message composer IDL files
-
-COMPOSER_IDL_GENERATED_H = \
- Evolution-Composer.h
-COMPOSER_IDL_GENERATED_C = \
- Evolution-Composer-common.c \
- Evolution-Composer-skels.c \
- Evolution-Composer-stubs.c
-COMPOSER_IDL_GENERATED = $(COMPOSER_IDL_GENERATED_C) $(COMPOSER_IDL_GENERATED_H)
-
-$(COMPOSER_IDL_GENERATED_H): $(IDLS)
- $(ORBIT_IDL) -I $(srcdir) $(IDL_INCLUDES) \
- $(srcdir)/../../composer/Evolution-Composer.idl
-$(COMPOSER_IDL_GENERATED_C): $(COMPOSER_IDL_GENERATED_H)
-
-IDL_GENERATED = $(CALENDAR_IDL_GENERATED) $(COMPOSER_IDL_GENERATED)
-
# The marshallers
MARSHAL_GENERATED = e-calendar-marshal.c e-calendar-marshal.h
@EVO_MARSHAL_RULE@
Modified: branches/mbarnes-composer/calendar/gui/itip-utils.c
==============================================================================
--- branches/mbarnes-composer/calendar/gui/itip-utils.c (original)
+++ branches/mbarnes-composer/calendar/gui/itip-utils.c Sat Feb 9 21:54:02 2008
@@ -24,9 +24,6 @@
#include <config.h>
#endif
-#include <bonobo/bonobo-exception.h>
-#include <bonobo/bonobo-object.h>
-#include <bonobo/bonobo-moniker-util.h>
#include <glib/gi18n.h>
#include <libedataserver/e-time-utils.h>
#include <gtk/gtkmessagedialog.h>
@@ -41,7 +38,8 @@
#include "itip-utils.h"
#include <time.h>
-#define GNOME_EVOLUTION_COMPOSER_OAFIID "OAFIID:GNOME_Evolution_Mail_Composer:" BASE_VERSION
+#include <composer/e-msg-composer.h>
+#include <camel/camel-mime-filter-tohtml.h>
static gchar *itip_methods[] = {
"PUBLISH",
@@ -408,36 +406,28 @@
return FALSE;
}
-static CORBA_char *
+static gchar *
comp_from (ECalComponentItipMethod method, ECalComponent *comp)
{
ECalComponentOrganizer organizer;
ECalComponentAttendee *attendee;
GSList *attendees;
- CORBA_char *str;
+ gchar *from;
char *sender = NULL;
switch (method) {
case E_CAL_COMPONENT_METHOD_PUBLISH:
- return CORBA_string_dup ("");
+ return NULL;
case E_CAL_COMPONENT_METHOD_REQUEST:
- sender = itip_get_comp_attendee (comp, NULL);
- if (sender) {
- str = CORBA_string_dup (sender);
- g_free (sender);
- return str;
- }
+ return itip_get_comp_attendee (comp, NULL);
case E_CAL_COMPONENT_METHOD_REPLY:
sender = itip_get_comp_attendee (comp, NULL);
- if (sender) {
- str = CORBA_string_dup (sender);
- g_free (sender);
- return str;
- }
+ if (sender != NULL)
+ return sender;
if (!e_cal_component_has_attendees (comp))
- return CORBA_string_dup ("");
+ return NULL;
case E_CAL_COMPONENT_METHOD_CANCEL:
@@ -449,32 +439,40 @@
_("An organizer must be set."));
return NULL;
}
- return CORBA_string_dup (itip_strip_mailto (organizer.value));
+ return g_strdup (itip_strip_mailto (organizer.value));
default:
if (!e_cal_component_has_attendees (comp))
- return CORBA_string_dup ("");
+ return NULL;
e_cal_component_get_attendee_list (comp, &attendees);
attendee = attendees->data;
- str = CORBA_string_dup (attendee->value ? itip_strip_mailto (attendee->value) : "");
+ if (attendee->value != NULL)
+ from = g_strdup (itip_strip_mailto (attendee->value));
+ else
+ from = NULL;
e_cal_component_free_attendee_list (attendees);
- return str;
+ return from;
}
}
-static GNOME_Evolution_Composer_RecipientList *
+static EDestination **
comp_to_list (ECalComponentItipMethod method, ECalComponent *comp, GList *users, gboolean reply_all)
{
- GNOME_Evolution_Composer_RecipientList *to_list;
- GNOME_Evolution_Composer_Recipient *recipient;
ECalComponentOrganizer organizer;
GSList *attendees, *l;
+ GPtrArray *array = NULL;
+ EDestination *destination;
gint len;
char *sender = NULL;
+ union {
+ gpointer *pdata;
+ EDestination **destinations;
+ } convert;
+
switch (method) {
case E_CAL_COMPONENT_METHOD_REQUEST:
case E_CAL_COMPONENT_METHOD_CANCEL:
@@ -487,11 +485,6 @@
return NULL;
}
- to_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- to_list->_maximum = len;
- to_list->_length = 0;
- to_list->_buffer = CORBA_sequence_GNOME_Evolution_Composer_Recipient_allocbuf (len);
-
e_cal_component_get_organizer (comp, &organizer);
if (organizer.value == NULL) {
e_notice (NULL, GTK_MESSAGE_ERROR,
@@ -499,6 +492,8 @@
return NULL;
}
+ array = g_ptr_array_new ();
+
sender = itip_get_comp_attendee (comp, NULL);
for (l = attendees; l != NULL; l = l->next) {
@@ -518,14 +513,12 @@
&& !(att->rsvp) && method == E_CAL_COMPONENT_METHOD_REQUEST)
continue;
- recipient = &(to_list->_buffer[to_list->_length]);
- if (att->cn)
- recipient->name = CORBA_string_dup (att->cn);
- else
- recipient->name = CORBA_string_dup ("");
- recipient->address = CORBA_string_dup (itip_strip_mailto (att->value));
-
- to_list->_length++;
+ destination = e_destination_new ();
+ if (att->cn != NULL)
+ e_destination_set_name (destination, att->cn);
+ e_destination_set_email (
+ destination, itip_strip_mailto (att->value));
+ g_ptr_array_add (array, destination);
}
g_free (sender);
e_cal_component_free_attendee_list (attendees);
@@ -537,19 +530,10 @@
e_cal_component_get_attendee_list (comp, &attendees);
len = g_slist_length (attendees);
- if (len <= 0) {
- to_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- to_list->_maximum = len;
- to_list->_length = 0;
- to_list->_buffer = CORBA_sequence_GNOME_Evolution_Composer_Recipient_allocbuf (len);
- e_cal_component_free_attendee_list (attendees);
- return to_list;
- }
+ if (len <= 0)
+ return NULL;
- to_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- to_list->_maximum = len;
- to_list->_length = 0;
- to_list->_buffer = CORBA_sequence_GNOME_Evolution_Composer_Recipient_allocbuf (len);
+ array = g_ptr_array_new ();
e_cal_component_get_organizer (comp, &organizer);
sender = itip_get_comp_attendee (comp, NULL);
@@ -557,39 +541,26 @@
for (l = attendees; l != NULL; l = l->next) {
ECalComponentAttendee *att = l->data;
-
- recipient = &(to_list->_buffer[to_list->_length]);
- if (att->cn)
- recipient->name = CORBA_string_dup (att->cn);
- else
- recipient->name = CORBA_string_dup ("");
- recipient->address = CORBA_string_dup (itip_strip_mailto (att->value));
-
- to_list->_length++;
+ destination = e_destination_new ();
+ if (att->cn != NULL)
+ e_destination_set_name (destination, att->cn);
+ e_destination_set_email (
+ destination, itip_strip_mailto (att->value));
+ g_ptr_array_add (array, destination);
}
g_free (sender);
e_cal_component_free_attendee_list (attendees);
} else {
+ array = g_ptr_array_new ();
- to_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- to_list->_maximum = 1;
- to_list->_length = 0;
- to_list->_buffer = CORBA_sequence_GNOME_Evolution_Composer_Recipient_allocbuf (1);
-
- recipient = &(to_list->_buffer[to_list->_length]);
-
+ destination = e_destination_new ();
e_cal_component_get_organizer (comp, &organizer);
- if (organizer.value) {
- recipient->name = CORBA_string_dup ("");
- recipient->address = CORBA_string_dup (itip_strip_mailto (organizer.value));
- to_list->_length++;
- return to_list;
- } else {
- recipient->address = CORBA_string_dup ("");
- recipient->name = CORBA_string_dup ("");
- }
+ if (organizer.value)
+ e_destination_set_email (
+ destination, itip_strip_mailto (organizer.value));
+ g_ptr_array_add (array, destination);
}
break;
@@ -605,20 +576,14 @@
return NULL;
}
- len = 2;
-
- to_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- to_list->_maximum = len;
- to_list->_length = 0;
- to_list->_buffer = CORBA_sequence_GNOME_Evolution_Composer_Recipient_allocbuf (len);
- recipient = &(to_list->_buffer[0]);
- to_list->_length++;
+ array = g_ptr_array_new ();
+ destination = e_destination_new ();
if (organizer.cn != NULL)
- recipient->name = CORBA_string_dup (organizer.cn);
- else
- recipient->name = CORBA_string_dup ("");
- recipient->address = CORBA_string_dup (itip_strip_mailto (organizer.value));
+ e_destination_set_name (destination, organizer.cn);
+ e_destination_set_email (
+ destination, itip_strip_mailto (organizer.value));
+ g_ptr_array_add (array, destination);
/* send the status to delegatee to the delegate also*/
e_cal_component_get_attendee_list (comp, &attendees);
@@ -632,10 +597,10 @@
if (!(att->delfrom && *att->delfrom))
break;
- recipient = &(to_list->_buffer[to_list->_length]);
- recipient->name = CORBA_string_dup ("");
- recipient->address = CORBA_string_dup (itip_strip_mailto (att->delfrom));
- to_list->_length++;
+ destination = e_destination_new ();
+ e_destination_set_email (
+ destination, itip_strip_mailto (att->delfrom));
+ g_ptr_array_add (array, destination);
}
}
@@ -646,38 +611,37 @@
if(users) {
GList *list;
- len = g_list_length (users);
- to_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- to_list->_maximum = len;
- to_list->_length = 0;
- to_list->_buffer = CORBA_sequence_GNOME_Evolution_Composer_Recipient_allocbuf (len);
+ array = g_ptr_array_new ();
for (list = users; list != NULL; list = list->next) {
- recipient = &(to_list->_buffer[to_list->_length]);
- recipient->name = CORBA_string_dup ("");
- recipient->address = CORBA_string_dup (list->data);
- to_list->_length++;
+ destination = e_destination_new ();
+ e_destination_set_email (destination, list->data);
+ g_ptr_array_add (array, destination);
}
break;
}
default:
- to_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- to_list->_maximum = to_list->_length = 0;
break;
}
- CORBA_sequence_set_release (to_list, TRUE);
- return to_list;
+ if (array == NULL)
+ return NULL;
+
+ convert.pdata = array->pdata;
+ g_ptr_array_add (array, NULL);
+ g_ptr_array_free (array, FALSE);
+
+ return convert.destinations;
}
-static CORBA_char *
+static gchar *
comp_subject (ECalComponentItipMethod method, ECalComponent *comp)
{
ECalComponentText caltext;
const char *description, *prefix = NULL;
GSList *alist, *l;
- CORBA_char *subject;
+ gchar *subject;
char *sender;
ECalComponentAttendee *a = NULL;
@@ -767,54 +731,49 @@
break;
}
- if (prefix) {
- subject = CORBA_string_alloc (strlen (description) +
- strlen (prefix) + 3);
- sprintf (subject, "%s: %s", prefix, description);
- } else
- subject = CORBA_string_dup (description);
+ if (prefix != NULL)
+ subject = g_strdup_printf ("%s: %s", prefix, description);
+ else
+ subject = g_strdup (description);
return subject;
}
-static CORBA_char *
+static gchar *
comp_content_type (ECalComponent *comp, ECalComponentItipMethod method)
{
- char tmp[256];
-
- sprintf (tmp, "text/calendar; name=\"%s\"; charset=utf-8; METHOD=%s",
- e_cal_component_get_vtype (comp) == E_CAL_COMPONENT_FREEBUSY ?
- "freebusy.ifb" : "calendar.ics", itip_methods[method]);
-
- return CORBA_string_dup (tmp);
-
+ return g_strdup_printf (
+ "text/calendar; name=\"%s\"; charset=utf-8; METHOD=%s",
+ e_cal_component_get_vtype (comp) == E_CAL_COMPONENT_FREEBUSY ?
+ "freebusy.ifb" : "calendar.ics", itip_methods[method]);
}
-static CORBA_char *
+static const gchar *
comp_filename (ECalComponent *comp)
{
- switch (e_cal_component_get_vtype (comp)) {
- case E_CAL_COMPONENT_FREEBUSY:
- return CORBA_string_dup ("freebusy.ifb");
- default:
- return CORBA_string_dup ("calendar.ics");
- }
+ if (e_cal_component_get_vtype (comp) == E_CAL_COMPONENT_FREEBUSY)
+ return "freebusy.ifb";
+ else
+ return "calendar.ics";
}
-static CORBA_char *
+static gchar *
comp_description (ECalComponent *comp)
{
- CORBA_char *description;
+ gchar *description;
ECalComponentDateTime dt;
char *start = NULL, *end = NULL;
switch (e_cal_component_get_vtype (comp)) {
case E_CAL_COMPONENT_EVENT:
- return CORBA_string_dup (_("Event information"));
+ description = g_strdup (_("Event information"));
+ break;
case E_CAL_COMPONENT_TODO:
- return CORBA_string_dup (_("Task information"));
+ description = g_strdup (_("Task information"));
+ break;
case E_CAL_COMPONENT_JOURNAL:
- return CORBA_string_dup (_("Memo information"));
+ description = g_strdup (_("Memo information"));
+ break;
case E_CAL_COMPONENT_FREEBUSY:
e_cal_component_get_dtstart (comp, &dt);
if (dt.value)
@@ -826,20 +785,21 @@
end = get_label (dt.value);
e_cal_component_free_datetime (&dt);
- if (start != NULL && end != NULL) {
- char *tmp;
- tmp = g_strdup_printf (_("Free/Busy information (%s to %s)"), start, end);
- description = CORBA_string_dup (tmp);
- g_free (tmp);
- } else {
- description = CORBA_string_dup (_("Free/Busy information"));
- }
+ if (start != NULL && end != NULL)
+ description = g_strdup_printf (
+ _("Free/Busy information (%s to %s)"),
+ start, end);
+ else
+ description = g_strdup (_("Free/Busy information"));
g_free (start);
g_free (end);
- return description;
+ break;
default:
- return CORBA_string_dup (_("iCalendar information"));
+ description = g_strdup (_("iCalendar information"));
+ break;
}
+
+ return description;
}
static gboolean
@@ -1159,84 +1119,64 @@
return clone;
}
-static gboolean
-append_cal_attachments (GNOME_Evolution_Composer composer_server, ECalComponent
- *comp, GSList *attach_list)
+static void
+append_cal_attachments (EMsgComposer *composer,
+ ECalComponent *comp,
+ GSList *attach_list)
{
- CORBA_char *content_type = NULL, *filename = NULL, *description = NULL;
- CORBA_Environment ev;
- GNOME_Evolution_Composer_AttachmentData *attach_data = NULL;
struct CalMimeAttach *mime_attach;
GSList *l;
- gboolean retval = TRUE;
-
- CORBA_exception_init (&ev);
for (l = attach_list; l ; l = l->next) {
+ CamelMimePart *attachment;
+
mime_attach = (struct CalMimeAttach *) l->data;
- filename = CORBA_string_dup (mime_attach->filename ? mime_attach->filename : "");
- content_type = CORBA_string_dup (mime_attach->content_type);
- description = CORBA_string_dup (mime_attach->description);
-
- attach_data = GNOME_Evolution_Composer_AttachmentData__alloc ();
- attach_data->_length = mime_attach->length;
- attach_data->_maximum = attach_data->_length;
- attach_data->_buffer = CORBA_sequence_CORBA_char_allocbuf (attach_data->_length);
- memcpy (attach_data->_buffer, mime_attach->encoded_data, attach_data->_length);
-
- GNOME_Evolution_Composer_attachData (composer_server,
- content_type, filename, description,
- mime_attach->disposition, attach_data,
- &ev);
- if (BONOBO_EX (&ev)) {
- g_warning ("Unable to add attachments in composer");
- retval = FALSE;
- }
+ attachment = camel_mime_part_new ();
+ camel_mime_part_set_content (
+ attachment, mime_attach->encoded_data,
+ mime_attach->length, mime_attach->content_type);
+ if (mime_attach->filename != NULL)
+ camel_mime_part_set_filename (
+ attachment, mime_attach->filename);
+ if (mime_attach->description != NULL)
+ camel_mime_part_set_description (
+ attachment, mime_attach->description);
+ if (mime_attach->disposition)
+ camel_mime_part_set_disposition (
+ attachment, "inline");
+ else
+ camel_mime_part_set_disposition (
+ attachment, "attachment");
+ e_msg_composer_attach (composer, attachment);
+ camel_object_unref (attachment);
- CORBA_exception_free (&ev);
- if (content_type != NULL)
- CORBA_free (content_type);
- if (filename != NULL)
- CORBA_free (filename);
- if (description != NULL)
- CORBA_free (description);
- if (attach_data != NULL) {
- CORBA_free (attach_data->_buffer);
- CORBA_free (attach_data);
- }
g_free (mime_attach->filename);
g_free (mime_attach->content_type);
g_free (mime_attach->description);
g_free (mime_attach->encoded_data);
}
-
- return retval;
}
gboolean
itip_send_comp (ECalComponentItipMethod method, ECalComponent *send_comp,
ECal *client, icalcomponent *zones, GSList *attachments_list, GList *users)
{
- GNOME_Evolution_Composer composer_server;
+ EMsgComposer *composer;
+ EComposerHeaderTable *table;
+ EDestination **destinations;
ECalComponent *comp = NULL;
icalcomponent *top_level = NULL;
- GNOME_Evolution_Composer_RecipientList *to_list = NULL;
- GNOME_Evolution_Composer_RecipientList *cc_list = NULL;
- GNOME_Evolution_Composer_RecipientList *bcc_list = NULL;
- CORBA_char *subject = NULL, *body = NULL, *content_type = NULL;
- CORBA_char *from = NULL, *filename = NULL, *description = NULL;
- GNOME_Evolution_Composer_AttachmentData *attach_data = NULL;
char *ical_string;
- CORBA_Environment ev;
+ gchar *from;
+ gchar *content_type;
+ gchar *subject;
gboolean retval = FALSE;
/* check whether backend could handle sending requests/updates */
if (method != E_CAL_COMPONENT_METHOD_PUBLISH && e_cal_get_save_schedules (client))
return TRUE;
- CORBA_exception_init (&ev);
-
/* Give the server a chance to manipulate the comp */
if (method != E_CAL_COMPONENT_METHOD_PUBLISH) {
if (!comp_server_send (method, send_comp, client, zones, &users))
@@ -1250,46 +1190,29 @@
goto cleanup;
/* Recipients */
- to_list = comp_to_list (method, comp, users, FALSE);
+ destinations = comp_to_list (method, comp, users, FALSE);
if (method != E_CAL_COMPONENT_METHOD_PUBLISH) {
- if (to_list == NULL || to_list->_length == 0) {
+ if (destinations == NULL) {
/* We sent them all via the server */
retval = TRUE;
goto cleanup;
- } else if (to_list == NULL || to_list->_length == 0) {
- /* if we don't have recipients, return */
- retval = FALSE;
- goto cleanup;
}
}
- cc_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- cc_list->_maximum = cc_list->_length = 0;
- bcc_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- bcc_list->_maximum = bcc_list->_length = 0;
-
/* Subject information */
subject = comp_subject (method, comp);
/* From address */
from = comp_from (method, comp);
- /* Obtain an object reference for the Composer. */
- composer_server = bonobo_activation_activate_from_id (GNOME_EVOLUTION_COMPOSER_OAFIID, 0, NULL, &ev);
- if (BONOBO_EX (&ev)) {
- g_warning ("Could not activate composer: %s", bonobo_exception_get_text (&ev));
- CORBA_exception_free (&ev);
- return FALSE;
- }
+ composer = e_msg_composer_new ();
+ table = e_msg_composer_get_header_table (composer);
- /* Set recipients, subject */
- GNOME_Evolution_Composer_setHeaders (composer_server, from, to_list, cc_list, bcc_list, subject, &ev);
- if (BONOBO_EX (&ev)) {
- g_warning ("Unable to set composer headers while sending iTip message: %s",
- bonobo_exception_get_text (&ev));
- goto cleanup;
- }
+ e_composer_header_table_set_subject (table, subject);
+ e_composer_header_table_set_account_name (table, from);
+ e_composer_header_table_set_destinations_to (table, destinations);
+ e_destination_freev (destinations);
/* Content type */
content_type = comp_content_type (comp, method);
@@ -1298,62 +1221,46 @@
ical_string = icalcomponent_as_ical_string (top_level);
if (e_cal_component_get_vtype (comp) == E_CAL_COMPONENT_EVENT) {
- GNOME_Evolution_Composer_setBody (composer_server, ical_string, content_type, &ev);
+ e_msg_composer_set_body (composer, ical_string, content_type);
} else {
- GNOME_Evolution_Composer_setMultipartType (composer_server, GNOME_Evolution_Composer_MIXED, &ev);
- if (BONOBO_EX (&ev)) {
- g_warning ("Unable to set multipart type while sending iTip message");
- goto cleanup;
- }
+ CamelMimePart *attachment;
+ const gchar *filename;
+ gchar *description;
+ gchar *body;
filename = comp_filename (comp);
description = comp_description (comp);
- GNOME_Evolution_Composer_setBody (composer_server, description, "text/plain", &ev);
- if (BONOBO_EX (&ev)) {
- g_warning ("Unable to set body text while sending iTip message");
- goto cleanup;
- }
+ body = camel_text_to_html (
+ body, CAMEL_MIME_FILTER_TOHTML_PRE, 0);
+ e_msg_composer_set_body_text (composer, body, -1);
+ g_free (body);
+
+ attachment = camel_mime_part_new ();
+ camel_mime_part_set_content (
+ attachment, ical_string,
+ strlen (ical_string), content_type);
+ if (filename != NULL && *filename != '\0')
+ camel_mime_part_set_filename (attachment, filename);
+ if (description != NULL && *description != '\0')
+ camel_mime_part_set_description (attachment, description);
+ camel_mime_part_set_disposition (attachment, "inline");
+ e_msg_composer_attach (composer, attachment);
+ camel_object_unref (attachment);
- attach_data = GNOME_Evolution_Composer_AttachmentData__alloc ();
- attach_data->_length = strlen (ical_string);
- attach_data->_maximum = attach_data->_length;
- attach_data->_buffer = CORBA_sequence_CORBA_char_allocbuf (attach_data->_length);
- memcpy (attach_data->_buffer, ical_string, attach_data->_length);
-
- GNOME_Evolution_Composer_attachData (composer_server,
- content_type, filename, description,
- TRUE, attach_data,
- &ev);
+ g_free (description);
}
- if (BONOBO_EX (&ev)) {
- g_warning ("Unable to place iTip message in composer");
- goto cleanup;
- }
+ append_cal_attachments (composer, comp, attachments_list);
- if (attachments_list) {
- if (append_cal_attachments (composer_server, comp, attachments_list))
- retval = TRUE;
- }
+ if ((method == E_CAL_COMPONENT_METHOD_PUBLISH) && !users)
+ gtk_widget_show (GTK_WIDGET (composer));
+ else
+ e_msg_composer_send (composer);
- if ((method == E_CAL_COMPONENT_METHOD_PUBLISH) && !users) {
- GNOME_Evolution_Composer_show (composer_server, &ev);
- if (BONOBO_EX (&ev))
- g_warning ("Unable to show the composer while sending iTip message");
- else
- retval = TRUE;
- } else {
- GNOME_Evolution_Composer_send (composer_server, &ev);
- if (BONOBO_EX (&ev))
- g_warning ("Unable to send iTip message");
- else
- retval = TRUE;
- }
+ retval = TRUE;
cleanup:
- CORBA_exception_free (&ev);
-
if (comp != NULL)
g_object_unref (comp);
if (top_level != NULL)
@@ -1364,65 +1271,39 @@
g_list_free (users);
}
- if (to_list != NULL)
- CORBA_free (to_list);
- if (cc_list != NULL)
- CORBA_free (cc_list);
- if (bcc_list != NULL)
- CORBA_free (bcc_list);
-
- if (from != NULL)
- CORBA_free (from);
- if (subject != NULL)
- CORBA_free (subject);
- if (body != NULL)
- CORBA_free (body);
- if (content_type != NULL)
- CORBA_free (content_type);
- if (filename != NULL)
- CORBA_free (filename);
- if (description != NULL)
- CORBA_free (description);
- if (attach_data != NULL) {
- CORBA_free (attach_data->_buffer);
- CORBA_free (attach_data);
- }
+ g_free (from);
+ g_free (content_type);
+ g_free (subject);
return retval;
}
gboolean
-reply_to_calendar_comp (ECalComponentItipMethod method, ECalComponent *send_comp,
- ECal *client, gboolean reply_all, icalcomponent *zones, GSList *attachments_list)
-{
- GNOME_Evolution_Composer composer_server;
+reply_to_calendar_comp (ECalComponentItipMethod method,
+ ECalComponent *send_comp,
+ ECal *client,
+ gboolean reply_all,
+ icalcomponent *zones,
+ GSList *attachments_list)
+{
+ EMsgComposer *composer;
+ EComposerHeaderTable *table;
+ EDestination **destinations;
ECalComponent *comp = NULL;
icalcomponent *top_level = NULL;
GList *users = NULL;
- GNOME_Evolution_Composer_RecipientList *to_list = NULL;
- GNOME_Evolution_Composer_RecipientList *cc_list = NULL;
- GNOME_Evolution_Composer_RecipientList *bcc_list = NULL;
- CORBA_char *subject = NULL, *content_type = NULL;
- char tmp [256];
- CORBA_char *from = NULL;
+ gchar *from;
+ gchar *subject;
char *ical_string;
- CORBA_Environment ev;
gboolean retval = FALSE;
- CORBA_exception_init (&ev);
-
/* Tidy up the comp */
comp = comp_compliant (method, send_comp, client, zones);
if (comp == NULL)
goto cleanup;
/* Recipients */
- to_list = comp_to_list (method, comp, users, reply_all);
-
- cc_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- cc_list->_maximum = cc_list->_length = 0;
- bcc_list = GNOME_Evolution_Composer_RecipientList__alloc ();
- bcc_list->_maximum = bcc_list->_length = 0;
+ destinations = comp_to_list (method, comp, users, reply_all);
/* Subject information */
subject = comp_subject (method, comp);
@@ -1430,26 +1311,14 @@
/* From address */
from = comp_from (method, comp);
- /* Obtain an object reference for the Composer. */
- composer_server = bonobo_activation_activate_from_id (GNOME_EVOLUTION_COMPOSER_OAFIID, 0, NULL, &ev);
- if (BONOBO_EX (&ev)) {
- g_warning ("Could not activate composer: %s", bonobo_exception_get_text (&ev));
- CORBA_exception_free (&ev);
- return FALSE;
- }
+ composer = e_msg_composer_new ();
+ table = e_msg_composer_get_header_table (composer);
- /* Set recipients, subject */
- GNOME_Evolution_Composer_setHeaders (composer_server, from, to_list, cc_list, bcc_list, subject, &ev);
- if (BONOBO_EX (&ev)) {
- g_warning ("Unable to set composer headers while sending iTip message: %s",
- bonobo_exception_get_text (&ev));
- goto cleanup;
- }
+ e_composer_header_table_set_subject (table, subject);
+ e_composer_header_table_set_account_name (table, from);
+ e_composer_header_table_set_destinations_to (table, destinations);
-
- /* Content type */
- sprintf (tmp, "text/plain");
- content_type = CORBA_string_dup (tmp);
+ e_destination_freev (destinations);
top_level = comp_toplevel_with_zones (method, comp, client, zones);
ical_string = icalcomponent_as_ical_string (top_level);
@@ -1546,25 +1415,15 @@
g_string_append (body, html_description);
g_free (html_description);
- GNOME_Evolution_Composer_setBody (composer_server, body->str, "text/html", &ev);
+ e_msg_composer_set_body_text (composer, body->str, -1);
g_string_free (body, TRUE);
-
- if (BONOBO_EX (&ev)) {
- g_warning ("Unable to set body text while sending iTip message");
- goto cleanup;
- }
-
}
+ gtk_widget_show (GTK_WIDGET (composer));
- GNOME_Evolution_Composer_show (composer_server, &ev);
- if (BONOBO_EX (&ev))
- g_warning ("Unable to show the composer while sending iTip message");
- else
- retval = TRUE;
+ retval = TRUE;
cleanup:
- CORBA_exception_free (&ev);
if (comp != NULL)
g_object_unref (comp);
@@ -1576,19 +1435,8 @@
g_list_free (users);
}
- if (to_list != NULL)
- CORBA_free (to_list);
- if (cc_list != NULL)
- CORBA_free (cc_list);
- if (bcc_list != NULL)
- CORBA_free (bcc_list);
-
- if (from != NULL)
- CORBA_free (from);
- if (subject != NULL)
- CORBA_free (subject);
- if (content_type != NULL)
- CORBA_free (content_type);
+ g_free (from);
+ g_free (subject);
return retval;
}
Modified: branches/mbarnes-composer/composer/Makefile.am
==============================================================================
--- branches/mbarnes-composer/composer/Makefile.am (original)
+++ branches/mbarnes-composer/composer/Makefile.am Sat Feb 9 21:54:02 2008
@@ -1,32 +1,3 @@
-## CORBA stuff
-
-IDLS = \
- Evolution-Composer.idl \
- Composer.idl
-
-IDL_GENERATED = \
- Composer.h \
- Composer-common.c \
- Composer-skels.c \
- Composer-stubs.c
-
-HTML_EDITOR_GENERATED = \
- Editor.h \
- Editor-common.c \
- Editor-skels.c \
- Editor-stubs.c
-
-$(IDL_GENERATED): $(IDLS)
- $(ORBIT_IDL) -I $(srcdir) -I $(datadir)/idl $(IDL_INCLUDES) \
- $(srcdir)/Composer.idl
-
-Editor-commmon.c: $(GTKHTML_DATADIR)/Editor.idl
-
-$(HTML_EDITOR_GENERATED): $(GTKHTML_DATADIR)/Editor.idl
- $(ORBIT_IDL) -I $(srcdir) $(IDL_INCLUDES) -I $(GTKHTML_DATADIR)/gtkhtml $(GTKHTML_DATADIR)/Editor.idl
-
-##
-
error_DATA = mail-composer.error
errordir = $(privdatadir)/errors
@@ -80,10 +51,8 @@
e-msg-composer-select-file.h \
e-msg-composer.c \
e-msg-composer.h \
- evolution-composer.c \
- evolution-composer.h \
- listener.c \
- listener.h
+ gconf-bridge.c \
+ gconf-bridge.h
EXTRA_DIST = \
mail-composer.error.xml \
Modified: branches/mbarnes-composer/composer/e-composer-actions.c
==============================================================================
--- branches/mbarnes-composer/composer/e-composer-actions.c (original)
+++ branches/mbarnes-composer/composer/e-composer-actions.c Sat Feb 9 21:54:02 2008
@@ -101,16 +101,14 @@
action_save_draft_cb (GtkAction *action,
EMsgComposer *composer)
{
- g_signal_emit_by_name (composer, "save-draft", FALSE);
- e_msg_composer_unset_changed (composer);
- e_msg_composer_unset_autosaved (composer);
+ e_msg_composer_save_draft (composer);
}
static void
action_send_cb (GtkAction *action,
EMsgComposer *composer)
{
- g_signal_emit_by_name (composer, "send");
+ e_msg_composer_send (composer);
}
static void
Modified: branches/mbarnes-composer/composer/e-composer-private.h
==============================================================================
--- branches/mbarnes-composer/composer/e-composer-private.h (original)
+++ branches/mbarnes-composer/composer/e-composer-private.h Sat Feb 9 21:54:02 2008
@@ -4,6 +4,7 @@
#include "e-composer-common.h"
#include <glib/gi18n.h>
+#include <gtkhtml-editor.h>
#include "e-msg-composer.h"
#include "e-composer-actions.h"
@@ -64,10 +65,6 @@
guint notify_id;
gboolean send_invoked;
-
- GtkWidget *saveas; /* saveas async file requester */
- GtkWidget *load; /* same for load - not used */
-
};
G_END_DECLS
Modified: branches/mbarnes-composer/composer/e-msg-composer-select-file.c
==============================================================================
--- branches/mbarnes-composer/composer/e-msg-composer-select-file.c (original)
+++ branches/mbarnes-composer/composer/e-msg-composer-select-file.c Sat Feb 9 21:54:02 2008
@@ -44,160 +44,55 @@
#include "e-msg-composer.h"
#include "e-attachment-bar.h"
-enum {
- SELECTOR_MODE_MULTI = (1 << 0),
- SELECTOR_MODE_SAVE = (1 << 1),
- SELECTOR_SHOW_INLINE = 1<<2
-};
-
-/* this is a mess */
-
-static GtkWidget*
-get_selector(struct _EMsgComposer *composer, const char *title, guint32 flags)
+void
+e_msg_composer_select_file_attachments (EMsgComposer *composer,
+ EMsgComposerSelectAttachFunc func)
{
- GtkWidget *selection;
- GtkWidget *showinline = NULL;
- GList *icon_list;
- const char *path;
-
- path = e_msg_composer_get_attach_path (composer);
-
- if (flags & SELECTOR_MODE_SAVE)
- selection = gtk_file_chooser_dialog_new (title,
- NULL,
- GTK_FILE_CHOOSER_ACTION_SAVE,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_SAVE, GTK_RESPONSE_OK,
- NULL);
- else
- selection = gtk_file_chooser_dialog_new (title,
- NULL,
- GTK_FILE_CHOOSER_ACTION_OPEN,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- _("A_ttach"), GTK_RESPONSE_OK,
- NULL);
-
- gtk_dialog_set_default_response (GTK_DIALOG (selection), GTK_RESPONSE_OK);
- gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (selection), FALSE);
-
- if ((flags & SELECTOR_MODE_SAVE) == 0)
- gtk_file_chooser_set_select_multiple ((GtkFileChooser *) selection, (flags & SELECTOR_MODE_MULTI));
-
- /* restore last path used */
- if (!path)
- gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (selection), g_get_home_dir ());
- else
- gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (selection), path);
-
- if (flags & SELECTOR_SHOW_INLINE) {
- showinline = gtk_check_button_new_with_mnemonic (_("_Suggest automatic display of attachment"));
- gtk_widget_show (showinline);
- gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (selection), showinline);
- g_object_set_data((GObject *)selection, "show-inline", showinline);
- }
-
- gtk_window_set_transient_for ((GtkWindow *) selection, (GtkWindow *) composer);
- gtk_window_set_wmclass ((GtkWindow *) selection, "fileselection", "Evolution:composer");
- gtk_window_set_modal ((GtkWindow *) selection, FALSE);
-
- icon_list = e_icon_factory_get_icon_list ("mail-message-new");
- if (icon_list) {
- gtk_window_set_icon_list (GTK_WINDOW (selection), icon_list);
- g_list_foreach (icon_list, (GFunc) g_object_unref, NULL);
- g_list_free (icon_list);
- }
-
- return selection;
-}
+ GtkWidget *dialog;
+ GtkWidget *option;
+ GSList *uris;
+ gboolean active;
+ gint response;
+
+ dialog = gtk_file_chooser_dialog_new (
+ _("Insert Attachment"), GTK_WINDOW (composer),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ _("A_ttach"), GTK_RESPONSE_OK,
+ NULL);
+
+ gtk_dialog_set_default_response (
+ GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ gtk_file_chooser_set_local_only (
+ GTK_FILE_CHOOSER (dialog), FALSE);
+ gtk_file_chooser_set_select_multiple (
+ GTK_FILE_CHOOSER (dialog), TRUE);
+ gtk_window_set_icon_name (
+ GTK_WINDOW (dialog), "mail-message-new");
+
+ option = gtk_check_button_new_with_mnemonic (
+ _("_Suggest automatic display of attachment"));
+ gtk_widget_show (option);
+ gtk_file_chooser_set_extra_widget (
+ GTK_FILE_CHOOSER (dialog), option);
+
+ response = gtkhtml_editor_file_chooser_dialog_run (
+ GTKHTML_EDITOR (composer), dialog);
+
+ if (response != GTK_RESPONSE_OK)
+ goto exit;
+
+ uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
+ active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (option));
+
+ func (composer, uris, active);
-static void
-select_file_response(GtkWidget *selector, guint response, struct _EMsgComposer *composer)
-{
- if (response == GTK_RESPONSE_OK) {
- const char *name;
- char *path;
- EMsgComposerSelectFileFunc func = g_object_get_data((GObject *)selector, "callback");
-
- name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (selector));
- path = g_path_get_dirname (gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (selector)));
- e_msg_composer_set_attach_path (composer, path);
- g_free (path);
+ e_msg_composer_show_attachments_ui (composer);
- func(composer, name);
- }
+ g_slist_foreach (uris, (GFunc) g_free, NULL);
+ g_slist_free (uris);
- gtk_widget_destroy(selector);
-}
+exit:
-/**
- * e_msg_composer_select_file:
- * @composer: a composer
- * @w: widget pointer, so same dialog is not re-shown
- * @func: callback invoked if the user selected a file
- * @title: the title for the file selection dialog box
- * @save: whether the file selection box should be shown in save mode or not
- *
- * This pops up a file selection dialog box with the given title
- * and allows the user to select a single file.
- *
- **/
-void e_msg_composer_select_file(struct _EMsgComposer *composer, GtkWidget **w, EMsgComposerSelectFileFunc func, const char *title, int save)
-{
- if (*w) {
- gtk_window_present((GtkWindow *)*w);
- return;
- }
-
- *w = get_selector (composer, title, save ? SELECTOR_MODE_SAVE : 0);
- g_signal_connect(*w, "response", G_CALLBACK(select_file_response), composer);
- g_signal_connect(*w, "destroy", G_CALLBACK(gtk_widget_destroyed), w);
- g_object_set_data((GObject *)*w, "callback", func);
- gtk_widget_show(*w);
-}
-
-
-static void
-select_attach_response(GtkWidget *selector, guint response, struct _EMsgComposer *composer)
-{
- if (response == GTK_RESPONSE_OK) {
- GSList *names;
- EMsgComposerSelectAttachFunc func = g_object_get_data((GObject *)selector, "callback");
- GtkToggleButton *showinline = g_object_get_data((GObject *)selector, "show-inline");
- char *path = NULL;
-
- char *filename = NULL;
- names = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (selector));
- filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (selector));
- if (filename) {
- path = g_path_get_dirname (filename);
- g_free (filename);
- }
- if (path)
- e_msg_composer_set_attach_path (composer, path);
- g_free (path);
-
- func(composer, names, gtk_toggle_button_get_active(showinline));
-
- e_msg_composer_show_attachments_ui (composer);
-
-
- g_slist_foreach(names, (GFunc)g_free, NULL);
- g_slist_free(names);
- }
-
- gtk_widget_destroy(selector);
-}
-
-void e_msg_composer_select_file_attachments(struct _EMsgComposer *composer, GtkWidget **w, EMsgComposerSelectAttachFunc func)
-{
- if (*w) {
- gtk_window_present((GtkWindow *)*w);
- return;
- }
-
- *w = get_selector (composer, _("Insert Attachment"), SELECTOR_MODE_MULTI|SELECTOR_SHOW_INLINE);
- g_signal_connect(*w, "response", G_CALLBACK(select_attach_response), composer);
- g_signal_connect(*w, "destroy", G_CALLBACK(gtk_widget_destroyed), w);
- g_object_set_data((GObject *)*w, "callback", func);
- gtk_widget_show(*w);
+ gtk_widget_destroy (dialog);
}
Modified: branches/mbarnes-composer/composer/e-msg-composer-select-file.h
==============================================================================
--- branches/mbarnes-composer/composer/e-msg-composer-select-file.h (original)
+++ branches/mbarnes-composer/composer/e-msg-composer-select-file.h Sat Feb 9 21:54:02 2008
@@ -24,13 +24,10 @@
#ifndef E_MSG_COMPOSER_SELECT_FILE_H
#define E_MSG_COMPOSER_SELECT_FILE_H
+#include "e-msg-composer.h"
-struct _EMsgComposer;
+typedef void (*EMsgComposerSelectAttachFunc)(EMsgComposer *composer, GSList *names, int isinline);
-typedef void (*EMsgComposerSelectFileFunc)(struct _EMsgComposer *composer, const char *filename);
-typedef void (*EMsgComposerSelectAttachFunc)(struct _EMsgComposer *composer, GSList *names, int isinline);
-
-void e_msg_composer_select_file(struct _EMsgComposer *composer, GtkWidget **w, EMsgComposerSelectFileFunc func, const char *title, int save);
-void e_msg_composer_select_file_attachments(struct _EMsgComposer *composer, GtkWidget **, EMsgComposerSelectAttachFunc func);
+void e_msg_composer_select_file_attachments(EMsgComposer *composer, EMsgComposerSelectAttachFunc func);
#endif /* E_MSG_COMPOSER_SELECT_FILE_H */
Modified: branches/mbarnes-composer/composer/e-msg-composer.c
==============================================================================
--- branches/mbarnes-composer/composer/e-msg-composer.c (original)
+++ branches/mbarnes-composer/composer/e-msg-composer.c Sat Feb 9 21:54:02 2008
@@ -116,19 +116,15 @@
#include "e-composer-private.h"
#include "e-composer-header-table.h"
#include "e-msg-composer-select-file.h"
+#include "gconf-bridge.h"
#include "evolution-shell-component-utils.h"
#include <e-util/e-icon-factory.h>
-#include "Editor.h"
-#include "listener.h"
-
#ifdef HAVE_XFREE
#include <X11/XF86keysym.h>
#endif
-#define GNOME_GTKHTML_EDITOR_CONTROL_ID "OAFIID:GNOME_GtkHTML_Editor:" GTKHTML_API_VERSION
-
#define COMPOSER_CURRENT_FOLDER_KEY "/apps/evolution/mail/composer/current_folder"
#define d(x)
@@ -1120,27 +1116,6 @@
FALSE);
}
-static void
-prepare_engine (EMsgComposer *composer)
-{
- GConfClient *client;
- gchar *path;
-
- /* FIXME Move this to msg_composer_init () */
-
- g_return_if_fail (E_IS_MSG_COMPOSER (composer));
-
- client = gconf_client_get_default ();
- path = gconf_client_get_string (
- client, COMPOSER_CURRENT_FOLDER_KEY, NULL);
- g_object_unref (client);
-
- /* change it only if we have set path before */
- if (path && *path)
- e_msg_composer_set_attach_path (composer, path);
- g_free (path);
-}
-
/**
* e_msg_composer_set_attach_path
* Attach path is used to be preset when choosing files. This function ensures same path
@@ -1172,20 +1147,6 @@
gtkhtml_editor_set_current_folder (GTKHTML_EDITOR (composer), path);
}
-/**
- * e_msg_composer_get_attach_path
- * Last path, if any, used to select file.
- * @param composer Composer.
- * @return Last used path, or NULL when not set yet.
- **/
-const gchar *
-e_msg_composer_get_attach_path (EMsgComposer *composer)
-{
- g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
-
- return gtkhtml_editor_get_current_folder (GTKHTML_EDITOR (composer));
-}
-
static gchar *
encode_signature_name (const gchar *name)
{
@@ -1466,17 +1427,41 @@
}
static void
-saveas_response (EMsgComposer *composer, const gchar *name)
-{
- save (composer, name);
-}
-
-static void
saveas (EMsgComposer *composer)
{
- EMsgComposerPrivate *p = composer->priv;
+ GtkWidget *dialog;
+ gchar *filename;
+ gint response;
+
+ dialog = gtk_file_chooser_dialog_new (
+ _("Save as..."), GTK_WINDOW (composer),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_OK,
+ NULL);
+
+ gtk_dialog_set_default_response (
+ GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ gtk_file_chooser_set_local_only (
+ GTK_FILE_CHOOSER (dialog), FALSE);
+ gtk_window_set_icon_name (
+ GTK_WINDOW (dialog), "mail-message-new");
+
+ response = gtkhtml_editor_file_chooser_dialog_run (
+ GTKHTML_EDITOR (composer), dialog);
+
+ if (response != GTK_RESPONSE_OK)
+ goto exit;
+
+ filename = gtk_file_chooser_get_filename (
+ GTK_FILE_CHOOSER (dialog));
+
+ save (composer, filename);
+
+ g_free (filename);
- e_msg_composer_select_file (composer, &p->saveas, saveas_response, _("Save as..."), TRUE);
+exit:
+ gtk_widget_destroy (dialog);
}
static void
@@ -1658,9 +1643,8 @@
EMsgComposer *composer = E_MSG_COMPOSER (data);
EMsgComposerPrivate *p = composer->priv;
EMsgComposer *toplevel = E_MSG_COMPOSER (gtk_widget_get_toplevel (GTK_WIDGET (p->attachment_bar)));
- GtkWidget **attachment_selector = e_attachment_bar_get_selector (E_ATTACHMENT_BAR(p->attachment_bar));
- e_msg_composer_select_file_attachments (toplevel, attachment_selector, add_to_bar);
+ e_msg_composer_select_file_attachments (toplevel, add_to_bar);
}
static void
@@ -2034,15 +2018,15 @@
active = account->pgp_always_sign &&
(!account->pgp_no_imip_sign || !p->mime_type ||
g_ascii_strncasecmp (p->mime_type, "text/calendar", 13) != 0);
- gtk_toggle_action (action, active);
+ gtk_toggle_action_set_active (action, active);
action = GTK_TOGGLE_ACTION (ACTION (SMIME_SIGN));
active = account->smime_sign_default;
- gtk_toggle_action (action, active);
+ gtk_toggle_action_set_active (action, active);
action = GTK_TOGGLE_ACTION (ACTION (SMIME_ENCRYPT));
active = account->smime_encrypt_default;
- gtk_toggle_action (action, active);
+ gtk_toggle_action_set_active (action, active);
update_auto_recipients (table, UPDATE_AUTO_CC, account->always_cc ? account->cc_addrs : NULL);
update_auto_recipients (table, UPDATE_AUTO_BCC, account->always_bcc ? account->bcc_addrs : NULL);
@@ -2483,23 +2467,6 @@
}
#endif
- if (p->load) {
- gtk_widget_destroy (p->load);
- p->load = NULL;
- }
-
- if (p->saveas) {
- gtk_widget_destroy (p->saveas);
- p->saveas = NULL;
- }
-
-#if 0 /* GTKHTML-EDITOR */
- if (p->uic) {
- bonobo_object_unref (BONOBO_OBJECT (p->uic));
- p->uic = NULL;
- }
-#endif
-
/* FIXME? I assume the Bonobo widget will get destroyed
normally? */
if (p->address_dialog != NULL) {
@@ -2670,6 +2637,10 @@
editor_class->paste_clipboard = msg_composer_paste_clipboard;
editor_class->select_all = msg_composer_select_all;
+ /* These callbacks are in the mail component. */
+ class->send = em_utils_composer_send_cb;
+ class->save_draft = em_utils_composer_save_draft_cb;
+
signals[SEND] =
g_signal_new ("send",
E_TYPE_MSG_COMPOSER,
@@ -2975,9 +2946,8 @@
{
EAttachmentBar *bar = data;
EMsgComposer *toplevel = E_MSG_COMPOSER (gtk_widget_get_toplevel (GTK_WIDGET (bar)));
- GtkWidget **attachment_selector = e_attachment_bar_get_selector (E_ATTACHMENT_BAR(bar));
- e_msg_composer_select_file_attachments (toplevel, attachment_selector, add_to_bar);
+ e_msg_composer_select_file_attachments (toplevel, add_to_bar);
}
static void
@@ -3307,7 +3277,9 @@
#endif /* GTKHTML-EDITOR */
gtk_widget_show (vbox);
- prepare_engine (composer);
+ gconf_bridge_bind_property (
+ gconf_bridge_get (), COMPOSER_CURRENT_FOLDER_KEY,
+ G_OBJECT (composer), "current-folder");
#if 0 /* GTKHTML-EDITOR */
/* The engine would have the GtkHTML widget stored in "html-widget"
@@ -4140,6 +4112,37 @@
return composer;
}
+/**
+ * e_msg_composer_send:
+ * @composer: an #EMsgComposer
+ *
+ * Send the message in @composer.
+ **/
+void
+e_msg_composer_send (EMsgComposer *composer)
+{
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+
+ g_signal_emit (composer, signals[SEND], 0);
+}
+
+/**
+ * e_msg_composer_save_draft:
+ * @composer: an #EMsgComposer
+ *
+ * Save the message in @composer to the selected account's Drafts folder.
+ **/
+void
+e_msg_composer_save_draft (EMsgComposer *composer)
+{
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+
+ g_signal_emit (composer, signals[SAVE_DRAFT], 0, FALSE);
+
+ /* XXX This should be elsewhere. */
+ e_msg_composer_unset_changed (composer);
+ e_msg_composer_unset_autosaved (composer);
+}
static GList *
add_recipients (GList *list, const gchar *recips)
Modified: branches/mbarnes-composer/composer/e-msg-composer.h
==============================================================================
--- branches/mbarnes-composer/composer/e-msg-composer.h (original)
+++ branches/mbarnes-composer/composer/e-msg-composer.h Sat Feb 9 21:54:02 2008
@@ -31,7 +31,6 @@
#include <gtkhtml-editor.h>
#include "e-composer-header-table.h"
-#include "Editor.h"
/* Standard GObject macros */
#define E_TYPE_MSG_COMPOSER \
@@ -87,6 +86,10 @@
EMsgComposer *e_msg_composer_new_from_url (const gchar *url);
EMsgComposer *e_msg_composer_new_redirect (CamelMimeMessage *message,
const gchar *resent_from);
+
+void e_msg_composer_send (EMsgComposer *composer);
+void e_msg_composer_save_draft (EMsgComposer *composer);
+
void e_msg_composer_show_attachments_ui (EMsgComposer *composer);
void e_msg_composer_set_alternative (EMsgComposer *composer,
@@ -175,9 +178,6 @@
struct _EAttachmentBar* e_msg_composer_get_attachment_bar (EMsgComposer *composer);
-void e_msg_composer_set_attach_path (EMsgComposer *composer, const gchar *path);
-const gchar * e_msg_composer_get_attach_path (EMsgComposer *composer);
-
G_END_DECLS
#endif /* ___E_MSG_COMPOSER_H__ */
Added: branches/mbarnes-composer/composer/gconf-bridge.c
==============================================================================
--- (empty file)
+++ branches/mbarnes-composer/composer/gconf-bridge.c Sat Feb 9 21:54:02 2008
@@ -0,0 +1,1249 @@
+/*
+ * (C) 2005 OpenedHand Ltd.
+ *
+ * Author: Jorn Baayen <jorn openedhand com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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 <config.h>
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtkmessagedialog.h>
+#include <string.h>
+
+#include "gconf-bridge.h"
+
+struct _GConfBridge {
+ GConfClient *client;
+
+ GHashTable *bindings;
+};
+
+/* The data structures for the different kinds of bindings */
+typedef enum {
+ BINDING_PROP,
+ BINDING_WINDOW,
+ BINDING_LIST_STORE
+} BindingType;
+
+typedef struct {
+ BindingType type;
+ guint id;
+
+ gboolean delayed_mode;
+
+ char *key;
+ guint val_notify_id;
+ GSList *val_changes; /* List of changes made to GConf value,
+ that have not received change notification
+ yet. */
+
+ GObject *object;
+ GParamSpec *prop;
+ gulong prop_notify_id;
+
+ guint sync_timeout_id; /* Used in delayed mode */
+} PropBinding;
+
+typedef struct {
+ BindingType type;
+ guint id;
+
+ gboolean bind_size;
+ gboolean bind_pos;
+
+ char *key_prefix;
+
+ GtkWindow *window;
+ gulong configure_event_id;
+ gulong unmap_id;
+ guint sync_timeout_id;
+} WindowBinding;
+
+typedef struct {
+ BindingType type;
+ guint id;
+
+ char *key;
+ guint val_notify_id;
+ GSList *val_changes; /* List of changes made to GConf value,
+ that have not received change notification
+ yet. */
+
+ GtkListStore *list_store;
+ guint row_inserted_id;
+ guint row_changed_id;
+ guint row_deleted_id;
+ guint rows_reordered_id;
+
+ guint sync_idle_id;
+} ListStoreBinding;
+
+/* Some trickery to be able to treat the data structures generically */
+typedef union {
+ BindingType type;
+
+ PropBinding prop_binding;
+ WindowBinding window_binding;
+ ListStoreBinding list_store_binding;
+} Binding;
+
+/* Function prototypes */
+static void
+unbind (Binding *binding);
+
+#if !HAVE_DECL_GCONF_VALUE_COMPARE /* Not in headers in GConf < 2.13 */
+int gconf_value_compare (const GConfValue *value_a,
+ const GConfValue *value_b);
+#endif
+
+static GConfBridge *bridge = NULL; /* Global GConfBridge object */
+
+/* Free up all resources allocated by the GConfBridge. Called on exit. */
+static void
+destroy_bridge (void)
+{
+ g_hash_table_destroy (bridge->bindings);
+ g_object_unref (bridge->client);
+
+ g_free (bridge);
+}
+
+/**
+ * gconf_bridge_get
+ *
+ * Returns the #GConfBridge. This is a singleton object.
+ *
+ * Return value: The #GConfBridge.
+ **/
+GConfBridge *
+gconf_bridge_get (void)
+{
+ if (bridge)
+ return bridge;
+
+ gconf_bridge_install_default_error_handler ();
+
+ bridge = g_new (GConfBridge, 1);
+
+ bridge->client = gconf_client_get_default ();
+ bridge->bindings = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) unbind);
+
+ g_atexit (destroy_bridge);
+
+ return bridge;
+}
+
+/**
+ * gconf_bridge_get_client
+ * @bridge: A #GConfBridge
+ *
+ * Returns the #GConfClient used by @bridge. This is the same #GConfClient
+ * as returned by gconf_client_get_default().
+ *
+ * Return value: A #GConfClient.
+ **/
+GConfClient *
+gconf_bridge_get_client (GConfBridge *bridge)
+{
+ g_return_val_if_fail (bridge != NULL, NULL);
+
+ return bridge->client;
+}
+
+/* Generate an ID for a new binding */
+static guint
+new_id (void)
+{
+ static guint id_counter = 0;
+
+ id_counter++;
+
+ return id_counter;
+}
+
+/*
+ * Property bindings
+ */
+
+/* Syncs a value from GConf to an object property */
+static void
+prop_binding_sync_pref_to_prop (PropBinding *binding,
+ GConfValue *pref_value)
+{
+ GValue src_value, value;
+
+ /* Make sure we don't enter an infinite synchronizing loop */
+ g_signal_handler_block (binding->object, binding->prop_notify_id);
+
+ memset (&src_value, 0, sizeof (GValue));
+
+ /* First, convert GConfValue to GValue */
+ switch (pref_value->type) {
+ case GCONF_VALUE_STRING:
+ g_value_init (&src_value, G_TYPE_STRING);
+ g_value_set_string (&src_value,
+ gconf_value_get_string (pref_value));
+ break;
+ case GCONF_VALUE_INT:
+ g_value_init (&src_value, G_TYPE_INT);
+ g_value_set_int (&src_value,
+ gconf_value_get_int (pref_value));
+ break;
+ case GCONF_VALUE_BOOL:
+ g_value_init (&src_value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (&src_value,
+ gconf_value_get_bool (pref_value));
+ break;
+ case GCONF_VALUE_FLOAT:
+ g_value_init (&src_value, G_TYPE_FLOAT);
+ g_value_set_float (&src_value,
+ gconf_value_get_float (pref_value));
+ break;
+ default:
+ g_warning ("prop_binding_sync_pref_to_prop: Unhandled value "
+ "type '%d'.\n", pref_value->type);
+
+ return;
+ }
+
+ /* Then convert to the type expected by the object, if necessary */
+ memset (&value, 0, sizeof (GValue));
+ g_value_init (&value,
+ G_PARAM_SPEC_VALUE_TYPE (binding->prop));
+
+ if (src_value.g_type != value.g_type) {
+ if (!g_value_transform (&src_value, &value)) {
+ g_warning ("prop_binding_sync_pref_to_prop: Failed to "
+ "transform a \"%s\" to a \"%s\".",
+ g_type_name (src_value.g_type),
+ g_type_name (value.g_type));
+
+ goto done;
+ }
+
+ g_object_set_property (binding->object,
+ binding->prop->name, &value);
+ } else {
+ g_object_set_property (binding->object,
+ binding->prop->name, &src_value);
+ }
+
+done:
+ g_value_unset (&src_value);
+ g_value_unset (&value);
+
+ g_signal_handler_unblock (binding->object, binding->prop_notify_id);
+}
+
+/* Syncs an object property to GConf */
+static void
+prop_binding_sync_prop_to_pref (PropBinding *binding)
+{
+ GValue value;
+ GConfValue *gconf_value;
+
+ memset (&value, 0, sizeof (GValue));
+
+ g_value_init (&value,
+ G_PARAM_SPEC_VALUE_TYPE (binding->prop));
+ g_object_get_property (binding->object,
+ binding->prop->name,
+ &value);
+
+ switch (value.g_type) {
+ case G_TYPE_STRING:
+ gconf_value = gconf_value_new (GCONF_VALUE_STRING);
+ gconf_value_set_string (gconf_value,
+ g_value_get_string (&value));
+ break;
+ case G_TYPE_INT:
+ gconf_value = gconf_value_new (GCONF_VALUE_INT);
+ gconf_value_set_int (gconf_value,
+ g_value_get_int (&value));
+ break;
+ case G_TYPE_UINT:
+ gconf_value = gconf_value_new (GCONF_VALUE_INT);
+ gconf_value_set_int (gconf_value,
+ g_value_get_uint (&value));
+ break;
+ case G_TYPE_LONG:
+ gconf_value = gconf_value_new (GCONF_VALUE_INT);
+ gconf_value_set_int (gconf_value,
+ g_value_get_long (&value));
+ break;
+ case G_TYPE_ULONG:
+ gconf_value = gconf_value_new (GCONF_VALUE_INT);
+ gconf_value_set_int (gconf_value,
+ g_value_get_ulong (&value));
+ break;
+ case G_TYPE_INT64:
+ gconf_value = gconf_value_new (GCONF_VALUE_INT);
+ gconf_value_set_int (gconf_value,
+ g_value_get_int64 (&value));
+ break;
+ case G_TYPE_UINT64:
+ gconf_value = gconf_value_new (GCONF_VALUE_INT);
+ gconf_value_set_int (gconf_value,
+ g_value_get_uint64 (&value));
+ break;
+ case G_TYPE_CHAR:
+ gconf_value = gconf_value_new (GCONF_VALUE_INT);
+ gconf_value_set_int (gconf_value,
+ g_value_get_char (&value));
+ break;
+ case G_TYPE_UCHAR:
+ gconf_value = gconf_value_new (GCONF_VALUE_INT);
+ gconf_value_set_int (gconf_value,
+ g_value_get_uchar (&value));
+ break;
+ case G_TYPE_ENUM:
+ gconf_value = gconf_value_new (GCONF_VALUE_INT);
+ gconf_value_set_int (gconf_value,
+ g_value_get_enum (&value));
+ break;
+ case G_TYPE_BOOLEAN:
+ gconf_value = gconf_value_new (GCONF_VALUE_BOOL);
+ gconf_value_set_bool (gconf_value,
+ g_value_get_boolean (&value));
+ break;
+ case G_TYPE_DOUBLE:
+ gconf_value = gconf_value_new (GCONF_VALUE_FLOAT);
+#ifdef HAVE_CORBA_GCONF
+ /* FIXME we cast to a float explicitly as CORBA GConf
+ * uses doubles in its API, but treats them as floats
+ * when transporting them over CORBA. See #322837 */
+ gconf_value_set_float (gconf_value,
+ (float) g_value_get_double (&value));
+#else
+ gconf_value_set_float (gconf_value,
+ g_value_get_double (&value));
+#endif
+ break;
+ case G_TYPE_FLOAT:
+ gconf_value = gconf_value_new (GCONF_VALUE_FLOAT);
+ gconf_value_set_float (gconf_value,
+ g_value_get_float (&value));
+ break;
+ default:
+ if (g_type_is_a (value.g_type, G_TYPE_ENUM)) {
+ gconf_value = gconf_value_new (GCONF_VALUE_INT);
+ gconf_value_set_int (gconf_value,
+ g_value_get_enum (&value));
+ } else {
+ g_warning ("prop_binding_sync_prop_to_pref: "
+ "Unhandled value type '%s'.\n",
+ g_type_name (value.g_type));
+
+ goto done;
+ }
+
+ break;
+ }
+
+ /* Set to GConf */
+ gconf_client_set (bridge->client, binding->key, gconf_value, NULL);
+
+ /* Store until change notification comes in, so that we are able
+ * to ignore it */
+ binding->val_changes = g_slist_append (binding->val_changes,
+ gconf_value);
+
+done:
+ g_value_unset (&value);
+}
+
+/* Called when a GConf value bound to an object property has changed */
+static void
+prop_binding_pref_changed (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ GConfValue *gconf_value;
+ PropBinding *binding;
+ GSList *l;
+
+ gconf_value = gconf_entry_get_value (entry);
+ if (!gconf_value)
+ return; /* NULL means that the value has been unset */
+
+ binding = (PropBinding *) user_data;
+
+ /* Check that this notification is not caused by sync_prop_to_pref() */
+ l = g_slist_find_custom (binding->val_changes,
+ gconf_value,
+ (GCompareFunc) gconf_value_compare);
+ if (l) {
+ gconf_value_free (l->data);
+
+ binding->val_changes = g_slist_delete_link
+ (binding->val_changes, l);
+
+ return;
+ }
+
+ prop_binding_sync_pref_to_prop (binding, gconf_value);
+}
+
+/* Performs a scheduled prop-to-pref sync for a prop binding in
+ * delay mode */
+static gboolean
+prop_binding_perform_scheduled_sync (PropBinding *binding)
+{
+ prop_binding_sync_prop_to_pref (binding);
+
+ binding->sync_timeout_id = 0;
+
+ g_object_unref (binding->object);
+
+ return FALSE;
+}
+
+#define PROP_BINDING_SYNC_DELAY 100 /* Delay for bindings with "delayed"
+ set to TRUE, in ms */
+
+/* Called when an object property has changed */
+static void
+prop_binding_prop_changed (GObject *object,
+ GParamSpec *param_spec,
+ PropBinding *binding)
+{
+ if (binding->delayed_mode) {
+ /* Just schedule a sync */
+ if (binding->sync_timeout_id == 0) {
+ /* We keep a reference on the object as long as
+ * we haven't synced yet to make sure we don't
+ * lose any data */
+ g_object_ref (binding->object);
+
+ binding->sync_timeout_id =
+ g_timeout_add
+ (PROP_BINDING_SYNC_DELAY,
+ (GSourceFunc)
+ prop_binding_perform_scheduled_sync,
+ binding);
+ }
+ } else {
+ /* Directly sync */
+ prop_binding_sync_prop_to_pref (binding);
+ }
+}
+
+/* Called when an object is destroyed */
+static void
+prop_binding_object_destroyed (gpointer user_data,
+ GObject *where_the_object_was)
+{
+ PropBinding *binding;
+
+ binding = (PropBinding *) user_data;
+ binding->object = NULL; /* Don't do anything with the object
+ at unbind() */
+
+ g_hash_table_remove (bridge->bindings,
+ GUINT_TO_POINTER (binding->id));
+}
+
+/**
+ * gconf_bridge_bind_property_full
+ * @bridge: A #GConfBridge
+ * @key: A GConf key to be bound
+ * @object: A #GObject
+ * @prop: The property of @object to be bound
+ * @delayed_sync: TRUE if there should be a delay between property changes
+ * and syncs to GConf. Set to TRUE when binding to a rapidly-changing
+ * property, for example the "value" property on a #GtkAdjustment.
+ *
+ * Binds @key to @prop, causing them to have the same value at all times.
+ *
+ * The types of @key and @prop should be compatible. Floats and doubles, and
+ * ints, uints, longs, unlongs, int64s, uint64s, chars, uchars and enums
+ * can be matched up. Booleans and strings can only be matched to their
+ * respective types.
+ *
+ * On calling this function the current value of @key will be set to @prop.
+ *
+ * Return value: The ID of the new binding.
+ **/
+guint
+gconf_bridge_bind_property_full (GConfBridge *bridge,
+ const char *key,
+ GObject *object,
+ const char *prop,
+ gboolean delayed_sync)
+{
+ GParamSpec *pspec;
+ PropBinding *binding;
+ char *signal;
+ GConfValue *val;
+
+ g_return_val_if_fail (bridge != NULL, 0);
+ g_return_val_if_fail (key != NULL, 0);
+ g_return_val_if_fail (G_IS_OBJECT (object), 0);
+ g_return_val_if_fail (prop != NULL, 0);
+
+ /* First, try to fetch the propertys GParamSpec off the object */
+ pspec = g_object_class_find_property
+ (G_OBJECT_GET_CLASS (object), prop);
+ if (G_UNLIKELY (pspec == NULL)) {
+ g_warning ("gconf_bridge_bind_property_full: A property \"%s\" "
+ "was not found. Please make sure you are passing "
+ "the right property name.", prop);
+
+ return 0;
+ }
+
+ /* GParamSpec found: All good, create new binding. */
+ binding = g_new (PropBinding, 1);
+
+ binding->type = BINDING_PROP;
+ binding->id = new_id ();
+ binding->delayed_mode = delayed_sync;
+ binding->val_changes = NULL;
+ binding->key = g_strdup (key);
+ binding->object = object;
+ binding->prop = pspec;
+ binding->sync_timeout_id = 0;
+
+ /* Watch GConf key */
+ binding->val_notify_id =
+ gconf_client_notify_add (bridge->client, key,
+ prop_binding_pref_changed,
+ binding, NULL, NULL);
+
+ /* Connect to property change notifications */
+ signal = g_strconcat ("notify::", prop, NULL);
+ binding->prop_notify_id =
+ g_signal_connect (object, signal,
+ G_CALLBACK (prop_binding_prop_changed),
+ binding);
+ g_free (signal);
+
+ /* Sync object to value from GConf, if set */
+ val = gconf_client_get (bridge->client, key, NULL);
+ if (val) {
+ prop_binding_sync_pref_to_prop (binding, val);
+ gconf_value_free (val);
+ }
+
+ /* Handle case where watched object gets destroyed */
+ g_object_weak_ref (object,
+ prop_binding_object_destroyed, binding);
+
+ /* Insert binding */
+ g_hash_table_insert (bridge->bindings,
+ GUINT_TO_POINTER (binding->id), binding);
+
+ /* Done */
+ return binding->id;
+}
+
+/* Unbinds a property binding */
+static void
+prop_binding_unbind (PropBinding *binding)
+{
+ if (binding->delayed_mode && binding->sync_timeout_id > 0) {
+ /* Perform any scheduled syncs */
+ g_source_remove (binding->sync_timeout_id);
+
+ /* The object will still be around as we have
+ * a reference */
+ prop_binding_perform_scheduled_sync (binding);
+ }
+
+ gconf_client_notify_remove (bridge->client,
+ binding->val_notify_id);
+ g_free (binding->key);
+
+ while (binding->val_changes) {
+ gconf_value_free (binding->val_changes->data);
+
+ binding->val_changes = g_slist_delete_link
+ (binding->val_changes, binding->val_changes);
+ }
+
+ /* The object might have been destroyed .. */
+ if (binding->object) {
+ g_signal_handler_disconnect (binding->object,
+ binding->prop_notify_id);
+
+ g_object_weak_unref (binding->object,
+ prop_binding_object_destroyed, binding);
+ }
+}
+
+/*
+ * Window bindings
+ */
+
+/* Performs a scheduled dimensions-to-prefs sync for a window binding */
+static gboolean
+window_binding_perform_scheduled_sync (WindowBinding *binding)
+{
+ if (binding->bind_size) {
+ int width, height;
+ char *key;
+ GdkWindowState state;
+
+ state = gdk_window_get_state (GTK_WIDGET (binding->window)->window);
+
+ if (state & GDK_WINDOW_STATE_MAXIMIZED) {
+ key = g_strconcat (binding->key_prefix, "_maximized", NULL);
+ gconf_client_set_bool (bridge->client, key, TRUE, NULL);
+ g_free (key);
+ } else {
+ gtk_window_get_size (binding->window, &width, &height);
+
+ key = g_strconcat (binding->key_prefix, "_width", NULL);
+ gconf_client_set_int (bridge->client, key, width, NULL);
+ g_free (key);
+
+ key = g_strconcat (binding->key_prefix, "_height", NULL);
+ gconf_client_set_int (bridge->client, key, height, NULL);
+ g_free (key);
+
+ key = g_strconcat (binding->key_prefix, "_maximized", NULL);
+ gconf_client_set_bool (bridge->client, key, FALSE, NULL);
+ g_free (key);
+ }
+ }
+
+ if (binding->bind_pos) {
+ int x, y;
+ char *key;
+
+ gtk_window_get_position (binding->window, &x, &y);
+
+ key = g_strconcat (binding->key_prefix, "_x", NULL);
+ gconf_client_set_int (bridge->client, key, x, NULL);
+ g_free (key);
+
+ key = g_strconcat (binding->key_prefix, "_y", NULL);
+ gconf_client_set_int (bridge->client, key, y, NULL);
+ g_free (key);
+ }
+
+ binding->sync_timeout_id = 0;
+
+ return FALSE;
+}
+
+#define WINDOW_BINDING_SYNC_DELAY 1000 /* Delay before syncing new window
+ dimensions to GConf, in ms */
+
+/* Called when the window han been resized or moved */
+static gboolean
+window_binding_configure_event_cb (GtkWindow *window,
+ GdkEventConfigure *event,
+ WindowBinding *binding)
+{
+ /* Schedule a sync */
+ if (binding->sync_timeout_id == 0) {
+ binding->sync_timeout_id =
+ g_timeout_add (WINDOW_BINDING_SYNC_DELAY,
+ (GSourceFunc)
+ window_binding_perform_scheduled_sync,
+ binding);
+ }
+
+ return FALSE;
+}
+
+/* Called when the window state is being changed */
+static gboolean
+window_binding_state_event_cb (GtkWindow *window,
+ GdkEventWindowState *event,
+ WindowBinding *binding)
+{
+ window_binding_perform_scheduled_sync (binding);
+
+ return FALSE;
+}
+
+/* Called when the window is being unmapped */
+static gboolean
+window_binding_unmap_cb (GtkWindow *window,
+ WindowBinding *binding)
+{
+ /* Force sync */
+ if (binding->sync_timeout_id > 0)
+ g_source_remove (binding->sync_timeout_id);
+
+ window_binding_perform_scheduled_sync (binding);
+
+ return FALSE;
+}
+
+/* Called when a window is destroyed */
+static void
+window_binding_window_destroyed (gpointer user_data,
+ GObject *where_the_object_was)
+{
+ WindowBinding *binding;
+
+ binding = (WindowBinding *) user_data;
+ binding->window = NULL; /* Don't do anything with the window
+ at unbind() */
+
+ g_hash_table_remove (bridge->bindings,
+ GUINT_TO_POINTER (binding->id));
+}
+
+/**
+ * gconf_bridge_bind_window
+ * @bridge: A #GConfBridge
+ * @key_prefix: The prefix of the GConf keys
+ * @window: A #GtkWindow
+ * @bind_size: TRUE to bind the size of @window
+ * @bind_pos: TRUE to bind the position of @window
+ *
+ * On calling this function @window will be resized to the values
+ * specified by "@key_prefix<!-- -->_width" and "@key_prefix<!-- -->_height"
+ * and maximixed if "@key_prefix<!-- -->_maximized is TRUE if
+ * @bind_size is TRUE, and moved to the values specified by
+ * "@key_prefix<!-- -->_x" and "@key_prefix<!-- -->_y" if @bind_pos is TRUE.
+ * The respective GConf values will be updated when the window is resized
+ * and/or moved.
+ *
+ * Return value: The ID of the new binding.
+ **/
+guint
+gconf_bridge_bind_window (GConfBridge *bridge,
+ const char *key_prefix,
+ GtkWindow *window,
+ gboolean bind_size,
+ gboolean bind_pos)
+{
+ WindowBinding *binding;
+
+ g_return_val_if_fail (bridge != NULL, 0);
+ g_return_val_if_fail (key_prefix != NULL, 0);
+ g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
+
+ /* Create new binding. */
+ binding = g_new (WindowBinding, 1);
+
+ binding->type = BINDING_WINDOW;
+ binding->id = new_id ();
+ binding->bind_size = bind_size;
+ binding->bind_pos = bind_pos;
+ binding->key_prefix = g_strdup (key_prefix);
+ binding->window = window;
+ binding->sync_timeout_id = 0;
+
+ /* Set up GConf keys & sync window to GConf values */
+ if (bind_size) {
+ char *key;
+ GConfValue *width_val, *height_val, *maximized_val;
+
+ key = g_strconcat (key_prefix, "_width", NULL);
+ width_val = gconf_client_get (bridge->client, key, NULL);
+ g_free (key);
+
+ key = g_strconcat (key_prefix, "_height", NULL);
+ height_val = gconf_client_get (bridge->client, key, NULL);
+ g_free (key);
+
+ key = g_strconcat (key_prefix, "_maximized", NULL);
+ maximized_val = gconf_client_get (bridge->client, key, NULL);
+ g_free (key);
+
+ if (width_val && height_val) {
+ gtk_window_resize (window,
+ gconf_value_get_int (width_val),
+ gconf_value_get_int (height_val));
+
+ gconf_value_free (width_val);
+ gconf_value_free (height_val);
+ } else if (width_val) {
+ gconf_value_free (width_val);
+ } else if (height_val) {
+ gconf_value_free (height_val);
+ }
+
+ if (maximized_val) {
+ if (gconf_value_get_bool (maximized_val)) {
+ gtk_window_maximize (window);
+ }
+ gconf_value_free (maximized_val);
+ }
+ }
+
+ if (bind_pos) {
+ char *key;
+ GConfValue *x_val, *y_val;
+
+ key = g_strconcat (key_prefix, "_x", NULL);
+ x_val = gconf_client_get (bridge->client, key, NULL);
+ g_free (key);
+
+ key = g_strconcat (key_prefix, "_y", NULL);
+ y_val = gconf_client_get (bridge->client, key, NULL);
+ g_free (key);
+
+ if (x_val && y_val) {
+ gtk_window_move (window,
+ gconf_value_get_int (x_val),
+ gconf_value_get_int (y_val));
+
+ gconf_value_free (x_val);
+ gconf_value_free (y_val);
+ } else if (x_val) {
+ gconf_value_free (x_val);
+ } else if (y_val) {
+ gconf_value_free (y_val);
+ }
+ }
+
+ /* Connect to window size change notifications */
+ binding->configure_event_id =
+ g_signal_connect (window,
+ "configure-event",
+ G_CALLBACK
+ (window_binding_configure_event_cb),
+ binding);
+
+ binding->configure_event_id =
+ g_signal_connect (window,
+ "window_state_event",
+ G_CALLBACK
+ (window_binding_state_event_cb),
+ binding);
+ binding->unmap_id =
+ g_signal_connect (window,
+ "unmap",
+ G_CALLBACK (window_binding_unmap_cb),
+ binding);
+
+ /* Handle case where window gets destroyed */
+ g_object_weak_ref (G_OBJECT (window),
+ window_binding_window_destroyed, binding);
+
+ /* Insert binding */
+ g_hash_table_insert (bridge->bindings,
+ GUINT_TO_POINTER (binding->id), binding);
+
+ /* Done */
+ return binding->id;
+}
+
+/* Unbinds a window binding */
+static void
+window_binding_unbind (WindowBinding *binding)
+{
+ if (binding->sync_timeout_id > 0)
+ g_source_remove (binding->sync_timeout_id);
+
+ g_free (binding->key_prefix);
+
+ /* The window might have been destroyed .. */
+ if (binding->window) {
+ g_signal_handler_disconnect (binding->window,
+ binding->configure_event_id);
+ g_signal_handler_disconnect (binding->window,
+ binding->unmap_id);
+
+ g_object_weak_unref (G_OBJECT (binding->window),
+ window_binding_window_destroyed, binding);
+ }
+}
+
+/*
+ * List store bindings
+ */
+
+/* Fills a GtkListStore with the string list from @value */
+static void
+list_store_binding_sync_pref_to_store (ListStoreBinding *binding,
+ GConfValue *value)
+{
+ GSList *list, *l;
+ GtkTreeIter iter;
+
+ /* Make sure we don't enter an infinite synchronizing loop */
+ g_signal_handler_block (binding->list_store,
+ binding->row_inserted_id);
+ g_signal_handler_block (binding->list_store,
+ binding->row_deleted_id);
+
+ gtk_list_store_clear (binding->list_store);
+
+ list = gconf_value_get_list (value);
+ for (l = list; l; l = l->next) {
+ GConfValue *l_value;
+ const char *string;
+
+ l_value = (GConfValue *) l->data;
+ string = gconf_value_get_string (l_value);
+
+ gtk_list_store_insert_with_values (binding->list_store,
+ &iter, -1,
+ 0, string,
+ -1);
+ }
+
+ g_signal_handler_unblock (binding->list_store,
+ binding->row_inserted_id);
+ g_signal_handler_unblock (binding->list_store,
+ binding->row_deleted_id);
+}
+
+/* Sets a GConf value to the contents of a GtkListStore */
+static gboolean
+list_store_binding_sync_store_to_pref (ListStoreBinding *binding)
+{
+ GtkTreeModel *tree_model;
+ GtkTreeIter iter;
+ GSList *list;
+ int res;
+ GConfValue *gconf_value;
+
+ tree_model = GTK_TREE_MODEL (binding->list_store);
+
+ /* Build list */
+ list = NULL;
+ res = gtk_tree_model_get_iter_first (tree_model, &iter);
+ while (res) {
+ char *string;
+ GConfValue *tmp_value;
+
+ gtk_tree_model_get (tree_model, &iter,
+ 0, &string, -1);
+
+ tmp_value = gconf_value_new (GCONF_VALUE_STRING);
+ gconf_value_set_string (tmp_value, string);
+
+ list = g_slist_append (list, tmp_value);
+
+ res = gtk_tree_model_iter_next (tree_model, &iter);
+ }
+
+ /* Create value */
+ gconf_value = gconf_value_new (GCONF_VALUE_LIST);
+ gconf_value_set_list_type (gconf_value, GCONF_VALUE_STRING);
+ gconf_value_set_list_nocopy (gconf_value, list);
+
+ /* Set */
+ gconf_client_set (bridge->client, binding->key, gconf_value, NULL);
+
+ /* Store until change notification comes in, so that we are able
+ * to ignore it */
+ binding->val_changes = g_slist_append (binding->val_changes,
+ gconf_value);
+
+ binding->sync_idle_id = 0;
+
+ g_object_unref (binding->list_store);
+
+ return FALSE;
+}
+
+/* Pref changed: sync */
+static void
+list_store_binding_pref_changed (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ GConfValue *gconf_value;
+ ListStoreBinding *binding;
+ GSList *l;
+
+ gconf_value = gconf_entry_get_value (entry);
+ if (!gconf_value)
+ return; /* NULL means that the value has been unset */
+
+ binding = (ListStoreBinding *) user_data;
+
+ /* Check that this notification is not caused by
+ * sync_store_to_pref() */
+ l = g_slist_find_custom (binding->val_changes,
+ gconf_value,
+ (GCompareFunc) gconf_value_compare);
+ if (l) {
+ gconf_value_free (l->data);
+
+ binding->val_changes = g_slist_delete_link
+ (binding->val_changes, l);
+
+ return;
+ }
+
+ list_store_binding_sync_pref_to_store (binding, gconf_value);
+}
+
+/* Called when an object is destroyed */
+static void
+list_store_binding_store_destroyed (gpointer user_data,
+ GObject *where_the_object_was)
+{
+ ListStoreBinding *binding;
+
+ binding = (ListStoreBinding *) user_data;
+ binding->list_store = NULL; /* Don't do anything with the store
+ at unbind() */
+
+ g_hash_table_remove (bridge->bindings,
+ GUINT_TO_POINTER (binding->id));
+}
+
+/* List store changed: Sync */
+static void
+list_store_binding_store_changed_cb (ListStoreBinding *binding)
+{
+ if (binding->sync_idle_id == 0) {
+ g_object_ref (binding->list_store);
+
+ binding->sync_idle_id = g_idle_add
+ ((GSourceFunc) list_store_binding_sync_store_to_pref,
+ binding);
+ }
+}
+
+/**
+ * gconf_bridge_bind_string_list_store
+ * @bridge: A #GConfBridge
+ * @key: A GConf key to be bound
+ * @list_store: A #GtkListStore
+ *
+ * On calling this function single string column #GtkListStore @list_store
+ * will be kept synchronized with the GConf string list value pointed to by
+ * @key. On calling this function @list_store will be populated with the
+ * strings specified by the value of @key.
+ *
+ * Return value: The ID of the new binding.
+ **/
+guint
+gconf_bridge_bind_string_list_store (GConfBridge *bridge,
+ const char *key,
+ GtkListStore *list_store)
+{
+ GtkTreeModel *tree_model;
+ gboolean have_one_column, is_string_column;
+ ListStoreBinding *binding;
+ GConfValue *val;
+
+ g_return_val_if_fail (bridge != NULL, 0);
+ g_return_val_if_fail (key != NULL, 0);
+ g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), 0);
+
+ /* Check list store suitability */
+ tree_model = GTK_TREE_MODEL (list_store);
+ have_one_column = (gtk_tree_model_get_n_columns (tree_model) == 1);
+ is_string_column = (gtk_tree_model_get_column_type
+ (tree_model, 0) == G_TYPE_STRING);
+ if (G_UNLIKELY (!have_one_column || !is_string_column)) {
+ g_warning ("gconf_bridge_bind_string_list_store: Only "
+ "GtkListStores with exactly one string column are "
+ "supported.");
+
+ return 0;
+ }
+
+ /* Create new binding. */
+ binding = g_new (ListStoreBinding, 1);
+
+ binding->type = BINDING_LIST_STORE;
+ binding->id = new_id ();
+ binding->key = g_strdup (key);
+ binding->val_changes = NULL;
+ binding->list_store = list_store;
+ binding->sync_idle_id = 0;
+
+ /* Watch GConf key */
+ binding->val_notify_id =
+ gconf_client_notify_add (bridge->client, key,
+ list_store_binding_pref_changed,
+ binding, NULL, NULL);
+
+ /* Connect to ListStore change notifications */
+ binding->row_inserted_id =
+ g_signal_connect_swapped (list_store, "row-inserted",
+ G_CALLBACK
+ (list_store_binding_store_changed_cb),
+ binding);
+ binding->row_changed_id =
+ g_signal_connect_swapped (list_store, "row-inserted",
+ G_CALLBACK
+ (list_store_binding_store_changed_cb),
+ binding);
+ binding->row_deleted_id =
+ g_signal_connect_swapped (list_store, "row-inserted",
+ G_CALLBACK
+ (list_store_binding_store_changed_cb),
+ binding);
+ binding->rows_reordered_id =
+ g_signal_connect_swapped (list_store, "row-inserted",
+ G_CALLBACK
+ (list_store_binding_store_changed_cb),
+ binding);
+
+ /* Sync object to value from GConf, if set */
+ val = gconf_client_get (bridge->client, key, NULL);
+ if (val) {
+ list_store_binding_sync_pref_to_store (binding, val);
+ gconf_value_free (val);
+ }
+
+ /* Handle case where watched object gets destroyed */
+ g_object_weak_ref (G_OBJECT (list_store),
+ list_store_binding_store_destroyed, binding);
+
+ /* Insert binding */
+ g_hash_table_insert (bridge->bindings,
+ GUINT_TO_POINTER (binding->id), binding);
+
+ /* Done */
+ return binding->id;
+}
+
+/* Unbinds a list store binding */
+static void
+list_store_binding_unbind (ListStoreBinding *binding)
+{
+ /* Perform any scheduled syncs */
+ if (binding->sync_idle_id > 0) {
+ g_source_remove (binding->sync_idle_id);
+
+ /* The store will still be around as we added a reference */
+ list_store_binding_sync_store_to_pref (binding);
+ }
+
+ g_free (binding->key);
+
+ while (binding->val_changes) {
+ gconf_value_free (binding->val_changes->data);
+
+ binding->val_changes = g_slist_delete_link
+ (binding->val_changes, binding->val_changes);
+ }
+
+ /* The store might have been destroyed .. */
+ if (binding->list_store) {
+ g_signal_handler_disconnect (binding->list_store,
+ binding->row_inserted_id);
+ g_signal_handler_disconnect (binding->list_store,
+ binding->row_changed_id);
+ g_signal_handler_disconnect (binding->list_store,
+ binding->row_deleted_id);
+ g_signal_handler_disconnect (binding->list_store,
+ binding->rows_reordered_id);
+
+ g_object_weak_unref (G_OBJECT (binding->list_store),
+ list_store_binding_store_destroyed,
+ binding);
+ }
+}
+
+/*
+ * Generic unbinding
+ */
+
+/* Unbinds a binding */
+static void
+unbind (Binding *binding)
+{
+ /* Call specialized unbinding function */
+ switch (binding->type) {
+ case BINDING_PROP:
+ prop_binding_unbind ((PropBinding *) binding);
+ break;
+ case BINDING_WINDOW:
+ window_binding_unbind ((WindowBinding *) binding);
+ break;
+ case BINDING_LIST_STORE:
+ list_store_binding_unbind ((ListStoreBinding *) binding);
+ break;
+ default:
+ g_warning ("Unknown binding type '%d'\n", binding->type);
+ break;
+ }
+
+ g_free (binding);
+}
+
+/**
+ * gconf_bridge_unbind
+ * @bridge: A #GConfBridge
+ * @binding_id: The ID of the binding to be removed
+ *
+ * Removes the binding with ID @binding_id.
+ **/
+void
+gconf_bridge_unbind (GConfBridge *bridge,
+ guint binding_id)
+{
+ g_return_if_fail (bridge != NULL);
+ g_return_if_fail (binding_id > 0);
+
+ /* This will trigger the hash tables value destruction
+ * function, which will take care of further cleanup */
+ g_hash_table_remove (bridge->bindings,
+ GUINT_TO_POINTER (binding_id));
+}
+
+/*
+ * Error handling
+ */
+
+/* This is the same dialog as used in eel */
+static void
+error_handler (GConfClient *client,
+ GError *error)
+{
+ static gboolean shown_dialog = FALSE;
+
+ g_warning ("GConf error:\n %s", error->message);
+
+ if (!shown_dialog) {
+ char *message;
+ GtkWidget *dlg;
+
+ message = g_strdup_printf (_("GConf error: %s"),
+ error->message);
+ dlg = gtk_message_dialog_new (NULL, 0,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ message);
+ g_free (message);
+
+ gtk_message_dialog_format_secondary_text
+ (GTK_MESSAGE_DIALOG (dlg),
+ _("All further errors shown only on terminal."));
+ gtk_window_set_title (GTK_WINDOW (dlg), "");
+
+ gtk_dialog_run (GTK_DIALOG (dlg));
+
+ gtk_widget_destroy (dlg);
+
+ shown_dialog = TRUE;
+ }
+}
+
+/**
+ * gconf_bridge_install_default_error_handler
+ *
+ * Sets up the default error handler. Any unhandled GConf errors will
+ * automatically be handled by presenting the user an error dialog.
+ **/
+void
+gconf_bridge_install_default_error_handler (void)
+{
+ gconf_client_set_global_default_error_handler (error_handler);
+}
Added: branches/mbarnes-composer/composer/gconf-bridge.h
==============================================================================
--- (empty file)
+++ branches/mbarnes-composer/composer/gconf-bridge.h Sat Feb 9 21:54:02 2008
@@ -0,0 +1,117 @@
+/*
+ * (C) 2005 OpenedHand Ltd.
+ *
+ * Author: Jorn Baayen <jorn openedhand com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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 __GCONF_BRIDGE_H__
+#define __GCONF_BRIDGE_H__
+
+#include <gconf/gconf-client.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtkliststore.h>
+
+G_BEGIN_DECLS
+
+void gconf_bridge_install_default_error_handler (void);
+
+typedef struct _GConfBridge GConfBridge;
+
+GConfBridge *gconf_bridge_get (void);
+
+GConfClient *gconf_bridge_get_client (GConfBridge *bridge);
+
+guint gconf_bridge_bind_property_full (GConfBridge *bridge,
+ const char *key,
+ GObject *object,
+ const char *prop,
+ gboolean delayed_sync);
+
+/**
+ * gconf_bridge_bind_property
+ * @bridge: A #GConfBridge
+ * @key: A GConf key to be bound
+ * @object: A #GObject
+ * @prop: The property of @object to be bound
+ *
+ * Binds @key to @prop without delays, causing them to have the same value at all times. See
+ * #gconf_bridge_bind_property_full for more details.
+ *
+ **/
+#define gconf_bridge_bind_property(bridge, key, object, prop) \
+ gconf_bridge_bind_property_full ((bridge), (key), \
+ (object), (prop), FALSE)
+
+/**
+ * gconf_bridge_bind_property_delayed
+ * @bridge: A #GConfBridge
+ * @key: A GConf key to be bound
+ * @object: A #GObject
+ * @prop: The property of @object to be bound
+ *
+ * Binds @key to @prop with a delay, causing them to have the same value at all
+ * times. See #gconf_bridge_bind_property_full for more details.
+ **/
+#define gconf_bridge_bind_property_delayed(bridge, key, object, prop) \
+ gconf_bridge_bind_property_full ((bridge), (key), \
+ (object), (prop), TRUE)
+
+guint gconf_bridge_bind_window (GConfBridge *bridge,
+ const char *key_prefix,
+ GtkWindow *window,
+ gboolean bind_size,
+ gboolean bind_pos);
+
+/**
+ * gconf_bridge_bind_window_size
+ * @bridge: A #GConfBridge
+ * @key_prefix: The prefix of the GConf keys
+ * @window: A #GtkWindow
+ *
+ * On calling this function @window will be resized to the values specified by
+ * "@key_prefix<!-- -->_width" and "@key_prefix<!-- -->_height". The respective
+ * GConf values will be updated when the window is resized. See
+ * #gconf_bridge_bind_window for more details.
+ **/
+#define gconf_bridge_bind_window_size(bridge, key_prefix, window) \
+ gconf_bridge_bind_window ((bridge), (key_prefix), (window), TRUE, FALSE)
+
+/**
+ * gconf_bridge_bind_window_pos
+ * @bridge: A #GConfBridge
+ * @key_prefix: The prefix of the GConf keys
+ * @window: A #GtkWindow
+ *
+ * On calling this function @window will be moved to the values specified by
+ * "@key_prefix<!-- -->_x" and "@key_prefix<!-- -->_y". The respective GConf
+ * values will be updated when the window is moved. See
+ * #gconf_bridge_bind_window for more details.
+ **/
+#define gconf_bridge_bind_window_pos(bridge, key_prefix, window) \
+ gconf_bridge_bind_window ((bridge), (key_prefix), (window), FALSE, TRUE)
+
+guint gconf_bridge_bind_string_list_store (GConfBridge *bridge,
+ const char *key,
+ GtkListStore *list_store);
+
+void gconf_bridge_unbind (GConfBridge *bridge,
+ guint binding_id);
+
+G_END_DECLS
+
+#endif /* __GCONF_BRIDGE_H__ */
Modified: branches/mbarnes-composer/configure.in
==============================================================================
--- branches/mbarnes-composer/configure.in (original)
+++ branches/mbarnes-composer/configure.in Sat Feb 9 21:54:02 2008
@@ -1496,7 +1496,7 @@
dnl --- evolution-addressbook flags
-EVOLUTION_ADDRESSBOOK_DEPS="libbonoboui-2.0 libglade-2.0 libgnomeui-2.0 gnome-vfs-2.0 libgtkhtml-$GTKHTML_PACKAGE libebook-$EDS_PACKAGE libedataserverui-$EDS_PACKAGE camel-$EDS_PACKAGE"
+EVOLUTION_ADDRESSBOOK_DEPS="libbonoboui-2.0 libglade-2.0 libgnomeui-2.0 gnome-vfs-2.0 libgtkhtml-$GTKHTML_PACKAGE libebook-$EDS_PACKAGE libedataserverui-$EDS_PACKAGE camel-$EDS_PACKAGE gtkhtml-editor"
EVO_SET_COMPILE_FLAGS(EVOLUTION_ADDRESSBOOK, $EVOLUTION_ADDRESSBOOK_DEPS)
AC_SUBST(EVOLUTION_ADDRESSBOOK_CFLAGS)
@@ -1525,7 +1525,7 @@
AC_SUBST(LIBSOUP_CFLAGS)
AC_SUBST(LIBSOUP_LIBS)
-EVO_SET_COMPILE_FLAGS(EVOLUTION_CALENDAR, libgnomeui-2.0 libbonoboui-2.0 libglade-2.0 gnome-vfs-module-2.0 libgtkhtml-$GTKHTML_PACKAGE libebook-$EDS_PACKAGE libecal-$EDS_PACKAGE libedataserverui-$EDS_PACKAGE $HAL_REQUIREMENT $libnotify)
+EVO_SET_COMPILE_FLAGS(EVOLUTION_CALENDAR, libgnomeui-2.0 libbonoboui-2.0 libglade-2.0 gnome-vfs-module-2.0 libgtkhtml-$GTKHTML_PACKAGE libebook-$EDS_PACKAGE libecal-$EDS_PACKAGE libedataserverui-$EDS_PACKAGE $HAL_REQUIREMENT $libnotify gtkhtml-editor)
AC_SUBST(EVOLUTION_CALENDAR_CFLAGS)
AC_SUBST(EVOLUTION_CALENDAR_LIBS)
Modified: branches/mbarnes-composer/mail/em-composer-utils.c
==============================================================================
--- branches/mbarnes-composer/mail/em-composer-utils.c (original)
+++ branches/mbarnes-composer/mail/em-composer-utils.c Sat Feb 9 21:54:02 2008
@@ -593,8 +593,13 @@
}
void
-em_composer_utils_setup_callbacks (EMsgComposer *composer, CamelFolder *folder, const char *uid,
- guint32 flags, guint32 set, CamelFolder *drafts, const char *drafts_uid)
+em_composer_utils_setup_callbacks (EMsgComposer *composer,
+ CamelFolder *folder,
+ const char *uid,
+ guint32 flags,
+ guint32 set,
+ CamelFolder *drafts,
+ const char *drafts_uid)
{
struct emcs_t *emcs;
@@ -614,9 +619,6 @@
emcs->drafts_uid = g_strdup (drafts_uid);
}
- g_signal_connect (composer, "send", G_CALLBACK (em_utils_composer_send_cb), emcs);
- g_signal_connect (composer, "save-draft", G_CALLBACK (em_utils_composer_save_draft_cb), emcs);
-
g_object_weak_ref ((GObject *) composer, (GWeakNotify) composer_destroy_cb, emcs);
}
Modified: branches/mbarnes-composer/mail/mail-component-factory.c
==============================================================================
--- branches/mbarnes-composer/mail/mail-component-factory.c (original)
+++ branches/mbarnes-composer/mail/mail-component-factory.c Sat Feb 9 21:54:02 2008
@@ -24,8 +24,6 @@
#include <config.h>
#endif
-#include "em-composer-utils.h"
-#include "evolution-composer.h"
#include "mail-component.h"
#include "em-account-prefs.h"
#include "em-mailer-prefs.h"
@@ -55,7 +53,6 @@
#define FACTORY_ID "OAFIID:GNOME_Evolution_Mail_Factory:" BASE_VERSION
#define COMPONENT_ID "OAFIID:GNOME_Evolution_Mail_Component:" BASE_VERSION
-#define COMPOSER_ID "OAFIID:GNOME_Evolution_Mail_Composer:" BASE_VERSION
#define FOLDER_INFO_ID "OAFIID:GNOME_Evolution_FolderInfo:" BASE_VERSION
static BonoboObject *
@@ -72,9 +69,6 @@
|| strcmp (component_id, EM_MAILER_PREFS_CONTROL_ID) == 0
|| strcmp (component_id, EM_COMPOSER_PREFS_CONTROL_ID) == 0) {
return mail_config_control_factory_cb (factory, component_id, CORBA_OBJECT_NIL);
- } else if (strcmp(component_id, COMPOSER_ID) == 0) {
- /* FIXME: how to remove need for callbacks, probably make the composer more tightly integrated with mail */
- return (BonoboObject *) evolution_composer_new (em_utils_composer_send_cb, em_utils_composer_save_draft_cb);
}
o = mail_importer_factory_cb(factory, component_id, NULL);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]