Index: backend/Makefile.am =================================================================== RCS file: /cvs/gnome/evince/backend/Makefile.am,v retrieving revision 1.27 diff -u -8 -p -r1.27 Makefile.am --- backend/Makefile.am 2 May 2006 19:02:45 -0000 1.27 +++ backend/Makefile.am 28 May 2006 15:44:41 -0000 @@ -36,16 +36,18 @@ libevbackend_la_SOURCES= \ ev-document-fonts.h \ ev-document-links.c \ ev-document-links.h \ ev-document-security.c \ ev-document-security.h \ ev-document-find.c \ ev-document-find.h \ ev-document-info.h \ + ev-form.h \ + ev-form.c \ ev-ps-exporter.c \ ev-ps-exporter.h \ ev-render-context.h \ ev-render-context.c \ ev-selection.h \ ev-selection.c \ ev-document-misc.h \ ev-document-misc.c Index: backend/ev-document.c =================================================================== RCS file: /cvs/gnome/evince/backend/ev-document.c,v retrieving revision 1.35 diff -u -8 -p -r1.35 ev-document.c --- backend/ev-document.c 2 May 2006 19:02:45 -0000 1.35 +++ backend/ev-document.c 28 May 2006 15:44:41 -0000 @@ -220,16 +220,43 @@ ev_document_render_pixbuf (EvDocument LOG ("ev_document_render_pixbuf"); g_assert (iface->render_pixbuf); retval = iface->render_pixbuf (document, rc); return retval; } +GList * +ev_document_get_form_fields (EvDocument *document, + int page) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document); + GList *retval; + + LOG("ev_document_get_form_fields"); + if (iface->get_form_fields == NULL) + return NULL; + retval = iface->get_form_fields (document, page); + return retval; +} + +gboolean +ev_document_get_crop_box (EvDocument *document, int page, EvRectangle *rect) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document); + LOG("ev_document_get_crop_box"); + if (iface->get_crop_box == NULL) + return FALSE; + + iface->get_crop_box(document, page, rect); + return TRUE; + +} + void ev_document_info_free (EvDocumentInfo *info) { if (info == NULL) return; g_free (info->title); g_free (info->format); Index: backend/ev-document.h =================================================================== RCS file: /cvs/gnome/evince/backend/ev-document.h,v retrieving revision 1.34 diff -u -8 -p -r1.34 ev-document.h --- backend/ev-document.h 2 May 2006 19:02:45 -0000 1.34 +++ backend/ev-document.h 28 May 2006 15:44:42 -0000 @@ -22,16 +22,17 @@ #ifndef EV_DOCUMENT_H #define EV_DOCUMENT_H #include #include #include #include "ev-link.h" +#include "ev-form.h" #include "ev-document-info.h" #include "ev-render-context.h" G_BEGIN_DECLS #define EV_TYPE_DOCUMENT (ev_document_get_type ()) #define EV_DOCUMENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_DOCUMENT, EvDocument)) #define EV_DOCUMENT_IFACE(k) (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_DOCUMENT, EvDocumentIface)) @@ -83,21 +84,28 @@ struct _EvDocumentIface double *width, double *height); char * (* get_page_label) (EvDocument *document, int page); gboolean (* can_get_text) (EvDocument *document); char * (* get_text) (EvDocument *document, int page, EvRectangle *rect); + GList * (* get_form_fields) (EvDocument *document, + int page); + gboolean (* has_attachments) (EvDocument *document); GList * (* get_attachments) (EvDocument *document); GdkPixbuf * (* render_pixbuf) (EvDocument *document, EvRenderContext *rc); EvDocumentInfo * (* get_info) (EvDocument *document); + + void (* get_crop_box) (EvDocument *document, + int page, + EvRectangle *rect); }; GType ev_document_get_type (void); GQuark ev_document_error_quark (void); GMutex *ev_document_get_doc_mutex (void); void ev_document_doc_mutex_lock (void); void ev_document_doc_mutex_unlock (void); @@ -121,13 +129,20 @@ char *ev_document_get_text EvRectangle *rect); gboolean ev_document_has_attachments (EvDocument *document); GList *ev_document_get_attachments (EvDocument *document); GdkPixbuf *ev_document_render_pixbuf (EvDocument *document, EvRenderContext *rc); gint ev_rect_cmp (EvRectangle *a, EvRectangle *b); + +GList *ev_document_get_form_fields (EvDocument *document, + int page); + +gboolean ev_document_get_crop_box (EvDocument *document, + int page, + EvRectangle *rect); G_END_DECLS #endif Index: backend/ev-form.c =================================================================== RCS file: backend/ev-form.c diff -N backend/ev-form.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ backend/ev-form.c 28 May 2006 15:44:43 -0000 @@ -0,0 +1,402 @@ +/* -*- 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) 2005 Red Hat, Inc. + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ev-form.h" + +enum { + PROP_0, + PROP_TITLE, + PROP_TYPE, + PROP_X1, + PROP_Y1, + PROP_X2, + PROP_Y2 +}; + +struct _EvFormField { + GObject base_instance; + EvFormFieldPrivate *priv; +}; + +struct _EvFormFieldClass { + GObjectClass base_class; +}; + +struct _EvFormFieldPrivate { + char *title; + EvFormFieldType type; + gdouble x1; + gdouble y1; + gdouble x2; + gdouble y2; +}; + +G_DEFINE_TYPE (EvFormField, ev_form_field, G_TYPE_OBJECT) + +#define EV_FORM_FIELD_GET_PRIVATE(object) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_FORM_FIELD, EvFormFieldPrivate)) + +GType +ev_form_field_type_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GEnumValue values[] = { + { EV_FORM_FIELD_TYPE_BUTTON, "EV_FORM_FIELD_TYPE_TITLE", "button" }, + { EV_FORM_FIELD_TYPE_TEXT, "EV_FORM_FIELD_TYPE_TEXT", "text" }, + { EV_FORM_FIELD_TYPE_CHOICE, "EV_FORM_FIELD_TYPE_CHOICE", "choice" }, + { EV_FORM_FIELD_TYPE_SIGNATURE, "EV_FORM_FIELD_TYPE_SIGNATURE", "signature"}, + { 0, NULL, NULL } + }; + + type = g_enum_register_static ("EvFormFieldType", values); + } + + return type; +} + +const char * +ev_form_field_get_title (EvFormField *self) +{ + g_return_val_if_fail (EV_IS_FORM_FIELD (self), NULL); + + return self->priv->title; +} + + +EvFormFieldType +ev_form_field_get_form_field_type (EvFormField *self) +{ + g_return_val_if_fail (EV_IS_FORM_FIELD (self), 0); + + return self->priv->type; +} + +double +ev_form_field_get_x1 (EvFormField *field) +{ + g_return_val_if_fail (EV_IS_FORM_FIELD(field), 0); + return field->priv->x1; +} + +double +ev_form_field_get_y1 (EvFormField *field) +{ + g_return_val_if_fail (EV_IS_FORM_FIELD(field), 0); + return field->priv->y1; +} + +double +ev_form_field_get_x2 (EvFormField *field) +{ + g_return_val_if_fail (EV_IS_FORM_FIELD(field), 0); + return field->priv->x2; +} + +double +ev_form_field_get_y2 (EvFormField *field) +{ + g_return_val_if_fail (EV_IS_FORM_FIELD(field), 0); + return field->priv->y2; +} + +static void +ev_form_field_get_property (GObject *object, guint prop_id, GValue *value, + GParamSpec *param_spec) +{ + EvFormField *self; + + self = EV_FORM_FIELD (object); + + switch (prop_id) { + case PROP_TITLE: + g_value_set_string (value, self->priv->title); + break; + case PROP_TYPE: + g_value_set_enum (value, self->priv->type); + break; + case PROP_X1: + g_value_set_double (value, self->priv->x1); + break; + case PROP_Y1: + g_value_set_double (value, self->priv->y1); + break; + case PROP_X2: + g_value_set_double (value, self->priv->x2); + break; + case PROP_Y2: + g_value_set_double (value, self->priv->y2); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, + prop_id, + param_spec); + break; + } +} + +static void +ev_form_field_set_property (GObject *object, guint prop_id, const GValue *value, + GParamSpec *param_spec) +{ + EvFormField *field = EV_FORM_FIELD (object); + + switch (prop_id) { + case PROP_TITLE: + field->priv->title = g_strdup (g_value_get_string (value)); + break; + case PROP_TYPE: + field->priv->type = g_value_get_enum (value); + break; + case PROP_X1: + field->priv->x1 = g_value_get_double (value); + break; + case PROP_Y1: + field->priv->y1 = g_value_get_double (value); + break; + case PROP_X2: + field->priv->x2 = g_value_get_double (value); + break; + case PROP_Y2: + field->priv->y2 = g_value_get_double (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, + prop_id, + param_spec); + break; + } +} + +static void +ev_window_dispose (GObject *object) +{ + EvFormFieldPrivate *priv; + + g_return_if_fail (EV_IS_FORM_FIELD (object)); + + priv = EV_FORM_FIELD (object)->priv; + + if (priv->title) { + g_free (priv->title); + priv->title = NULL; + } + + G_OBJECT_CLASS (ev_form_field_parent_class)->dispose (object); +} + +static void +ev_form_field_init (EvFormField *ev_form_field) +{ + ev_form_field->priv = EV_FORM_FIELD_GET_PRIVATE (ev_form_field); +/* ev_form_field->priv->page = -1;*/ + ev_form_field->priv->type = EV_FORM_FIELD_TYPE_BUTTON; +} + +static void +ev_form_field_class_init (EvFormFieldClass *ev_window_class) +{ + GObjectClass *g_object_class; + + g_object_class = G_OBJECT_CLASS (ev_window_class); + g_object_class->dispose = ev_window_dispose; + g_object_class->set_property = ev_form_field_set_property; + g_object_class->get_property = ev_form_field_get_property; + + g_type_class_add_private (g_object_class, sizeof (EvFormFieldPrivate)); + + g_object_class_install_property (g_object_class, + PROP_TITLE, + g_param_spec_string ("title", + "Form Field Title", + "The form field title", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (g_object_class, + PROP_TYPE, + g_param_spec_enum ("type", + "Form Field Type", + "The form field type", + EV_TYPE_FORM_FIELD_TYPE, + EV_FORM_FIELD_TYPE_BUTTON, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (g_object_class, + PROP_X1, + g_param_spec_double ("x1", + "Bounding rect x1 coord", + "The x1 coord of bounding rect", + -G_MAXDOUBLE, + G_MAXDOUBLE, + 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (g_object_class, + PROP_Y1, + g_param_spec_double ("y1", + "Bounding rect y1 coord", + "The y1 coord of bounding rect", + -G_MAXDOUBLE, + G_MAXDOUBLE, + 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (g_object_class, + PROP_X2, + g_param_spec_double ("x2", + "Bounding rect x2 coord", + "The x2 coord of bounding rect", + -G_MAXDOUBLE, + G_MAXDOUBLE, + 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (g_object_class, + PROP_Y2, + g_param_spec_double ("y2", + "Bounding rect y2 coord", + "The y2 coord of bounding rect", + -G_MAXDOUBLE, + G_MAXDOUBLE, + 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); +} + +EvFormField * +ev_form_field_new_button (const char *title, + gdouble px1, + gdouble py1, + gdouble px2, + gdouble py2) +{ + return EV_FORM_FIELD (g_object_new (EV_TYPE_FORM_FIELD, + "title", title, + "type", EV_FORM_FIELD_TYPE_BUTTON, + "x1", px1, + "y1", py1, + "x2", px2, + "y2", py2, + NULL)); +} + +EvFormField * +ev_form_field_new_text (const char *title, + gdouble px1, + gdouble py1, + gdouble px2, + gdouble py2) +{ + return EV_FORM_FIELD (g_object_new (EV_TYPE_FORM_FIELD, + "title", title, + "type", EV_FORM_FIELD_TYPE_TEXT, + "x1", px1, + "y1", py1, + "x2", px2, + "y2", py2, + NULL)); +} + +EvFormField * +ev_form_field_new_choice (const char *title, + gdouble px1, + gdouble py1, + gdouble px2, + gdouble py2) +{ + return EV_FORM_FIELD (g_object_new (EV_TYPE_FORM_FIELD, + "title", title, + "type", EV_FORM_FIELD_TYPE_CHOICE, + "x1", px1, + "y1", py1, + "x2", px2, + "y2", py2, + NULL)); +} + +EvFormField * +ev_form_field_new_signature (const char *title, + gdouble px1, + gdouble py1, + gdouble px2, + gdouble py2) +{ + return EV_FORM_FIELD (g_object_new (EV_TYPE_FORM_FIELD, + "title", title, + "type", EV_FORM_FIELD_TYPE_SIGNATURE, + "x1", px1, + "y1", py1, + "x2", px2, + "y2", py2, + NULL)); +} + +static void +ev_form_field_mapping_free_foreach (EvFormFieldMapping *form_field_mapping) +{ + g_object_unref (G_OBJECT (form_field_mapping->field)); + g_free (form_field_mapping); +} + +void +ev_form_field_mapping_free (GList *form_field_mapping) +{ + if (form_field_mapping == NULL) + return; + + g_list_foreach (form_field_mapping, (GFunc) (ev_form_field_mapping_free_foreach), NULL); + g_list_free (form_field_mapping); +} + + +EvFormField * +ev_form_field_mapping_find (GList *form_field_mapping, + gdouble x, + gdouble y) +{ + GList *list; + EvFormField *field = NULL; + int i; + + i = 0; + + for (list = form_field_mapping; list; list = list->next) { + EvFormFieldMapping *mapping = list->data; + + i++; + if ((x >= mapping->x1) && + (y >= mapping->y1) && + (x <= mapping->x2) && + (y <= mapping->y2)) { + field = mapping->field; + break; + } + } + + return field; +} + Index: backend/ev-form.h =================================================================== RCS file: backend/ev-form.h diff -N backend/ev-form.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ backend/ev-form.h 28 May 2006 15:44:43 -0000 @@ -0,0 +1,100 @@ +/* this file is part of evince, a gnome document viewer + * + * Copyright (C) 2005 Red Hat, Inc. + * 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_H +#define EV_FORM_H + +#include + +G_BEGIN_DECLS + +typedef struct _EvFormField EvFormField; +typedef struct _EvFormFieldClass EvFormFieldClass; +typedef struct _EvFormFieldPrivate EvFormFieldPrivate; + +#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_CHACK_CLASS_CAST((klass), EV_TYPE_FORM_FIELD, EvFormField)) +#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_LINK, EvLinkClass)) + +#define EV_TYPE_FORM_FIELD_TYPE (ev_form_field_type_get_type ()) + + + +typedef enum +{ + EV_FORM_FIELD_TYPE_BUTTON, + EV_FORM_FIELD_TYPE_TEXT, + EV_FORM_FIELD_TYPE_CHOICE, + EV_FORM_FIELD_TYPE_SIGNATURE +} EvFormFieldType; + +GType ev_form_field_type_get_type (void); +GType ev_form_field_get_type (void); + +EvFormField *ev_form_field_new_button (const char *title, + gdouble px1, + gdouble py1, + gdouble px2, + gdouble py2); +EvFormField *ev_form_field_new_text (const char *title, + gdouble px1, + gdouble py1, + gdouble px2, + gdouble py2); +EvFormField *ev_form_field_new_choice (const char *title, + gdouble px1, + gdouble py1, + gdouble px2, + gdouble py2); +EvFormField *ev_form_field_new_signature (const char *title, + gdouble px1, + gdouble py1, + gdouble px2, + gdouble py2); + +const char* ev_form_field_get_title (EvFormField *field); +EvFormFieldType ev_form_field_get_form_field_type (EvFormField *field); +double ev_form_field_get_x1 (EvFormField *field); +double ev_form_field_get_y1 (EvFormField *field); +double ev_form_field_get_x2 (EvFormField *field); +double ev_form_field_get_y2 (EvFormField *field); + + +/* Form 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 *form_field_mapping); +EvFormField *ev_form_field_mapping_find (GList *form_field_mapping, + gdouble x, + gdouble y); +G_END_DECLS + +#endif /* !EV_FORM_H */ Index: pdf/ev-poppler.cc =================================================================== RCS file: /cvs/gnome/evince/pdf/ev-poppler.cc,v retrieving revision 1.69 diff -u -8 -p -r1.69 ev-poppler.cc --- pdf/ev-poppler.cc 9 May 2006 18:00:47 -0000 1.69 +++ pdf/ev-poppler.cc 28 May 2006 15:44:48 -0000 @@ -615,28 +615,92 @@ pdf_document_get_text (EvDocument *docum text = poppler_page_get_text (poppler_page, &r); g_object_unref (poppler_page); return text; } +static GList * +pdf_document_get_form_fields (EvDocument *document, + int page) +{ + PdfDocument *pdf_document; + PopplerPage *poppler_page; + GList *retval = NULL; + GList *fields; + GList *list; + double height; + printf("pdf_document_get_form_fields\n"); + + pdf_document = PDF_DOCUMENT (document); + poppler_page = poppler_document_get_page (pdf_document->document, + page); + fields = poppler_page_get_form_fields (poppler_page); + poppler_page_get_size (poppler_page, NULL, &height); + + for (list = fields; list; list = list->next) { + PopplerFormField *field; + EvFormFieldMapping *ev_form_field; + double rect[4]; + + field = (PopplerFormField *)list->data; + /* Invert y for X-style coordinates */ + rect[0] = field->area.x1; rect[1] = height - field->area.y2; + rect[2] = field->area.x2; rect[3] = height - field->area.y1; + + ev_form_field = g_new (EvFormFieldMapping, 1); + ev_form_field->field = ev_form_field_new_button("test",rect[0],rect[1],rect[2],rect[3]); + ev_form_field->x1 = rect[0]; + ev_form_field->x2 = rect[2]; + ev_form_field->y1 = rect[1]; + ev_form_field->y2 = rect[3]; + + retval = g_list_prepend(retval, ev_form_field); + } + poppler_page_free_form_fields(fields); + g_object_unref (poppler_page); + + return g_list_reverse(retval); +} + +void +pdf_document_get_crop_box (EvDocument *document, + int page, + EvRectangle *rect) +{ + PdfDocument *pdf_document; + PopplerPage *poppler_page; + PopplerRectangle poppler_rect; + + printf("pdf_document_get_crop_box\n"); + 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; +} + static void pdf_document_document_iface_init (EvDocumentIface *iface) { iface->save = pdf_document_save; iface->load = pdf_document_load; iface->get_n_pages = pdf_document_get_n_pages; iface->get_page_size = pdf_document_get_page_size; iface->get_page_label = pdf_document_get_page_label; iface->has_attachments = pdf_document_has_attachments; iface->get_attachments = pdf_document_get_attachments; iface->render_pixbuf = pdf_document_render_pixbuf; iface->get_text = pdf_document_get_text; + iface->get_form_fields = pdf_document_get_form_fields; + iface->get_crop_box = pdf_document_get_crop_box; iface->can_get_text = pdf_document_can_get_text; iface->get_info = pdf_document_get_info; }; static void pdf_document_security_iface_init (EvDocumentSecurityIface *iface) { iface->has_document_security = pdf_document_has_document_security; @@ -1496,8 +1560,11 @@ pdf_selection_iface_init (EvSelectionIfa iface->get_selection_map = pdf_selection_get_selection_map; } PdfDocument * pdf_document_new (void) { return PDF_DOCUMENT (g_object_new (PDF_TYPE_DOCUMENT, NULL)); } + + + Index: shell/ev-jobs.c =================================================================== RCS file: /cvs/gnome/evince/shell/ev-jobs.c,v retrieving revision 1.16 diff -u -8 -p -r1.16 ev-jobs.c --- shell/ev-jobs.c 28 May 2006 11:14:38 -0000 1.16 +++ shell/ev-jobs.c 28 May 2006 15:44:49 -0000 @@ -208,16 +208,17 @@ ev_job_links_run (EvJobLinks *job) EvJob * ev_job_render_new (EvDocument *document, EvRenderContext *rc, gint width, gint height, EvRectangle *selection_points, GdkColor *text, GdkColor *base, + gboolean include_form, gboolean include_links, gboolean include_text, gboolean include_selection) { EvJobRender *job; g_return_val_if_fail (EV_IS_RENDER_CONTEXT (rc), NULL); if (include_selection) @@ -226,16 +227,17 @@ ev_job_render_new (EvDocument *docu job = g_object_new (EV_TYPE_JOB_RENDER, NULL); EV_JOB (job)->document = g_object_ref (document); job->rc = g_object_ref (rc); job->target_width = width; job->target_height = height; job->text = *text; job->base = *base; + job->include_form = include_form; job->include_links = include_links; job->include_text = include_text; job->include_selection = include_selection; if (include_selection) job->selection_points = *selection_points; if (EV_IS_ASYNC_RENDERER (document)) { @@ -266,16 +268,19 @@ ev_job_render_run (EvJobRender *job) if (EV_JOB (job)->async) { EvAsyncRenderer *renderer = EV_ASYNC_RENDERER (EV_JOB (job)->document); ev_async_renderer_render_pixbuf (renderer, job->rc->page, job->rc->scale, job->rc->rotation); g_signal_connect (EV_JOB (job)->document, "render_finished", G_CALLBACK (render_finished_cb), job); } else { job->pixbuf = ev_document_render_pixbuf (EV_JOB (job)->document, job->rc); + if (job->include_form) + job->form_field_mapping = + ev_document_get_form_fields (EV_JOB (job)->document, job->rc->page); 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), 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), job->rc); Index: shell/ev-jobs.h =================================================================== RCS file: /cvs/gnome/evince/shell/ev-jobs.h,v retrieving revision 1.11 diff -u -8 -p -r1.11 ev-jobs.h --- shell/ev-jobs.h 2 Apr 2006 23:24:26 -0000 1.11 +++ shell/ev-jobs.h 28 May 2006 15:44:50 -0000 @@ -111,23 +111,25 @@ struct _EvJobRender EvRenderContext *rc; gint target_width; gint target_height; GdkPixbuf *pixbuf; GList *link_mapping; GdkRegion *text_mapping; + GList *form_field_mapping; GdkPixbuf *selection; GdkRegion *selection_region; EvRectangle selection_points; GdkColor base; GdkColor text; - + + gint include_form : 1; gint include_links : 1; gint include_text : 1; gint include_selection : 1; }; struct _EvJobRenderClass { EvJobClass parent_class; @@ -185,16 +187,17 @@ void ev_job_links_run GType ev_job_render_get_type (void); EvJob *ev_job_render_new (EvDocument *document, EvRenderContext *rc, gint width, gint height, EvRectangle *selection_points, GdkColor *text, GdkColor *base, + gboolean include_form, gboolean include_links, gboolean include_text, gboolean include_selection); void ev_job_render_run (EvJobRender *thumbnail); /* EvJobThumbnail */ GType ev_job_thumbnail_get_type (void); EvJob *ev_job_thumbnail_new (EvDocument *document, Index: shell/ev-pixbuf-cache.c =================================================================== RCS file: /cvs/gnome/evince/shell/ev-pixbuf-cache.c,v retrieving revision 1.22 diff -u -8 -p -r1.22 ev-pixbuf-cache.c --- shell/ev-pixbuf-cache.c 7 Jan 2006 13:18:28 -0000 1.22 +++ shell/ev-pixbuf-cache.c 28 May 2006 15:44:52 -0000 @@ -7,26 +7,28 @@ typedef struct _CacheJobInfo { EvJob *job; EvRenderContext *rc; /* Data we get from rendering */ GdkPixbuf *pixbuf; GList *link_mapping; GdkRegion *text_mapping; + GList *form_field_mapping; /* Selection data. * Selection_points are the coordinates encapsulated in selection. * target_points is the target selection size. */ EvRectangle selection_points; EvRectangle target_points; gboolean points_set; GdkPixbuf *selection; GdkRegion *selection_region; + } CacheJobInfo; struct _EvPixbufCache { GObject parent; /* We keep a link to our containing view just for style information. */ GtkWidget *view; @@ -143,16 +145,20 @@ dispose_cache_job_info (CacheJobInfo *jo ev_job_queue_remove_job (job_info->job); g_object_unref (G_OBJECT (job_info->job)); job_info->job = NULL; } if (job_info->pixbuf) { g_object_unref (G_OBJECT (job_info->pixbuf)); job_info->pixbuf = 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->link_mapping) { ev_link_mapping_free (job_info->link_mapping); job_info->link_mapping = NULL; } if (job_info->text_mapping) { gdk_region_destroy (job_info->text_mapping); job_info->text_mapping = NULL; } @@ -307,16 +313,17 @@ move_one_job (CacheJobInfo *job_info, new_priority = EV_JOB_PRIORITY_HIGH; target_page = new_job_list + page_offset; } *target_page = *job_info; job_info->job = NULL; job_info->pixbuf = NULL; job_info->link_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); } } @@ -386,16 +393,17 @@ ev_pixbuf_cache_update_range (EvPixbufCa pixbuf_cache->job_list = new_job_list; pixbuf_cache->prev_job = new_prev_job; pixbuf_cache->next_job = new_next_job; pixbuf_cache->start_page = start_page; pixbuf_cache->end_page = end_page; } + static void copy_job_to_job_info (EvJobRender *job_render, CacheJobInfo *job_info, EvPixbufCache *pixbuf_cache) { GdkPixbuf *pixbuf; EvRenderContext *rc; @@ -405,17 +413,19 @@ copy_job_to_job_info (EvJobRender *job dispose_cache_job_info (job_info, pixbuf_cache); job_info->pixbuf = pixbuf; job_info->rc = rc; if (job_render->link_mapping) job_info->link_mapping = job_render->link_mapping; if (job_render->text_mapping) - job_info->text_mapping = job_render->text_mapping; + job_info->text_mapping = job_render->text_mapping; + if (job_render->form_field_mapping) + job_info->form_field_mapping = job_render->form_field_mapping; if (job_render->include_selection) { pixbuf = g_object_ref (job_render->selection); job_info->selection_points = job_render->selection_points; job_info->selection_region = gdk_region_copy (job_render->selection_region); job_info->selection = pixbuf; g_assert (job_info->selection_points.x1 >= 0); } @@ -492,16 +502,17 @@ static void add_job_if_needed (EvPixbufCache *pixbuf_cache, CacheJobInfo *job_info, EvPageCache *page_cache, gint page, gint rotation, gfloat scale, EvJobPriority priority) { + gboolean include_form = FALSE; gboolean include_links = FALSE; gboolean include_text = FALSE; gboolean include_selection = FALSE; int width, height; GdkColor *text, *base; if (job_info->job) return; @@ -519,16 +530,18 @@ add_job_if_needed (EvPixbufCache *pixbuf 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->form_field_mapping == NULL) + include_form = TRUE; if (job_info->link_mapping == NULL) include_links = TRUE; if (job_info->text_mapping == NULL) include_text = TRUE; if (new_selection_pixbuf_needed (pixbuf_cache, job_info, page, scale)) { include_selection = TRUE; } @@ -536,16 +549,17 @@ add_job_if_needed (EvPixbufCache *pixbuf 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_form, include_links, 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); } @@ -656,16 +670,34 @@ ev_pixbuf_cache_get_link_mapping (EvPixb /* We don't need to wait for the idle to handle the callback */ 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->link_mapping; } + +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; +} + static gboolean new_selection_pixbuf_needed (EvPixbufCache *pixbuf_cache, CacheJobInfo *job_info, gint page, gfloat scale) { EvPageCache *page_cache; Index: shell/ev-pixbuf-cache.h =================================================================== RCS file: /cvs/gnome/evince/shell/ev-pixbuf-cache.h,v retrieving revision 1.9 diff -u -8 -p -r1.9 ev-pixbuf-cache.h --- shell/ev-pixbuf-cache.h 6 Aug 2005 05:13:20 -0000 1.9 +++ shell/ev-pixbuf-cache.h 28 May 2006 15:44:52 -0000 @@ -58,16 +58,18 @@ void ev_pixbuf_cache_set_page_ gfloat scale, GList *selection_list); GdkPixbuf *ev_pixbuf_cache_get_pixbuf (EvPixbufCache *pixbuf_cache, gint page); GList *ev_pixbuf_cache_get_link_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); /* Selection */ GdkPixbuf *ev_pixbuf_cache_get_selection_pixbuf (EvPixbufCache *pixbuf_cache, gint page, gfloat scale, GdkRegion **region); Index: shell/ev-view-private.h =================================================================== RCS file: /cvs/gnome/evince/shell/ev-view-private.h,v retrieving revision 1.9 diff -u -8 -p -r1.9 ev-view-private.h --- shell/ev-view-private.h 4 May 2006 08:24:19 -0000 1.9 +++ shell/ev-view-private.h 28 May 2006 15:44:53 -0000 @@ -52,17 +52,18 @@ typedef enum { EV_VIEW_CURSOR_IBEAM, EV_VIEW_CURSOR_LINK, EV_VIEW_CURSOR_WAIT, EV_VIEW_CURSOR_HIDDEN, EV_VIEW_CURSOR_DRAG } EvViewCursor; struct _EvView { - GtkWidget parent_instance; + //GtkWidget parent_instance; + GtkContainer parent_instance; EvDocument *document; char *status; char *find_status; int find_result; gboolean jump_to_find_result; @@ -111,20 +112,27 @@ struct _EvView { guint selection_scroll_id; EvViewSelectionMode selection_mode; SelectionInfo selection_info; /* Links */ GtkWidget *link_tooltip; EvLink *hovered_link; + + /* Container */ + gint current_width; + gint current_height; + GList *children; + GList *field_widgets; }; struct _EvViewClass { - GtkWidgetClass parent_class; + //GtkWidgetClass parent_class; + GtkContainerClass parent_class; void (*set_scroll_adjustments) (EvView *view, GtkAdjustment *hadjustment, GtkAdjustment *vadjustment); void (*binding_activated) (EvView *view, EvScrollType scroll, gboolean horizontal); void (*zoom_invalid) (EvView *view); Index: shell/ev-view.c =================================================================== RCS file: /cvs/gnome/evince/shell/ev-view.c,v retrieving revision 1.207 diff -u -8 -p -r1.207 ev-view.c --- shell/ev-view.c 27 May 2006 13:00:31 -0000 1.207 +++ shell/ev-view.c 28 May 2006 15:45:03 -0000 @@ -36,16 +36,17 @@ #include "ev-document-links.h" #include "ev-document-find.h" #include "ev-document-misc.h" #include "ev-debug.h" #include "ev-job-queue.h" #include "ev-page-cache.h" #include "ev-pixbuf-cache.h" #include "ev-tooltip.h" +#include "ev-debug.h" #define EV_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_VIEW, EvViewClass)) #define EV_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_VIEW)) #define EV_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_VIEW, EvViewClass)) enum { PROP_0, @@ -57,16 +58,22 @@ enum { PROP_PRESENTATION, PROP_SIZING_MODE, PROP_ZOOM, PROP_ROTATION, PROP_HAS_SELECTION, }; enum { + CHILD_PROP_0, + CHILD_PROP_X, + CHILD_PROP_Y +}; + +enum { SIGNAL_BINDING_ACTIVATED, SIGNAL_ZOOM_INVALID, SIGNAL_EXTERNAL_LINK, SIGNAL_POPUP_MENU, N_SIGNALS, }; enum { @@ -86,16 +93,24 @@ static const GtkTargetEntry targets[] = static guint signals[N_SIGNALS]; typedef enum { EV_VIEW_FIND_NEXT, EV_VIEW_FIND_PREV } EvViewFindDirection; +typedef struct _EvViewChild EvViewChild; + +struct _EvViewChild { + GtkWidget *widget; + gint x; + gint y; +}; + #define ZOOM_IN_FACTOR 1.2 #define ZOOM_OUT_FACTOR (1.0/ZOOM_IN_FACTOR) #define MIN_SCALE 0.05409 #define MAX_SCALE 4.0 #define SCROLL_TIME 150 @@ -155,16 +170,24 @@ static gboolean doc_point_to_view_point 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); +static void handle_form_field_over_xy (EvView* view, + gint x, + gint y); /*** GtkWidget implementation ***/ static void ev_view_size_request_continuous_dual_page (EvView *view, GtkRequisition *requisition); static void ev_view_size_request_continuous (EvView *view, GtkRequisition *requisition); static void ev_view_size_request_dual_page (EvView *view, GtkRequisition *requisition); static void ev_view_size_request_single_page (EvView *view, @@ -307,17 +330,62 @@ static void ev_view_primary_get_cb GtkSelectionData *selection_data, guint info, gpointer data); static void ev_view_primary_clear_cb (GtkClipboard *clipboard, gpointer data); static void ev_view_update_primary_selection (EvView *ev_view); -G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_WIDGET) +/*** Container ***/ +static void ev_view_map (GtkWidget *widget); + +static void ev_view_add (GtkContainer *cont, + GtkWidget *widget); + +static void ev_view_remove (GtkContainer *cont, + GtkWidget *widget); + +static void ev_view_put (EvView *view, + GtkWidget *widget, + gint x, + gint y); + +static void ev_view_forall (GtkContainer *cont, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); + +static void ev_view_set_child_property (GtkContainer *cont, + GtkWidget *child, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void ev_view_get_child_property (GtkContainer *cont, + GtkWidget *child, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static void ev_view_allocate_child (EvView *view, + EvViewChild *child); +static void ev_view_move_internal (EvView *view, + GtkWidget *widget, + gboolean change_x, + gint x, + gboolean change_y, + gint y); + +/*** Form fields ***/ +static void form_field_widgets_clean_and_add (EvView *view); + + +//G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_WIDGET) +G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_CONTAINER) static void scroll_to_current_page (EvView *view, GtkOrientation orientation) { GdkPoint view_point; if (view->document == NULL) { return; @@ -422,16 +490,19 @@ view_set_adjustment_values (EvView gtk_adjustment_changed (adjustment); } static void view_update_range_and_current_page (EvView *view) { gint current_page; gint best_current_page = -1; + static int form_field_block = 0; + gint initial_start_page = view->start_page; + gint initial_end_page = view->end_page; if (view->pending_scroll != SCROLL_TO_KEEP_POSITION) return; /* Presentation trumps all other modes */ if (view->presentation) { view->start_page = view->current_page; view->end_page = view->current_page; @@ -439,17 +510,17 @@ view_update_range_and_current_page (EvVi GdkRectangle current_area, unused, page_area; GtkBorder border; gboolean found = FALSE; gint area_max = -1, area; int i; if (!(view->vadjustment && view->hadjustment)) return; - + current_area.x = view->hadjustment->value; current_area.width = view->hadjustment->upper; current_area.y = view->vadjustment->value; current_area.height = view->vadjustment->page_size; for (i = 0; i < ev_page_cache_get_n_pages (view->page_cache); i++) { get_page_extents (view, i, &page_area, &border); @@ -496,16 +567,21 @@ view_update_range_and_current_page (EvVi best_current_page = MAX (best_current_page, view->start_page); current_page = ev_page_cache_get_current_page (view->page_cache); if (current_page != best_current_page) { view->current_page = best_current_page; ev_page_cache_set_current_page (view->page_cache, best_current_page); } + if (view->start_page != initial_start_page || view->end_page != initial_end_page) { + + form_field_widgets_clean_and_add (view); + } + ev_pixbuf_cache_set_page_range (view->pixbuf_cache, view->start_page, view->end_page, view->rotation, view->scale, view->selection_info.selections); } @@ -1441,16 +1517,83 @@ handle_link_over_xy (EvView *view, gint ev_view_set_status (view, NULL); if (view->cursor == EV_VIEW_CURSOR_LINK || view->cursor == EV_VIEW_CURSOR_IBEAM) ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL); } return; } +/*** Form ***/ +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; + GList *form_field_mapping; + + 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; + + form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, page); + + if (form_field_mapping) + return ev_form_field_mapping_find (form_field_mapping, x_offset / view->scale, y_offset / view->scale); + else + return NULL; +} + + +static void +handle_form_field_over_xy (EvView *view, gint x, gint y) +{ + EvFormField *field; + //static GtkWidget *button = NULL; + + field = ev_view_get_form_field_at_location (view, x, y); + if(field) { + /*double v[4]; + GdkPoint d[2]; + EvPoint p[2]; + gint page = -1; + gint x_offset = 0, y_offset = 0;*/ + + ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK); + /*p[0].x = ev_form_field_get_x1(field); + p[0].y = ev_form_field_get_y1(field); + p[1].x = ev_form_field_get_x2(field); + p[1].y = ev_form_field_get_y2(field); + + find_page_at_location(view, p[0].x, p[0].y, &page, &x_offset, &y_offset); + if(page < 0) + return; + doc_point_to_view_point(view, page,&p[0], &d[0]); + doc_point_to_view_point(view, page,&p[1], &d[1]); + + v[0] = d[0].x - view->scroll_x; v[1] = d[0].y - view->scroll_y; + v[2] = d[1].x - view->scroll_x; v[3] = d[1].y - view->scroll_y; + //display the field's bounding rectangle +#define LINE(x1,y1,x2,y2) gdk_draw_line(GTK_WIDGET(view)->window, GTK_WIDGET(view)->style->fg_gc[GTK_STATE_NORMAL],x1,y1,x2,y2) + LINE(v[0], v[1], v[2], v[1]); + LINE(v[2], v[1], v[2], v[3]); + LINE(v[2], v[3], v[0], v[3]); + LINE(v[0], v[3], v[0], v[1]);*/ + + } else { + ev_view_set_cursor(view, EV_VIEW_CURSOR_NORMAL); + } +} + /*** GtkWidget implementation ***/ static void ev_view_size_request_continuous_dual_page (EvView *view, GtkRequisition *requisition) { int max_width; gint n_pages; @@ -1568,44 +1711,71 @@ ev_view_size_request_single_page (EvView } } static void ev_view_size_request (GtkWidget *widget, GtkRequisition *requisition) { EvView *view = EV_VIEW (widget); + GList *tmp_list; if (view->document == NULL) { requisition->width = 1; requisition->height = 1; return; } if (view->presentation) { requisition->width = 1; requisition->height = 1; return; } + + tmp_list = view->children; + while (tmp_list) { + EvViewChild *child = tmp_list->data; + GtkRequisition child_requisition; + + tmp_list = tmp_list->next; + gtk_widget_size_request (child->widget, &child_requisition); + } + + //printf("%i %i => requested : %i %i\n", view->current_width, view->current_height, requisition->width, requisition->height); + if(!(requisition->width == view->current_width && requisition->height == view->current_height)) { + //printf("call to form_field_widgets\n"); + form_field_widgets_clean_and_add(view); + } + view->current_width = requisition->width; + view->current_height = requisition->height; if (view->continuous && view->dual_page) ev_view_size_request_continuous_dual_page (view, requisition); else if (view->continuous) ev_view_size_request_continuous (view, requisition); else if (view->dual_page) ev_view_size_request_dual_page (view, requisition); else ev_view_size_request_single_page (view, requisition); } static void ev_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { EvView *view = EV_VIEW (widget); + GList *tmp_list; + + tmp_list = view->children; + while (tmp_list) { + EvViewChild *child = tmp_list->data; + tmp_list = tmp_list->next; + + ev_view_allocate_child(view, child); + } if (view->sizing_mode == EV_SIZING_FIT_WIDTH || view->sizing_mode == EV_SIZING_BEST_FIT) { g_signal_emit (view, signals[SIGNAL_ZOOM_INVALID], 0); ev_view_size_request (widget, &widget->requisition); } @@ -1622,16 +1792,17 @@ ev_view_size_allocate (GtkWidget *w GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation); } static void ev_view_realize (GtkWidget *widget) { EvView *view = EV_VIEW (widget); GdkWindowAttr attributes; + GList *tmp_list; 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); @@ -1657,16 +1828,24 @@ ev_view_realize (GtkWidget *widget) GDK_WA_VISUAL); gdk_window_set_user_data (widget->window, widget); widget->style = gtk_style_attach (widget->style, widget->window); if (view->presentation) gdk_window_set_background (widget->window, &widget->style->black); else gdk_window_set_background (widget->window, &widget->style->mid [GTK_STATE_NORMAL]); + + tmp_list = view->children; + while (tmp_list) { + EvViewChild *child = tmp_list->data; + tmp_list = tmp_list->next; + + gtk_widget_set_parent_window (child->widget, GTK_WIDGET(view)->window); + } } static gboolean ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event) { EvView *view = EV_VIEW (widget); guint state; @@ -1736,16 +1915,17 @@ find_selection_for_page (EvView *view, if (selection->page == page) return selection; } return NULL; } + static gboolean ev_view_expose_event (GtkWidget *widget, GdkEventExpose *event) { EvView *view = EV_VIEW (widget); int i; if (view->loading) { @@ -1773,17 +1953,17 @@ ev_view_expose_event (GtkWidget *wi page_area.x -= view->scroll_x; page_area.y -= view->scroll_y; draw_one_page (view, i, &page_area, &border, &(event->area), &page_ready); if (page_ready && EV_IS_DOCUMENT_FIND (view->document)) highlight_find_results (view, i); } - + (* GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event) (widget, event); return FALSE; } static gboolean ev_view_popup_menu (GtkWidget *widget) { gint x, y; EvLink *link; @@ -2014,16 +2194,17 @@ ev_view_motion_notify_event (GtkWidget return TRUE; } /* For the Evince 0.4.x release, we limit links to un-rotated documents * only. */ } else if (view->pressed_button <= 0 && view->rotation == 0) { handle_link_over_xy (view, x, y); + handle_form_field_over_xy (view, x, y); return TRUE; } return FALSE; } static gboolean ev_view_button_release_event (GtkWidget *widget, @@ -2273,17 +2454,17 @@ draw_one_page (EvView *view, gboolean *page_ready) { gint width, height; GdkPixbuf *current_pixbuf; GdkRectangle overlap; GdkRectangle real_page_area; EvViewSelection *selection; gint current_page; - + g_assert (view->document); if (! gdk_rectangle_intersect (page_area, expose_area, &overlap)) return; current_page = ev_page_cache_get_current_page (view->page_cache); selection = find_selection_for_page (view, page); ev_page_cache_get_size (view->page_cache, @@ -2377,17 +2558,17 @@ draw_one_page (EvView *view, /*** GObject functions ***/ static void ev_view_finalize (GObject *object) { EvView *view = EV_VIEW (object); - LOG ("Finalize"); +// LOG ("Finalize"); g_free (view->status); g_free (view->find_status); clear_selection (view); G_OBJECT_CLASS (ev_view_parent_class)->finalize (object); } @@ -2537,23 +2718,28 @@ ev_view_get_property (GObject *object, } } static void ev_view_class_init (EvViewClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (class); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); GtkBindingSet *binding_set; object_class->finalize = ev_view_finalize; object_class->set_property = ev_view_set_property; object_class->get_property = ev_view_get_property; + container_class->set_child_property = ev_view_set_child_property; + container_class->get_child_property = ev_view_get_child_property; + + widget_class->map = ev_view_map; widget_class->expose_event = ev_view_expose_event; widget_class->button_press_event = ev_view_button_press_event; widget_class->motion_notify_event = ev_view_motion_notify_event; widget_class->button_release_event = ev_view_button_release_event; widget_class->focus_in_event = ev_view_focus_in; widget_class->focus_out_event = ev_view_focus_out; widget_class->get_accessible = ev_view_get_accessible; widget_class->size_request = ev_view_size_request; @@ -2562,16 +2748,20 @@ ev_view_class_init (EvViewClass *class) widget_class->scroll_event = ev_view_scroll_event; widget_class->enter_notify_event = ev_view_enter_notify_event; widget_class->leave_notify_event = ev_view_leave_notify_event; widget_class->style_set = ev_view_style_set; widget_class->drag_data_get = ev_view_drag_data_get; widget_class->popup_menu = ev_view_popup_menu; gtk_object_class->destroy = ev_view_destroy; + container_class->add = ev_view_add; + container_class->remove = ev_view_remove; + container_class->forall = ev_view_forall; + 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), @@ -2610,16 +2800,36 @@ ev_view_class_init (EvViewClass *class) G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (EvViewClass, popup_menu), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); + gtk_container_class_install_child_property (container_class, + CHILD_PROP_X, + g_param_spec_int ("x", + "X position", + "X position of child widget", + G_MININT, + G_MAXINT, + 0, + G_PARAM_READWRITE)); + + gtk_container_class_install_child_property (container_class, + CHILD_PROP_Y, + g_param_spec_int ("y", + "Y position", + "Y position of child widget", + G_MININT, + G_MAXINT, + 0, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_STATUS, g_param_spec_string ("status", "Status Message", "The status message", NULL, G_PARAM_READABLE)); @@ -2707,17 +2917,21 @@ ev_view_class_init (EvViewClass *class) add_scroll_binding_keypad (binding_set, GDK_Up, GDK_MOD1_MASK, EV_SCROLL_STEP_DOWN, FALSE); add_scroll_binding_keypad (binding_set, GDK_Down, GDK_MOD1_MASK, EV_SCROLL_STEP_UP, FALSE); } static void ev_view_init (EvView *view) { GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS); - + + view->current_width = 0; + view->current_height = 0; + view->children = NULL; + view->field_widgets = NULL; view->spacing = 5; view->scale = 1.0; view->current_page = 0; view->pressed_button = -1; view->cursor = EV_VIEW_CURSOR_NORMAL; view->drag_info.in_drag = FALSE; view->selection_info.selections = NULL; view->selection_info.in_selection = FALSE; @@ -2727,16 +2941,170 @@ ev_view_init (EvView *view) view->dual_page = FALSE; view->presentation = FALSE; view->fullscreen = FALSE; view->sizing_mode = EV_SIZING_FIT_WIDTH; view->pending_scroll = SCROLL_TO_KEEP_POSITION; view->jump_to_find_result = TRUE; } +static void remove_field_widget (gpointer data, gpointer user_data) +{ + g_return_if_fail(GTK_IS_CONTAINER(user_data)); + g_return_if_fail(GTK_IS_WIDGET(data)); + ev_view_remove(GTK_CONTAINER(user_data), GTK_WIDGET(data)); +} + +static void field_inc_count (gpointer data, gpointer user_data) +{ + int* count = (int*)user_data; + (*count)++; +} + + +static void +form_field_widgets_clean_and_add (EvView *view) +{ + int count = 0; + GList *form_field_mapping; + GList *tmp_list; + gint page_count = 0; + + if (view->field_widgets) { + g_list_foreach(view->field_widgets, (GFunc)field_inc_count, &count); + g_list_foreach(view->field_widgets, (GFunc)remove_field_widget, GTK_CONTAINER(view)); + view->field_widgets = NULL; + } + printf("- removed %i widgets\n", count); + printf(" range : %i -> %i\n", view->start_page, view->end_page); + count = 0; + for (page_count = view->start_page; page_count <= view->end_page; page_count++) { + EvRectangle crop_box; + gboolean has_crop; + + has_crop = ev_document_get_crop_box(view->document, page_count, &crop_box); + + form_field_mapping = ev_pixbuf_cache_get_form_field_mapping(view->pixbuf_cache, page_count); + if (form_field_mapping == NULL) { + printf("form_field_mapping == NULL -> skipping\n"); + continue; + } + + tmp_list = form_field_mapping; + while (tmp_list) { + EvFormFieldMapping *mapping = tmp_list->data; + EvFormField *field; + GtkWidget *wid; + EvPoint p[2]; + GdkPoint d[2]; + gint v[4]; + + tmp_list = tmp_list->next; + + field = mapping->field; + //printf("field : %i\n", ev_form_field_get_form_field_type(field)); + p[0].x = ev_form_field_get_x1(field); + p[0].y = ev_form_field_get_y1(field); + p[1].x = ev_form_field_get_x2(field); + p[1].y = ev_form_field_get_y2(field); + if(has_crop) { + p[0].x -= crop_box.x1; + p[0].y += crop_box.y1; + p[1].x -= crop_box.x1; + p[1].y += crop_box.y1; + } + + doc_point_to_view_point(view, page_count/*view->current_page*/, &p[0], &d[0]); + doc_point_to_view_point(view, page_count/*view->current_page*/, &p[1], &d[1]); + /*printf("\nd[0]: %i, %i\n", d[0].x, d[0].y); + printf("d[1]: %i, %i\n", d[1].x, d[1].y); + printf("view->scroll: %i, %i\n", view->scroll_x, view->scroll_y);*/ + v[0] = d[0].x - view->scroll_x; v[1] = d[0].y - view->scroll_y; + v[2] = d[1].x - view->scroll_x; v[3] = d[1].y - view->scroll_y; + /*printf("v[]: %i, %i, %i, %i\n", v[0],v[1],v[2],v[3]);*/ + wid = gtk_button_new_with_label("Bonjour"); + //wid = ev_debug_new(); + /*printf("%i, %i\n", v[2]-v[0], v[3]-v[1]);*/ + gtk_widget_set_usize(wid, v[2]-v[0], v[3]-v[1]); + ev_view_put(view, wid,v[0],v[1]); + gtk_widget_show(wid); + + view->field_widgets = g_list_append(view->field_widgets, wid); + count++; + + } + } + printf("- added %i widgets\n", count); +#if 0 + static int runned = 0; + if(runned == 1) + return; + + + form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, view->current_page); + /* FIXME: we avoid removing all the widgets if we haven't anything to add. + It sometime is the case, perhaps if we have the render job not finished when we query for the form mapping, but doing it this way will cause the fields not being removed if we switch to a page without fields from a page with fields*/ + if (form_field_mapping == NULL) { + printf ("form_field_mapping == NULL\n"); + return; + } + + //runned = 1; + printf("form_field_widgets_clean_and_add\n"); + if(view->field_widgets) { + g_list_foreach(view->field_widgets,(GFunc)field_inc_count, &count); + g_list_foreach(view->field_widgets,(GFunc)remove_field_widget, GTK_CONTAINER(view)); + view->field_widgets = NULL; + } + printf("-removed %i widgets\n", count); + + /* Put form's fields widgets */ + + tmp_list = form_field_mapping; + count = 0; + while (tmp_list) { + EvFormFieldMapping *mapping = tmp_list->data; + EvFormField *field; + GtkWidget *wid; + EvPoint p[2]; + GdkPoint d[2]; + gint v[4]; + + tmp_list = tmp_list->next; + + field = mapping->field; + //printf("field : %i\n", ev_form_field_get_form_field_type(field)); + p[0].x = ev_form_field_get_x1(field); + p[0].y = ev_form_field_get_y1(field); + p[1].x = ev_form_field_get_x2(field); + p[1].y = ev_form_field_get_y2(field); + + doc_point_to_view_point(view, view->current_page, &p[0], &d[0]); + doc_point_to_view_point(view, view->current_page, &p[1], &d[1]); + /*printf("\nd[0]: %i, %i\n", d[0].x, d[0].y); + printf("d[1]: %i, %i\n", d[1].x, d[1].y); + printf("view->scroll: %i, %i\n", view->scroll_x, view->scroll_y);*/ + v[0] = d[0].x - view->scroll_x; v[1] = d[0].y - view->scroll_y; + v[2] = d[1].x - view->scroll_x; v[3] = d[1].y - view->scroll_y; + /*printf("v[]: %i, %i, %i, %i\n", v[0],v[1],v[2],v[3]);*/ + wid = gtk_button_new_with_label("Bonjour"); + //wid = ev_debug_new(); + /*printf("%i, %i\n", v[2]-v[0], v[3]-v[1]);*/ + gtk_widget_set_usize(wid, v[2]-v[0], v[3]-v[1]); + ev_view_put(view, wid,v[0],v[1]); + gtk_widget_show(wid); + + view->field_widgets = g_list_append(view->field_widgets, wid); + count++; + } + printf("-added %i widgets\n", count); + +#endif +} + /*** Callbacks ***/ static void find_changed_cb (EvDocument *document, int page, EvView *view) { double percent; int n_pages; @@ -2752,19 +3120,21 @@ find_changed_cb (EvDocument *document, i if (view->current_page == page) gtk_widget_queue_draw (GTK_WIDGET (view)); } static void job_finished_cb (EvPixbufCache *pixbuf_cache, EvView *view) { + form_field_widgets_clean_and_add(view); gtk_widget_queue_draw (GTK_WIDGET (view)); } + static void page_changed_cb (EvPageCache *page_cache, int new_page, EvView *view) { if (view->current_page != new_page) { view->current_page = new_page; view->pending_scroll = SCROLL_TO_PAGE_POSITION; @@ -2778,33 +3148,42 @@ page_changed_cb (EvPageCache *page_cache update_find_status_message (view, TRUE); } } static void on_adjustment_value_changed (GtkAdjustment *adjustment, EvView *view) { int dx = 0, dy = 0; - + GList *tmp_list; + if (! GTK_WIDGET_REALIZED (view)) return; if (view->hadjustment) { dx = view->scroll_x - (int) view->hadjustment->value; view->scroll_x = (int) view->hadjustment->value; } else { view->scroll_x = 0; } if (view->vadjustment) { dy = view->scroll_y - (int) view->vadjustment->value; view->scroll_y = (int) view->vadjustment->value; } else { view->scroll_y = 0; } + //printf("adjustment_value_changed\n"); + tmp_list = view->children; + while (tmp_list) { + EvViewChild *child = tmp_list->data; + tmp_list = tmp_list->next; + + ev_view_move_internal(view,child->widget, TRUE, child->x + dx, TRUE, child->y + dy); + } if (view->pending_resize) gtk_widget_queue_draw (GTK_WIDGET (view)); else gdk_window_scroll (GTK_WIDGET (view)->window, dx, dy); @@ -3380,17 +3759,17 @@ ev_view_set_zoom_for_size (EvView *view, { g_return_if_fail (view->sizing_mode == EV_SIZING_FIT_WIDTH || view->sizing_mode == EV_SIZING_BEST_FIT); g_return_if_fail (width >= 0); g_return_if_fail (height >= 0); if (view->document == NULL) return; - + if (view->presentation) ev_view_zoom_for_size_presentation (view, width, height); else if (view->continuous && view->dual_page) ev_view_zoom_for_size_continuous_and_dual_page (view, width, height, vsb_width, hsb_height); else if (view->continuous) ev_view_zoom_for_size_continuous (view, width, height, vsb_width, hsb_height); else if (view->dual_page) ev_view_zoom_for_size_dual_page (view, width, height, vsb_width, hsb_height); @@ -4213,8 +4592,192 @@ ev_scroll_type_get_type (void) { EV_SCROLL_STEP_UP, "EV_SCROLL_STEP_UP", "scroll-step-up" }, { EV_SCROLL_STEP_DOWN, "EV_SCROLL_STEP_DOWN", "scroll-step-down" }, { 0, NULL, NULL } }; etype = g_enum_register_static ("EvScrollType", values); } return etype; } + +/*** Container ***/ +static void +ev_view_map (GtkWidget *widget) +{ + GList *tmp_list; + EvView *view = EV_VIEW(widget); + + GTK_WIDGET_SET_FLAGS(widget, GTK_MAPPED); + + tmp_list = view->children; + while (tmp_list) { + EvViewChild *child = tmp_list->data; + tmp_list = tmp_list->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) { + if (!GTK_WIDGET_MAPPED (child->widget)) { + gtk_widget_map(child->widget); + } + } + } + + gdk_window_show(GTK_WIDGET(view)->window); +} + +static void +ev_view_add (GtkContainer *cont, GtkWidget *widget) +{ + ev_view_put(EV_VIEW(cont), widget, 0, 0); +} + +static void +ev_view_remove (GtkContainer *cont, GtkWidget *widget) +{ + GList *tmp_list; + EvView *view = EV_VIEW(cont); + EvViewChild *child = NULL; + + tmp_list = view->children; + while (tmp_list) { + child = tmp_list->data; + if(child->widget == widget) + break; + tmp_list = tmp_list->next; + } + + if (tmp_list) { + gtk_widget_unparent (widget); + view->children = g_list_remove_link(view->children, tmp_list); + g_list_free_1(tmp_list); + g_free(child); + } +} + +static void +ev_view_put (EvView *view, GtkWidget *widget, gint x, gint y) +{ + EvViewChild *child; + + child = g_new(EvViewChild, 1); + child->widget = widget; + child->x = x; + child->y = y; + + view->children = g_list_append(view->children, child); + + if (GTK_WIDGET_REALIZED(view)) + gtk_widget_set_parent_window (widget, GTK_WIDGET(view)->window); + gtk_widget_set_parent(widget, GTK_WIDGET(view)); +} + +static void +ev_view_forall (GtkContainer *cont, gboolean include_internals, GtkCallback callback, gpointer callback_data) +{ + EvView *view = EV_VIEW(cont); + EvViewChild *child; + GList *tmp_list; + + tmp_list = view->children; + while (tmp_list) { + child = tmp_list->data; + tmp_list = tmp_list->next; + + (*callback)(child->widget, callback_data); + } +} + +static EvViewChild* +get_child (EvView *view, GtkWidget *widget) +{ + GList *tmp_list = view->children; + while (tmp_list) { + EvViewChild *child; + child = tmp_list->data; + tmp_list = tmp_list->next; + if (child->widget == widget) + return child; + } + return NULL; +} + +static void +ev_view_move_internal (EvView *view, GtkWidget *widget, gboolean change_x, gint x, gboolean change_y, gint y) +{ + EvViewChild *child; + child = get_child(view, widget); + + g_assert(child); + + gtk_widget_freeze_child_notify(widget); + + if(change_x) { + child->x = x; + gtk_widget_child_notify(widget, "x"); + } + if(change_y) { + child->y = y; + gtk_widget_child_notify(widget, "y"); + } + gtk_widget_thaw_child_notify(widget); + + if (GTK_WIDGET_VISIBLE(widget) && GTK_WIDGET_VISIBLE(view)) + gtk_widget_queue_resize (GTK_WIDGET(widget)); +} + +static void +ev_view_set_child_property (GtkContainer *cont, + GtkWidget *child, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case CHILD_PROP_X: + ev_view_move_internal(EV_VIEW(cont), child, TRUE, g_value_get_int(value), FALSE, 0); + break; + case CHILD_PROP_Y: + ev_view_move_internal(EV_VIEW(cont), child, FALSE, 0, TRUE, g_value_get_int(value)); + break; + default: + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(cont, property_id, pspec); + break; + } +} + +static void +ev_view_get_child_property (GtkContainer *cont, + GtkWidget *child, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + EvViewChild *view_child; + view_child = get_child(EV_VIEW(cont), child); + + switch (property_id) { + case CHILD_PROP_X: + g_value_set_int (value, view_child->x); + break; + case CHILD_PROP_Y: + g_value_set_int (value, view_child->y); + break; + default: + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(cont, property_id, pspec); + break; + } +} + +static void +ev_view_allocate_child (EvView *view, EvViewChild *child) +{ + GtkAllocation allocation; + GtkRequisition requisition; + allocation.x = child->x; + allocation.y = child->y; + gtk_widget_get_child_requisition (child->widget, &requisition); + allocation.width = requisition.width; + allocation.height = requisition.height; + + gtk_widget_size_allocate (child->widget, &allocation); +} + + + Index: shell/ev-view.h =================================================================== RCS file: /cvs/gnome/evince/shell/ev-view.h,v retrieving revision 1.50 diff -u -8 -p -r1.50 ev-view.h --- shell/ev-view.h 2 May 2006 19:02:46 -0000 1.50 +++ shell/ev-view.h 28 May 2006 15:45:03 -0000 @@ -16,16 +16,17 @@ * 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_VIEW_H__ #define __EV_VIEW_H__ #include +#include #include "ev-document.h" #include "ev-link.h" #include "ev-view-accessible.h" G_BEGIN_DECLS #define EV_TYPE_VIEW (ev_view_get_type ())