Commit 726b0d87 authored by Matthias Clasen's avatar Matthias Clasen

Bandaid fix for icon view subclassing

I've decided that it is isn't feasible to make cell areas runtime-settable
in the time we have left before 3.0, therefore, I'm going with the
approach to allow init() functions to instantiate the default cell area
and issue a warning if a construct property is ignored.

This is not ideal, but it keeps existing icon view and combo box
subclasses working.

https://bugzilla.gnome.org/show_bug.cgi?id=639139
parent 1f3a5a8d
......@@ -83,6 +83,55 @@
* </example>
* </para>
* </refsect2>
*
* <refsect2>
* <title>Subclassing GtkCellLayout implementations</title>
* <para>
* When subclassing a widget that implements #GtkCellLayout like
* #GtkIconView or #GtkComboBox, there are some considerations related
* to the fact that these widgets internally use a #GtkCellArea.
* The cell area is exposed as a construct-only property by these
* widgets. This means that it is possible to e.g. do
* <informalexample><programlisting>
* combo = g_object_new (GTK_TYPE_COMBO_BOX, "cell-area", my_cell_area, NULL);
* </programlisting></informalexample>
* to use a custom cell area with a combo box. But construct properties
* are only initialized <emphasis>after</emphasis> instance init()
* functions have run, which means that using functions which rely on
* the existence of the cell area in your subclass' init() function will
* cause the default cell area to be instantiated. In this case, a provided
* construct property value will be ignored (with a warning, to alert
* you to the problem).
* <informalexample><programlisting>
* static void
* my_combo_box_init (MyComboBox *b)
* {
* GtkCellRenderer *cell;
*
* cell = gtk_cell_renderer_pixbuf_new ();
* /&ast; The following call causes the default cell area for combo boxes,
* &ast; a GtkCellAreaBox, to be instantiated
* &ast;/
* gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (b), cell, FALSE);
* ...
* }
*
* GtkWidget *
* my_combo_box_new (GtkCellArea *area)
* {
* /&ast; This call is going to cause a warning
* &ast; about area being ignored
* &ast;/
* return g_object_new (MY_TYPE_COMBO_BOX, "cell-area", area, NULL);
* }
* </programlisting></informalexample>
* If supporting alternative cell areas with your derived widget is
* not important, then this does not have to concern you. If you want
* to support alternative cell areas, you can do so by moving the
* problematic calls out of init() and into a constructor()
* for your class.
* </para>
* </refsect2>
*/
#include "config.h"
......
......@@ -347,15 +347,14 @@ gtk_cell_view_constructor (GType type,
if (!priv->area)
{
GtkCellArea *area = gtk_cell_area_box_new ();
priv->area = g_object_ref_sink (area);
priv->area = gtk_cell_area_box_new ();
g_object_ref_sink (priv->area);
}
if (!priv->context)
priv->context = gtk_cell_area_create_context (priv->area);
priv->size_changed_id =
priv->size_changed_id =
g_signal_connect (priv->context, "notify",
G_CALLBACK (context_size_changed_cb), view);
......@@ -421,15 +420,16 @@ gtk_cell_view_set_property (GObject *object,
GParamSpec *pspec)
{
GtkCellView *view = GTK_CELL_VIEW (object);
GtkCellViewPrivate *priv = view->priv;
GtkCellArea *area;
GtkCellAreaContext *context;
switch (param_id)
{
case PROP_ORIENTATION:
view->priv->orientation = g_value_get_enum (value);
if (view->priv->context)
gtk_cell_area_context_reset (view->priv->context);
priv->orientation = g_value_get_enum (value);
if (priv->context)
gtk_cell_area_context_reset (priv->context);
_gtk_orientable_set_style_classes (GTK_ORIENTABLE (object));
break;
......@@ -462,16 +462,34 @@ gtk_cell_view_set_property (GObject *object,
case PROP_CELL_AREA:
/* Construct-only, can only be assigned once */
area = g_value_get_object (value);
if (area)
view->priv->area = g_object_ref_sink (area);
{
if (priv->area != NULL)
{
g_warning ("cell-area has already been set, ignoring construct property");
g_object_ref_sink (area);
g_object_unref (area);
}
else
priv->area = g_object_ref_sink (area);
}
break;
case PROP_CELL_AREA_CONTEXT:
/* Construct-only, can only be assigned once */
context = g_value_get_object (value);
if (context)
view->priv->context = g_object_ref (context);
{
if (priv->context != NULL)
{
g_warning ("cell-area-context has already been set, ignoring construct property");
g_object_ref_sink (context);
g_object_unref (context);
}
else
priv->context = g_object_ref (context);
}
break;
case PROP_DRAW_SENSITIVE:
......@@ -809,8 +827,15 @@ static GtkCellArea *
gtk_cell_view_cell_layout_get_area (GtkCellLayout *layout)
{
GtkCellView *cellview = GTK_CELL_VIEW (layout);
GtkCellViewPrivate *priv = cellview->priv;
if (G_UNLIKELY (!priv->area))
{
priv->area = gtk_cell_area_box_new ();
g_object_ref_sink (priv->area);
}
return cellview->priv->area;
return priv->area;
}
/* GtkBuildable implementation */
......@@ -1391,8 +1416,8 @@ gtk_cell_view_get_fit_model (GtkCellView *cell_view)
* Since: 3.0
*/
void
gtk_cell_view_set_fit_model (GtkCellView *cell_view,
gboolean fit_model)
gtk_cell_view_set_fit_model (GtkCellView *cell_view,
gboolean fit_model)
{
GtkCellViewPrivate *priv;
......
......@@ -65,7 +65,7 @@ struct _GtkCellViewClass
GType gtk_cell_view_get_type (void) G_GNUC_CONST;
GtkWidget *gtk_cell_view_new (void);
GtkWidget *gtk_cell_view_new_with_context (GtkCellArea *area,
GtkCellAreaContext *context);
GtkCellAreaContext *context);
GtkWidget *gtk_cell_view_new_with_text (const gchar *text);
GtkWidget *gtk_cell_view_new_with_markup (const gchar *markup);
GtkWidget *gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf);
......@@ -81,10 +81,10 @@ void gtk_cell_view_set_background_rgba (GtkCellView *cell_v
const GdkRGBA *rgba);
gboolean gtk_cell_view_get_draw_sensitive (GtkCellView *cell_view);
void gtk_cell_view_set_draw_sensitive (GtkCellView *cell_view,
gboolean draw_sensitive);
gboolean draw_sensitive);
gboolean gtk_cell_view_get_fit_model (GtkCellView *cell_view);
void gtk_cell_view_set_fit_model (GtkCellView *cell_view,
gboolean fit_model);
gboolean fit_model);
#ifndef GTK_DISABLE_DEPRECATED
gboolean gtk_cell_view_get_size_of_row (GtkCellView *cell_view,
......
......@@ -406,7 +406,7 @@ static void gtk_combo_box_menu_popup (GtkComboBox *combo_box,
guint32 activate_time);
/* cell layout */
GtkCellArea *gtk_combo_box_cell_layout_get_area (GtkCellLayout *cell_layout);
static GtkCellArea *gtk_combo_box_cell_layout_get_area (GtkCellLayout *cell_layout);
static gboolean gtk_combo_box_mnemonic_activate (GtkWidget *widget,
gboolean group_cycling);
......@@ -1049,6 +1049,7 @@ gtk_combo_box_set_property (GObject *object,
GParamSpec *pspec)
{
GtkComboBox *combo_box = GTK_COMBO_BOX (object);
GtkComboBoxPrivate *priv = combo_box->priv;
GtkCellArea *area;
switch (prop_id)
......@@ -1078,16 +1079,15 @@ gtk_combo_box_set_property (GObject *object,
break;
case PROP_HAS_FRAME:
combo_box->priv->has_frame = g_value_get_boolean (value);
priv->has_frame = g_value_get_boolean (value);
if (combo_box->priv->has_entry)
if (priv->has_entry)
{
GtkWidget *child;
child = gtk_bin_get_child (GTK_BIN (combo_box));
gtk_entry_set_has_frame (GTK_ENTRY (child),
combo_box->priv->has_frame);
gtk_entry_set_has_frame (GTK_ENTRY (child), priv->has_frame);
}
break;
......@@ -1119,11 +1119,11 @@ gtk_combo_box_set_property (GObject *object,
break;
case PROP_EDITING_CANCELED:
combo_box->priv->editing_canceled = g_value_get_boolean (value);
priv->editing_canceled = g_value_get_boolean (value);
break;
case PROP_HAS_ENTRY:
combo_box->priv->has_entry = g_value_get_boolean (value);
priv->has_entry = g_value_get_boolean (value);
break;
case PROP_ENTRY_TEXT_COLUMN:
......@@ -1141,9 +1141,17 @@ gtk_combo_box_set_property (GObject *object,
case PROP_CELL_AREA:
/* Construct-only, can only be assigned once */
area = g_value_get_object (value);
if (area)
combo_box->priv->area = g_object_ref_sink (area);
{
if (priv->area != NULL)
{
g_warning ("cell-area has already been set, ignoring construct property");
g_object_ref_sink (area);
g_object_unref (area);
}
else
priv->area = g_object_ref_sink (area);
}
break;
default:
......@@ -3757,10 +3765,19 @@ gtk_combo_box_list_row_changed (GtkTreeModel *model,
/*
* GtkCellLayout implementation
*/
GtkCellArea *
gtk_combo_box_cell_layout_get_area (GtkCellLayout *cell_layout)
static GtkCellArea *
gtk_combo_box_cell_layout_get_area (GtkCellLayout *cell_layout)
{
return GTK_COMBO_BOX (cell_layout)->priv->area;
GtkComboBox *combo = GTK_COMBO_BOX (cell_layout);
GtkComboBoxPrivate *priv = combo->priv;
if (G_UNLIKELY (!priv->area))
{
priv->area = gtk_cell_area_box_new ();
g_object_ref_sink (priv->area);
}
return priv->area;
}
/*
......@@ -4552,9 +4569,8 @@ gtk_combo_box_constructor (GType type,
if (!priv->area)
{
GtkCellArea *area = gtk_cell_area_box_new ();
priv->area = g_object_ref_sink (area);
priv->area = gtk_cell_area_box_new ();
g_object_ref_sink (priv->area);
}
priv->cell_view = gtk_cell_view_new_with_context (priv->area, NULL);
......
......@@ -481,9 +481,9 @@ gtk_entry_completion_init (GtkEntryCompletion *completion)
}
static GObject *
gtk_entry_completion_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
gtk_entry_completion_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GtkEntryCompletion *completion;
GtkEntryCompletionPrivate *priv;
......@@ -657,9 +657,17 @@ gtk_entry_completion_set_property (GObject *object,
case PROP_CELL_AREA:
/* Construct-only, can only be assigned once */
area = g_value_get_object (value);
if (area)
priv->cell_area = g_object_ref_sink (area);
{
if (priv->cell_area != NULL)
{
g_warning ("cell-area has already been set, ignoring construct property");
g_object_ref_sink (area);
g_object_unref (area);
}
else
priv->cell_area = g_object_ref_sink (area);
}
break;
default:
......@@ -786,6 +794,12 @@ gtk_entry_completion_get_area (GtkCellLayout *cell_layout)
priv = GTK_ENTRY_COMPLETION (cell_layout)->priv;
if (G_UNLIKELY (!priv->cell_area))
{
priv->cell_area = gtk_cell_area_box_new ();
g_object_ref_sink (priv->cell_area);
}
return priv->cell_area;
}
......
......@@ -370,6 +370,9 @@ static GtkIconViewItem * gtk_icon_view_get_item_at_coords (GtkIco
static void gtk_icon_view_set_cell_data (GtkIconView *icon_view,
GtkIconViewItem *item);
static void gtk_icon_view_ensure_cell_area (GtkIconView *icon_view,
GtkCellArea *cell_area);
static GtkCellArea *gtk_icon_view_cell_layout_get_area (GtkCellLayout *layout);
static void gtk_icon_view_item_selected_changed (GtkIconView *icon_view,
......@@ -1100,35 +1103,14 @@ gtk_icon_view_constructor (GType type,
GObjectConstructParam *construct_properties)
{
GtkIconView *icon_view;
GtkIconViewPrivate *priv;
GObject *object;
object = G_OBJECT_CLASS (gtk_icon_view_parent_class)->constructor
(type, n_construct_properties, construct_properties);
icon_view = (GtkIconView *) object;
priv = icon_view->priv;
if (!priv->cell_area)
{
priv->cell_area = gtk_cell_area_box_new ();
g_object_ref_sink (priv->cell_area);
}
if (GTK_IS_ORIENTABLE (priv->cell_area))
gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->cell_area), priv->item_orientation);
priv->cell_area_context = gtk_cell_area_create_context (priv->cell_area);
priv->add_editable_id =
g_signal_connect (priv->cell_area, "add-editable",
G_CALLBACK (gtk_icon_view_add_editable), icon_view);
priv->remove_editable_id =
g_signal_connect (priv->cell_area, "remove-editable",
G_CALLBACK (gtk_icon_view_remove_editable), icon_view);
priv->context_changed_id =
g_signal_connect (priv->cell_area_context, "notify",
G_CALLBACK (gtk_icon_view_context_changed), icon_view);
gtk_icon_view_ensure_cell_area (icon_view, NULL);
return object;
}
......@@ -1237,9 +1219,17 @@ gtk_icon_view_set_property (GObject *object,
case PROP_CELL_AREA:
/* Construct-only, can only be assigned once */
area = g_value_get_object (value);
if (area)
icon_view->priv->cell_area = g_object_ref_sink (area);
{
if (icon_view->priv->cell_area != NULL)
{
g_warning ("cell-area has already been set, ignoring construct property");
g_object_ref_sink (area);
g_object_unref (area);
}
else
gtk_icon_view_ensure_cell_area (icon_view, area);
}
break;
case PROP_HADJUSTMENT:
......@@ -4097,21 +4087,58 @@ gtk_icon_view_scroll_to_item (GtkIconView *icon_view,
}
/* GtkCellLayout implementation */
static void
gtk_icon_view_ensure_cell_area (GtkIconView *icon_view,
GtkCellArea *cell_area)
{
GtkIconViewPrivate *priv = icon_view->priv;
if (priv->cell_area)
return;
if (cell_area)
priv->cell_area = cell_area;
else
priv->cell_area = gtk_cell_area_box_new ();
g_object_ref_sink (priv->cell_area);
if (GTK_IS_ORIENTABLE (priv->cell_area))
gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->cell_area), priv->item_orientation);
priv->cell_area_context = gtk_cell_area_create_context (priv->cell_area);
priv->add_editable_id =
g_signal_connect (priv->cell_area, "add-editable",
G_CALLBACK (gtk_icon_view_add_editable), icon_view);
priv->remove_editable_id =
g_signal_connect (priv->cell_area, "remove-editable",
G_CALLBACK (gtk_icon_view_remove_editable), icon_view);
priv->context_changed_id =
g_signal_connect (priv->cell_area_context, "notify",
G_CALLBACK (gtk_icon_view_context_changed), icon_view);
}
static GtkCellArea *
gtk_icon_view_cell_layout_get_area (GtkCellLayout *cell_layout)
{
GtkIconView *icon_view = GTK_ICON_VIEW (cell_layout);
GtkIconViewPrivate *priv = icon_view->priv;
if (G_UNLIKELY (!priv->cell_area))
gtk_icon_view_ensure_cell_area (icon_view, NULL);
return icon_view->priv->cell_area;
}
static void
gtk_icon_view_set_cell_data (GtkIconView *icon_view,
gtk_icon_view_set_cell_data (GtkIconView *icon_view,
GtkIconViewItem *item)
{
gboolean iters_persist;
GtkTreeIter iter;
iters_persist = gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST;
if (!iters_persist)
......
......@@ -76,6 +76,9 @@ static GObject *gtk_tree_view_column_constructor (GType
GObjectConstructParam *construct_properties);
/* GtkCellLayout implementation */
static void gtk_tree_view_column_ensure_cell_area (GtkTreeViewColumn *column,
GtkCellArea *cell_area);
static GtkCellArea *gtk_tree_view_column_cell_layout_get_area (GtkCellLayout *cell_layout);
/* Button handling code */
......@@ -476,40 +479,19 @@ gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
}
static GObject *
gtk_tree_view_column_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
gtk_tree_view_column_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GtkTreeViewColumn *tree_column;
GtkTreeViewColumnPrivate *priv;
GObject *object;
object = G_OBJECT_CLASS (gtk_tree_view_column_parent_class)->constructor
(type, n_construct_properties, construct_properties);
tree_column = (GtkTreeViewColumn *) object;
priv = tree_column->priv;
if (!priv->cell_area)
{
priv->cell_area = gtk_cell_area_box_new ();
g_object_ref_sink (priv->cell_area);
}
priv->add_editable_signal =
g_signal_connect (priv->cell_area, "add-editable",
G_CALLBACK (gtk_tree_view_column_add_editable_callback),
tree_column);
priv->remove_editable_signal =
g_signal_connect (priv->cell_area, "remove-editable",
G_CALLBACK (gtk_tree_view_column_remove_editable_callback),
tree_column);
priv->cell_area_context = gtk_cell_area_create_context (priv->cell_area);
priv->context_changed_signal =
g_signal_connect (priv->cell_area_context, "notify",
G_CALLBACK (gtk_tree_view_column_context_changed), tree_column);
gtk_tree_view_column_ensure_cell_area (tree_column, NULL);
return object;
}
......@@ -537,7 +519,7 @@ gtk_tree_view_column_dispose (GObject *object)
priv->add_editable_signal);
g_signal_handler_disconnect (priv->cell_area,
priv->remove_editable_signal);
g_object_unref (priv->cell_area);
priv->cell_area = NULL;
priv->add_editable_signal = 0;
......@@ -662,9 +644,18 @@ gtk_tree_view_column_set_property (GObject *object,
area = g_value_get_object (value);
if (area)
tree_column->priv->cell_area = g_object_ref_sink (area);
{
if (tree_column->priv->cell_area != NULL)
{
g_warning ("cell-area has already been set, ignoring construct property");
g_object_ref_sink (area);
g_object_unref (area);
}
else
gtk_tree_view_column_ensure_cell_area (tree_column, area);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -780,12 +771,51 @@ gtk_tree_view_column_get_property (GObject *object,
/* Implementation of GtkCellLayout interface
*/
static void
gtk_tree_view_column_ensure_cell_area (GtkTreeViewColumn *column,
GtkCellArea *cell_area)
{
GtkTreeViewColumnPrivate *priv = column->priv;
if (priv->cell_area)
return;
if (cell_area)
priv->cell_area = cell_area;
else
priv->cell_area = gtk_cell_area_box_new ();
g_object_ref_sink (priv->cell_area);
priv->cell_area_context = gtk_cell_area_create_context (priv->cell_area);
priv->add_editable_signal =
g_signal_connect (priv->cell_area, "add-editable",
G_CALLBACK (gtk_tree_view_column_add_editable_callback),
column);
priv->remove_editable_signal =
g_signal_connect (priv->cell_area, "remove-editable",
G_CALLBACK (gtk_tree_view_column_remove_editable_callback),
column);
priv->cell_area_context = gtk_cell_area_create_context (priv->cell_area);
priv->context_changed_signal =
g_signal_connect (priv->cell_area_context, "notify",
G_CALLBACK (gtk_tree_view_column_context_changed),
column);
}
static GtkCellArea *
gtk_tree_view_column_cell_layout_get_area (GtkCellLayout *cell_layout)
{
GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (cell_layout);
GtkTreeViewColumnPrivate *priv = column->priv;
if (G_UNLIKELY (!priv->cell_area))
gtk_tree_view_column_ensure_cell_area (column, NULL);
return priv->cell_area;
}
......
......@@ -105,6 +105,10 @@ TEST_PROGS += papersize
papersize_SOURCES = papersize.c
papersize_LDADD = $(progs_ldadd)
TEST_PROGS += cellarea
cellarea_SOURCES = cellarea.c
cellarea_LDADD = $(progs_ldadd)
EXTRA_DIST += \
file-chooser-test-dir/empty \
file-chooser-test-dir/text.txt
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment