1 /* this file is part of evince, a gnome document viewer
3 * Copyright (C) 2004 Red Hat, Inc
5 * Evince is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * Evince is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20 #include <gtk/gtkalignment.h>
22 #include "ev-marshal.h"
25 #define EV_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_VIEW, EvViewClass))
26 #define EV_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_VIEW))
27 #define EV_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_VIEW, EvViewClass))
30 GtkWidget parent_instance;
34 GdkWindow *bin_window;
39 GtkAdjustment *hadjustment;
40 GtkAdjustment *vadjustment;
44 GtkWidgetClass parent_class;
46 void (*set_scroll_adjustments) (EvView *view,
47 GtkAdjustment *hadjustment,
48 GtkAdjustment *vadjustment);
50 /* Should this be notify::page? */
51 void (*page_changed) (EvView *view);
54 static guint page_changed_signal = 0;
56 static void ev_view_set_scroll_adjustments (EvView *view,
57 GtkAdjustment *hadjustment,
58 GtkAdjustment *vadjustment);
60 G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_WIDGET)
62 /*** Helper functions ***/
65 view_update_adjustments (EvView *view)
67 int old_x = view->scroll_x;
68 int old_y = view->scroll_y;
70 if (view->hadjustment)
71 view->scroll_x = view->hadjustment->value;
75 if (view->vadjustment)
76 view->scroll_y = view->vadjustment->value;
80 if (GTK_WIDGET_REALIZED (view) &&
81 (view->scroll_x != old_x || view->scroll_y != old_y)) {
82 gdk_window_move (view->bin_window, - view->scroll_x, - view->scroll_y);
83 gdk_window_process_updates (view->bin_window, TRUE);
88 view_set_adjustment_values (EvView *view,
89 GtkOrientation orientation)
91 GtkWidget *widget = GTK_WIDGET (view);
92 GtkAdjustment *adjustment;
93 gboolean value_changed = FALSE;
97 if (orientation == GTK_ORIENTATION_HORIZONTAL) {
98 requisition = widget->requisition.width;
99 allocation = widget->allocation.width;
100 adjustment = view->hadjustment;
102 requisition = widget->requisition.height;
103 allocation = widget->allocation.height;
104 adjustment = view->vadjustment;
110 adjustment->page_size = allocation;
111 adjustment->step_increment = allocation * 0.1;
112 adjustment->page_increment = allocation * 0.9;
113 adjustment->lower = 0;
114 adjustment->upper = MAX (allocation, requisition);
116 if (adjustment->value > adjustment->upper - adjustment->page_size) {
117 adjustment->value = adjustment->upper - adjustment->page_size;
118 value_changed = TRUE;
121 gtk_adjustment_changed (adjustment);
123 gtk_adjustment_value_changed (adjustment);
126 /*** Virtual function implementations ***/
129 ev_view_finalize (GObject *object)
131 EvView *view = EV_VIEW (object);
134 g_object_unref (view->document);
136 ev_view_set_scroll_adjustments (view, NULL, NULL);
138 G_OBJECT_CLASS (ev_view_parent_class)->finalize (object);
142 ev_view_destroy (GtkObject *object)
144 EvView *view = EV_VIEW (object);
146 ev_view_set_scroll_adjustments (view, NULL, NULL);
148 GTK_OBJECT_CLASS (ev_view_parent_class)->destroy (object);
152 ev_view_size_request (GtkWidget *widget,
153 GtkRequisition *requisition)
155 EvView *view = EV_VIEW (widget);
157 if (GTK_WIDGET_REALIZED (widget)) {
158 if (view->document) {
159 ev_document_get_page_size (view->document,
161 &requisition->height);
163 requisition->width = 10;
164 requisition->height = 10;
171 ev_view_size_allocate (GtkWidget *widget,
172 GtkAllocation *allocation)
174 EvView *view = EV_VIEW (widget);
176 GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation);
178 view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
179 view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
181 if (GTK_WIDGET_REALIZED (widget)) {
182 gdk_window_resize (view->bin_window,
183 MAX (widget->allocation.width, widget->requisition.width),
184 MAX (widget->allocation.height, widget->requisition.height));
189 update_window_backgrounds (EvView *view)
191 GtkWidget *widget = GTK_WIDGET (view);
193 if (GTK_WIDGET_REALIZED (view)) {
194 gdk_window_set_background (view->bin_window,
195 &widget->style->base[GTK_WIDGET_STATE (widget)]);
200 ev_view_realize (GtkWidget *widget)
202 EvView *view = EV_VIEW (widget);
203 GdkWindowAttr attributes;
205 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
207 attributes.window_type = GDK_WINDOW_CHILD;
208 attributes.wclass = GDK_INPUT_OUTPUT;
209 attributes.visual = gtk_widget_get_visual (widget);
210 attributes.colormap = gtk_widget_get_colormap (widget);
212 attributes.x = widget->allocation.x;
213 attributes.y = widget->allocation.y;
214 attributes.width = widget->allocation.width;
215 attributes.height = widget->allocation.height;
216 attributes.event_mask = 0;
218 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
220 GDK_WA_X | GDK_WA_Y |
223 gdk_window_set_user_data (widget->window, widget);
224 widget->style = gtk_style_attach (widget->style, widget->window);
228 attributes.width = MAX (widget->allocation.width, widget->requisition.width);
229 attributes.height = MAX (widget->allocation.height, widget->requisition.height);
230 attributes.event_mask = GDK_EXPOSURE_MASK;
232 view->bin_window = gdk_window_new (widget->window,
234 GDK_WA_X | GDK_WA_Y |
237 gdk_window_set_user_data (view->bin_window, widget);
238 gdk_window_show (view->bin_window);
240 if (view->document) {
241 ev_document_set_target (view->document, view->bin_window);
243 /* We can't get page size without a target, so we have to
244 * queue a size request at realization. Could be fixed
245 * with EvDocument changes to allow setting a GdkScreen
246 * without setting a target.
248 gtk_widget_queue_resize (widget);
251 update_window_backgrounds (view);
255 ev_view_unrealize (GtkWidget *widget)
257 EvView *view = EV_VIEW (widget);
260 ev_document_set_target (view->document, NULL);
262 gdk_window_set_user_data (view->bin_window, NULL);
263 gdk_window_destroy (view->bin_window);
264 view->bin_window = NULL;
266 GTK_WIDGET_CLASS (ev_view_parent_class)->unrealize (widget);
270 ev_view_style_set (GtkWidget *widget,
271 GtkStyle *previous_style)
273 update_window_backgrounds (EV_VIEW (widget));
277 ev_view_state_changed (GtkWidget *widget,
278 GtkStateType previous_state)
280 update_window_backgrounds (EV_VIEW (widget));
284 expose_bin_window (GtkWidget *widget,
285 GdkEventExpose *event)
287 EvView *view = EV_VIEW (widget);
290 ev_document_render (view->document,
291 event->area.x, event->area.y,
292 event->area.width, event->area.height);
296 ev_view_expose_event (GtkWidget *widget,
297 GdkEventExpose *event)
299 EvView *view = EV_VIEW (widget);
301 if (event->window == view->bin_window)
302 expose_bin_window (widget, event);
304 return GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event (widget, event);
311 ev_view_button_press_event (GtkWidget *widget,
312 GdkEventButton *event)
314 /* EvView *view = EV_VIEW (widget); */
320 ev_view_motion_notify_event (GtkWidget *widget,
321 GdkEventMotion *event)
323 /* EvView *view = EV_VIEW (widget); */
329 ev_view_button_release_event (GtkWidget *widget,
330 GdkEventButton *event)
332 /* EvView *view = EV_VIEW (widget); */
338 on_adjustment_value_changed (GtkAdjustment *adjustment,
341 view_update_adjustments (view);
345 set_scroll_adjustment (EvView *view,
346 GtkOrientation orientation,
347 GtkAdjustment *adjustment)
349 GtkAdjustment **to_set;
351 if (orientation == GTK_ORIENTATION_HORIZONTAL)
352 to_set = &view->hadjustment;
354 to_set = &view->vadjustment;
356 if (*to_set != adjustment) {
358 g_signal_handlers_disconnect_by_func (*to_set,
359 (gpointer) on_adjustment_value_changed,
361 g_object_unref (*to_set);
364 *to_set = adjustment;
365 view_set_adjustment_values (view, orientation);
368 g_object_ref (*to_set);
369 g_signal_connect (*to_set, "value_changed",
370 G_CALLBACK (on_adjustment_value_changed), view);
376 ev_view_set_scroll_adjustments (EvView *view,
377 GtkAdjustment *hadjustment,
378 GtkAdjustment *vadjustment)
380 set_scroll_adjustment (view, GTK_ORIENTATION_HORIZONTAL, hadjustment);
381 set_scroll_adjustment (view, GTK_ORIENTATION_VERTICAL, vadjustment);
383 view_update_adjustments (view);
387 ev_view_class_init (EvViewClass *class)
389 GObjectClass *object_class = G_OBJECT_CLASS (class);
390 GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (class);
391 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
393 object_class->finalize = ev_view_finalize;
395 widget_class->expose_event = ev_view_expose_event;
396 widget_class->button_press_event = ev_view_button_press_event;
397 widget_class->motion_notify_event = ev_view_motion_notify_event;
398 widget_class->button_release_event = ev_view_button_release_event;
399 widget_class->size_request = ev_view_size_request;
400 widget_class->size_allocate = ev_view_size_allocate;
401 widget_class->realize = ev_view_realize;
402 widget_class->unrealize = ev_view_unrealize;
403 widget_class->style_set = ev_view_style_set;
404 widget_class->state_changed = ev_view_state_changed;
405 gtk_object_class->destroy = ev_view_destroy;
407 class->set_scroll_adjustments = ev_view_set_scroll_adjustments;
409 widget_class->set_scroll_adjustments_signal = g_signal_new ("set-scroll-adjustments",
410 G_OBJECT_CLASS_TYPE (object_class),
411 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
412 G_STRUCT_OFFSET (EvViewClass, set_scroll_adjustments),
414 ev_marshal_VOID__OBJECT_OBJECT,
417 GTK_TYPE_ADJUSTMENT);
418 page_changed_signal = g_signal_new ("page-changed",
419 G_OBJECT_CLASS_TYPE (object_class),
420 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
421 G_STRUCT_OFFSET (EvViewClass, page_changed),
423 ev_marshal_VOID__NONE,
428 ev_view_init (EvView *view)
430 static const GdkColor white = { 0, 0xffff, 0xffff, 0xffff };
432 gtk_widget_modify_bg (GTK_WIDGET (view), GTK_STATE_NORMAL, &white);
440 return g_object_new (EV_TYPE_VIEW, NULL);
444 ev_view_set_document (EvView *view,
445 EvDocument *document)
447 g_return_if_fail (EV_IS_VIEW (view));
449 if (document != view->document) {
450 int old_page = ev_view_get_page (view);
453 g_object_unref (view->document);
455 view->document = document;
458 g_object_ref (view->document);
460 if (GTK_WIDGET_REALIZED (view))
461 ev_document_set_target (view->document, view->bin_window);
463 gtk_widget_queue_resize (GTK_WIDGET (view));
465 if (old_page != ev_view_get_page (view))
466 g_signal_emit (view, page_changed_signal, 0);
471 ev_view_set_page (EvView *view,
474 if (view->document) {
475 int old_page = ev_document_get_page (view->document);
476 if (old_page != page)
477 ev_document_set_page (view->document, page);
478 if (old_page != ev_document_get_page (view->document)) {
479 g_signal_emit (view, page_changed_signal, 0);
480 gtk_widget_queue_draw (GTK_WIDGET (view));
486 ev_view_get_page (EvView *view)
489 return ev_document_get_page (view->document);