]> www.fi.muni.cz Git - evince.git/commitdiff
Merge evince-forms branch.
authorCarlos Garcia Campos <carlosgc@gnome.org>
Sun, 8 Jul 2007 20:09:36 +0000 (20:09 +0000)
committerCarlos Garcia Campos <carlosgc@src.gnome.org>
Sun, 8 Jul 2007 20:09:36 +0000 (20:09 +0000)
2007-07-08  Carlos Garcia Campos  <carlosgc@gnome.org>
* configure.ac:
* backend/pdf/ev-poppler.cc: (pdf_document_get_crop_box),
(ev_form_field_from_poppler_field),
(pdf_document_forms_get_form_fields),
(pdf_document_forms_form_field_text_get_text),
(pdf_document_forms_form_field_text_set_text),
(pdf_document_forms_form_field_button_set_state),
(pdf_document_forms_form_field_button_get_state),
(pdf_document_forms_form_field_choice_get_item),
(pdf_document_forms_form_field_choice_get_n_items),
(pdf_document_forms_form_field_choice_is_item_selected),
(pdf_document_forms_form_field_choice_select_item),
(pdf_document_forms_form_field_choice_toggle_item),
(pdf_document_forms_form_field_choice_unselect_all),
(pdf_document_forms_form_field_choice_set_text),
(pdf_document_forms_form_field_choice_get_text),
(pdf_document_document_forms_iface_init):
* libdocument/Makefile.am:
* libdocument/ev-form-field.[ch]:
* libdocument/ev-document-forms.[ch]:
* shell/ev-pixbuf-cache.[ch]: (dispose_cache_job_info),
(move_one_job), (copy_job_to_job_info), (add_job_if_needed),
(add_job), (ev_pixbuf_cache_reload_page),
(ev_pixbuf_cache_get_form_field_mapping):
* shell/ev-jobs.[ch]: (ev_job_render_new), (ev_job_render_run):
* shell/ev-view-private.h:
* shell/ev-view.[ch]: (ev_view_set_scroll_adjustments),
(ev_view_handle_cursor_over_xy),
(ev_view_get_form_field_at_location),
(ev_view_forms_remove_widgets), (ev_view_form_field_destroy),
(ev_view_form_field_button_create_widget),
(ev_view_form_field_text_save), (ev_view_form_field_text_changed),
(ev_view_form_field_text_create_widget),
(ev_view_form_field_choice_save),
(ev_view_form_field_choice_changed),
(ev_view_form_field_choice_create_widget),
(ev_view_handle_form_field), (ev_view_size_allocate),
(ev_view_realize), (draw_end_presentation_page),
(ev_view_button_press_event), (ev_view_remove_all),
(ev_view_motion_notify_event), (ev_view_key_press_event),
(ev_view_enter_notify_event), (highlight_find_results),
(draw_loading_text), (draw_one_page), (ev_view_destroy),
(ev_view_class_init), (page_changed_cb),
(on_adjustment_value_changed), (ev_view_set_presentation),
(merge_selection_region), (ev_view_set_cursor),
(ev_view_reset_presentation_state):
Merge evince-forms branch.

svn path=/trunk/; revision=2560

17 files changed:
ChangeLog
backend/pdf/ev-poppler.cc
configure.ac
libdocument/Makefile.am
libdocument/ev-document-forms.c [new file with mode: 0644]
libdocument/ev-document-forms.h [new file with mode: 0644]
libdocument/ev-document.c
libdocument/ev-document.h
libdocument/ev-form-field.c [new file with mode: 0644]
libdocument/ev-form-field.h [new file with mode: 0644]
shell/ev-jobs.c
shell/ev-jobs.h
shell/ev-pixbuf-cache.c
shell/ev-pixbuf-cache.h
shell/ev-view-private.h
shell/ev-view.c
shell/ev-view.h

index 7fd60bd7caa0a58223bc25191e050c267e6c98e6..9fc7297ba44e03420eddf4bfe1a2b83157a2dc16 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,54 @@
+2007-07-08  Carlos Garcia Campos  <carlosgc@gnome.org>
+
+       * configure.ac:
+       * backend/pdf/ev-poppler.cc: (pdf_document_get_crop_box),
+       (ev_form_field_from_poppler_field),
+       (pdf_document_forms_get_form_fields),
+       (pdf_document_forms_form_field_text_get_text),
+       (pdf_document_forms_form_field_text_set_text),
+       (pdf_document_forms_form_field_button_set_state),
+       (pdf_document_forms_form_field_button_get_state),
+       (pdf_document_forms_form_field_choice_get_item),
+       (pdf_document_forms_form_field_choice_get_n_items),
+       (pdf_document_forms_form_field_choice_is_item_selected),
+       (pdf_document_forms_form_field_choice_select_item),
+       (pdf_document_forms_form_field_choice_toggle_item),
+       (pdf_document_forms_form_field_choice_unselect_all),
+       (pdf_document_forms_form_field_choice_set_text),
+       (pdf_document_forms_form_field_choice_get_text),
+       (pdf_document_document_forms_iface_init):
+       * libdocument/Makefile.am:
+       * libdocument/ev-form-field.[ch]:
+       * libdocument/ev-document-forms.[ch]:
+       * shell/ev-pixbuf-cache.[ch]: (dispose_cache_job_info),
+       (move_one_job), (copy_job_to_job_info), (add_job_if_needed),
+       (add_job), (ev_pixbuf_cache_reload_page),
+       (ev_pixbuf_cache_get_form_field_mapping):
+       * shell/ev-jobs.[ch]: (ev_job_render_new), (ev_job_render_run):
+       * shell/ev-view-private.h:
+       * shell/ev-view.[ch]: (ev_view_set_scroll_adjustments),
+       (ev_view_handle_cursor_over_xy),
+       (ev_view_get_form_field_at_location),
+       (ev_view_forms_remove_widgets), (ev_view_form_field_destroy),
+       (ev_view_form_field_button_create_widget),
+       (ev_view_form_field_text_save), (ev_view_form_field_text_changed),
+       (ev_view_form_field_text_create_widget),
+       (ev_view_form_field_choice_save),
+       (ev_view_form_field_choice_changed),
+       (ev_view_form_field_choice_create_widget),
+       (ev_view_handle_form_field), (ev_view_size_allocate),
+       (ev_view_realize), (draw_end_presentation_page),
+       (ev_view_button_press_event), (ev_view_remove_all),
+       (ev_view_motion_notify_event), (ev_view_key_press_event),
+       (ev_view_enter_notify_event), (highlight_find_results),
+       (draw_loading_text), (draw_one_page), (ev_view_destroy),
+       (ev_view_class_init), (page_changed_cb),
+       (on_adjustment_value_changed), (ev_view_set_presentation),
+       (merge_selection_region), (ev_view_set_cursor),
+       (ev_view_reset_presentation_state):
+       
+       Merge evince-forms branch.
+       
 2007-07-03  Jaap Haitsma  <jaap@haitsma.org>
 
        * cut-n-paste/toolbar-editor/update-toolbareditor-from-libegg: removed
@@ -16,7 +67,7 @@
        Adds a nice icon to page action during toolbar editing.
        See bug #452872.
 
-2007-07-02  Nickolay V. Shmyrev  <nshmyrev@yandex.ru
+2007-07-02  Nickolay V. Shmyrev  <nshmyrev@yandex.ru>
 
        * data/evince-toolbar.xml:
        * shell/ev-window.c:
index 5cdeddecbf6ad4f960d731420b97b53c3f54603b..3b3fe2be7f0cf8af2ab524a1c06343468b447795 100644 (file)
 
 #include "config.h"
 
+#ifdef HAVE_POPPLER_FORM_FIELD_BUTTON_GET_BUTTON_TYPE
+#define HAVE_FORMS
+#endif
+
 #include <math.h>
 #include <string.h>
 #include <gtk/gtk.h>
@@ -40,6 +44,7 @@
 #include "ev-document-security.h"
 #include "ev-document-thumbnails.h"
 #include "ev-document-transition.h"
+#include "ev-document-forms.h"
 #include "ev-selection.h"
 #include "ev-attachment.h"
 #include "ev-image.h"
@@ -86,6 +91,7 @@ static void pdf_document_security_iface_init            (EvDocumentSecurityIface
 static void pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
 static void pdf_document_document_links_iface_init      (EvDocumentLinksIface      *iface);
 static void pdf_document_document_images_iface_init     (EvDocumentImagesIface     *iface);
+static void pdf_document_document_forms_iface_init      (EvDocumentFormsIface      *iface);
 static void pdf_document_document_fonts_iface_init      (EvDocumentFontsIface      *iface);
 static void pdf_document_find_iface_init                (EvDocumentFindIface       *iface);
 static void pdf_document_file_exporter_iface_init       (EvFileExporterIface       *iface);
@@ -104,7 +110,6 @@ static EvLink     *ev_link_from_action      (PdfDocument       *pdf_document,
 static void        pdf_document_search_free (PdfDocumentSearch *search);
 static void        pdf_print_context_free   (PdfPrintContext   *ctx);
 
-
 G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT,
                          {
                                 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
@@ -117,6 +122,10 @@ G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT,
                                                        pdf_document_document_links_iface_init);
                                 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_IMAGES,
                                                        pdf_document_document_images_iface_init);
+#ifdef HAVE_FORMS
+                                G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FORMS,
+                                                       pdf_document_document_forms_iface_init);
+#endif /* HAVE_FORMS */
                                 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FONTS,
                                                        pdf_document_document_fonts_iface_init);
                                 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND,
@@ -1775,3 +1784,392 @@ pdf_document_new (void)
 {
        return PDF_DOCUMENT (g_object_new (PDF_TYPE_DOCUMENT, NULL));
 }
+
+/* Forms */
+static void
+pdf_document_get_crop_box (EvDocument  *document, 
+                          int          page, 
+                          EvRectangle *rect)
+{
+       PdfDocument *pdf_document;
+       PopplerPage *poppler_page;
+       PopplerRectangle poppler_rect;
+
+       pdf_document = PDF_DOCUMENT (document);
+       poppler_page = poppler_document_get_page (pdf_document->document, page);
+       poppler_page_get_crop_box (poppler_page, &poppler_rect);
+       rect->x1 = poppler_rect.x1;
+       rect->x2 = poppler_rect.x2;
+       rect->y1 = poppler_rect.y1;
+       rect->y2 = poppler_rect.y2;
+}
+
+#ifdef HAVE_FORMS
+static EvFormField *
+ev_form_field_from_poppler_field (PopplerFormField *poppler_field)
+{
+       EvFormField *ev_field = NULL;
+       gint         id;
+       gdouble      font_size;
+       gboolean     is_read_only;
+
+       id = poppler_form_field_get_id (poppler_field);
+       font_size = poppler_form_field_get_font_size (poppler_field);
+       is_read_only = poppler_form_field_is_read_only (poppler_field);
+
+       switch (poppler_form_field_get_field_type (poppler_field)) {
+               case POPPLER_FORM_FIELD_TEXT: {
+                       EvFormFieldText    *field_text;
+                       EvFormFieldTextType ev_text_type = EV_FORM_FIELD_TEXT_NORMAL;
+
+                       switch (poppler_form_field_text_get_text_type (poppler_field)) {
+                               case POPPLER_FORM_TEXT_NORMAL:
+                                       ev_text_type = EV_FORM_FIELD_TEXT_NORMAL;
+                                       break;
+                               case POPPLER_FORM_TEXT_MULTILINE:
+                                       ev_text_type = EV_FORM_FIELD_TEXT_MULTILINE;
+                                       break;
+                               case POPPLER_FORM_TEXT_PASSWORD:
+                                       ev_text_type = EV_FORM_FIELD_TEXT_PASSWORD;
+                                       break;
+                               case POPPLER_FORM_TEXT_FILE_SELECT:
+                                       ev_text_type = EV_FORM_FIELD_TEXT_FILE_SELECT;
+                                       break;
+                       }
+                       
+                       ev_field = ev_form_field_text_new (id, ev_text_type);
+                       field_text = EV_FORM_FIELD_TEXT (ev_field);
+
+                       field_text->do_spell_check = poppler_form_field_text_do_spell_check (poppler_field);
+                       field_text->do_scroll = poppler_form_field_text_do_scroll (poppler_field);
+                       field_text->is_rich_text = poppler_form_field_text_is_rich_text (poppler_field);
+
+                       field_text->text = poppler_form_field_text_get_text (poppler_field);
+
+               }
+                       break;
+               case POPPLER_FORM_FIELD_BUTTON: {
+                       EvFormFieldButton    *field_button;
+                       EvFormFieldButtonType ev_button_type = EV_FORM_FIELD_BUTTON_PUSH;
+
+                       switch (poppler_form_field_button_get_button_type (poppler_field)) {
+                               case POPPLER_FORM_BUTTON_PUSH:
+                                       ev_button_type = EV_FORM_FIELD_BUTTON_PUSH;
+                                       break;
+                               case POPPLER_FORM_BUTTON_CHECK:
+                                       ev_button_type = EV_FORM_FIELD_BUTTON_CHECK;
+                                       break;
+                               case POPPLER_FORM_BUTTON_RADIO:
+                                       ev_button_type = EV_FORM_FIELD_BUTTON_RADIO;
+                                       break;
+                       }
+
+                       ev_field = ev_form_field_button_new (id, ev_button_type);
+                       field_button = EV_FORM_FIELD_BUTTON (ev_field);
+                       
+                       field_button->state = poppler_form_field_button_get_state (poppler_field);
+               }
+                       break;
+               case POPPLER_FORM_FIELD_CHOICE: {
+                       EvFormFieldChoice    *field_choice;
+                       EvFormFieldChoiceType ev_choice_type = EV_FORM_FIELD_CHOICE_COMBO;
+
+                       switch (poppler_form_field_choice_get_choice_type (poppler_field)) {
+                               case POPPLER_FORM_CHOICE_COMBO:
+                                       ev_choice_type = EV_FORM_FIELD_CHOICE_COMBO;
+                                       break;
+                               case EV_FORM_FIELD_CHOICE_LIST:
+                                       ev_choice_type = EV_FORM_FIELD_CHOICE_LIST;
+                                       break;
+                       }
+
+                       ev_field = ev_form_field_choice_new (id, ev_choice_type);
+                       field_choice = EV_FORM_FIELD_CHOICE (ev_field);
+
+                       field_choice->is_editable = poppler_form_field_choice_is_editable (poppler_field);
+                       field_choice->multi_select = poppler_form_field_choice_can_select_multiple (poppler_field);
+                       field_choice->do_spell_check = poppler_form_field_choice_do_spell_check (poppler_field);
+                       field_choice->commit_on_sel_change = poppler_form_field_choice_commit_on_change (poppler_field);
+
+                       /* TODO: we need poppler_form_field_choice_get_selected_items in poppler 
+                       field_choice->selected_items = poppler_form_field_choice_get_selected_items (poppler_field);*/
+                       if (field_choice->is_editable)
+                               field_choice->text = poppler_form_field_choice_get_text (poppler_field);
+               }
+                       break;
+               case POPPLER_FORM_FIELD_SIGNATURE:
+                       /* TODO */
+                       ev_field = ev_form_field_signature_new (id);
+                       break;
+               case POPPLER_FORM_FIELD_UNKNOWN:
+                       break;
+       }
+
+       ev_field->font_size = font_size;
+       ev_field->is_read_only = is_read_only;
+
+       return ev_field;
+}
+
+static GList *
+pdf_document_forms_get_form_fields (EvDocumentForms *document, 
+                                   gint             page)
+{
+       PdfDocument *pdf_document;
+       PopplerPage *poppler_page;
+       GList *retval = NULL;
+       GList *fields;
+       GList *list;
+       double height;
+       
+
+       pdf_document = PDF_DOCUMENT (document);
+       poppler_page = poppler_document_get_page (pdf_document->document, page);
+       fields = poppler_page_get_form_field_mapping (poppler_page);
+       poppler_page_get_size (poppler_page, NULL, &height);
+
+       for (list = fields; list; list = list->next) {
+               PopplerFormFieldMapping *mapping;
+               EvFormFieldMapping *field_mapping;
+               
+               mapping = (PopplerFormFieldMapping *)list->data;
+
+               field_mapping = g_new0 (EvFormFieldMapping, 1);
+               field_mapping->x1 = mapping->area.x1;
+               field_mapping->x2 = mapping->area.x2;
+               field_mapping->y1 = height - mapping->area.y2;
+               field_mapping->y2 = height - mapping->area.y1;
+               field_mapping->field = ev_form_field_from_poppler_field (mapping->field);
+               field_mapping->field->page = page;
+               
+               retval = g_list_prepend (retval, field_mapping);
+       }
+       poppler_page_free_form_field_mapping (fields);
+       g_object_unref (poppler_page);
+
+       return g_list_reverse (retval);
+}
+
+static gchar *
+pdf_document_forms_form_field_text_get_text (EvDocumentForms *document,
+                                            EvFormField     *field)
+       
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       PopplerFormField *poppler_field;
+       gchar *text;
+
+       poppler_field = poppler_document_get_form_field (pdf_document->document, field->id);
+       if (!poppler_field)
+               return NULL;
+       
+       text = poppler_form_field_text_get_text (poppler_field);
+       g_object_unref (poppler_field);
+
+       return text;
+}
+
+static void
+pdf_document_forms_form_field_text_set_text (EvDocumentForms *document, 
+                                            EvFormField     *field,
+                                            const gchar     *text)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       PopplerFormField *poppler_field;
+
+       poppler_field = poppler_document_get_form_field (pdf_document->document, field->id);
+       if (!poppler_field)
+               return;
+       poppler_form_field_text_set_text (poppler_field, text);
+       g_object_unref (poppler_field);
+}
+
+static void
+pdf_document_forms_form_field_button_set_state (EvDocumentForms *document, 
+                                               EvFormField     *field,
+                                               gboolean         state)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       PopplerFormField *poppler_field;
+
+       poppler_field = poppler_document_get_form_field (pdf_document->document, field->id);
+       if (!poppler_field)
+               return;
+       
+       poppler_form_field_button_set_state (poppler_field, state);
+       g_object_unref (poppler_field);
+}
+
+static gboolean
+pdf_document_forms_form_field_button_get_state (EvDocumentForms *document, 
+                                               EvFormField     *field)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       PopplerFormField *poppler_field;
+       gboolean state;
+
+       poppler_field = poppler_document_get_form_field (pdf_document->document, field->id);
+       if (!poppler_field)
+               return FALSE;
+
+       state = poppler_form_field_button_get_state (poppler_field);
+       g_object_unref (poppler_field);
+
+       return state;
+}
+
+static gchar *
+pdf_document_forms_form_field_choice_get_item (EvDocumentForms *document, 
+                                              EvFormField     *field,
+                                              gint             index)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       PopplerFormField *poppler_field;
+       gchar *text;
+
+       poppler_field = poppler_document_get_form_field (pdf_document->document, field->id);
+       if (!poppler_field)
+               return NULL;
+
+       text = poppler_form_field_choice_get_item (poppler_field, index);
+       g_object_unref (poppler_field);
+
+       return text;
+}
+
+static int
+pdf_document_forms_form_field_choice_get_n_items (EvDocumentForms *document, 
+                                                 EvFormField     *field)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       PopplerFormField *poppler_field;
+       gint n_items;
+
+       poppler_field = poppler_document_get_form_field (pdf_document->document, field->id);
+       if (!poppler_field)
+               return -1;
+       
+       n_items = poppler_form_field_choice_get_n_items (poppler_field);
+       g_object_unref (poppler_field);
+
+       return n_items;
+}
+
+static gboolean
+pdf_document_forms_form_field_choice_is_item_selected (EvDocumentForms *document, 
+                                                      EvFormField     *field,
+                                                      gint             index)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       PopplerFormField *poppler_field;
+       gboolean selected;
+
+       poppler_field = poppler_document_get_form_field (pdf_document->document, field->id);
+       if (!poppler_field)
+               return FALSE;
+
+       selected = poppler_form_field_choice_is_item_selected (poppler_field, index);
+       g_object_unref (poppler_field);
+
+       return selected;
+}
+
+static void
+pdf_document_forms_form_field_choice_select_item (EvDocumentForms *document, 
+                                                 EvFormField     *field,
+                                                 gint             index)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       PopplerFormField *poppler_field;
+
+       poppler_field = poppler_document_get_form_field (pdf_document->document, field->id);
+       if (!poppler_field)
+               return;
+
+       poppler_form_field_choice_select_item (poppler_field, index);
+       g_object_unref (poppler_field);
+}
+
+static void
+pdf_document_forms_form_field_choice_toggle_item (EvDocumentForms *document, 
+                                                 EvFormField     *field,
+                                                 gint             index)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       PopplerFormField *poppler_field;
+
+       poppler_field = poppler_document_get_form_field (pdf_document->document, field->id);
+       if (!poppler_field)
+               return;
+
+       poppler_form_field_choice_toggle_item (poppler_field, index);
+       g_object_unref (poppler_field);
+}
+
+static void
+pdf_document_forms_form_field_choice_unselect_all (EvDocumentForms *document, 
+                                                  EvFormField     *field)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       PopplerFormField *poppler_field;
+
+       poppler_field = poppler_document_get_form_field (pdf_document->document, field->id);
+       if (!poppler_field)
+               return;
+       
+       poppler_form_field_choice_unselect_all (poppler_field);
+       g_object_unref (poppler_field);
+}
+
+static void
+pdf_document_forms_form_field_choice_set_text (EvDocumentForms *document,
+                                              EvFormField     *field,
+                                              const gchar     *text)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       PopplerFormField *poppler_field;
+
+       poppler_field = poppler_document_get_form_field (pdf_document->document, field->id);
+       if (!poppler_field)
+               return;
+       
+       poppler_form_field_choice_set_text (poppler_field, text);
+       g_object_unref (poppler_field);
+}
+
+static gchar *
+pdf_document_forms_form_field_choice_get_text (EvDocumentForms *document,
+                                              EvFormField     *field)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       PopplerFormField *poppler_field;
+       gchar *text;
+
+       poppler_field = poppler_document_get_form_field (pdf_document->document, field->id);
+       if (!poppler_field)
+               return NULL;
+
+       text = poppler_form_field_choice_get_text (poppler_field);
+       g_object_unref (poppler_field);
+
+       return text;
+}
+
+static void
+pdf_document_document_forms_iface_init (EvDocumentFormsIface *iface)
+{
+       iface->get_form_fields = pdf_document_forms_get_form_fields;
+       iface->form_field_text_get_text = pdf_document_forms_form_field_text_get_text;
+       iface->form_field_text_set_text = pdf_document_forms_form_field_text_set_text;
+       iface->form_field_button_set_state = pdf_document_forms_form_field_button_set_state;
+       iface->form_field_button_get_state = pdf_document_forms_form_field_button_get_state;
+       iface->form_field_choice_get_item = pdf_document_forms_form_field_choice_get_item;
+       iface->form_field_choice_get_n_items = pdf_document_forms_form_field_choice_get_n_items;
+       iface->form_field_choice_is_item_selected = pdf_document_forms_form_field_choice_is_item_selected;
+       iface->form_field_choice_select_item = pdf_document_forms_form_field_choice_select_item;
+       iface->form_field_choice_toggle_item = pdf_document_forms_form_field_choice_toggle_item;
+       iface->form_field_choice_unselect_all = pdf_document_forms_form_field_choice_unselect_all;
+       iface->form_field_choice_set_text = pdf_document_forms_form_field_choice_set_text;
+       iface->form_field_choice_get_text = pdf_document_forms_form_field_choice_get_text;
+}
+#endif /* HAVE_FORMS */
index 0846107b61216113781164b799f94702d16d5d65..0a0e97a90e871a131c470e874f3d21a148076a10 100644 (file)
@@ -247,6 +247,9 @@ if test "x$enable_pdf" = "xyes"; then
            evince_save_LIBS=$LIBS
            LIBS="$LIBS $FRONTEND_LIBS"
            AC_CHECK_FUNCS(poppler_page_render)
+           dnl we need latest poppler cvs head, 
+           dnl this function was the last to be added
+           AC_CHECK_FUNCS(poppler_form_field_button_get_button_type)
            LIBS=$evince_save_LIBS
 
            PKG_CHECK_MODULES(CAIRO_PDF, cairo-pdf, enable_cairo_pdf=yes, enable_cairo_pdf=no)
index 73340ff1f123c818c69ab91707b8b661493d5477..f96d0197aeb19976b628b181c83efa92ebd9fcc9 100644 (file)
@@ -48,6 +48,10 @@ libevbackend_la_SOURCES=                     \
        ev-document-info.h                      \
        ev-document-transition.h                \
        ev-document-transition.c                \
+       ev-document-forms.h                     \
+       ev-document-forms.c                     \
+       ev-form-field.h                         \
+       ev-form-field.c                         \
        ev-file-exporter.c                      \
        ev-file-exporter.h                      \
        ev-file-helpers.c                       \
diff --git a/libdocument/ev-document-forms.c b/libdocument/ev-document-forms.c
new file mode 100644 (file)
index 0000000..cdefb46
--- /dev/null
@@ -0,0 +1,165 @@
+/* ev-document-forms.c
+ *  this file is part of evince, a gnome document viewer
+ * 
+ * Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+ */
+
+#include "ev-document-forms.h"
+
+GType
+ev_document_forms_get_type (void)
+{
+       static GType type = 0;
+
+       if (G_UNLIKELY (type == 0)) {
+               const GTypeInfo our_info = {
+                       sizeof (EvDocumentFormsIface),
+                       NULL,
+                       NULL,
+               };
+
+               type = g_type_register_static (G_TYPE_INTERFACE,
+                                              "EvDocumentForms",
+                                              &our_info, (GTypeFlags)0);
+       }
+
+       return type;
+}
+
+GList *
+ev_document_forms_get_form_fields (EvDocumentForms *document_forms,
+                                  gint             page)
+{
+       EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms);
+
+       return iface->get_form_fields (document_forms, page);
+}
+
+gchar *
+ev_document_forms_form_field_text_get_text (EvDocumentForms *document_forms, 
+                                           EvFormField     *field)
+{
+       EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms);
+
+       return iface->form_field_text_get_text (document_forms, field);
+}
+
+void
+ev_document_forms_form_field_text_set_text (EvDocumentForms *document_forms, 
+                                           EvFormField     *field, 
+                                           const gchar     *text)
+{
+       EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms);
+
+       iface->form_field_text_set_text (document_forms, field, text);
+}
+
+gboolean
+ev_document_forms_form_field_button_get_state (EvDocumentForms   *document_forms,
+                                              EvFormField       *field)
+{
+       EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms);
+
+       return iface->form_field_button_get_state (document_forms, field);
+}
+
+void
+ev_document_forms_form_field_button_set_state (EvDocumentForms   *document_forms, 
+                                              EvFormField       *field, 
+                                              gboolean           state)
+{
+       EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms);
+
+       iface->form_field_button_set_state (document_forms, field, state);
+}
+
+gchar *
+ev_document_forms_form_field_choice_get_item (EvDocumentForms   *document_forms, 
+                                             EvFormField       *field, 
+                                             gint               index)
+{
+       EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms);
+
+       return iface->form_field_choice_get_item (document_forms, field, index);
+}
+
+gint
+ev_document_forms_form_field_choice_get_n_items (EvDocumentForms   *document_forms, 
+                                                EvFormField       *field)
+{
+       EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms);
+
+       return iface->form_field_choice_get_n_items (document_forms, field);
+}
+
+gboolean
+ev_document_forms_form_field_choice_is_item_selected (EvDocumentForms   *document_forms, 
+                                                     EvFormField       *field, 
+                                                     gint               index)
+{
+       EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms);
+
+       return iface->form_field_choice_is_item_selected (document_forms, field, index);
+}
+
+void
+ev_document_forms_form_field_choice_select_item (EvDocumentForms   *document_forms, 
+                                                EvFormField       *field, 
+                                                gint               index)
+{
+       EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms);
+
+       iface->form_field_choice_select_item (document_forms, field, index);
+}
+
+void
+ev_document_forms_form_field_choice_toggle_item (EvDocumentForms   *document_forms, 
+                                                EvFormField       *field, 
+                                                gint               index)
+{
+       EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms);
+
+       iface->form_field_choice_toggle_item (document_forms, field, index);
+}
+
+void
+ev_document_forms_form_field_choice_unselect_all (EvDocumentForms   *document_forms, 
+                                                 EvFormField       *field)
+{
+       EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms);
+
+       iface->form_field_choice_unselect_all (document_forms, field);
+}
+
+void
+ev_document_forms_form_field_choice_set_text (EvDocumentForms   *document_forms,
+                                             EvFormField       *field,
+                                             const gchar       *text)
+{
+       EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms);
+
+       iface->form_field_choice_set_text (document_forms, field, text);
+}
+
+gchar *
+ev_document_forms_form_field_choice_get_text (EvDocumentForms   *document_forms,
+                                             EvFormField       *field)
+{
+       EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms);
+
+       return iface->form_field_choice_get_text (document_forms, field);
+}
diff --git a/libdocument/ev-document-forms.h b/libdocument/ev-document-forms.h
new file mode 100644 (file)
index 0000000..a1b192d
--- /dev/null
@@ -0,0 +1,121 @@
+/* ev-document-forms.h
+ *  this file is part of evince, a gnome document viewer
+ * 
+ * Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+ */
+
+#ifndef EV_DOCUMENT_FORMS_H
+#define EV_DOCUMENT_FORMS_H
+
+#include <glib-object.h>
+
+#include "ev-document.h"
+#include "ev-form-field.h"
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_DOCUMENT_FORMS           (ev_document_forms_get_type ())
+#define EV_DOCUMENT_FORMS(o)             (G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_DOCUMENT_FORMS, EvDocumentForms))
+#define EV_DOCUMENT_FORMS_IFACE(k)       (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_DOCUMENT_FORMS, EvDocumentFormsIface))
+#define EV_IS_DOCUMENT_FORMS(o)                  (G_TYPE_CHECK_INSTANCE_TYPE ((o), EV_TYPE_DOCUMENT_FORMS))
+#define EV_IS_DOCUMENT_FORMS_IFACE(k)     (G_TYPE_CHECK_CLASS_TYPE ((k), EV_TYPE_DOCUMENT_FORMS))
+#define EV_DOCUMENT_FORMS_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), EV_TYPE_DOCUMENT_FORMS, EvDocumentFormsIface))
+
+typedef struct _EvDocumentForms      EvDocumentForms;
+typedef struct _EvDocumentFormsIface EvDocumentFormsIface;
+
+struct _EvDocumentFormsIface
+{
+       GTypeInterface base_iface;
+
+       /* Methods  */
+       GList   *(* get_form_fields)                    (EvDocumentForms   *document_forms,
+                                                        gint               page);
+       gchar   *(* form_field_text_get_text)           (EvDocumentForms   *document_forms,
+                                                        EvFormField       *field);
+       void     (* form_field_text_set_text)           (EvDocumentForms   *document_forms,
+                                                        EvFormField       *field,
+                                                        const gchar       *text);
+       gboolean (* form_field_button_get_state)        (EvDocumentForms   *document_forms,
+                                                        EvFormField       *field);
+       void     (* form_field_button_set_state)        (EvDocumentForms   *document_forms,
+                                                        EvFormField       *field,
+                                                        gboolean           state);
+       gchar   *(* form_field_choice_get_item)         (EvDocumentForms   *document_forms,
+                                                        EvFormField       *field,
+                                                        gint               index);
+       gint     (* form_field_choice_get_n_items)      (EvDocumentForms   *document_forms,
+                                                        EvFormField       *field);
+       gboolean (* form_field_choice_is_item_selected) (EvDocumentForms   *document_forms,
+                                                        EvFormField       *field,
+                                                        gint               index);
+       void     (* form_field_choice_select_item)      (EvDocumentForms   *document_forms,
+                                                        EvFormField       *field,
+                                                        gint               index);
+       void     (* form_field_choice_toggle_item)      (EvDocumentForms   *document_forms,
+                                                        EvFormField       *field,
+                                                        gint               index);
+       void     (* form_field_choice_unselect_all)     (EvDocumentForms   *document_forms,
+                                                        EvFormField       *field);
+       void     (* form_field_choice_set_text)         (EvDocumentForms   *document_forms,
+                                                        EvFormField       *field,
+                                                        const gchar       *text);
+       gchar   *(* form_field_choice_get_text)         (EvDocumentForms   *document_forms,
+                                                        EvFormField       *field);
+};
+
+GType    ev_document_forms_get_type                            (void) G_GNUC_CONST;
+GList   *ev_document_forms_get_form_fields                     (EvDocumentForms   *document_forms,
+                                                               gint               page);
+
+gchar  *ev_document_forms_form_field_text_get_text            (EvDocumentForms   *document_forms, 
+                                                               EvFormField       *field);
+void    ev_document_forms_form_field_text_set_text            (EvDocumentForms   *document_forms, 
+                                                               EvFormField       *field, 
+                                                               const gchar       *text);
+
+gboolean ev_document_forms_form_field_button_get_state         (EvDocumentForms   *document_forms,
+                                                               EvFormField       *field);
+void    ev_document_forms_form_field_button_set_state         (EvDocumentForms   *document_forms, 
+                                                               EvFormField       *field, 
+                                                               gboolean           state);
+
+gchar    *ev_document_forms_form_field_choice_get_item         (EvDocumentForms   *document_forms, 
+                                                               EvFormField       *field, 
+                                                               gint               index);
+gint     ev_document_forms_form_field_choice_get_n_items      (EvDocumentForms   *document_forms, 
+                                                               EvFormField       *field);
+gboolean  ev_document_forms_form_field_choice_is_item_selected (EvDocumentForms   *document_forms, 
+                                                               EvFormField       *field, 
+                                                               gint               index);
+void     ev_document_forms_form_field_choice_select_item      (EvDocumentForms   *document_forms, 
+                                                               EvFormField       *field, 
+                                                               gint               index);
+void     ev_document_forms_form_field_choice_toggle_item      (EvDocumentForms   *document_forms, 
+                                                               EvFormField       *field, 
+                                                               gint               index);
+void     ev_document_forms_form_field_choice_unselect_all     (EvDocumentForms   *document_forms, 
+                                                               EvFormField       *field);
+void     ev_document_forms_form_field_choice_set_text         (EvDocumentForms   *document_forms,
+                                                               EvFormField       *field,
+                                                               const gchar       *text);
+gchar    *ev_document_forms_form_field_choice_get_text         (EvDocumentForms   *document_forms,
+                                                               EvFormField       *field);
+
+G_END_DECLS
+
+#endif /* EV_DOCUMENT_FORMS_H */
index f22f55f3ac1c9c94a957c51cacc0144fdbad70e3..e0ce69fd644e9df4d8c8aa5b0da1601034f47b82 100644 (file)
@@ -283,3 +283,6 @@ ev_rect_cmp (EvRectangle *a,
                  (ABS (a->x2 - b->x2) < EPSILON) &&
                  (ABS (a->y2 - b->y2) < EPSILON));
 }
+
+
+
index ce887fc6e0c3a35d360b741efa31b74ac0818914..e83295f0c0d256f4ea67609d48c784103615e1fc 100644 (file)
@@ -134,8 +134,6 @@ cairo_surface_t *ev_document_render           (EvDocument      *document,
 
 gint            ev_rect_cmp                   (EvRectangle    *a,
                                                EvRectangle    *b);
-
-
 G_END_DECLS
 
 #endif /* EV_DOCUMENT_H */
diff --git a/libdocument/ev-form-field.c b/libdocument/ev-form-field.c
new file mode 100644 (file)
index 0000000..b3cc791
--- /dev/null
@@ -0,0 +1,269 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
+/* this file is part of evince, a gnome document viewer
+ *
+ *  Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
+ *  Copyright (C) 2006 Julien Rebetez
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+ */
+
+#include "ev-form-field.h"
+
+static void ev_form_field_init                 (EvFormField               *field);
+static void ev_form_field_class_init           (EvFormFieldClass          *klass);
+static void ev_form_field_text_init            (EvFormFieldText           *field_text);
+static void ev_form_field_text_class_init      (EvFormFieldTextClass      *klass);
+static void ev_form_field_button_init          (EvFormFieldButton         *field_button);
+static void ev_form_field_button_class_init    (EvFormFieldButtonClass    *klass);
+static void ev_form_field_choice_init          (EvFormFieldChoice         *field_choice);
+static void ev_form_field_choice_class_init    (EvFormFieldChoiceClass    *klass);
+static void ev_form_field_signature_init       (EvFormFieldSignature      *field_choice);
+static void ev_form_field_signature_class_init (EvFormFieldSignatureClass *klass);
+
+G_DEFINE_ABSTRACT_TYPE (EvFormField, ev_form_field, G_TYPE_OBJECT)
+G_DEFINE_TYPE (EvFormFieldText, ev_form_field_text, EV_TYPE_FORM_FIELD)
+G_DEFINE_TYPE (EvFormFieldButton, ev_form_field_button, EV_TYPE_FORM_FIELD)
+G_DEFINE_TYPE (EvFormFieldChoice, ev_form_field_choice, EV_TYPE_FORM_FIELD)
+G_DEFINE_TYPE (EvFormFieldSignature, ev_form_field_signature, EV_TYPE_FORM_FIELD)
+
+static void
+ev_form_field_init (EvFormField *field)
+{
+       field->page = -1;
+       field->changed = FALSE;
+       field->is_read_only = FALSE;
+}
+
+static void
+ev_form_field_class_init (EvFormFieldClass *klass)
+{
+}
+
+static void
+ev_form_field_text_finalize (GObject *object)
+{
+       EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (object);
+
+       if (field_text->text) {
+               g_free (field_text->text);
+               field_text->text = NULL;
+       }
+
+       (* G_OBJECT_CLASS (ev_form_field_text_parent_class)->finalize) (object);
+}
+
+static void
+ev_form_field_text_init (EvFormFieldText *field_text)
+{
+}
+
+static void
+ev_form_field_text_class_init (EvFormFieldTextClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->finalize = ev_form_field_text_finalize;
+}
+
+static void
+ev_form_field_button_init (EvFormFieldButton *field_button)
+{
+}
+
+static void
+ev_form_field_button_class_init (EvFormFieldButtonClass *klass)
+{
+}
+
+static void
+ev_form_field_choice_finalize (GObject *object)
+{
+       EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (object);
+
+       if (field_choice->selected_items) {
+               g_list_free (field_choice->selected_items);
+               field_choice->selected_items = NULL;
+       }
+
+       if (field_choice->text) {
+               g_free (field_choice->text);
+               field_choice->text = NULL;
+       }
+
+       (* G_OBJECT_CLASS (ev_form_field_choice_parent_class)->finalize) (object);
+}
+
+static void
+ev_form_field_choice_init (EvFormFieldChoice *field_choice)
+{
+}
+
+static void
+ev_form_field_choice_class_init (EvFormFieldChoiceClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->finalize = ev_form_field_choice_finalize;
+}
+
+static void
+ev_form_field_signature_init (EvFormFieldSignature *field_signature)
+{
+}
+
+static void
+ev_form_field_signature_class_init (EvFormFieldSignatureClass *klass)
+{
+}
+
+EvFormField *
+ev_form_field_text_new (gint                id,
+                       EvFormFieldTextType type)
+{
+       EvFormField *field;
+       
+       g_return_val_if_fail (id >= 0, NULL);
+       g_return_val_if_fail (type >= EV_FORM_FIELD_TEXT_NORMAL &&
+                             type <= EV_FORM_FIELD_TEXT_FILE_SELECT, NULL);
+
+       field = EV_FORM_FIELD (g_object_new (EV_TYPE_FORM_FIELD_TEXT, NULL));
+       field->id = id;
+       EV_FORM_FIELD_TEXT (field)->type = type;
+
+       return field;
+}
+
+EvFormField *
+ev_form_field_button_new (gint                  id,
+                         EvFormFieldButtonType type)
+{
+       EvFormField *field;
+
+       g_return_val_if_fail (id >= 0, NULL);
+       g_return_val_if_fail (type >= EV_FORM_FIELD_BUTTON_PUSH &&
+                             type <= EV_FORM_FIELD_BUTTON_RADIO, NULL);
+
+       field = EV_FORM_FIELD (g_object_new (EV_TYPE_FORM_FIELD_BUTTON, NULL));
+       field->id = id;
+       EV_FORM_FIELD_BUTTON (field)->type = type;
+
+       return field;
+}
+
+EvFormField *
+ev_form_field_choice_new (gint                  id,
+                         EvFormFieldChoiceType type)
+{
+       EvFormField *field;
+
+       g_return_val_if_fail (id >= 0, NULL);
+       g_return_val_if_fail (type >= EV_FORM_FIELD_CHOICE_COMBO &&
+                             type <= EV_FORM_FIELD_CHOICE_LIST, NULL);
+       
+       field = EV_FORM_FIELD (g_object_new (EV_TYPE_FORM_FIELD_CHOICE, NULL));
+       field->id = id;
+       EV_FORM_FIELD_CHOICE (field)->type = type;
+
+       return field;
+}
+
+EvFormField *
+ev_form_field_signature_new (gint id)
+{
+       EvFormField *field;
+
+       g_return_val_if_fail (id >= 0, NULL);
+
+       field = EV_FORM_FIELD (g_object_new (EV_TYPE_FORM_FIELD_SIGNATURE, NULL));
+       field->id = id;
+
+       return field;
+}
+
+/* EvFormFieldMapping */
+static void
+ev_form_field_mapping_free_foreach (EvFormFieldMapping *mapping)
+{
+       g_object_unref (mapping->field);
+       g_free (mapping);
+}
+
+void
+ev_form_field_mapping_free (GList *field_mapping)
+{
+       if (!field_mapping)
+               return;
+
+       g_list_foreach (field_mapping, (GFunc)ev_form_field_mapping_free_foreach, NULL);
+       g_list_free (field_mapping);
+}
+
+EvFormField *
+ev_form_field_mapping_find (GList   *field_mapping,
+                           gdouble  x,
+                           gdouble  y)
+{
+       GList *list;
+
+       for (list = field_mapping; list; list = list->next) {
+               EvFormFieldMapping *mapping = list->data;
+
+               if ((x >= mapping->x1) &&
+                   (y >= mapping->y1) &&
+                   (x <= mapping->x2) &&
+                   (y <= mapping->y2)) {
+                       return mapping->field;
+               }
+       }
+
+       return NULL;
+}
+
+void
+ev_form_field_mapping_get_area (GList       *field_mapping,
+                               EvFormField *field,
+                               EvRectangle *area)
+{
+       GList *list;
+
+       for (list = field_mapping; list; list = list->next) {
+               EvFormFieldMapping *mapping = list->data;
+
+               if (mapping->field->id == field->id) {
+                       area->x1 = mapping->x1;
+                       area->y1 = mapping->y1;
+                       area->x2 = mapping->x2;
+                       area->y2 = mapping->y2;
+
+                       break;
+               }
+       }
+}
+
+EvFormField *
+ev_form_field_mapping_find_by_id (GList *field_mapping,
+                                 gint   id)
+{
+       GList *list;
+       
+       for (list = field_mapping; list; list = list->next) {
+               EvFormFieldMapping *mapping = list->data;
+
+               if (id == mapping->field->id)
+                       return mapping->field;
+       }
+       
+       return NULL;
+}
diff --git a/libdocument/ev-form-field.h b/libdocument/ev-form-field.h
new file mode 100644 (file)
index 0000000..1405999
--- /dev/null
@@ -0,0 +1,230 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
+/* this file is part of evince, a gnome document viewer
+ *
+ *  Copyright (C) 2006 Julien Rebetez
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+ */
+
+#ifndef EV_FORM_FIELD_H
+#define EV_FORM_FIELD_H
+
+#include <glib-object.h>
+
+#include "ev-document.h"
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_FORM_FIELD                        (ev_form_field_get_type())
+#define EV_FORM_FIELD(object)                     (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_FORM_FIELD, EvFormField))
+#define EV_FORM_FIELD_CLASS(klass)                (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_FORM_FIELD, EvFormFieldClass))
+#define EV_IS_FORM_FIELD(object)                  (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_FORM_FIELD))
+#define EV_IS_FORM_FIELD_CLASS(klass)             (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_FORM_FIELD))
+#define EV_FORM_FIELD_GET_CLASS(object)           (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_FORM_FIELD, EvFormFieldClass)) 
+
+#define EV_TYPE_FORM_FIELD_TEXT                   (ev_form_field_text_get_type())
+#define EV_FORM_FIELD_TEXT(object)                (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_FORM_FIELD_TEXT, EvFormFieldText))
+#define EV_FORM_FIELD_TEXT_CLASS(klass)           (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_FORM_FIELD_TEXT, EvFormFieldTextClass))
+#define EV_IS_FORM_FIELD_TEXT(object)             (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_FORM_FIELD_TEXT))
+#define EV_IS_FORM_FIELD_TEXT_CLASS(klass)        (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_FORM_FIELD_TEXT))
+#define EV_FORM_FIELD_TEXT_GET_CLASS(object)      (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_FORM_FIELD_TEXT, EvFormFieldTextClass))
+
+#define EV_TYPE_FORM_FIELD_BUTTON                 (ev_form_field_button_get_type())
+#define EV_FORM_FIELD_BUTTON(object)              (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_FORM_FIELD_BUTTON, EvFormFieldButton))
+#define EV_FORM_FIELD_BUTTON_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_FORM_FIELD_BUTTON, EvFormFieldButtonClass))
+#define EV_IS_FORM_FIELD_BUTTON(object)           (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_FORM_FIELD_BUTTON))
+#define EV_IS_FORM_FIELD_BUTTON_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_FORM_FIELD_BUTTON))
+#define EV_FORM_FIELD_BUTTON_GET_CLASS(object)    (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_FORM_FIELD_BUTTON, EvFormFieldButtonClass))
+
+#define EV_TYPE_FORM_FIELD_CHOICE                 (ev_form_field_choice_get_type())
+#define EV_FORM_FIELD_CHOICE(object)              (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_FORM_FIELD_CHOICE, EvFormFieldChoice))
+#define EV_FORM_FIELD_CHOICE_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_FORM_FIELD_CHOICE, EvFormFieldChoiceClass))
+#define EV_IS_FORM_FIELD_CHOICE(object)           (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_FORM_FIELD_CHOICE))
+#define EV_IS_FORM_FIELD_CHOICE_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_FORM_FIELD_CHOICE))
+#define EV_FORM_FIELD_CHOICE_GET_CLASS(object)    (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_FORM_FIELD_CHOICE, EvFormFieldChoiceClass))
+
+#define EV_TYPE_FORM_FIELD_SIGNATURE              (ev_form_field_signature_get_type())
+#define EV_FORM_FIELD_SIGNATURE(object)           (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_FORM_FIELD_SIGNATURE, EvFormFieldSignature))
+#define EV_FORM_FIELD_SIGNATURE_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_FORM_FIELD_SIGNATURE, EvFormFieldSignatureClass))
+#define EV_IS_FORM_FIELD_SIGNATURE(object)        (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_FORM_FIELD_SIGNATURE))
+#define EV_IS_FORM_FIELD_SIGNATURE_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_FORM_FIELD_SIGNATURE))
+#define EV_FORM_FIELD_SIGNATURE_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_FORM_FIELD_SIGNATURE, EvFormFieldSignatureClass))
+
+typedef struct _EvFormField               EvFormField;
+typedef struct _EvFormFieldClass          EvFormFieldClass;
+
+typedef struct _EvFormFieldText           EvFormFieldText;
+typedef struct _EvFormFieldTextClass      EvFormFieldTextClass;
+
+typedef struct _EvFormFieldButton         EvFormFieldButton;
+typedef struct _EvFormFieldButtonClass    EvFormFieldButtonClass;
+
+typedef struct _EvFormFieldChoice         EvFormFieldChoice;
+typedef struct _EvFormFieldChoiceClass    EvFormFieldChoiceClass;
+
+typedef struct _EvFormFieldSignature      EvFormFieldSignature;
+typedef struct _EvFormFieldSignatureClass EvFormFieldSignatureClass;
+
+typedef enum
+{
+       EV_FORM_FIELD_TEXT_NORMAL,
+       EV_FORM_FIELD_TEXT_MULTILINE,
+       EV_FORM_FIELD_TEXT_PASSWORD,
+       EV_FORM_FIELD_TEXT_FILE_SELECT
+} EvFormFieldTextType;
+
+typedef enum
+{
+       EV_FORM_FIELD_BUTTON_PUSH,
+       EV_FORM_FIELD_BUTTON_CHECK,
+       EV_FORM_FIELD_BUTTON_RADIO
+} EvFormFieldButtonType;
+
+typedef enum
+{
+       EV_FORM_FIELD_CHOICE_COMBO,
+       EV_FORM_FIELD_CHOICE_LIST
+} EvFormFieldChoiceType;
+
+struct _EvFormField
+{
+       GObject parent;
+
+       gint     id;
+       gboolean is_read_only;
+       gdouble  font_size;
+
+       gint     page;
+       gboolean changed;
+};
+
+struct _EvFormFieldClass
+{
+       GObjectClass parent_class;
+};
+       
+struct _EvFormFieldText
+{
+       EvFormField partent;
+       
+       EvFormFieldTextType type;
+       
+       gboolean do_spell_check : 1;
+       gboolean do_scroll : 1;
+       gboolean comb : 1;
+       gboolean is_rich_text : 1;
+
+       gint   max_len;
+       gchar *text;
+};
+
+struct _EvFormFieldTextClass
+{
+       EvFormFieldClass partent_class;
+};
+
+struct _EvFormFieldButton
+{
+       EvFormField partent;
+       
+       EvFormFieldButtonType type;
+
+       gboolean state;
+};
+
+struct _EvFormFieldButtonClass
+{
+       EvFormFieldClass partent_class;
+};
+
+struct _EvFormFieldChoice
+{
+       EvFormField partent;
+
+       EvFormFieldChoiceType type;
+       
+       gboolean multi_select : 1;
+       gboolean is_editable : 1;
+       gboolean do_spell_check : 1;
+       gboolean commit_on_sel_change : 1;
+
+       GList *selected_items;
+       gchar *text;
+};
+
+struct _EvFormFieldChoiceClass
+{
+       EvFormFieldClass partent_class;
+};
+
+struct _EvFormFieldSignature
+{
+       EvFormField partent;
+       
+       /* TODO */
+};
+
+struct _EvFormFieldSignatureClass
+{
+       EvFormFieldClass partent_class;
+};
+
+/* EvFormField base class */
+GType        ev_form_field_get_type           (void) G_GNUC_CONST;
+
+/* EvFormFieldText */
+GType        ev_form_field_text_get_type      (void) G_GNUC_CONST;
+EvFormField *ev_form_field_text_new           (gint                  id,
+                                              EvFormFieldTextType   type);
+
+/* EvFormFieldButton */
+GType        ev_form_field_button_get_type    (void) G_GNUC_CONST;
+EvFormField *ev_form_field_button_new         (gint                  id,
+                                              EvFormFieldButtonType type);
+
+/* EvFormFieldChoice */
+GType        ev_form_field_choice_get_type    (void) G_GNUC_CONST;
+EvFormField *ev_form_field_choice_new         (gint                  id,
+                                              EvFormFieldChoiceType type);
+
+/* EvFormFieldSignature */
+GType        ev_form_field_signature_get_type (void) G_GNUC_CONST;
+EvFormField *ev_form_field_signature_new      (gint                  id);
+
+
+/* FormField Mapping stuff */
+typedef struct _EvFormFieldMapping EvFormFieldMapping;
+struct _EvFormFieldMapping {
+       EvFormField *field;
+       gdouble x1;
+       gdouble y1;
+       gdouble x2;
+       gdouble y2;
+};
+
+void         ev_form_field_mapping_free       (GList        *field_mapping);
+EvFormField *ev_form_field_mapping_find       (GList        *field_mapping,
+                                              gdouble       x,
+                                              gdouble       y);
+void         ev_form_field_mapping_get_area   (GList        *field_mapping,
+                                              EvFormField  *field,
+                                              EvRectangle  *area);
+EvFormField *ev_form_field_mapping_find_by_id (GList        *form_field_mapping,
+                                              gint          id);
+
+G_END_DECLS
+
+#endif /* !EV_FORM_FIELD_H */
+
index d9cdac8ae33c20e751c184e4c199d8d936ce2a9d..0f0a0daf18b1d2ddae82cb9314dcd45ffbea5bbf 100644 (file)
@@ -3,6 +3,7 @@
 #include "ev-document-thumbnails.h"
 #include "ev-document-links.h"
 #include "ev-document-images.h"
+#include "ev-document-forms.h"
 #include "ev-document-factory.h"
 #include "ev-document-misc.h"
 #include "ev-file-helpers.h"
@@ -265,6 +266,7 @@ ev_job_render_new (EvDocument      *document,
                   EvRectangle     *selection_points,
                   GdkColor        *text,
                   GdkColor        *base,
+                  gboolean         include_forms,
                   gboolean         include_links,
                   gboolean         include_images,
                   gboolean         include_text,
@@ -284,6 +286,7 @@ ev_job_render_new (EvDocument      *document,
        job->target_height = height;
        job->text = *text;
        job->base = *base;
+       job->include_forms = include_forms;
        job->include_links = include_links;
        job->include_images = include_images;
        job->include_text = include_text;
@@ -330,6 +333,7 @@ ev_job_render_run (EvJobRender *job)
                ev_document_fc_mutex_lock ();
                
                job->surface = ev_document_render (EV_JOB (job)->document, job->rc);
+
                if (job->include_links && EV_IS_DOCUMENT_LINKS (EV_JOB (job)->document))
                        job->link_mapping =
                                ev_document_links_get_links (EV_DOCUMENT_LINKS (EV_JOB (job)->document),
@@ -338,6 +342,10 @@ ev_job_render_run (EvJobRender *job)
                        job->image_mapping =
                                ev_document_images_get_images (EV_DOCUMENT_IMAGES (EV_JOB (job)->document),
                                                               job->rc->page);
+               if (job->include_forms && EV_IS_DOCUMENT_FORMS (EV_JOB (job)->document))
+                       job->form_field_mapping =
+                               ev_document_forms_get_form_fields (EV_DOCUMENT_FORMS (EV_JOB(job)->document),
+                                                                  job->rc->page);
                if (job->include_text && EV_IS_SELECTION (EV_JOB (job)->document))
                        job->text_mapping =
                                ev_selection_get_selection_map (EV_SELECTION (EV_JOB (job)->document),
index fc681d371a2ec43d3eead18ab954d4f8b51bb562..052319898c7c0223eb755f214252b616a332dc69 100644 (file)
@@ -126,6 +126,7 @@ struct _EvJobRender
        GList *link_mapping;
        GdkRegion *text_mapping;
        GList *image_mapping;
+       GList *form_field_mapping;
 
        cairo_surface_t *selection;
        GdkRegion *selection_region;
@@ -133,6 +134,7 @@ struct _EvJobRender
        GdkColor base;
        GdkColor text; 
 
+       gint include_forms : 1;
        gint include_links : 1;
        gint include_text : 1;
        gint include_selection : 1;
@@ -223,6 +225,7 @@ EvJob          *ev_job_render_new         (EvDocument      *document,
                                           EvRectangle     *selection_points,
                                           GdkColor        *text,
                                           GdkColor        *base,
+                                          gboolean         include_forms,
                                           gboolean         include_links,
                                           gboolean         include_images,
                                           gboolean         include_text,
index 20446b101acae6c2d0583dab679de94cefe80325..6cc0580b7bc787d790a101e130a6ddeaf6cf7a7f 100644 (file)
@@ -4,6 +4,7 @@
 #include "ev-selection.h"
 #include "ev-document-images.h"
 #include "ev-image.h"
+#include "ev-form-field.h"
 
 typedef struct _CacheJobInfo
 {
@@ -14,6 +15,7 @@ typedef struct _CacheJobInfo
        cairo_surface_t *surface;
        GList *link_mapping;
        GList *image_mapping;
+       GList *form_field_mapping;
        GdkRegion *text_mapping;
        
        /* Selection data. 
@@ -161,6 +163,10 @@ dispose_cache_job_info (CacheJobInfo *job_info,
                ev_image_mapping_free (job_info->image_mapping);
                job_info->image_mapping = NULL;
        }
+       if (job_info->form_field_mapping) {
+               ev_form_field_mapping_free (job_info->form_field_mapping);
+               job_info->form_field_mapping = NULL;
+       }
        if (job_info->text_mapping) {
                gdk_region_destroy (job_info->text_mapping);
                job_info->text_mapping = NULL;
@@ -323,6 +329,7 @@ move_one_job (CacheJobInfo  *job_info,
        job_info->surface = NULL;
        job_info->link_mapping = NULL;
        job_info->image_mapping = NULL;
+       job_info->form_field_mapping = NULL;
 
        if (new_priority != priority && target_page->job) {
                ev_job_queue_update_job (target_page->job, new_priority);
@@ -432,6 +439,12 @@ copy_job_to_job_info (EvJobRender   *job_render,
                job_info->image_mapping = job_render->image_mapping;
        }
 
+       if (job_render->include_forms) {
+               if (job_info->form_field_mapping)
+                       ev_form_field_mapping_free (job_info->form_field_mapping);
+               job_info->form_field_mapping = job_render->form_field_mapping;
+       }
+
        if (job_render->include_text) {
                if (job_info->text_mapping)
                        gdk_region_destroy (job_info->text_mapping);
@@ -540,6 +553,7 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache,
                   gfloat         scale,
                   EvJobPriority  priority)
 {
+       gboolean include_forms = FALSE;
        gboolean include_links = FALSE;
        gboolean include_text = FALSE;
        gboolean include_selection = FALSE;
@@ -572,6 +586,8 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache,
                include_links = TRUE;
        if (job_info->image_mapping == NULL)
                include_images = TRUE;
+       if (job_info->form_field_mapping == NULL)
+               include_forms = TRUE;
        if (job_info->text_mapping == NULL)
                include_text = TRUE;
        if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) {
@@ -587,6 +603,7 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache,
                                           width, height,
                                           &(job_info->target_points),
                                           text, base,
+                                          include_forms,
                                           include_links,
                                           include_images,
                                           include_text,
@@ -1102,3 +1119,101 @@ ev_pixbuf_cache_get_selection_list (EvPixbufCache *pixbuf_cache)
        return retval;
 }
 
+static void add_job (EvPixbufCache *pixbuf_cache,
+                    CacheJobInfo  *job_info,
+                    EvPageCache   *page_cache,
+                    gint           page,
+                    gint           rotation,
+                    gfloat         scale,
+                    EvJobPriority  priority,
+                    int            width,
+                    int            height)
+{
+       gboolean include_links = FALSE;
+       gboolean include_text = FALSE;
+       gboolean include_selection = FALSE;
+       gboolean include_images = TRUE;
+       gboolean include_forms = FALSE;
+        GdkColor *text, *base;
+
+
+        if (job_info->rc == NULL) {
+               job_info->rc = ev_render_context_new (rotation, page, scale);
+       } else {
+               ev_render_context_set_rotation (job_info->rc, rotation);
+               ev_render_context_set_page (job_info->rc, page);
+               ev_render_context_set_scale (job_info->rc, scale);
+       }
+
+       /* Figure out what else we need for this job */
+       if (job_info->link_mapping == NULL)
+               include_links = TRUE;
+       if (job_info->image_mapping == NULL)
+               include_images = TRUE;
+       if (job_info->form_field_mapping == NULL)
+               include_forms = TRUE; 
+       if (job_info->text_mapping == NULL)
+               include_text = TRUE;
+       if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) {
+               include_selection = TRUE;
+       }
+
+       gtk_widget_ensure_style (pixbuf_cache->view);
+
+       get_selection_colors (pixbuf_cache->view, &text, &base);
+
+       job_info->job = ev_job_render_new (pixbuf_cache->document,
+                                          job_info->rc,
+                                          width, height,
+                                          &(job_info->target_points),
+                                          text, base,
+                                          include_forms,
+                                          include_links,
+                                          include_images,
+                                          include_text,
+                                          include_selection);
+       ev_job_queue_add_job (job_info->job, priority);
+       g_signal_connect (job_info->job, "finished", G_CALLBACK (job_finished_cb), pixbuf_cache);
+
+}
+
+void           
+ev_pixbuf_cache_reload_page (EvPixbufCache *pixbuf_cache, 
+                            gint           page,
+                            gint           rotation,
+                            gfloat         scale)
+{
+       CacheJobInfo *job_info;
+        EvPageCache *page_cache;
+        int width, height;
+
+       if(page < pixbuf_cache->start_page || page > pixbuf_cache->end_page)
+               return;
+        page_cache = ev_page_cache_get (pixbuf_cache->document);
+       ev_page_cache_get_size (page_cache, page, rotation, scale, &width, &height);
+       job_info = pixbuf_cache->job_list + (page - pixbuf_cache->start_page);
+
+        //dispose_cache_job_info (job_info, pixbuf_cache);
+
+        add_job(pixbuf_cache, job_info, page_cache, page, rotation, scale, EV_JOB_PRIORITY_HIGH, width, height);
+        
+
+}
+
+GList *
+ev_pixbuf_cache_get_form_field_mapping (EvPixbufCache *pixbuf_cache,
+                                       gint           page)
+{
+       CacheJobInfo *job_info;
+       
+       job_info = find_job_cache (pixbuf_cache, page);
+       if(job_info == NULL)
+               return NULL;
+       
+       if(job_info->job &&
+          EV_JOB(job_info->job)->finished) {
+               copy_job_to_job_info (EV_JOB_RENDER(job_info->job), job_info, pixbuf_cache);
+       }
+       return job_info->form_field_mapping;
+}
+
index 79e0810a0f2956486f8ef6215f05acd6e5934393..a8ff30abbce7a9add2a26e8a8d18154e736fef02 100644 (file)
@@ -65,9 +65,14 @@ GList         *ev_pixbuf_cache_get_image_mapping    (EvPixbufCache *pixbuf_cache
                                                     gint           page);
 GdkRegion     *ev_pixbuf_cache_get_text_mapping     (EvPixbufCache *pixbuf_cache,
                                                     gint           page);
+GList        *ev_pixbuf_cache_get_form_field_mapping (EvPixbufCache *pixbuf_cache,
+                                                      gint         page);
 void           ev_pixbuf_cache_clear                (EvPixbufCache *pixbuf_cache);
 void           ev_pixbuf_cache_style_changed        (EvPixbufCache *pixbuf_cache);
-
+void           ev_pixbuf_cache_reload_page         (EvPixbufCache *pixbuf_cache, 
+                                                    gint           page,
+                                                    gint           rotation,
+                                                    gfloat         scale);
 /* Selection */
 cairo_surface_t *ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache,
                                                        gint           page,
index cab09417fe6ad1f53bd292f650ea505fb3931fe2..4908711fbe06c1e01e88456f4a25b16ffeb713b4 100644 (file)
@@ -25,6 +25,7 @@
 #include "ev-pixbuf-cache.h"
 #include "ev-page-cache.h"
 #include "ev-image.h"
+#include "ev-form-field.h"
 
 /* Information for middle clicking and moving around the doc */
 typedef struct {
@@ -73,7 +74,7 @@ typedef enum {
 } EvPresentationState;
 
 struct _EvView {
-       GtkWidget parent_instance;
+       GtkLayout layout;
 
        EvDocument *document;
 
@@ -152,11 +153,8 @@ struct _EvView {
 };
 
 struct _EvViewClass {
-       GtkWidgetClass parent_class;
+       GtkLayoutClass parent_class;
 
-       void    (*set_scroll_adjustments) (EvView         *view,
-                                          GtkAdjustment  *hadjustment,
-                                          GtkAdjustment  *vadjustment);
        void    (*binding_activated)      (EvView         *view,
                                           EvScrollType   scroll,
                                           gboolean        horizontal);
index 08694725b5c40b69cc3ac028d17912151ced5576..468a8946acd72e84f6efe5429320872f80e90691 100644 (file)
@@ -37,6 +37,7 @@
 #include "ev-document-images.h"
 #include "ev-document-find.h"
 #include "ev-document-transition.h"
+#include "ev-document-forms.h"
 #include "ev-document-misc.h"
 #include "ev-job-queue.h"
 #include "ev-page-cache.h"
@@ -115,7 +116,7 @@ typedef enum {
 /*** Scrolling ***/
 static void       scroll_to_current_page                    (EvView *view,
                                                              GtkOrientation orientation);
-static void       ev_view_set_scroll_adjustments             (EvView             *view,
+static void       ev_view_set_scroll_adjustments             (GtkLayout          *layout,
                                                              GtkAdjustment      *hadjustment,
                                                              GtkAdjustment      *vadjustment);
 static void       view_update_range_and_current_page         (EvView             *view);
@@ -157,19 +158,21 @@ static void       find_page_at_location                      (EvView
                                                              gint               *page,
                                                              gint               *x_offset,
                                                              gint               *y_offset);
-static gboolean  doc_point_to_view_point                    (EvView       *view,
-                                                             int           page,
-                                                             EvPoint      *doc_point,
-                                                             GdkPoint     *view_point);
+static gboolean  doc_point_to_view_point                    (EvView             *view,
+                                                             int                 page,
+                                                             EvPoint            *doc_point,
+                                                             GdkPoint           *view_point);
 /*** Hyperrefs ***/
-static EvLink *   ev_view_get_link_at_location                      (EvView  *view,
-                                                             gdouble  x,
-                                                             gdouble  y);
+static EvLink *   ev_view_get_link_at_location                      (EvView             *view,
+                                                             gdouble             x,
+                                                             gdouble             y);
 static char*      tip_from_link                              (EvView             *view,
                                                              EvLink             *link);
-static void       handle_link_over_xy                        (EvView *view, 
-                                                             gint x, 
-                                                             gint y);
+/*** Forms ***/
+static EvFormField *ev_view_get_form_field_at_location       (EvView             *view,
+                                                              gdouble            x,
+                                                              gdouble            y);
+
 /*** GtkWidget implementation ***/
 static void       ev_view_size_request_continuous_dual_page  (EvView             *view,
                                                              GtkRequisition     *requisition);
@@ -201,6 +204,7 @@ static gboolean   ev_view_leave_notify_event                 (GtkWidget
                                                              GdkEventCrossing   *event);
 static void       ev_view_style_set                          (GtkWidget          *widget,
                                                              GtkStyle           *old_style);
+static void       ev_view_remove_all                         (EvView             *view);
 
 static AtkObject *ev_view_get_accessible                     (GtkWidget *widget);
 
@@ -292,6 +296,9 @@ static void ev_view_zoom_for_size_single_page              (EvView *view,
 static GdkCursor* ev_view_create_invisible_cursor            (void);
 static void       ev_view_set_cursor                         (EvView             *view,
                                                              EvViewCursor        new_cursor);
+static void       ev_view_handle_cursor_over_xy              (EvView *view,
+                                                             gint x,
+                                                             gint y);
 
 /*** Status messages ***/
 static void       ev_view_set_status                         (EvView             *view,
@@ -326,7 +333,7 @@ static void       ev_view_presentation_transition_start      (EvView
 static void       ev_view_presentation_transition_stop       (EvView             *ev_view);
 
 
-G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_WIDGET)
+G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_LAYOUT)
 
 static void
 scroll_to_current_page (EvView *view, GtkOrientation orientation)
@@ -554,13 +561,15 @@ set_scroll_adjustment (EvView *view,
 }
 
 static void
-ev_view_set_scroll_adjustments (EvView *view,
+ev_view_set_scroll_adjustments (GtkLayout      *layout,
                                GtkAdjustment  *hadjustment,
                                GtkAdjustment  *vadjustment)
 {
+       EvView *view = EV_VIEW (layout);
+       
        set_scroll_adjustment (view, GTK_ORIENTATION_HORIZONTAL, hadjustment);
        set_scroll_adjustment (view, GTK_ORIENTATION_VERTICAL, vadjustment);
-
+       
        on_adjustment_value_changed (NULL, view);
 }
 
@@ -1481,7 +1490,7 @@ tip_from_link (EvView *view, EvLink *link)
 }
 
 static void
-handle_link_over_xy (EvView *view, gint x, gint y)
+ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
 {
        EvLink *link;
 
@@ -1511,6 +1520,8 @@ handle_link_over_xy (EvView *view, gint x, gint y)
                ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
        } else if (location_in_text (view, x + view->scroll_x, y + view->scroll_y)) {
                ev_view_set_cursor (view, EV_VIEW_CURSOR_IBEAM);
+       } else if (ev_view_get_form_field_at_location (view, x, y)) {
+               ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
        } else {
                ev_view_set_status (view, NULL);
                if (view->cursor == EV_VIEW_CURSOR_LINK ||
@@ -1553,6 +1564,440 @@ ev_view_get_image_at_location (EvView  *view,
                return NULL;
 }
 
+/*** Forms ***/
+static EvFormField *
+ev_view_get_form_field_at_location (EvView  *view,
+                                   gdouble  x,
+                                   gdouble  y)
+{
+       gint page = -1;
+       gint x_offset = 0, y_offset = 0;
+       gint x_new = 0, y_new = 0;
+       GList *forms_mapping;
+       
+       if (!EV_IS_DOCUMENT_FORMS (view->document))
+               return NULL;
+
+       x += view->scroll_x;
+       y += view->scroll_y;
+       
+       find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
+       
+       if (page == -1)
+               return NULL;
+
+       if (get_doc_point_from_offset (view, page, x_offset,
+                                      y_offset, &x_new, &y_new) == FALSE)
+               return NULL;
+
+       forms_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, page);
+
+       if (forms_mapping)
+               return ev_form_field_mapping_find (forms_mapping, x_new, y_new);
+       else
+               return NULL;
+}
+
+static gboolean
+ev_view_forms_remove_widgets (EvView *view)
+{
+       ev_view_remove_all (view);
+
+       return FALSE;
+}
+
+static void
+ev_view_form_field_destroy (GtkWidget *widget,
+                           EvView    *view)
+{
+       g_idle_add ((GSourceFunc)ev_view_forms_remove_widgets, view);
+}
+
+static GtkWidget *
+ev_view_form_field_button_create_widget (EvView      *view,
+                                        EvFormField *field)
+{
+       EvFormFieldButton *field_button = EV_FORM_FIELD_BUTTON (field);
+       
+       switch (field_button->type) {
+               case EV_FORM_FIELD_BUTTON_PUSH:
+                       break;
+               case EV_FORM_FIELD_BUTTON_CHECK:
+               case EV_FORM_FIELD_BUTTON_RADIO: {
+                       gboolean state;
+
+                       state = ev_document_forms_form_field_button_get_state (EV_DOCUMENT_FORMS (view->document),
+                                                                              field);
+                       ev_document_forms_form_field_button_set_state (EV_DOCUMENT_FORMS (view->document),
+                                                                      field, !state);
+                       ev_pixbuf_cache_reload_page (view->pixbuf_cache,
+                                                    field->page,
+                                                    view->rotation,
+                                                    view->scale);
+               }
+                       break;
+       }
+       
+       return NULL;
+}
+
+static void
+ev_view_form_field_text_save (EvView    *view,
+                             GtkWidget *widget)
+{
+       EvFormField *field;
+
+       field = g_object_get_data (G_OBJECT (widget), "form-field");
+       
+       if (field->changed) {
+               EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
+               
+               ev_document_forms_form_field_text_set_text (EV_DOCUMENT_FORMS (view->document),
+                                                           field, field_text->text);
+               field->changed = FALSE;
+               ev_pixbuf_cache_reload_page (view->pixbuf_cache,
+                                            field->page,
+                                            view->rotation,
+                                            view->scale);
+       }
+}
+
+static void
+ev_view_form_field_text_changed (GtkWidget   *widget,
+                                EvFormField *field)
+{
+       EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
+       gchar           *text = NULL;
+
+       if (GTK_IS_ENTRY (widget)) {
+               text = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget)));
+       } else if (GTK_IS_TEXT_BUFFER (widget)) {
+               GtkTextIter start, end;
+
+               gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (widget), &start, &end);
+               text = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (widget),
+                                                &start, &end, FALSE);
+       }
+
+       if (!field_text->text ||
+           (field_text->text && g_ascii_strcasecmp (field_text->text, text) != 0)) {
+               g_free (field_text->text);
+               field_text->text = text;
+               field->changed = TRUE;
+       }
+}
+
+static GtkWidget *
+ev_view_form_field_text_create_widget (EvView      *view,
+                                      EvFormField *field)
+{
+       EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
+       GtkWidget       *text = NULL;
+       gchar           *txt;
+
+       txt = ev_document_forms_form_field_text_get_text (EV_DOCUMENT_FORMS (view->document),
+                                                         field);
+
+       switch (field_text->type) {
+               case EV_FORM_FIELD_TEXT_FILE_SELECT:
+                       /* TODO */
+               case EV_FORM_FIELD_TEXT_NORMAL:
+               case EV_FORM_FIELD_TEXT_PASSWORD:
+                       text = gtk_entry_new ();
+                       gtk_entry_set_has_frame (GTK_ENTRY (text), FALSE);
+                       gtk_entry_set_max_length (GTK_ENTRY (text), field_text->max_len);
+                       gtk_entry_set_visibility (GTK_ENTRY (text),
+                                                 !(field_text->type == EV_FORM_FIELD_TEXT_PASSWORD));
+                       
+                       if (txt) {
+                               gtk_entry_set_text (GTK_ENTRY (text), txt);
+                               g_free (txt);
+                       }
+
+                       g_signal_connect (G_OBJECT (text), "changed",
+                                         G_CALLBACK (ev_view_form_field_text_changed),
+                                         field);
+                       g_signal_connect_after (G_OBJECT (text), "activate",
+                                               G_CALLBACK (ev_view_form_field_destroy),
+                                               view);
+                       break;
+               case EV_FORM_FIELD_TEXT_MULTILINE: {
+                       GtkTextBuffer *buffer;
+               
+                       text = gtk_text_view_new ();
+                       buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text));
+               
+                       if (txt) {
+                               gtk_text_buffer_set_text (buffer, txt, -1);
+                               g_free (txt);
+                       }
+                       
+                       g_signal_connect (G_OBJECT (buffer), "changed",
+                                         G_CALLBACK (ev_view_form_field_text_changed),
+                                         field);
+               }
+                       break;
+       }                       
+
+       g_object_weak_ref (G_OBJECT (text),
+                          (GWeakNotify)ev_view_form_field_text_save,
+                          view);
+
+       return text;
+}
+
+static void
+ev_view_form_field_choice_save (EvView    *view,
+                               GtkWidget *widget)
+{
+       EvFormField *field;
+
+       field = g_object_get_data (G_OBJECT (widget), "form-field");
+
+       if (field->changed) {
+               GList             *l;
+               EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
+
+               if (field_choice->is_editable) {
+                       ev_document_forms_form_field_choice_set_text (EV_DOCUMENT_FORMS (view->document),
+                                                                     field, field_choice->text);
+               }
+               
+               ev_document_forms_form_field_choice_unselect_all (EV_DOCUMENT_FORMS (view->document), field);
+               for (l = field_choice->selected_items; l && l->data; l = g_list_next (l)) {
+                       ev_document_forms_form_field_choice_select_item (EV_DOCUMENT_FORMS (view->document),
+                                                                        field,
+                                                                        GPOINTER_TO_INT (l->data));
+               }
+               field->changed = FALSE;
+               ev_pixbuf_cache_reload_page (view->pixbuf_cache,
+                                            field->page,
+                                            view->rotation,
+                                            view->scale);
+       }
+}
+
+static void
+ev_view_form_field_choice_changed (GtkWidget   *widget,
+                                  EvFormField *field)
+{
+       EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
+       
+       if (GTK_IS_COMBO_BOX (widget)) {
+               gint item;
+               
+               item = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+               if (GPOINTER_TO_INT (field_choice->selected_items->data) != item) {
+                       g_list_free (field_choice->selected_items);
+                       field_choice->selected_items = NULL;
+                       field_choice->selected_items = g_list_prepend (field_choice->selected_items,
+                                                                      GINT_TO_POINTER (item));
+                       field->changed = TRUE;
+               }
+
+               if (GTK_IS_COMBO_BOX_ENTRY (widget)) {
+                       gchar *text;
+                       
+                       text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (widget));
+                       if (!field_choice->text ||
+                           (field_choice->text && g_ascii_strcasecmp (field_choice->text, text) != 0)) {
+                               g_free (field_choice->text);
+                               field_choice->text = text;
+                               field->changed = TRUE;
+                       }
+               }
+       } else if (GTK_IS_TREE_SELECTION (widget)) {
+               GtkTreeSelection *selection = GTK_TREE_SELECTION (widget);
+               GtkTreeModel     *model;
+               GList            *items, *l;
+               
+               items = gtk_tree_selection_get_selected_rows (selection, &model);
+               g_list_free (field_choice->selected_items);
+               field_choice->selected_items = NULL;
+
+               for (l = items; l && l->data; l = g_list_next (l)) {
+                       GtkTreeIter  iter;
+                       GtkTreePath *path = (GtkTreePath *)l->data;
+                       gint         item;
+                       
+                       gtk_tree_model_get_iter (model, &iter, path);
+                       gtk_tree_model_get (model, &iter, 1, &item, -1);
+
+                       field_choice->selected_items = g_list_prepend (field_choice->selected_items,
+                                                                      GINT_TO_POINTER (item));
+
+                       gtk_tree_path_free (path);
+               }
+
+               g_list_free (items);
+
+               field->changed = TRUE;
+       }
+}
+
+static GtkWidget *
+ev_view_form_field_choice_create_widget (EvView      *view,
+                                        EvFormField *field)
+{
+       EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
+       GtkWidget         *choice;
+       GtkTreeModel      *model;
+       gint               n_items, i;
+       gint               selected_item = 0;
+
+       n_items = ev_document_forms_form_field_choice_get_n_items (EV_DOCUMENT_FORMS (view->document),
+                                                                  field);
+       model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT));
+       for (i = 0; i < n_items; i++) {
+               GtkTreeIter iter;
+               gchar      *item;
+
+               item = ev_document_forms_form_field_choice_get_item (EV_DOCUMENT_FORMS (view->document),
+                                                                    field, i);
+               if (ev_document_forms_form_field_choice_is_item_selected (
+                           EV_DOCUMENT_FORMS (view->document), field, i)) {
+                       selected_item = i;
+                       /* FIXME: we need a get_selected_items function in poppler */
+                       field_choice->selected_items = g_list_prepend (field_choice->selected_items,
+                                                                      GINT_TO_POINTER (i));
+               }
+               
+               if (item) {
+                       gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+                       gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+                                           0, item,
+                                           1, i,
+                                           -1);
+                       g_free (item);
+               }
+       }
+
+       if (field_choice->type == EV_FORM_FIELD_CHOICE_LIST) {
+               GtkCellRenderer  *renderer;
+               GtkWidget        *tree_view;
+               GtkTreeSelection *selection;
+
+               tree_view = gtk_tree_view_new_with_model (model);
+               gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
+
+               selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+               if (field_choice->multi_select) {
+                       gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+               }
+
+               /* TODO: set selected items */
+
+               renderer = gtk_cell_renderer_text_new ();
+               gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
+                                                            0,
+                                                            "choix", renderer,
+                                                            "text", 0,
+                                                            NULL);
+
+               choice = gtk_scrolled_window_new (NULL, NULL);
+               gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (choice),
+                                               GTK_POLICY_AUTOMATIC,
+                                               GTK_POLICY_AUTOMATIC);
+               gtk_container_add (GTK_CONTAINER (choice), tree_view);
+               gtk_widget_show (tree_view);
+
+               g_signal_connect (G_OBJECT (selection), "changed",
+                                 G_CALLBACK (ev_view_form_field_choice_changed),
+                                 field);
+               g_signal_connect_after (G_OBJECT (selection), "changed",
+                                       G_CALLBACK (ev_view_form_field_destroy),
+                                       view);
+       } else if (field_choice->is_editable) { /* ComboBoxEntry */
+               gchar *text;
+               
+               choice = gtk_combo_box_entry_new_with_model (model, 0);
+               text = ev_document_forms_form_field_choice_get_text (EV_DOCUMENT_FORMS (view->document), field);
+               if (text) {
+                       gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (choice))), text);
+                       g_free (text);
+               }
+
+               g_signal_connect (G_OBJECT (choice), "changed",
+                                 G_CALLBACK (ev_view_form_field_choice_changed),
+                                 field);
+               g_signal_connect_after (G_OBJECT (GTK_BIN (choice)->child), "activate",
+                                       G_CALLBACK (ev_view_form_field_destroy),
+                                       view);
+       } else { /* ComboBoxText */
+               GtkCellRenderer *renderer;
+
+               choice = gtk_combo_box_new_with_model (model);
+               renderer = gtk_cell_renderer_text_new ();
+               gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (choice),
+                                           renderer, TRUE);
+               gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (choice),
+                                               renderer,
+                                               "text", 0,
+                                               NULL);
+               gtk_combo_box_set_active (GTK_COMBO_BOX (choice), selected_item);
+               gtk_combo_box_popup (GTK_COMBO_BOX (choice));
+               
+               g_signal_connect (G_OBJECT (choice), "changed",
+                                 G_CALLBACK (ev_view_form_field_choice_changed),
+                                 field);
+               g_signal_connect_after (G_OBJECT (choice), "changed",
+                                       G_CALLBACK (ev_view_form_field_destroy),
+                                       view);
+       }
+
+       g_object_unref (model);
+
+       g_object_weak_ref (G_OBJECT (choice),
+                          (GWeakNotify)ev_view_form_field_choice_save,
+                          view);
+
+       return choice;
+}
+
+static void
+ev_view_handle_form_field (EvView      *view,
+                          EvFormField *field,
+                          gdouble      x,
+                          gdouble      y)
+{
+       GtkWidget   *field_widget = NULL;
+       GList       *form_field_mapping;
+       EvRectangle  field_area;
+       GdkRectangle view_area;
+
+       if (field->is_read_only)
+               return;
+       
+       if (EV_IS_FORM_FIELD_BUTTON (field)) {
+               field_widget = ev_view_form_field_button_create_widget (view, field);
+       } else if (EV_IS_FORM_FIELD_TEXT (field)) {
+               field_widget = ev_view_form_field_text_create_widget (view, field);
+       } else if (EV_IS_FORM_FIELD_CHOICE (field)) {
+               field_widget = ev_view_form_field_choice_create_widget (view, field);
+       } else if (EV_IS_FORM_FIELD_SIGNATURE (field)) {
+               /* TODO */
+       }
+
+       /* Form field doesn't require a widget */
+       if (!field_widget)
+               return;
+
+       g_object_set_data_full (G_OBJECT (field_widget), "form-field",
+                               g_object_ref (field),
+                               (GDestroyNotify)g_object_unref);
+
+       form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, field->page);
+       ev_form_field_mapping_get_area (form_field_mapping, field, &field_area);
+       
+       doc_rect_to_view_rect (view, field->page, &field_area, &view_area);
+       view_area.x -= view->scroll_x;
+       view_area.y -= view->scroll_y;
+
+       gtk_layout_put (GTK_LAYOUT (view), field_widget, view_area.x, view_area.y);
+       gtk_widget_show (field_widget);
+       gtk_widget_grab_focus (field_widget);
+}
+
 /*** GtkWidget implementation ***/
 
 static void
@@ -1680,7 +2125,7 @@ ev_view_size_request (GtkWidget      *widget,
                      GtkRequisition *requisition)
 {
        EvView *view = EV_VIEW (widget);
-
+       
        if (view->document == NULL) {
                requisition->width = 1;
                requisition->height = 1;
@@ -1708,6 +2153,7 @@ ev_view_size_allocate (GtkWidget      *widget,
                       GtkAllocation  *allocation)
 {
        EvView *view = EV_VIEW (widget);
+       GList  *children, *l;
 
        GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation);
        
@@ -1718,7 +2164,7 @@ ev_view_size_allocate (GtkWidget      *widget,
 
                ev_view_size_request (widget, &widget->requisition);
        }
-
+       
        view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
        view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
 
@@ -1727,47 +2173,71 @@ ev_view_size_allocate (GtkWidget      *widget,
 
        view->pending_scroll = SCROLL_TO_KEEP_POSITION;
        view->pending_resize = FALSE;
+
+       children = gtk_container_get_children (GTK_CONTAINER (widget));
+       for (l = children; l && l->data; l = g_list_next (l)) {
+               EvFormField   *field;
+               EvRectangle    field_area;
+               GdkRectangle   view_area;
+               GList         *form_field_mapping;
+               GtkAllocation  child_allocation;
+               GtkRequisition child_requisition;
+               GtkWidget     *child = (GtkWidget *)l->data;
+               
+               field = g_object_get_data (G_OBJECT (child), "form-field");
+               if (!field)
+                       continue;
+
+               form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache,
+                                                                            field->page);
+               ev_form_field_mapping_get_area (form_field_mapping, field, &field_area);
+
+               doc_rect_to_view_rect (view, field->page, &field_area, &view_area);
+               view_area.x -= view->scroll_x;
+               view_area.y -= view->scroll_y;
+
+               gtk_widget_size_request (child, &child_requisition);
+               if (child_requisition.width != view_area.width ||
+                   child_requisition.height != view_area.height)
+                       gtk_widget_set_size_request (child, view_area.width, view_area.height);
+
+               gtk_container_child_get (GTK_CONTAINER (widget),
+                                        child,
+                                        "x", &child_allocation.x,
+                                        "y", &child_allocation.y,
+                                        NULL);
+               if (child_allocation.x != view_area.x ||
+                   child_allocation.y != view_area.y) {
+                       gtk_layout_move (GTK_LAYOUT (widget), child, view_area.x, view_area.y);
+               }
+       }
+       g_list_free (children);
 }
 
 static void
 ev_view_realize (GtkWidget *widget)
 {
        EvView *view = EV_VIEW (widget);
-       GdkWindowAttr attributes;
-
-       GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
 
-       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);
+       if (GTK_WIDGET_CLASS (ev_view_parent_class)->realize)
+               (* GTK_WIDGET_CLASS (ev_view_parent_class)->realize) (widget);
 
-       attributes.x = widget->allocation.x;
-       attributes.y = widget->allocation.y;
-       attributes.width = widget->allocation.width;
-       attributes.height = widget->allocation.height;
-       attributes.event_mask = GDK_EXPOSURE_MASK |
+       gdk_window_set_events (view->layout.bin_window,
+                              (gdk_window_get_events (view->layout.bin_window) | 
+                               GDK_EXPOSURE_MASK |
                                GDK_BUTTON_PRESS_MASK |
                                GDK_BUTTON_RELEASE_MASK |
                                GDK_SCROLL_MASK |
                                GDK_KEY_PRESS_MASK |
                                GDK_POINTER_MOTION_MASK |
                                GDK_POINTER_MOTION_HINT_MASK |
-                               GDK_ENTER_NOTIFY_MASK |
-                               GDK_LEAVE_NOTIFY_MASK;
-
-       widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
-                                        &attributes,
-                                        GDK_WA_X | GDK_WA_Y |
-                                        GDK_WA_COLORMAP |
-                                        GDK_WA_VISUAL);
-       gdk_window_set_user_data (widget->window, widget);
-       widget->style = gtk_style_attach (widget->style, widget->window);
+                               GDK_ENTER_NOTIFY_MASK |
+                               GDK_LEAVE_NOTIFY_MASK));
 
        if (view->presentation)
-               gdk_window_set_background (widget->window, &widget->style->black);
+               gdk_window_set_background (view->layout.bin_window, &widget->style->black);
        else
-               gdk_window_set_background (widget->window, &widget->style->mid [GTK_STATE_NORMAL]);
+               gdk_window_set_background (view->layout.bin_window, &widget->style->mid [GTK_STATE_NORMAL]);
 }
 
 static gboolean
@@ -1869,7 +2339,7 @@ draw_end_presentation_page (EvView       *view,
        pango_layout_set_font_description (layout, font_desc);
 
        gtk_paint_layout (GTK_WIDGET (view)->style,
-                         GTK_WIDGET (view)->window,
+                         view->layout.bin_window,
                          GTK_WIDGET_STATE (view),
                          FALSE,
                          page_area,
@@ -1939,6 +2409,9 @@ ev_view_expose_event (GtkWidget      *widget,
                        highlight_find_results (view, i);
        }
 
+       if (GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event)
+               (* GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event) (widget, event);
+
        return FALSE;
 }
 
@@ -1995,6 +2468,7 @@ ev_view_button_press_event (GtkWidget      *widget,
        switch (event->button) {
                case 1: {
                        EvImage *image;
+                       EvFormField *field;
 
                        if (view->selection_info.selections) {
                                if (location_in_selected_text (view,
@@ -2018,7 +2492,11 @@ ev_view_button_press_event (GtkWidget      *widget,
 
                                view->image_dnd_info.start.x = event->x + view->scroll_x;
                                view->image_dnd_info.start.y = event->y + view->scroll_y;
+                       } else if ((field = ev_view_get_form_field_at_location (view, event->x, event->y))) {
+                               ev_view_remove_all (view);
+                               ev_view_handle_form_field (view, field, event->x, event->y);
                        } else {
+                               ev_view_remove_all (view);
                                view->selection_info.start.x = event->x + view->scroll_x;
                                view->selection_info.start.y = event->y + view->scroll_y;
                        }
@@ -2042,6 +2520,19 @@ ev_view_button_press_event (GtkWidget      *widget,
        return FALSE;
 }
 
+static void
+ev_view_remove_all (EvView *view)
+{
+       GList *children, *child;
+
+       children = gtk_container_get_children (GTK_CONTAINER (view));
+       for (child = children; child && child->data; child = g_list_next (child)) {
+               gtk_container_remove (GTK_CONTAINER (view),
+                                     GTK_WIDGET (child->data));
+       }
+       g_list_free (children);
+}
+
 /*** Drag and Drop ***/
 static void
 ev_view_drag_data_get (GtkWidget        *widget,
@@ -2196,7 +2687,7 @@ ev_view_motion_notify_event (GtkWidget      *widget,
        if (!view->document)
                return FALSE;
                
-        if (event->is_hint || event->window != widget->window) {
+        if (event->is_hint || event->window != view->layout.bin_window) {
            gtk_widget_get_pointer (widget, &x, &y);
         } else {
            x = event->x;
@@ -2306,7 +2797,7 @@ ev_view_motion_notify_event (GtkWidget      *widget,
                        return TRUE;
                }
        } else if (view->pressed_button <= 0) {
-               handle_link_over_xy (view, x, y);
+               ev_view_handle_cursor_over_xy (view, x, y);
                return TRUE;
        }
 
@@ -2642,11 +3133,11 @@ ev_view_key_press_event (GtkWidget   *widget,
        switch (view->presentation_state) {
                case EV_PRESENTATION_NORMAL:
                case EV_PRESENTATION_BLACK:
-                       gdk_window_set_background (widget->window,
+                       gdk_window_set_background (view->layout.bin_window,
                                                   &widget->style->black);
                        break;
                case EV_PRESENTATION_WHITE:
-                       gdk_window_set_background (widget->window,
+                       gdk_window_set_background (view->layout.bin_window,
                                                   &widget->style->white);
                        break;
                default:
@@ -2706,7 +3197,7 @@ ev_view_enter_notify_event (GtkWidget *widget, GdkEventCrossing   *event)
 {
        EvView *view = EV_VIEW (widget);
 
-       handle_link_over_xy (view, event->x, event->y);
+       ev_view_handle_cursor_over_xy (view, event->x, event->y);
     
        return FALSE;
 }
@@ -2793,7 +3284,7 @@ highlight_find_results (EvView *view, int page)
 
                ev_document_find_get_result (find, page, i, &rectangle);
                doc_rect_to_view_rect (view, page, &rectangle, &view_rectangle);
-               draw_rubberband (GTK_WIDGET (view), GTK_WIDGET(view)->window,
+               draw_rubberband (GTK_WIDGET (view), view->layout.bin_window,
                                 &view_rectangle, alpha);
         }
 }
@@ -2857,7 +3348,7 @@ draw_loading_text (EvView       *view,
        width = (page_area->width - cairo_image_surface_get_width (view->loading_text)) / 2;
        height = (page_area->height - cairo_image_surface_get_height (view->loading_text)) / 2;
        
-       cr = gdk_cairo_create (GTK_WIDGET (view)->window);
+       cr = gdk_cairo_create (view->layout.bin_window);
        cairo_translate (cr,
                         page_area->x + width,
                         page_area->y + height);
@@ -2893,9 +3384,9 @@ draw_one_page (EvView       *view,
 
        if (!view->presentation) {
                gint current_page;
-
+               
                current_page = ev_page_cache_get_current_page (view->page_cache);
-               ev_document_misc_paint_one_page (GTK_WIDGET (view)->window,
+               ev_document_misc_paint_one_page (view->layout.bin_window,
                                                 GTK_WIDGET (view),
                                                 page_area, border, 
                                                 page == current_page);
@@ -2925,7 +3416,7 @@ draw_one_page (EvView       *view,
                                        view->scale,
                                        &width, &height);
 
-               cr = gdk_cairo_create (GTK_WIDGET (view)->window);
+               cr = gdk_cairo_create (view->layout.bin_window);
                
                cairo_save (cr);
                
@@ -3057,7 +3548,7 @@ ev_view_destroy (GtkObject *object)
 
        ev_view_presentation_transition_stop (view);
 
-       ev_view_set_scroll_adjustments (view, NULL, NULL);
+       ev_view_set_scroll_adjustments (GTK_LAYOUT (view), NULL, NULL);
 
        GTK_OBJECT_CLASS (ev_view_parent_class)->destroy (object);
 }
@@ -3179,6 +3670,7 @@ ev_view_class_init (EvViewClass *class)
        GObjectClass *object_class = G_OBJECT_CLASS (class);
        GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (class);
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+       GtkLayoutClass *layout_class = GTK_LAYOUT_CLASS (class);
        GtkBindingSet *binding_set;
 
        object_class->finalize = ev_view_finalize;
@@ -3204,22 +3696,13 @@ ev_view_class_init (EvViewClass *class)
        widget_class->drag_motion = ev_view_drag_motion;
        widget_class->drag_data_received = ev_view_drag_data_received;
        widget_class->popup_menu = ev_view_popup_menu;
+
        gtk_object_class->destroy = ev_view_destroy;
 
-       class->set_scroll_adjustments = ev_view_set_scroll_adjustments;
+       layout_class->set_scroll_adjustments = ev_view_set_scroll_adjustments;
+       
        class->binding_activated = ev_view_scroll;
 
-       widget_class->set_scroll_adjustments_signal =
-           g_signal_new ("set-scroll-adjustments",
-                         G_OBJECT_CLASS_TYPE (object_class),
-                         G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                         G_STRUCT_OFFSET (EvViewClass, set_scroll_adjustments),
-                         NULL, NULL,
-                         ev_marshal_VOID__OBJECT_OBJECT,
-                         G_TYPE_NONE, 2,
-                         GTK_TYPE_ADJUSTMENT,
-                         GTK_TYPE_ADJUSTMENT);
-
        signals[SIGNAL_BINDING_ACTIVATED] = g_signal_new ("binding_activated",
                         G_TYPE_FROM_CLASS (object_class),
                         G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
@@ -3379,6 +3862,9 @@ ev_view_init (EvView *view)
        view->pending_scroll = SCROLL_TO_KEEP_POSITION;
        view->jump_to_find_result = TRUE;
 
+       gtk_layout_set_hadjustment (GTK_LAYOUT (view), NULL);
+       gtk_layout_set_vadjustment (GTK_LAYOUT (view), NULL);
+
        gtk_drag_dest_set (GTK_WIDGET (view),
                           GTK_DEST_DEFAULT_ALL,
                           view_drop_targets,
@@ -3429,7 +3915,7 @@ page_changed_cb (EvPageCache *page_cache,
                        ev_view_presentation_transition_start (view);
                
                gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
-               handle_link_over_xy (view, x, y);
+               ev_view_handle_cursor_over_xy (view, x, y);
                
                gtk_widget_queue_resize (GTK_WIDGET (view));
        } else {
@@ -3448,6 +3934,7 @@ on_adjustment_value_changed (GtkAdjustment *adjustment,
 {
        int dx = 0, dy = 0;
        gint x, y;
+       GList *children, *l;
 
        if (! GTK_WIDGET_REALIZED (view))
                return;
@@ -3466,13 +3953,27 @@ on_adjustment_value_changed (GtkAdjustment *adjustment,
                view->scroll_y = 0;
        }
 
+       children = gtk_container_get_children (GTK_CONTAINER (view));
+       for (l = children; l && l->data; l = g_list_next (l)) {
+               gint       child_x, child_y;
+               GtkWidget *child = (GtkWidget *)l->data;
+               
+               gtk_container_child_get (GTK_CONTAINER (view),
+                                        child,
+                                        "x", &child_x,
+                                        "y", &child_y,
+                                        NULL);
+               gtk_layout_move (GTK_LAYOUT (view), child, child_x + dx, child_y + dy);
+       }
+       g_list_free (children);
+       
        if (view->pending_resize)
                gtk_widget_queue_draw (GTK_WIDGET (view));
        else
-               gdk_window_scroll (GTK_WIDGET (view)->window, dx, dy);
+               gdk_window_scroll (view->layout.bin_window, dx, dy);
                
        gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
-       handle_link_over_xy (view, x, y);
+       ev_view_handle_cursor_over_xy (view, x, y);
 
        if (view->document)
                view_update_range_and_current_page (view);
@@ -3725,10 +4226,10 @@ ev_view_set_presentation (EvView   *view,
 
        if (GTK_WIDGET_REALIZED (view)) {
                if (view->presentation)
-                       gdk_window_set_background (GTK_WIDGET(view)->window,
+                       gdk_window_set_background (view->layout.bin_window,
                                                   &GTK_WIDGET (view)->style->black);
                else
-                       gdk_window_set_background (GTK_WIDGET(view)->window,
+                       gdk_window_set_background (view->layout.bin_window,
                                                   &GTK_WIDGET (view)->style->mid [GTK_STATE_NORMAL]);
        }
 
@@ -4629,7 +5130,7 @@ merge_selection_region (EvView *view,
                        gdk_region_offset (region,
                                           page_area.x + border.left - view->scroll_x,
                                           page_area.y + border.top - view->scroll_y);
-                       gdk_window_invalidate_region (GTK_WIDGET (view)->window, region, TRUE);
+                       gdk_window_invalidate_region (view->layout.bin_window, region, TRUE);
                        gdk_region_destroy (region);
                }
        }
@@ -4843,7 +5344,7 @@ ev_view_set_cursor (EvView *view, EvViewCursor new_cursor)
 
        switch (new_cursor) {
                case EV_VIEW_CURSOR_NORMAL:
-                       gdk_window_set_cursor (widget->window, NULL);
+                       gdk_window_set_cursor (view->layout.bin_window, NULL);
                        break;
                case EV_VIEW_CURSOR_IBEAM:
                        cursor = gdk_cursor_new_for_display (display, GDK_XTERM);
@@ -4863,7 +5364,7 @@ ev_view_set_cursor (EvView *view, EvViewCursor new_cursor)
        }
 
        if (cursor) {
-               gdk_window_set_cursor (widget->window, cursor);
+               gdk_window_set_cursor (view->layout.bin_window, cursor);
                gdk_cursor_unref (cursor);
                gdk_flush();
        }
@@ -4889,7 +5390,7 @@ ev_view_reset_presentation_state (EvView *view)
                return;
 
        view->presentation_state = EV_PRESENTATION_NORMAL;
-       gdk_window_set_background (GTK_WIDGET (view)->window,
+       gdk_window_set_background (view->layout.bin_window,
                                   &GTK_WIDGET (view)->style->black);
        gtk_widget_queue_draw (GTK_WIDGET (view));
 }
index e9b8afa55a7416166860c02f39fe0dffd0da40a7..78fc6598ac83a145c76aad04287d4e01453a21f6 100644 (file)
@@ -21,6 +21,7 @@
 #define __EV_VIEW_H__
 
 #include <gtk/gtkwidget.h>
+#include <gtk/gtklayout.h>
 
 #include "ev-document.h"
 #include "ev-link.h"