In gtk now we instantiate the new ModestFindToolbar
[modest] / src / widgets / modest-gtkhtml-msg-view.c
1 /* Copyright (c) 2006, 2007, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <config.h>
31 #include <tny-gtk-text-buffer-stream.h>
32 #include <string.h>
33 #include <regex.h>
34 #include <ctype.h>
35 #include <stdlib.h>
36 #include <glib/gi18n.h>
37 #include <tny-list.h>
38 #include <tny-simple-list.h>
39 #include <tny-vfs-stream.h>
40
41 #include <modest-tny-msg.h>
42 #include <modest-text-utils.h>
43 #include <widgets/modest-msg-view.h>
44 #ifdef MODEST_TOOLKIT_HILDON2
45 #include <widgets/modest-compact-mail-header-view.h>
46 #include <hildon/hildon-gtk.h>
47 #else
48 #include <widgets/modest-expander-mail-header-view.h>
49 #endif
50 #include <widgets/modest-attachments-view.h>
51 #include <modest-marshal.h>
52 #include <widgets/modest-gtkhtml-mime-part-view.h>
53 #include <widgets/modest-gtkhtml-msg-view.h>
54 #include <widgets/modest-isearch-view.h>
55 #include <widgets/modest-ui-constants.h>
56 #include <modest-icon-names.h>
57
58 /* 'private'/'protected' functions */
59 static void     modest_gtkhtml_msg_view_class_init   (ModestGtkhtmlMsgViewClass *klass);
60 static void     tny_header_view_init (gpointer g, gpointer iface_data);
61 static void     tny_msg_view_init (gpointer g, gpointer iface_data);
62 static void     tny_mime_part_view_init (gpointer g, gpointer iface_data);
63 static void     modest_mime_part_view_init (gpointer g, gpointer iface_data);
64 static void     modest_zoomable_init (gpointer g, gpointer iface_data);
65 static void     modest_isearch_view_init (gpointer g, gpointer iface_data);
66 static void     modest_msg_view_init (gpointer g, gpointer iface_data);
67 static void     modest_gtkhtml_msg_view_init         (ModestGtkhtmlMsgView *obj);
68 static void     modest_gtkhtml_msg_view_finalize     (GObject *obj);
69 static void     modest_gtkhtml_msg_view_destroy     (GtkObject *obj);
70 static void     set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
71 static void     get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
72
73 /* headers signals */
74 static void on_recpt_activated (ModestMailHeaderView *header_view, const gchar *address, ModestGtkhtmlMsgView *msg_view);
75 static void on_show_details (ModestMailHeaderView *header_view, ModestGtkhtmlMsgView *msg_view);
76 static void on_attachment_activated (ModestAttachmentsView * att_view, TnyMimePart *mime_part, gpointer userdata);
77
78 /* body view signals */
79 static gboolean on_activate_link (GtkWidget *widget, const gchar *uri, ModestGtkhtmlMsgView *msg_view);
80 static gboolean on_fetch_url (GtkWidget *widget, const gchar *uri, TnyStream *stream,
81                               ModestGtkhtmlMsgView *msg_view);
82 static gboolean on_link_hover (GtkWidget *widget, const gchar *uri, ModestGtkhtmlMsgView *msg_view);
83 static void on_limit_error (GtkWidget *widget, ModestGtkhtmlMsgView *msg_view);
84
85 #ifdef MAEMO_CHANGES
86 static void     on_tap_and_hold (GtkWidget *widget, gpointer userdata); 
87 static gboolean on_tap_and_hold_query (GtkWidget *widget, GdkEvent *event, gpointer userdata); 
88 #endif /*MAEMO_CHANGES*/
89
90
91 /* size allocation and drawing handlers */
92 static void get_view_allocation (ModestGtkhtmlMsgView *msg_view, GtkAllocation *allocation);
93 static void size_request (GtkWidget *widget, GtkRequisition *req);
94 static void size_allocate (GtkWidget *widget, GtkAllocation *alloc);
95 static void realize (GtkWidget *widget);
96 static void unrealize (GtkWidget *widget);
97 static gint expose (GtkWidget *widget, GdkEventExpose *event);
98 static void reclamp_adjustment (GtkAdjustment *adj, gboolean *value_changed);
99 static void set_hadjustment_values (ModestGtkhtmlMsgView *msg_view, gboolean *value_changed);
100 static void set_scroll_adjustments (ModestGtkhtmlMsgView *msg_view, GtkAdjustment *hadj, GtkAdjustment *vadj);
101 static void adjustment_value_changed (GtkAdjustment *adj, gpointer data);
102 static void html_adjustment_changed (GtkAdjustment *adj, gpointer data);
103 static void disconnect_vadjustment (ModestGtkhtmlMsgView *obj);
104 static void disconnect_hadjustment (ModestGtkhtmlMsgView *obj);
105 static gboolean idle_readjust_scroll (ModestGtkhtmlMsgView *obj);
106
107 /* vertical panning implementation */
108 #ifdef MAEMO_CHANGES
109 static gboolean motion_notify_event (GtkWidget *widget,
110                                      GdkEventMotion *event,
111                                      gpointer userdata);
112 #endif
113
114 static gboolean 
115 button_press_event (GtkWidget *widget,
116                     GdkEventButton *event,
117                     gpointer userdata);
118 static gboolean 
119 button_release_event (GtkWidget *widget,
120                       GdkEventButton *event,
121                       gpointer userdata);
122
123 /* GtkContainer methods */
124 static void forall (GtkContainer *container, gboolean include_internals,
125                     GtkCallback callback, gpointer userdata);
126 static void container_remove (GtkContainer *container, GtkWidget *widget);
127
128 /* TnyMimePartView implementation */
129 static void modest_msg_view_mp_clear (TnyMimePartView *self);
130 static void modest_msg_view_mp_set_part (TnyMimePartView *self, TnyMimePart *part);
131 static void modest_msg_view_mp_set_part_default (TnyMimePartView *self, TnyMimePart *part);
132 static TnyMimePart* modest_msg_view_mp_get_part (TnyMimePartView *self);
133 static TnyMimePart* modest_msg_view_mp_get_part_default (TnyMimePartView *self);
134 /* ModestMimePartView implementation */
135 static gboolean modest_msg_view_mp_is_empty (ModestMimePartView *self);
136 static gboolean modest_msg_view_mp_is_empty_default (ModestMimePartView *self);
137 /* TnyHeaderView implementation */
138 static void modest_msg_view_set_header (TnyHeaderView *self, TnyHeader *header);
139 static void modest_msg_view_set_header_default (TnyHeaderView *self, TnyHeader *header);
140 static void modest_msg_view_clear_header (TnyHeaderView *self);
141 static void modest_msg_view_clear_header_default (TnyHeaderView *self);
142 /* TnyMsgView implementation */
143 static TnyMsg *modest_msg_view_get_msg (TnyMsgView *self);
144 static TnyMsg *modest_msg_view_get_msg_default (TnyMsgView *self);
145 static void modest_msg_view_set_msg (TnyMsgView *self, TnyMsg *msg);
146 static void modest_msg_view_set_msg_default (TnyMsgView *self, TnyMsg *msg);
147 static void modest_msg_view_clear (TnyMsgView *self);
148 static void modest_msg_view_clear_default (TnyMsgView *self);
149 static void modest_msg_view_set_unavailable (TnyMsgView *self);
150 static void modest_msg_view_set_unavailable_default (TnyMsgView *self);
151 static TnyMimePartView *modest_msg_view_create_mime_part_view_for (TnyMsgView *self, TnyMimePart *part);
152 static TnyMimePartView *modest_msg_view_create_mime_part_view_for_default (TnyMsgView *self, TnyMimePart *part);
153 static TnyMsgView *modest_msg_view_create_new_inline_viewer (TnyMsgView *self);
154 static TnyMsgView *modest_msg_view_create_new_inline_viewer_default (TnyMsgView *self);
155 /* ModestZoomable implementation */
156 static gdouble modest_msg_view_get_zoom (ModestZoomable *self);
157 static void modest_msg_view_set_zoom (ModestZoomable *self, gdouble value);
158 static gboolean modest_msg_view_zoom_minus (ModestZoomable *self);
159 static gboolean modest_msg_view_zoom_plus (ModestZoomable *self);
160 static gdouble modest_msg_view_get_zoom_default (ModestZoomable *self);
161 static void modest_msg_view_set_zoom_default (ModestZoomable *self, gdouble value);
162 static gboolean modest_msg_view_zoom_minus_default (ModestZoomable *self);
163 static gboolean modest_msg_view_zoom_plus_default (ModestZoomable *self);
164 /* ModestISearchView implementation */
165 static gboolean modest_msg_view_search (ModestISearchView *self, const gchar *string);
166 static gboolean modest_msg_view_search_default (ModestISearchView *self, const gchar *string);
167 static gboolean modest_msg_view_search_next (ModestISearchView *self);
168 static gboolean modest_msg_view_search_next_default (ModestISearchView *self);
169 /* ModestMsgView implementation */
170 static void modest_gtkhtml_msg_view_set_msg_with_other_body (ModestMsgView *self, TnyMsg *msg, TnyMimePart *other_body);
171 static GtkAdjustment *modest_gtkhtml_msg_view_get_vadjustment (ModestMsgView *self);
172 static GtkAdjustment *modest_gtkhtml_msg_view_get_hadjustment (ModestMsgView *self);
173 static void modest_gtkhtml_msg_view_set_vadjustment (ModestMsgView *self, GtkAdjustment *vadj);
174 static void modest_gtkhtml_msg_view_set_hadjustment (ModestMsgView *self, GtkAdjustment *hadj);
175 static void modest_gtkhtml_msg_view_set_shadow_type (ModestMsgView *self, GtkShadowType type);
176 static GtkShadowType modest_gtkhtml_msg_view_get_shadow_type (ModestMsgView *self);
177 static TnyHeaderFlags modest_gtkhtml_msg_view_get_priority (ModestMsgView *self);
178 static void modest_gtkhtml_msg_view_set_priority (ModestMsgView *self, TnyHeaderFlags flags);
179 static TnyList *modest_gtkhtml_msg_view_get_selected_attachments (ModestMsgView *self);
180 static TnyList *modest_gtkhtml_msg_view_get_attachments (ModestMsgView *self);
181 static void modest_gtkhtml_msg_view_grab_focus (ModestMsgView *self);
182 static void modest_gtkhtml_msg_view_remove_attachment (ModestMsgView *view, TnyMimePart *attachment);
183 static void modest_gtkhtml_msg_view_request_fetch_images (ModestMsgView *view);
184 static void modest_gtkhtml_msg_view_set_branding (ModestMsgView *view, const gchar *brand_name, const GdkPixbuf *brand_icon);
185 static gboolean modest_gtkhtml_msg_view_has_blocked_external_images (ModestMsgView *view);
186 static void modest_gtkhtml_msg_view_set_msg_with_other_body_default (ModestMsgView *view, TnyMsg *msg, TnyMimePart *part);
187 static GtkAdjustment *modest_gtkhtml_msg_view_get_vadjustment_default (ModestMsgView *self);
188 static GtkAdjustment *modest_gtkhtml_msg_view_get_hadjustment_default (ModestMsgView *self);
189 static void modest_gtkhtml_msg_view_set_vadjustment_default (ModestMsgView *self, GtkAdjustment *vadj);
190 static void modest_gtkhtml_msg_view_set_hadjustment_default (ModestMsgView *self, GtkAdjustment *hadj);
191 static void modest_gtkhtml_msg_view_set_shadow_type_default (ModestMsgView *self, GtkShadowType type);
192 static GtkShadowType modest_gtkhtml_msg_view_get_shadow_type_default (ModestMsgView *self);
193 static TnyHeaderFlags modest_gtkhtml_msg_view_get_priority_default (ModestMsgView *self);
194 static void modest_gtkhtml_msg_view_set_priority_default (ModestMsgView *self, TnyHeaderFlags flags);
195 static TnyList *modest_gtkhtml_msg_view_get_selected_attachments_default (ModestMsgView *self);
196 static TnyList *modest_gtkhtml_msg_view_get_attachments_default (ModestMsgView *self);
197 static void modest_gtkhtml_msg_view_grab_focus_default (ModestMsgView *self);
198 static void modest_gtkhtml_msg_view_remove_attachment_default (ModestMsgView *view, TnyMimePart *attachment);
199 static gboolean modest_gtkhtml_msg_view_has_blocked_external_images_default (ModestMsgView *view);
200 static void modest_gtkhtml_msg_view_request_fetch_images_default (ModestMsgView *view);
201 static void modest_gtkhtml_msg_view_set_branding_default (ModestMsgView *view, const gchar *brand_name, const GdkPixbuf *brand_icon);
202
203 /* internal api */
204 static void     set_header     (ModestGtkhtmlMsgView *self, TnyHeader *header);
205 static TnyMsg   *get_message   (ModestGtkhtmlMsgView *self);
206 static void     set_message    (ModestGtkhtmlMsgView *self, TnyMsg *tny_msg, TnyMimePart *other_body);
207 static gboolean is_empty       (ModestGtkhtmlMsgView *self); 
208 static void     set_zoom       (ModestGtkhtmlMsgView *self, gdouble zoom);
209 static gdouble  get_zoom       (ModestGtkhtmlMsgView *self);
210 static gboolean search         (ModestGtkhtmlMsgView *self, const gchar *search);
211 static gboolean search_next    (ModestGtkhtmlMsgView *self);
212 static GtkAdjustment *get_vadjustment (ModestGtkhtmlMsgView *self);
213 static GtkAdjustment *get_hadjustment (ModestGtkhtmlMsgView *self);
214 static void set_vadjustment (ModestGtkhtmlMsgView *self, GtkAdjustment *vadj);
215 static void set_hadjustment (ModestGtkhtmlMsgView *self, GtkAdjustment *hadj);
216 static void set_shadow_type (ModestGtkhtmlMsgView *self, GtkShadowType type);
217 static GtkShadowType get_shadow_type (ModestGtkhtmlMsgView *self);
218 static TnyHeaderFlags get_priority (ModestGtkhtmlMsgView *self);
219 static void set_priority (ModestGtkhtmlMsgView *self, TnyHeaderFlags flags);
220 static TnyList *get_selected_attachments (ModestGtkhtmlMsgView *self);
221 static TnyList *get_attachments (ModestGtkhtmlMsgView *self);
222 static void grab_focus (ModestGtkhtmlMsgView *self);
223 static void remove_attachment (ModestGtkhtmlMsgView *view, TnyMimePart *attachment);
224 static void request_fetch_images (ModestGtkhtmlMsgView *view);
225 static void set_branding (ModestGtkhtmlMsgView *view, const gchar *brand_name, const GdkPixbuf *brand_icon);
226 static gboolean has_blocked_external_images (ModestGtkhtmlMsgView *view);
227
228 /* list properties */
229 enum {
230         PROP_0,
231         PROP_HADJUSTMENT,
232         PROP_VADJUSTMENT,
233         PROP_SHADOW_TYPE
234 };
235
236 typedef struct _ModestGtkhtmlMsgViewPrivate ModestGtkhtmlMsgViewPrivate;
237 struct _ModestGtkhtmlMsgViewPrivate {
238         GtkWidget   *body_view;
239         GtkWidget   *mail_header_view;
240         GtkWidget   *attachments_view;
241
242         TnyMsg      *msg;
243
244         /* embedded elements */
245         GtkWidget   *headers_box;
246         GtkWidget   *html_scroll;
247         GtkWidget   *attachments_box;
248
249 #ifdef MODEST_TOOLKIT_HILDON2
250         GtkWidget   *priority_box;
251         GtkWidget   *priority_icon;
252 #endif
253
254         /* internal adjustments for set_scroll_adjustments */
255         GtkAdjustment *hadj;
256         GtkAdjustment *vadj;
257         GtkShadowType shadow_type;
258
259         /* gdk windows for drawing */
260         GdkWindow *view_window;
261         GdkWindow *headers_window;
262         GdkWindow *html_window;
263
264         /* id handler for dragged scroll */
265         guint idle_motion_id;
266
267         /* idle changes count */
268         gint idle_changes_count;
269         guint idle_readjust_scroll_id;
270         guint idle_resize_children_id;
271
272         /* zoom */
273         gdouble current_zoom;
274
275         /* link click management */
276         gchar *last_url;
277 };
278
279 #define MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
280                                                                                  MODEST_TYPE_GTKHTML_MSG_VIEW, \
281                                                                                  ModestGtkhtmlMsgViewPrivate))
282
283 /* globals */
284 static GtkContainerClass *parent_class = NULL;
285
286 GType
287 modest_gtkhtml_msg_view_get_type (void)
288 {
289         static GType my_type = 0;
290         if (!my_type) {
291                 static const GTypeInfo my_info = {
292                         sizeof(ModestGtkhtmlMsgViewClass),
293                         NULL,           /* base init */
294                         NULL,           /* base finalize */
295                         (GClassInitFunc) modest_gtkhtml_msg_view_class_init,
296                         NULL,           /* class finalize */
297                         NULL,           /* class data */
298                         sizeof(ModestGtkhtmlMsgView),
299                         1,              /* n_preallocs */
300                         (GInstanceInitFunc) modest_gtkhtml_msg_view_init,
301                         NULL
302                 };
303                 static const GInterfaceInfo tny_msg_view_info = 
304                 {
305                   (GInterfaceInitFunc) tny_msg_view_init, /* interface_init */
306                   NULL,         /* interface_finalize */
307                   NULL          /* interface_data */
308                 };
309
310                 static const GInterfaceInfo tny_mime_part_view_info = 
311                 {
312                   (GInterfaceInitFunc) tny_mime_part_view_init, /* interface_init */
313                   NULL,         /* interface_finalize */
314                   NULL          /* interface_data */
315                 };
316
317                 static const GInterfaceInfo tny_header_view_info = 
318                 {
319                   (GInterfaceInitFunc) tny_header_view_init, /* interface_init */
320                   NULL,         /* interface_finalize */
321                   NULL          /* interface_data */
322                 };
323
324                 static const GInterfaceInfo modest_mime_part_view_info = 
325                 {
326                   (GInterfaceInitFunc) modest_mime_part_view_init, /* interface_init */
327                   NULL,         /* interface_finalize */
328                   NULL          /* interface_data */
329                 };
330
331                 static const GInterfaceInfo modest_zoomable_info = 
332                 {
333                   (GInterfaceInitFunc) modest_zoomable_init, /* interface_init */
334                   NULL,         /* interface_finalize */
335                   NULL          /* interface_data */
336                 };
337
338                 static const GInterfaceInfo modest_isearch_view_info = 
339                 {
340                   (GInterfaceInitFunc) modest_isearch_view_init, /* interface_init */
341                   NULL,         /* interface_finalize */
342                   NULL          /* interface_data */
343                 };
344
345                 static const GInterfaceInfo modest_msg_view_info = 
346                 {
347                   (GInterfaceInitFunc) modest_msg_view_init, /* interface_init */
348                   NULL,         /* interface_finalize */
349                   NULL          /* interface_data */
350                 };
351
352                 my_type = g_type_register_static (GTK_TYPE_CONTAINER,
353                                                   "ModestGtkhtmlMsgView",
354                                                   &my_info, 0);
355
356                 g_type_add_interface_static (my_type, TNY_TYPE_HEADER_VIEW, 
357                         &tny_header_view_info);
358
359                 g_type_add_interface_static (my_type, TNY_TYPE_MIME_PART_VIEW, 
360                         &tny_mime_part_view_info);
361
362                 g_type_add_interface_static (my_type, MODEST_TYPE_MIME_PART_VIEW, 
363                         &modest_mime_part_view_info);
364
365                 g_type_add_interface_static (my_type, TNY_TYPE_MSG_VIEW, 
366                         &tny_msg_view_info);
367
368                 g_type_add_interface_static (my_type, MODEST_TYPE_ZOOMABLE, 
369                         &modest_zoomable_info);
370
371                 g_type_add_interface_static (my_type, MODEST_TYPE_ISEARCH_VIEW, 
372                         &modest_isearch_view_info);
373
374                 g_type_add_interface_static (my_type, MODEST_TYPE_MSG_VIEW, 
375                         &modest_msg_view_info);
376         }
377         return my_type;
378 }
379
380 static void
381 modest_gtkhtml_msg_view_class_init (ModestGtkhtmlMsgViewClass *klass)
382 {
383         GObjectClass *gobject_class;
384         GtkWidgetClass *widget_class;
385         GtkObjectClass *gtkobject_class;
386         GtkContainerClass *container_class;
387         gobject_class = (GObjectClass*) klass;
388         widget_class = (GtkWidgetClass *) klass;
389         gtkobject_class = (GtkObjectClass *) klass;
390         container_class = (GtkContainerClass *) klass;
391
392         parent_class            = g_type_class_peek_parent (klass);
393         gobject_class->finalize = modest_gtkhtml_msg_view_finalize;
394         gobject_class->set_property = set_property;
395         gobject_class->get_property = get_property;
396         gtkobject_class->destroy = modest_gtkhtml_msg_view_destroy;
397
398         widget_class->realize = realize;
399         widget_class->unrealize = unrealize;
400         widget_class->expose_event = expose;
401         widget_class->size_request = size_request;
402         widget_class->size_allocate = size_allocate;
403
404         container_class->forall = forall;
405         container_class->remove = container_remove;
406
407         klass->set_header_func = modest_msg_view_set_header_default;
408         klass->clear_header_func = modest_msg_view_clear_header_default;
409         klass->set_scroll_adjustments = set_scroll_adjustments;
410         klass->get_part_func = modest_msg_view_mp_get_part_default;
411         klass->set_part_func = modest_msg_view_mp_set_part_default;
412         klass->is_empty_func = modest_msg_view_mp_is_empty_default;
413         klass->get_msg_func = modest_msg_view_get_msg_default;
414         klass->set_msg_func = modest_msg_view_set_msg_default;
415         klass->set_unavailable_func = modest_msg_view_set_unavailable_default;
416         klass->clear_func = modest_msg_view_clear_default;
417         klass->create_mime_part_view_for_func = modest_msg_view_create_mime_part_view_for_default;
418         klass->create_new_inline_viewer_func = modest_msg_view_create_new_inline_viewer_default;
419         klass->get_zoom_func = modest_msg_view_get_zoom_default;
420         klass->set_zoom_func = modest_msg_view_set_zoom_default;
421         klass->zoom_minus_func = modest_msg_view_zoom_minus_default;
422         klass->zoom_plus_func = modest_msg_view_zoom_plus_default;
423         klass->search_func = modest_msg_view_search_default;
424         klass->search_next_func = modest_msg_view_search_next_default;
425         klass->set_msg_with_other_body_func = modest_gtkhtml_msg_view_set_msg_with_other_body_default;
426         klass->get_vadjustment_func = modest_gtkhtml_msg_view_get_vadjustment_default;
427         klass->get_hadjustment_func = modest_gtkhtml_msg_view_get_hadjustment_default;
428         klass->set_vadjustment_func = modest_gtkhtml_msg_view_set_vadjustment_default;
429         klass->set_hadjustment_func = modest_gtkhtml_msg_view_set_hadjustment_default;
430         klass->get_shadow_type_func = modest_gtkhtml_msg_view_get_shadow_type_default;
431         klass->set_shadow_type_func = modest_gtkhtml_msg_view_set_shadow_type_default;
432         klass->get_priority_func = modest_gtkhtml_msg_view_get_priority_default;
433         klass->set_priority_func = modest_gtkhtml_msg_view_set_priority_default;
434         klass->get_selected_attachments_func = modest_gtkhtml_msg_view_get_selected_attachments_default;
435         klass->get_attachments_func = modest_gtkhtml_msg_view_get_attachments_default;
436         klass->grab_focus_func = modest_gtkhtml_msg_view_grab_focus_default;
437         klass->remove_attachment_func = modest_gtkhtml_msg_view_remove_attachment_default;
438         klass->request_fetch_images_func = modest_gtkhtml_msg_view_request_fetch_images_default;
439         klass->set_branding_func = modest_gtkhtml_msg_view_set_branding_default;
440         klass->has_blocked_external_images_func = modest_gtkhtml_msg_view_has_blocked_external_images_default;
441
442         g_type_class_add_private (gobject_class, sizeof(ModestGtkhtmlMsgViewPrivate));
443
444         g_object_class_install_property (gobject_class,
445                                          PROP_HADJUSTMENT,
446                                          g_param_spec_object ("hadjustment", 
447                                                               _("Horizontal adjustment"),
448                                                               _("GtkAdjustment with information of the horizontal visible position"),
449                                                               GTK_TYPE_ADJUSTMENT,
450                                                               G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
451
452         g_object_class_install_property (gobject_class,
453                                          PROP_VADJUSTMENT,
454                                          g_param_spec_object ("vadjustment", 
455                                                               _("Vertical adjustment"),
456                                                               _("GtkAdjustment with information of the vertical visible position"),
457                                                               GTK_TYPE_ADJUSTMENT,
458                                                               G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
459
460         g_object_class_install_property (gobject_class,
461                                          PROP_SHADOW_TYPE,
462                                          g_param_spec_enum ("shadow_type", 
463                                                             _("Shadow type"),
464                                                             _("Kind of shadow that's shown around the view"),
465                                                             GTK_TYPE_SHADOW_TYPE,
466                                                             GTK_SHADOW_IN,
467                                                             G_PARAM_READABLE | G_PARAM_WRITABLE ));
468
469         widget_class->set_scroll_adjustments_signal =
470                 g_signal_new ("set_scroll_adjustments",
471                               G_OBJECT_CLASS_TYPE (gobject_class),
472                               G_SIGNAL_RUN_LAST|G_SIGNAL_ACTION,
473                               G_STRUCT_OFFSET (ModestGtkhtmlMsgViewClass, set_scroll_adjustments),
474                               NULL, NULL,
475                               modest_marshal_VOID__POINTER_POINTER,
476                               G_TYPE_NONE, 2,
477                               GTK_TYPE_ADJUSTMENT,
478                               GTK_TYPE_ADJUSTMENT);
479 }
480
481 static void
482 set_property (GObject *object, 
483               guint prop_id, 
484               const GValue *value, 
485               GParamSpec *pspec)
486 {
487         ModestGtkhtmlMsgView *self = MODEST_GTKHTML_MSG_VIEW (object);
488
489         switch (prop_id) {
490         case PROP_HADJUSTMENT:
491                 set_hadjustment (self, g_value_get_object (value));
492                 break;
493         case PROP_VADJUSTMENT:
494                 set_vadjustment (self, g_value_get_object (value));
495                 break;
496         case PROP_SHADOW_TYPE:
497                 set_shadow_type (self, g_value_get_enum (value));
498                 break;
499         default:
500                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
501                 break;
502         }
503 }
504
505 static void
506 get_property (GObject *object, 
507               guint prop_id, 
508               GValue *value, 
509               GParamSpec *pspec)
510 {
511         ModestGtkhtmlMsgView *self = MODEST_GTKHTML_MSG_VIEW (object);
512         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
513
514         switch (prop_id) {
515         case PROP_HADJUSTMENT:
516                 g_value_set_object (value, priv->hadj);
517                 break;
518         case PROP_VADJUSTMENT:
519                 g_value_set_object (value, priv->vadj);
520                 break;
521         case PROP_SHADOW_TYPE:
522                 g_value_set_enum (value, priv->shadow_type);
523                 break;
524         default:
525                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
526                 break;
527         }
528 }
529
530 static void
531 disconnect_hadjustment (ModestGtkhtmlMsgView *self)
532 {
533         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
534
535         if (priv->hadj) {
536                 g_signal_handlers_disconnect_by_func(priv->hadj, adjustment_value_changed, self);
537                 g_object_unref (priv->hadj);
538                 priv->hadj = NULL;
539         }
540 }
541
542 static void
543 disconnect_vadjustment (ModestGtkhtmlMsgView *self)
544 {
545         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
546
547         if (priv->vadj) {
548                 g_signal_handlers_disconnect_by_func(priv->vadj, adjustment_value_changed, self);
549                 g_object_unref (priv->vadj);
550                 priv->vadj = NULL;
551         }
552 }
553
554 static void 
555 get_view_allocation (ModestGtkhtmlMsgView *self, GtkAllocation *allocation)
556 {
557         /* This method gets the allocation of the widget in parent widget. It's the
558            real position and size of the widget */
559         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
560         
561         allocation->x = 0;
562         allocation->y = 0;
563
564         if (priv->shadow_type != GTK_SHADOW_NONE) {
565                 allocation->x = GTK_WIDGET (self)->style->xthickness;
566                 allocation->y = GTK_WIDGET (self)->style->ythickness;
567         }
568
569         allocation->width = MAX (1, (GTK_WIDGET (self)->allocation.width) - allocation->x * 2);
570         allocation->height = MAX (1, (GTK_WIDGET (self)->allocation.height) - allocation->y * 2);
571
572 }
573
574 static void 
575 reclamp_adjustment (GtkAdjustment *adj, 
576                     gboolean *value_changed)
577 {
578         gdouble value = adj->value;
579
580         /* Correct value to be inside the expected values of a scroll */
581
582         value = CLAMP (value, 0, adj->upper - adj->page_size);
583
584         if (value != adj->value) {
585                 adj->value = value;
586                 if (value_changed)
587                         *value_changed = TRUE;
588         } else if (value_changed) {
589                 *value_changed = FALSE;
590         }
591 }
592
593 static void 
594 set_hadjustment_values (ModestGtkhtmlMsgView *self,
595                         gboolean *value_changed)
596 {
597         GtkAllocation view_allocation;
598         GtkAdjustment *hadj = get_hadjustment (self);
599         gint full_width = 0;
600         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
601
602         get_view_allocation (self, &view_allocation);
603         hadj->page_size = view_allocation.width;
604         hadj->step_increment = view_allocation.width * 0.1;
605         hadj->page_increment = view_allocation.width * 0.9;
606
607         hadj->lower = 0;
608         hadj->upper = view_allocation.width;
609
610         /* Get the real width of the embedded html */
611         if (priv->html_scroll && GTK_WIDGET_VISIBLE(priv->html_scroll)) {
612                 GtkAdjustment *html_hadj;
613                 html_hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
614                 full_width += html_hadj->upper;
615         }
616
617         hadj->upper = MAX (view_allocation.width, full_width);
618
619         reclamp_adjustment (hadj, value_changed);
620
621 }
622
623 static void
624 set_vadjustment_values (ModestGtkhtmlMsgView *self,
625                         gboolean *value_changed)
626 {
627         GtkAllocation view_allocation;
628         GtkAdjustment *vadj = get_vadjustment (self);
629         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
630         gint full_height = 0;
631         GtkAdjustment *html_vadj;
632
633         get_view_allocation (self, &view_allocation);
634         vadj->page_size = view_allocation.height;
635         vadj->step_increment = view_allocation.height * 0.1;
636         vadj->page_increment = view_allocation.height * 0.9;
637
638         vadj->lower = 0;
639
640         if (priv->headers_box && GTK_WIDGET_VISIBLE(priv->headers_box)) {
641                 GtkRequisition child_requisition;
642
643                 gtk_widget_get_child_requisition (priv->headers_box, &child_requisition);
644                 full_height = child_requisition.height;
645         } else {
646                 full_height = 0;
647         }
648         
649         /* Get the real height of the embedded html */
650         if (priv->html_scroll && GTK_WIDGET_VISIBLE(priv->html_scroll)) {
651                 html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
652                 full_height += html_vadj->upper;
653         }
654
655         vadj->upper = MAX (view_allocation.height, full_height);
656
657         reclamp_adjustment (vadj, value_changed);
658
659 }
660
661 static void
662 set_scroll_adjustments (ModestGtkhtmlMsgView *self,
663                         GtkAdjustment *hadj,
664                         GtkAdjustment *vadj)
665 {
666         set_hadjustment (self, hadj);
667         set_vadjustment (self, vadj);
668
669 #ifndef MODEST_TOOLKIT_HILDON2
670         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
671         gtk_container_set_focus_vadjustment (GTK_CONTAINER (priv->body_view), vadj);
672 #endif
673 }
674
675 static void
676 realize (GtkWidget *widget)
677 {
678         ModestGtkhtmlMsgView *self = MODEST_GTKHTML_MSG_VIEW (widget);
679         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
680         GtkAdjustment *hadj = get_hadjustment (self);
681         GtkAdjustment *vadj = get_vadjustment (self);
682         GdkWindowAttr attributes;
683         gint event_mask;
684         gint attributes_mask;
685         GtkAllocation view_allocation;
686
687         GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
688
689         /* The structure of the GdkWindow's is:
690          *    * widget->window: the shown gdkwindow embedding all the stuff inside
691          *    * view_window: a backing store gdkwindow containing the headers and contents
692          *      being scrolled. This window should have all the visible and non visible
693          *      widgets inside.
694          *    * headers_window: gdk window for headers_box.
695          *    * html_window: gdk window for html_scroll (the scrolled window containing the
696          *      body view showing the contents of the mail).
697          */
698
699         attributes.x = widget->allocation.x;
700         attributes.y = widget->allocation.y;
701         attributes.width = widget->allocation.width;
702         attributes.height = widget->allocation.height;
703         attributes.window_type = GDK_WINDOW_CHILD;
704         attributes.wclass = GDK_INPUT_OUTPUT;
705         attributes.visual = gtk_widget_get_visual (widget);
706         attributes.colormap = gtk_widget_get_colormap (widget);
707
708         event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
709         attributes.event_mask = event_mask | GDK_BUTTON_PRESS_MASK;
710         attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
711
712         widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
713                                          &attributes, attributes_mask);
714         gdk_window_set_user_data (widget->window, self);
715
716         get_view_allocation (self, &view_allocation);
717
718         attributes.x = view_allocation.x;
719         attributes.y = view_allocation.y;
720         attributes.width = view_allocation.width;
721         attributes.height = view_allocation.height;
722         attributes.event_mask = 0;
723         priv->view_window = gdk_window_new (widget->window, &attributes, attributes_mask);
724         gdk_window_set_user_data (priv->view_window, self);
725         gdk_window_set_back_pixmap (priv->view_window, NULL, FALSE);
726
727         attributes.x = -hadj->value;
728         attributes.y = -vadj->value;
729         attributes.width = hadj->upper;
730         if (priv->headers_box)
731                 attributes.height = GTK_WIDGET (priv->headers_box)->allocation.height;
732         else
733                 attributes.height = 1;
734         attributes.event_mask = event_mask;
735
736         priv->headers_window = gdk_window_new (priv->view_window, &attributes, attributes_mask);
737         gdk_window_set_user_data (priv->headers_window, self);
738
739         if (priv->headers_box)
740                 gtk_widget_set_parent_window (priv->headers_box, priv->headers_window);
741
742         attributes.x = -hadj->value;
743         if (priv->headers_box)
744                 attributes.y = GTK_WIDGET (priv->headers_box)->allocation.height - vadj->value;
745         else 
746                 attributes.y = -vadj->value;
747         attributes.width = hadj->upper;
748         if (priv->headers_box)
749                 attributes.height = vadj->upper - GTK_WIDGET (priv->headers_box)->allocation.height;
750         else
751                 attributes.height = vadj->upper;
752         attributes.event_mask = event_mask;
753
754         priv->html_window = gdk_window_new (priv->view_window, &attributes, attributes_mask);
755         gdk_window_set_user_data (priv->html_window, self);
756
757         if (priv->html_scroll)
758                 gtk_widget_set_parent_window (priv->html_scroll, priv->html_window);
759
760         widget->style = gtk_style_attach (widget->style, widget->window);
761         gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
762         gtk_style_set_background (widget->style, priv->headers_window, GTK_STATE_NORMAL);
763         gtk_style_set_background (widget->style, priv->html_window, GTK_STATE_NORMAL);
764
765         gtk_paint_flat_box(widget->style, priv->headers_window, GTK_STATE_NORMAL,
766                            GTK_SHADOW_NONE, 
767                            NULL, widget, "msgviewheaders",
768                            0,0,-1,-1);
769         gtk_paint_flat_box(widget->style, priv->html_window, GTK_STATE_NORMAL,
770                            GTK_SHADOW_NONE, 
771                            NULL, widget, "msgviewcontents",
772                            0,0,-1,-1);
773
774         gdk_window_show (priv->view_window);
775         gdk_window_show (priv->headers_window);
776         gdk_window_show (priv->html_window);
777
778 }
779
780 static void
781 unrealize (GtkWidget *widget)
782 {
783         ModestGtkhtmlMsgView *self = MODEST_GTKHTML_MSG_VIEW (widget);
784         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
785
786         gdk_window_set_user_data (priv->view_window, NULL);
787         gdk_window_destroy (priv->view_window);
788         priv->view_window = NULL;
789
790         gdk_window_set_user_data (priv->headers_window, NULL);
791         gdk_window_destroy (priv->headers_window);
792         priv->headers_window = NULL;
793
794         gdk_window_set_user_data (priv->html_window, NULL);
795         gdk_window_destroy (priv->html_window);
796         priv->html_window = NULL;
797
798         if (GTK_WIDGET_CLASS (parent_class)->unrealize)
799                 ( * GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
800
801 }
802
803 static gint
804 expose (GtkWidget *widget, 
805         GdkEventExpose *event)
806 {
807         ModestGtkhtmlMsgView *self;
808         ModestGtkhtmlMsgViewPrivate *priv;
809
810         if (GTK_WIDGET_DRAWABLE (widget)) {
811                 self = MODEST_GTKHTML_MSG_VIEW (widget);
812                 priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
813                 if (event->window == widget->window) {
814                         gtk_paint_shadow (widget->style, widget->window,
815                                           GTK_STATE_NORMAL, priv->shadow_type,
816                                           &event->area, widget, "msgview",
817                                           0,0,-1,-1);
818                 } else if (event->window == priv->headers_window) {
819                         gtk_paint_flat_box(widget->style, priv->headers_window, GTK_STATE_NORMAL,
820                                            GTK_SHADOW_NONE, 
821                                            &event->area, widget, "msgviewheaders",
822                                            0,0,-1,-1);
823                 } else if (event->window == priv->html_window) {
824                         gtk_paint_flat_box(widget->style, priv->html_window, GTK_STATE_NORMAL,
825                                            GTK_SHADOW_NONE, 
826                                            &event->area, widget, "msgviewcontents",
827                                            0,0,-1,-1);
828                 }
829                 if (priv->headers_box)
830                         gtk_container_propagate_expose (GTK_CONTAINER (self), priv->headers_box, event);
831                 if (priv->html_scroll)
832                         gtk_container_propagate_expose (GTK_CONTAINER (self), priv->html_scroll, event);
833                 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
834         }
835
836         return FALSE;
837 }
838
839 static void 
840 forall (GtkContainer *container, 
841         gboolean include_internals,
842         GtkCallback callback,
843         gpointer userdata)
844 {
845         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (container);
846         g_return_if_fail (callback != NULL);
847
848         if (priv->headers_box)
849                 (*callback) (priv->headers_box, userdata);
850         if (priv->html_scroll)
851                 (*callback) (priv->html_scroll, userdata);
852 }
853
854 static void
855 container_remove (GtkContainer *container,
856                   GtkWidget *widget)
857 {
858         gboolean was_visible = FALSE;
859         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (container);
860         was_visible = GTK_WIDGET_VISIBLE (widget);
861         if (widget == priv->headers_box) {
862                 gtk_widget_unparent (priv->headers_box);
863                 priv->headers_box = NULL;
864         } else if (widget == priv->html_scroll) {
865                 gtk_widget_unparent (priv->html_scroll);
866                 priv->html_scroll = NULL;
867         } else {
868                 return;
869         }
870         if (was_visible)
871                 gtk_widget_queue_resize (GTK_WIDGET(container));
872
873 }
874
875 static void
876 size_request (GtkWidget *widget,
877               GtkRequisition *req)
878 {
879         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (widget);
880         GtkRequisition child_req;
881
882         req->width = 0;
883         req->height = 0;
884
885         gtk_widget_size_request (priv->headers_box, &child_req);
886         req->width = child_req.width;
887         req->height += child_req.height;
888         gtk_widget_size_request (priv->html_scroll, &child_req);
889         req->width = MAX (child_req.width, req->width);
890         req->height += child_req.height;
891
892 }
893
894 static void
895 size_allocate (GtkWidget *widget,
896                GtkAllocation *allocation)
897 {
898         ModestGtkhtmlMsgView *self = MODEST_GTKHTML_MSG_VIEW (widget);
899         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
900         gboolean hadj_value_changed, vadj_value_changed;
901         GtkAllocation headers_allocation, html_allocation, view_allocation;
902         GtkAdjustment *html_vadj;
903
904         if (GTK_WIDGET_MAPPED (widget) &&
905             priv->shadow_type != GTK_SHADOW_NONE && 
906             (allocation->width != widget->allocation.width ||
907              allocation->height != widget->allocation.height))
908                 gdk_window_invalidate_rect (widget->window, NULL, FALSE);
909
910         if (priv->idle_readjust_scroll_id == 0 && priv->idle_changes_count < 5 && widget->allocation.width != allocation->width) {
911                 g_object_ref (self);
912                 priv->idle_readjust_scroll_id = g_idle_add ((GSourceFunc) idle_readjust_scroll, self);
913                 priv->idle_changes_count ++;
914         }
915
916         widget->allocation = *allocation;
917         set_hadjustment_values (self, &hadj_value_changed);
918         set_vadjustment_values (self, &vadj_value_changed);
919
920         get_view_allocation (self, &view_allocation);
921
922         headers_allocation.x = 0;
923         headers_allocation.y = 0;
924         headers_allocation.width = view_allocation.width;
925         if (priv->headers_box)
926                 headers_allocation.height = GTK_WIDGET (priv->headers_box)->requisition.height;
927         else
928                 headers_allocation.height = 0;
929
930         html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
931
932         html_allocation.x = 0;
933         html_allocation.y = headers_allocation.height;
934         html_allocation.width = view_allocation.width;
935         html_allocation.height = MAX ((gint) html_vadj->upper, (gint)(priv->vadj->upper - headers_allocation.height));
936
937         if (GTK_WIDGET_REALIZED (widget)) {
938                 gdk_window_move_resize (widget->window,
939                                         allocation->x,
940                                         allocation->y,
941                                         allocation->width,
942                                         allocation->height);
943
944                 gdk_window_move_resize (priv->view_window,
945                                         view_allocation.x,
946                                         view_allocation.y,
947                                         view_allocation.width,
948                                         view_allocation.height);
949                 gdk_window_move_resize (priv->headers_window,
950                                         0,
951                                         (gint) (- priv->vadj->value),
952                                         allocation->width,
953                                         headers_allocation.height);
954                 gdk_window_move_resize (priv->html_window,
955                                         (gint) (- priv->hadj->value),
956                                         (gint) (html_allocation.y - priv->vadj->value),
957                                         (gint) priv->hadj->upper,
958                                         html_allocation.height);
959         }
960
961         if (priv->headers_box && GTK_WIDGET_VISIBLE (priv->headers_box)) {
962                 gtk_widget_size_allocate (priv->headers_box, &headers_allocation);
963         }
964         if (priv->html_scroll && GTK_WIDGET_VISIBLE (priv->html_scroll)) {
965                 html_allocation.x = 0;
966                 html_allocation.y = 0;
967                 html_allocation.width = (gint) priv->hadj->upper;
968                 html_allocation.height = (gint) priv->vadj->upper - headers_allocation.height;
969                 gtk_widget_size_allocate (priv->html_scroll, &html_allocation);
970         }
971         gtk_adjustment_changed (priv->hadj);
972         gtk_adjustment_changed (priv->vadj);
973
974         if (hadj_value_changed)
975                 gtk_adjustment_value_changed (priv->hadj);
976         if (vadj_value_changed)
977                 gtk_adjustment_value_changed (priv->vadj);
978
979 }
980
981 static void 
982 adjustment_value_changed (GtkAdjustment *adj, gpointer data)
983 {
984         ModestGtkhtmlMsgView *self = NULL;
985         ModestGtkhtmlMsgViewPrivate *priv = NULL;
986
987         g_return_if_fail (GTK_IS_ADJUSTMENT (adj));
988         g_return_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (data));
989
990         self = MODEST_GTKHTML_MSG_VIEW (data);
991         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
992
993         if (GTK_WIDGET_REALIZED (self)) {
994                 GtkAdjustment *hadj = get_hadjustment (self);
995                 GtkAdjustment *vadj = get_vadjustment (self);
996                 gint headers_offset = 0;
997
998                 gtk_widget_queue_resize (priv->html_scroll);
999
1000                 if (priv->headers_box && GTK_WIDGET_VISIBLE (priv->headers_box)) {
1001                         gint old_x, old_y;
1002                         gint new_x, new_y;
1003                         gdk_window_get_position (priv->headers_window, &old_x, &old_y);
1004                         new_x = 0;
1005                         new_y = -vadj->value;
1006
1007                         headers_offset = GTK_WIDGET(priv->headers_box)->allocation.height;
1008
1009                         if (new_x != old_x || new_y != old_y) {
1010                                 gdk_window_move (priv->headers_window, new_x, new_y);
1011                                 gdk_window_process_updates (priv->headers_window, TRUE);
1012                         }
1013                 }
1014                 
1015                 if (priv->html_scroll && GTK_WIDGET_VISIBLE (priv->html_scroll)) {
1016                         gint old_x, old_y;
1017                         gint new_x, new_y;
1018                         gdk_window_get_position (priv->html_window, &old_x, &old_y);
1019                         new_x = -hadj->value;
1020                         new_y = headers_offset - vadj->value;
1021
1022                         if (new_x != old_x || new_y != old_y) {
1023                                 gdk_window_move (priv->html_window, new_x, new_y);
1024                                 gdk_window_process_updates (priv->html_window, TRUE);
1025                         }
1026                 }
1027                 
1028         }
1029 }
1030
1031 static gboolean
1032 resize_children_idle (GtkContainer *cont)
1033 {
1034         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (cont);
1035         if (GTK_WIDGET_DRAWABLE (cont)) {
1036                 gtk_container_resize_children (cont);
1037         }
1038         priv->idle_resize_children_id = 0;
1039
1040         return FALSE;
1041 }
1042
1043 static void
1044 html_adjustment_changed (GtkAdjustment *adj,
1045                          gpointer userdata)
1046 {
1047         ModestGtkhtmlMsgView *self = MODEST_GTKHTML_MSG_VIEW (userdata);
1048         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1049         GtkAdjustment *html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW(priv->html_scroll));
1050         gboolean vadj_changed;
1051         gint new_height;
1052
1053         g_signal_stop_emission_by_name (G_OBJECT (adj), "changed");
1054
1055         priv->html_scroll->requisition.height = html_vadj->upper;
1056         if (html_vadj->upper == priv->html_scroll->allocation.height)
1057                 return;
1058         priv->html_scroll->allocation.height = html_vadj->upper;
1059
1060         set_vadjustment_values (self, &vadj_changed);
1061
1062         new_height = MAX ((gint) html_vadj->upper, (gint) (priv->vadj->upper - priv->headers_box->allocation.height));
1063         
1064         gtk_adjustment_changed (priv->vadj);
1065         if (GTK_WIDGET_DRAWABLE (priv->html_scroll)) {
1066                 gdk_window_resize (priv->html_window, (gint) priv->hadj->upper, (gint) new_height);
1067                 gdk_window_process_updates (priv->view_window, TRUE);
1068                 if (priv->idle_resize_children_id == 0)
1069                         priv->idle_resize_children_id = gdk_threads_add_idle ((GSourceFunc) resize_children_idle, self);
1070         }
1071         
1072 }
1073
1074 gboolean
1075 idle_readjust_scroll (ModestGtkhtmlMsgView *self)
1076 {
1077         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1078
1079         /* We're out the main lock */
1080         gdk_threads_enter ();
1081
1082         if (GTK_WIDGET_DRAWABLE (self)) {
1083                 GtkAdjustment *html_vadj;
1084                 GtkAdjustment *html_hadj;
1085
1086                 html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
1087                 html_vadj->upper = 0;
1088                 html_vadj->page_size = 0;
1089                 g_signal_emit_by_name (G_OBJECT (html_vadj), "changed");
1090
1091                 html_hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
1092                 html_hadj->upper = 0;
1093                 html_hadj->page_size = 0;
1094                 g_signal_emit_by_name (G_OBJECT (html_hadj), "changed");
1095
1096                 gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), 1, 1);
1097                 gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), -1, -1);
1098
1099                 gtk_widget_queue_resize (GTK_WIDGET (priv->body_view));
1100                 gtk_widget_queue_draw (GTK_WIDGET (priv->body_view));
1101
1102                 /* Just another hack for making readjust really work. This forces an update
1103                  * of the scroll, and then, make the scroll really update properly the
1104                  * the size and not corrupt scrollable area */
1105                 gtk_adjustment_set_value (priv->vadj, 1.0);
1106                 gtk_adjustment_set_value (priv->vadj, 0.0);
1107
1108         }
1109         priv->idle_readjust_scroll_id = 0;
1110         g_object_unref (G_OBJECT (self));
1111
1112
1113         gdk_threads_leave ();
1114
1115         return FALSE;
1116 }
1117
1118 static void
1119 modest_gtkhtml_msg_view_init (ModestGtkhtmlMsgView *obj)
1120 {
1121         ModestGtkhtmlMsgViewPrivate *priv;
1122         GtkAdjustment *html_vadj;
1123 #ifndef MODEST_TOOLKIT_HILDON2
1124         GtkWidget *separator;
1125 #endif
1126
1127         GTK_WIDGET_UNSET_FLAGS (obj, GTK_NO_WINDOW);
1128         gtk_widget_set_redraw_on_allocate (GTK_WIDGET (obj), TRUE);
1129         gtk_container_set_reallocate_redraws (GTK_CONTAINER (obj), TRUE);
1130         gtk_container_set_resize_mode (GTK_CONTAINER (obj), GTK_RESIZE_QUEUE);
1131         
1132         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE(obj);
1133
1134         priv->idle_changes_count = 0;
1135         priv->idle_readjust_scroll_id = 0;
1136         priv->idle_resize_children_id = 0;
1137         priv->current_zoom = 1.0;
1138
1139         priv->hadj = NULL;
1140         priv->vadj = NULL;
1141         priv->shadow_type = GTK_SHADOW_IN;
1142         priv->view_window = NULL;
1143         priv->headers_window = NULL;
1144         priv->html_window = NULL;
1145
1146         priv->idle_motion_id = 0;
1147
1148         gtk_widget_push_composite_child ();
1149         priv->html_scroll = gtk_scrolled_window_new (NULL, NULL);
1150         gtk_widget_set_composite_name (priv->html_scroll, "contents");
1151         gtk_widget_pop_composite_child ();
1152         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->html_scroll), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
1153
1154         priv->msg                     = NULL;
1155
1156         priv->body_view                 = GTK_WIDGET (g_object_new (MODEST_TYPE_GTKHTML_MIME_PART_VIEW, NULL));
1157 #ifdef MODEST_TOOLKIT_HILDON2
1158         priv->mail_header_view        = GTK_WIDGET(modest_compact_mail_header_view_new ());
1159 #else
1160         priv->mail_header_view        = GTK_WIDGET(modest_expander_mail_header_view_new (TRUE));
1161 #endif
1162         gtk_widget_set_no_show_all (priv->mail_header_view, TRUE);
1163         priv->attachments_view        = GTK_WIDGET(modest_attachments_view_new (NULL));
1164 #ifdef MODEST_TOOLKIT_HILDON2
1165         modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1166                                            MODEST_ATTACHMENTS_VIEW_STYLE_LINKS);
1167 #else
1168         modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1169                                            MODEST_ATTACHMENTS_VIEW_STYLE_SELECTABLE);
1170 #endif
1171
1172         g_signal_connect (G_OBJECT(priv->body_view), "activate_link",
1173                                        G_CALLBACK(on_activate_link), obj);
1174         g_signal_connect (G_OBJECT(priv->body_view), "fetch_url",
1175                                        G_CALLBACK(on_fetch_url), obj);
1176         g_signal_connect (G_OBJECT(priv->body_view), "link_hover",
1177                                        G_CALLBACK(on_link_hover), obj);
1178         g_signal_connect (G_OBJECT(priv->body_view), "limit_error",
1179                           G_CALLBACK(on_limit_error), obj);
1180 #ifdef MAEMO_CHANGES
1181         g_signal_connect (G_OBJECT(priv->body_view), "motion-notify-event",
1182                           G_CALLBACK (motion_notify_event), obj);
1183 #endif
1184         g_signal_connect (G_OBJECT (priv->body_view), "button-press-event",
1185                           G_CALLBACK (button_press_event), obj);
1186         g_signal_connect (G_OBJECT (priv->body_view), "button-release-event",
1187                           G_CALLBACK (button_release_event), obj);
1188
1189         g_signal_connect (G_OBJECT (priv->mail_header_view), "recpt-activated", 
1190                           G_CALLBACK (on_recpt_activated), obj);
1191         g_signal_connect (G_OBJECT (priv->mail_header_view), "show-details", 
1192                           G_CALLBACK (on_show_details), obj);
1193
1194         g_signal_connect (G_OBJECT (priv->attachments_view), "activate",
1195                           G_CALLBACK (on_attachment_activated), obj);
1196
1197         html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW(priv->html_scroll));
1198
1199         g_signal_connect (G_OBJECT (html_vadj), "changed",
1200                           G_CALLBACK (html_adjustment_changed), obj);
1201
1202         gtk_widget_push_composite_child ();
1203         priv->headers_box = gtk_vbox_new (FALSE, MODEST_MARGIN_DEFAULT);
1204         gtk_widget_set_composite_name (priv->headers_box, "headers");
1205         gtk_widget_pop_composite_child ();
1206
1207         if (priv->mail_header_view)
1208                 gtk_box_pack_start (GTK_BOX(priv->headers_box), priv->mail_header_view, FALSE, FALSE, 0);
1209
1210 #ifdef MODEST_TOOLKIT_HILDON2
1211         priv->priority_icon = gtk_image_new ();
1212         gtk_misc_set_alignment (GTK_MISC (priv->priority_icon), 0.0, 0.5);
1213         if (priv->priority_icon) {
1214                 priv->priority_box = (GtkWidget *)
1215                         modest_mail_header_view_add_custom_header (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view),
1216                                                                    _("mcen_me_editor_message_priority"),
1217                                                                    priv->priority_icon,
1218                                                                    FALSE, FALSE);
1219                                                                    
1220                 gtk_widget_hide_all (priv->priority_box);
1221         }
1222 #endif
1223         if (priv->attachments_view) {
1224 #ifndef MODEST_TOOLKIT_HILDON2
1225                 gchar *att_label = g_strconcat (_("mcen_me_viewer_attachments"), ":", NULL);
1226 #else
1227                 gchar *att_label = g_strconcat (_("mail_va_attachment"), ":", NULL);
1228 #endif
1229
1230                 priv->attachments_box = (GtkWidget *)
1231                         modest_mail_header_view_add_custom_header (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view),
1232                                                                    att_label,
1233                                                                    priv->attachments_view,
1234                                                                    FALSE, FALSE);
1235                 gtk_widget_hide_all (priv->attachments_box);
1236                 g_free (att_label);
1237         }
1238
1239 #ifndef MODEST_TOOLKIT_HILDON2
1240         separator = gtk_hseparator_new ();
1241         gtk_box_pack_start (GTK_BOX(priv->headers_box), separator, FALSE, FALSE, 0);
1242 #endif
1243
1244         gtk_widget_set_parent (priv->headers_box, GTK_WIDGET (obj));
1245
1246         if (priv->body_view) {
1247                 gtk_container_add (GTK_CONTAINER (priv->html_scroll), priv->body_view);
1248                 gtk_widget_set_parent (priv->html_scroll, GTK_WIDGET(obj));
1249 #ifdef MAEMO_CHANGES
1250                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->body_view), NULL, NULL, 0);
1251                 g_signal_connect (G_OBJECT (priv->body_view), "tap-and-hold", G_CALLBACK (on_tap_and_hold), obj);
1252                 g_signal_connect (G_OBJECT (priv->body_view), "tap-and-hold-query", G_CALLBACK (on_tap_and_hold_query), obj);
1253 #endif
1254         }
1255         
1256 }
1257         
1258
1259 static void
1260 modest_gtkhtml_msg_view_finalize (GObject *obj)
1261 {       
1262         ModestGtkhtmlMsgViewPrivate *priv;
1263         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (obj);
1264
1265         if (priv->msg) {
1266                 g_object_unref (G_OBJECT(priv->msg));
1267                 priv->msg = NULL;
1268         }
1269
1270         if (priv->idle_resize_children_id > 0) {
1271                 g_source_remove (priv->idle_resize_children_id);
1272                 priv->idle_resize_children_id = 0;
1273         }
1274
1275         if (priv->idle_readjust_scroll_id > 0) {
1276                 g_source_remove (priv->idle_readjust_scroll_id);
1277                 priv->idle_readjust_scroll_id = 0;
1278         }
1279
1280         if (priv->idle_motion_id > 0) {
1281                 g_source_remove (priv->idle_motion_id);
1282                 priv->idle_motion_id = 0;
1283         }
1284         
1285         /* we cannot disconnect sigs, because priv->body_view is
1286          * already dead */
1287         
1288         disconnect_vadjustment (MODEST_GTKHTML_MSG_VIEW(obj));
1289         disconnect_hadjustment (MODEST_GTKHTML_MSG_VIEW(obj));
1290
1291         priv->body_view = NULL;
1292         priv->attachments_view = NULL;
1293
1294         G_OBJECT_CLASS(parent_class)->finalize (obj);           
1295 }
1296
1297 static void
1298 modest_gtkhtml_msg_view_destroy (GtkObject *obj)
1299 {       
1300         disconnect_vadjustment (MODEST_GTKHTML_MSG_VIEW(obj));
1301         disconnect_hadjustment (MODEST_GTKHTML_MSG_VIEW(obj));
1302
1303         GTK_OBJECT_CLASS(parent_class)->destroy (obj);          
1304 }
1305
1306 /* INTERNAL METHODS */
1307
1308 #ifdef MAEMO_CHANGES
1309 static gboolean 
1310 motion_notify_event (GtkWidget *widget,
1311                      GdkEventMotion *event,
1312                      gpointer userdata)
1313 {
1314         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (userdata);
1315
1316         /* Use panning information in gtkhtml widget to support also vertical panning */
1317
1318         if (GTK_HTML (widget)->panning) {
1319                 gint y, dy;
1320                 gdouble value;
1321
1322                 gdk_window_get_pointer (GTK_LAYOUT (widget)->bin_window, NULL, &y, NULL);
1323                 dy = y - GTK_HTML (widget)->lasty;
1324                 value = priv->vadj->value - (gdouble) dy;
1325
1326                 if (value < priv->vadj->lower)
1327                         value = priv->vadj->lower;
1328                 else if (value > priv->vadj->upper - priv->vadj->page_size)
1329                         value = priv->vadj->upper - priv->vadj->page_size;
1330                 gtk_adjustment_set_value (priv->vadj, value);
1331                 
1332         } 
1333         return FALSE;
1334 }
1335 #endif
1336
1337 static gboolean
1338 idle_motion (gpointer userdata)
1339 {
1340         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (userdata);
1341         if (GTK_HTML (priv->body_view)->in_selection_drag) {
1342                 gdouble offset;
1343                 GtkAdjustment *adj;
1344                 gint gdk_y;
1345                 gdk_window_get_pointer (gtk_widget_get_parent_window (priv->body_view), NULL, &gdk_y, NULL);
1346                 offset= (gdouble) (priv->headers_box->requisition.height + gdk_y);
1347                 adj = GTK_ADJUSTMENT (priv->vadj);
1348                 if (offset < adj->value + adj->step_increment) {
1349                         gtk_adjustment_set_value (adj, MAX (offset + adj->page_increment - adj->page_size, 0.0));
1350                 } else if (offset > adj->value + adj->page_increment) {
1351                         gtk_adjustment_set_value (adj, MIN (offset - adj->page_increment, adj->upper - adj->page_size));
1352                 }
1353                 gtk_widget_queue_resize (userdata);
1354         }
1355         return TRUE;
1356 }
1357
1358 static gboolean 
1359 button_press_event (GtkWidget *widget,
1360                     GdkEventButton *event,
1361                     gpointer userdata)
1362 {
1363         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (userdata);
1364
1365         if (priv->idle_motion_id == 0) {
1366                 priv->idle_motion_id = g_timeout_add (200, idle_motion, userdata);
1367         }
1368         return FALSE;
1369 }
1370
1371 static gboolean 
1372 button_release_event (GtkWidget *widget,
1373                       GdkEventButton *event,
1374                       gpointer userdata)
1375 {
1376         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (userdata);
1377
1378         if (priv->idle_motion_id > 0) {
1379                 gint gdk_y;
1380                 g_source_remove (priv->idle_motion_id);
1381                 
1382                 priv->idle_motion_id = 0;;
1383                 gdk_window_get_pointer (gtk_widget_get_parent_window (priv->body_view), NULL, &gdk_y, NULL);
1384                 event->y = (gdouble) gdk_y;
1385         }
1386         return FALSE;
1387 }
1388
1389 static GtkAdjustment *
1390 get_vadjustment (ModestGtkhtmlMsgView *self)
1391 {
1392         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1393
1394         if (!priv->vadj)
1395                 set_vadjustment (self, NULL);
1396
1397         return priv->vadj;
1398         
1399 }
1400
1401 static GtkAdjustment *
1402 get_hadjustment (ModestGtkhtmlMsgView *self)
1403 {
1404         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1405
1406         if (!priv->hadj)
1407                 set_hadjustment (self, NULL);
1408
1409         return priv->hadj;
1410         
1411 }
1412
1413 static void
1414 set_hadjustment (ModestGtkhtmlMsgView *self, GtkAdjustment *hadj)
1415 {
1416         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1417         gboolean value_changed;
1418         
1419         if (hadj && hadj == priv->hadj)
1420                 return;
1421
1422         if (!hadj)
1423                 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,0.0,0.0,0.0,0.0,0.0));
1424         disconnect_hadjustment (self);
1425         g_object_ref (G_OBJECT (hadj));
1426         gtk_object_sink (GTK_OBJECT (hadj));
1427         priv->hadj = hadj;
1428         set_hadjustment_values (self, &value_changed);
1429
1430         g_signal_connect (hadj, "value_changed", G_CALLBACK (adjustment_value_changed),
1431                           self);
1432
1433         gtk_adjustment_changed (hadj);
1434         if (value_changed)
1435                 gtk_adjustment_value_changed (hadj);
1436         else
1437                 adjustment_value_changed (hadj, self);
1438
1439         g_object_notify (G_OBJECT (self), "hadjustment");
1440 }
1441
1442 static void
1443 set_vadjustment (ModestGtkhtmlMsgView *self, GtkAdjustment *vadj)
1444 {
1445         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1446         gboolean value_changed;
1447
1448         if (vadj && vadj == priv->vadj)
1449                 return;
1450
1451         if (!vadj)
1452                 vadj = (GtkAdjustment *) gtk_adjustment_new (0.0,0.0,0.0,0.0,0.0,0.0);
1453         disconnect_vadjustment (self);
1454         g_object_ref (G_OBJECT (vadj));
1455         gtk_object_sink (GTK_OBJECT (vadj));
1456         priv->vadj = vadj;
1457         set_vadjustment_values (self, &value_changed);
1458
1459         g_signal_connect (vadj, "value_changed", G_CALLBACK (adjustment_value_changed),
1460                           self);
1461
1462         gtk_adjustment_changed (vadj);
1463         if (value_changed)
1464                 gtk_adjustment_value_changed (vadj);
1465         else
1466                 adjustment_value_changed (vadj, self);
1467
1468         g_object_notify (G_OBJECT (self), "vadjustment");
1469 }
1470
1471 static void
1472 set_shadow_type (ModestGtkhtmlMsgView *self,
1473                  GtkShadowType shadow_type)
1474 {
1475         ModestGtkhtmlMsgViewPrivate *priv;
1476         g_return_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (self));
1477
1478         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1479         
1480         if (priv->shadow_type != shadow_type) {
1481                 priv->shadow_type = shadow_type;
1482                 
1483                 if (GTK_WIDGET_VISIBLE (self)) {
1484                         gtk_widget_size_allocate (GTK_WIDGET (self), &(GTK_WIDGET (self)->allocation));
1485                         gtk_widget_queue_draw (GTK_WIDGET (self));
1486                 }
1487                 g_object_notify (G_OBJECT (self), "shadow-type");
1488         }
1489 }
1490
1491 static GtkShadowType
1492 get_shadow_type (ModestGtkhtmlMsgView *self)
1493 {
1494         ModestGtkhtmlMsgViewPrivate *priv;
1495         g_return_val_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (self), GTK_SHADOW_NONE);
1496         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1497         
1498         return priv->shadow_type;
1499 }
1500
1501 GtkWidget*
1502 modest_msg_view_new (TnyMsg *msg)
1503 {
1504         GObject *obj;
1505         ModestGtkhtmlMsgView* self;
1506         
1507         obj  = G_OBJECT(g_object_new(MODEST_TYPE_GTKHTML_MSG_VIEW, NULL));
1508         self = MODEST_GTKHTML_MSG_VIEW(obj);
1509         tny_msg_view_set_msg (TNY_MSG_VIEW (self), msg);
1510
1511         return GTK_WIDGET(self);
1512 }
1513
1514 #ifdef MAEMO_CHANGES
1515 static void
1516 on_tap_and_hold (GtkWidget *widget,
1517                  gpointer data)
1518 {
1519         ModestGtkhtmlMsgView *self = (ModestGtkhtmlMsgView *) data;
1520         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1521
1522         g_signal_emit_by_name (G_OBJECT (self), "link-contextual", priv->last_url);
1523 }
1524
1525 static gboolean
1526 on_tap_and_hold_query (GtkWidget *widget,
1527                        GdkEvent *event,
1528                        gpointer data)
1529 {
1530         ModestGtkhtmlMsgView *self = (ModestGtkhtmlMsgView *) data;
1531         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1532
1533         /* Don't show the tap and hold animation if no url below */
1534         return (priv->last_url == NULL);
1535 }
1536 #endif
1537
1538 static void
1539 on_recpt_activated (ModestMailHeaderView *header_view, 
1540                     const gchar *address,
1541                     ModestGtkhtmlMsgView *self)
1542 {
1543         g_signal_emit_by_name (G_OBJECT (self), "recpt-activated", address);
1544 }
1545
1546 static void
1547 on_show_details (ModestMailHeaderView *header_view, 
1548                  ModestGtkhtmlMsgView *self)
1549 {
1550         g_signal_emit_by_name (G_OBJECT (self), "show-details");
1551 }
1552
1553 static void
1554 on_attachment_activated (ModestAttachmentsView * att_view, TnyMimePart *mime_part, gpointer self)
1555 {
1556
1557         g_signal_emit_by_name (G_OBJECT(self), "attachment_clicked", mime_part);
1558 }
1559
1560 static void
1561 request_fetch_images (ModestGtkhtmlMsgView *self)
1562 {
1563         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1564         TnyMimePart *part;
1565
1566         /* The message could have not been downloaded yet */
1567         if (priv->msg) {
1568                 modest_mime_part_view_set_view_images (MODEST_MIME_PART_VIEW (priv->body_view), TRUE);
1569                 part = tny_mime_part_view_get_part (TNY_MIME_PART_VIEW (priv->body_view));
1570                 if (part) {
1571                         tny_mime_part_view_set_part (TNY_MIME_PART_VIEW (priv->body_view), part);
1572                         g_object_unref (part);
1573                 }
1574                 tny_msg_set_allow_external_images (TNY_MSG (priv->msg), TRUE);
1575         }
1576 }
1577
1578 static void
1579 set_branding (ModestGtkhtmlMsgView *self, const gchar *brand_name, const GdkPixbuf *brand_icon)
1580 {
1581         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1582
1583         modest_mail_header_view_set_branding (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view), brand_name, brand_icon);
1584 }
1585
1586 static gboolean
1587 has_blocked_external_images (ModestGtkhtmlMsgView *self)
1588 {
1589         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1590
1591         return (modest_mime_part_view_has_external_images (MODEST_MIME_PART_VIEW (priv->body_view)) &&
1592                 !modest_mime_part_view_get_view_images (MODEST_MIME_PART_VIEW (priv->body_view)));
1593 }
1594
1595 static gboolean
1596 on_activate_link (GtkWidget *widget, const gchar *uri, ModestGtkhtmlMsgView *self)
1597 {
1598         gboolean result;
1599         g_return_val_if_fail (self, FALSE);
1600
1601         g_signal_emit_by_name (G_OBJECT(self), "activate-link", uri, &result);
1602
1603         return result;
1604 }
1605
1606
1607 static gboolean
1608 on_link_hover (GtkWidget *widget, const gchar *uri, ModestGtkhtmlMsgView *self)
1609 {
1610         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1611         gboolean result;
1612
1613         g_free (priv->last_url);
1614         priv->last_url = g_strdup (uri);
1615
1616         g_signal_emit_by_name (G_OBJECT(self), "link-hover", uri, &result);
1617
1618         return result;
1619 }
1620
1621 static void 
1622 on_limit_error (GtkWidget *widget, ModestGtkhtmlMsgView *msg_view)
1623 {
1624         g_signal_emit_by_name (G_OBJECT (msg_view), "limit-error");
1625 }
1626
1627
1628 static TnyMimePart *
1629 find_cid_image (TnyMsg *msg, const gchar *cid)
1630 {
1631         TnyMimePart *part = NULL;
1632         TnyList *parts;
1633         TnyIterator *iter;
1634         
1635         g_return_val_if_fail (msg, NULL);
1636         g_return_val_if_fail (cid, NULL);
1637         
1638         parts  = TNY_LIST (tny_simple_list_new());
1639
1640         tny_mime_part_get_parts (TNY_MIME_PART (msg), parts); 
1641         iter   = tny_list_create_iterator (parts);
1642         
1643         while (!tny_iterator_is_done(iter)) {
1644                 const gchar *part_cid;
1645
1646                 part = TNY_MIME_PART(tny_iterator_get_current(iter));
1647                 part_cid = tny_mime_part_get_content_id (part);
1648
1649                 /* if there is no content id, try the content location;
1650                  * this is what Outlook seems to use when it converts
1651                  * it's internal richtext to html
1652                  */
1653                 if (!part_cid)
1654                         part_cid = tny_mime_part_get_content_location (part);
1655                 
1656                 if (part_cid && strcmp (cid, part_cid) == 0)
1657                         break;
1658
1659                 if (tny_mime_part_content_type_is (part, "multipart/related")) {
1660                         TnyList *related_parts = TNY_LIST (tny_simple_list_new ());
1661                         TnyIterator *related_iter = NULL;
1662                         TnyMimePart *related_part = NULL;
1663
1664                         tny_mime_part_get_parts (part, related_parts);
1665                         related_iter = tny_list_create_iterator (related_parts);
1666
1667                         while (!tny_iterator_is_done (related_iter)) {
1668                                 related_part = TNY_MIME_PART (tny_iterator_get_current (related_iter));
1669                                 part_cid = tny_mime_part_get_content_id (related_part);
1670                                 if (part_cid && strcmp (cid, part_cid) == 0) {
1671                                         break;
1672                                 }
1673                                 g_object_unref (related_part);
1674                                 related_part = NULL;
1675                                 tny_iterator_next (related_iter);
1676                         }
1677
1678                         g_object_unref (related_iter);
1679                         g_object_unref (related_parts);
1680                         if (related_part != NULL) {
1681                                 g_object_unref (part);
1682                                 part = related_part;
1683                                 break;
1684                         }
1685                 }
1686
1687                 g_object_unref (G_OBJECT(part));
1688         
1689                 part = NULL;
1690                 tny_iterator_next (iter);
1691         }
1692         
1693         g_object_unref (G_OBJECT(iter));        
1694         g_object_unref (G_OBJECT(parts));
1695         
1696         return part;
1697 }
1698
1699
1700 static gboolean
1701 on_fetch_url (GtkWidget *widget, const gchar *uri,
1702               TnyStream *stream, ModestGtkhtmlMsgView *self)
1703 {
1704         ModestGtkhtmlMsgViewPrivate *priv;
1705         const gchar* my_uri;
1706         TnyMimePart *part = NULL;
1707         
1708
1709
1710         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1711
1712         /*
1713          * we search for either something starting with cid:, or something
1714          * with no prefix at all; this latter case occurs when sending mails
1715          * with MS Outlook in rich-text mode, and 'attach-as-object
1716          */
1717         if (g_str_has_prefix (uri, "cid:"))  
1718                 my_uri = uri + 4;  /* +4 ==> skip "cid:" */
1719         else
1720                 my_uri = uri;
1721         
1722         /* now try to find the embedded image */
1723         part = find_cid_image (priv->msg, my_uri);
1724
1725         if (!part) {
1726                 if (g_str_has_prefix (uri, "http:")) {
1727                         if (modest_mime_part_view_get_view_images (MODEST_MIME_PART_VIEW (priv->body_view))) {
1728                                 gboolean result = FALSE;
1729                                 g_signal_emit_by_name (self, "fetch-image", uri, stream, &result);
1730                                 return result;
1731                         } else {
1732                                 /* we return immediately to get a "image not found" icon */
1733                                 tny_stream_close (stream);
1734                                 return TRUE;
1735                         }
1736                 } else {
1737                         return FALSE;
1738                 }
1739         }
1740
1741         tny_mime_part_decode_to_stream ((TnyMimePart*)part, stream, NULL);
1742         tny_stream_close (stream);
1743         g_object_unref (G_OBJECT(part));
1744         return TRUE;
1745 }
1746
1747 static void
1748 set_message (ModestGtkhtmlMsgView *self, TnyMsg *msg, TnyMimePart *other_body)
1749 {
1750         TnyMimePart *body;
1751         ModestGtkhtmlMsgViewPrivate *priv;
1752         TnyHeader *header;
1753         GtkAdjustment *html_vadj, *html_hadj;
1754
1755         g_return_if_fail (self);
1756
1757         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE(self);
1758         modest_mail_header_view_set_loading (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view), FALSE);
1759         gtk_widget_set_no_show_all (priv->mail_header_view, FALSE);
1760         modest_mime_part_view_set_view_images (MODEST_MIME_PART_VIEW (priv->body_view), FALSE);
1761
1762         if (msg != priv->msg) {
1763                 if (priv->msg)
1764                         g_object_unref (G_OBJECT(priv->msg));
1765                 if (msg)
1766                         g_object_ref   (G_OBJECT(msg));
1767                 priv->msg = msg;
1768         }
1769
1770         if (!msg) {
1771                 tny_header_view_clear (TNY_HEADER_VIEW (priv->mail_header_view));
1772                 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), NULL);
1773                 gtk_widget_hide_all (priv->mail_header_view);
1774                 gtk_widget_hide_all (priv->attachments_box);
1775 #ifdef MODEST_TOOKIT_HILDON2
1776                 gtk_widget_hide_all (priv->priority_box);
1777 #endif
1778                 gtk_widget_set_no_show_all (priv->mail_header_view, TRUE);
1779                 tny_mime_part_view_clear (TNY_MIME_PART_VIEW (priv->body_view));
1780
1781                 html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
1782                 html_vadj->upper = 0;
1783                 html_vadj->page_size = 0;
1784                 g_signal_emit_by_name (G_OBJECT (html_vadj), "changed");
1785
1786                 html_hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
1787                 html_hadj->upper = 0;
1788                 html_hadj->page_size = 0;
1789                 g_signal_emit_by_name (G_OBJECT (html_hadj), "changed");
1790
1791                 gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), 1, 1);
1792                 gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), -1, -1);
1793
1794                 priv->idle_changes_count = 0;
1795                 gtk_widget_queue_resize (GTK_WIDGET (priv->body_view));
1796
1797                 gtk_widget_queue_resize (GTK_WIDGET(self));
1798                 gtk_widget_queue_draw (GTK_WIDGET(self));
1799                 return;
1800         }
1801
1802         header = tny_msg_get_header (msg);
1803         tny_header_view_set_header (TNY_HEADER_VIEW (priv->mail_header_view), header);
1804         g_object_unref (header);
1805
1806         modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1807                                              other_body?NULL:msg);
1808
1809         modest_mime_part_view_set_view_images (MODEST_MIME_PART_VIEW (priv->body_view), tny_msg_get_allow_external_images (msg));
1810
1811         if (other_body) {
1812                 body = other_body;
1813                 g_object_ref (body);
1814         } else {
1815                 body = modest_tny_msg_find_body_part (msg, TRUE);
1816         }
1817         if (body) {
1818                 ModestAttachmentsView *widget;
1819
1820                 tny_mime_part_view_set_part (TNY_MIME_PART_VIEW (priv->body_view), body);
1821                 g_object_unref (body);
1822                 widget = MODEST_ATTACHMENTS_VIEW (priv->attachments_view);
1823
1824                 if (modest_attachments_view_has_attachments (widget)) {
1825                         GtkLabel *label;
1826                         GList *children = NULL;
1827                         gchar *text = NULL;
1828                         /* Ugly but... */
1829                         children = gtk_container_get_children (GTK_CONTAINER (priv->attachments_box));
1830                         label = GTK_LABEL (children->data);
1831                         gtk_widget_show_all (priv->attachments_box);
1832 #ifdef MODEST_TOOLKIT_HILDON2
1833                         if (modest_attachments_view_get_num_attachments (widget) > 1) {
1834                                 text = _("mail_va_attachments");
1835                         } else {
1836                                 text = _("mail_va_attachment");
1837                         }
1838 #else
1839                                 text = _("mail_va_attachment");
1840 #endif
1841                         gtk_label_set_text (label, text);
1842                 } else {
1843                         gtk_widget_hide_all (priv->attachments_box);
1844                 }
1845
1846         } else {
1847                 tny_mime_part_view_clear (TNY_MIME_PART_VIEW (priv->body_view));
1848         }
1849
1850         /* Refresh priority */
1851         set_priority (self, tny_header_get_flags (header));
1852
1853         gtk_widget_show (priv->body_view);
1854 #ifdef MODEST_TOOLKIT_HILDON2
1855         gtk_widget_set_no_show_all (priv->priority_box, TRUE);
1856 #endif
1857         gtk_widget_set_no_show_all (priv->attachments_box, TRUE);
1858         gtk_widget_show_all (priv->mail_header_view);
1859         gtk_widget_set_no_show_all (priv->attachments_box, FALSE);
1860 #ifdef MODEST_TOOLKIT_HILDON2
1861         gtk_widget_set_no_show_all (priv->priority_box, FALSE);
1862 #endif
1863         gtk_widget_set_no_show_all (priv->mail_header_view, TRUE);
1864
1865         html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
1866         html_vadj->upper = 0;
1867         html_vadj->page_size = 0;
1868         g_signal_emit_by_name (G_OBJECT (html_vadj), "changed");
1869
1870         html_hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
1871         html_hadj->upper = 0;
1872         html_hadj->page_size = 0;
1873         g_signal_emit_by_name (G_OBJECT (html_hadj), "changed");
1874
1875         gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), 1, 1);
1876         gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), -1, -1);
1877
1878         priv->idle_changes_count = 0;
1879         gtk_widget_queue_resize (GTK_WIDGET (priv->body_view));
1880
1881         gtk_widget_queue_resize (GTK_WIDGET(self));
1882         gtk_widget_queue_draw (GTK_WIDGET(self));
1883
1884         if (priv->hadj != NULL)
1885                 priv->hadj->value = 0.0;
1886         if (priv->vadj != NULL)
1887                 priv->vadj->value = 0.0;
1888
1889         g_signal_emit_by_name (G_OBJECT (html_vadj), "changed");
1890
1891         /* This is a hack to force reallocation of scroll after drawing all the stuff. This
1892          * makes the html view get the proper and expected size and prevent being able to scroll
1893          * the buffer when it shouldn't be scrollable */
1894         if (priv->idle_readjust_scroll_id == 0) {
1895                 g_object_ref (self);
1896                 priv->idle_readjust_scroll_id = g_idle_add ((GSourceFunc) idle_readjust_scroll, self);
1897         }
1898 }
1899
1900 static void
1901 set_header (ModestGtkhtmlMsgView *self, TnyHeader *header)
1902 {
1903         ModestGtkhtmlMsgViewPrivate *priv;
1904         GtkAdjustment *html_vadj, *html_hadj;
1905         
1906         g_return_if_fail (self);
1907
1908         if (header == NULL) {
1909                 set_message (self, NULL, NULL);
1910                 return;
1911         }
1912         
1913         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE(self);
1914         modest_mail_header_view_set_loading (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view), TRUE);
1915         gtk_widget_set_no_show_all (priv->mail_header_view, FALSE);
1916         modest_mime_part_view_set_view_images (MODEST_MIME_PART_VIEW (priv->body_view), FALSE);
1917
1918         html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
1919         html_vadj->upper = 0;
1920         html_vadj->page_size = 0;
1921         g_signal_emit_by_name (G_OBJECT (html_vadj), "changed");
1922
1923         html_hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
1924         html_hadj->upper = 0;
1925         html_hadj->page_size = 0;
1926         g_signal_emit_by_name (G_OBJECT (html_hadj), "changed");
1927
1928         priv->idle_changes_count = 0;
1929         gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), 1, 1);
1930         gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), -1, -1);
1931         gtk_widget_queue_resize (GTK_WIDGET (priv->body_view));
1932
1933         if (priv->msg) {
1934                 g_object_unref (G_OBJECT(priv->msg));
1935         }
1936         priv->msg = NULL;
1937         
1938         tny_header_view_set_header (TNY_HEADER_VIEW (priv->mail_header_view), header);
1939         modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), NULL);
1940         gtk_widget_show_all (priv->mail_header_view);
1941         gtk_widget_hide_all (priv->attachments_box);
1942 #ifdef MODEST_TOOLKIT_HILDON2
1943         gtk_widget_hide_all (priv->priority_box);
1944 #endif
1945         gtk_widget_set_no_show_all (priv->mail_header_view, TRUE);
1946         tny_mime_part_view_clear (TNY_MIME_PART_VIEW (priv->body_view));
1947         priv->idle_changes_count = 0;
1948         gtk_widget_queue_resize (GTK_WIDGET(self));
1949         gtk_widget_queue_draw (GTK_WIDGET(self));
1950 }
1951
1952
1953 static TnyMsg*
1954 get_message (ModestGtkhtmlMsgView *self)
1955 {
1956         TnyMsg *msg;
1957
1958         g_return_val_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (self), NULL);
1959
1960         msg = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE(self)->msg;
1961
1962         if (msg)
1963                 g_object_ref (msg);
1964         
1965         return msg;
1966 }
1967
1968 static gboolean 
1969 is_empty (ModestGtkhtmlMsgView *self)
1970 {
1971         ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1972
1973         return modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->body_view));
1974 }
1975
1976 static void
1977 set_zoom (ModestGtkhtmlMsgView *self, gdouble zoom)
1978 {
1979         ModestGtkhtmlMsgViewPrivate *priv;
1980         GtkAdjustment *html_vadj, *html_hadj;
1981
1982         g_return_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (self));
1983         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
1984
1985         modest_zoomable_set_zoom (MODEST_ZOOMABLE(priv->body_view), zoom);
1986
1987         html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
1988         html_vadj->upper = 0;
1989         html_vadj->page_size = 0;
1990         g_signal_emit_by_name (G_OBJECT (html_vadj), "changed");
1991
1992         html_hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
1993         html_hadj->upper = 0;
1994         html_hadj->page_size = 0;
1995         g_signal_emit_by_name (G_OBJECT (html_hadj), "changed");
1996
1997         gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), 1, 1);
1998         gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), -1, -1);
1999
2000         priv->idle_changes_count = 0;
2001         gtk_widget_queue_resize (priv->body_view);
2002 }
2003
2004 static gdouble
2005 get_zoom (ModestGtkhtmlMsgView *self)
2006 {
2007         ModestGtkhtmlMsgViewPrivate *priv;
2008
2009         g_return_val_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (self), 1.0);
2010         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
2011
2012         return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->body_view));
2013 }
2014
2015 static TnyHeaderFlags
2016 get_priority (ModestGtkhtmlMsgView *self)
2017 {
2018         ModestGtkhtmlMsgViewPrivate *priv;
2019
2020         g_return_val_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (self), 0);
2021
2022         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
2023
2024         return modest_mail_header_view_get_priority (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view));
2025 }
2026
2027 static void
2028 set_priority (ModestGtkhtmlMsgView *self, TnyHeaderFlags flags)
2029 {
2030         ModestGtkhtmlMsgViewPrivate *priv;
2031
2032         g_return_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (self));
2033         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
2034
2035         modest_mail_header_view_set_priority (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view), flags);
2036
2037 #ifdef MODEST_TOOLKIT_HILDON2
2038         gboolean show_priority = FALSE;
2039         TnyHeaderFlags priority_flags;
2040
2041         priority_flags = flags & TNY_HEADER_FLAG_PRIORITY_MASK;
2042         if (priority_flags == TNY_HEADER_FLAG_HIGH_PRIORITY) {
2043                 show_priority = TRUE;
2044                 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), MODEST_HEADER_ICON_HIGH, GTK_ICON_SIZE_MENU);
2045         } else if (priority_flags == TNY_HEADER_FLAG_LOW_PRIORITY) {
2046                 show_priority = TRUE;
2047                 gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), MODEST_HEADER_ICON_LOW, GTK_ICON_SIZE_MENU);
2048         }
2049
2050         if (show_priority && MODEST_IS_COMPACT_MAIL_HEADER_VIEW (priv->mail_header_view)) {
2051                 gtk_widget_show_all  (priv->priority_box);
2052         } else {
2053                 gtk_widget_hide_all (priv->priority_box);
2054         }
2055 #endif
2056
2057 }
2058
2059 /* INCREMENTAL SEARCH IMPLEMENTATION */
2060
2061 static gboolean 
2062 search (ModestGtkhtmlMsgView *self, const gchar *search)
2063 {
2064         ModestGtkhtmlMsgViewPrivate *priv;
2065         gboolean result;
2066         GtkAdjustment *vadj, *tmp_vadj;
2067         gdouble y_offset;
2068
2069         g_return_val_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (self), FALSE);
2070
2071         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
2072         vadj = gtk_layout_get_vadjustment (GTK_LAYOUT (priv->body_view));
2073         g_object_ref (vadj);
2074         tmp_vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, vadj->lower, vadj->upper, vadj->step_increment, 32.0, 32.0));
2075         gtk_layout_set_vadjustment (GTK_LAYOUT (priv->body_view), tmp_vadj);
2076         result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->body_view),
2077                                              search);
2078
2079         if (result) {
2080                 gint x, y, w, h;
2081                 gdouble offset_top, offset_bottom;
2082                 GtkAdjustment *adj;
2083                 if (modest_isearch_view_get_selection_area (MODEST_ISEARCH_VIEW (priv->body_view), &x, &y, &w, &h)) {
2084                         offset_top = (gdouble) (priv->headers_box->requisition.height + y);
2085                         offset_bottom = (gdouble) (priv->headers_box->requisition.height + y + h);
2086                         adj = GTK_ADJUSTMENT (priv->vadj);
2087                         if (offset_top < adj->value)
2088                                 gtk_adjustment_set_value (adj, offset_top + adj->page_increment - adj->page_size);
2089                         else if (offset_bottom > adj->value + adj->page_increment)
2090                                 gtk_adjustment_set_value (adj, offset_bottom - adj->page_increment);
2091                 }
2092         }
2093
2094         y_offset = tmp_vadj->value;
2095         gtk_layout_set_vadjustment (GTK_LAYOUT (priv->body_view), vadj);
2096         g_object_unref (vadj);
2097
2098         return result;
2099 }
2100
2101 static gboolean
2102 search_next (ModestGtkhtmlMsgView *self)
2103 {
2104         ModestGtkhtmlMsgViewPrivate *priv;
2105         gboolean result;
2106
2107         g_return_val_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (self), FALSE);
2108
2109         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
2110         result = modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->body_view));
2111
2112         if (result) {
2113                 gint x, y, w, h;
2114                 gdouble offset_top, offset_bottom;
2115                 GtkAdjustment *adj;
2116
2117                 if (modest_isearch_view_get_selection_area (MODEST_ISEARCH_VIEW (priv->body_view), &x, &y, &w, &h)) {
2118                         offset_top = (gdouble) (priv->headers_box->requisition.height + y);
2119                         offset_bottom = (gdouble) (priv->headers_box->requisition.height + y + h);
2120                         adj = GTK_ADJUSTMENT (priv->vadj);
2121                         if (offset_top < adj->value)
2122                                 gtk_adjustment_set_value (adj, offset_top + adj->page_increment - adj->page_size);
2123                         else if (offset_bottom > adj->value + adj->page_increment)
2124                                 gtk_adjustment_set_value (adj, offset_bottom - adj->page_increment);
2125                 }
2126         }
2127         return result;
2128 }
2129
2130 static TnyList *
2131 get_selected_attachments (ModestGtkhtmlMsgView *self)
2132 {
2133         ModestGtkhtmlMsgViewPrivate *priv;
2134
2135         g_return_val_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (self), NULL);
2136         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
2137
2138         return modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2139         
2140 }
2141
2142 static TnyList *
2143 get_attachments (ModestGtkhtmlMsgView *self)
2144 {
2145         ModestGtkhtmlMsgViewPrivate *priv;
2146
2147         g_return_val_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (self), NULL);
2148         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
2149
2150         return modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2151         
2152 }
2153
2154 static void
2155 grab_focus (ModestGtkhtmlMsgView *self)
2156 {
2157         ModestGtkhtmlMsgViewPrivate *priv = NULL;
2158
2159         g_return_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (self));
2160         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
2161
2162         gtk_widget_grab_focus (priv->body_view);
2163 }
2164
2165 static void
2166 remove_attachment (ModestGtkhtmlMsgView *self, TnyMimePart *attachment)
2167 {
2168         ModestGtkhtmlMsgViewPrivate *priv;
2169
2170         g_return_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (self));
2171         g_return_if_fail (TNY_IS_MIME_PART (attachment));
2172         priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self);
2173
2174         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2175                                                    attachment);
2176         
2177 }
2178
2179 /* TNY HEADER VIEW IMPLEMENTATION */
2180
2181 static void
2182 tny_header_view_init (gpointer g, gpointer iface_data)
2183 {
2184         TnyHeaderViewIface *klass = (TnyHeaderViewIface *)g;
2185
2186         klass->set_header = modest_msg_view_set_header;
2187         klass->clear = modest_msg_view_clear_header;
2188
2189         return;
2190 }
2191
2192 static void
2193 modest_msg_view_set_header (TnyHeaderView *self, TnyHeader *header)
2194 {
2195         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->set_header_func (self, header);
2196 }
2197
2198
2199 static void
2200 modest_msg_view_set_header_default (TnyHeaderView *self, TnyHeader *header)
2201 {
2202         set_header (MODEST_GTKHTML_MSG_VIEW (self), header);
2203 }
2204
2205 static void
2206 modest_msg_view_clear_header (TnyHeaderView *self)
2207 {
2208         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->clear_header_func (self);
2209 }
2210
2211
2212 static void
2213 modest_msg_view_clear_header_default (TnyHeaderView *self)
2214 {
2215         set_message (MODEST_GTKHTML_MSG_VIEW (self), NULL, NULL);
2216 }
2217
2218 /* TNY MSG IMPLEMENTATION */
2219
2220 static void
2221 tny_msg_view_init (gpointer g, gpointer iface_data)
2222 {
2223         TnyMsgViewIface *klass = (TnyMsgViewIface *)g;
2224
2225         klass->get_msg = modest_msg_view_get_msg;
2226         klass->set_msg = modest_msg_view_set_msg;
2227         klass->set_unavailable = modest_msg_view_set_unavailable;
2228         klass->clear = modest_msg_view_clear;
2229         klass->create_mime_part_view_for = modest_msg_view_create_mime_part_view_for;
2230         klass->create_new_inline_viewer = modest_msg_view_create_new_inline_viewer;
2231
2232         return;
2233 }
2234
2235 static TnyMsg *
2236 modest_msg_view_get_msg (TnyMsgView *self)
2237 {
2238         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->get_msg_func (self);
2239 }
2240
2241 static TnyMsg *
2242 modest_msg_view_get_msg_default (TnyMsgView *self)
2243 {
2244         return TNY_MSG (tny_mime_part_view_get_part (TNY_MIME_PART_VIEW (self)));
2245 }
2246
2247 static void
2248 modest_msg_view_set_msg (TnyMsgView *self, TnyMsg *msg)
2249 {
2250         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->set_msg_func (self, msg);
2251 }
2252
2253 static void 
2254 modest_msg_view_set_msg_default (TnyMsgView *self, TnyMsg *msg)
2255 {
2256
2257         tny_mime_part_view_set_part (TNY_MIME_PART_VIEW (self), TNY_MIME_PART (msg));
2258
2259         return;
2260 }
2261
2262 static void
2263 modest_msg_view_set_unavailable (TnyMsgView *self)
2264 {
2265         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->set_unavailable_func (self);
2266 }
2267
2268 static void
2269 modest_msg_view_set_unavailable_default (TnyMsgView *self)
2270 {
2271         tny_msg_view_clear (self);
2272
2273         return;
2274 }
2275
2276 static void
2277 modest_msg_view_clear (TnyMsgView *self)
2278 {
2279         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->clear_func (self);
2280 }
2281
2282 static void
2283 modest_msg_view_clear_default (TnyMsgView *self)
2284 {
2285         set_message (MODEST_GTKHTML_MSG_VIEW (self), NULL, NULL);
2286 }
2287
2288 static TnyMimePartView*
2289 modest_msg_view_create_mime_part_view_for (TnyMsgView *self, TnyMimePart *part)
2290 {
2291         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->create_mime_part_view_for_func (self, part);
2292 }
2293
2294 static TnyMimePartView*
2295 modest_msg_view_create_mime_part_view_for_default (TnyMsgView *self, TnyMimePart *part)
2296 {
2297         g_warning ("modest_msg_view_create_mime_part_view_for_default is not implemented");
2298         return NULL;
2299 }
2300
2301 static TnyMsgView*
2302 modest_msg_view_create_new_inline_viewer (TnyMsgView *self)
2303 {
2304         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->create_new_inline_viewer_func (self);
2305 }
2306
2307 static TnyMsgView*
2308 modest_msg_view_create_new_inline_viewer_default (TnyMsgView *self)
2309 {
2310         g_warning ("modest_msg_view_create_new_inline_viewer_default is not implemented");
2311
2312         return NULL;
2313 }
2314
2315 /* TNY MIME PART IMPLEMENTATION */
2316
2317 static void
2318 tny_mime_part_view_init (gpointer g, gpointer iface_data)
2319 {
2320         TnyMimePartViewIface *klass = (TnyMimePartViewIface *)g;
2321
2322         klass->get_part = modest_msg_view_mp_get_part;
2323         klass->set_part = modest_msg_view_mp_set_part;
2324         klass->clear = modest_msg_view_mp_clear;
2325
2326         return;
2327 }
2328
2329 static TnyMimePart* 
2330 modest_msg_view_mp_get_part (TnyMimePartView *self)
2331 {
2332         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->get_part_func (self);
2333 }
2334
2335
2336 static TnyMimePart* 
2337 modest_msg_view_mp_get_part_default (TnyMimePartView *self)
2338 {
2339         return TNY_MIME_PART (get_message (MODEST_GTKHTML_MSG_VIEW (self)));
2340 }
2341
2342 static void
2343 modest_msg_view_mp_set_part (TnyMimePartView *self,
2344                              TnyMimePart *part)
2345 {
2346         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->set_part_func (self, part);
2347 }
2348
2349 static void
2350 modest_msg_view_mp_set_part_default (TnyMimePartView *self,
2351                                      TnyMimePart *part)
2352 {
2353         g_return_if_fail ((part == NULL) || TNY_IS_MSG (part));
2354
2355         set_message (MODEST_GTKHTML_MSG_VIEW (self), TNY_MSG (part), NULL);
2356 }
2357
2358 static void
2359 modest_msg_view_mp_clear (TnyMimePartView *self)
2360 {
2361         tny_msg_view_clear (TNY_MSG_VIEW (self));
2362 }
2363
2364 /* MODEST MIME PART VIEW IMPLEMENTATION */
2365
2366 static void
2367 modest_mime_part_view_init (gpointer g, gpointer iface_data)
2368 {
2369         ModestMimePartViewIface *klass = (ModestMimePartViewIface *)g;
2370
2371         klass->is_empty_func = modest_msg_view_mp_is_empty;
2372
2373         return;
2374 }
2375
2376 static gboolean
2377 modest_msg_view_mp_is_empty (ModestMimePartView *self)
2378 {
2379         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->is_empty_func (self);
2380 }
2381
2382 static gboolean
2383 modest_msg_view_mp_is_empty_default (ModestMimePartView *self)
2384 {
2385         return is_empty (MODEST_GTKHTML_MSG_VIEW (self));
2386 }
2387
2388 /* MODEST ZOOMABLE IMPLEMENTATION */
2389 static void
2390 modest_zoomable_init (gpointer g, gpointer iface_data)
2391 {
2392         ModestZoomableIface *klass = (ModestZoomableIface *)g;
2393
2394         klass->get_zoom_func = modest_msg_view_get_zoom;
2395         klass->set_zoom_func = modest_msg_view_set_zoom;
2396         klass->zoom_minus_func = modest_msg_view_zoom_minus;
2397         klass->zoom_plus_func = modest_msg_view_zoom_plus;
2398
2399         return;
2400 }
2401
2402 static gdouble
2403 modest_msg_view_get_zoom (ModestZoomable *self)
2404 {
2405         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->get_zoom_func (self);
2406 }
2407
2408 static gdouble
2409 modest_msg_view_get_zoom_default (ModestZoomable *self)
2410 {
2411         return get_zoom (MODEST_GTKHTML_MSG_VIEW (self));
2412 }
2413
2414 static void
2415 modest_msg_view_set_zoom (ModestZoomable *self, gdouble value)
2416 {
2417         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->set_zoom_func (self, value);
2418 }
2419
2420 static void
2421 modest_msg_view_set_zoom_default (ModestZoomable *self, gdouble value)
2422 {
2423         set_zoom (MODEST_GTKHTML_MSG_VIEW (self), value);
2424 }
2425
2426 static gboolean
2427 modest_msg_view_zoom_minus (ModestZoomable *self)
2428 {
2429         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->zoom_minus_func (self);
2430 }
2431
2432 static gboolean
2433 modest_msg_view_zoom_minus_default (ModestZoomable *self)
2434 {
2435         /* operation not supported in ModestMsgView */
2436         return FALSE;
2437 }
2438
2439 static gboolean
2440 modest_msg_view_zoom_plus (ModestZoomable *self)
2441 {
2442         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->zoom_plus_func (self);
2443 }
2444
2445 static gboolean
2446 modest_msg_view_zoom_plus_default (ModestZoomable *self)
2447 {
2448         /* operation not supported in ModestMsgView */
2449         return FALSE;
2450 }
2451
2452 /* MODEST ISEARCH VIEW IMPLEMENTATION */
2453 static void
2454 modest_isearch_view_init (gpointer g, gpointer iface_data)
2455 {
2456         ModestISearchViewIface *klass = (ModestISearchViewIface *)g;
2457
2458         klass->search_func = modest_msg_view_search;
2459         klass->search_next_func = modest_msg_view_search_next;
2460
2461         return;
2462 }
2463
2464 static gboolean
2465 modest_msg_view_search (ModestISearchView *self, const gchar *string)
2466 {
2467         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->search_func (self, string);
2468 }
2469
2470 static gboolean
2471 modest_msg_view_search_default (ModestISearchView *self, const gchar *string)
2472 {
2473         return search (MODEST_GTKHTML_MSG_VIEW (self), string);
2474 }
2475
2476 static gboolean
2477 modest_msg_view_search_next (ModestISearchView *self)
2478 {
2479         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->search_next_func (self);
2480 }
2481
2482 static gboolean
2483 modest_msg_view_search_next_default (ModestISearchView *self)
2484 {
2485         return search_next (MODEST_GTKHTML_MSG_VIEW (self));
2486 }
2487
2488 /* MODEST MSG VIEW IMPLEMENTATION */
2489 static void
2490 modest_msg_view_init (gpointer g, gpointer iface_data)
2491 {
2492         ModestMsgViewIface *klass = (ModestMsgViewIface *)g;
2493
2494         klass->set_msg_with_other_body_func = modest_gtkhtml_msg_view_set_msg_with_other_body;
2495         klass->get_vadjustment_func = modest_gtkhtml_msg_view_get_vadjustment;
2496         klass->get_hadjustment_func = modest_gtkhtml_msg_view_get_hadjustment;
2497         klass->set_vadjustment_func = modest_gtkhtml_msg_view_set_vadjustment;
2498         klass->set_hadjustment_func = modest_gtkhtml_msg_view_set_hadjustment;
2499         klass->set_shadow_type_func = modest_gtkhtml_msg_view_set_shadow_type;
2500         klass->get_shadow_type_func = modest_gtkhtml_msg_view_get_shadow_type;
2501         klass->get_priority_func = modest_gtkhtml_msg_view_get_priority;
2502         klass->set_priority_func = modest_gtkhtml_msg_view_set_priority;
2503         klass->get_selected_attachments_func = modest_gtkhtml_msg_view_get_selected_attachments;
2504         klass->get_attachments_func = modest_gtkhtml_msg_view_get_attachments;
2505         klass->grab_focus_func = modest_gtkhtml_msg_view_grab_focus;
2506         klass->remove_attachment_func = modest_gtkhtml_msg_view_remove_attachment;
2507         klass->request_fetch_images_func = modest_gtkhtml_msg_view_request_fetch_images;
2508         klass->set_branding_func = modest_gtkhtml_msg_view_set_branding;
2509         klass->has_blocked_external_images_func = modest_gtkhtml_msg_view_has_blocked_external_images;
2510
2511         return;
2512 }
2513
2514 static void
2515 modest_gtkhtml_msg_view_set_msg_with_other_body (ModestMsgView *self, TnyMsg *msg, TnyMimePart *other_body)
2516 {
2517         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->set_msg_with_other_body_func (self, msg, other_body);
2518 }
2519
2520 static void
2521 modest_gtkhtml_msg_view_set_msg_with_other_body_default (ModestMsgView *self, TnyMsg *msg, TnyMimePart *other_body)
2522 {
2523         set_message (MODEST_GTKHTML_MSG_VIEW (self), msg, other_body);
2524 }
2525
2526 static GtkAdjustment*
2527 modest_gtkhtml_msg_view_get_vadjustment (ModestMsgView *self)
2528 {
2529         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->get_vadjustment_func (self);
2530 }
2531
2532 static GtkAdjustment*
2533 modest_gtkhtml_msg_view_get_vadjustment_default (ModestMsgView *self)
2534 {
2535         return get_vadjustment (MODEST_GTKHTML_MSG_VIEW (self));
2536 }
2537
2538 static GtkAdjustment*
2539 modest_gtkhtml_msg_view_get_hadjustment (ModestMsgView *self)
2540 {
2541         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->get_hadjustment_func (self);
2542 }
2543
2544 static GtkAdjustment*
2545 modest_gtkhtml_msg_view_get_hadjustment_default (ModestMsgView *self)
2546 {
2547         return get_hadjustment (MODEST_GTKHTML_MSG_VIEW (self));
2548 }
2549
2550 static void
2551 modest_gtkhtml_msg_view_set_vadjustment (ModestMsgView *self, GtkAdjustment *adj)
2552 {
2553         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->set_vadjustment_func (self, adj);
2554 }
2555
2556 static void
2557 modest_gtkhtml_msg_view_set_vadjustment_default (ModestMsgView *self, GtkAdjustment *adj)
2558 {
2559         set_vadjustment (MODEST_GTKHTML_MSG_VIEW (self), adj);
2560 }
2561
2562 static void
2563 modest_gtkhtml_msg_view_set_hadjustment (ModestMsgView *self, GtkAdjustment *adj)
2564 {
2565         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->set_hadjustment_func (self, adj);
2566 }
2567
2568 static void
2569 modest_gtkhtml_msg_view_set_hadjustment_default (ModestMsgView *self, GtkAdjustment *adj)
2570 {
2571         set_hadjustment (MODEST_GTKHTML_MSG_VIEW (self), adj);
2572 }
2573
2574 static void
2575 modest_gtkhtml_msg_view_set_shadow_type (ModestMsgView *self, GtkShadowType type)
2576 {
2577         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->set_shadow_type_func (self, type);
2578 }
2579
2580 static void
2581 modest_gtkhtml_msg_view_set_shadow_type_default (ModestMsgView *self, GtkShadowType type)
2582 {
2583         set_shadow_type (MODEST_GTKHTML_MSG_VIEW (self), type);
2584 }
2585
2586 static GtkShadowType
2587 modest_gtkhtml_msg_view_get_shadow_type (ModestMsgView *self)
2588 {
2589         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->get_shadow_type_func (self);
2590 }
2591
2592 static GtkShadowType
2593 modest_gtkhtml_msg_view_get_shadow_type_default (ModestMsgView *self)
2594 {
2595         return get_shadow_type (MODEST_GTKHTML_MSG_VIEW (self));
2596 }
2597
2598 static void
2599 modest_gtkhtml_msg_view_set_priority (ModestMsgView *self, TnyHeaderFlags flags)
2600 {
2601         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->set_priority_func (self, flags);
2602 }
2603
2604 static void
2605 modest_gtkhtml_msg_view_set_priority_default (ModestMsgView *self, TnyHeaderFlags flags)
2606 {
2607         set_priority (MODEST_GTKHTML_MSG_VIEW (self), flags);
2608 }
2609
2610 static TnyHeaderFlags
2611 modest_gtkhtml_msg_view_get_priority (ModestMsgView *self)
2612 {
2613         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->get_priority_func (self);
2614 }
2615
2616 static TnyHeaderFlags
2617 modest_gtkhtml_msg_view_get_priority_default (ModestMsgView *self)
2618 {
2619         return get_priority (MODEST_GTKHTML_MSG_VIEW (self));
2620 }
2621
2622 static TnyList*
2623 modest_gtkhtml_msg_view_get_selected_attachments (ModestMsgView *self)
2624 {
2625         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->get_selected_attachments_func (self);
2626 }
2627
2628 static TnyList*
2629 modest_gtkhtml_msg_view_get_selected_attachments_default (ModestMsgView *self)
2630 {
2631         return get_selected_attachments (MODEST_GTKHTML_MSG_VIEW (self));
2632 }
2633
2634 static TnyList*
2635 modest_gtkhtml_msg_view_get_attachments (ModestMsgView *self)
2636 {
2637         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->get_attachments_func (self);
2638 }
2639
2640 static TnyList*
2641 modest_gtkhtml_msg_view_get_attachments_default (ModestMsgView *self)
2642 {
2643         return get_attachments (MODEST_GTKHTML_MSG_VIEW (self));
2644 }
2645
2646 static void
2647 modest_gtkhtml_msg_view_grab_focus (ModestMsgView *self)
2648 {
2649         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->grab_focus_func (self);
2650 }
2651
2652 static void
2653 modest_gtkhtml_msg_view_grab_focus_default (ModestMsgView *self)
2654 {
2655         grab_focus (MODEST_GTKHTML_MSG_VIEW (self));
2656 }
2657
2658 static void
2659 modest_gtkhtml_msg_view_remove_attachment (ModestMsgView *self, TnyMimePart *attachment)
2660 {
2661         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->remove_attachment_func (self, attachment);
2662 }
2663
2664 static void
2665 modest_gtkhtml_msg_view_remove_attachment_default (ModestMsgView *self, TnyMimePart *attachment)
2666 {
2667         remove_attachment (MODEST_GTKHTML_MSG_VIEW (self), attachment);
2668 }
2669
2670 static void
2671 modest_gtkhtml_msg_view_request_fetch_images (ModestMsgView *self)
2672 {
2673         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->request_fetch_images_func (self);
2674 }
2675
2676 static void
2677 modest_gtkhtml_msg_view_request_fetch_images_default (ModestMsgView *self)
2678 {
2679         request_fetch_images (MODEST_GTKHTML_MSG_VIEW (self));
2680 }
2681
2682 static void
2683 modest_gtkhtml_msg_view_set_branding (ModestMsgView *self, const gchar *brand_name, const GdkPixbuf *brand_icon)
2684 {
2685         MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->set_branding_func (self, brand_name, brand_icon);
2686 }
2687
2688 static void
2689 modest_gtkhtml_msg_view_set_branding_default (ModestMsgView *self, const gchar *brand_name, const GdkPixbuf *brand_icon)
2690 {
2691         set_branding (MODEST_GTKHTML_MSG_VIEW (self), brand_name, brand_icon);
2692 }
2693
2694 static gboolean
2695 modest_gtkhtml_msg_view_has_blocked_external_images (ModestMsgView *self)
2696 {
2697         return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->has_blocked_external_images_func (self);
2698 }
2699
2700 static gboolean
2701 modest_gtkhtml_msg_view_has_blocked_external_images_default (ModestMsgView *self)
2702 {
2703         return has_blocked_external_images (MODEST_GTKHTML_MSG_VIEW (self));
2704 }