]> Pileus Git - ~andy/gtk/blob - gtk/gtkviewport.c
marshaller fixes.
[~andy/gtk] / gtk / gtkviewport.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "gtksignal.h"
28 #include "gtkviewport.h"
29
30 enum {
31   ARG_0,
32   ARG_HADJUSTMENT,
33   ARG_VADJUSTMENT,
34   ARG_SHADOW_TYPE
35 };
36
37
38 static void gtk_viewport_class_init               (GtkViewportClass *klass);
39 static void gtk_viewport_init                     (GtkViewport      *viewport);
40 static void gtk_viewport_destroy                  (GtkObject        *object);
41 static void gtk_viewport_set_arg                  (GtkObject        *object,
42                                                    GtkArg           *arg,
43                                                    guint             arg_id);
44 static void gtk_viewport_get_arg                  (GtkObject        *object,
45                                                    GtkArg           *arg,
46                                                    guint             arg_id);
47 static void gtk_viewport_set_scroll_adjustments   (GtkViewport      *viewport,
48                                                    GtkAdjustment    *hadjustment,
49                                                    GtkAdjustment    *vadjustment);
50 static void gtk_viewport_map                      (GtkWidget        *widget);
51 static void gtk_viewport_unmap                    (GtkWidget        *widget);
52 static void gtk_viewport_realize                  (GtkWidget        *widget);
53 static void gtk_viewport_unrealize                (GtkWidget        *widget);
54 static void gtk_viewport_paint                    (GtkWidget        *widget,
55                                                    GdkRectangle     *area);
56 static gint gtk_viewport_expose                   (GtkWidget        *widget,
57                                                    GdkEventExpose   *event);
58 static void gtk_viewport_add                      (GtkContainer     *container,
59                                                    GtkWidget        *widget);
60 static void gtk_viewport_size_request             (GtkWidget        *widget,
61                                                    GtkRequisition   *requisition);
62 static void gtk_viewport_size_allocate            (GtkWidget        *widget,
63                                                    GtkAllocation    *allocation);
64 static void gtk_viewport_adjustment_changed       (GtkAdjustment    *adjustment,
65                                                    gpointer          data);
66 static void gtk_viewport_adjustment_value_changed (GtkAdjustment    *adjustment,
67                                                    gpointer          data);
68 static void gtk_viewport_style_set                (GtkWidget *widget,
69                                                    GtkStyle  *previous_style);
70
71 static GtkBinClass *parent_class;
72
73 GtkType
74 gtk_viewport_get_type (void)
75 {
76   static GtkType viewport_type = 0;
77
78   if (!viewport_type)
79     {
80       static const GtkTypeInfo viewport_info =
81       {
82         "GtkViewport",
83         sizeof (GtkViewport),
84         sizeof (GtkViewportClass),
85         (GtkClassInitFunc) gtk_viewport_class_init,
86         (GtkObjectInitFunc) gtk_viewport_init,
87         /* reserved_1 */ NULL,
88         /* reserved_2 */ NULL,
89         (GtkClassInitFunc) NULL,
90       };
91
92       viewport_type = gtk_type_unique (GTK_TYPE_BIN, &viewport_info);
93     }
94
95   return viewport_type;
96 }
97
98 static void
99 gtk_viewport_class_init (GtkViewportClass *class)
100 {
101   GtkObjectClass *object_class;
102   GtkWidgetClass *widget_class;
103   GtkContainerClass *container_class;
104
105   object_class = (GtkObjectClass*) class;
106   widget_class = (GtkWidgetClass*) class;
107   container_class = (GtkContainerClass*) class;
108   parent_class = (GtkBinClass*) gtk_type_class (GTK_TYPE_BIN);
109
110   object_class->set_arg = gtk_viewport_set_arg;
111   object_class->get_arg = gtk_viewport_get_arg;
112   object_class->destroy = gtk_viewport_destroy;
113   
114   widget_class->map = gtk_viewport_map;
115   widget_class->unmap = gtk_viewport_unmap;
116   widget_class->realize = gtk_viewport_realize;
117   widget_class->unrealize = gtk_viewport_unrealize;
118   widget_class->expose_event = gtk_viewport_expose;
119   widget_class->size_request = gtk_viewport_size_request;
120   widget_class->size_allocate = gtk_viewport_size_allocate;
121   widget_class->style_set = gtk_viewport_style_set;
122   
123   container_class->add = gtk_viewport_add;
124
125   class->set_scroll_adjustments = gtk_viewport_set_scroll_adjustments;
126
127   gtk_object_add_arg_type ("GtkViewport::hadjustment",
128                            GTK_TYPE_ADJUSTMENT,
129                            GTK_ARG_READWRITE,
130                            ARG_HADJUSTMENT);
131   gtk_object_add_arg_type ("GtkViewport::vadjustment",
132                            GTK_TYPE_ADJUSTMENT,
133                            GTK_ARG_READWRITE,
134                            ARG_VADJUSTMENT);
135   gtk_object_add_arg_type ("GtkViewport::shadow_type",
136                            GTK_TYPE_SHADOW_TYPE,
137                            GTK_ARG_READWRITE,
138                            ARG_SHADOW_TYPE);
139
140   widget_class->set_scroll_adjustments_signal =
141     gtk_signal_new ("set_scroll_adjustments",
142                     GTK_RUN_LAST,
143                     GTK_CLASS_TYPE (object_class),
144                     GTK_SIGNAL_OFFSET (GtkViewportClass, set_scroll_adjustments),
145                     gtk_marshal_VOID__OBJECT_OBJECT,
146                     GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
147 }
148
149 static void
150 gtk_viewport_set_arg (GtkObject        *object,
151                       GtkArg           *arg,
152                       guint             arg_id)
153 {
154   GtkViewport *viewport;
155
156   viewport = GTK_VIEWPORT (object);
157
158   switch (arg_id)
159     {
160     case ARG_HADJUSTMENT:
161       gtk_viewport_set_hadjustment (viewport, GTK_VALUE_POINTER (*arg));
162       break;
163     case ARG_VADJUSTMENT:
164       gtk_viewport_set_vadjustment (viewport, GTK_VALUE_POINTER (*arg));
165       break;
166     case ARG_SHADOW_TYPE:
167       gtk_viewport_set_shadow_type (viewport, GTK_VALUE_ENUM (*arg));
168       break;
169     default:
170       break;
171     }
172 }
173
174 static void
175 gtk_viewport_get_arg (GtkObject        *object,
176                       GtkArg           *arg,
177                       guint             arg_id)
178 {
179   GtkViewport *viewport;
180
181   viewport = GTK_VIEWPORT (object);
182
183   switch (arg_id)
184     {
185     case ARG_HADJUSTMENT:
186       GTK_VALUE_POINTER (*arg) = viewport->hadjustment;
187       break;
188     case ARG_VADJUSTMENT:
189       GTK_VALUE_POINTER (*arg) = viewport->vadjustment;
190       break;
191     case ARG_SHADOW_TYPE:
192       GTK_VALUE_ENUM (*arg) = viewport->shadow_type;
193       break;
194     default:
195       arg->type = GTK_TYPE_INVALID;
196       break;
197     }
198 }
199
200 static void
201 gtk_viewport_init (GtkViewport *viewport)
202 {
203   GTK_WIDGET_UNSET_FLAGS (viewport, GTK_NO_WINDOW);
204
205   gtk_container_set_resize_mode (GTK_CONTAINER (viewport), GTK_RESIZE_QUEUE);
206   
207   viewport->shadow_type = GTK_SHADOW_IN;
208   viewport->view_window = NULL;
209   viewport->bin_window = NULL;
210   viewport->hadjustment = NULL;
211   viewport->vadjustment = NULL;
212 }
213
214 GtkWidget*
215 gtk_viewport_new (GtkAdjustment *hadjustment,
216                   GtkAdjustment *vadjustment)
217 {
218   GtkWidget *viewport;
219
220   viewport = gtk_widget_new (GTK_TYPE_VIEWPORT,
221                              "hadjustment", hadjustment,
222                              "vadjustment", vadjustment,
223                              NULL);
224
225   return viewport;
226 }
227
228 static void
229 gtk_viewport_destroy (GtkObject *object)
230 {
231   GtkViewport *viewport = GTK_VIEWPORT (object);
232
233   if (viewport->hadjustment)
234     {
235       gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->hadjustment), viewport);
236       gtk_object_unref (GTK_OBJECT (viewport->hadjustment));
237       viewport->hadjustment = NULL;
238     }
239   if (viewport->vadjustment)
240     {
241       gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->vadjustment), viewport);
242       gtk_object_unref (GTK_OBJECT (viewport->vadjustment));
243       viewport->vadjustment = NULL;
244     }
245
246   GTK_OBJECT_CLASS (parent_class)->destroy (object);
247 }
248
249 GtkAdjustment*
250 gtk_viewport_get_hadjustment (GtkViewport *viewport)
251 {
252   g_return_val_if_fail (viewport != NULL, NULL);
253   g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);
254
255   if (!viewport->hadjustment)
256     gtk_viewport_set_hadjustment (viewport, NULL);
257
258   return viewport->hadjustment;
259 }
260
261 GtkAdjustment*
262 gtk_viewport_get_vadjustment (GtkViewport *viewport)
263 {
264   g_return_val_if_fail (viewport != NULL, NULL);
265   g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);
266
267   if (!viewport->vadjustment)
268     gtk_viewport_set_vadjustment (viewport, NULL);
269
270   return viewport->vadjustment;
271 }
272
273 void
274 gtk_viewport_set_hadjustment (GtkViewport   *viewport,
275                               GtkAdjustment *adjustment)
276 {
277   g_return_if_fail (viewport != NULL);
278   g_return_if_fail (GTK_IS_VIEWPORT (viewport));
279   if (adjustment)
280     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
281
282   if (viewport->hadjustment && viewport->hadjustment != adjustment)
283     {
284       gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->hadjustment), viewport);
285       gtk_object_unref (GTK_OBJECT (viewport->hadjustment));
286       viewport->hadjustment = NULL;
287     }
288
289   if (!adjustment)
290     adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0,
291                                                      0.0, 0.0, 0.0));
292
293   if (viewport->hadjustment != adjustment)
294     {
295       viewport->hadjustment = adjustment;
296       gtk_object_ref (GTK_OBJECT (viewport->hadjustment));
297       gtk_object_sink (GTK_OBJECT (viewport->hadjustment));
298       
299       gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
300                           (GtkSignalFunc) gtk_viewport_adjustment_changed,
301                           (gpointer) viewport);
302       gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
303                           (GtkSignalFunc) gtk_viewport_adjustment_value_changed,
304                           (gpointer) viewport);
305
306       gtk_viewport_adjustment_changed (adjustment, viewport);
307     }
308 }
309
310 void
311 gtk_viewport_set_vadjustment (GtkViewport   *viewport,
312                               GtkAdjustment *adjustment)
313 {
314   g_return_if_fail (viewport != NULL);
315   g_return_if_fail (GTK_IS_VIEWPORT (viewport));
316   if (adjustment)
317     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
318
319   if (viewport->vadjustment && viewport->vadjustment != adjustment)
320     {
321       gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->vadjustment), viewport);
322       gtk_object_unref (GTK_OBJECT (viewport->vadjustment));
323       viewport->vadjustment = NULL;
324     }
325
326   if (!adjustment)
327     adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0,
328                                                      0.0, 0.0, 0.0));
329
330   if (viewport->vadjustment != adjustment)
331     {
332       viewport->vadjustment = adjustment;
333       gtk_object_ref (GTK_OBJECT (viewport->vadjustment));
334       gtk_object_sink (GTK_OBJECT (viewport->vadjustment));
335       
336       gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
337                           (GtkSignalFunc) gtk_viewport_adjustment_changed,
338                           (gpointer) viewport);
339       gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
340                           (GtkSignalFunc) gtk_viewport_adjustment_value_changed,
341                           (gpointer) viewport);
342
343       gtk_viewport_adjustment_changed (adjustment, viewport);
344     }
345 }
346
347 static void
348 gtk_viewport_set_scroll_adjustments (GtkViewport      *viewport,
349                                      GtkAdjustment    *hadjustment,
350                                      GtkAdjustment    *vadjustment)
351 {
352   if (viewport->hadjustment != hadjustment)
353     gtk_viewport_set_hadjustment (viewport, hadjustment);
354   if (viewport->vadjustment != vadjustment)
355     gtk_viewport_set_vadjustment (viewport, vadjustment);
356 }
357
358 void
359 gtk_viewport_set_shadow_type (GtkViewport   *viewport,
360                               GtkShadowType  type)
361 {
362   g_return_if_fail (viewport != NULL);
363   g_return_if_fail (GTK_IS_VIEWPORT (viewport));
364
365   if ((GtkShadowType) viewport->shadow_type != type)
366     {
367       viewport->shadow_type = type;
368
369       if (GTK_WIDGET_VISIBLE (viewport))
370         {
371           gtk_widget_size_allocate (GTK_WIDGET (viewport), &(GTK_WIDGET (viewport)->allocation));
372           gtk_widget_queue_draw (GTK_WIDGET (viewport));
373         }
374     }
375 }
376
377
378 static void
379 gtk_viewport_map (GtkWidget *widget)
380 {
381   GtkBin *bin;
382
383   g_return_if_fail (widget != NULL);
384   g_return_if_fail (GTK_IS_VIEWPORT (widget));
385
386   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
387   bin = GTK_BIN (widget);
388
389   if (bin->child &&
390       GTK_WIDGET_VISIBLE (bin->child) &&
391       !GTK_WIDGET_MAPPED (bin->child))
392     gtk_widget_map (bin->child);
393
394   gdk_window_show (widget->window);
395 }
396
397 static void
398 gtk_viewport_unmap (GtkWidget *widget)
399 {
400   g_return_if_fail (widget != NULL);
401   g_return_if_fail (GTK_IS_VIEWPORT (widget));
402
403   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
404   
405   gdk_window_hide (widget->window);
406 }
407
408 static void
409 gtk_viewport_realize (GtkWidget *widget)
410 {
411   GtkBin *bin;
412   GtkViewport *viewport;
413   GdkWindowAttr attributes;
414   gint attributes_mask;
415   gint event_mask;
416   gint border_width;
417
418   g_return_if_fail (widget != NULL);
419   g_return_if_fail (GTK_IS_VIEWPORT (widget));
420
421   border_width = GTK_CONTAINER (widget)->border_width;
422
423   bin = GTK_BIN (widget);
424   viewport = GTK_VIEWPORT (widget);
425   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
426
427   attributes.x = widget->allocation.x + border_width;
428   attributes.y = widget->allocation.y + border_width;
429   attributes.width = widget->allocation.width - border_width * 2;
430   attributes.height = widget->allocation.height - border_width * 2;
431   attributes.window_type = GDK_WINDOW_CHILD;
432   attributes.wclass = GDK_INPUT_OUTPUT;
433   attributes.visual = gtk_widget_get_visual (widget);
434   attributes.colormap = gtk_widget_get_colormap (widget);
435
436   event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
437   /* We select on button_press_mask so that button 4-5 scrolls are trapped.
438    */
439   attributes.event_mask = event_mask | GDK_BUTTON_PRESS_MASK;
440
441   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
442
443   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
444                                    &attributes, attributes_mask);
445   gdk_window_set_user_data (widget->window, viewport);
446
447   if (viewport->shadow_type != GTK_SHADOW_NONE)
448     {
449       attributes.x = widget->style->xthickness;
450       attributes.y = widget->style->ythickness;
451     }
452   else
453     {
454       attributes.x = 0;
455       attributes.y = 0;
456     }
457
458   attributes.width = MAX (1, (gint)widget->allocation.width - attributes.x * 2 - border_width * 2);
459   attributes.height = MAX (1, (gint)widget->allocation.height - attributes.y * 2 - border_width * 2);
460   attributes.event_mask = 0;
461
462   viewport->view_window = gdk_window_new (widget->window, &attributes, attributes_mask);
463   gdk_window_set_user_data (viewport->view_window, viewport);
464
465   attributes.x = 0;
466   attributes.y = 0;
467
468   if (bin->child)
469     {
470       attributes.width = viewport->hadjustment->upper;
471       attributes.height = viewport->vadjustment->upper;
472     }
473   
474   attributes.event_mask = event_mask;
475
476   viewport->bin_window = gdk_window_new (viewport->view_window, &attributes, attributes_mask);
477   gdk_window_set_user_data (viewport->bin_window, viewport);
478
479   if (bin->child)
480     gtk_widget_set_parent_window (bin->child, viewport->bin_window);
481
482   widget->style = gtk_style_attach (widget->style, widget->window);
483   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
484   gtk_style_set_background (widget->style, viewport->bin_window, GTK_STATE_NORMAL);
485
486    gtk_paint_flat_box(widget->style, viewport->bin_window, GTK_STATE_NORMAL,
487                       GTK_SHADOW_NONE,
488                       NULL, widget, "viewportbin",
489                       0, 0, -1, -1);
490    
491   gdk_window_show (viewport->bin_window);
492   gdk_window_show (viewport->view_window);
493 }
494
495 static void
496 gtk_viewport_unrealize (GtkWidget *widget)
497 {
498   GtkViewport *viewport;
499
500   g_return_if_fail (widget != NULL);
501   g_return_if_fail (GTK_IS_VIEWPORT (widget));
502
503   viewport = GTK_VIEWPORT (widget);
504
505   gdk_window_set_user_data (viewport->view_window, NULL);
506   gdk_window_destroy (viewport->view_window);
507   viewport->view_window = NULL;
508
509   gdk_window_set_user_data (viewport->bin_window, NULL);
510   gdk_window_destroy (viewport->bin_window);
511   viewport->bin_window = NULL;
512
513   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
514     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
515 }
516
517 static void
518 gtk_viewport_paint (GtkWidget    *widget,
519                     GdkRectangle *area)
520 {
521   GtkViewport *viewport;
522
523   g_return_if_fail (widget != NULL);
524   g_return_if_fail (GTK_IS_VIEWPORT (widget));
525   g_return_if_fail (area != NULL);
526
527   if (GTK_WIDGET_DRAWABLE (widget))
528     {
529       viewport = GTK_VIEWPORT (widget);
530
531       gtk_draw_shadow (widget->style, widget->window,
532                        GTK_STATE_NORMAL, viewport->shadow_type,
533                        0, 0, -1, -1);
534     }
535 }
536
537 static gint
538 gtk_viewport_expose (GtkWidget      *widget,
539                      GdkEventExpose *event)
540 {
541   GtkViewport *viewport;
542   GtkBin *bin;
543   GdkEventExpose child_event;
544
545   g_return_val_if_fail (widget != NULL, FALSE);
546   g_return_val_if_fail (GTK_IS_VIEWPORT (widget), FALSE);
547   g_return_val_if_fail (event != NULL, FALSE);
548
549   if (GTK_WIDGET_DRAWABLE (widget))
550     {
551       viewport = GTK_VIEWPORT (widget);
552       bin = GTK_BIN (widget);
553
554       if (event->window == widget->window)
555         gtk_viewport_paint (widget, &event->area);
556       else if (event->window == viewport->bin_window)
557         {
558           child_event = *event;
559
560           gtk_paint_flat_box(widget->style, viewport->bin_window, 
561                              GTK_STATE_NORMAL, GTK_SHADOW_NONE,
562                              &event->area, widget, "viewportbin",
563                              0, 0, -1, -1);
564           
565           if ((bin->child != NULL) &&
566               GTK_WIDGET_NO_WINDOW (bin->child) &&
567               gtk_widget_intersect (bin->child, &event->area, &child_event.area))
568             gtk_widget_event (bin->child, (GdkEvent*) &child_event);
569         }
570         
571
572     }
573
574   return FALSE;
575 }
576
577 static void
578 gtk_viewport_add (GtkContainer *container,
579                   GtkWidget    *child)
580 {
581   GtkBin *bin;
582
583   g_return_if_fail (container != NULL);
584   g_return_if_fail (GTK_IS_VIEWPORT (container));
585   g_return_if_fail (child != NULL);
586
587   bin = GTK_BIN (container);
588   g_return_if_fail (bin->child == NULL);
589
590   gtk_widget_set_parent_window (child, GTK_VIEWPORT (bin)->bin_window);
591
592   GTK_CONTAINER_CLASS (parent_class)->add (container, child);
593 }
594
595 static void
596 gtk_viewport_size_request (GtkWidget      *widget,
597                            GtkRequisition *requisition)
598 {
599   GtkViewport *viewport;
600   GtkBin *bin;
601   GtkRequisition child_requisition;
602
603   g_return_if_fail (widget != NULL);
604   g_return_if_fail (GTK_IS_VIEWPORT (widget));
605   g_return_if_fail (requisition != NULL);
606
607   viewport = GTK_VIEWPORT (widget);
608   bin = GTK_BIN (widget);
609
610   requisition->width = (GTK_CONTAINER (widget)->border_width +
611                         GTK_WIDGET (widget)->style->xthickness) * 2 + 5;
612
613   requisition->height = (GTK_CONTAINER (widget)->border_width * 2 +
614                          GTK_WIDGET (widget)->style->ythickness) * 2 + 5;
615
616   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
617     {
618       gtk_widget_size_request (bin->child, &child_requisition);
619       requisition->width += child_requisition.width;
620       requisition->height += child_requisition.height;
621     }
622 }
623
624 static void
625 gtk_viewport_size_allocate (GtkWidget     *widget,
626                             GtkAllocation *allocation)
627 {
628   GtkViewport *viewport;
629   GtkBin *bin;
630   GtkAllocation child_allocation;
631   gint hval, vval;
632   gint border_width;
633
634   g_return_if_fail (widget != NULL);
635   g_return_if_fail (GTK_IS_VIEWPORT (widget));
636   g_return_if_fail (allocation != NULL);
637
638   widget->allocation = *allocation;
639   viewport = GTK_VIEWPORT (widget);
640   bin = GTK_BIN (widget);
641
642   /* demand creation */
643   if (!viewport->hadjustment)
644     gtk_viewport_set_hadjustment (viewport, NULL);
645   if (!viewport->vadjustment)
646     gtk_viewport_set_hadjustment (viewport, NULL);
647
648   border_width = GTK_CONTAINER (widget)->border_width;
649
650   child_allocation.x = 0;
651   child_allocation.y = 0;
652
653   if (viewport->shadow_type != GTK_SHADOW_NONE)
654     {
655       child_allocation.x = GTK_WIDGET (viewport)->style->xthickness;
656       child_allocation.y = GTK_WIDGET (viewport)->style->ythickness;
657     }
658
659   child_allocation.width = MAX (1, allocation->width - child_allocation.x * 2 - border_width * 2);
660   child_allocation.height = MAX (1, allocation->height - child_allocation.y * 2 - border_width * 2);
661
662   if (GTK_WIDGET_REALIZED (widget))
663     {
664       gdk_window_move_resize (widget->window,
665                               allocation->x + border_width,
666                               allocation->y + border_width,
667                               allocation->width - border_width * 2,
668                               allocation->height - border_width * 2);
669
670       gdk_window_move_resize (viewport->view_window,
671                               child_allocation.x,
672                               child_allocation.y,
673                               child_allocation.width,
674                               child_allocation.height);
675     }
676
677   viewport->hadjustment->page_size = child_allocation.width;
678   viewport->hadjustment->page_increment = viewport->hadjustment->page_size / 2;
679   viewport->hadjustment->step_increment = 10;
680
681   viewport->vadjustment->page_size = child_allocation.height;
682   viewport->vadjustment->page_increment = viewport->vadjustment->page_size / 2;
683   viewport->vadjustment->step_increment = 10;
684
685   hval = viewport->hadjustment->value;
686   vval = viewport->vadjustment->value;
687
688   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
689     {
690       GtkRequisition child_requisition;
691       gtk_widget_get_child_requisition (bin->child, &child_requisition);
692       
693       viewport->hadjustment->lower = 0;
694       viewport->hadjustment->upper = MAX (child_requisition.width,
695                                           child_allocation.width);
696
697       hval = CLAMP (hval, 0,
698                     viewport->hadjustment->upper -
699                     viewport->hadjustment->page_size);
700
701       viewport->vadjustment->lower = 0;
702       viewport->vadjustment->upper = MAX (child_requisition.height,
703                                           child_allocation.height);
704
705       vval = CLAMP (vval, 0,
706                     viewport->vadjustment->upper -
707                     viewport->vadjustment->page_size);
708     }
709
710   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
711     {
712       child_allocation.x = 0;
713       child_allocation.y = 0;
714
715       child_allocation.width = viewport->hadjustment->upper;
716       child_allocation.height = viewport->vadjustment->upper;
717
718       if (GTK_WIDGET_REALIZED (widget))
719         gdk_window_resize (viewport->bin_window,
720                            child_allocation.width,
721                            child_allocation.height);
722
723       child_allocation.x = 0;
724       child_allocation.y = 0;
725       gtk_widget_size_allocate (bin->child, &child_allocation);
726     }
727
728   gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "changed");
729   gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "changed");
730   if (viewport->hadjustment->value != hval)
731     {
732       viewport->hadjustment->value = hval;
733       gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "value_changed");
734     }
735   if (viewport->vadjustment->value != vval)
736     {
737       viewport->vadjustment->value = vval;
738       gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "value_changed");
739     }
740 }
741
742 static void
743 gtk_viewport_adjustment_changed (GtkAdjustment *adjustment,
744                                  gpointer       data)
745 {
746   GtkViewport *viewport;
747
748   g_return_if_fail (adjustment != NULL);
749   g_return_if_fail (data != NULL);
750   g_return_if_fail (GTK_IS_VIEWPORT (data));
751
752   viewport = GTK_VIEWPORT (data);
753 }
754
755 static void
756 gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment,
757                                        gpointer       data)
758 {
759   GtkViewport *viewport;
760   GtkBin *bin;
761   GtkAllocation child_allocation;
762
763   g_return_if_fail (adjustment != NULL);
764   g_return_if_fail (data != NULL);
765   g_return_if_fail (GTK_IS_VIEWPORT (data));
766
767   viewport = GTK_VIEWPORT (data);
768   bin = GTK_BIN (data);
769
770   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
771     {
772       child_allocation.x = 0;
773       child_allocation.y = 0;
774
775       if (viewport->hadjustment->lower != (viewport->hadjustment->upper -
776                                            viewport->hadjustment->page_size))
777         child_allocation.x =  viewport->hadjustment->lower - viewport->hadjustment->value;
778
779       if (viewport->vadjustment->lower != (viewport->vadjustment->upper -
780                                            viewport->vadjustment->page_size))
781         child_allocation.y = viewport->vadjustment->lower - viewport->vadjustment->value;
782
783       if (GTK_WIDGET_REALIZED (viewport))
784         {
785           gdk_window_move (viewport->bin_window,
786                            child_allocation.x,
787                            child_allocation.y);
788       
789           gdk_window_process_updates (viewport->bin_window, TRUE);
790         }
791     }
792 }
793
794 static void
795 gtk_viewport_style_set (GtkWidget *widget,
796                         GtkStyle  *previous_style)
797 {
798    GtkViewport *viewport;
799    
800    if (GTK_WIDGET_REALIZED (widget) &&
801        !GTK_WIDGET_NO_WINDOW (widget))
802      {
803         viewport = GTK_VIEWPORT (widget);
804         
805         gtk_style_set_background (widget->style, viewport->bin_window, GTK_STATE_NORMAL);
806         gtk_style_set_background (widget->style, widget->window, widget->state);
807      }
808 }