gtkcellrenderer.c 58 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* gtkcellrenderer.c
 * Copyright (C) 2000  Red Hat, Inc. Jonathan Blandford
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library 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/>.
16 17
 */

18
#include "config.h"
19
#include "gtkcellrenderer.h"
20
#include "gtkintl.h"
Federico Mena Quintero's avatar
Federico Mena Quintero committed
21
#include "gtkmarshalers.h"
22
#include "gtktypebuiltins.h"
23
#include "gtkprivate.h"
24
#include "gtktreeprivate.h"
25
#include "a11y/gtkrenderercellaccessible.h"
26

27 28 29

/**
 * SECTION:gtkcellrenderer
30
 * @Short_description: An object for rendering a single cell
31
 * @Title: GtkCellRenderer
32
 * @See_also: #GtkCellEditable
33 34
 *
 * The #GtkCellRenderer is a base class of a set of objects used for
35
 * rendering a cell to a #cairo_t.  These objects are used primarily by
36
 * the #GtkTreeView widget, though they aren’t tied to them in any
37 38 39 40
 * specific way.  It is worth noting that #GtkCellRenderer is not a
 * #GtkWidget and cannot be treated as such.
 *
 * The primary use of a #GtkCellRenderer is for drawing a certain graphical
41
 * elements on a #cairo_t. Typically, one cell renderer is used to
42
 * draw many cells on the screen.  To this extent, it isn’t expected that a
43
 * CellRenderer keep any permanent state around.  Instead, any state is set
44
 * just prior to use using #GObjects property system.  Then, the
45 46 47 48
 * cell is measured using gtk_cell_renderer_get_size(). Finally, the cell
 * is rendered in the correct location using gtk_cell_renderer_render().
 *
 * There are a number of rules that must be followed when writing a new
49
 * #GtkCellRenderer.  First and foremost, it’s important that a certain set
50 51 52 53 54 55
 * of properties will always yield a cell renderer of the same size,
 * barring a #GtkStyle change.  The #GtkCellRenderer also has a number of
 * generic properties that are expected to be honored by all children.
 *
 * Beyond merely rendering a cell, cell renderers can optionally
 * provide active user interface elements. A cell renderer can be
56
 * “activatable” like #GtkCellRendererToggle,
57
 * which toggles when it gets activated by a mouse click, or it can be
58
 * “editable” like #GtkCellRendererText, which
59 60
 * allows the user to edit the text using a widget implementing the
 * #GtkCellEditable interface, e.g. #GtkEntry.
61 62 63
 * To make a cell renderer activatable or editable, you have to
 * implement the #GtkCellRendererClass.activate or
 * #GtkCellRendererClass.start_editing virtual functions, respectively.
64 65
 *
 * Many properties of #GtkCellRenderer and its subclasses have a
William Jon McCann's avatar
William Jon McCann committed
66 67
 * corresponding “set” property, e.g. “cell-background-set” corresponds
 * to “cell-background”. These “set” properties reflect whether a property
68
 * has been set or not. You should not set them independently.
69 70 71
 */


72
#define DEBUG_CELL_SIZE_REQUEST 0
73

74 75
static void gtk_cell_renderer_init          (GtkCellRenderer      *cell);
static void gtk_cell_renderer_class_init    (GtkCellRendererClass *class);
76 77 78
static void gtk_cell_renderer_get_property  (GObject              *object,
					     guint                 param_id,
					     GValue               *value,
Tim Janik's avatar
Tim Janik committed
79
					     GParamSpec           *pspec);
80 81 82
static void gtk_cell_renderer_set_property  (GObject              *object,
					     guint                 param_id,
					     const GValue         *value,
Tim Janik's avatar
Tim Janik committed
83
					     GParamSpec           *pspec);
84
static void set_cell_bg_color               (GtkCellRenderer      *cell,
85
					     GdkRGBA              *rgba);
86

87
/* Fallback GtkCellRenderer    implementation to use remaining ->get_size() implementations */
88
static GtkSizeRequestMode gtk_cell_renderer_real_get_request_mode(GtkCellRenderer         *cell);
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
static void gtk_cell_renderer_real_get_preferred_width           (GtkCellRenderer         *cell,
                                                                  GtkWidget               *widget,
                                                                  gint                    *minimum_size,
                                                                  gint                    *natural_size);
static void gtk_cell_renderer_real_get_preferred_height          (GtkCellRenderer         *cell,
                                                                  GtkWidget               *widget,
                                                                  gint                    *minimum_size,
                                                                  gint                    *natural_size);
static void gtk_cell_renderer_real_get_preferred_height_for_width(GtkCellRenderer         *cell,
                                                                  GtkWidget               *widget,
                                                                  gint                     width,
                                                                  gint                    *minimum_height,
                                                                  gint                    *natural_height);
static void gtk_cell_renderer_real_get_preferred_width_for_height(GtkCellRenderer         *cell,
                                                                  GtkWidget               *widget,
                                                                  gint                     height,
                                                                  gint                    *minimum_width,
                                                                  gint                    *natural_width);
107 108 109 110 111
static void gtk_cell_renderer_real_get_aligned_area              (GtkCellRenderer         *cell,
								  GtkWidget               *widget,
								  GtkCellRendererState     flags,
								  const GdkRectangle      *cell_area,
								  GdkRectangle            *aligned_area);
112

113

114
struct _GtkCellRendererPrivate
115
{
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
  gfloat xalign;
  gfloat yalign;

  gint width;
  gint height;

  guint16 xpad;
  guint16 ypad;

  guint mode                : 2;
  guint visible             : 1;
  guint is_expander         : 1;
  guint is_expanded         : 1;
  guint cell_background_set : 1;
  guint sensitive           : 1;
  guint editing             : 1;

133
  GdkRGBA cell_background;
134 135
};

136 137
struct _GtkCellRendererClassPrivate
{
138
  GType accessible_type;
139
};
140

141
enum {
142
  PROP_0,
143
  PROP_MODE,
144
  PROP_VISIBLE,
145
  PROP_SENSITIVE,
146 147 148
  PROP_XALIGN,
  PROP_YALIGN,
  PROP_XPAD,
149
  PROP_YPAD,
150 151
  PROP_WIDTH,
  PROP_HEIGHT,
152
  PROP_IS_EXPANDER,
153 154 155
  PROP_IS_EXPANDED,
  PROP_CELL_BACKGROUND,
  PROP_CELL_BACKGROUND_GDK,
156
  PROP_CELL_BACKGROUND_RGBA,
157 158
  PROP_CELL_BACKGROUND_SET,
  PROP_EDITING
159 160
};

Federico Mena Quintero's avatar
Federico Mena Quintero committed
161 162 163
/* Signal IDs */
enum {
  EDITING_CANCELED,
164
  EDITING_STARTED,
Federico Mena Quintero's avatar
Federico Mena Quintero committed
165 166 167
  LAST_SIGNAL
};

168
static gint GtkCellRenderer_private_offset;
169 170
static guint  cell_renderer_signals[LAST_SIGNAL] = { 0 };

171 172 173 174 175 176
static inline gpointer
gtk_cell_renderer_get_instance_private (GtkCellRenderer *self)
{
  return (G_STRUCT_MEMBER_P (self, GtkCellRenderer_private_offset));
}

177 178 179
static void
gtk_cell_renderer_init (GtkCellRenderer *cell)
{
180
  GtkCellRendererPrivate *priv;
181

182
  cell->priv = gtk_cell_renderer_get_instance_private (cell);
183 184 185 186 187 188 189 190 191 192 193 194 195 196
  priv = cell->priv;

  priv->mode = GTK_CELL_RENDERER_MODE_INERT;
  priv->visible = TRUE;
  priv->width = -1;
  priv->height = -1;
  priv->xalign = 0.5;
  priv->yalign = 0.5;
  priv->xpad = 0;
  priv->ypad = 0;
  priv->sensitive = TRUE;
  priv->is_expander = FALSE;
  priv->is_expanded = FALSE;
  priv->editing = FALSE;
197 198 199 200 201 202 203
}

static void
gtk_cell_renderer_class_init (GtkCellRendererClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);

204 205
  object_class->get_property = gtk_cell_renderer_get_property;
  object_class->set_property = gtk_cell_renderer_set_property;
206 207 208

  class->render = NULL;
  class->get_size = NULL;
209
  class->get_request_mode               = gtk_cell_renderer_real_get_request_mode;
210 211 212 213
  class->get_preferred_width            = gtk_cell_renderer_real_get_preferred_width;
  class->get_preferred_height           = gtk_cell_renderer_real_get_preferred_height;
  class->get_preferred_width_for_height = gtk_cell_renderer_real_get_preferred_width_for_height;
  class->get_preferred_height_for_width = gtk_cell_renderer_real_get_preferred_height_for_width;
214
  class->get_aligned_area               = gtk_cell_renderer_real_get_aligned_area;
215

Federico Mena Quintero's avatar
Federico Mena Quintero committed
216 217
  /**
   * GtkCellRenderer::editing-canceled:
Matthias Clasen's avatar
Matthias Clasen committed
218
   * @renderer: the object which received the signal
Federico Mena Quintero's avatar
Federico Mena Quintero committed
219 220 221
   *
   * This signal gets emitted when the user cancels the process of editing a
   * cell.  For example, an editable cell renderer could be written to cancel
222
   * editing when the user presses Escape. 
Federico Mena Quintero's avatar
Federico Mena Quintero committed
223
   *
Matthias Clasen's avatar
Matthias Clasen committed
224
   * See also: gtk_cell_renderer_stop_editing().
Federico Mena Quintero's avatar
Federico Mena Quintero committed
225 226 227 228
   *
   * Since: 2.4
   */
  cell_renderer_signals[EDITING_CANCELED] =
Matthias Clasen's avatar
Matthias Clasen committed
229
    g_signal_new (I_("editing-canceled"),
Federico Mena Quintero's avatar
Federico Mena Quintero committed
230 231 232 233
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkCellRendererClass, editing_canceled),
		  NULL, NULL,
234
		  NULL,
Federico Mena Quintero's avatar
Federico Mena Quintero committed
235 236
		  G_TYPE_NONE, 0);

237 238 239 240 241 242 243
  /**
   * GtkCellRenderer::editing-started:
   * @renderer: the object which received the signal
   * @editable: the #GtkCellEditable
   * @path: the path identifying the edited cell
   *
   * This signal gets emitted when a cell starts to be edited.
Paul Pogonyshev's avatar
Paul Pogonyshev committed
244
   * The intended use of this signal is to do special setup
245 246 247
   * on @editable, e.g. adding a #GtkEntryCompletion or setting
   * up additional columns in a #GtkComboBox.
   *
248 249 250
   * See gtk_cell_editable_start_editing() for information on the lifecycle of
   * the @editable and a way to do setup that doesn’t depend on the @renderer.
   *
251 252 253 254
   * Note that GTK+ doesn't guarantee that cell renderers will
   * continue to use the same kind of widget for editing in future
   * releases, therefore you should check the type of @editable
   * before doing any specific setup, as in the following example:
255
   * |[<!-- language="C" -->
256 257 258 259 260 261 262 263 264
   * static void
   * text_editing_started (GtkCellRenderer *cell,
   *                       GtkCellEditable *editable,
   *                       const gchar     *path,
   *                       gpointer         data)
   * {
   *   if (GTK_IS_ENTRY (editable)) 
   *     {
   *       GtkEntry *entry = GTK_ENTRY (editable);
Matthias Clasen's avatar
Matthias Clasen committed
265
   *       
266
   *       // ... create a GtkEntryCompletion
Matthias Clasen's avatar
Matthias Clasen committed
267
   *       
268 269 270
   *       gtk_entry_set_completion (entry, completion);
   *     }
   * }
Matthias Clasen's avatar
Matthias Clasen committed
271
   * ]|
272 273 274 275
   *
   * Since: 2.6
   */
  cell_renderer_signals[EDITING_STARTED] =
Matthias Clasen's avatar
Matthias Clasen committed
276
    g_signal_new (I_("editing-started"),
277 278 279 280 281 282 283 284
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkCellRendererClass, editing_started),
		  NULL, NULL,
		  _gtk_marshal_VOID__OBJECT_STRING,
		  G_TYPE_NONE, 2,
		  GTK_TYPE_CELL_EDITABLE,
		  G_TYPE_STRING);
285 286 287
  g_signal_set_va_marshaller (cell_renderer_signals[EDITING_STARTED],
                              G_TYPE_FROM_CLASS (object_class),
                              _gtk_marshal_VOID__OBJECT_STRINGv);
288

289
  g_object_class_install_property (object_class,
290 291
				   PROP_MODE,
				   g_param_spec_enum ("mode",
292 293
						      P_("mode"),
						      P_("Editable mode of the CellRenderer"),
294 295
						      GTK_TYPE_CELL_RENDERER_MODE,
						      GTK_CELL_RENDERER_MODE_INERT,
296
						      GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
297

298 299 300
  g_object_class_install_property (object_class,
				   PROP_VISIBLE,
				   g_param_spec_boolean ("visible",
301 302
							 P_("visible"),
							 P_("Display the cell"),
303
							 TRUE,
304
							 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
305 306 307 308 309 310
  g_object_class_install_property (object_class,
				   PROP_SENSITIVE,
				   g_param_spec_boolean ("sensitive",
							 P_("Sensitive"),
							 P_("Display the cell sensitive"),
							 TRUE,
311
							 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
312

313 314 315
  g_object_class_install_property (object_class,
				   PROP_XALIGN,
				   g_param_spec_float ("xalign",
316 317
						       P_("xalign"),
						       P_("The x-align"),
318 319
						       0.0,
						       1.0,
320
						       0.5,
321
						       GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
322

323 324 325
  g_object_class_install_property (object_class,
				   PROP_YALIGN,
				   g_param_spec_float ("yalign",
326 327
						       P_("yalign"),
						       P_("The y-align"),
328 329 330
						       0.0,
						       1.0,
						       0.5,
331
						       GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
332

333 334 335
  g_object_class_install_property (object_class,
				   PROP_XPAD,
				   g_param_spec_uint ("xpad",
336 337
						      P_("xpad"),
						      P_("The xpad"),
338
						      0,
339
						      G_MAXUINT,
340
						      0,
341
						      GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
342

343 344 345
  g_object_class_install_property (object_class,
				   PROP_YPAD,
				   g_param_spec_uint ("ypad",
346 347
						      P_("ypad"),
						      P_("The ypad"),
348
						      0,
349
						      G_MAXUINT,
350
						      0,
351
						      GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
352 353 354 355

  g_object_class_install_property (object_class,
				   PROP_WIDTH,
				   g_param_spec_int ("width",
356 357
						     P_("width"),
						     P_("The fixed width"),
358
						     -1,
359
						     G_MAXINT,
360
						     -1,
361
						     GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
362 363 364 365

  g_object_class_install_property (object_class,
				   PROP_HEIGHT,
				   g_param_spec_int ("height",
366 367
						     P_("height"),
						     P_("The fixed height"),
368
						     -1,
369
						     G_MAXINT,
370
						     -1,
371
						     GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
372 373 374

  g_object_class_install_property (object_class,
				   PROP_IS_EXPANDER,
Matthias Clasen's avatar
x  
Matthias Clasen committed
375
				   g_param_spec_boolean ("is-expander",
376 377
							 P_("Is Expander"),
							 P_("Row has children"),
378
							 FALSE,
379
							 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
380 381 382 383


  g_object_class_install_property (object_class,
				   PROP_IS_EXPANDED,
Matthias Clasen's avatar
x  
Matthias Clasen committed
384
				   g_param_spec_boolean ("is-expanded",
385 386
							 P_("Is Expanded"),
							 P_("Row is an expander row, and is expanded"),
387
							 FALSE,
388
							 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
389 390 391

  g_object_class_install_property (object_class,
				   PROP_CELL_BACKGROUND,
Matthias Clasen's avatar
x  
Matthias Clasen committed
392
				   g_param_spec_string ("cell-background",
393 394
							P_("Cell background color name"),
							P_("Cell background color as a string"),
395
							NULL,
396
							GTK_PARAM_WRITABLE));
397

398 399 400 401 402 403 404
  /**
   * GtkCellRenderer:cell-background-gdk:
   *
   * Cell background as a #GdkColor
   *
   * Deprecated: 3.4: Use #GtkCellRenderer:cell-background-rgba instead.
   */
Matthias Clasen's avatar
Matthias Clasen committed
405
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
406 407
  g_object_class_install_property (object_class,
				   PROP_CELL_BACKGROUND_GDK,
Matthias Clasen's avatar
x  
Matthias Clasen committed
408
				   g_param_spec_boxed ("cell-background-gdk",
409 410
						       P_("Cell background color"),
						       P_("Cell background color as a GdkColor"),
411
						       GDK_TYPE_COLOR,
412
						       GTK_PARAM_READWRITE|G_PARAM_DEPRECATED));
Matthias Clasen's avatar
Matthias Clasen committed
413
G_GNUC_END_IGNORE_DEPRECATIONS
414 415 416 417 418 419 420 421 422 423 424 425 426 427
  /**
   * GtkCellRenderer:cell-background-rgba:
   *
   * Cell background as a #GdkRGBA
   *
   * Since: 3.0
   */
  g_object_class_install_property (object_class,
				   PROP_CELL_BACKGROUND_RGBA,
				   g_param_spec_boxed ("cell-background-rgba",
						       P_("Cell background RGBA color"),
						       P_("Cell background color as a GdkRGBA"),
						       GDK_TYPE_RGBA,
						       GTK_PARAM_READWRITE));
428

429 430 431 432 433 434
  g_object_class_install_property (object_class,
				   PROP_EDITING,
				   g_param_spec_boolean ("editing",
							 P_("Editing"),
							 P_("Whether the cell renderer is currently in editing mode"),
							 FALSE,
435
							 GTK_PARAM_READABLE));
436

437

438
#define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (object_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY))
439

Matthias Clasen's avatar
x  
Matthias Clasen committed
440
  ADD_SET_PROP ("cell-background-set", PROP_CELL_BACKGROUND_SET,
441
                P_("Cell background set"),
442
                P_("Whether the cell background color is set"));
443

444 445
  if (GtkCellRenderer_private_offset != 0)
    g_type_class_adjust_private_offset (class, &GtkCellRenderer_private_offset);
446

447
  gtk_cell_renderer_class_set_accessible_type (class, GTK_TYPE_RENDERER_CELL_ACCESSIBLE);
448 449
}

450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
static void
gtk_cell_renderer_base_class_init (gpointer g_class)
{
  GtkCellRendererClass *klass = g_class;

  klass->priv = G_TYPE_CLASS_GET_PRIVATE (g_class, GTK_TYPE_CELL_RENDERER, GtkCellRendererClassPrivate);
}

GType
gtk_cell_renderer_get_type (void)
{
  static GType cell_renderer_type = 0;

  if (G_UNLIKELY (cell_renderer_type == 0))
    {
      const GTypeInfo cell_renderer_info =
      {
	sizeof (GtkCellRendererClass),
	gtk_cell_renderer_base_class_init,
        NULL,
	(GClassInitFunc) gtk_cell_renderer_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_init */
	sizeof (GtkWidget),
	0,		/* n_preallocs */
	(GInstanceInitFunc) gtk_cell_renderer_init,
	NULL,		/* value_table */
      };
      cell_renderer_type = g_type_register_static (G_TYPE_INITIALLY_UNOWNED, "GtkCellRenderer",
                                                   &cell_renderer_info, G_TYPE_FLAG_ABSTRACT);

481 482
      GtkCellRenderer_private_offset =
        g_type_add_instance_private (cell_renderer_type, sizeof (GtkCellRendererPrivate));
483 484 485 486 487 488
      g_type_add_class_private (cell_renderer_type, sizeof (GtkCellRendererClassPrivate));
    }

  return cell_renderer_type;
}

489
static void
490 491 492
gtk_cell_renderer_get_property (GObject     *object,
				guint        param_id,
				GValue      *value,
Tim Janik's avatar
Tim Janik committed
493
				GParamSpec  *pspec)
494 495
{
  GtkCellRenderer *cell = GTK_CELL_RENDERER (object);
496
  GtkCellRendererPrivate *priv = cell->priv;
497 498 499

  switch (param_id)
    {
500
    case PROP_MODE:
501
      g_value_set_enum (value, priv->mode);
502
      break;
503
    case PROP_VISIBLE:
504
      g_value_set_boolean (value, priv->visible);
505
      break;
506
    case PROP_SENSITIVE:
507
      g_value_set_boolean (value, priv->sensitive);
508
      break;
509
    case PROP_EDITING:
510
      g_value_set_boolean (value, priv->editing);
511
      break;
512
    case PROP_XALIGN:
513
      g_value_set_float (value, priv->xalign);
514 515
      break;
    case PROP_YALIGN:
516
      g_value_set_float (value, priv->yalign);
517 518
      break;
    case PROP_XPAD:
519
      g_value_set_uint (value, priv->xpad);
520 521
      break;
    case PROP_YPAD:
522
      g_value_set_uint (value, priv->ypad);
523
      break;
524
    case PROP_WIDTH:
525
      g_value_set_int (value, priv->width);
526 527
      break;
    case PROP_HEIGHT:
528
      g_value_set_int (value, priv->height);
529
      break;
530
    case PROP_IS_EXPANDER:
531
      g_value_set_boolean (value, priv->is_expander);
532 533
      break;
    case PROP_IS_EXPANDED:
534
      g_value_set_boolean (value, priv->is_expanded);
535
      break;
536 537 538 539
    case PROP_CELL_BACKGROUND_GDK:
      {
	GdkColor color;

540 541 542
	color.red = (guint16) (priv->cell_background.red * 65535);
	color.green = (guint16) (priv->cell_background.green * 65535);
	color.blue = (guint16) (priv->cell_background.blue * 65535);
543 544 545 546

	g_value_set_boxed (value, &color);
      }
      break;
547 548 549
    case PROP_CELL_BACKGROUND_RGBA:
      g_value_set_boxed (value, &priv->cell_background);
      break;
550
    case PROP_CELL_BACKGROUND_SET:
551
      g_value_set_boolean (value, priv->cell_background_set);
552 553
      break;
    case PROP_CELL_BACKGROUND:
554
    default:
555
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
556 557 558 559 560 561
      break;
    }

}

static void
562 563 564
gtk_cell_renderer_set_property (GObject      *object,
				guint         param_id,
				const GValue *value,
Tim Janik's avatar
Tim Janik committed
565
				GParamSpec   *pspec)
566 567
{
  GtkCellRenderer *cell = GTK_CELL_RENDERER (object);
568
  GtkCellRendererPrivate *priv = cell->priv;
569 570 571

  switch (param_id)
    {
572
    case PROP_MODE:
573 574 575 576 577
      if (priv->mode != g_value_get_enum (value))
        {
          priv->mode = g_value_get_enum (value);
          g_object_notify_by_pspec (object, pspec);
        }
578
      break;
579
    case PROP_VISIBLE:
580 581 582 583 584
      if (priv->visible != g_value_get_boolean (value))
        {
          priv->visible = g_value_get_boolean (value);
          g_object_notify_by_pspec (object, pspec);
        }
585
      break;
586
    case PROP_SENSITIVE:
587 588 589 590 591
      if (priv->sensitive != g_value_get_boolean (value))
        {
          priv->sensitive = g_value_get_boolean (value);
          g_object_notify_by_pspec (object, pspec);
        }
592
      break;
593
    case PROP_XALIGN:
594 595 596 597 598
      if (priv->xalign != g_value_get_float (value))
        {
          priv->xalign = g_value_get_float (value);
          g_object_notify_by_pspec (object, pspec);
        }
599 600
      break;
    case PROP_YALIGN:
601 602 603 604 605
      if (priv->yalign != g_value_get_float (value))
        {
          priv->yalign = g_value_get_float (value);
          g_object_notify_by_pspec (object, pspec);
        }
606 607
      break;
    case PROP_XPAD:
608 609 610 611 612
      if (priv->xpad != g_value_get_uint (value))
        {
          priv->xpad = g_value_get_uint (value);
          g_object_notify_by_pspec (object, pspec);
        }
613 614
      break;
    case PROP_YPAD:
615 616 617 618 619
      if (priv->ypad != g_value_get_uint (value))
        {
          priv->ypad = g_value_get_uint (value);
          g_object_notify_by_pspec (object, pspec);
        }
620
      break;
621
    case PROP_WIDTH:
622 623 624 625 626
      if (priv->width != g_value_get_int (value))
        {
          priv->width = g_value_get_int (value);
          g_object_notify_by_pspec (object, pspec);
        }
627 628
      break;
    case PROP_HEIGHT:
629 630 631 632 633
      if (priv->height != g_value_get_int (value))
        {
          priv->height = g_value_get_int (value);
          g_object_notify_by_pspec (object, pspec);
        }
634
      break;
635
    case PROP_IS_EXPANDER:
636 637 638 639 640
      if (priv->is_expander != g_value_get_boolean (value))
        {
          priv->is_expander = g_value_get_boolean (value);
          g_object_notify_by_pspec (object, pspec);
        }
641 642
      break;
    case PROP_IS_EXPANDED:
643 644 645 646 647
      if (priv->is_expanded != g_value_get_boolean (value))
        {
          priv->is_expanded = g_value_get_boolean (value);
          g_object_notify_by_pspec (object, pspec);
        }
648
      break;
649 650
    case PROP_CELL_BACKGROUND:
      {
651
        GdkRGBA rgba;
652

653 654
        if (!g_value_get_string (value))
          set_cell_bg_color (cell, NULL);
655
        else if (gdk_rgba_parse (&rgba, g_value_get_string (value)))
656 657
          set_cell_bg_color (cell, &rgba);
        else
658
          g_warning ("Don't know color '%s'", g_value_get_string (value));
659

660
        g_object_notify (object, "cell-background");
661 662 663
      }
      break;
    case PROP_CELL_BACKGROUND_GDK:
664 665 666 667
      {
        GdkColor *color;

        color = g_value_get_boxed (value);
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
        if (color)
          {
            GdkRGBA rgba;

            rgba.red = color->red / 65535.;
            rgba.green = color->green / 65535.;
            rgba.blue = color->blue / 65535.;
            rgba.alpha = 1;

            set_cell_bg_color (cell, &rgba);
          }
        else
          {
            set_cell_bg_color (cell, NULL);
          }
683
        g_object_notify (object, "cell-background-gdk");
684 685 686
      }
      break;
    case PROP_CELL_BACKGROUND_RGBA:
687 688 689
      set_cell_bg_color (cell, g_value_get_boxed (value));
      break;
    case PROP_CELL_BACKGROUND_SET:
690 691 692 693 694
      if (priv->cell_background_set != g_value_get_boolean (value))
        {
          priv->cell_background_set = g_value_get_boolean (value);
          g_object_notify (object, "cell-background-set");
        }
695
      break;
696
    default:
697
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
698 699 700 701
      break;
    }
}

702 703
static void
set_cell_bg_color (GtkCellRenderer *cell,
704
                   GdkRGBA         *rgba)
705
{
706
  GtkCellRendererPrivate *priv = cell->priv;
707

708
  if (rgba)
709
    {
710
      if (!priv->cell_background_set)
711
        {
712 713 714
          priv->cell_background_set = TRUE;
          g_object_notify (G_OBJECT (cell), "cell-background-set");
        }
715

716
      priv->cell_background = *rgba;
717 718 719
    }
  else
    {
720
      if (priv->cell_background_set)
721
        {
722
	  priv->cell_background_set = FALSE;
723
	  g_object_notify (G_OBJECT (cell), "cell-background-set");
724 725
	}
    }
726
  g_object_notify (G_OBJECT (cell), "cell-background-rgba");
727 728
}

729 730 731 732
/**
 * gtk_cell_renderer_get_size:
 * @cell: a #GtkCellRenderer
 * @widget: the widget the renderer is rendering to
Johan Dahlin's avatar
Johan Dahlin committed
733
 * @cell_area: (allow-none): The area a cell will be allocated, or %NULL
734 735 736 737
 * @x_offset: (out) (allow-none): location to return x offset of cell relative to @cell_area, or %NULL
 * @y_offset: (out) (allow-none): location to return y offset of cell relative to @cell_area, or %NULL
 * @width: (out) (allow-none): location to return width needed to render a cell, or %NULL
 * @height: (out) (allow-none): location to return height needed to render a cell, or %NULL
738
 *
Matthias Clasen's avatar
Matthias Clasen committed
739 740 741 742 743 744 745
 * Obtains the width and height needed to render the cell. Used by view 
 * widgets to determine the appropriate size for the cell_area passed to
 * gtk_cell_renderer_render().  If @cell_area is not %NULL, fills in the
 * x and y offsets (if set) of the cell relative to this location. 
 *
 * Please note that the values set in @width and @height, as well as those 
 * in @x_offset and @y_offset are inclusive of the xpad and ypad properties.
746 747
 *
 *
748
 * Deprecated: 3.0: Use gtk_cell_renderer_get_preferred_size() instead.
749
 **/
750
void
751 752 753 754 755 756 757
gtk_cell_renderer_get_size (GtkCellRenderer    *cell,
			    GtkWidget          *widget,
			    const GdkRectangle *cell_area,
			    gint               *x_offset,
			    gint               *y_offset,
			    gint               *width,
			    gint               *height)
758
{
759
  GtkRequisition request;
760

761 762
  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));

763
  gtk_cell_renderer_get_preferred_size (cell, widget, &request, NULL);
764

765 766 767 768 769
  if (width)
    *width = request.width;
  
  if (height)
    *height = request.height;
770

771 772
  if (cell_area)
    _gtk_cell_renderer_calc_offset (cell, cell_area, gtk_widget_get_direction (widget),
773
                                    request.width, request.height, x_offset, y_offset);
774 775
}

776
/**
777
 * gtk_cell_renderer_render:
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794
 * @cell: a #GtkCellRenderer
 * @cr: a cairo context to draw to
 * @widget: the widget owning @window
 * @background_area: entire cell area (including tree expanders and maybe 
 *    padding on the sides)
 * @cell_area: area normally rendered by a cell renderer
 * @flags: flags that affect rendering
 *
 * Invokes the virtual render function of the #GtkCellRenderer. The three
 * passed-in rectangles are areas in @cr. Most renderers will draw within
 * @cell_area; the xalign, yalign, xpad, and ypad fields of the #GtkCellRenderer
 * should be honored with respect to @cell_area. @background_area includes the
 * blank space around the cell, and also the area containing the tree expander;
 * so the @background_area rectangles for all cells tile to cover the entire
 * @window.
 **/
void
795 796 797 798 799 800
gtk_cell_renderer_render (GtkCellRenderer      *cell,
                          cairo_t              *cr,
                          GtkWidget            *widget,
                          const GdkRectangle   *background_area,
                          const GdkRectangle   *cell_area,
                          GtkCellRendererState  flags)
801 802 803
{
  gboolean selected = FALSE;
  GtkCellRendererPrivate *priv = cell->priv;
804 805
  GtkStyleContext *context;
  GtkStateFlags state;
806 807 808 809 810 811 812 813 814

  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
  g_return_if_fail (GTK_CELL_RENDERER_GET_CLASS (cell)->render != NULL);
  g_return_if_fail (cr != NULL);

  selected = (flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED;

  cairo_save (cr);

815
  if (priv->cell_background_set && !selected)
816
    {
817
      gdk_cairo_rectangle (cr, background_area);
818
      gdk_cairo_set_source_rgba (cr, &priv->cell_background);
819
      cairo_fill (cr);
820 821
    }

822 823 824
  gdk_cairo_rectangle (cr, background_area);
  cairo_clip (cr);

825 826 827 828 829 830 831 832
  context = gtk_widget_get_style_context (widget);

  gtk_style_context_save (context);
  gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);

  state = gtk_cell_renderer_get_state (cell, widget, flags);
  gtk_style_context_set_state (context, state);

833
  GTK_CELL_RENDERER_GET_CLASS (cell)->render (cell,
834
                                              cr,
835
					      widget,
836 837
					      background_area,
					      cell_area,
838
					      flags);
839
  gtk_style_context_restore (context);
840
  cairo_restore (cr);
841 842
}

843
/**
844
 * gtk_cell_renderer_activate:
845 846 847
 * @cell: a #GtkCellRenderer
 * @event: a #GdkEvent
 * @widget: widget that received the event
Matthias Clasen's avatar
Matthias Clasen committed
848 849 850 851
 * @path: widget-dependent string representation of the event location; 
 *    e.g. for #GtkTreeView, a string representation of #GtkTreePath
 * @background_area: background area as passed to gtk_cell_renderer_render()
 * @cell_area: cell area as passed to gtk_cell_renderer_render()
852
 * @flags: render flags
853
 *
Matthias Clasen's avatar
Matthias Clasen committed
854 855 856
 * Passes an activate event to the cell renderer for possible processing.  
 * Some cell renderers may use events; for example, #GtkCellRendererToggle 
 * toggles when it gets a mouse click.
857
 *
858
 * Returns: %TRUE if the event was consumed/handled
859
 **/
860
gboolean
861 862 863
gtk_cell_renderer_activate (GtkCellRenderer      *cell,
			    GdkEvent             *event,
			    GtkWidget            *widget,
864
			    const gchar          *path,
865 866
			    const GdkRectangle   *background_area,
			    const GdkRectangle   *cell_area,
867
			    GtkCellRendererState  flags)
868
{
869
  GtkCellRendererPrivate *priv;
870

871
  g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), FALSE);
872

873 874 875
  priv = cell->priv;

  if (priv->mode != GTK_CELL_RENDERER_MODE_ACTIVATABLE)
876 877
    return FALSE;

878 879 880 881 882 883 884
  if (GTK_CELL_RENDERER_GET_CLASS (cell)->activate == NULL)
    return FALSE;

  return GTK_CELL_RENDERER_GET_CLASS (cell)->activate (cell,
						       event,
						       widget,
						       path,
885 886
						       (GdkRectangle *) background_area,
						       (GdkRectangle *) cell_area,
887 888 889 890 891 892
						       flags);
}

/**
 * gtk_cell_renderer_start_editing:
 * @cell: a #GtkCellRenderer
893
 * @event: (nullable): a #GdkEvent
894
 * @widget: widget that received the event
895
 * @path: widget-dependent string representation of the event location;
Matthias Clasen's avatar
Matthias Clasen committed
896 897 898
 *    e.g. for #GtkTreeView, a string representation of #GtkTreePath
 * @background_area: background area as passed to gtk_cell_renderer_render()
 * @cell_area: cell area as passed to gtk_cell_renderer_render()
899
 * @flags: render flags
900
 *
901 902
 * Starts editing the contents of this @cell, through a new #GtkCellEditable
 * widget created by the #GtkCellRendererClass.start_editing virtual function.
903
 *
904 905
 * Returns: (nullable) (transfer none): A new #GtkCellEditable for editing this
 *   @cell, or %NULL if editing is not possible
906 907 908 909 910
 **/
GtkCellEditable *
gtk_cell_renderer_start_editing (GtkCellRenderer      *cell,
				 GdkEvent             *event,
				 GtkWidget            *widget,
911
				 const gchar          *path,
912 913
				 const GdkRectangle   *background_area,
				 const GdkRectangle   *cell_area,
914 915 916
				 GtkCellRendererState  flags)

{
917
  GtkCellRendererPrivate *priv;
918 919
  GtkCellEditable *editable;

920 921
  g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), NULL);

922 923 924
  priv = cell->priv;

  if (priv->mode != GTK_CELL_RENDERER_MODE_EDITABLE)
925 926 927 928 929
    return NULL;

  if (GTK_CELL_RENDERER_GET_CLASS (cell)->start_editing == NULL)
    return NULL;

930 931 932 933
  editable = GTK_CELL_RENDERER_GET_CLASS (cell)->start_editing (cell,
								event,
								widget,
								path,
934 935
								(GdkRectangle *) background_area,
								(GdkRectangle *) cell_area,
936
								flags);
937 938 939
  if (editable == NULL)
    return NULL;

940 941
  gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (editable)),
                               GTK_STYLE_CLASS_CELL);
942 943 944 945 946

  g_signal_emit (cell, 
		 cell_renderer_signals[EDITING_STARTED], 0,
		 editable, path);

947
  priv->editing = TRUE;
948

949
  return editable;
950 951
}

952 953 954 955 956
/**
 * gtk_cell_renderer_set_fixed_size:
 * @cell: A #GtkCellRenderer
 * @width: the width of the cell renderer, or -1
 * @height: the height of the cell renderer, or -1
957
 *
958 959 960 961 962 963 964
 * Sets the renderer size to be explicit, independent of the properties set.
 **/
void
gtk_cell_renderer_set_fixed_size (GtkCellRenderer *cell,
				  gint             width,
				  gint             height)
{
965
  GtkCellRendererPrivate *priv;
966

967 968 969
  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
  g_return_if_fail (width >= -1 && height >= -1);

970 971 972
  priv = cell->priv;

  if ((width != priv->width) || (height != priv->height))
973
    {
Hans Breuer's avatar
Hans Breuer committed
974
      g_object_freeze_notify (G_OBJECT (cell));
975

976
      if (width != priv->width)
Hans Breuer's avatar
Hans Breuer committed
977
        {
978
          priv->width = width;
Hans Breuer's avatar
Hans Breuer committed
979 980 981
          g_object_notify (G_OBJECT (cell), "width");
        }

982
      if (height != priv->height)
Hans Breuer's avatar
Hans Breuer committed
983
        {
984
          priv->height = height;
Hans Breuer's avatar
Hans Breuer committed
985 986 987 988
          g_object_notify (G_OBJECT (cell), "height");
        }

      g_object_thaw_notify (G_OBJECT (cell));
989 990 991 992 993 994
    }
}

/**
 * gtk_cell_renderer_get_fixed_size:
 * @cell: A #GtkCellRenderer
995 996
 * @width: (out) (allow-none): location to fill in with the fixed width of the cell, or %NULL
 * @height: (out) (allow-none): location to fill in with the fixed height of the cell, or %NULL
997
 *
998 999 1000 1001 1002 1003 1004
 * Fills in @width and @height with the appropriate size of @cell.
 **/
void
gtk_cell_renderer_get_fixed_size (GtkCellRenderer *cell,
				  gint            *width,
				  gint            *height)
{
1005
  GtkCellRendererPrivate *priv;
1006

1007 1008
  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));

1009 1010
  priv = cell->priv;

1011
  if (width)
1012
    *width = priv->width;
1013
  if (height)
1014
    *height = priv->height;
1015 1016 1017 1018 1019 1020 1021 1022
}

/**
 * gtk_cell_renderer_set_alignment:
 * @cell: A #GtkCellRenderer
 * @xalign: the x alignment of the cell renderer
 * @yalign: the y alignment of the cell renderer
 *
1023
 * Sets the renderer’s alignment within its available space.
1024 1025 1026 1027 1028 1029 1030 1031
 *
 * Since: 2.18
 **/
void
gtk_cell_renderer_set_alignment (GtkCellRenderer *cell,
                                 gfloat           xalign,
                                 gfloat           yalign)
{
1032
  GtkCellRendererPrivate *priv;
1033

1034 1035 1036 1037
  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
  g_return_if_fail (xalign >= 0.0 && xalign <= 1.0);
  g_return_if_fail (yalign >= 0.0 && yalign <= 1.0);

1038 1039 1040
  priv = cell->priv;

  if ((xalign != priv->xalign) || (yalign != priv->yalign))
1041 1042 1043
    {
      g_object_freeze_notify (G_OBJECT (cell));

1044
      if (xalign != priv->xalign)
1045
        {
1046
          priv->xalign = xalign;
1047 1048 1049
          g_object_notify (G_OBJECT (cell), "xalign");
        }

1050
      if (yalign != priv->yalign)
1051
        {
1052
          priv->yalign = yalign;
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
          g_object_notify (G_OBJECT (cell), "yalign");
        }

      g_object_thaw_notify (G_OBJECT (cell));
    }
}

/**
 * gtk_cell_renderer_get_alignment:
 * @cell: A #GtkCellRenderer
1063 1064
 * @xalign: (out) (allow-none): location to fill in with the x alignment of the cell, or %NULL
 * @yalign: (out) (allow-none): location to fill in with the y alignment of the cell, or %NULL
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
 *
 * Fills in @xalign and @yalign with the appropriate values of @cell.
 *
 * Since: 2.18
 **/
void
gtk_cell_renderer_get_alignment (GtkCellRenderer *cell,
                                 gfloat          *xalign,
                                 gfloat          *yalign)
{
1075
  GtkCellRendererPrivate *priv;
1076

1077 1078
  g_return_if_fail (GTK_IS_CELL_RENDERER (cell));

1079 1080
  priv = cell->priv;

1081
  if (xalign)