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"
27 /* We keep a cached array of all the page sizes. The info is accessed via
28 * page_sizes [page - 1], as pages start at 1 */
29 typedef struct _EvPageViewInfo
35 struct _EvPageViewPrivate
40 GdkWindow *bin_window;
42 EvPageViewInfo *page_sizes;
44 GtkAdjustment *hadjustment;
45 GtkAdjustment *vadjustment;
53 /* these two are only set if uniform_page_size is set */
54 gint uniform_page_width;
55 gint uniform_page_height;
56 guint uniform_page_size : 1;
60 static void ev_page_view_init (EvPageView *page_view);
61 static void ev_page_view_class_init (EvPageViewClass *klass);
62 static void ev_page_view_set_scroll_adjustments (EvPageView *page_view,
63 GtkAdjustment *hadjustment,
64 GtkAdjustment *vadjustment);
65 static void ev_page_view_size_request (GtkWidget *widget,
66 GtkRequisition *requisition);
67 static void ev_page_view_size_allocate (GtkWidget *widget,
68 GtkAllocation *allocation);
69 static gboolean ev_page_view_expose (GtkWidget *widget,
70 GdkEventExpose *expose);
71 static void ev_page_view_realize (GtkWidget *widget);
72 static void ev_page_view_unrealize (GtkWidget *widget);
73 static void ev_page_view_map (GtkWidget *widget);
74 static void ev_page_view_load (EvPageView *page_view);
75 static void ev_page_view_adjustment_changed (GtkAdjustment *adjustment,
76 EvPageView *page_view);
77 static void ev_page_view_update_size (EvPageView *page_view);
80 G_DEFINE_TYPE (EvPageView, ev_page_view, GTK_TYPE_WIDGET)
82 #define EV_PAGE_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_PAGE_VIEW, EvPageViewPrivate))
85 ev_page_view_init (EvPageView *page_view)
87 page_view->priv = EV_PAGE_VIEW_GET_PRIVATE (page_view);
89 page_view->priv->width = 1;
90 page_view->priv->height = 1;
91 page_view->priv->page_spacing = 10;
92 page_view->priv->scale = 1.0;
94 /* Make some stuff up */
95 page_view->priv->n_pages = 0;
96 page_view->priv->uniform_page_width = -1;
97 page_view->priv->uniform_page_height = -1;
98 page_view->priv->uniform_page_size = FALSE;
102 ev_page_view_dispose (GObject *object)
104 EvPageView *view = EV_PAGE_VIEW (object);
108 if (view->priv->document) {
109 g_object_unref (view->priv->document);
110 view->priv->document = NULL;
113 G_OBJECT_CLASS (ev_page_view_parent_class)->dispose (object);
117 ev_page_view_class_init (EvPageViewClass *klass)
119 GObjectClass *o_class;
120 GtkWidgetClass *widget_class;
122 o_class = (GObjectClass *) klass;
123 widget_class = (GtkWidgetClass *) klass;
124 klass->set_scroll_adjustments = ev_page_view_set_scroll_adjustments;
126 g_type_class_add_private (klass, sizeof (EvPageViewPrivate));
127 widget_class->size_request = ev_page_view_size_request;
128 widget_class->size_allocate = ev_page_view_size_allocate;
129 widget_class->expose_event = ev_page_view_expose;
130 widget_class->realize = ev_page_view_realize;
131 widget_class->unrealize = ev_page_view_unrealize;
132 widget_class->map = ev_page_view_map;
134 o_class->dispose = ev_page_view_dispose;
136 widget_class->set_scroll_adjustments_signal =
137 g_signal_new ("set_scroll_adjustments",
138 G_TYPE_FROM_CLASS (o_class),
139 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
140 G_STRUCT_OFFSET (EvPageViewClass, set_scroll_adjustments),
142 ev_marshal_VOID__OBJECT_OBJECT,
145 GTK_TYPE_ADJUSTMENT);
152 ev_page_view_set_scroll_adjustments (EvPageView *page_view,
153 GtkAdjustment *hadjustment,
154 GtkAdjustment *vadjustment)
156 gboolean need_adjust = FALSE;
159 g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
161 hadjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
163 g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
165 vadjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
167 if (page_view->priv->hadjustment && (page_view->priv->hadjustment != hadjustment))
169 g_signal_handlers_disconnect_matched (page_view->priv->hadjustment, G_SIGNAL_MATCH_DATA,
170 0, 0, NULL, NULL, page_view);
171 g_object_unref (page_view->priv->hadjustment);
174 if (page_view->priv->vadjustment && (page_view->priv->vadjustment != vadjustment))
176 g_signal_handlers_disconnect_matched (page_view->priv->vadjustment, G_SIGNAL_MATCH_DATA,
177 0, 0, NULL, NULL, page_view);
178 g_object_unref (page_view->priv->vadjustment);
181 if (page_view->priv->hadjustment != hadjustment)
183 page_view->priv->hadjustment = hadjustment;
184 g_object_ref (page_view->priv->hadjustment);
185 gtk_object_sink (GTK_OBJECT (page_view->priv->hadjustment));
187 g_signal_connect (page_view->priv->hadjustment, "value_changed",
188 G_CALLBACK (ev_page_view_adjustment_changed),
193 if (page_view->priv->vadjustment != vadjustment)
195 page_view->priv->vadjustment = vadjustment;
196 g_object_ref (page_view->priv->vadjustment);
197 gtk_object_sink (GTK_OBJECT (page_view->priv->vadjustment));
199 g_signal_connect (page_view->priv->vadjustment, "value_changed",
200 G_CALLBACK (ev_page_view_adjustment_changed),
206 ev_page_view_adjustment_changed (NULL, page_view);
210 ev_page_view_update_size (EvPageView *page_view)
218 g_assert (page_view->priv->scale > 0.0);
220 if (page_view->priv->uniform_page_size) {
221 width = (int) (page_view->priv->uniform_page_width *
222 page_view->priv->scale);
223 height = (int) (page_view->priv->uniform_page_height *
224 page_view->priv->scale);
226 ev_document_misc_get_page_border_size (width, height,
227 & left_border, & right_border,
228 & top_border, & bottom_border);
230 page_view->priv->width = width
231 + page_view->priv->page_spacing * 2
234 page_view->priv->height =
236 + page_view->priv->page_spacing
239 * page_view->priv->n_pages) +
240 page_view->priv->page_spacing;
244 page_view->priv->width = 0;
245 page_view->priv->height = page_view->priv->page_spacing;
247 for (i = 0; i < page_view->priv->n_pages; i++) {
248 width = page_view->priv->page_sizes[i].width *
249 page_view->priv->scale;
250 height = page_view->priv->page_sizes[i].height *
251 page_view->priv->scale;
253 ev_document_misc_get_page_border_size (width, height,
254 & left_border, & right_border,
255 & top_border, & bottom_border);
258 + page_view->priv->page_spacing * 2
262 + page_view->priv->page_spacing
266 page_view->priv->width = MAX (width, page_view->priv->width);
267 page_view->priv->height += height;
274 ev_page_view_size_request (GtkWidget *widget,
275 GtkRequisition *requisition)
277 EvPageView *page_view;
279 page_view = EV_PAGE_VIEW (widget);
281 ev_page_view_update_size (page_view);
283 requisition->width = page_view->priv->width;
284 requisition->height = page_view->priv->height;
288 ev_page_view_paint_one_page (EvPageView *page_view,
297 widget = GTK_WIDGET (page_view);
299 g_print ("paint one page (%d,%d) %dx%d\n",
303 gdk_draw_rectangle (page_view->priv->bin_window,
304 widget->style->black_gc,
310 gdk_draw_rectangle (page_view->priv->bin_window,
311 widget->style->white_gc,
313 area->x + left_border,
314 area->y + top_border,
315 area->width - (left_border + right_border),
316 area->height - (top_border + bottom_border));
317 gdk_draw_rectangle (page_view->priv->bin_window,
318 widget->style->mid_gc[widget->state],
321 area->y + area->height - (bottom_border - top_border),
322 bottom_border - top_border,
323 bottom_border - top_border);
324 gdk_draw_rectangle (page_view->priv->bin_window,
325 widget->style->mid_gc[widget->state],
327 area->x + area->width - (right_border - left_border),
329 right_border - left_border,
330 right_border - left_border);
334 ev_page_view_expose_uniform (GtkWidget *widget,
335 GdkEventExpose *expose)
337 EvPageView *page_view;
343 GdkRectangle rectangle;
347 page_view = EV_PAGE_VIEW (widget);
349 width = (int) (page_view->priv->uniform_page_width *
350 page_view->priv->scale);
351 height = (int) (page_view->priv->uniform_page_height *
352 page_view->priv->scale);
354 if (widget->allocation.width > page_view->priv->width)
355 x_offset = (widget->allocation.width - page_view->priv->width)/2;
357 ev_document_misc_get_page_border_size (width, height,
363 rectangle.x = page_view->priv->page_spacing + x_offset;
364 rectangle.y = page_view->priv->page_spacing;
365 rectangle.width = width
368 rectangle.height = height
371 for (i = 0; i < page_view->priv->n_pages; i++) {
374 if (gdk_rectangle_intersect (&rectangle,
377 ev_page_view_paint_one_page (page_view,
379 left_border, right_border,
380 top_border, bottom_border);
381 rectangle.y += rectangle.height
382 + page_view->priv->page_spacing;
388 ev_page_view_expose_pages (GtkWidget *widget,
389 GdkEventExpose *expose)
391 EvPageView *page_view;
397 GdkRectangle rectangle;
401 page_view = EV_PAGE_VIEW (widget);
403 width = (int) (page_view->priv->uniform_page_width *
404 page_view->priv->scale);
405 height = (int) (page_view->priv->uniform_page_height *
406 page_view->priv->scale);
408 if (widget->allocation.width > page_view->priv->width)
409 x_offset = (widget->allocation.width - page_view->priv->width)/2;
411 ev_document_misc_get_page_border_size (width, height,
417 rectangle.x = page_view->priv->page_spacing + x_offset;
418 rectangle.y = page_view->priv->page_spacing;
419 rectangle.width = width
422 rectangle.height = height
425 for (i = 0; i < page_view->priv->n_pages; i++) {
428 if (gdk_rectangle_intersect (&rectangle,
431 ev_page_view_paint_one_page (page_view,
433 left_border, right_border,
434 top_border, bottom_border);
435 rectangle.y += rectangle.height
436 + page_view->priv->page_spacing;
442 ev_page_view_expose (GtkWidget *widget,
443 GdkEventExpose *expose)
445 EvPageView *page_view;
447 page_view = EV_PAGE_VIEW (widget);
449 if (expose->window != page_view->priv->bin_window)
452 if (page_view->priv->uniform_page_size) {
453 ev_page_view_expose_uniform (widget, expose);
455 ev_page_view_expose_pages (widget, expose);
462 ev_page_view_size_allocate (GtkWidget *widget,
463 GtkAllocation *allocation)
465 EvPageView *page_view;
467 widget->allocation = *allocation;
469 page_view = EV_PAGE_VIEW (widget);
471 if (GTK_WIDGET_REALIZED (widget))
473 gdk_window_move_resize (widget->window,
474 allocation->x, allocation->y,
475 allocation->width, allocation->height);
476 gdk_window_resize (page_view->priv->bin_window,
477 MAX (page_view->priv->width, allocation->width),
478 MAX (page_view->priv->height, allocation->height));
481 page_view->priv->hadjustment->page_size = allocation->width;
482 page_view->priv->hadjustment->page_increment = allocation->width * 0.9;
483 page_view->priv->hadjustment->step_increment = allocation->width * 0.1;
484 page_view->priv->hadjustment->lower = 0;
485 page_view->priv->hadjustment->upper = MAX (allocation->width, page_view->priv->width);
486 gtk_adjustment_changed (page_view->priv->hadjustment);
488 page_view->priv->vadjustment->page_size = allocation->height;
489 page_view->priv->vadjustment->page_increment = allocation->height * 0.9;
490 page_view->priv->vadjustment->step_increment = allocation->width * 0.1;
491 page_view->priv->vadjustment->lower = 0;
492 page_view->priv->vadjustment->upper = MAX (allocation->height, page_view->priv->height);
493 gtk_adjustment_changed (page_view->priv->vadjustment);
497 ev_page_view_adjustment_changed (GtkAdjustment *adjustment,
498 EvPageView *page_view)
500 if (GTK_WIDGET_REALIZED (page_view)) {
501 gdk_window_move (page_view->priv->bin_window,
502 - page_view->priv->hadjustment->value,
503 - page_view->priv->vadjustment->value);
505 gdk_window_process_updates (page_view->priv->bin_window, TRUE);
510 ev_page_view_realize_document (EvPageView *page_view)
512 if (page_view->priv->document == NULL)
515 ev_document_set_target (page_view->priv->document,
516 page_view->priv->bin_window);
517 ev_page_view_load (page_view);
518 gtk_widget_queue_resize (GTK_WIDGET (page_view));
523 ev_page_view_realize (GtkWidget *widget)
525 EvPageView *page_view;
526 GdkWindowAttr attributes;
527 gint attributes_mask;
529 g_return_if_fail (EV_IS_PAGE_VIEW (widget));
531 page_view = EV_PAGE_VIEW (widget);
532 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
534 /* Make the main, clipping window */
535 attributes.window_type = GDK_WINDOW_CHILD;
536 attributes.x = widget->allocation.x;
537 attributes.y = widget->allocation.y;
538 attributes.width = widget->allocation.width;
539 attributes.height = widget->allocation.height;
540 attributes.wclass = GDK_INPUT_OUTPUT;
541 attributes.visual = gtk_widget_get_visual (widget);
542 attributes.colormap = gtk_widget_get_colormap (widget);
543 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
545 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
547 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
548 &attributes, attributes_mask);
549 gdk_window_set_user_data (widget->window, widget);
551 /* Make the window for the page view */
554 attributes.width = MAX (page_view->priv->width, widget->allocation.width);
555 attributes.height = MAX (page_view->priv->height, widget->allocation.height);
556 attributes.event_mask = (GDK_EXPOSURE_MASK |
558 GDK_POINTER_MOTION_MASK |
559 GDK_BUTTON_PRESS_MASK |
560 GDK_BUTTON_RELEASE_MASK |
562 GDK_KEY_RELEASE_MASK) |
563 gtk_widget_get_events (widget);
565 page_view->priv->bin_window = gdk_window_new (widget->window,
566 &attributes, attributes_mask);
567 gdk_window_set_user_data (page_view->priv->bin_window, widget);
569 widget->style = gtk_style_attach (widget->style, widget->window);
570 gdk_window_set_background (page_view->priv->bin_window, &widget->style->mid[widget->state]);
571 gdk_window_set_background (widget->window, &widget->style->mid[widget->state]);
573 ev_page_view_realize_document (page_view);
578 ev_page_view_unrealize (GtkWidget *widget)
580 EvPageView *page_view;
582 page_view = EV_PAGE_VIEW (widget);
584 gdk_window_set_user_data (page_view->priv->bin_window, NULL);
585 gdk_window_destroy (page_view->priv->bin_window);
586 page_view->priv->bin_window = NULL;
588 /* GtkWidget::unrealize destroys children and widget->window */
589 if (GTK_WIDGET_CLASS (ev_page_view_parent_class)->unrealize)
590 (* GTK_WIDGET_CLASS (ev_page_view_parent_class)->unrealize) (widget);
594 ev_page_view_map (GtkWidget *widget)
596 EvPageView *page_view;
598 page_view = EV_PAGE_VIEW (widget);
600 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
602 gdk_window_show (page_view->priv->bin_window);
603 gdk_window_show (widget->window);
607 ev_page_view_load (EvPageView *page_view)
610 gboolean uniform_page_size = TRUE;
611 int width = 0, height = 0;
613 page_view->priv->n_pages =
614 ev_document_get_n_pages (page_view->priv->document);
616 for (i = 1; i <= page_view->priv->n_pages; i++) {
617 EvPageViewInfo *info;
619 gint page_height = 0;
621 ev_document_set_scale (page_view->priv->document, page_view->priv->scale);
622 ev_document_get_page_size (page_view->priv->document,
624 &page_width, &page_height);
628 height = page_height;
629 } else if (width != page_width || height != page_height) {
630 /* It's a different page size. Backfill the array. */
633 uniform_page_size = FALSE;
635 page_view->priv->page_sizes =
636 g_new0 (EvPageViewInfo, page_view->priv->n_pages);
638 for (j = 1; j < i; j++) {
640 info = &(page_view->priv->page_sizes[j - 1]);
642 info->height = height;
646 if (! uniform_page_size) {
647 info = &(page_view->priv->page_sizes[i - 1]);
649 info->width = page_width;
650 info->height = page_height;
654 page_view->priv->uniform_page_size = uniform_page_size;
656 if (uniform_page_size) {
657 page_view->priv->uniform_page_width = width;
658 page_view->priv->uniform_page_height = height;
661 ev_page_view_update_size (page_view);
663 gtk_widget_queue_resize (GTK_WIDGET (page_view));
666 /* Public functions */
668 ev_page_view_new (void)
670 return g_object_new (EV_TYPE_PAGE_VIEW, NULL);
674 ev_page_view_set_document (EvPageView *page_view,
675 EvDocument *document)
677 g_return_if_fail (EV_IS_PAGE_VIEW (page_view));
679 if (document != page_view->priv->document) {
680 if (page_view->priv->document) {
681 g_object_unref (page_view->priv->document);
684 page_view->priv->document = document;
686 if (page_view->priv->document) {
687 g_object_ref (page_view->priv->document);
690 if (GTK_WIDGET_REALIZED (page_view)) {
691 ev_page_view_realize_document (page_view);