-GType
-modest_msg_view_get_type (void)
-{
- static GType my_type = 0;
- if (!my_type) {
- static const GTypeInfo my_info = {
- sizeof(ModestMsgViewClass),
- NULL, /* base init */
- NULL, /* base finalize */
- (GClassInitFunc) modest_msg_view_class_init,
- NULL, /* class finalize */
- NULL, /* class data */
- sizeof(ModestMsgView),
- 1, /* n_preallocs */
- (GInstanceInitFunc) modest_msg_view_init,
- NULL
- };
- my_type = g_type_register_static (GTK_TYPE_CONTAINER,
- "ModestMsgView",
- &my_info, 0);
- }
- return my_type;
-}
-
-static void
-modest_msg_view_class_init (ModestMsgViewClass *klass)
-{
- GObjectClass *gobject_class;
- GtkWidgetClass *widget_class;
- GtkObjectClass *gtkobject_class;
- GtkContainerClass *container_class;
- gobject_class = (GObjectClass*) klass;
- widget_class = (GtkWidgetClass *) klass;
- gtkobject_class = (GtkObjectClass *) klass;
- container_class = (GtkContainerClass *) klass;
-
- parent_class = g_type_class_peek_parent (klass);
- gobject_class->finalize = modest_msg_view_finalize;
- gobject_class->set_property = set_property;
- gobject_class->get_property = get_property;
- gtkobject_class->destroy = modest_msg_view_destroy;
-
- widget_class->realize = realize;
- widget_class->unrealize = unrealize;
- widget_class->expose_event = expose;
- widget_class->size_request = size_request;
- widget_class->size_allocate = size_allocate;
-
- container_class->forall = forall;
- container_class->remove = container_remove;
-
- klass->set_scroll_adjustments = set_scroll_adjustments;
-
- g_type_class_add_private (gobject_class, sizeof(ModestMsgViewPrivate));
-
- g_object_class_install_property (gobject_class,
- PROP_HADJUSTMENT,
- g_param_spec_object ("hadjustment",
- _("Horizontal adjustment"),
- _("GtkAdjustment with information of the horizontal visible position"),
- GTK_TYPE_ADJUSTMENT,
- G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
-
- g_object_class_install_property (gobject_class,
- PROP_VADJUSTMENT,
- g_param_spec_object ("vadjustment",
- _("Vertical adjustment"),
- _("GtkAdjustment with information of the vertical visible position"),
- GTK_TYPE_ADJUSTMENT,
- G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
-
- g_object_class_install_property (gobject_class,
- PROP_SHADOW_TYPE,
- g_param_spec_enum ("shadow_type",
- _("Shadow type"),
- _("Kind of shadow that's shown around the view"),
- GTK_TYPE_SHADOW_TYPE,
- GTK_SHADOW_IN,
- G_PARAM_READABLE | G_PARAM_WRITABLE ));
-
- signals[LINK_CLICKED_SIGNAL] =
- g_signal_new ("link_clicked",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET(ModestMsgViewClass, link_clicked),
- NULL, NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE, 1, G_TYPE_STRING);
-
- signals[ATTACHMENT_CLICKED_SIGNAL] =
- g_signal_new ("attachment_clicked",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET(ModestMsgViewClass, attachment_clicked),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 1, G_TYPE_OBJECT);
-
- signals[LINK_HOVER_SIGNAL] =
- g_signal_new ("link_hover",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET(ModestMsgViewClass, link_hover),
- NULL, NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE, 1, G_TYPE_STRING);
-
- signals[RECPT_ACTIVATED_SIGNAL] =
- g_signal_new ("recpt_activated",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET(ModestMsgViewClass, recpt_activated),
- NULL, NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE, 1, G_TYPE_STRING);
-
- widget_class->set_scroll_adjustments_signal =
- g_signal_new ("set_scroll_adjustments",
- G_OBJECT_CLASS_TYPE (gobject_class),
- G_SIGNAL_RUN_LAST|G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (ModestMsgViewClass, set_scroll_adjustments),
- NULL, NULL,
- modest_marshal_VOID__POINTER_POINTER,
- G_TYPE_NONE, 2,
- GTK_TYPE_ADJUSTMENT,
- GTK_TYPE_ADJUSTMENT);
-}
-
-static void
-set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ModestMsgView *msg_view = MODEST_MSG_VIEW (object);
-
- switch (prop_id) {
- case PROP_HADJUSTMENT:
- modest_msg_view_set_hadjustment (msg_view, g_value_get_object (value));
- break;
- case PROP_VADJUSTMENT:
- modest_msg_view_set_vadjustment (msg_view, g_value_get_object (value));
- break;
- case PROP_SHADOW_TYPE:
- modest_msg_view_set_shadow_type (msg_view, g_value_get_enum (value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ModestMsgView *msg_view = MODEST_MSG_VIEW (object);
- ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
-
- switch (prop_id) {
- case PROP_HADJUSTMENT:
- g_value_set_object (value, priv->hadj);
- break;
- case PROP_VADJUSTMENT:
- g_value_set_object (value, priv->vadj);
- break;
- case PROP_SHADOW_TYPE:
- g_value_set_enum (value, priv->shadow_type);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-disconnect_hadjustment (ModestMsgView *msg_view)
-{
- ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
-
- if (priv->hadj) {
- g_signal_handlers_disconnect_by_func(priv->hadj, adjustment_value_changed, msg_view);
- g_object_unref (priv->hadj);
- priv->hadj = NULL;
- }
-}
-
-static void
-disconnect_vadjustment (ModestMsgView *msg_view)
-{
- ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
-
- if (priv->vadj) {
- g_signal_handlers_disconnect_by_func(priv->vadj, adjustment_value_changed, msg_view);
- g_object_unref (priv->vadj);
- priv->vadj = NULL;
- }
-}
-
-static void
-get_view_allocation (ModestMsgView *msg_view, GtkAllocation *allocation)
-{
- /* This method gets the allocation of the widget in parent widget. It's the
- real position and size of the widget */
- ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
-
- allocation->x = 0;
- allocation->y = 0;
-
- if (priv->shadow_type != GTK_SHADOW_NONE) {
- allocation->x = GTK_WIDGET (msg_view)->style->xthickness;
- allocation->y = GTK_WIDGET (msg_view)->style->ythickness;
- }
-
- allocation->width = MAX (1, (GTK_WIDGET (msg_view)->allocation.width) - allocation->x * 2);
- allocation->height = MAX (1, (GTK_WIDGET (msg_view)->allocation.height) - allocation->y * 2);
-
-}
-
-static void
-reclamp_adjustment (GtkAdjustment *adj,
- gboolean *value_changed)
-{
- gdouble value = adj->value;
-
- /* Correct value to be inside the expected values of a scroll */
-
- value = CLAMP (value, 0, adj->upper - adj->page_size);
-
- if (value != adj->value) {
- adj->value = value;
- if (value_changed)
- *value_changed = TRUE;
- } else if (value_changed) {
- *value_changed = FALSE;
- }
-}
-
-static void
-set_hadjustment_values (ModestMsgView *msg_view,
- gboolean *value_changed)
-{
- GtkAllocation view_allocation;
- GtkAdjustment *hadj = modest_msg_view_get_hadjustment (msg_view);
-
- get_view_allocation (msg_view, &view_allocation);
- hadj->page_size = view_allocation.width;
- hadj->step_increment = view_allocation.width * 0.1;
- hadj->page_increment = view_allocation.width * 0.9;
-
- hadj->lower = 0;
- hadj->upper = view_allocation.width;
-
- reclamp_adjustment (hadj, value_changed);
-
-}
-
-static void
-set_vadjustment_values (ModestMsgView *msg_view,
- gboolean *value_changed)
-{
- GtkAllocation view_allocation;
- GtkAdjustment *vadj = modest_msg_view_get_vadjustment (msg_view);
- ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
- gint full_height = 0;
- GtkAdjustment *html_vadj;
-
- get_view_allocation (msg_view, &view_allocation);
- vadj->page_size = view_allocation.height;
- vadj->step_increment = view_allocation.height * 0.1;
- vadj->page_increment = view_allocation.height * 0.9;
-
- vadj->lower = 0;
-
- if (priv->headers_box && GTK_WIDGET_VISIBLE(priv->headers_box)) {
- GtkRequisition child_requisition;
-
- gtk_widget_get_child_requisition (priv->headers_box, &child_requisition);
- full_height = child_requisition.height;
- } else {
- full_height = 0;
- }
-
- /* Get the real height of the embedded html */
- if (priv->html_scroll && GTK_WIDGET_VISIBLE(priv->html_scroll)) {
- html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
- full_height += html_vadj->upper;
- }
-
- vadj->upper = MAX (view_allocation.height, full_height);
-
- reclamp_adjustment (vadj, value_changed);
-
-}
-
-static void
-set_scroll_adjustments (ModestMsgView *msg_view,
- GtkAdjustment *hadj,
- GtkAdjustment *vadj)
-{
- modest_msg_view_set_hadjustment (msg_view, hadj);
- modest_msg_view_set_vadjustment (msg_view, vadj);
-}
-
-static void
-realize (GtkWidget *widget)
-{
- ModestMsgView *msg_view = MODEST_MSG_VIEW (widget);
- ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
- GtkAdjustment *hadj = modest_msg_view_get_hadjustment (msg_view);
- GtkAdjustment *vadj = modest_msg_view_get_vadjustment (msg_view);
- GdkWindowAttr attributes;
- gint event_mask;
- gint attributes_mask;
- GtkAllocation view_allocation;
-
- GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-
- /* The structure of the GdkWindow's is:
- * * widget->window: the shown gdkwindow embedding all the stuff inside
- * * view_window: a backing store gdkwindow containing the headers and contents
- * being scrolled. This window should have all the visible and non visible
- * widgets inside.
- * * headers_window: gdk window for headers_box.
- * * html_window: gdk window for html_scroll (the scrolled window containing the
- * gtkhtml showing the contents of the mail).
- */
-
- attributes.x = widget->allocation.x;
- attributes.y = widget->allocation.y;
- attributes.width = widget->allocation.width;
- attributes.height = widget->allocation.height;
- attributes.window_type = GDK_WINDOW_CHILD;
- attributes.wclass = GDK_INPUT_OUTPUT;
- attributes.visual = gtk_widget_get_visual (widget);
- attributes.colormap = gtk_widget_get_colormap (widget);
-
- event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
- attributes.event_mask = event_mask | GDK_BUTTON_PRESS_MASK;
- attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-
- widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
- &attributes, attributes_mask);
- gdk_window_set_user_data (widget->window, msg_view);
-
- get_view_allocation (msg_view, &view_allocation);
-
- attributes.x = view_allocation.x;
- attributes.y = view_allocation.y;
- attributes.width = view_allocation.width;
- attributes.height = view_allocation.height;
- attributes.event_mask = 0;
- priv->view_window = gdk_window_new (widget->window, &attributes, attributes_mask);
- gdk_window_set_user_data (priv->view_window, msg_view);
- gdk_window_set_back_pixmap (priv->view_window, NULL, FALSE);
-
- attributes.x = -hadj->value;
- attributes.y = -vadj->value;
- attributes.width = hadj->upper;
- if (priv->headers_box)
- attributes.height = GTK_WIDGET (priv->headers_box)->allocation.height;
- else
- attributes.height = 1;
- attributes.event_mask = event_mask;
-
- priv->headers_window = gdk_window_new (priv->view_window, &attributes, attributes_mask);
- gdk_window_set_user_data (priv->headers_window, msg_view);
-
- if (priv->headers_box)
- gtk_widget_set_parent_window (priv->headers_box, priv->headers_window);
-
- attributes.x = -hadj->value;
- if (priv->headers_box)
- attributes.y = GTK_WIDGET (priv->headers_box)->allocation.height - vadj->value;
- else
- attributes.y = -vadj->value;
- attributes.width = hadj->upper;
- if (priv->headers_box)
- attributes.height = vadj->upper - GTK_WIDGET (priv->headers_box)->allocation.height;
- else
- attributes.height = vadj->upper;
- attributes.event_mask = event_mask;
-
- priv->html_window = gdk_window_new (priv->view_window, &attributes, attributes_mask);
- gdk_window_set_user_data (priv->html_window, msg_view);
-
- if (priv->html_scroll)
- gtk_widget_set_parent_window (priv->html_scroll, priv->html_window);
-
- widget->style = gtk_style_attach (widget->style, widget->window);
- gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
- gtk_style_set_background (widget->style, priv->headers_window, GTK_STATE_NORMAL);
- gtk_style_set_background (widget->style, priv->html_window, GTK_STATE_NORMAL);
-
- gtk_paint_flat_box(widget->style, priv->headers_window, GTK_STATE_NORMAL,
- GTK_SHADOW_NONE,
- NULL, widget, "msgviewheaders",
- 0,0,-1,-1);
- gtk_paint_flat_box(widget->style, priv->html_window, GTK_STATE_NORMAL,
- GTK_SHADOW_NONE,
- NULL, widget, "msgviewcontents",
- 0,0,-1,-1);
-
- gdk_window_show (priv->view_window);
- gdk_window_show (priv->headers_window);
- gdk_window_show (priv->html_window);
-
-}
-
-static void
-unrealize (GtkWidget *widget)
-{
- ModestMsgView *msg_view = MODEST_MSG_VIEW (widget);
- ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
-
- gdk_window_set_user_data (priv->view_window, NULL);
- gdk_window_destroy (priv->view_window);
- priv->view_window = NULL;
-
- gdk_window_set_user_data (priv->headers_window, NULL);
- gdk_window_destroy (priv->headers_window);
- priv->headers_window = NULL;
-
- gdk_window_set_user_data (priv->html_window, NULL);
- gdk_window_destroy (priv->html_window);
- priv->html_window = NULL;
-
- if (GTK_WIDGET_CLASS (parent_class)->unrealize)
- ( * GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
-
-}
-
-static gint
-expose (GtkWidget *widget,
- GdkEventExpose *event)
-{
- ModestMsgView *msg_view;
- ModestMsgViewPrivate *priv;
-
- if (GTK_WIDGET_DRAWABLE (widget)) {
- msg_view = MODEST_MSG_VIEW (widget);
- priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
- if (event->window == widget->window) {
- gtk_paint_shadow (widget->style, widget->window,
- GTK_STATE_NORMAL, priv->shadow_type,
- &event->area, widget, "msgview",
- 0,0,-1,-1);
- } else if (event->window == priv->headers_window) {
- gtk_paint_flat_box(widget->style, priv->headers_window, GTK_STATE_NORMAL,
- GTK_SHADOW_NONE,
- &event->area, widget, "msgviewheaders",
- 0,0,-1,-1);
- } else if (event->window == priv->html_window) {
- gtk_paint_flat_box(widget->style, priv->html_window, GTK_STATE_NORMAL,
- GTK_SHADOW_NONE,
- &event->area, widget, "msgviewcontents",
- 0,0,-1,-1);
- }
- if (priv->headers_box)
- gtk_container_propagate_expose (GTK_CONTAINER (msg_view), priv->headers_box, event);
- if (priv->html_scroll)
- gtk_container_propagate_expose (GTK_CONTAINER (msg_view), priv->html_scroll, event);
- (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
- }
-
- return FALSE;
-}
-
-static void
-forall (GtkContainer *container,
- gboolean include_internals,
- GtkCallback callback,
- gpointer userdata)
-{
- ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (container);
- g_return_if_fail (callback != NULL);
-
- if (priv->headers_box)
- (*callback) (priv->headers_box, userdata);
- if (priv->html_scroll)
- (*callback) (priv->html_scroll, userdata);
-}
-
-static void
-container_remove (GtkContainer *container,
- GtkWidget *widget)
-{
- gboolean was_visible = FALSE;
- ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (container);
- was_visible = GTK_WIDGET_VISIBLE (widget);
- if (widget == priv->headers_box) {
- gtk_widget_unparent (priv->headers_box);
- priv->headers_box = NULL;
- } else if (widget == priv->html_scroll) {
- gtk_widget_unparent (priv->html_scroll);
- priv->html_scroll = NULL;
- } else {
- return;
- }
- if (was_visible)
- gtk_widget_queue_resize (GTK_WIDGET(container));
-
-}
-
-static void
-size_request (GtkWidget *widget,
- GtkRequisition *req)
-{
- ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (widget);
- GtkRequisition child_req;
-
- req->width = 0;
- req->height = 0;
-
- gtk_widget_size_request (priv->headers_box, &child_req);
- req->width = child_req.width;
- req->height += child_req.height;
- gtk_widget_size_request (priv->html_scroll, &child_req);
- req->width = MAX (child_req.width, req->width);
- req->height += child_req.height;
-
-}
-
-static void
-size_allocate (GtkWidget *widget,
- GtkAllocation *allocation)