2 * Copyright (C) 2005 Jonathan Blandford
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include "ev-page-view.h"
22 #include "ev-marshal.h"
23 #include "ev-document-misc.h"
26 /* We keep a cached array of all the page sizes. The info is accessed via
27 * page_sizes [page - 1], as pages start at 1 */
28 typedef struct _EvPageViewInfo
34 struct _EvPageViewPrivate
39 GdkWindow *bin_window;
41 EvPageViewInfo *page_sizes;
43 GtkAdjustment *hadjustment;
44 GtkAdjustment *vadjustment;
52 /* these two are only set if uniform_page_size is set */
53 gint uniform_page_width;
54 gint uniform_page_height;
55 guint uniform_page_size : 1;
59 static void ev_page_view_init (EvPageView *page_view);
60 static void ev_page_view_class_init (EvPageViewClass *klass);
61 static void ev_page_view_set_scroll_adjustments (EvPageView *page_view,
62 GtkAdjustment *hadjustment,
63 GtkAdjustment *vadjustment);
64 static void ev_page_view_size_request (GtkWidget *widget,
65 GtkRequisition *requisition);
66 static void ev_page_view_size_allocate (GtkWidget *widget,
67 GtkAllocation *allocation);
68 static gboolean ev_page_view_expose (GtkWidget *widget,
69 GdkEventExpose *expose);
70 static void ev_page_view_realize (GtkWidget *widget);
71 static void ev_page_view_unrealize (GtkWidget *widget);
72 static void ev_page_view_map (GtkWidget *widget);
73 static void ev_page_view_load (EvPageView *page_view);
74 static void ev_page_view_adjustment_changed (GtkAdjustment *adjustment,
75 EvPageView *page_view);
76 static void ev_page_view_update_size (EvPageView *page_view);
79 G_DEFINE_TYPE (EvPageView, ev_page_view, GTK_TYPE_WIDGET)
81 #define EV_PAGE_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_PAGE_VIEW, EvPageViewPrivate))
84 ev_page_view_init (EvPageView *page_view)
86 page_view->priv = EV_PAGE_VIEW_GET_PRIVATE (page_view);
88 page_view->priv->width = 1;
89 page_view->priv->height = 1;
90 page_view->priv->page_spacing = 10;
91 page_view->priv->scale = 1.0;
93 /* Make some stuff up */
94 page_view->priv->n_pages = 0;
95 page_view->priv->uniform_page_width = -1;
96 page_view->priv->uniform_page_height = -1;
97 page_view->priv->uniform_page_size = FALSE;
101 ev_page_view_dispose (GObject *object)
103 EvPageView *view = EV_PAGE_VIEW (object);
105 if (view->priv->document) {
106 g_object_unref (view->priv->document);
107 view->priv->document = NULL;
110 G_OBJECT_CLASS (ev_page_view_parent_class)->dispose (object);
114 ev_page_view_class_init (EvPageViewClass *klass)
116 GObjectClass *o_class;
117 GtkWidgetClass *widget_class;
119 o_class = (GObjectClass *) klass;
120 widget_class = (GtkWidgetClass *) klass;
121 klass->set_scroll_adjustments = ev_page_view_set_scroll_adjustments;
123 g_type_class_add_private (klass, sizeof (EvPageViewPrivate));
124 widget_class->size_request = ev_page_view_size_request;
125 widget_class->size_allocate = ev_page_view_size_allocate;
126 widget_class->expose_event = ev_page_view_expose;
127 widget_class->realize = ev_page_view_realize;
128 widget_class->unrealize = ev_page_view_unrealize;
129 widget_class->map = ev_page_view_map;
131 o_class->dispose = ev_page_view_dispose;
133 widget_class->set_scroll_adjustments_signal =
134 g_signal_new ("set_scroll_adjustments",
135 G_TYPE_FROM_CLASS (o_class),
136 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
137 G_STRUCT_OFFSET (EvPageViewClass, set_scroll_adjustments),
139 ev_marshal_VOID__OBJECT_OBJECT,
142 GTK_TYPE_ADJUSTMENT);
149 ev_page_view_set_scroll_adjustments (EvPageView *page_view,
150 GtkAdjustment *hadjustment,
151 GtkAdjustment *vadjustment)
153 gboolean need_adjust = FALSE;
156 g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
158 hadjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
160 g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
162 vadjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
164 if (page_view->priv->hadjustment && (page_view->priv->hadjustment != hadjustment))
166 g_signal_handlers_disconnect_matched (page_view->priv->hadjustment, G_SIGNAL_MATCH_DATA,
167 0, 0, NULL, NULL, page_view);
168 g_object_unref (page_view->priv->hadjustment);
171 if (page_view->priv->vadjustment && (page_view->priv->vadjustment != vadjustment))
173 g_signal_handlers_disconnect_matched (page_view->priv->vadjustment, G_SIGNAL_MATCH_DATA,
174 0, 0, NULL, NULL, page_view);
175 g_object_unref (page_view->priv->vadjustment);
178 if (page_view->priv->hadjustment != hadjustment)
180 page_view->priv->hadjustment = hadjustment;
181 g_object_ref (page_view->priv->hadjustment);
182 gtk_object_sink (GTK_OBJECT (page_view->priv->hadjustment));
184 g_signal_connect (page_view->priv->hadjustment, "value_changed",
185 G_CALLBACK (ev_page_view_adjustment_changed),
190 if (page_view->priv->vadjustment != vadjustment)
192 page_view->priv->vadjustment = vadjustment;
193 g_object_ref (page_view->priv->vadjustment);
194 gtk_object_sink (GTK_OBJECT (page_view->priv->vadjustment));
196 g_signal_connect (page_view->priv->vadjustment, "value_changed",
197 G_CALLBACK (ev_page_view_adjustment_changed),
203 ev_page_view_adjustment_changed (NULL, page_view);
207 ev_page_view_update_size (EvPageView *page_view)
215 g_assert (page_view->priv->scale > 0.0);
217 if (page_view->priv->uniform_page_size) {
218 width = (int) (page_view->priv->uniform_page_width *
219 page_view->priv->scale);
220 height = (int) (page_view->priv->uniform_page_height *
221 page_view->priv->scale);
223 ev_document_misc_get_page_border_size (width, height,
224 & left_border, & right_border,
225 & top_border, & bottom_border);
227 page_view->priv->width = width
228 + page_view->priv->page_spacing * 2
231 page_view->priv->height =
233 + page_view->priv->page_spacing
236 * page_view->priv->n_pages) +
237 page_view->priv->page_spacing;
241 page_view->priv->width = 0;
242 page_view->priv->height = page_view->priv->page_spacing;
244 for (i = 0; i < page_view->priv->n_pages; i++) {
245 width = page_view->priv->page_sizes[i].width *
246 page_view->priv->scale;
247 height = page_view->priv->page_sizes[i].height *
248 page_view->priv->scale;
250 ev_document_misc_get_page_border_size (width, height,
251 & left_border, & right_border,
252 & top_border, & bottom_border);
255 + page_view->priv->page_spacing * 2
259 + page_view->priv->page_spacing
263 page_view->priv->width = MAX (width, page_view->priv->width);
264 page_view->priv->height += height;
271 ev_page_view_size_request (GtkWidget *widget,
272 GtkRequisition *requisition)
274 EvPageView *page_view;
276 page_view = EV_PAGE_VIEW (widget);
278 ev_page_view_update_size (page_view);
280 requisition->width = page_view->priv->width;
281 requisition->height = page_view->priv->height;
285 ev_page_view_paint_one_page (EvPageView *page_view,
294 widget = GTK_WIDGET (page_view);
296 g_print ("paint one page (%d,%d) %dx%d\n",
300 gdk_draw_rectangle (page_view->priv->bin_window,
301 widget->style->black_gc,
307 gdk_draw_rectangle (page_view->priv->bin_window,
308 widget->style->white_gc,
310 area->x + left_border,
311 area->y + top_border,
312 area->width - (left_border + right_border),
313 area->height - (top_border + bottom_border));
314 gdk_draw_rectangle (page_view->priv->bin_window,
315 widget->style->mid_gc[widget->state],
318 area->y + area->height - (bottom_border - top_border),
319 bottom_border - top_border,
320 bottom_border - top_border);
321 gdk_draw_rectangle (page_view->priv->bin_window,
322 widget->style->mid_gc[widget->state],
324 area->x + area->width - (right_border - left_border),
326 right_border - left_border,
327 right_border - left_border);
331 ev_page_view_expose_uniform (GtkWidget *widget,
332 GdkEventExpose *expose)
334 EvPageView *page_view;
340 GdkRectangle rectangle;
344 page_view = EV_PAGE_VIEW (widget);
346 width = (int) (page_view->priv->uniform_page_width *
347 page_view->priv->scale);
348 height = (int) (page_view->priv->uniform_page_height *
349 page_view->priv->scale);
351 if (widget->allocation.width > page_view->priv->width)
352 x_offset = (widget->allocation.width - page_view->priv->width)/2;
354 ev_document_misc_get_page_border_size (width, height,
360 rectangle.x = page_view->priv->page_spacing + x_offset;
361 rectangle.y = page_view->priv->page_spacing;
362 rectangle.width = width
365 rectangle.height = height
368 for (i = 0; i < page_view->priv->n_pages; i++) {
371 if (gdk_rectangle_intersect (&rectangle,
374 ev_page_view_paint_one_page (page_view,
376 left_border, right_border,
377 top_border, bottom_border);
378 rectangle.y += rectangle.height
379 + page_view->priv->page_spacing;
385 ev_page_view_expose_pages (GtkWidget *widget,
386 GdkEventExpose *expose)
388 EvPageView *page_view;
394 GdkRectangle rectangle;
398 page_view = EV_PAGE_VIEW (widget);
400 width = (int) (page_view->priv->uniform_page_width *
401 page_view->priv->scale);
402 height = (int) (page_view->priv->uniform_page_height *
403 page_view->priv->scale);
405 if (widget->allocation.width > page_view->priv->width)
406 x_offset = (widget->allocation.width - page_view->priv->width)/2;
408 ev_document_misc_get_page_border_size (width, height,
414 rectangle.x = page_view->priv->page_spacing + x_offset;
415 rectangle.y = page_view->priv->page_spacing;
416 rectangle.width = width
419 rectangle.height = height
422 for (i = 0; i < page_view->priv->n_pages; i++) {
425 if (gdk_rectangle_intersect (&rectangle,
428 ev_page_view_paint_one_page (page_view,
430 left_border, right_border,
431 top_border, bottom_border);
432 rectangle.y += rectangle.height
433 + page_view->priv->page_spacing;
439 ev_page_view_expose (GtkWidget *widget,
440 GdkEventExpose *expose)
442 EvPageView *page_view;
444 page_view = EV_PAGE_VIEW (widget);
446 if (expose->window != page_view->priv->bin_window)
449 if (page_view->priv->uniform_page_size) {
450 ev_page_view_expose_uniform (widget, expose);
452 ev_page_view_expose_pages (widget, expose);
459 ev_page_view_size_allocate (GtkWidget *widget,
460 GtkAllocation *allocation)
462 EvPageView *page_view;
464 widget->allocation = *allocation;
466 page_view = EV_PAGE_VIEW (widget);
468 if (GTK_WIDGET_REALIZED (widget))
470 gdk_window_move_resize (widget->window,
471 allocation->x, allocation->y,
472 allocation->width, allocation->height);
473 gdk_window_resize (page_view->priv->bin_window,
474 MAX (page_view->priv->width, allocation->width),
475 MAX (page_view->priv->height, allocation->height));
478 page_view->priv->hadjustment->page_size = allocation->width;
479 page_view->priv->hadjustment->page_increment = allocation->width * 0.9;
480 page_view->priv->hadjustment->step_increment = allocation->width * 0.1;
481 page_view->priv->hadjustment->lower = 0;
482 page_view->priv->hadjustment->upper = MAX (allocation->width, page_view->priv->width);
483 gtk_adjustment_changed (page_view->priv->hadjustment);
485 page_view->priv->vadjustment->page_size = allocation->height;
486 page_view->priv->vadjustment->page_increment = allocation->height * 0.9;
487 page_view->priv->vadjustment->step_increment = allocation->width * 0.1;
488 page_view->priv->vadjustment->lower = 0;
489 page_view->priv->vadjustment->upper = MAX (allocation->height, page_view->priv->height);
490 gtk_adjustment_changed (page_view->priv->vadjustment);
494 ev_page_view_adjustment_changed (GtkAdjustment *adjustment,
495 EvPageView *page_view)
497 if (GTK_WIDGET_REALIZED (page_view)) {
498 gdk_window_move (page_view->priv->bin_window,
499 - page_view->priv->hadjustment->value,
500 - page_view->priv->vadjustment->value);
502 gdk_window_process_updates (page_view->priv->bin_window, TRUE);
507 ev_page_view_realize_document (EvPageView *page_view)
509 if (page_view->priv->document == NULL)
512 ev_document_set_target (page_view->priv->document,
513 page_view->priv->bin_window);
514 ev_page_view_load (page_view);
515 gtk_widget_queue_resize (GTK_WIDGET (page_view));
520 ev_page_view_realize (GtkWidget *widget)
522 EvPageView *page_view;
523 GdkWindowAttr attributes;
524 gint attributes_mask;
526 g_return_if_fail (EV_IS_PAGE_VIEW (widget));
528 page_view = EV_PAGE_VIEW (widget);
529 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
531 /* Make the main, clipping window */
532 attributes.window_type = GDK_WINDOW_CHILD;
533 attributes.x = widget->allocation.x;
534 attributes.y = widget->allocation.y;
535 attributes.width = widget->allocation.width;
536 attributes.height = widget->allocation.height;
537 attributes.wclass = GDK_INPUT_OUTPUT;
538 attributes.visual = gtk_widget_get_visual (widget);
539 attributes.colormap = gtk_widget_get_colormap (widget);
540 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
542 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
544 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
545 &attributes, attributes_mask);
546 gdk_window_set_user_data (widget->window, widget);
548 /* Make the window for the page view */
551 attributes.width = MAX (page_view->priv->width, widget->allocation.width);
552 attributes.height = MAX (page_view->priv->height, widget->allocation.height);
553 attributes.event_mask = (GDK_EXPOSURE_MASK |
555 GDK_POINTER_MOTION_MASK |
556 GDK_BUTTON_PRESS_MASK |
557 GDK_BUTTON_RELEASE_MASK |
559 GDK_KEY_RELEASE_MASK) |
560 gtk_widget_get_events (widget);
562 page_view->priv->bin_window = gdk_window_new (widget->window,
563 &attributes, attributes_mask);
564 gdk_window_set_user_data (page_view->priv->bin_window, widget);
566 widget->style = gtk_style_attach (widget->style, widget->window);
567 gdk_window_set_background (page_view->priv->bin_window, &widget->style->mid[widget->state]);
568 gdk_window_set_background (widget->window, &widget->style->mid[widget->state]);
570 ev_page_view_realize_document (page_view);
575 ev_page_view_unrealize (GtkWidget *widget)
577 EvPageView *page_view;
579 page_view = EV_PAGE_VIEW (widget);
581 gdk_window_set_user_data (page_view->priv->bin_window, NULL);
582 gdk_window_destroy (page_view->priv->bin_window);
583 page_view->priv->bin_window = NULL;
585 /* GtkWidget::unrealize destroys children and widget->window */
586 if (GTK_WIDGET_CLASS (ev_page_view_parent_class)->unrealize)
587 (* GTK_WIDGET_CLASS (ev_page_view_parent_class)->unrealize) (widget);
591 ev_page_view_map (GtkWidget *widget)
593 EvPageView *page_view;
595 page_view = EV_PAGE_VIEW (widget);
597 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
599 gdk_window_show (page_view->priv->bin_window);
600 gdk_window_show (widget->window);
604 ev_page_view_load (EvPageView *page_view)
607 gboolean uniform_page_size = TRUE;
608 int width = 0, height = 0;
610 page_view->priv->n_pages =
611 ev_document_get_n_pages (page_view->priv->document);
613 for (i = 1; i <= page_view->priv->n_pages; i++) {
614 EvPageViewInfo *info;
616 gint page_height = 0;
618 ev_document_set_scale (page_view->priv->document, page_view->priv->scale);
619 ev_document_get_page_size (page_view->priv->document,
621 &page_width, &page_height);
625 height = page_height;
626 } else if (width != page_width || height != page_height) {
627 /* It's a different page size. Backfill the array. */
630 uniform_page_size = FALSE;
632 page_view->priv->page_sizes =
633 g_new0 (EvPageViewInfo, page_view->priv->n_pages);
635 for (j = 1; j < i; j++) {
637 info = &(page_view->priv->page_sizes[j - 1]);
639 info->height = height;
643 if (! uniform_page_size) {
644 info = &(page_view->priv->page_sizes[i - 1]);
646 info->width = page_width;
647 info->height = page_height;
651 page_view->priv->uniform_page_size = uniform_page_size;
653 if (uniform_page_size) {
654 page_view->priv->uniform_page_width = width;
655 page_view->priv->uniform_page_height = height;
658 ev_page_view_update_size (page_view);
660 gtk_widget_queue_resize (GTK_WIDGET (page_view));
663 /* Public functions */
665 ev_page_view_new (void)
667 return g_object_new (EV_TYPE_PAGE_VIEW, NULL);
671 ev_page_view_set_document (EvPageView *page_view,
672 EvDocument *document)
674 g_return_if_fail (EV_IS_PAGE_VIEW (page_view));
676 if (document != page_view->priv->document) {
677 if (page_view->priv->document) {
678 g_object_unref (page_view->priv->document);
681 page_view->priv->document = document;
683 if (page_view->priv->document) {
684 g_object_ref (page_view->priv->document);
687 if (GTK_WIDGET_REALIZED (page_view)) {
688 ev_page_view_realize_document (page_view);