]> www.fi.muni.cz Git - evince.git/blob - shell/ev-page-view.c
Updated Catalan translation by Gil Forcada <gilforcada@guifi.net>.
[evince.git] / shell / ev-page-view.c
1 /*
2  *  Copyright (C) 2005 Jonathan Blandford
3  *
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)
7  *  any later version.
8  *
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.
13  *
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.
17  */
18
19 #include "config.h"
20
21 #include "ev-page-view.h"
22 #include "ev-marshal.h"
23 #include "ev-document-misc.h"
24 #include "ev-debug.h"
25 #include <gtk/gtk.h>
26
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
30 {
31         gint width;
32         gint height;
33 } EvPageViewInfo;
34
35 struct _EvPageViewPrivate
36 {
37         gint width, height;
38         gint page_spacing;
39
40         GdkWindow *bin_window;
41         EvDocument *document;
42         EvPageViewInfo *page_sizes;
43
44         GtkAdjustment *hadjustment;
45         GtkAdjustment *vadjustment;
46
47         gdouble scale;
48
49         /* Page information*/
50         gint n_pages;
51         gint max_page_width;
52
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;
57 };
58
59
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);
78
79
80 G_DEFINE_TYPE (EvPageView, ev_page_view, GTK_TYPE_WIDGET)
81
82 #define EV_PAGE_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_PAGE_VIEW, EvPageViewPrivate))
83
84 static void
85 ev_page_view_init (EvPageView *page_view)
86 {
87         page_view->priv = EV_PAGE_VIEW_GET_PRIVATE (page_view);
88
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;
93
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;
99 }
100
101 static void
102 ev_page_view_dispose (GObject *object)
103 {
104         EvPageView *view = EV_PAGE_VIEW (object);
105
106         LOG ("dispose");
107
108         if (view->priv->document) {
109                 g_object_unref (view->priv->document);
110                 view->priv->document = NULL;
111         }
112
113         G_OBJECT_CLASS (ev_page_view_parent_class)->dispose (object);
114 }
115
116 static void
117 ev_page_view_class_init (EvPageViewClass *klass)
118 {
119         GObjectClass *o_class;
120         GtkWidgetClass *widget_class;
121
122         o_class = (GObjectClass *) klass;
123         widget_class = (GtkWidgetClass *) klass;
124         klass->set_scroll_adjustments = ev_page_view_set_scroll_adjustments;
125
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;
133
134         o_class->dispose = ev_page_view_dispose;
135
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),
141                               NULL, NULL,
142                               ev_marshal_VOID__OBJECT_OBJECT,
143                               G_TYPE_NONE, 2,
144                               GTK_TYPE_ADJUSTMENT,
145                               GTK_TYPE_ADJUSTMENT);
146
147
148 }
149
150
151 static void
152 ev_page_view_set_scroll_adjustments (EvPageView    *page_view,
153                                      GtkAdjustment *hadjustment,
154                                      GtkAdjustment *vadjustment)
155 {
156   gboolean need_adjust = FALSE;
157
158   if (hadjustment)
159     g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
160   else
161     hadjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
162   if (vadjustment)
163     g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
164   else
165     vadjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
166
167   if (page_view->priv->hadjustment && (page_view->priv->hadjustment != hadjustment))
168     {
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);
172     }
173
174   if (page_view->priv->vadjustment && (page_view->priv->vadjustment != vadjustment))
175     {
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);
179     }
180
181   if (page_view->priv->hadjustment != hadjustment)
182     {
183       page_view->priv->hadjustment = hadjustment;
184       g_object_ref (page_view->priv->hadjustment);
185       gtk_object_sink (GTK_OBJECT (page_view->priv->hadjustment));
186
187       g_signal_connect (page_view->priv->hadjustment, "value_changed",
188                         G_CALLBACK (ev_page_view_adjustment_changed),
189                         page_view);
190       need_adjust = TRUE;
191     }
192
193   if (page_view->priv->vadjustment != vadjustment)
194     {
195       page_view->priv->vadjustment = vadjustment;
196       g_object_ref (page_view->priv->vadjustment);
197       gtk_object_sink (GTK_OBJECT (page_view->priv->vadjustment));
198
199       g_signal_connect (page_view->priv->vadjustment, "value_changed",
200                         G_CALLBACK (ev_page_view_adjustment_changed),
201                         page_view);
202       need_adjust = TRUE;
203     }
204
205   if (need_adjust)
206           ev_page_view_adjustment_changed (NULL, page_view);
207 }
208
209 static void
210 ev_page_view_update_size (EvPageView *page_view)
211 {
212         gint left_border;
213         gint right_border;
214         gint top_border;
215         gint bottom_border;
216         gint width, height;
217
218         g_assert (page_view->priv->scale > 0.0);
219
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);
225
226                 ev_document_misc_get_page_border_size (width, height,
227                                                        & left_border, & right_border,
228                                                        & top_border, & bottom_border);
229
230                 page_view->priv->width = width
231                         + page_view->priv->page_spacing * 2
232                         + left_border
233                         + right_border;
234                 page_view->priv->height =
235                         ((height
236                           + page_view->priv->page_spacing
237                           + top_border
238                           + bottom_border)
239                          * page_view->priv->n_pages) +
240                         page_view->priv->page_spacing;
241         } else {
242                 int i;
243
244                 page_view->priv->width = 0;
245                 page_view->priv->height = page_view->priv->page_spacing;
246
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;
252
253                         ev_document_misc_get_page_border_size (width, height,
254                                                                & left_border, & right_border,
255                                                                & top_border, & bottom_border);
256
257                         width = width
258                                 + page_view->priv->page_spacing * 2
259                                 + left_border
260                                 + right_border;
261                         height = height
262                                 + page_view->priv->page_spacing
263                                 + top_border
264                                 + bottom_border;
265
266                         page_view->priv->width = MAX (width, page_view->priv->width);
267                         page_view->priv->height += height;
268                 }
269         }
270
271 }
272
273 static void
274 ev_page_view_size_request (GtkWidget      *widget,
275                            GtkRequisition *requisition)
276 {
277         EvPageView *page_view;
278
279         page_view = EV_PAGE_VIEW (widget);
280
281         ev_page_view_update_size (page_view);
282
283         requisition->width = page_view->priv->width;
284         requisition->height = page_view->priv->height;
285 }
286
287 static void
288 ev_page_view_paint_one_page (EvPageView   *page_view,
289                              GdkRectangle *area,
290                              gint          left_border,
291                              gint          right_border,
292                              gint          top_border,
293                              gint          bottom_border)
294 {
295         GtkWidget *widget;
296
297         widget = GTK_WIDGET (page_view);
298
299                 g_print ("paint one page (%d,%d) %dx%d\n",
300                  area->x, area->y,
301                  area->width,
302                  area->height);
303         gdk_draw_rectangle (page_view->priv->bin_window,
304                             widget->style->black_gc,
305                             TRUE,
306                             area->x,
307                             area->y,
308                             area->width,
309                             area->height);
310         gdk_draw_rectangle (page_view->priv->bin_window,
311                             widget->style->white_gc,
312                             TRUE,
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],
319                             TRUE,
320                             area->x,
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],
326                             TRUE,
327                             area->x + area->width - (right_border - left_border),
328                             area->y,
329                             right_border - left_border,
330                             right_border - left_border);
331 }
332
333 static void
334 ev_page_view_expose_uniform (GtkWidget      *widget,
335                              GdkEventExpose *expose)
336 {
337         EvPageView *page_view;
338         gint left_border;
339         gint right_border;
340         gint top_border;
341         gint bottom_border;
342         int x_offset = 0;
343         GdkRectangle rectangle;
344         gint width, height;
345         int i;
346
347         page_view = EV_PAGE_VIEW (widget);
348
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);
353
354         if (widget->allocation.width > page_view->priv->width)
355                 x_offset = (widget->allocation.width - page_view->priv->width)/2;
356
357         ev_document_misc_get_page_border_size (width, height,
358                                                & left_border,
359                                                & right_border,
360                                                & top_border,
361                                                & bottom_border);
362
363         rectangle.x = page_view->priv->page_spacing + x_offset;
364         rectangle.y = page_view->priv->page_spacing;
365         rectangle.width = width
366                 + left_border
367                 + right_border;
368         rectangle.height = height
369                 + top_border
370                 + bottom_border;
371         for (i = 0; i < page_view->priv->n_pages; i++) {
372                 GdkRectangle unused;
373
374                 if (gdk_rectangle_intersect (&rectangle,
375                                              &expose->area,
376                                              &unused))
377                         ev_page_view_paint_one_page (page_view,
378                                                      & rectangle,
379                                                      left_border, right_border,
380                                                      top_border, bottom_border);
381                 rectangle.y += rectangle.height
382                         + page_view->priv->page_spacing;
383
384         }
385 }
386
387 static void
388 ev_page_view_expose_pages (GtkWidget      *widget,
389                            GdkEventExpose *expose)
390 {
391         EvPageView *page_view;
392         gint left_border;
393         gint right_border;
394         gint top_border;
395         gint bottom_border;
396         int x_offset = 0;
397         GdkRectangle rectangle;
398         gint width, height;
399         int i;
400
401         page_view = EV_PAGE_VIEW (widget);
402
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);
407
408         if (widget->allocation.width > page_view->priv->width)
409                 x_offset = (widget->allocation.width - page_view->priv->width)/2;
410
411         ev_document_misc_get_page_border_size (width, height,
412                                                & left_border,
413                                                & right_border,
414                                                & top_border,
415                                                & bottom_border);
416
417         rectangle.x = page_view->priv->page_spacing + x_offset;
418         rectangle.y = page_view->priv->page_spacing;
419         rectangle.width = width
420                 + left_border
421                 + right_border;
422         rectangle.height = height
423                 + top_border
424                 + bottom_border;
425         for (i = 0; i < page_view->priv->n_pages; i++) {
426                 GdkRectangle unused;
427
428                 if (gdk_rectangle_intersect (&rectangle,
429                                              &expose->area,
430                                              &unused))
431                         ev_page_view_paint_one_page (page_view,
432                                                      & rectangle,
433                                                      left_border, right_border,
434                                                      top_border, bottom_border);
435                 rectangle.y += rectangle.height
436                         + page_view->priv->page_spacing;
437
438         }
439 }
440
441 static gboolean
442 ev_page_view_expose (GtkWidget      *widget,
443                      GdkEventExpose *expose)
444 {
445         EvPageView *page_view;
446
447         page_view = EV_PAGE_VIEW (widget);
448
449         if (expose->window != page_view->priv->bin_window)
450                 return FALSE;
451
452         if (page_view->priv->uniform_page_size) {
453                 ev_page_view_expose_uniform (widget, expose);
454         } else {
455                 ev_page_view_expose_pages (widget, expose);
456         }
457
458         return TRUE;
459 }
460
461 static void
462 ev_page_view_size_allocate (GtkWidget     *widget,
463                             GtkAllocation *allocation)
464 {
465   EvPageView *page_view;
466
467   widget->allocation = *allocation;
468
469   page_view = EV_PAGE_VIEW (widget);
470
471   if (GTK_WIDGET_REALIZED (widget))
472     {
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));
479     }
480
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);
487
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);
494 }
495
496 static void
497 ev_page_view_adjustment_changed (GtkAdjustment *adjustment,
498                                  EvPageView    *page_view)
499 {
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);
504
505                 gdk_window_process_updates (page_view->priv->bin_window, TRUE);
506         }
507 }
508
509 static void
510 ev_page_view_realize_document (EvPageView *page_view)
511 {
512         if (page_view->priv->document == NULL)
513                 return;
514
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));
519 }
520
521
522 static void
523 ev_page_view_realize (GtkWidget *widget)
524 {
525         EvPageView *page_view;
526         GdkWindowAttr attributes;
527         gint attributes_mask;
528
529         g_return_if_fail (EV_IS_PAGE_VIEW (widget));
530
531         page_view = EV_PAGE_VIEW (widget);
532         GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
533
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;
544
545         attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
546
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);
550
551         /* Make the window for the page view */
552         attributes.x = 0;
553         attributes.y = 0;
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 |
557                                  GDK_SCROLL_MASK |
558                                  GDK_POINTER_MOTION_MASK |
559                                  GDK_BUTTON_PRESS_MASK |
560                                  GDK_BUTTON_RELEASE_MASK |
561                                  GDK_KEY_PRESS_MASK |
562                                  GDK_KEY_RELEASE_MASK) |
563                 gtk_widget_get_events (widget);
564
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);
568
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]);
572
573         ev_page_view_realize_document (page_view);
574 }
575
576
577 static void
578 ev_page_view_unrealize (GtkWidget *widget)
579 {
580   EvPageView *page_view;
581
582   page_view = EV_PAGE_VIEW (widget);
583
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;
587
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);
591 }
592
593 static void
594 ev_page_view_map (GtkWidget *widget)
595 {
596   EvPageView *page_view;
597
598   page_view = EV_PAGE_VIEW (widget);
599
600   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
601
602   gdk_window_show (page_view->priv->bin_window);
603   gdk_window_show (widget->window);
604 }
605
606 static void
607 ev_page_view_load (EvPageView *page_view)
608 {
609         int i;
610         gboolean uniform_page_size = TRUE;
611         int width = 0, height = 0;
612
613         page_view->priv->n_pages =
614                 ev_document_get_n_pages (page_view->priv->document);
615
616         for (i = 1; i <= page_view->priv->n_pages; i++) {
617                 EvPageViewInfo *info;
618                 gint page_width = 0;
619                 gint page_height = 0;
620
621                 ev_document_set_scale (page_view->priv->document, page_view->priv->scale);
622                 ev_document_get_page_size (page_view->priv->document,
623                                            i,
624                                            &page_width, &page_height);
625
626                 if (i == 1) {
627                         width = page_width;
628                         height = page_height;
629                 } else if (width != page_width || height != page_height) {
630                         /* It's a different page size.  Backfill the array. */
631                         int j;
632
633                         uniform_page_size = FALSE;
634
635                         page_view->priv->page_sizes =
636                                 g_new0 (EvPageViewInfo, page_view->priv->n_pages);
637
638                         for (j = 1; j < i; j++) {
639
640                                 info = &(page_view->priv->page_sizes[j - 1]);
641                                 info->width = width;
642                                 info->height = height;
643                         }
644                 }
645
646                 if (! uniform_page_size) {
647                         info = &(page_view->priv->page_sizes[i - 1]);
648
649                         info->width = page_width;
650                         info->height = page_height;
651                 }
652         }
653
654         page_view->priv->uniform_page_size = uniform_page_size;
655
656         if (uniform_page_size) {
657                 page_view->priv->uniform_page_width = width;
658                 page_view->priv->uniform_page_height = height;
659         }
660
661         ev_page_view_update_size (page_view);
662
663         gtk_widget_queue_resize (GTK_WIDGET (page_view));
664 }
665
666 /* Public functions */
667 GtkWidget *
668 ev_page_view_new (void)
669 {
670         return g_object_new (EV_TYPE_PAGE_VIEW, NULL);
671 }
672
673 void
674 ev_page_view_set_document (EvPageView *page_view,
675                            EvDocument *document)
676 {
677         g_return_if_fail (EV_IS_PAGE_VIEW (page_view));
678
679         if (document != page_view->priv->document) {
680                 if (page_view->priv->document) {
681                         g_object_unref (page_view->priv->document);
682                 }
683
684                 page_view->priv->document = document;
685
686                 if (page_view->priv->document) {
687                         g_object_ref (page_view->priv->document);
688                 }
689
690                 if (GTK_WIDGET_REALIZED (page_view)) {
691                         ev_page_view_realize_document (page_view);
692                 }
693         }
694
695 }
696