1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library 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.
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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 #include "gtksignal.h"
19 #include "gtkviewport.h"
22 static void gtk_viewport_class_init (GtkViewportClass *klass);
23 static void gtk_viewport_init (GtkViewport *viewport);
24 static void gtk_viewport_map (GtkWidget *widget);
25 static void gtk_viewport_unmap (GtkWidget *widget);
26 static void gtk_viewport_realize (GtkWidget *widget);
27 static void gtk_viewport_unrealize (GtkWidget *widget);
28 static void gtk_viewport_paint (GtkWidget *widget,
30 static void gtk_viewport_draw (GtkWidget *widget,
32 static gint gtk_viewport_expose (GtkWidget *widget,
33 GdkEventExpose *event);
34 static void gtk_viewport_size_request (GtkWidget *widget,
35 GtkRequisition *requisition);
36 static void gtk_viewport_size_allocate (GtkWidget *widget,
37 GtkAllocation *allocation);
38 static gint gtk_viewport_need_resize (GtkContainer *container);
39 static void gtk_viewport_adjustment_changed (GtkAdjustment *adjustment,
41 static void gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment,
46 gtk_viewport_get_type ()
48 static guint viewport_type = 0;
52 GtkTypeInfo viewport_info =
56 sizeof (GtkViewportClass),
57 (GtkClassInitFunc) gtk_viewport_class_init,
58 (GtkObjectInitFunc) gtk_viewport_init,
62 viewport_type = gtk_type_unique (gtk_bin_get_type (), &viewport_info);
69 gtk_viewport_class_init (GtkViewportClass *class)
71 GtkWidgetClass *widget_class;
72 GtkContainerClass *container_class;
74 widget_class = (GtkWidgetClass*) class;
75 container_class = (GtkContainerClass*) class;
77 widget_class->map = gtk_viewport_map;
78 widget_class->unmap = gtk_viewport_unmap;
79 widget_class->realize = gtk_viewport_realize;
80 widget_class->unrealize = gtk_viewport_unrealize;
81 widget_class->draw = gtk_viewport_draw;
82 widget_class->expose_event = gtk_viewport_expose;
83 widget_class->size_request = gtk_viewport_size_request;
84 widget_class->size_allocate = gtk_viewport_size_allocate;
86 container_class->need_resize = gtk_viewport_need_resize;
90 gtk_viewport_init (GtkViewport *viewport)
92 GTK_WIDGET_UNSET_FLAGS (viewport, GTK_NO_WINDOW);
93 GTK_WIDGET_SET_FLAGS (viewport, GTK_BASIC);
95 viewport->shadow_type = GTK_SHADOW_IN;
96 viewport->main_window = NULL;
97 viewport->view_window = NULL;
98 viewport->hadjustment = NULL;
99 viewport->vadjustment = NULL;
103 gtk_viewport_new (GtkAdjustment *hadjustment,
104 GtkAdjustment *vadjustment)
106 GtkViewport *viewport;
108 viewport = gtk_type_new (gtk_viewport_get_type ());
111 hadjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
114 vadjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
116 gtk_viewport_set_hadjustment (viewport, hadjustment);
117 gtk_viewport_set_vadjustment (viewport, vadjustment);
119 return GTK_WIDGET (viewport);
123 gtk_viewport_get_hadjustment (GtkViewport *viewport)
125 g_return_val_if_fail (viewport != NULL, NULL);
126 g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);
128 return viewport->hadjustment;
132 gtk_viewport_get_vadjustment (GtkViewport *viewport)
134 g_return_val_if_fail (viewport != NULL, NULL);
135 g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);
137 return viewport->vadjustment;
141 gtk_viewport_set_hadjustment (GtkViewport *viewport,
142 GtkAdjustment *adjustment)
144 g_return_if_fail (viewport != NULL);
145 g_return_if_fail (GTK_IS_VIEWPORT (viewport));
146 g_return_if_fail (adjustment != NULL);
148 if (viewport->hadjustment)
150 gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->hadjustment), (gpointer) viewport);
151 gtk_object_unref (GTK_OBJECT (viewport->hadjustment));
154 viewport->hadjustment = adjustment;
155 gtk_object_ref (GTK_OBJECT (viewport->hadjustment));
157 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
158 (GtkSignalFunc) gtk_viewport_adjustment_changed,
159 (gpointer) viewport);
160 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
161 (GtkSignalFunc) gtk_viewport_adjustment_value_changed,
162 (gpointer) viewport);
164 gtk_viewport_adjustment_changed (adjustment, (gpointer) viewport);
168 gtk_viewport_set_vadjustment (GtkViewport *viewport,
169 GtkAdjustment *adjustment)
171 g_return_if_fail (viewport != NULL);
172 g_return_if_fail (GTK_IS_VIEWPORT (viewport));
173 g_return_if_fail (adjustment != NULL);
175 if (viewport->vadjustment)
177 gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->vadjustment), (gpointer) viewport);
178 gtk_object_unref (GTK_OBJECT (viewport->vadjustment));
181 viewport->vadjustment = adjustment;
182 gtk_object_ref (GTK_OBJECT (viewport->vadjustment));
184 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
185 (GtkSignalFunc) gtk_viewport_adjustment_changed,
186 (gpointer) viewport);
187 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
188 (GtkSignalFunc) gtk_viewport_adjustment_value_changed,
189 (gpointer) viewport);
191 gtk_viewport_adjustment_changed (adjustment, (gpointer) viewport);
195 gtk_viewport_set_shadow_type (GtkViewport *viewport,
198 g_return_if_fail (viewport != NULL);
199 g_return_if_fail (GTK_IS_VIEWPORT (viewport));
201 if ((GtkShadowType) viewport->shadow_type != type)
203 viewport->shadow_type = type;
205 if (GTK_WIDGET_VISIBLE (viewport))
207 gtk_widget_size_allocate (GTK_WIDGET (viewport), &(GTK_WIDGET (viewport)->allocation));
208 gtk_widget_queue_draw (GTK_WIDGET (viewport));
215 gtk_viewport_map (GtkWidget *widget)
217 GtkViewport *viewport;
220 g_return_if_fail (widget != NULL);
221 g_return_if_fail (GTK_IS_VIEWPORT (widget));
223 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
224 viewport = GTK_VIEWPORT (widget);
225 bin = GTK_BIN (widget);
227 gdk_window_show (viewport->main_window);
230 GTK_WIDGET_VISIBLE (bin->child) &&
231 !GTK_WIDGET_MAPPED (bin->child))
232 gtk_widget_map (bin->child);
236 gtk_viewport_unmap (GtkWidget *widget)
238 GtkViewport *viewport;
240 g_return_if_fail (widget != NULL);
241 g_return_if_fail (GTK_IS_VIEWPORT (widget));
243 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
244 viewport = GTK_VIEWPORT (widget);
246 gdk_window_hide (viewport->main_window);
250 gtk_viewport_realize (GtkWidget *widget)
252 GtkViewport *viewport;
253 GdkWindowAttr attributes;
254 GtkRequisition *child_requisition;
255 gint attributes_mask;
257 g_return_if_fail (widget != NULL);
258 g_return_if_fail (GTK_IS_VIEWPORT (widget));
260 viewport = GTK_VIEWPORT (widget);
261 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
263 attributes.x = widget->allocation.x + GTK_CONTAINER (widget)->border_width;
264 attributes.y = widget->allocation.y + GTK_CONTAINER (widget)->border_width;
265 attributes.width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2;
266 attributes.height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2;
267 attributes.window_type = GDK_WINDOW_CHILD;
268 attributes.wclass = GDK_INPUT_OUTPUT;
269 attributes.visual = gtk_widget_get_visual (widget);
270 attributes.colormap = gtk_widget_get_colormap (widget);
271 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
273 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
275 viewport->main_window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
276 gdk_window_set_user_data (viewport->main_window, viewport);
278 attributes.x += widget->style->klass->xthickness;
279 attributes.y += widget->style->klass->ythickness;
280 attributes.width -= widget->style->klass->xthickness * 2;
281 attributes.height -= widget->style->klass->ythickness * 2;
283 viewport->view_window = gdk_window_new (viewport->main_window, &attributes, attributes_mask);
284 gdk_window_set_user_data (viewport->view_window, viewport);
289 if (GTK_BIN (viewport)->child)
291 child_requisition = >K_WIDGET (GTK_BIN (viewport)->child)->requisition;
292 attributes.width = child_requisition->width;
293 attributes.height = child_requisition->height;
296 widget->window = gdk_window_new (viewport->view_window, &attributes, attributes_mask);
297 gdk_window_set_user_data (widget->window, viewport);
299 widget->style = gtk_style_attach (widget->style, viewport->main_window);
300 gtk_style_set_background (widget->style, viewport->main_window, GTK_STATE_NORMAL);
301 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
303 gdk_window_show (widget->window);
304 gdk_window_show (viewport->view_window);
308 gtk_viewport_unrealize (GtkWidget *widget)
310 GtkViewport *viewport;
312 g_return_if_fail (widget != NULL);
313 g_return_if_fail (GTK_IS_VIEWPORT (widget));
315 viewport = GTK_VIEWPORT (widget);
316 GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED);
318 gtk_style_detach (widget->style);
320 gdk_window_destroy (widget->window);
321 gdk_window_destroy (viewport->view_window);
322 gdk_window_destroy (viewport->main_window);
324 widget->window = NULL;
325 viewport->view_window = NULL;
326 viewport->main_window = NULL;
330 gtk_viewport_paint (GtkWidget *widget,
333 GtkViewport *viewport;
337 g_return_if_fail (widget != NULL);
338 g_return_if_fail (GTK_IS_VIEWPORT (widget));
339 g_return_if_fail (area != NULL);
341 if (GTK_WIDGET_DRAWABLE (widget))
343 viewport = GTK_VIEWPORT (widget);
345 state = widget->state;
346 if (!GTK_WIDGET_IS_SENSITIVE (widget))
347 state = GTK_STATE_INSENSITIVE;
349 x = GTK_CONTAINER (viewport)->border_width;
350 y = GTK_CONTAINER (viewport)->border_width;
352 gtk_draw_shadow (widget->style, viewport->main_window,
353 GTK_STATE_NORMAL, viewport->shadow_type,
359 gtk_viewport_draw (GtkWidget *widget,
362 GtkViewport *viewport;
364 GdkRectangle tmp_area;
365 GdkRectangle child_area;
367 g_return_if_fail (widget != NULL);
368 g_return_if_fail (GTK_IS_VIEWPORT (widget));
369 g_return_if_fail (area != NULL);
371 if (GTK_WIDGET_DRAWABLE (widget))
373 viewport = GTK_VIEWPORT (widget);
374 bin = GTK_BIN (widget);
376 gtk_viewport_paint (widget, area);
381 tmp_area.x += viewport->hadjustment->value;
382 tmp_area.y += viewport->vadjustment->value;
384 if (gtk_widget_intersect (bin->child, &tmp_area, &child_area))
385 gtk_widget_draw (bin->child, &child_area);
391 gtk_viewport_expose (GtkWidget *widget,
392 GdkEventExpose *event)
394 GtkViewport *viewport;
396 GdkEventExpose child_event;
398 g_return_val_if_fail (widget != NULL, FALSE);
399 g_return_val_if_fail (GTK_IS_VIEWPORT (widget), FALSE);
400 g_return_val_if_fail (event != NULL, FALSE);
402 if (GTK_WIDGET_DRAWABLE (widget))
404 viewport = GTK_VIEWPORT (widget);
405 bin = GTK_BIN (widget);
407 if (event->window == viewport->main_window)
408 gtk_viewport_paint (widget, &event->area);
410 child_event = *event;
412 GTK_WIDGET_NO_WINDOW (bin->child) &&
413 gtk_widget_intersect (bin->child, &event->area, &child_event.area))
414 gtk_widget_event (bin->child, (GdkEvent*) &child_event);
421 gtk_viewport_size_request (GtkWidget *widget,
422 GtkRequisition *requisition)
424 GtkViewport *viewport;
427 g_return_if_fail (widget != NULL);
428 g_return_if_fail (GTK_IS_VIEWPORT (widget));
429 g_return_if_fail (requisition != NULL);
431 viewport = GTK_VIEWPORT (widget);
432 bin = GTK_BIN (widget);
434 requisition->width = (GTK_CONTAINER (widget)->border_width +
435 GTK_WIDGET (widget)->style->klass->xthickness) * 2 + 5;
437 requisition->height = (GTK_CONTAINER (widget)->border_width * 2 +
438 GTK_WIDGET (widget)->style->klass->ythickness) * 2 + 5;
440 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
441 gtk_widget_size_request (bin->child, &bin->child->requisition);
445 gtk_viewport_size_allocate (GtkWidget *widget,
446 GtkAllocation *allocation)
448 GtkViewport *viewport;
450 GtkAllocation child_allocation;
453 g_return_if_fail (widget != NULL);
454 g_return_if_fail (GTK_IS_VIEWPORT (widget));
455 g_return_if_fail (allocation != NULL);
457 widget->allocation = *allocation;
458 viewport = GTK_VIEWPORT (widget);
459 bin = GTK_BIN (widget);
461 child_allocation.x = GTK_WIDGET (viewport)->style->klass->xthickness;
462 child_allocation.width = allocation->width - child_allocation.x * 2;
464 child_allocation.y = GTK_WIDGET (viewport)->style->klass->ythickness;
465 child_allocation.height = allocation->height - child_allocation.y * 2;
467 if (GTK_WIDGET_REALIZED (widget))
469 gdk_window_move_resize (viewport->main_window,
470 allocation->x + GTK_CONTAINER (viewport)->border_width,
471 allocation->y + GTK_CONTAINER (viewport)->border_width,
472 allocation->width - GTK_CONTAINER (viewport)->border_width * 2,
473 allocation->height - GTK_CONTAINER (viewport)->border_width * 2);
475 gdk_window_move_resize (viewport->view_window,
478 child_allocation.width,
479 child_allocation.height);
482 viewport->hadjustment->page_size = child_allocation.width;
483 viewport->hadjustment->page_increment = viewport->hadjustment->page_size / 2;
484 viewport->hadjustment->step_increment = 10;
486 viewport->vadjustment->page_size = child_allocation.height;
487 viewport->vadjustment->page_increment = viewport->vadjustment->page_size / 2;
488 viewport->vadjustment->step_increment = 10;
490 hval = viewport->hadjustment->value;
491 vval = viewport->vadjustment->value;
493 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
495 viewport->hadjustment->lower = 0;
496 viewport->hadjustment->upper = MAX (bin->child->requisition.width,
497 child_allocation.width);
499 hval = CLAMP (hval, 0,
500 viewport->hadjustment->upper -
501 viewport->hadjustment->page_size);
503 viewport->vadjustment->lower = 0;
504 viewport->vadjustment->upper = MAX (bin->child->requisition.height,
505 child_allocation.height);
507 vval = CLAMP (vval, 0,
508 viewport->vadjustment->upper -
509 viewport->vadjustment->page_size);
512 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
514 child_allocation.x = 0;
515 child_allocation.y = 0;
517 child_allocation.width = viewport->hadjustment->upper;
518 child_allocation.height = viewport->vadjustment->upper;
520 if (!GTK_WIDGET_REALIZED (widget))
521 gtk_widget_realize (widget);
523 gdk_window_resize (widget->window,
524 child_allocation.width,
525 child_allocation.height);
527 child_allocation.x = 0;
528 child_allocation.y = 0;
529 gtk_widget_size_allocate (bin->child, &child_allocation);
532 gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "changed");
533 gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "changed");
534 if (viewport->hadjustment->value != hval)
536 viewport->hadjustment->value = hval;
537 gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "value_changed");
539 if (viewport->vadjustment->value != vval)
541 viewport->vadjustment->value = vval;
542 gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "value_changed");
547 gtk_viewport_need_resize (GtkContainer *container)
551 g_return_val_if_fail (container != NULL, FALSE);
552 g_return_val_if_fail (GTK_IS_VIEWPORT (container), FALSE);
554 if (GTK_WIDGET_REALIZED (container))
556 bin = GTK_BIN (container);
558 gtk_widget_size_request (bin->child, &bin->child->requisition);
560 gtk_widget_size_allocate (GTK_WIDGET (container),
561 &(GTK_WIDGET (container)->allocation));
568 gtk_viewport_adjustment_changed (GtkAdjustment *adjustment,
571 GtkViewport *viewport;
573 g_return_if_fail (adjustment != NULL);
574 g_return_if_fail (data != NULL);
575 g_return_if_fail (GTK_IS_VIEWPORT (data));
577 viewport = GTK_VIEWPORT (data);
581 gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment,
584 GtkViewport *viewport;
586 GtkAllocation child_allocation;
589 g_return_if_fail (adjustment != NULL);
590 g_return_if_fail (data != NULL);
591 g_return_if_fail (GTK_IS_VIEWPORT (data));
593 viewport = GTK_VIEWPORT (data);
594 bin = GTK_BIN (data);
596 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
598 gdk_window_get_size (viewport->view_window, &width, &height);
600 child_allocation.x = 0;
601 child_allocation.y = 0;
603 if (viewport->hadjustment->lower != (viewport->hadjustment->upper -
604 viewport->hadjustment->page_size))
605 child_allocation.x = viewport->hadjustment->lower - viewport->hadjustment->value;
607 if (viewport->vadjustment->lower != (viewport->vadjustment->upper -
608 viewport->vadjustment->page_size))
609 child_allocation.y = viewport->vadjustment->lower - viewport->vadjustment->value;
611 if (GTK_WIDGET_REALIZED (viewport))
612 gdk_window_move (GTK_WIDGET (viewport)->window,