Home | History | Annotate | Download | only in gtk
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/gtk/gtk_expanded_container.h"
      6 
      7 #include <gtk/gtk.h>
      8 
      9 #include <algorithm>
     10 
     11 namespace {
     12 
     13 enum {
     14   CHILD_SIZE_REQUEST,
     15   LAST_SIGNAL
     16 };
     17 
     18 guint expanded_container_signals[LAST_SIGNAL] = { 0 };
     19 
     20 struct SizeAllocateData {
     21   GtkWidget* container;
     22   GtkAllocation* allocation;
     23   int border_width;
     24 };
     25 
     26 void GetChildPosition(GtkWidget* container, GtkWidget* child, int* x, int* y) {
     27   GValue v = { 0 };
     28   g_value_init(&v, G_TYPE_INT);
     29   gtk_container_child_get_property(GTK_CONTAINER(container), child, "x", &v);
     30   *x = g_value_get_int(&v);
     31   gtk_container_child_get_property(GTK_CONTAINER(container), child, "y", &v);
     32   *y = g_value_get_int(&v);
     33   g_value_unset(&v);
     34 }
     35 
     36 void ChildSizeAllocate(GtkWidget* child, gpointer userdata) {
     37   if (!GTK_WIDGET_VISIBLE(child))
     38     return;
     39 
     40   SizeAllocateData* data = reinterpret_cast<SizeAllocateData*>(userdata);
     41 
     42   GtkRequisition child_requisition;
     43   child_requisition.width = data->allocation->width - data->border_width * 2;
     44   child_requisition.height = data->allocation->height - data->border_width * 2;
     45 
     46   // We need to give whoever is pulling our strings a chance to adjust the
     47   // size of our children.
     48   g_signal_emit(data->container,
     49                 expanded_container_signals[CHILD_SIZE_REQUEST], 0,
     50                 child, &child_requisition);
     51 
     52   GtkAllocation child_allocation;
     53   child_allocation.width = child_requisition.width;
     54   child_allocation.height = child_requisition.height;
     55   if (child_allocation.width < 0 || child_allocation.height < 0) {
     56     gtk_widget_get_child_requisition(child, &child_requisition);
     57     if (child_allocation.width < 0)
     58       child_allocation.width = child_requisition.width;
     59     if (child_allocation.height < 0)
     60       child_allocation.height = child_requisition.height;
     61   }
     62 
     63   int x, y;
     64   GetChildPosition(data->container, child, &x, &y);
     65 
     66   child_allocation.x = x + data->border_width;
     67   child_allocation.y = y + data->border_width;
     68 
     69   if (GTK_WIDGET_NO_WINDOW(data->container)) {
     70     child_allocation.x += data->allocation->x;
     71     child_allocation.y += data->allocation->y;
     72   }
     73   gtk_widget_size_allocate(child, &child_allocation);
     74 }
     75 
     76 void Marshal_VOID__OBJECT_BOXED(GClosure* closure,
     77                                 GValue* return_value G_GNUC_UNUSED,
     78                                 guint n_param_values,
     79                                 const GValue* param_values,
     80                                 gpointer invocation_hint G_GNUC_UNUSED,
     81                                 gpointer marshal_data) {
     82   typedef void (*GMarshalFunc_VOID__OBJECT_BOXED) (gpointer data1,
     83                                                    gpointer arg_1,
     84                                                    gpointer arg_2,
     85                                                    gpointer data2);
     86   register GMarshalFunc_VOID__OBJECT_BOXED callback;
     87   register GCClosure *cc = reinterpret_cast<GCClosure*>(closure);
     88   register gpointer data1, data2;
     89 
     90   g_return_if_fail(n_param_values == 3);
     91 
     92   if (G_CCLOSURE_SWAP_DATA(closure)) {
     93     data1 = closure->data;
     94     data2 = g_value_peek_pointer(param_values + 0);
     95   } else {
     96     data1 = g_value_peek_pointer(param_values + 0);
     97     data2 = closure->data;
     98   }
     99 
    100   callback = reinterpret_cast<GMarshalFunc_VOID__OBJECT_BOXED>(
    101       marshal_data ? marshal_data : cc->callback);
    102 
    103   callback(data1,
    104            g_value_get_object(param_values + 1),
    105            g_value_get_boxed(param_values + 2),
    106            data2);
    107 }
    108 
    109 }  // namespace
    110 
    111 G_BEGIN_DECLS
    112 
    113 static void gtk_expanded_container_size_allocate(GtkWidget* widget,
    114                                                  GtkAllocation* allocation);
    115 
    116 G_DEFINE_TYPE(GtkExpandedContainer, gtk_expanded_container, GTK_TYPE_FIXED)
    117 
    118 static void gtk_expanded_container_class_init(
    119     GtkExpandedContainerClass *klass) {
    120   GtkObjectClass* object_class =
    121       reinterpret_cast<GtkObjectClass*>(klass);
    122 
    123   GtkWidgetClass* widget_class =
    124       reinterpret_cast<GtkWidgetClass*>(klass);
    125   widget_class->size_allocate = gtk_expanded_container_size_allocate;
    126 
    127   expanded_container_signals[CHILD_SIZE_REQUEST] =
    128       g_signal_new("child-size-request",
    129                    G_OBJECT_CLASS_TYPE(object_class),
    130                    static_cast<GSignalFlags>(G_SIGNAL_RUN_FIRST),
    131                    0,
    132                    NULL, NULL,
    133                    Marshal_VOID__OBJECT_BOXED,
    134                    G_TYPE_NONE, 2,
    135                    GTK_TYPE_WIDGET,
    136                    GTK_TYPE_REQUISITION | G_SIGNAL_TYPE_STATIC_SCOPE);
    137 }
    138 
    139 static void gtk_expanded_container_init(GtkExpandedContainer* container) {
    140 }
    141 
    142 static void gtk_expanded_container_size_allocate(GtkWidget* widget,
    143                                                  GtkAllocation* allocation) {
    144   widget->allocation = *allocation;
    145 
    146   if (!GTK_WIDGET_NO_WINDOW(widget) && GTK_WIDGET_REALIZED(widget)) {
    147     gdk_window_move_resize(widget->window,
    148                            allocation->x,
    149                            allocation->y,
    150                            allocation->width,
    151                            allocation->height);
    152   }
    153 
    154   SizeAllocateData data;
    155   data.container = widget;
    156   data.allocation = allocation;
    157   data.border_width = gtk_container_get_border_width(GTK_CONTAINER(widget));
    158 
    159   gtk_container_foreach(GTK_CONTAINER(widget), ChildSizeAllocate, &data);
    160 }
    161 
    162 GtkWidget* gtk_expanded_container_new() {
    163   return GTK_WIDGET(g_object_new(GTK_TYPE_EXPANDED_CONTAINER, NULL));
    164 }
    165 
    166 void gtk_expanded_container_put(GtkExpandedContainer* container,
    167                                 GtkWidget* widget, gint x, gint y) {
    168   g_return_if_fail(GTK_IS_EXPANDED_CONTAINER(container));
    169   g_return_if_fail(GTK_IS_WIDGET(widget));
    170   gtk_fixed_put(GTK_FIXED(container), widget, x, y);
    171 }
    172 
    173 void gtk_expanded_container_move(GtkExpandedContainer* container,
    174                                  GtkWidget* widget, gint x, gint y) {
    175   g_return_if_fail(GTK_IS_EXPANDED_CONTAINER(container));
    176   g_return_if_fail(GTK_IS_WIDGET(widget));
    177   gtk_fixed_move(GTK_FIXED(container), widget, x, y);
    178 }
    179 
    180 void gtk_expanded_container_set_has_window(GtkExpandedContainer* container,
    181                                            gboolean has_window) {
    182   g_return_if_fail(GTK_IS_EXPANDED_CONTAINER(container));
    183   g_return_if_fail(!GTK_WIDGET_REALIZED(container));
    184   gtk_fixed_set_has_window(GTK_FIXED(container), has_window);
    185 }
    186 
    187 gboolean gtk_expanded_container_get_has_window(
    188     GtkExpandedContainer* container) {
    189   g_return_val_if_fail(GTK_IS_EXPANDED_CONTAINER(container), FALSE);
    190   return gtk_fixed_get_has_window(GTK_FIXED(container));
    191 }
    192 
    193 G_END_DECLS
    194