]> www.fi.muni.cz Git - evince.git/blobdiff - libdocument/ev-annotation.c
[dualscreen] fix crash on ctrl+w and fix control window closing
[evince.git] / libdocument / ev-annotation.c
index 2fadb9787be2f8ccc9acf564ed3b6b6e52f68322..e215fdfbda7538a24a12181822d1b7c7f567f68a 100644 (file)
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
 #include "config.h"
 
 #include "ev-annotation.h"
+#include "ev-document-misc.h"
+#include "ev-document-type-builtins.h"
 
+struct _EvAnnotation {
+       GObject          parent;
 
-static void ev_annotation_markup_iface_base_init (EvAnnotationMarkupIface *iface);
-static void ev_annotation_text_markup_iface_init (EvAnnotationMarkupIface *iface);
+       EvAnnotationType type;
+       EvPage          *page;
+
+       gchar           *contents;
+       gchar           *name;
+       gchar           *modified;
+       GdkColor         color;
 
-enum {
-       PROP_0,
-       PROP_LABEL,
-       PROP_OPACITY,
-       PROP_HAS_POPUP,
-       PROP_RECTANGLE,
-       PROP_IS_OPEN
 };
 
-G_DEFINE_ABSTRACT_TYPE (EvAnnotation, ev_annotation, G_TYPE_OBJECT)
-GType
-ev_annotation_markup_get_type (void)
-{
-       static volatile gsize g_define_type_id__volatile = 0;
+struct _EvAnnotationClass {
+       GObjectClass parent_class;
+};
 
-       if (g_once_init_enter (&g_define_type_id__volatile)) {
-               GType g_define_type_id;
-               const GTypeInfo our_info = {
-                       sizeof (EvAnnotationMarkupIface),
-                       (GBaseInitFunc) ev_annotation_markup_iface_base_init,
-                       NULL,
-               };
+struct _EvAnnotationMarkupInterface {
+       GTypeInterface base_iface;
+};
 
-               g_define_type_id = g_type_register_static (G_TYPE_INTERFACE,
-                                                          "EvAnnotationMarkup",
-                                                          &our_info, (GTypeFlags)0);
-               g_type_interface_add_prerequisite (g_define_type_id, EV_TYPE_ANNOTATION);
+struct _EvAnnotationText {
+       EvAnnotation parent;
 
-               g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
-       }
+       gboolean             is_open : 1;
+       EvAnnotationTextIcon icon;
+};
 
-       return g_define_type_id__volatile;
-}
+struct _EvAnnotationTextClass {
+       EvAnnotationClass parent_class;
+};
+
+struct _EvAnnotationAttachment {
+       EvAnnotation parent;
+
+       EvAttachment *attachment;
+};
+
+struct _EvAnnotationAttachmentClass {
+       EvAnnotationClass parent_class;
+};
+
+static void ev_annotation_markup_default_init          (EvAnnotationMarkupInterface *iface);
+static void ev_annotation_text_markup_iface_init       (EvAnnotationMarkupInterface *iface);
+static void ev_annotation_attachment_markup_iface_init (EvAnnotationMarkupInterface *iface);
+
+/* EvAnnotation */
+enum {
+       PROP_ANNOT_0,
+       PROP_ANNOT_PAGE,
+       PROP_ANNOT_CONTENTS,
+       PROP_ANNOT_NAME,
+       PROP_ANNOT_MODIFIED,
+       PROP_ANNOT_COLOR
+};
 
+/* EvAnnotationMarkup */
+enum {
+       PROP_MARKUP_0,
+       PROP_MARKUP_LABEL,
+       PROP_MARKUP_OPACITY,
+       PROP_MARKUP_HAS_POPUP,
+       PROP_MARKUP_RECTANGLE,
+       PROP_MARKUP_POPUP_IS_OPEN
+};
+
+/* EvAnnotationText */
+enum {
+       PROP_TEXT_ICON = PROP_MARKUP_POPUP_IS_OPEN + 1,
+       PROP_TEXT_IS_OPEN
+};
+
+/* EvAnnotationAttachment */
+enum {
+       PROP_ATTACHMENT_ATTACHMENT = PROP_MARKUP_POPUP_IS_OPEN + 1
+};
+
+G_DEFINE_ABSTRACT_TYPE (EvAnnotation, ev_annotation, G_TYPE_OBJECT)
+G_DEFINE_INTERFACE (EvAnnotationMarkup, ev_annotation_markup, EV_TYPE_ANNOTATION)
 G_DEFINE_TYPE_WITH_CODE (EvAnnotationText, ev_annotation_text, EV_TYPE_ANNOTATION,
         {
                 G_IMPLEMENT_INTERFACE (EV_TYPE_ANNOTATION_MARKUP,
                                        ev_annotation_text_markup_iface_init);
         });
+G_DEFINE_TYPE_WITH_CODE (EvAnnotationAttachment, ev_annotation_attachment, EV_TYPE_ANNOTATION,
+        {
+                G_IMPLEMENT_INTERFACE (EV_TYPE_ANNOTATION_MARKUP,
+                                       ev_annotation_attachment_markup_iface_init);
+        });
 
 /* EvAnnotation */
 static void
@@ -99,6 +147,62 @@ ev_annotation_finalize (GObject *object)
 static void
 ev_annotation_init (EvAnnotation *annot)
 {
+       annot->type = EV_ANNOTATION_TYPE_UNKNOWN;
+}
+
+static void
+ev_annotation_set_property (GObject      *object,
+                           guint         prop_id,
+                           const GValue *value,
+                           GParamSpec   *pspec)
+{
+       EvAnnotation *annot = EV_ANNOTATION (object);
+
+       switch (prop_id) {
+       case PROP_ANNOT_PAGE:
+               annot->page = g_value_dup_object (value);
+               break;
+       case PROP_ANNOT_CONTENTS:
+               ev_annotation_set_contents (annot, g_value_get_string (value));
+               break;
+       case PROP_ANNOT_NAME:
+               ev_annotation_set_name (annot, g_value_get_string (value));
+               break;
+       case PROP_ANNOT_MODIFIED:
+               ev_annotation_set_modified (annot, g_value_get_string (value));
+               break;
+       case PROP_ANNOT_COLOR:
+               ev_annotation_set_color (annot, g_value_get_pointer (value));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
+static void
+ev_annotation_get_property (GObject    *object,
+                           guint       prop_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
+{
+       EvAnnotation *annot = EV_ANNOTATION (object);
+
+       switch (prop_id) {
+       case PROP_ANNOT_CONTENTS:
+               g_value_set_string (value, ev_annotation_get_contents (annot));
+               break;
+       case PROP_ANNOT_NAME:
+               g_value_set_string (value, ev_annotation_get_name (annot));
+               break;
+       case PROP_ANNOT_MODIFIED:
+               g_value_set_string (value, ev_annotation_get_modified (annot));
+               break;
+       case PROP_ANNOT_COLOR:
+               g_value_set_pointer (value, &annot->color);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
 }
 
 static void
@@ -107,17 +211,208 @@ ev_annotation_class_init (EvAnnotationClass *klass)
        GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
 
        g_object_class->finalize = ev_annotation_finalize;
+       g_object_class->set_property = ev_annotation_set_property;
+       g_object_class->get_property = ev_annotation_get_property;
+
+       g_object_class_install_property (g_object_class,
+                                        PROP_ANNOT_PAGE,
+                                        g_param_spec_object ("page",
+                                                             "Page",
+                                                             "The page wehere the annotation is",
+                                                             EV_TYPE_PAGE,
+                                                             G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+       g_object_class_install_property (g_object_class,
+                                        PROP_ANNOT_CONTENTS,
+                                        g_param_spec_string ("contents",
+                                                             "Contents",
+                                                             "The annotation contents",
+                                                             NULL,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (g_object_class,
+                                        PROP_ANNOT_NAME,
+                                        g_param_spec_string ("name",
+                                                             "Name",
+                                                             "The annotation unique name",
+                                                             NULL,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (g_object_class,
+                                        PROP_ANNOT_MODIFIED,
+                                        g_param_spec_string ("modified",
+                                                             "Modified",
+                                                             "Last modified date as string",
+                                                             NULL,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (g_object_class,
+                                        PROP_ANNOT_COLOR,
+                                        g_param_spec_pointer ("color",
+                                                              "Color",
+                                                              "The annotation color",
+                                                              G_PARAM_READWRITE));
 }
 
-EvAnnotation *
-ev_annotation_text_new (EvPage *page)
+EvAnnotationType
+ev_annotation_get_annotation_type (EvAnnotation *annot)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), 0);
+
+       return annot->type;
+}
+
+EvPage *
+ev_annotation_get_page (EvAnnotation *annot)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), NULL);
+
+       return annot->page;
+}
+
+guint
+ev_annotation_get_page_index (EvAnnotation *annot)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), 0);
+
+       return annot->page->index;
+}
+
+gboolean
+ev_annotation_equal (EvAnnotation *annot,
+                    EvAnnotation *other)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
+       g_return_val_if_fail (EV_IS_ANNOTATION (other), FALSE);
+
+       return (annot == other || g_strcmp0 (annot->name, other->name) == 0);
+}
+
+const gchar *
+ev_annotation_get_contents (EvAnnotation *annot)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), NULL);
+
+       return annot->contents;
+}
+
+gboolean
+ev_annotation_set_contents (EvAnnotation *annot,
+                           const gchar  *contents)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
+
+       if (g_strcmp0 (annot->contents, contents) == 0)
+               return FALSE;
+
+       if (annot->contents)
+               g_free (annot->contents);
+       annot->contents = contents ? g_strdup (contents) : NULL;
+
+       g_object_notify (G_OBJECT (annot), "contents");
+
+       return TRUE;
+}
+
+const gchar *
+ev_annotation_get_name (EvAnnotation *annot)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), NULL);
+
+       return annot->name;
+}
+
+gboolean
+ev_annotation_set_name (EvAnnotation *annot,
+                       const gchar  *name)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
+
+       if (g_strcmp0 (annot->name, name) == 0)
+               return FALSE;
+
+       if (annot->name)
+               g_free (annot->name);
+       annot->name = name ? g_strdup (name) : NULL;
+
+       g_object_notify (G_OBJECT (annot), "name");
+
+       return TRUE;
+}
+
+const gchar *
+ev_annotation_get_modified (EvAnnotation *annot)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), NULL);
+
+       return annot->modified;
+}
+
+gboolean
+ev_annotation_set_modified (EvAnnotation *annot,
+                           const gchar  *modified)
 {
-       EvAnnotation *annot;
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
+
+       if (g_strcmp0 (annot->modified, modified) == 0)
+               return FALSE;
+
+       if (annot->modified)
+               g_free (annot->modified);
+       annot->modified = modified ? g_strdup (modified) : NULL;
 
-       annot = EV_ANNOTATION (g_object_new (EV_TYPE_ANNOTATION_TEXT, NULL));
-       annot->page = g_object_ref (page);
+       g_object_notify (G_OBJECT (annot), "modified");
 
-       return annot;
+       return TRUE;
+}
+
+gboolean
+ev_annotation_set_modified_from_time (EvAnnotation *annot,
+                                     GTime         utime)
+{
+       gchar *modified;
+
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
+
+       modified = ev_document_misc_format_date (utime);
+
+       if (g_strcmp0 (annot->modified, modified) == 0) {
+               g_free (modified);
+               return FALSE;
+       }
+
+       if (annot->modified)
+               g_free (annot->modified);
+       annot->modified = modified;
+
+       g_object_notify (G_OBJECT (annot), "modified");
+
+       return TRUE;
+}
+
+void
+ev_annotation_get_color (EvAnnotation *annot,
+                        GdkColor     *color)
+{
+       g_return_if_fail (EV_IS_ANNOTATION (annot));
+
+       if (color)
+               *color = annot->color;
+}
+
+gboolean
+ev_annotation_set_color (EvAnnotation   *annot,
+                        const GdkColor *color)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
+
+       if (annot->color.red == color->red &&
+           annot->color.green == color->green &&
+           annot->color.blue == color->blue)
+               return FALSE;
+
+       if (color)
+               annot->color = *color;
+
+       g_object_notify (G_OBJECT (annot), "color");
+
+       return TRUE;
 }
 
 /* EvAnnotationMarkup */
@@ -125,12 +420,12 @@ typedef struct {
        gchar   *label;
        gdouble  opacity;
        gboolean has_popup;
-       gboolean is_open;
-       EvRectangle *rectangle;
+       gboolean popup_is_open;
+       EvRectangle rectangle;
 } EvAnnotationMarkupProps;
 
 static void
-ev_annotation_markup_iface_base_init (EvAnnotationMarkupIface *iface)
+ev_annotation_markup_default_init (EvAnnotationMarkupInterface *iface)
 {
        static gboolean initialized = FALSE;
 
@@ -147,7 +442,7 @@ ev_annotation_markup_iface_base_init (EvAnnotationMarkupIface *iface)
                                                                          "Opacity of the markup annotation",
                                                                          0,
                                                                          G_MAXDOUBLE,
-                                                                         0,
+                                                                         1.,
                                                                          G_PARAM_READWRITE));
                g_object_interface_install_property (iface,
                                                     g_param_spec_boolean ("has_popup",
@@ -164,8 +459,8 @@ ev_annotation_markup_iface_base_init (EvAnnotationMarkupIface *iface)
                                                                         EV_TYPE_RECTANGLE,
                                                                         G_PARAM_READWRITE));
                g_object_interface_install_property (iface,
-                                                    g_param_spec_boolean ("is_open",
-                                                                          "Is open",
+                                                    g_param_spec_boolean ("popup_is_open",
+                                                                          "PopupIsOpen",
                                                                           "Whether the popup associated to "
                                                                           "the markup annotation is open",
                                                                           FALSE,
@@ -178,7 +473,6 @@ static void
 ev_annotation_markup_props_free (EvAnnotationMarkupProps *props)
 {
        g_free (props->label);
-       ev_rectangle_free (props->rectangle);
        g_slice_free (EvAnnotationMarkupProps, props);
 }
 
@@ -208,27 +502,23 @@ ev_annotation_markup_set_property (GObject      *object,
                                   const GValue *value,
                                   GParamSpec   *pspec)
 {
-       EvAnnotationMarkupProps *props;
-
-       props = ev_annotation_markup_get_properties (EV_ANNOTATION_MARKUP (object));
+       EvAnnotationMarkup *markup = EV_ANNOTATION_MARKUP (object);
 
        switch (prop_id) {
-       case PROP_LABEL:
-               g_free (props->label);
-               props->label = g_value_dup_string (value);
+       case PROP_MARKUP_LABEL:
+               ev_annotation_markup_set_label (markup, g_value_get_string (value));
                break;
-       case PROP_OPACITY:
-               props->opacity = g_value_get_double (value);
+       case PROP_MARKUP_OPACITY:
+               ev_annotation_markup_set_opacity (markup, g_value_get_double (value));
                break;
-       case PROP_HAS_POPUP:
-               props->has_popup = g_value_get_boolean (value);
+       case PROP_MARKUP_HAS_POPUP:
+               ev_annotation_markup_set_has_popup (markup, g_value_get_boolean (value));
                break;
-       case PROP_RECTANGLE:
-               ev_rectangle_free (props->rectangle);
-               props->rectangle = g_value_dup_boxed (value);
+       case PROP_MARKUP_RECTANGLE:
+               ev_annotation_markup_set_rectangle (markup, g_value_get_boxed (value));
                break;
-       case PROP_IS_OPEN:
-               props->is_open = g_value_get_boolean (value);
+       case PROP_MARKUP_POPUP_IS_OPEN:
+               ev_annotation_markup_set_popup_is_open (markup, g_value_get_boolean (value));
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -246,20 +536,20 @@ ev_annotation_markup_get_property (GObject    *object,
        props = ev_annotation_markup_get_properties (EV_ANNOTATION_MARKUP (object));
 
        switch (prop_id) {
-       case PROP_LABEL:
+       case PROP_MARKUP_LABEL:
                g_value_set_string (value, props->label);
                break;
-       case PROP_OPACITY:
+       case PROP_MARKUP_OPACITY:
                g_value_set_double (value, props->opacity);
                break;
-       case PROP_HAS_POPUP:
+       case PROP_MARKUP_HAS_POPUP:
                g_value_set_boolean (value, props->has_popup);
                break;
-       case PROP_RECTANGLE:
-               g_value_set_boxed (value, props->rectangle);
+       case PROP_MARKUP_RECTANGLE:
+               g_value_set_boxed (value, &props->rectangle);
                break;
-       case PROP_IS_OPEN:
-               g_value_set_boolean (value, props->is_open);
+       case PROP_MARKUP_POPUP_IS_OPEN:
+               g_value_set_boolean (value, props->popup_is_open);
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -272,106 +562,227 @@ ev_annotation_markup_class_install_properties (GObjectClass *klass)
        klass->set_property = ev_annotation_markup_set_property;
        klass->get_property = ev_annotation_markup_get_property;
 
-       g_object_class_override_property (klass, PROP_LABEL, "label");
-       g_object_class_override_property (klass, PROP_OPACITY, "opacity");
-       g_object_class_override_property (klass, PROP_HAS_POPUP, "has_popup");
-       g_object_class_override_property (klass, PROP_RECTANGLE, "rectangle");
-       g_object_class_override_property (klass, PROP_IS_OPEN, "is_open");
+       g_object_class_override_property (klass, PROP_MARKUP_LABEL, "label");
+       g_object_class_override_property (klass, PROP_MARKUP_OPACITY, "opacity");
+       g_object_class_override_property (klass, PROP_MARKUP_HAS_POPUP, "has_popup");
+       g_object_class_override_property (klass, PROP_MARKUP_RECTANGLE, "rectangle");
+       g_object_class_override_property (klass, PROP_MARKUP_POPUP_IS_OPEN, "popup_is_open");
 }
 
-gchar *
+const gchar *
 ev_annotation_markup_get_label (EvAnnotationMarkup *markup)
 {
-       gchar *retval;
+       EvAnnotationMarkupProps *props;
 
        g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), NULL);
 
-       g_object_get (G_OBJECT (markup), "label", &retval, NULL);
-
-       return retval;
+       props = ev_annotation_markup_get_properties (markup);
+       return props->label;
 }
 
-void
+gboolean
 ev_annotation_markup_set_label (EvAnnotationMarkup *markup,
                                const gchar        *label)
 {
-       g_return_if_fail (EV_IS_ANNOTATION_MARKUP (markup));
-       g_return_if_fail (label != NULL);
+       EvAnnotationMarkupProps *props;
+
+       g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
+       g_return_val_if_fail (label != NULL, FALSE);
 
-       g_object_set (G_OBJECT (markup), "label", label, NULL);
+       props = ev_annotation_markup_get_properties (markup);
+       if (g_strcmp0 (props->label, label) == 0)
+               return FALSE;
+
+       if (props->label)
+               g_free (props->label);
+       props->label = g_strdup (label);
+
+       g_object_notify (G_OBJECT (markup), "label");
+
+       return TRUE;
 }
 
 gdouble
 ev_annotation_markup_get_opacity (EvAnnotationMarkup *markup)
 {
-       gdouble retval;
-
-       g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), 0.0);
+       EvAnnotationMarkupProps *props;
 
-       g_object_get (G_OBJECT (markup), "opacity", &retval, NULL);
+       g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), 1.0);
 
-       return retval;
+       props = ev_annotation_markup_get_properties (markup);
+       return props->opacity;
 }
 
-void
+gboolean
 ev_annotation_markup_set_opacity (EvAnnotationMarkup *markup,
                                  gdouble             opacity)
 {
-       g_return_if_fail (EV_IS_ANNOTATION_MARKUP (markup));
+       EvAnnotationMarkupProps *props;
+
+       g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
+
+       props = ev_annotation_markup_get_properties (markup);
+       if (props->opacity == opacity)
+               return FALSE;
+
+       props->opacity = opacity;
 
-       g_object_set (G_OBJECT (markup), "opacity", opacity, NULL);
+       g_object_notify (G_OBJECT (markup), "opacity");
+
+       return TRUE;
 }
 
 gboolean
 ev_annotation_markup_has_popup (EvAnnotationMarkup *markup)
 {
-       gboolean retval;
+       EvAnnotationMarkupProps *props;
+
+       g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
+
+       props = ev_annotation_markup_get_properties (markup);
+       return props->has_popup;
+}
+
+gboolean
+ev_annotation_markup_set_has_popup (EvAnnotationMarkup *markup,
+                                   gboolean            has_popup)
+{
+       EvAnnotationMarkupProps *props;
 
        g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
 
-       g_object_get (G_OBJECT (markup), "has_popup", &retval, NULL);
+       props = ev_annotation_markup_get_properties (markup);
+       if (props->has_popup == has_popup)
+               return FALSE;
 
-       return retval;
+       props->has_popup = has_popup;
+
+       g_object_notify (G_OBJECT (markup), "has-popup");
+
+       return TRUE;
 }
 
 void
 ev_annotation_markup_get_rectangle (EvAnnotationMarkup *markup,
                                    EvRectangle        *ev_rect)
 {
-       EvRectangle *r;
+       EvAnnotationMarkupProps *props;
 
        g_return_if_fail (EV_IS_ANNOTATION_MARKUP (markup));
        g_return_if_fail (ev_rect != NULL);
 
-       g_object_get (G_OBJECT (markup), "rectangle", &r, NULL);
-       *ev_rect = *r;
+       props = ev_annotation_markup_get_properties (markup);
+       *ev_rect = props->rectangle;
 }
 
 gboolean
-ev_annotation_markup_get_is_open (EvAnnotationMarkup *markup)
+ev_annotation_markup_set_rectangle (EvAnnotationMarkup *markup,
+                                   const EvRectangle  *ev_rect)
 {
-       gboolean retval;
+       EvAnnotationMarkupProps *props;
 
        g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
+       g_return_val_if_fail (ev_rect != NULL, FALSE);
+
+       props = ev_annotation_markup_get_properties (markup);
+       if (props->rectangle.x1 == ev_rect->x1 &&
+           props->rectangle.y1 == ev_rect->y1 &&
+           props->rectangle.x2 == ev_rect->x2 &&
+           props->rectangle.y2 == ev_rect->y2)
+               return FALSE;
 
-       g_object_get (G_OBJECT (markup), "is_open", &retval, NULL);
+       props->rectangle = *ev_rect;
 
-       return retval;
+       g_object_notify (G_OBJECT (markup), "rectangle");
+
+       return TRUE;
 }
 
-void
-ev_annotation_markup_set_is_open (EvAnnotationMarkup *markup,
-                                 gboolean            is_open)
+gboolean
+ev_annotation_markup_get_popup_is_open (EvAnnotationMarkup *markup)
 {
-       g_return_if_fail (EV_IS_ANNOTATION_MARKUP (markup));
+       EvAnnotationMarkupProps *props;
+
+       g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
+
+       props = ev_annotation_markup_get_properties (markup);
+       return props->popup_is_open;
+}
+
+gboolean
+ev_annotation_markup_set_popup_is_open (EvAnnotationMarkup *markup,
+                                       gboolean            is_open)
+{
+       EvAnnotationMarkupProps *props;
+
+       g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
 
-       g_object_set (G_OBJECT (markup), "is_open", is_open, NULL);
+       props = ev_annotation_markup_get_properties (markup);
+       if (props->popup_is_open == is_open)
+               return FALSE;
+
+       props->popup_is_open = is_open;
+
+       g_object_notify (G_OBJECT (markup), "popup_is_open");
+
+       return TRUE;
 }
 
 /* EvAnnotationText */
 static void
 ev_annotation_text_init (EvAnnotationText *annot)
 {
+       EV_ANNOTATION (annot)->type = EV_ANNOTATION_TYPE_TEXT;
+}
+
+static void
+ev_annotation_text_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+       EvAnnotationText *annot = EV_ANNOTATION_TEXT (object);
+
+       if (prop_id < PROP_ATTACHMENT_ATTACHMENT) {
+               ev_annotation_markup_set_property (object, prop_id, value, pspec);
+               return;
+       }
+
+       switch (prop_id) {
+       case PROP_TEXT_ICON:
+               ev_annotation_text_set_icon (annot, g_value_get_enum (value));
+               break;
+       case PROP_TEXT_IS_OPEN:
+               ev_annotation_text_set_is_open (annot, g_value_get_boolean (value));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
+static void
+ev_annotation_text_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+       EvAnnotationText *annot = EV_ANNOTATION_TEXT (object);
+
+       if (prop_id < PROP_ATTACHMENT_ATTACHMENT) {
+               ev_annotation_markup_get_property (object, prop_id, value, pspec);
+               return;
+       }
+
+       switch (prop_id) {
+       case PROP_TEXT_ICON:
+               g_value_set_enum (value, annot->icon);
+               break;
+       case PROP_TEXT_IS_OPEN:
+               g_value_set_boolean (value, annot->is_open);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
 }
 
 static void
@@ -380,10 +791,212 @@ ev_annotation_text_class_init (EvAnnotationTextClass *klass)
        GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
 
        ev_annotation_markup_class_install_properties (g_object_class);
+
+       g_object_class->set_property = ev_annotation_text_set_property;
+       g_object_class->get_property = ev_annotation_text_get_property;
+
+       g_object_class_install_property (g_object_class,
+                                        PROP_TEXT_ICON,
+                                        g_param_spec_enum ("icon",
+                                                           "Icon",
+                                                           "The icon fo the text annotation",
+                                                           EV_TYPE_ANNOTATION_TEXT_ICON,
+                                                           EV_ANNOTATION_TEXT_ICON_NOTE,
+                                                           G_PARAM_READWRITE));
+       g_object_class_install_property (g_object_class,
+                                        PROP_TEXT_IS_OPEN,
+                                        g_param_spec_boolean ("is_open",
+                                                              "IsOpen",
+                                                              "Whether text annot is initially open",
+                                                              FALSE,
+                                                              G_PARAM_READWRITE));
+}
+
+static void
+ev_annotation_text_markup_iface_init (EvAnnotationMarkupInterface *iface)
+{
+}
+
+EvAnnotation *
+ev_annotation_text_new (EvPage *page)
+{
+       return EV_ANNOTATION (g_object_new (EV_TYPE_ANNOTATION_TEXT,
+                                           "page", page,
+                                           NULL));
+}
+
+EvAnnotationTextIcon
+ev_annotation_text_get_icon (EvAnnotationText *text)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION_TEXT (text), 0);
+
+       return text->icon;
+}
+
+gboolean
+ev_annotation_text_set_icon (EvAnnotationText    *text,
+                            EvAnnotationTextIcon icon)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION_TEXT (text), FALSE);
+
+       if (text->icon == icon)
+               return FALSE;
+
+       text->icon = icon;
+
+       g_object_notify (G_OBJECT (text), "icon");
+
+       return TRUE;
+}
+
+gboolean
+ev_annotation_text_get_is_open (EvAnnotationText *text)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION_TEXT (text), FALSE);
+
+       return text->is_open;
+}
+
+gboolean
+ev_annotation_text_set_is_open (EvAnnotationText *text,
+                               gboolean          is_open)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION_TEXT (text), FALSE);
+
+       if (text->is_open == is_open)
+               return FALSE;
+
+       text->is_open = is_open;
+
+       g_object_notify (G_OBJECT (text), "is_open");
+
+       return TRUE;
+}
+
+/* EvAnnotationAttachment */
+static void
+ev_annotation_attachment_finalize (GObject *object)
+{
+       EvAnnotationAttachment *annot = EV_ANNOTATION_ATTACHMENT (object);
+
+       if (annot->attachment) {
+               g_object_unref (annot->attachment);
+               annot->attachment = NULL;
+       }
+
+       G_OBJECT_CLASS (ev_annotation_attachment_parent_class)->finalize (object);
+}
+
+static void
+ev_annotation_attachment_init (EvAnnotationAttachment *annot)
+{
+       EV_ANNOTATION (annot)->type = EV_ANNOTATION_TYPE_ATTACHMENT;
+}
+
+static void
+ev_annotation_attachment_set_property (GObject      *object,
+                                      guint         prop_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
+{
+       EvAnnotationAttachment *annot = EV_ANNOTATION_ATTACHMENT (object);
+
+       if (prop_id < PROP_ATTACHMENT_ATTACHMENT) {
+               ev_annotation_markup_set_property (object, prop_id, value, pspec);
+               return;
+       }
+
+       switch (prop_id) {
+       case PROP_ATTACHMENT_ATTACHMENT:
+               ev_annotation_attachment_set_attachment (annot, g_value_get_object (value));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
+static void
+ev_annotation_attachment_get_property (GObject    *object,
+                                      guint       prop_id,
+                                      GValue     *value,
+                                      GParamSpec *pspec)
+{
+       EvAnnotationAttachment *annot = EV_ANNOTATION_ATTACHMENT (object);
+
+       if (prop_id < PROP_ATTACHMENT_ATTACHMENT) {
+               ev_annotation_markup_get_property (object, prop_id, value, pspec);
+               return;
+       }
+
+       switch (prop_id) {
+       case PROP_ATTACHMENT_ATTACHMENT:
+               g_value_set_object (value, annot->attachment);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
+static void
+ev_annotation_attachment_class_init (EvAnnotationAttachmentClass *klass)
+{
+       GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
+
+       ev_annotation_markup_class_install_properties (g_object_class);
+
+       g_object_class->set_property = ev_annotation_attachment_set_property;
+       g_object_class->get_property = ev_annotation_attachment_get_property;
+       g_object_class->finalize = ev_annotation_attachment_finalize;
+
+       g_object_class_install_property (g_object_class,
+                                        PROP_ATTACHMENT_ATTACHMENT,
+                                        g_param_spec_object ("attachment",
+                                                             "Attachment",
+                                                             "The attachment of the annotation",
+                                                             EV_TYPE_ATTACHMENT,
+                                                             G_PARAM_CONSTRUCT |
+                                                             G_PARAM_READWRITE));
 }
 
 static void
-ev_annotation_text_markup_iface_init (EvAnnotationMarkupIface *iface)
+ev_annotation_attachment_markup_iface_init (EvAnnotationMarkupInterface *iface)
+{
+}
+
+EvAnnotation *
+ev_annotation_attachment_new (EvPage       *page,
+                             EvAttachment *attachment)
 {
+       g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
+
+       return EV_ANNOTATION (g_object_new (EV_TYPE_ANNOTATION_ATTACHMENT,
+                                           "page", page,
+                                           "attachment", attachment,
+                                           NULL));
 }
 
+EvAttachment *
+ev_annotation_attachment_get_attachment (EvAnnotationAttachment *annot)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION_ATTACHMENT (annot), NULL);
+
+       return annot->attachment;
+}
+
+gboolean
+ev_annotation_attachment_set_attachment (EvAnnotationAttachment *annot,
+                                        EvAttachment           *attachment)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION_ATTACHMENT (annot), FALSE);
+
+       if (annot->attachment == attachment)
+               return FALSE;
+
+       if (annot->attachment)
+               g_object_unref (annot->attachment);
+       annot->attachment = attachment ? g_object_ref (attachment) : NULL;
+
+       g_object_notify (G_OBJECT (annot), "attachment");
+
+       return TRUE;
+}