gtkviewport.c 35.7 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
Elliot Lee's avatar
Elliot Lee committed
2 3 4
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6 7 8 9 10 11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
16
 */
17 18

/*
19
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20 21 22 23 24
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

25
#include "config.h"
26 27

#include "gtkviewport.h"
28

29
#include "gtkadjustment.h"
30
#include "gtkcsscustomgadgetprivate.h"
Alexander Larsson's avatar
Alexander Larsson committed
31
#include "gtkintl.h"
32
#include "gtkmarshalers.h"
33
#include "gtkpixelcacheprivate.h"
34
#include "gtkprivate.h"
35
#include "gtkscrollable.h"
36 37
#include "gtkrenderbackgroundprivate.h"
#include "gtkstylecontextprivate.h"
38
#include "gtktypebuiltins.h"
39
#include "gtkwidgetprivate.h"
40

Elliot Lee's avatar
Elliot Lee committed
41

42 43 44 45 46 47 48 49
/**
 * SECTION:gtkviewport
 * @Short_description: An adapter which makes widgets scrollable
 * @Title: GtkViewport
 * @See_also:#GtkScrolledWindow, #GtkAdjustment
 *
 * The #GtkViewport widget acts as an adaptor class, implementing
 * scrollability for child widgets that lack their own scrolling
50
 * capabilities. Use GtkViewport to scroll child widgets such as
51
 * #GtkGrid, #GtkBox, and so on.
52 53
 *
 * If a widget has native scrolling abilities, such as #GtkTextView,
54
 * #GtkTreeView or #GtkIconView, it can be added to a #GtkScrolledWindow
55 56
 * with gtk_container_add(). If a widget does not, you must first add the
 * widget to a #GtkViewport, then add the viewport to the scrolled window.
57 58 59
 * gtk_container_add() does this automatically if a child that does not
 * implement #GtkScrollable is added to a #GtkScrolledWindow, so you can
 * ignore the presence of the viewport.
60
 *
61
 * The GtkViewport will start scrolling content only if allocated less
62
 * than the child widget’s minimum size in a given orientation.
63 64 65 66
 *
 * # CSS nodes
 *
 * GtkViewport has a single CSS node with name viewport.
67 68
 */

69
struct _GtkViewportPrivate
70 71 72 73 74 75 76
{
  GtkAdjustment  *hadjustment;
  GtkAdjustment  *vadjustment;
  GtkShadowType   shadow_type;

  GdkWindow      *bin_window;
  GdkWindow      *view_window;
77

78 79
  GtkCssGadget *gadget;

80 81
  GtkPixelCache *pixel_cache;

82 83 84 85
  /* GtkScrollablePolicy needs to be checked when
   * driving the scrollable adjustment values */
  guint hscroll_policy : 1;
  guint vscroll_policy : 1;
86 87
};

88
enum {
Alexander Larsson's avatar
Alexander Larsson committed
89 90 91
  PROP_0,
  PROP_HADJUSTMENT,
  PROP_VADJUSTMENT,
92 93
  PROP_HSCROLL_POLICY,
  PROP_VSCROLL_POLICY,
Alexander Larsson's avatar
Alexander Larsson committed
94
  PROP_SHADOW_TYPE
95 96 97
};


Alexander Larsson's avatar
Alexander Larsson committed
98 99 100 101 102 103 104 105
static void gtk_viewport_set_property             (GObject         *object,
						   guint            prop_id,
						   const GValue    *value,
						   GParamSpec      *pspec);
static void gtk_viewport_get_property             (GObject         *object,
						   guint            prop_id,
						   GValue          *value,
						   GParamSpec      *pspec);
106
static void gtk_viewport_finalize                 (GObject         *object);
107
static void gtk_viewport_destroy                  (GtkWidget        *widget);
Elliot Lee's avatar
Elliot Lee committed
108 109
static void gtk_viewport_realize                  (GtkWidget        *widget);
static void gtk_viewport_unrealize                (GtkWidget        *widget);
110 111
static void gtk_viewport_map                      (GtkWidget        *widget);
static void gtk_viewport_unmap                    (GtkWidget        *widget);
112 113
static gint gtk_viewport_draw                     (GtkWidget        *widget,
						   cairo_t          *cr);
114 115
static void gtk_viewport_remove                   (GtkContainer     *container,
						   GtkWidget        *widget);
116 117
static void gtk_viewport_add                      (GtkContainer     *container,
						   GtkWidget        *widget);
Elliot Lee's avatar
Elliot Lee committed
118 119 120 121 122
static void gtk_viewport_size_allocate            (GtkWidget        *widget,
						   GtkAllocation    *allocation);
static void gtk_viewport_adjustment_value_changed (GtkAdjustment    *adjustment,
						   gpointer          data);

123 124 125 126 127 128
static void gtk_viewport_get_preferred_width      (GtkWidget        *widget,
						   gint             *minimum_size,
						   gint             *natural_size);
static void gtk_viewport_get_preferred_height     (GtkWidget        *widget,
						   gint             *minimum_size,
						   gint             *natural_size);
129 130 131 132 133 134 135 136
static void gtk_viewport_get_preferred_width_for_height (GtkWidget  *widget,
                                                   gint              height,
						   gint             *minimum_size,
						   gint             *natural_size);
static void gtk_viewport_get_preferred_height_for_width (GtkWidget  *widget,
                                                   gint              width,
						   gint             *minimum_size,
						   gint             *natural_size);
137

138 139 140
static void viewport_set_adjustment               (GtkViewport      *viewport,
                                                   GtkOrientation    orientation,
                                                   GtkAdjustment    *adjustment);
141 142
static void gtk_viewport_queue_draw_region        (GtkWidget        *widget,
						   const cairo_region_t *region);
143

144
G_DEFINE_TYPE_WITH_CODE (GtkViewport, gtk_viewport, GTK_TYPE_BIN,
145
                         G_ADD_PRIVATE (GtkViewport)
146
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
Elliot Lee's avatar
Elliot Lee committed
147

148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
static void
gtk_viewport_measure (GtkCssGadget   *gadget,
                      GtkOrientation  orientation,
                      int             for_size,
                      int            *minimum,
                      int            *natural,
                      int            *minimum_baseline,
                      int            *natural_baseline,
                      gpointer        data)
{
  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
  GtkWidget *child;

  *minimum = *natural = 0;

  child = gtk_bin_get_child (GTK_BIN (widget));
  if (child && gtk_widget_get_visible (child))
    _gtk_widget_get_preferred_size_for_size (child,
                                             orientation,
                                             for_size,
                                             minimum, natural,
                                             NULL, NULL);
}

static void
viewport_set_hadjustment_values (GtkViewport *viewport)
{
  GtkBin *bin = GTK_BIN (viewport);
  GtkAllocation view_allocation;
  GtkAdjustment *hadjustment = viewport->priv->hadjustment;
  GtkWidget *child;
  gdouble upper, value;

  gtk_css_gadget_get_content_allocation (viewport->priv->gadget,
                                         &view_allocation, NULL);

  child = gtk_bin_get_child (bin);
  if (child && gtk_widget_get_visible (child))
    {
      gint minimum_width, natural_width;
      gint scroll_height;

      if (viewport->priv->vscroll_policy == GTK_SCROLL_MINIMUM)
	gtk_widget_get_preferred_height (child, &scroll_height, NULL);
      else
	gtk_widget_get_preferred_height (child, NULL, &scroll_height);

      gtk_widget_get_preferred_width_for_height (child,
                                                 MAX (view_allocation.height, scroll_height),
                                                 &minimum_width,
                                                 &natural_width);

      if (viewport->priv->hscroll_policy == GTK_SCROLL_MINIMUM)
	upper = MAX (minimum_width, view_allocation.width);
      else
	upper = MAX (natural_width, view_allocation.width);
    }
  else
    upper = view_allocation.width;

  value = gtk_adjustment_get_value (hadjustment);
  /* We clamp to the left in RTL mode */
  if (gtk_widget_get_direction (GTK_WIDGET (viewport)) == GTK_TEXT_DIR_RTL)
    {
      gdouble dist = gtk_adjustment_get_upper (hadjustment)
                     - value
                     - gtk_adjustment_get_page_size (hadjustment);
      value = upper - dist - view_allocation.width;
    }

  gtk_adjustment_configure (hadjustment,
                            value,
                            0,
                            upper,
                            view_allocation.width * 0.1,
                            view_allocation.width * 0.9,
                            view_allocation.width);
}

static void
viewport_set_vadjustment_values (GtkViewport *viewport)
{
  GtkBin *bin = GTK_BIN (viewport);
  GtkAllocation view_allocation;
  GtkAdjustment *vadjustment = viewport->priv->vadjustment;
  GtkWidget *child;
  gdouble upper;

  gtk_css_gadget_get_content_allocation (viewport->priv->gadget,
                                         &view_allocation, NULL);

  child = gtk_bin_get_child (bin);
  if (child && gtk_widget_get_visible (child))
    {
      gint minimum_height, natural_height;
      gint scroll_width;

      if (viewport->priv->hscroll_policy == GTK_SCROLL_MINIMUM)
	gtk_widget_get_preferred_width (child, &scroll_width, NULL);
      else
	gtk_widget_get_preferred_width (child, NULL, &scroll_width);

      gtk_widget_get_preferred_height_for_width (child,
                                                 MAX (view_allocation.width, scroll_width),
                                                 &minimum_height,
                                                 &natural_height);

      if (viewport->priv->vscroll_policy == GTK_SCROLL_MINIMUM)
	upper = MAX (minimum_height, view_allocation.height);
      else
	upper = MAX (natural_height, view_allocation.height);
    }
  else
    upper = view_allocation.height;

  gtk_adjustment_configure (vadjustment,
                            gtk_adjustment_get_value (vadjustment),
                            0,
                            upper,
                            view_allocation.height * 0.1,
                            view_allocation.height * 0.9,
                            view_allocation.height);
}

static void
gtk_viewport_allocate (GtkCssGadget        *gadget,
                       const GtkAllocation *allocation,
                       int                  baseline,
                       GtkAllocation       *out_clip,
                       gpointer             data)
{
  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
  GtkViewport *viewport = GTK_VIEWPORT (widget);
  GtkViewportPrivate *priv = viewport->priv;
  GtkAdjustment *hadjustment = priv->hadjustment;
  GtkAdjustment *vadjustment = priv->vadjustment;
  GtkWidget *child;

  g_object_freeze_notify (G_OBJECT (hadjustment));
  g_object_freeze_notify (G_OBJECT (vadjustment));

  viewport_set_hadjustment_values (viewport);
  viewport_set_vadjustment_values (viewport);

  if (gtk_widget_get_realized (widget))
    {
      gdk_window_move_resize (priv->view_window,
			      allocation->x,
			      allocation->y,
			      allocation->width,
			      allocation->height);
      gdk_window_move_resize (priv->bin_window,
                              - gtk_adjustment_get_value (hadjustment),
                              - gtk_adjustment_get_value (vadjustment),
                              gtk_adjustment_get_upper (hadjustment),
                              gtk_adjustment_get_upper (vadjustment));
    }

  child = gtk_bin_get_child (GTK_BIN (widget));
  if (child && gtk_widget_get_visible (child))
    {
      GtkAllocation child_allocation;

      child_allocation.x = 0;
      child_allocation.y = 0;
      child_allocation.width = gtk_adjustment_get_upper (hadjustment);
      child_allocation.height = gtk_adjustment_get_upper (vadjustment);

      gtk_widget_size_allocate (child, &child_allocation);
    }

  g_object_thaw_notify (G_OBJECT (hadjustment));
  g_object_thaw_notify (G_OBJECT (vadjustment));
}

static void
draw_bin (cairo_t *cr,
	  gpointer user_data)
{
  GtkWidget *widget = GTK_WIDGET (user_data);
  GTK_WIDGET_CLASS (gtk_viewport_parent_class)->draw (widget, cr);
}

static gboolean
gtk_viewport_render (GtkCssGadget *gadget,
                     cairo_t      *cr,
                     int           x,
                     int           y,
                     int           width,
                     int           height,
                     gpointer      data)
{
  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
  GtkViewport *viewport = GTK_VIEWPORT (widget);
  GtkViewportPrivate *priv = viewport->priv;

  if (gtk_cairo_should_draw_window (cr, priv->bin_window))
    {
      cairo_rectangle_int_t view_rect;
      cairo_rectangle_int_t canvas_rect;

      gdk_window_get_position (priv->view_window, &view_rect.x, &view_rect.y);
      view_rect.width = gdk_window_get_width (priv->view_window);
      view_rect.height = gdk_window_get_height (priv->view_window);

      gdk_window_get_position (priv->bin_window, &canvas_rect.x, &canvas_rect.y);
      canvas_rect.width = gdk_window_get_width (priv->bin_window);
      canvas_rect.height = gdk_window_get_height (priv->bin_window);

      _gtk_pixel_cache_draw (priv->pixel_cache, cr, priv->bin_window,
			     &view_rect, &canvas_rect,
			     draw_bin, widget);
    }

  return FALSE;
}

Elliot Lee's avatar
Elliot Lee committed
365 366 367
static void
gtk_viewport_class_init (GtkViewportClass *class)
{
Alexander Larsson's avatar
Alexander Larsson committed
368
  GObjectClass   *gobject_class;
Elliot Lee's avatar
Elliot Lee committed
369 370 371
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;

Alexander Larsson's avatar
Alexander Larsson committed
372
  gobject_class = G_OBJECT_CLASS (class);
Elliot Lee's avatar
Elliot Lee committed
373 374
  widget_class = (GtkWidgetClass*) class;
  container_class = (GtkContainerClass*) class;
Manish Singh's avatar
Manish Singh committed
375

Alexander Larsson's avatar
Alexander Larsson committed
376 377
  gobject_class->set_property = gtk_viewport_set_property;
  gobject_class->get_property = gtk_viewport_get_property;
378
  gobject_class->finalize = gtk_viewport_finalize;
379 380

  widget_class->destroy = gtk_viewport_destroy;
Elliot Lee's avatar
Elliot Lee committed
381 382
  widget_class->realize = gtk_viewport_realize;
  widget_class->unrealize = gtk_viewport_unrealize;
383 384
  widget_class->map = gtk_viewport_map;
  widget_class->unmap = gtk_viewport_unmap;
385
  widget_class->draw = gtk_viewport_draw;
Elliot Lee's avatar
Elliot Lee committed
386
  widget_class->size_allocate = gtk_viewport_size_allocate;
387 388
  widget_class->get_preferred_width = gtk_viewport_get_preferred_width;
  widget_class->get_preferred_height = gtk_viewport_get_preferred_height;
389 390
  widget_class->get_preferred_width_for_height = gtk_viewport_get_preferred_width_for_height;
  widget_class->get_preferred_height_for_width = gtk_viewport_get_preferred_height_for_width;
391
  widget_class->queue_draw_region = gtk_viewport_queue_draw_region;
392
  
393 394
  gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_VIEWPORT);

395
  container_class->remove = gtk_viewport_remove;
396
  container_class->add = gtk_viewport_add;
397
  gtk_container_class_handle_border_width (container_class);
398

399
  /* GtkScrollable implementation */
400 401 402 403
  g_object_class_override_property (gobject_class, PROP_HADJUSTMENT,    "hadjustment");
  g_object_class_override_property (gobject_class, PROP_VADJUSTMENT,    "vadjustment");
  g_object_class_override_property (gobject_class, PROP_HSCROLL_POLICY, "hscroll-policy");
  g_object_class_override_property (gobject_class, PROP_VSCROLL_POLICY, "vscroll-policy");
Alexander Larsson's avatar
Alexander Larsson committed
404 405 406

  g_object_class_install_property (gobject_class,
                                   PROP_SHADOW_TYPE,
407
                                   g_param_spec_enum ("shadow-type",
408 409
						      P_("Shadow type"),
						      P_("Determines how the shadowed box around the viewport is drawn"),
Alexander Larsson's avatar
Alexander Larsson committed
410 411
						      GTK_TYPE_SHADOW_TYPE,
						      GTK_SHADOW_IN,
412
						      GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
413 414

  gtk_widget_class_set_css_name (widget_class, "viewport");
Elliot Lee's avatar
Elliot Lee committed
415 416
}

417
static void
Alexander Larsson's avatar
Alexander Larsson committed
418 419 420 421
gtk_viewport_set_property (GObject         *object,
			   guint            prop_id,
			   const GValue    *value,
			   GParamSpec      *pspec)
422 423 424 425 426
{
  GtkViewport *viewport;

  viewport = GTK_VIEWPORT (object);

Alexander Larsson's avatar
Alexander Larsson committed
427
  switch (prop_id)
428
    {
Alexander Larsson's avatar
Alexander Larsson committed
429
    case PROP_HADJUSTMENT:
430
      viewport_set_adjustment (viewport, GTK_ORIENTATION_HORIZONTAL, g_value_get_object (value));
431
      break;
Alexander Larsson's avatar
Alexander Larsson committed
432
    case PROP_VADJUSTMENT:
433
      viewport_set_adjustment (viewport, GTK_ORIENTATION_VERTICAL, g_value_get_object (value));
434
      break;
435
    case PROP_HSCROLL_POLICY:
436 437 438 439 440 441
      if (viewport->priv->hscroll_policy != g_value_get_enum (value))
        {
          viewport->priv->hscroll_policy = g_value_get_enum (value);
          gtk_widget_queue_resize (GTK_WIDGET (viewport));
          g_object_notify_by_pspec (object, pspec);
        }
442 443
      break;
    case PROP_VSCROLL_POLICY:
444 445 446 447 448 449
      if (viewport->priv->vscroll_policy != g_value_get_enum (value))
        {
          viewport->priv->vscroll_policy = g_value_get_enum (value);
          gtk_widget_queue_resize (GTK_WIDGET (viewport));
          g_object_notify_by_pspec (object, pspec);
        }
450
      break;
Alexander Larsson's avatar
Alexander Larsson committed
451 452
    case PROP_SHADOW_TYPE:
      gtk_viewport_set_shadow_type (viewport, g_value_get_enum (value));
453
      break;
454
    default:
Alexander Larsson's avatar
Alexander Larsson committed
455
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
456 457 458 459 460
      break;
    }
}

static void
Alexander Larsson's avatar
Alexander Larsson committed
461 462 463 464
gtk_viewport_get_property (GObject         *object,
			   guint            prop_id,
			   GValue          *value,
			   GParamSpec      *pspec)
465
{
466
  GtkViewport *viewport = GTK_VIEWPORT (object);
467
  GtkViewportPrivate *priv = viewport->priv;
468

Alexander Larsson's avatar
Alexander Larsson committed
469
  switch (prop_id)
470
    {
Alexander Larsson's avatar
Alexander Larsson committed
471
    case PROP_HADJUSTMENT:
472
      g_value_set_object (value, priv->hadjustment);
473
      break;
Alexander Larsson's avatar
Alexander Larsson committed
474
    case PROP_VADJUSTMENT:
475
      g_value_set_object (value, priv->vadjustment);
476
      break;
477 478 479 480 481 482
    case PROP_HSCROLL_POLICY:
      g_value_set_enum (value, priv->hscroll_policy);
      break;
    case PROP_VSCROLL_POLICY:
      g_value_set_enum (value, priv->vscroll_policy);
      break;
Alexander Larsson's avatar
Alexander Larsson committed
483
    case PROP_SHADOW_TYPE:
484
      g_value_set_enum (value, priv->shadow_type);
485 486
      break;
    default:
Alexander Larsson's avatar
Alexander Larsson committed
487
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
488 489 490 491
      break;
    }
}

Elliot Lee's avatar
Elliot Lee committed
492 493 494
static void
gtk_viewport_init (GtkViewport *viewport)
{
495
  GtkWidget *widget;
496
  GtkViewportPrivate *priv;
497
  GtkCssNode *widget_node;
498

499
  viewport->priv = gtk_viewport_get_instance_private (viewport);
500
  priv = viewport->priv;
501
  widget = GTK_WIDGET (viewport);
502

503 504
  gtk_widget_set_has_window (widget, TRUE);
  gtk_widget_set_redraw_on_allocate (widget, FALSE);
505 506 507 508 509 510

  priv->shadow_type = GTK_SHADOW_IN;
  priv->view_window = NULL;
  priv->bin_window = NULL;
  priv->hadjustment = NULL;
  priv->vadjustment = NULL;
511

512 513
  priv->pixel_cache = _gtk_pixel_cache_new ();

514 515 516 517 518 519 520 521
  widget_node = gtk_widget_get_css_node (widget);
  priv->gadget = gtk_css_custom_gadget_new_for_node (widget_node,
                                                     widget,
                                                     gtk_viewport_measure,
                                                     gtk_viewport_allocate,
                                                     gtk_viewport_render,
                                                     NULL, NULL);

522
  gtk_css_gadget_add_class (priv->gadget, GTK_STYLE_CLASS_FRAME);
523 524
  viewport_set_adjustment (viewport, GTK_ORIENTATION_HORIZONTAL, NULL);
  viewport_set_adjustment (viewport, GTK_ORIENTATION_VERTICAL, NULL);
Elliot Lee's avatar
Elliot Lee committed
525 526
}

Matthias Clasen's avatar
Matthias Clasen committed
527 528
/**
 * gtk_viewport_new:
529 530
 * @hadjustment: (allow-none): horizontal adjustment
 * @vadjustment: (allow-none): vertical adjustment
Matthias Clasen's avatar
Matthias Clasen committed
531
 *
532 533
 * Creates a new #GtkViewport with the given adjustments, or with default
 * adjustments if none are given.
Matthias Clasen's avatar
Matthias Clasen committed
534
 *
Matthias Clasen's avatar
Matthias Clasen committed
535 536
 * Returns: a new #GtkViewport
 */
Elliot Lee's avatar
Elliot Lee committed
537 538 539 540
GtkWidget*
gtk_viewport_new (GtkAdjustment *hadjustment,
		  GtkAdjustment *vadjustment)
{
541 542
  GtkWidget *viewport;

543
  viewport = g_object_new (GTK_TYPE_VIEWPORT,
544 545 546
                           "hadjustment", hadjustment,
                           "vadjustment", vadjustment,
                           NULL);
547 548 549

  return viewport;
}
Elliot Lee's avatar
Elliot Lee committed
550

551 552
#define ADJUSTMENT_POINTER(viewport, orientation)         \
  (((orientation) == GTK_ORIENTATION_HORIZONTAL) ?        \
553
     &(viewport)->priv->hadjustment : &(viewport)->priv->vadjustment)
554

555
static void
556 557
viewport_disconnect_adjustment (GtkViewport    *viewport,
				GtkOrientation  orientation)
558
{
559
  GtkAdjustment **adjustmentp = ADJUSTMENT_POINTER (viewport, orientation);
Elliot Lee's avatar
Elliot Lee committed
560

561
  if (*adjustmentp)
562
    {
563
      g_signal_handlers_disconnect_by_func (*adjustmentp,
Manish Singh's avatar
Manish Singh committed
564 565
					    gtk_viewport_adjustment_value_changed,
					    viewport);
566 567
      g_object_unref (*adjustmentp);
      *adjustmentp = NULL;
568
    }
569 570 571
}

static void
572
gtk_viewport_destroy (GtkWidget *widget)
573
{
574
  GtkViewport *viewport = GTK_VIEWPORT (widget);
575
  GtkViewportPrivate *priv = viewport->priv;
576 577 578

  viewport_disconnect_adjustment (viewport, GTK_ORIENTATION_HORIZONTAL);
  viewport_disconnect_adjustment (viewport, GTK_ORIENTATION_VERTICAL);
579

580
  GTK_WIDGET_CLASS (gtk_viewport_parent_class)->destroy (widget);
581 582

  g_clear_pointer (&priv->pixel_cache, _gtk_pixel_cache_free);
583 584
}

585 586 587 588 589 590 591 592 593 594 595
static void
gtk_viewport_finalize (GObject *object)
{
  GtkViewport *viewport = GTK_VIEWPORT (object);
  GtkViewportPrivate *priv = viewport->priv;

  g_clear_object (&priv->gadget);

  G_OBJECT_CLASS (gtk_viewport_parent_class)->finalize (object);
}

Matthias Clasen's avatar
Matthias Clasen committed
596 597 598
/**
 * gtk_viewport_get_hadjustment:
 * @viewport: a #GtkViewport.
599
 *
Matthias Clasen's avatar
Matthias Clasen committed
600 601
 * Returns the horizontal adjustment of the viewport.
 *
602
 * Returns: (transfer none): the horizontal adjustment of @viewport.
603 604
 *
 * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
Matthias Clasen's avatar
Matthias Clasen committed
605
 **/
Elliot Lee's avatar
Elliot Lee committed
606 607 608 609 610
GtkAdjustment*
gtk_viewport_get_hadjustment (GtkViewport *viewport)
{
  g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);

611
  return viewport->priv->hadjustment;
Elliot Lee's avatar
Elliot Lee committed
612 613
}

Matthias Clasen's avatar
Matthias Clasen committed
614 615 616 617 618 619
/**
 * gtk_viewport_get_vadjustment:
 * @viewport: a #GtkViewport.
 * 
 * Returns the vertical adjustment of the viewport.
 *
620
 * Returns: (transfer none): the vertical adjustment of @viewport.
621 622
 *
 * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
Matthias Clasen's avatar
Matthias Clasen committed
623
 **/
Elliot Lee's avatar
Elliot Lee committed
624 625 626 627 628
GtkAdjustment*
gtk_viewport_get_vadjustment (GtkViewport *viewport)
{
  g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);

629
  return viewport->priv->vadjustment;
Elliot Lee's avatar
Elliot Lee committed
630 631
}

632 633 634 635 636 637 638
static void
viewport_set_adjustment (GtkViewport    *viewport,
			 GtkOrientation  orientation,
			 GtkAdjustment  *adjustment)
{
  GtkAdjustment **adjustmentp = ADJUSTMENT_POINTER (viewport, orientation);

639
  if (adjustment && adjustment == *adjustmentp)
640 641 642
    return;

  if (!adjustment)
Javier Jardón's avatar
Javier Jardón committed
643
    adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
644
  viewport_disconnect_adjustment (viewport, orientation);
645
  *adjustmentp = adjustment;
646
  g_object_ref_sink (adjustment);
647 648

  if (orientation == GTK_ORIENTATION_HORIZONTAL)
649
    viewport_set_hadjustment_values (viewport);
650
  else
651
    viewport_set_vadjustment_values (viewport);
652

653
  g_signal_connect (adjustment, "value-changed",
654 655 656
		    G_CALLBACK (gtk_viewport_adjustment_value_changed),
		    viewport);

657
  gtk_viewport_adjustment_value_changed (adjustment, viewport);
658 659
}

Matthias Clasen's avatar
Matthias Clasen committed
660 661 662
/**
 * gtk_viewport_set_hadjustment:
 * @viewport: a #GtkViewport.
663 664
 * @adjustment: (allow-none): a #GtkAdjustment.
 *
Matthias Clasen's avatar
Matthias Clasen committed
665
 * Sets the horizontal adjustment of the viewport.
666 667
 *
 * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
Matthias Clasen's avatar
Matthias Clasen committed
668
 **/
Elliot Lee's avatar
Elliot Lee committed
669 670 671 672 673
void
gtk_viewport_set_hadjustment (GtkViewport   *viewport,
			      GtkAdjustment *adjustment)
{
  g_return_if_fail (GTK_IS_VIEWPORT (viewport));
674 675
  if (adjustment)
    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
Elliot Lee's avatar
Elliot Lee committed
676

677
  viewport_set_adjustment (viewport, GTK_ORIENTATION_HORIZONTAL, adjustment);
Alexander Larsson's avatar
Alexander Larsson committed
678 679

  g_object_notify (G_OBJECT (viewport), "hadjustment");
Elliot Lee's avatar
Elliot Lee committed
680 681
}

Matthias Clasen's avatar
Matthias Clasen committed
682 683 684
/**
 * gtk_viewport_set_vadjustment:
 * @viewport: a #GtkViewport.
685 686
 * @adjustment: (allow-none): a #GtkAdjustment.
 *
Matthias Clasen's avatar
Matthias Clasen committed
687
 * Sets the vertical adjustment of the viewport.
688 689
 *
 * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
Matthias Clasen's avatar
Matthias Clasen committed
690
 **/
Elliot Lee's avatar
Elliot Lee committed
691 692 693 694 695
void
gtk_viewport_set_vadjustment (GtkViewport   *viewport,
			      GtkAdjustment *adjustment)
{
  g_return_if_fail (GTK_IS_VIEWPORT (viewport));
696 697
  if (adjustment)
    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
Elliot Lee's avatar
Elliot Lee committed
698

699
  viewport_set_adjustment (viewport, GTK_ORIENTATION_VERTICAL, adjustment);
Alexander Larsson's avatar
Alexander Larsson committed
700

701
  g_object_notify (G_OBJECT (viewport), "vadjustment");
Elliot Lee's avatar
Elliot Lee committed
702 703
}

Matthias Clasen's avatar
Matthias Clasen committed
704 705 706 707 708 709 710
/** 
 * gtk_viewport_set_shadow_type:
 * @viewport: a #GtkViewport.
 * @type: the new shadow type.
 *
 * Sets the shadow type of the viewport.
 **/ 
Elliot Lee's avatar
Elliot Lee committed
711 712 713 714
void
gtk_viewport_set_shadow_type (GtkViewport   *viewport,
			      GtkShadowType  type)
{
715
  GtkViewportPrivate *priv;
716
  GtkWidget *widget;
717
  GtkStyleContext *context;
718

Elliot Lee's avatar
Elliot Lee committed
719 720
  g_return_if_fail (GTK_IS_VIEWPORT (viewport));

721
  widget = GTK_WIDGET (viewport);
722 723 724
  priv = viewport->priv;

  if ((GtkShadowType) priv->shadow_type != type)
Elliot Lee's avatar
Elliot Lee committed
725
    {
726
      priv->shadow_type = type;
Elliot Lee's avatar
Elliot Lee committed
727

728 729 730 731 732 733
      context = gtk_widget_get_style_context (widget);
      if (type != GTK_SHADOW_NONE)
        gtk_style_context_add_class (context, GTK_STYLE_CLASS_FRAME);
      else
        gtk_style_context_remove_class (context, GTK_STYLE_CLASS_FRAME);
 
734
      gtk_widget_queue_resize (widget);
Alexander Larsson's avatar
Alexander Larsson committed
735

736
      g_object_notify (G_OBJECT (viewport), "shadow-type");
737
    }
Elliot Lee's avatar
Elliot Lee committed
738 739
}

740 741 742 743 744 745
/**
 * gtk_viewport_get_shadow_type:
 * @viewport: a #GtkViewport
 *
 * Gets the shadow type of the #GtkViewport. See
 * gtk_viewport_set_shadow_type().
746
 *
747
 * Returns: the shadow type 
748 749 750 751 752 753
 **/
GtkShadowType
gtk_viewport_get_shadow_type (GtkViewport *viewport)
{
  g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), GTK_SHADOW_NONE);

754
  return viewport->priv->shadow_type;
755
}
Elliot Lee's avatar
Elliot Lee committed
756

757 758 759 760 761 762
/**
 * gtk_viewport_get_bin_window:
 * @viewport: a #GtkViewport
 *
 * Gets the bin window of the #GtkViewport.
 *
763
 * Returns: (transfer none): a #GdkWindow
764 765 766 767 768 769 770 771
 *
 * Since: 2.20
 **/
GdkWindow*
gtk_viewport_get_bin_window (GtkViewport *viewport)
{
  g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);

772
  return viewport->priv->bin_window;
773 774
}

775 776 777 778 779 780
/**
 * gtk_viewport_get_view_window:
 * @viewport: a #GtkViewport
 *
 * Gets the view window of the #GtkViewport.
 *
781
 * Returns: (transfer none): a #GdkWindow
782 783 784 785 786 787 788 789
 *
 * Since: 2.22
 **/
GdkWindow*
gtk_viewport_get_view_window (GtkViewport *viewport)
{
  g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);

790
  return viewport->priv->view_window;
791 792
}

793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
static void
gtk_viewport_bin_window_invalidate_handler (GdkWindow *window,
					    cairo_region_t *region)
{
  gpointer widget;
  GtkViewport *viewport;
  GtkViewportPrivate *priv;

  gdk_window_get_user_data (window, &widget);
  viewport = GTK_VIEWPORT (widget);
  priv = viewport->priv;

  _gtk_pixel_cache_invalidate (priv->pixel_cache, region);
}

static void
gtk_viewport_queue_draw_region (GtkWidget *widget,
				const cairo_region_t *region)
{
  GtkViewport *viewport = GTK_VIEWPORT (widget);
  GtkViewportPrivate *priv = viewport->priv;

  /* There is no way we can know if a region targets the
     not-currently-visible but in pixel cache region, so we
     always just invalidate the whole thing whenever the
     tree view gets a queue draw. This doesn't normally happen
     in normal scrolling cases anyway. */
  _gtk_pixel_cache_invalidate (priv->pixel_cache, NULL);

  GTK_WIDGET_CLASS (gtk_viewport_parent_class)->queue_draw_region (widget,
								   region);
}


Elliot Lee's avatar
Elliot Lee committed
827 828 829
static void
gtk_viewport_realize (GtkWidget *widget)
{
830
  GtkViewport *viewport = GTK_VIEWPORT (widget);
831
  GtkViewportPrivate *priv = viewport->priv;
832
  GtkBin *bin = GTK_BIN (widget);
833 834
  GtkAdjustment *hadjustment = priv->hadjustment;
  GtkAdjustment *vadjustment = priv->vadjustment;
835
  GtkAllocation allocation;
836
  GtkAllocation view_allocation;
Javier Jardón's avatar
Javier Jardón committed
837
  GtkWidget *child;
838
  GdkWindow *window;
Elliot Lee's avatar
Elliot Lee committed
839 840
  GdkWindowAttr attributes;
  gint attributes_mask;
841
  gint event_mask;
842

843
  gtk_widget_set_realized (widget, TRUE);
Elliot Lee's avatar
Elliot Lee committed
844

845 846
  gtk_widget_get_allocation (widget, &allocation);

847 848 849 850
  attributes.x = allocation.x;
  attributes.y = allocation.y;
  attributes.width = allocation.width;
  attributes.height = allocation.height;
Elliot Lee's avatar
Elliot Lee committed
851 852 853
  attributes.window_type = GDK_WINDOW_CHILD;
  attributes.wclass = GDK_INPUT_OUTPUT;
  attributes.visual = gtk_widget_get_visual (widget);
854

855
  event_mask = gtk_widget_get_events (widget);
856 857

  attributes.event_mask = event_mask | GDK_SCROLL_MASK | GDK_TOUCH_MASK | GDK_SMOOTH_SCROLL_MASK;
Elliot Lee's avatar
Elliot Lee committed
858

859
  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
Elliot Lee's avatar
Elliot Lee committed
860

861 862 863
  window = gdk_window_new (gtk_widget_get_parent_window (widget),
                           &attributes, attributes_mask);
  gtk_widget_set_window (widget, window);
864
  gtk_widget_register_window (widget, window);
Elliot Lee's avatar
Elliot Lee committed
865

866 867 868
  gtk_css_gadget_get_content_allocation (priv->gadget,
                                         &view_allocation, NULL);

869 870 871 872
  attributes.x = view_allocation.x;
  attributes.y = view_allocation.y;
  attributes.width = view_allocation.width;
  attributes.height = view_allocation.height;
873
  attributes.event_mask = 0;
Elliot Lee's avatar
Elliot Lee committed
874

875 876
  priv->view_window = gdk_window_new (window,
                                      &attributes, attributes_mask);
877
  gtk_widget_register_window (widget, priv->view_window);
Elliot Lee's avatar
Elliot Lee committed
878

879 880 881 882
  attributes.x = - gtk_adjustment_get_value (hadjustment);
  attributes.y = - gtk_adjustment_get_value (vadjustment);
  attributes.width = gtk_adjustment_get_upper (hadjustment);
  attributes.height = gtk_adjustment_get_upper (vadjustment);
883
  
884
  attributes.event_mask = event_mask;
Elliot Lee's avatar
Elliot Lee committed
885

886
  priv->bin_window = gdk_window_new (priv->view_window, &attributes, attributes_mask);
887
  gtk_widget_register_window (widget, priv->bin_window);
888 889
  gdk_window_set_invalidate_handler (priv->bin_window,
				     gtk_viewport_bin_window_invalidate_handler);
890

Javier Jardón's avatar
Javier Jardón committed
891 892
  child = gtk_bin_get_child (bin);
  if (child)
893
    gtk_widget_set_parent_window (child, priv->bin_window);
Elliot Lee's avatar
Elliot Lee committed
894

895 896
  gdk_window_show (priv->bin_window);
  gdk_window_show (priv->view_window);
Elliot Lee's avatar
Elliot Lee committed
897 898 899 900 901
}

static void
gtk_viewport_unrealize (GtkWidget *widget)
{
902
  GtkViewport *viewport = GTK_VIEWPORT (widget);
903
  GtkViewportPrivate *priv = viewport->priv;
Elliot Lee's avatar
Elliot Lee committed
904

905
  gtk_widget_unregister_window (widget, priv->view_window);
906 907
  gdk_window_destroy (priv->view_window);
  priv->view_window = NULL;
908

909
  gtk_widget_unregister_window (widget, priv->bin_window);
910 911
  gdk_window_destroy (priv->bin_window);
  priv->bin_window = NULL;
912

913
  GTK_WIDGET_CLASS (gtk_viewport_parent_class)->unrealize (widget);
Elliot Lee's avatar
Elliot Lee committed
914 915
}

916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937
static void
gtk_viewport_map (GtkWidget *widget)
{
  GtkViewport *viewport = GTK_VIEWPORT (widget);
  GtkViewportPrivate *priv = viewport->priv;

  _gtk_pixel_cache_map (priv->pixel_cache);

  GTK_WIDGET_CLASS (gtk_viewport_parent_class)->map (widget);
}

static void
gtk_viewport_unmap (GtkWidget *widget)
{
  GtkViewport *viewport = GTK_VIEWPORT (widget);
  GtkViewportPrivate *priv = viewport->priv;

  GTK_WIDGET_CLASS (gtk_viewport_parent_class)->unmap (widget);

  _gtk_pixel_cache_unmap (priv->pixel_cache);
}

Elliot Lee's avatar
Elliot Lee committed
938
static gint
939 940
gtk_viewport_draw (GtkWidget *widget,
                   cairo_t   *cr)
Elliot Lee's avatar
Elliot Lee committed
941
{
942 943 944
  GtkViewport *viewport = GTK_VIEWPORT (widget);
  GtkViewportPrivate *priv = viewport->priv;

945 946 947
  if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)) ||
      gtk_cairo_should_draw_window (cr, priv->bin_window))
    gtk_css_gadget_draw (priv->gadget, cr);
Elliot Lee's avatar
Elliot Lee committed
948 949 950 951

  return FALSE;
}

952 953 954 955 956 957 958 959 960 961 962 963
static void
gtk_viewport_update_pixelcache_opacity (GtkWidget   *child,
                                        GtkViewport *viewport)
{
  GtkViewportPrivate *priv = viewport->priv;

  gtk_pixel_cache_set_is_opaque (priv->pixel_cache,
                                 gtk_css_style_render_background_is_opaque (
                                   gtk_style_context_lookup_style (
                                     gtk_widget_get_style_context (child))));
}

964 965 966 967 968 969 970
static void
gtk_viewport_remove (GtkContainer *container,
		     GtkWidget    *child)
{
  GtkViewport *viewport = GTK_VIEWPORT (container);
  GtkViewportPrivate *priv = viewport->priv;

971 972 973 974
  if (g_signal_handlers_disconnect_by_func (child, gtk_viewport_update_pixelcache_opacity, viewport) != 1)
    {
      g_assert_not_reached ();
    }
975

976
  GTK_CONTAINER_CLASS (gtk_viewport_parent_class)->remove (container, child);
977

978
  gtk_pixel_cache_set_is_opaque (priv->pixel_cache, FALSE);
979 980
}

981 982
static void
gtk_viewport_add (GtkContainer *container,
983
		  GtkWidget    *child)
984
{
985
  GtkBin *bin = GTK_BIN (container);
986
  GtkViewport *viewport = GTK_VIEWPORT (bin);
987
  GtkViewportPrivate *priv = viewport->priv;
988

Javier Jardón's avatar
Javier Jardón committed
989
  g_return_if_fail (gtk_bin_get_child (bin) == NULL);
990

991
  gtk_widget_set_parent_window (child, priv->bin_window);
992
  
Matthias Clasen's avatar
Matthias Clasen committed
993
  GTK_CONTAINER_CLASS (gtk_viewport_parent_class)->add (container, child);
994 995 996

  g_signal_connect (child, "style-updated", G_CALLBACK (gtk_viewport_update_pixelcache_opacity), viewport);
  gtk_viewport_update_pixelcache_opacity (child, viewport);
997 998
}

Elliot Lee's avatar
Elliot Lee committed
999 1000 1001 1002
static void
gtk_viewport_size_allocate (GtkWidget     *widget,
			    GtkAllocation *allocation)
{
1003
  GtkViewport *viewport = GTK_VIEWPORT (widget);
1004
  GtkViewportPrivate *priv = viewport->priv;
1005
  GtkAllocation clip, content_allocation, widget_allocation;
1006

1007 1008 1009
  /* If our size changed, and we have a shadow, queue a redraw on widget->window to
   * redraw the shadow correctly.
   */
1010
  gtk_widget_get_allocation (widget, &widget_allocation);
1011
  if (gtk_widget_get_mapped (widget) &&
1012
      priv->shadow_type != GTK_SHADOW_NONE &&
1013 1014 1015 1016 1017 1018
      (widget_allocation.width != allocation->width ||
       widget_allocation.height != allocation->height))
    gdk_window_invalidate_rect (gtk_widget_get_window (widget), NULL, FALSE);

  gtk_widget_set_allocation (widget, allocation);

1019
  if (gtk_widget_get_realized (widget))
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
    gdk_window_move_resize (gtk_widget_get_window (widget),
                            allocation->x,
                            allocation->y,
                            allocation->width,
                            allocation->height);

  content_allocation = *allocation;
  content_allocation.x = content_allocation.y = 0;
  gtk_css_gadget_allocate (priv->gadget,
                           &content_allocation,
                           gtk_widget_get_allocated_baseline (widget),
                           &clip);

  clip.x += allocation->x;
  clip.y += allocation->y;
  gtk_widget_set_clip (widget, &clip);
Elliot Lee's avatar
Elliot Lee committed
1036 1037 1038 1039 1040 1041
}

static void
gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment,
				       gpointer       data)
{
1042
  GtkViewport *viewport = GTK_VIEWPORT (data);
1043
  GtkViewportPrivate *priv = viewport->priv;
1044
  GtkBin *bin = GTK_BIN (data);
Javier Jardón's avatar
Javier Jardón committed
1045
  GtkWidget *child;
Elliot Lee's avatar
Elliot Lee committed
1046

Javier Jardón's avatar
Javier Jardón committed
1047 1048
  child = gtk_bin_get_child (bin);
  if (child && gtk_widget_get_visible (child) &&
1049
      gtk_widget_get_realized (GTK_WIDGET (viewport)))
Elliot Lee's avatar
Elliot Lee committed
1050
    {
1051 1052
      GtkAdjustment *hadjustment = priv->hadjustment;
      GtkAdjustment *vadjustment = priv->vadjustment;
1053 1054
      gint old_x, old_y;
      gint new_x, new_y;
Elliot Lee's avatar
Elliot Lee committed
1055

1056
      gdk_window_get_position (priv->bin_window, &old_x, &old_y);
1057 1058
      new_x = - gtk_adjustment_get_value (hadjustment);
      new_y = - gtk_adjustment_get_value (vadjustment);
Elliot Lee's avatar
Elliot Lee committed
1059

1060
      if (new_x != old_x || new_y != old_y)
1061
	gdk_window_move (priv->bin_window, new_x, new_y);
Elliot Lee's avatar
Elliot Lee committed
1062 1063
    }
}
1064

1065
static void
1066 1067 1068
gtk_viewport_get_preferred_width (GtkWidget *widget,
                                  gint      *minimum_size,
                                  gint      *natural_size)
1069
{
1070 1071 1072 1073 1074
  gtk_css_gadget_get_preferred_size (GTK_VIEWPORT (widget)->priv->gadget,
                                     GTK_ORIENTATION_HORIZONTAL,
                                     -1,
                                     minimum_size, natural_size,
                                     NULL, NULL);
1075 1076 1077
}

static void
1078 1079 1080
gtk_viewport_get_preferred_height (GtkWidget *widget,
                                   gint      *minimum_size,
                                   gint      *natural_size)
1081
{
1082 1083 1084 1085 1086
  gtk_css_gadget_get_preferred_size (GTK_VIEWPORT (widget)->priv->gadget,
                                     GTK_ORIENTATION_VERTICAL,
                                     -1,
                                     minimum_size, natural_size,
                                     NULL, NULL);
1087 1088 1089 1090 1091 1092 1093 1094
}

static void
gtk_viewport_get_preferred_width_for_height (GtkWidget *widget,
                                             gint       height,
                                             gint      *minimum_size,
                                             gint      *natural_size)
{
1095 1096 1097 1098 1099
  gtk_css_gadget_get_preferred_size (GTK_VIEWPORT (widget)->priv->gadget,
                                     GTK_ORIENTATION_HORIZONTAL,
                                     height,
                                     minimum_size, natural_size,
                                     NULL, NULL);
1100 1101 1102 1103 1104 1105 1106 1107
}

static void
gtk_viewport_get_preferred_height_for_width (GtkWidget *widget,
                                             gint       width,
                                             gint      *minimum_size,
                                             gint      *natural_size)
{
1108 1109 1110 1111 1112
  gtk_css_gadget_get_preferred_size (GTK_VIEWPORT (widget)->priv->gadget,
                                     GTK_ORIENTATION_VERTICAL,
                                     width,
                                     minimum_size, natural_size,
                                     NULL, NULL);
1113
}