summaryrefslogtreecommitdiffstats
path: root/views/widget/gtk_views_fixed.cc
blob: 0b322bb6990420a87859f1cf4c57d10b982c9ca0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "views/widget/gtk_views_fixed.h"

// We store whether we use the widget's allocated size as a property. Ideally
// we would stash this in GtkFixedChild, but GtkFixed doesn't allow subclassing
// gtk_fixed_put. Alternatively we could subclass GtkContainer and use our own
// API (effectively duplicating GtkFixed), but that means folks could no longer
// use the GtkFixed API else where in Chrome. For now I'm going with this route.
static const char* kUseAllocatedSize = "__VIEWS_USE_ALLOCATED_SIZE__";

G_BEGIN_DECLS

G_DEFINE_TYPE(GtkViewsFixed, gtk_views_fixed, GTK_TYPE_FIXED)

static void gtk_views_fixed_size_allocate(GtkWidget* widget,
                                          GtkAllocation* allocation) {
  widget->allocation = *allocation;
  if (!GTK_WIDGET_NO_WINDOW(widget) && GTK_WIDGET_REALIZED(widget)) {
    gdk_window_move_resize(widget->window, allocation->x, allocation->y,
                           allocation->width, allocation->height);
  }

  int border_width = GTK_CONTAINER(widget)->border_width;
  GList* children = GTK_FIXED(widget)->children;
  while (children) {
    GtkFixedChild* child = reinterpret_cast<GtkFixedChild*>(children->data);
    children = children->next;

    if (GTK_WIDGET_VISIBLE(child->widget)) {
      GtkAllocation child_allocation;

      gpointer use_allocated_size = g_object_get_data(G_OBJECT(child->widget),
                                                      kUseAllocatedSize);
      if (use_allocated_size) {
        // NOTE: even though the size isn't changing, we have to call
        // size_allocate, otherwise things like buttons won't repaint.
        child_allocation.width = child->widget->allocation.width;
        child_allocation.height = child->widget->allocation.height;
      } else {
        GtkRequisition child_requisition;
        gtk_widget_get_child_requisition(child->widget, &child_requisition);
        child_allocation.width = child_requisition.width;
        child_allocation.height = child_requisition.height;
      }
      child_allocation.x = child->x + border_width;
      child_allocation.y = child->y + border_width;

      if (GTK_WIDGET_NO_WINDOW(widget)) {
        child_allocation.x += widget->allocation.x;
        child_allocation.y += widget->allocation.y;
      }

      gtk_widget_size_allocate(child->widget, &child_allocation);
    }
  }
}

static void gtk_views_fixed_class_init(GtkViewsFixedClass* views_fixed_class) {
  GtkWidgetClass* widget_class =
      reinterpret_cast<GtkWidgetClass*>(views_fixed_class);
  widget_class->size_allocate = gtk_views_fixed_size_allocate;
}

static void gtk_views_fixed_init(GtkViewsFixed* fixed) {
}

GtkWidget* gtk_views_fixed_new(void) {
  return GTK_WIDGET(g_object_new(GTK_TYPE_VIEWS_FIXED, NULL));
}

void gtk_views_fixed_set_use_allocated_size(GtkWidget* widget, bool value) {
  g_object_set_data(G_OBJECT(widget), kUseAllocatedSize,
                    reinterpret_cast<gpointer>(value ? 1 : 0));
}

G_END_DECLS