Files
evolution/plugins/face/face.c
Jonathon Jongsma c2ee0afbc8 Rename EError to EAlert to match general use better
The EError mechanism is used both for error dialogs as well as basic alerts or
user prompts, so we should give it a more general name which matches this use.

This patch also cleans up a few includes of e-alert.h (formerly e-error.h) that
were not actually being used.

https://bugzilla.gnome.org/show_bug.cgi?id=602963
2009-11-30 13:33:04 -06:00

467 lines
11 KiB
C

/*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
* Authors:
* Sankar P <psankar@novell.com>
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "composer/e-msg-composer.h"
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <mail/em-event.h>
#include <e-util/e-alert.h>
#include <e-util/e-util.h>
#include <e-util/e-icon-factory.h>
#define d(x)
#define SETTINGS_KEY "/apps/evolution/eplugin/face/insert_by_default"
static gboolean
get_include_face_by_default (void)
{
GConfClient *gconf = gconf_client_get_default ();
gboolean res;
res = gconf_client_get_bool (gconf, SETTINGS_KEY, NULL);
g_object_unref (gconf);
return res;
}
static void
set_include_face_by_default (gboolean value)
{
GConfClient *gconf = gconf_client_get_default ();
gconf_client_set_bool (gconf, SETTINGS_KEY, value, NULL);
g_object_unref (gconf);
}
static gchar *
get_filename (void)
{
return g_build_filename (e_get_user_data_dir (), "faces", NULL);
}
static gchar *
get_face_base64 (void)
{
gchar *filename = get_filename (), *file_contents = NULL;
gsize length = 0;
if (g_file_get_contents (filename, &file_contents, &length, NULL)) {
if (length > 0) {
file_contents = g_realloc (file_contents, length + 1);
file_contents [length] = 0;
} else {
g_free (file_contents);
file_contents = NULL;
}
} else {
file_contents = NULL;
}
g_free (filename);
return file_contents;
}
static void
set_face_raw (gchar *content, gsize length)
{
gchar *filename = get_filename ();
if (content) {
gchar *file_contents;
file_contents = g_base64_encode ((guchar *) content, length);
g_file_set_contents (filename, file_contents, -1, NULL);
g_free (file_contents);
} else {
g_file_set_contents (filename, "", -1, NULL);
}
g_free (filename);
}
/* g_object_unref returned pointer when done with it */
static GdkPixbuf *
get_active_face (void)
{
GdkPixbufLoader *loader;
GdkPixbuf *res = NULL;
gchar *face;
guchar *data;
gsize data_len = 0;
face = get_face_base64 ();
if (!face || !*face) {
g_free (face);
return NULL;
}
data = g_base64_decode (face, &data_len);
if (!data || !data_len) {
g_free (face);
g_free (data);
return NULL;
}
g_free (face);
loader = gdk_pixbuf_loader_new ();
if (gdk_pixbuf_loader_write (loader, data, data_len, NULL)
&& gdk_pixbuf_loader_close (loader, NULL)) {
res = gdk_pixbuf_loader_get_pixbuf (loader);
if (res)
g_object_ref (res);
}
g_object_unref (loader);
g_free (data);
return res;
}
static gboolean
prepare_image (const gchar *image_filename, gchar **file_contents, gsize *length, GdkPixbuf **use_pixbuf, gboolean can_claim)
{
gboolean res = FALSE;
g_return_val_if_fail (image_filename != NULL, FALSE);
g_return_val_if_fail (file_contents != NULL, FALSE);
g_return_val_if_fail (length != NULL, FALSE);
if (g_file_get_contents (image_filename, file_contents, length, NULL)) {
GError *error = NULL;
GdkPixbuf *pixbuf;
GdkPixbufLoader *loader = gdk_pixbuf_loader_new ();
if (!gdk_pixbuf_loader_write (loader, (const guchar *)(*file_contents), *length, &error)
|| !gdk_pixbuf_loader_close (loader, &error)
|| (pixbuf = gdk_pixbuf_loader_get_pixbuf (loader)) == NULL) {
const gchar *err = _("Unknown error");
if (error && error->message)
err = error->message;
if (can_claim)
e_alert_run_dialog_for_args (NULL, "org.gnome.evolution.plugins.face:not-an-image", err, NULL);
if (error)
g_error_free (error);
} else {
gint width, height;
height = gdk_pixbuf_get_height (pixbuf);
width = gdk_pixbuf_get_width (pixbuf);
if (height <= 0 || width <= 0) {
if (can_claim)
e_alert_run_dialog_for_args (NULL, "org.gnome.evolution.plugins.face:invalid-image-size", NULL, NULL);
} else if (height != 48 || width != 48) {
GdkPixbuf *copy, *scale;
guchar *pixels;
guint32 fill;
if (width >= height) {
if (width > 48) {
gdouble ratio = (gdouble) width / 48.0;
width = 48;
height = height / ratio;
if (height == 0)
height = 1;
}
} else {
if (height > 48) {
gdouble ratio = (gdouble) height / 48.0;
height = 48;
width = width / ratio;
if (width == 0)
width = 1;
}
}
scale = e_icon_factory_pixbuf_scale (pixbuf, width, height);
copy = e_icon_factory_pixbuf_scale (pixbuf, 48, 48);
width = gdk_pixbuf_get_width (scale);
height = gdk_pixbuf_get_height (scale);
pixels = gdk_pixbuf_get_pixels (scale);
/* fill with a pixel color at [0,0] */
fill = (pixels[0] << 24) | (pixels[1] << 16) | (pixels[2] << 8) | (pixels[0]);
gdk_pixbuf_fill (copy, fill);
gdk_pixbuf_copy_area (scale, 0, 0, width, height, copy, width < 48 ? (48 - width) / 2 : 0, height < 48 ? (48 - height) / 2 : 0);
g_free (*file_contents);
*file_contents = NULL;
*length = 0;
res = gdk_pixbuf_save_to_buffer (copy, file_contents, length, "png", NULL, "compression", "9", NULL);
if (res && use_pixbuf)
*use_pixbuf = g_object_ref (copy);
g_object_unref (copy);
g_object_unref (scale);
} else {
res = TRUE;
if (use_pixbuf)
*use_pixbuf = g_object_ref (pixbuf);
}
}
g_object_unref (loader);
} else {
if (can_claim)
e_alert_run_dialog_for_args (NULL, "org.gnome.evolution.plugins.face:file-not-found", NULL, NULL);
}
return res;
}
static void
update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
{
GtkWidget *preview;
gchar *filename, *file_contents = NULL;
GdkPixbuf *pixbuf = NULL;
gboolean have_preview;
gsize length = 0;
preview = GTK_WIDGET (data);
filename = gtk_file_chooser_get_preview_filename (file_chooser);
have_preview = filename && prepare_image (filename, &file_contents, &length, &pixbuf, FALSE);
if (have_preview) {
g_free (file_contents);
have_preview = pixbuf != NULL;
}
g_free (filename);
gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf);
if (pixbuf)
g_object_unref (pixbuf);
gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
}
static GdkPixbuf *
choose_new_face (void)
{
GdkPixbuf *res = NULL;
GtkWidget *filesel, *preview;
GtkFileFilter *filter;
filesel = gtk_file_chooser_dialog_new (_
("Select a png picture (the best 48*48 of size < 720 bytes)"),
NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
gtk_dialog_set_default_response (GTK_DIALOG (filesel), GTK_RESPONSE_OK);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("Image files"));
gtk_file_filter_add_mime_type (filter, "image/*");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (filesel), filter);
preview = gtk_image_new ();
gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (filesel), preview);
g_signal_connect (filesel, "update-preview", G_CALLBACK (update_preview_cb), preview);
if (GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (filesel))) {
gchar *image_filename, *file_contents = NULL;
gsize length = 0;
image_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filesel));
gtk_widget_destroy (filesel);
if (prepare_image (image_filename, &file_contents, &length, &res, TRUE)) {
set_face_raw (file_contents, length);
}
g_free (file_contents);
g_free (image_filename);
} else {
gtk_widget_destroy (filesel);
}
return res;
}
static void
toggled_check_include_by_default_cb (GtkWidget *widget, gpointer data)
{
set_include_face_by_default (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
}
static void
click_load_face_cb (GtkButton *butt, gpointer data)
{
GdkPixbuf *face;
GtkWidget *img;
img = gtk_button_get_image (butt);
g_return_if_fail (img != NULL);
face = choose_new_face ();
if (face) {
gtk_image_set_from_pixbuf (GTK_IMAGE (img), face);
g_object_unref (face);
}
}
static GtkWidget *
get_cfg_widget (void)
{
GtkWidget *vbox, *check, *img, *butt;
GdkPixbuf *face;
vbox = gtk_vbox_new (FALSE, 6);
check = gtk_check_button_new_with_mnemonic (_("_Insert Face picture by default"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), get_include_face_by_default ());
g_signal_connect (check, "toggled", G_CALLBACK (toggled_check_include_by_default_cb), NULL);
gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0);
face = get_active_face ();
img = gtk_image_new_from_pixbuf (face);
if (face)
g_object_unref (face);
butt = gtk_button_new_with_mnemonic (_("Load new _Face picture"));
gtk_button_set_image (GTK_BUTTON (butt), img);
g_signal_connect (butt, "clicked", G_CALLBACK (click_load_face_cb), NULL);
gtk_box_pack_start (GTK_BOX (vbox), butt, FALSE, FALSE, 0);
gtk_widget_show_all (vbox);
return vbox;
}
static void
action_toggle_face_cb (GtkToggleAction *action, EMsgComposer *composer)
{
if (gtk_toggle_action_get_active (action)) {
gchar *face = get_face_base64 ();
if (!face) {
GdkPixbuf *pixbuf = choose_new_face ();
if (pixbuf) {
g_object_unref (pixbuf);
} else {
/* cannot load a face image, uncheck the option */
gtk_toggle_action_set_active (action, FALSE);
}
} else {
g_free (face);
}
}
}
/* ----------------------------------------------------------------- */
gboolean e_plugin_ui_init (GtkUIManager *ui_manager, EMsgComposer *composer);
GtkWidget *e_plugin_lib_get_configure_widget (EPlugin *epl);
void face_handle_send (EPlugin *ep, EMEventTargetComposer *target);
/* ----------------------------------------------------------------- */
gboolean
e_plugin_ui_init (GtkUIManager *ui_manager,
EMsgComposer *composer)
{
GtkhtmlEditor *editor;
static GtkToggleActionEntry entries[] = {
{ "face-plugin",
NULL,
N_("Include _Face"),
NULL,
NULL,
G_CALLBACK (action_toggle_face_cb),
FALSE }
};
if (get_include_face_by_default ()) {
gchar *face = get_face_base64 ();
/* activate it only if has a face image available */
entries[0].is_active = face && *face;
g_free (face);
}
editor = GTKHTML_EDITOR (composer);
/* Add actions to the "composer" action group. */
gtk_action_group_add_toggle_actions (
gtkhtml_editor_get_action_group (editor, "composer"),
entries, G_N_ELEMENTS (entries), composer);
return TRUE;
}
GtkWidget *
e_plugin_lib_get_configure_widget (EPlugin *epl)
{
return get_cfg_widget ();
}
void
face_handle_send (EPlugin *ep, EMEventTargetComposer *target)
{
GtkhtmlEditor *editor;
GtkAction *action;
editor = GTKHTML_EDITOR (target->composer);
action = gtkhtml_editor_get_action (editor, "face-plugin");
g_return_if_fail (action != NULL);
if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
gchar *face = get_face_base64 ();
if (face)
e_msg_composer_modify_header (target->composer, "Face", face);
g_free (face);
}
}