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_class_init (EvPageViewClass *klass)
103 GObjectClass *o_class;
104 GtkWidgetClass *widget_class;
106 o_class = (GObjectClass *) klass;
107 widget_class = (GtkWidgetClass *) klass;
108 klass->set_scroll_adjustments = ev_page_view_set_scroll_adjustments;
110 g_type_class_add_private (klass, sizeof (EvPageViewPrivate));
111 widget_class->size_request = ev_page_view_size_request;
112 widget_class->size_allocate = ev_page_view_size_allocate;
113 widget_class->expose_event = ev_page_view_expose;
114 widget_class->realize = ev_page_view_realize;
115 widget_class->unrealize = ev_page_view_unrealize;
116 widget_class->map = ev_page_view_map;
118 widget_class->set_scroll_adjustments_signal =
119 g_signal_new ("set_scroll_adjustments",
120 G_TYPE_FROM_CLASS (o_class),
121 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
122 G_STRUCT_OFFSET (EvPageViewClass, set_scroll_adjustments),
124 ev_marshal_VOID__OBJECT_OBJECT,
127 GTK_TYPE_ADJUSTMENT);
134 ev_page_view_set_scroll_adjustments (EvPageView *page_view,
135 GtkAdjustment *hadjustment,
136 GtkAdjustment *vadjustment)
138 gboolean need_adjust = FALSE;
141 g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
143 hadjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
145 g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
147 vadjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
149 if (page_view->priv->hadjustment && (page_view->priv->hadjustment != hadjustment))
151 g_signal_handlers_disconnect_matched (page_view->priv->hadjustment, G_SIGNAL_MATCH_DATA,
152 0, 0, NULL, NULL, page_view);
153 g_object_unref (page_view->priv->hadjustment);
156 if (page_view->priv->vadjustment && (page_view->priv->vadjustment != vadjustment))
158 g_signal_handlers_disconnect_matched (page_view->priv->vadjustment, G_SIGNAL_MATCH_DATA,
159 0, 0, NULL, NULL, page_view);
160 g_object_unref (page_view->priv->vadjustment);
163 if (page_view->priv->hadjustment != hadjustment)
165 page_view->priv->hadjustment = hadjustment;
166 g_object_ref (page_view->priv->hadjustment);
167 gtk_object_sink (GTK_OBJECT (page_view->priv->hadjustment));
169 g_signal_connect (page_view->priv->hadjustment, "value_changed",
170 G_CALLBACK (ev_page_view_adjustment_changed),
175 if (page_view->priv->vadjustment != vadjustment)
177 page_view->priv->vadjustment = vadjustment;
178 g_object_ref (page_view->priv->vadjustment);
179 gtk_object_sink (GTK_OBJECT (page_view->priv->vadjustment));
181 g_signal_connect (page_view->priv->vadjustment, "value_changed",
182 G_CALLBACK (ev_page_view_adjustment_changed),
188 ev_page_view_adjustment_changed (NULL, page_view);
192 ev_page_view_update_size (EvPageView *page_view)
200 g_assert (page_view->priv->scale > 0.0);
202 if (page_view->priv->uniform_page_size) {
203 width = (int) (page_view->priv->uniform_page_width *
204 page_view->priv->scale);
205 height = (int) (page_view->priv->uniform_page_height *
206 page_view->priv->scale);
208 ev_document_misc_get_page_border_size (width, height,
209 & left_border, & right_border,
210 & top_border, & bottom_border);
212 page_view->priv->width = width
213 + page_view->priv->page_spacing * 2
216 page_view->priv->height =
218 + page_view->priv->page_spacing
221 * page_view->priv->n_pages) +
222 page_view->priv->page_spacing;
226 page_view->priv->width = 0;
227 page_view->priv->height = page_view->priv->page_spacing;
229 for (i = 0; i < page_view->priv->n_pages; i++) {
230 width = page_view->priv->page_sizes[i].width *
231 page_view->priv->scale;
232 height = page_view->priv->page_sizes[i].height *
233 page_view->priv->scale;
235 ev_document_misc_get_page_border_size (width, height,
236 & left_border, & right_border,
237 & top_border, & bottom_border);
240 + page_view->priv->page_spacing * 2
244 + page_view->priv->page_spacing
248 page_view->priv->width = MAX (width, page_view->priv->width);
249 page_view->priv->height += height;
256 ev_page_view_size_request (GtkWidget *widget,
257 GtkRequisition *requisition)
259 EvPageView *page_view;
261 page_view = EV_PAGE_VIEW (widget);
263 ev_page_view_update_size (page_view);
265 requisition->width = page_view->priv->width;
266 requisition->height = page_view->priv->height;
270 ev_page_view_paint_one_page (EvPageView *page_view,
279 widget = GTK_WIDGET (page_view);
281 g_print ("paint one page (%d,%d) %dx%d\n",
285 gdk_draw_rectangle (page_view->priv->bin_window,
286 widget->style->black_gc,
292 gdk_draw_rectangle (page_view->priv->bin_window,
293 widget->style->white_gc,
295 area->x + left_border,
296 area->y + top_border,
297 area->width - (left_border + right_border),
298 area->height - (top_border + bottom_border));
299 gdk_draw_rectangle (page_view->priv->bin_window,
300 widget->style->mid_gc[widget->state],
303 area->y + area->height - (bottom_border - top_border),
304 bottom_border - top_border,
305 bottom_border - top_border);
306 gdk_draw_rectangle (page_view->priv->bin_window,
307 widget->style->mid_gc[widget->state],
309 area->x + area->width - (right_border - left_border),
311 right_border - left_border,
312 right_border - left_border);
316 ev_page_view_expose_uniform (GtkWidget *widget,
317 GdkEventExpose *expose)
319 EvPageView *page_view;
325 GdkRectangle rectangle;
329 page_view = EV_PAGE_VIEW (widget);
331 width = (int) (page_view->priv->uniform_page_width *
332 page_view->priv->scale);
333 height = (int) (page_view->priv->uniform_page_height *
334 page_view->priv->scale);
336 if (widget->allocation.width > page_view->priv->width)
337 x_offset = (widget->allocation.width - page_view->priv->width)/2;
339 ev_document_misc_get_page_border_size (width, height,
345 rectangle.x = page_view->priv->page_spacing + x_offset;
346 rectangle.y = page_view->priv->page_spacing;
347 rectangle.width = width
350 rectangle.height = height
353 for (i = 0; i < page_view->priv->n_pages; i++) {
356 if (gdk_rectangle_intersect (&rectangle,
359 ev_page_view_paint_one_page (page_view,
361 left_border, right_border,
362 top_border, bottom_border);
363 rectangle.y += rectangle.height
364 + page_view->priv->page_spacing;
370 ev_page_view_expose_pages (GtkWidget *widget,
371 GdkEventExpose *expose)
373 EvPageView *page_view;
379 GdkRectangle rectangle;
383 page_view = EV_PAGE_VIEW (widget);
385 width = (int) (page_view->priv->uniform_page_width *
386 page_view->priv->scale);
387 height = (int) (page_view->priv->uniform_page_height *
388 page_view->priv->scale);
390 if (widget->allocation.width > page_view->priv->width)
391 x_offset = (widget->allocation.width - page_view->priv->width)/2;
393 ev_document_misc_get_page_border_size (width, height,
399 rectangle.x = page_view->priv->page_spacing + x_offset;
400 rectangle.y = page_view->priv->page_spacing;
401 rectangle.width = width
404 rectangle.height = height
407 for (i = 0; i < page_view->priv->n_pages; i++) {
410 if (gdk_rectangle_intersect (&rectangle,
413 ev_page_view_paint_one_page (page_view,
415 left_border, right_border,
416 top_border, bottom_border);
417 rectangle.y += rectangle.height
418 + page_view->priv->page_spacing;
424 ev_page_view_expose (GtkWidget *widget,
425 GdkEventExpose *expose)
427 EvPageView *page_view;
429 page_view = EV_PAGE_VIEW (widget);
431 if (expose->window != page_view->priv->bin_window)
434 if (page_view->priv->uniform_page_size) {
435 ev_page_view_expose_uniform (widget, expose);
437 ev_page_view_expose_pages (widget, expose);
444 ev_page_view_size_allocate (GtkWidget *widget,
445 GtkAllocation *allocation)
447 EvPageView *page_view;
449 widget->allocation = *allocation;
451 page_view = EV_PAGE_VIEW (widget);
453 if (GTK_WIDGET_REALIZED (widget))
455 gdk_window_move_resize (widget->window,
456 allocation->x, allocation->y,
457 allocation->width, allocation->height);
458 gdk_window_resize (page_view->priv->bin_window,
459 MAX (page_view->priv->width, allocation->width),
460 MAX (page_view->priv->height, allocation->height));
463 page_view->priv->hadjustment->page_size = allocation->width;
464 page_view->priv->hadjustment->page_increment = allocation->width * 0.9;
465 page_view->priv->hadjustment->step_increment = allocation->width * 0.1;
466 page_view->priv->hadjustment->lower = 0;
467 page_view->priv->hadjustment->upper = MAX (allocation->width, page_view->priv->width);
468 gtk_adjustment_changed (page_view->priv->hadjustment);
470 page_view->priv->vadjustment->page_size = allocation->height;
471 page_view->priv->vadjustment->page_increment = allocation->height * 0.9;
472 page_view->priv->vadjustment->step_increment = allocation->width * 0.1;
473 page_view->priv->vadjustment->lower = 0;
474 page_view->priv->vadjustment->upper = MAX (allocation->height, page_view->priv->height);
475 gtk_adjustment_changed (page_view->priv->vadjustment);
479 ev_page_view_adjustment_changed (GtkAdjustment *adjustment,
480 EvPageView *page_view)
482 if (GTK_WIDGET_REALIZED (page_view)) {
483 gdk_window_move (page_view->priv->bin_window,
484 - page_view->priv->hadjustment->value,
485 - page_view->priv->vadjustment->value);
487 gdk_window_process_updates (page_view->priv->bin_window, TRUE);
492 ev_page_view_realize_document (EvPageView *page_view)
494 if (page_view->priv->document == NULL)
497 ev_document_set_target (page_view->priv->document,
498 page_view->priv->bin_window);
499 ev_page_view_load (page_view);
500 gtk_widget_queue_resize (GTK_WIDGET (page_view));
505 ev_page_view_realize (GtkWidget *widget)
507 EvPageView *page_view;
508 GdkWindowAttr attributes;
509 gint attributes_mask;
511 g_return_if_fail (EV_IS_PAGE_VIEW (widget));
513 page_view = EV_PAGE_VIEW (widget);
514 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
516 /* Make the main, clipping window */
517 attributes.window_type = GDK_WINDOW_CHILD;
518 attributes.x = widget->allocation.x;
519 attributes.y = widget->allocation.y;
520 attributes.width = widget->allocation.width;
521 attributes.height = widget->allocation.height;
522 attributes.wclass = GDK_INPUT_OUTPUT;
523 attributes.visual = gtk_widget_get_visual (widget);
524 attributes.colormap = gtk_widget_get_colormap (widget);
525 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
527 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
529 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
530 &attributes, attributes_mask);
531 gdk_window_set_user_data (widget->window, widget);
533 /* Make the window for the page view */
536 attributes.width = MAX (page_view->priv->width, widget->allocation.width);
537 attributes.height = MAX (page_view->priv->height, widget->allocation.height);
538 attributes.event_mask = (GDK_EXPOSURE_MASK |
540 GDK_POINTER_MOTION_MASK |
541 GDK_BUTTON_PRESS_MASK |
542 GDK_BUTTON_RELEASE_MASK |
544 GDK_KEY_RELEASE_MASK) |
545 gtk_widget_get_events (widget);
547 page_view->priv->bin_window = gdk_window_new (widget->window,
548 &attributes, attributes_mask);
549 gdk_window_set_user_data (page_view->priv->bin_window, widget);
551 widget->style = gtk_style_attach (widget->style, widget->window);
552 gdk_window_set_background (page_view->priv->bin_window, &widget->style->mid[widget->state]);
553 gdk_window_set_background (widget->window, &widget->style->mid[widget->state]);
555 ev_page_view_realize_document (page_view);
560 ev_page_view_unrealize (GtkWidget *widget)
562 EvPageView *page_view;
564 page_view = EV_PAGE_VIEW (widget);
566 gdk_window_set_user_data (page_view->priv->bin_window, NULL);
567 gdk_window_destroy (page_view->priv->bin_window);
568 page_view->priv->bin_window = NULL;
570 /* GtkWidget::unrealize destroys children and widget->window */
571 if (GTK_WIDGET_CLASS (ev_page_view_parent_class)->unrealize)
572 (* GTK_WIDGET_CLASS (ev_page_view_parent_class)->unrealize) (widget);
576 ev_page_view_map (GtkWidget *widget)
578 EvPageView *page_view;
580 page_view = EV_PAGE_VIEW (widget);
582 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
584 gdk_window_show (page_view->priv->bin_window);
585 gdk_window_show (widget->window);
589 ev_page_view_load (EvPageView *page_view)
592 gboolean uniform_page_size = TRUE;
593 int width = 0, height = 0;
595 page_view->priv->n_pages =
596 ev_document_get_n_pages (page_view->priv->document);
598 for (i = 1; i <= page_view->priv->n_pages; i++) {
599 EvPageViewInfo *info;
601 gint page_height = 0;
603 ev_document_set_scale (page_view->priv->document, page_view->priv->scale);
604 ev_document_get_page_size (page_view->priv->document,
606 &page_width, &page_height);
610 height = page_height;
611 } else if (width != page_width || height != page_height) {
612 /* It's a different page size. Backfill the array. */
615 uniform_page_size = FALSE;
617 page_view->priv->page_sizes =
618 g_new0 (EvPageViewInfo, page_view->priv->n_pages);
620 for (j = 1; j < i; j++) {
622 info = &(page_view->priv->page_sizes[j - 1]);
624 info->height = height;
628 if (! uniform_page_size) {
629 info = &(page_view->priv->page_sizes[i - 1]);
631 info->width = page_width;
632 info->height = page_height;
636 page_view->priv->uniform_page_size = uniform_page_size;
638 if (uniform_page_size) {
639 page_view->priv->uniform_page_width = width;
640 page_view->priv->uniform_page_height = height;
643 ev_page_view_update_size (page_view);
645 gtk_widget_queue_resize (GTK_WIDGET (page_view));
648 /* Public functions */
650 ev_page_view_new (void)
652 return g_object_new (EV_TYPE_PAGE_VIEW, NULL);
656 ev_page_view_set_document (EvPageView *page_view,
657 EvDocument *document)
659 g_return_if_fail (EV_IS_PAGE_VIEW (page_view));
661 if (document != page_view->priv->document) {
662 if (page_view->priv->document) {
663 g_object_unref (page_view->priv->document);
666 page_view->priv->document = document;
668 if (page_view->priv->document) {
669 g_object_ref (page_view->priv->document);
672 if (GTK_WIDGET_REALIZED (page_view)) {
673 ev_page_view_realize_document (page_view);