mail-notification

Fork of Jean-Yves Lefort's mail-notification, a tray icon to notify of new mail
git clone https://code.djc.id.au/git/mail-notification/

src/nautilus-cell-renderer-pixbuf-emblem.c (17235B) - raw

      1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
      2  *
      3  * nautilus-cell-renderer-pixbuf-emblem.c: cell renderer which can render
      4  * an emblem on top of a pixbuf (for use in FMListView and FMTreeView)
      5  * Copyright (C) 2003 Juerg Billeter
      6  *
      7  * Mail Notification
      8  * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be>
      9  *
     10  * This program is free software; you can redistribute it and/or modify
     11  * it under the terms of the GNU General Public License as published by
     12  * the Free Software Foundation; either version 3 of the License, or
     13  * (at your option) any later version.
     14  *
     15  * This program is distributed in the hope that it will be useful,
     16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18  * GNU General Public License for more details.
     19  *
     20  * You should have received a copy of the GNU General Public License along
     21  * with this program; if not, write to the Free Software Foundation, Inc.,
     22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     23  */
     24 
     25 #include "nautilus-cell-renderer-pixbuf-emblem.h"
     26 
     27 static void nautilus_cell_renderer_pixbuf_emblem_get_property (GObject *object,
     28 							guint		param_id,
     29 							GValue		*value,
     30 							GParamSpec	*pspec);
     31 static void nautilus_cell_renderer_pixbuf_emblem_set_property (GObject *object,
     32 							guint		param_id,
     33 							const GValue	*value,
     34 							GParamSpec	*pspec);
     35 static void nautilus_cell_renderer_pixbuf_emblem_init       (NautilusCellRendererPixbufEmblem *cellpixbuf);
     36 static void nautilus_cell_renderer_pixbuf_emblem_class_init  (NautilusCellRendererPixbufEmblemClass *klass);
     37 static void nautilus_cell_renderer_pixbuf_emblem_finalize (GObject *object);
     38 static void nautilus_cell_renderer_pixbuf_emblem_create_stock_pixbuf (NautilusCellRendererPixbufEmblem *cellpixbuf,
     39                                                           GtkWidget             *widget);
     40 static void nautilus_cell_renderer_pixbuf_emblem_get_size   (GtkCellRenderer            *cell,
     41                                                  GtkWidget                  *widget,
     42                                                  GdkRectangle               *rectangle,
     43                                                  gint                       *x_offset,
     44                                                  gint                       *y_offset,
     45                                                  gint                       *width,
     46                                                  gint                       *height);
     47 static void     nautilus_cell_renderer_pixbuf_emblem_render     (GtkCellRenderer            *cell,
     48                                                           GdkWindow                  *window,
     49                                                           GtkWidget                  *widget,
     50                                                           GdkRectangle               *background_area,
     51                                                           GdkRectangle               *cell_area,
     52                                                           GdkRectangle               *expose_area,
     53                                                           GtkCellRendererState                       flags);
     54 
     55 enum {
     56 	PROP_ZERO,
     57 	PROP_PIXBUF,
     58 	PROP_PIXBUF_EXPANDER_OPEN,
     59 	PROP_PIXBUF_EXPANDER_CLOSED,
     60 	PROP_STOCK_ID,
     61 	PROP_STOCK_SIZE,
     62 	PROP_STOCK_DETAIL,
     63 	PROP_PIXBUF_EMBLEM
     64 };
     65 
     66 static gpointer parent_class;
     67 
     68 #define CELLINFO_KEY "nautilus-cell-renderer-pixbuf-emblem-info"
     69 
     70 typedef struct _NautilusCellRendererPixbufEmblemInfo NautilusCellRendererPixbufEmblemInfo;
     71 struct _NautilusCellRendererPixbufEmblemInfo
     72 {
     73 	gchar *stock_id;
     74 	GtkIconSize stock_size;
     75 	gchar *stock_detail;
     76 };
     77 
     78 GType
     79 nautilus_cell_renderer_pixbuf_emblem_get_type (void)
     80 {
     81 	static GType cell_pixbuf_type = 0;
     82 
     83 	if (!cell_pixbuf_type) {
     84 		static const GTypeInfo cell_pixbuf_info =
     85 		{
     86 			sizeof (NautilusCellRendererPixbufEmblemClass),
     87 			NULL,                                                     /* base_init */
     88 			NULL,                                                     /* base_finalize */
     89 			(GClassInitFunc) nautilus_cell_renderer_pixbuf_emblem_class_init,
     90 			NULL,                                                     /* class_finalize */
     91 			NULL,                                                     /* class_data */
     92 			sizeof (NautilusCellRendererPixbufEmblem),
     93 			0,                                                        /* n_preallocs */
     94 			(GInstanceInitFunc) nautilus_cell_renderer_pixbuf_emblem_init,
     95 		};
     96 
     97 		cell_pixbuf_type = g_type_register_static (GTK_TYPE_CELL_RENDERER,
     98 							   "NautilusCellRendererPixbufEmblem",
     99 							   &cell_pixbuf_info, 0);
    100 	}
    101 
    102 	return cell_pixbuf_type;
    103 }
    104 
    105 static void
    106 nautilus_cell_renderer_pixbuf_emblem_init (NautilusCellRendererPixbufEmblem *cellpixbuf)
    107 {
    108 	NautilusCellRendererPixbufEmblemInfo *cellinfo;
    109 
    110 	cellinfo = g_new0 (NautilusCellRendererPixbufEmblemInfo, 1);
    111 	cellinfo->stock_size = GTK_ICON_SIZE_MENU;
    112 	g_object_set_data (G_OBJECT (cellpixbuf), CELLINFO_KEY, cellinfo);
    113 }
    114 
    115 static void
    116 nautilus_cell_renderer_pixbuf_emblem_class_init (NautilusCellRendererPixbufEmblemClass *klass)
    117 {
    118 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
    119 	GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
    120 
    121 	parent_class = g_type_class_peek_parent (klass);
    122 
    123 	object_class->finalize = nautilus_cell_renderer_pixbuf_emblem_finalize;
    124 
    125 	object_class->get_property = nautilus_cell_renderer_pixbuf_emblem_get_property;
    126 	object_class->set_property = nautilus_cell_renderer_pixbuf_emblem_set_property;
    127 
    128 	cell_class->get_size = nautilus_cell_renderer_pixbuf_emblem_get_size;
    129 	cell_class->render = nautilus_cell_renderer_pixbuf_emblem_render;
    130 
    131 	g_object_class_install_property (object_class,
    132 				   PROP_PIXBUF,
    133 				   g_param_spec_object ("pixbuf",
    134 							"Pixbuf Object",
    135 							"The pixbuf to render",
    136 							GDK_TYPE_PIXBUF,
    137 							G_PARAM_READABLE |
    138 							G_PARAM_WRITABLE));
    139 
    140 	g_object_class_install_property (object_class,
    141 				   PROP_PIXBUF_EXPANDER_OPEN,
    142 				   g_param_spec_object ("pixbuf_expander_open",
    143 							"Pixbuf Expander Open",
    144 							"Pixbuf for open expander",
    145 							GDK_TYPE_PIXBUF,
    146 							G_PARAM_READABLE |
    147 							G_PARAM_WRITABLE));
    148 
    149 	g_object_class_install_property (object_class,
    150 				   PROP_PIXBUF_EXPANDER_CLOSED,
    151 				   g_param_spec_object ("pixbuf_expander_closed",
    152 							"Pixbuf Expander Closed",
    153 							"Pixbuf for closed expander",
    154 							GDK_TYPE_PIXBUF,
    155 							G_PARAM_READABLE |
    156 							G_PARAM_WRITABLE));
    157 
    158 	g_object_class_install_property (object_class,
    159 				   PROP_STOCK_ID,
    160 				   g_param_spec_string ("stock_id",
    161 							"Stock ID",
    162 							"The stock ID of the stock icon to render",
    163 							NULL,
    164 							G_PARAM_READWRITE));
    165 
    166 	g_object_class_install_property (object_class,
    167 				   PROP_STOCK_SIZE,
    168 				   g_param_spec_enum ("stock_size",
    169 						      "Size",
    170 						      "The size of the rendered icon",
    171 						      GTK_TYPE_ICON_SIZE,
    172 						      GTK_ICON_SIZE_MENU,
    173 						      G_PARAM_READWRITE));
    174 
    175 	g_object_class_install_property (object_class,
    176 				   PROP_STOCK_DETAIL,
    177 				   g_param_spec_string ("stock_detail",
    178 							"Detail",
    179 							"Render detail to pass to the theme engine",
    180 							NULL,
    181 							G_PARAM_READWRITE));
    182 
    183 	g_object_class_install_property (object_class,
    184 					 PROP_PIXBUF_EMBLEM,
    185 					 g_param_spec_object ("pixbuf_emblem",
    186 							      "Pixbuf Emblem Object",
    187 							      "The emblem to overlay",
    188 							      GDK_TYPE_PIXBUF,
    189 							      G_PARAM_READABLE |
    190 							      G_PARAM_WRITABLE));
    191 }
    192 
    193 static void
    194 nautilus_cell_renderer_pixbuf_emblem_finalize (GObject *object)
    195 {
    196 	NautilusCellRendererPixbufEmblem *cellpixbuf = NAUTILUS_CELL_RENDERER_PIXBUF_EMBLEM (object);
    197 	NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (object, CELLINFO_KEY);
    198 
    199 	if (cellpixbuf->pixbuf && cellinfo->stock_id) {
    200 		g_object_unref (cellpixbuf->pixbuf);
    201 	}
    202 
    203 	if (cellinfo->stock_id) {
    204 		g_free (cellinfo->stock_id);
    205 	}
    206 
    207 	if (cellinfo->stock_detail) {
    208 		g_free (cellinfo->stock_detail);
    209 	}
    210 
    211 	g_free (cellinfo);
    212 	g_object_set_data (object, CELLINFO_KEY, NULL);
    213 
    214 	(* G_OBJECT_CLASS (parent_class)->finalize) (object);
    215 }
    216 
    217 static void
    218 nautilus_cell_renderer_pixbuf_emblem_get_property (GObject        *object,
    219                                        guint           param_id,
    220                                        GValue         *value,
    221                                        GParamSpec     *pspec)
    222 {
    223 	NautilusCellRendererPixbufEmblem *cellpixbuf = NAUTILUS_CELL_RENDERER_PIXBUF_EMBLEM (object);
    224 	NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (object, CELLINFO_KEY);
    225 
    226 	switch (param_id)
    227 	{
    228 		case PROP_PIXBUF:
    229 			g_value_set_object (value,
    230 					    cellpixbuf->pixbuf ? G_OBJECT (cellpixbuf->pixbuf) : NULL);
    231 			break;
    232 		case PROP_PIXBUF_EXPANDER_OPEN:
    233 			g_value_set_object (value,
    234 					    cellpixbuf->pixbuf_expander_open ? G_OBJECT (cellpixbuf->pixbuf_expander_open) : NULL);
    235 			break;
    236 		case PROP_PIXBUF_EXPANDER_CLOSED:
    237 			g_value_set_object (value,
    238 					    cellpixbuf->pixbuf_expander_closed ? G_OBJECT (cellpixbuf->pixbuf_expander_closed) : NULL);
    239 			break;
    240 		case PROP_STOCK_ID:
    241 			g_value_set_string (value, cellinfo->stock_id);
    242 			break;
    243 		case PROP_STOCK_SIZE:
    244 			g_value_set_enum (value, cellinfo->stock_size);
    245 			break;
    246 		case PROP_STOCK_DETAIL:
    247 			g_value_set_string (value, cellinfo->stock_detail);
    248 			break;
    249 		case PROP_PIXBUF_EMBLEM:
    250 			g_value_set_object (value,
    251 					    cellpixbuf->pixbuf_emblem ? G_OBJECT (cellpixbuf->pixbuf_emblem) : NULL);
    252 			break;
    253 
    254 		default:
    255 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
    256 			break;
    257 	}
    258 }
    259 
    260 static void
    261 nautilus_cell_renderer_pixbuf_emblem_set_property (GObject      *object,
    262                                             guint         param_id,
    263                                             const GValue *value,
    264                                             GParamSpec   *pspec)
    265 {
    266 	GdkPixbuf *pixbuf;
    267 	NautilusCellRendererPixbufEmblem *cellpixbuf = NAUTILUS_CELL_RENDERER_PIXBUF_EMBLEM (object);
    268 	NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (object, CELLINFO_KEY);
    269 
    270 	switch (param_id)
    271 	{
    272 		case PROP_PIXBUF:
    273 			pixbuf = (GdkPixbuf*) g_value_get_object (value);
    274 			if (pixbuf) {
    275 				g_object_ref (pixbuf);
    276 			}
    277 			if (cellpixbuf->pixbuf) {
    278 				g_object_unref (cellpixbuf->pixbuf);
    279 			}
    280 			cellpixbuf->pixbuf = pixbuf;
    281 			break;
    282 		case PROP_PIXBUF_EXPANDER_OPEN:
    283 			pixbuf = (GdkPixbuf*) g_value_get_object (value);
    284 			if (pixbuf) {
    285 				g_object_ref (pixbuf);
    286 			}
    287 			if (cellpixbuf->pixbuf_expander_open) {
    288 				g_object_unref (cellpixbuf->pixbuf_expander_open);
    289 			}
    290 			cellpixbuf->pixbuf_expander_open = pixbuf;
    291 			break;
    292 		case PROP_PIXBUF_EXPANDER_CLOSED:
    293 			pixbuf = (GdkPixbuf*) g_value_get_object (value);
    294 			if (pixbuf) {
    295 				g_object_ref (pixbuf);
    296 			}
    297 			if (cellpixbuf->pixbuf_expander_closed) {
    298 				g_object_unref (cellpixbuf->pixbuf_expander_closed);
    299 			}
    300 			cellpixbuf->pixbuf_expander_closed = pixbuf;
    301 			break;
    302 		case PROP_STOCK_ID:
    303 			if (cellinfo->stock_id) {
    304 				g_free (cellinfo->stock_id);
    305 			}
    306 			cellinfo->stock_id = g_strdup (g_value_get_string (value));
    307 			break;
    308 		case PROP_STOCK_SIZE:
    309 			cellinfo->stock_size = g_value_get_enum (value);
    310 			break;
    311 		case PROP_STOCK_DETAIL:
    312 			if (cellinfo->stock_detail) {
    313 				g_free (cellinfo->stock_detail);
    314 			}
    315 			cellinfo->stock_detail = g_strdup (g_value_get_string (value));
    316 			break;
    317 		case PROP_PIXBUF_EMBLEM:
    318 			pixbuf = (GdkPixbuf *) g_value_get_object (value);
    319 			if (pixbuf) {
    320 				g_object_ref (pixbuf);
    321 			}
    322 			if (cellpixbuf->pixbuf_emblem) {
    323 				g_object_unref (cellpixbuf->pixbuf_emblem);
    324 			}
    325 			cellpixbuf->pixbuf_emblem = pixbuf;
    326 			break;
    327 
    328 		default:
    329 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
    330 			break;
    331 	}
    332 }
    333 
    334 GtkCellRenderer *
    335 nautilus_cell_renderer_pixbuf_emblem_new (void)
    336 {
    337 	return g_object_new (NAUTILUS_TYPE_CELL_RENDERER_PIXBUF_EMBLEM, NULL);
    338 }
    339 
    340 static void
    341 nautilus_cell_renderer_pixbuf_emblem_create_stock_pixbuf (NautilusCellRendererPixbufEmblem *cellpixbuf,
    342 					      GtkWidget             *widget)
    343 {
    344 	NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (G_OBJECT (cellpixbuf), CELLINFO_KEY);
    345 
    346 	if (cellpixbuf->pixbuf) {
    347 		g_object_unref (cellpixbuf->pixbuf);
    348 	}
    349 
    350 	cellpixbuf->pixbuf = gtk_widget_render_icon (widget,
    351 					       cellinfo->stock_id,
    352 					       cellinfo->stock_size,
    353 					       cellinfo->stock_detail);
    354 }
    355 
    356 static void
    357 nautilus_cell_renderer_pixbuf_emblem_get_size (GtkCellRenderer *cell,
    358 				   GtkWidget       *widget,
    359 				   GdkRectangle    *cell_area,
    360 				   gint            *x_offset,
    361 				   gint            *y_offset,
    362 				   gint            *width,
    363 				   gint            *height)
    364 {
    365 	NautilusCellRendererPixbufEmblem *cellpixbuf = (NautilusCellRendererPixbufEmblem *) cell;
    366 	NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (G_OBJECT (cell), CELLINFO_KEY);
    367 	gint pixbuf_width  = 0;
    368 	gint pixbuf_height = 0;
    369 	gint calc_width;
    370 	gint calc_height;
    371 
    372 	if (!cellpixbuf->pixbuf && cellinfo->stock_id)
    373 		nautilus_cell_renderer_pixbuf_emblem_create_stock_pixbuf (cellpixbuf, widget);
    374 
    375 	if (cellpixbuf->pixbuf) {
    376 		pixbuf_width  = gdk_pixbuf_get_width (cellpixbuf->pixbuf);
    377 		pixbuf_height = gdk_pixbuf_get_height (cellpixbuf->pixbuf);
    378 	}
    379 	if (cellpixbuf->pixbuf_expander_open) {
    380 		pixbuf_width  = MAX (pixbuf_width, gdk_pixbuf_get_width (cellpixbuf->pixbuf_expander_open));
    381 		pixbuf_height = MAX (pixbuf_height, gdk_pixbuf_get_height (cellpixbuf->pixbuf_expander_open));
    382 	}
    383 	if (cellpixbuf->pixbuf_expander_closed) {
    384 		pixbuf_width  = MAX (pixbuf_width, gdk_pixbuf_get_width (cellpixbuf->pixbuf_expander_closed));
    385 		pixbuf_height = MAX (pixbuf_height, gdk_pixbuf_get_height (cellpixbuf->pixbuf_expander_closed));
    386 	}
    387 
    388 	calc_width  = (gint) cell->xpad * 2 + pixbuf_width;
    389 	calc_height = (gint) cell->ypad * 2 + pixbuf_height;
    390 
    391 	if (x_offset) *x_offset = 0;
    392 	if (y_offset) *y_offset = 0;
    393 
    394 	if (cell_area && pixbuf_width > 0 && pixbuf_height > 0) {
    395 		if (x_offset) {
    396 			*x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
    397 				1.0 - cell->xalign : cell->xalign) *
    398 				(cell_area->width - calc_width - 2 * cell->xpad));
    399 			*x_offset = MAX (*x_offset, 0) + cell->xpad;
    400 		}
    401 		if (y_offset) {
    402 			*y_offset = (cell->yalign *
    403 				(cell_area->height - calc_height - 2 * cell->ypad));
    404 			*y_offset = MAX (*y_offset, 0) + cell->ypad;
    405 		}
    406 	}
    407 
    408 	if (width)
    409 		*width = calc_width;
    410 
    411 	if (height)
    412 		*height = calc_height;
    413 }
    414 
    415 static void
    416 nautilus_cell_renderer_pixbuf_emblem_render (GtkCellRenderer      *cell,
    417                                  GdkWindow            *window,
    418                                  GtkWidget            *widget,
    419                                  GdkRectangle         *background_area,
    420                                  GdkRectangle         *cell_area,
    421                                  GdkRectangle         *expose_area,
    422                                  GtkCellRendererState  flags)
    423 
    424 {
    425 	NautilusCellRendererPixbufEmblem *cellpixbuf = (NautilusCellRendererPixbufEmblem *) cell;
    426 	NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (G_OBJECT (cell), CELLINFO_KEY);
    427 	GdkPixbuf *pixbuf;
    428 	GdkRectangle pix_rect;
    429 	GdkRectangle pix_emblem_rect;
    430 	GdkRectangle draw_rect;
    431 	gboolean stock_pixbuf = FALSE;
    432 
    433 	pixbuf = cellpixbuf->pixbuf;
    434 	if (cell->is_expander) {
    435 		if (cell->is_expanded &&
    436 		    cellpixbuf->pixbuf_expander_open != NULL) {
    437 			pixbuf = cellpixbuf->pixbuf_expander_open;
    438 		} else if (!cell->is_expanded &&
    439 			   cellpixbuf->pixbuf_expander_closed != NULL) {
    440 			pixbuf = cellpixbuf->pixbuf_expander_closed;
    441 		}
    442 	}
    443 
    444 	if (!pixbuf && !cellinfo->stock_id) {
    445 		return;
    446 	} else if (!pixbuf && cellinfo->stock_id) {
    447 		stock_pixbuf = TRUE;
    448 	}
    449 
    450 	nautilus_cell_renderer_pixbuf_emblem_get_size (cell, widget, cell_area,
    451 				     &pix_rect.x,
    452 				     &pix_rect.y,
    453 				     &pix_rect.width,
    454 				     &pix_rect.height);
    455 
    456 	if (stock_pixbuf)
    457 		pixbuf = cellpixbuf->pixbuf;
    458 
    459 	pix_rect.x += cell_area->x;
    460 	pix_rect.y += cell_area->y;
    461 	pix_rect.width  -= cell->xpad * 2;
    462 	pix_rect.height -= cell->ypad * 2;
    463 
    464 	if (gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect) &&
    465 	    gdk_rectangle_intersect (expose_area, &draw_rect, &draw_rect)) {
    466 		gdk_draw_pixbuf (window,
    467 			widget->style->black_gc,
    468 			pixbuf,
    469 			/* pixbuf 0, 0 is at pix_rect.x, pix_rect.y */
    470 			draw_rect.x - pix_rect.x,
    471 			draw_rect.y - pix_rect.y,
    472 			draw_rect.x,
    473 			draw_rect.y,
    474 			draw_rect.width,
    475 			draw_rect.height,
    476 			GDK_RGB_DITHER_NORMAL,
    477 			0, 0);
    478 	}
    479 
    480 	if (cellpixbuf->pixbuf_emblem) {
    481 		pix_emblem_rect.width = gdk_pixbuf_get_width (cellpixbuf->pixbuf_emblem);
    482 		pix_emblem_rect.height = gdk_pixbuf_get_height (cellpixbuf->pixbuf_emblem);
    483 		pix_emblem_rect.x = pix_rect.x;
    484 		pix_emblem_rect.y = pix_rect.y + pix_rect.height - pix_emblem_rect.height;
    485 		if (gdk_rectangle_intersect (cell_area, &pix_emblem_rect, &draw_rect) &&
    486 		    gdk_rectangle_intersect (expose_area, &draw_rect, &draw_rect)) {
    487 			gdk_draw_pixbuf (window,
    488 				widget->style->black_gc,
    489 				cellpixbuf->pixbuf_emblem,
    490 				/* pixbuf 0, 0 is at pix_emblem_rect.x, pix_emblem_rect.y */
    491 				draw_rect.x - pix_emblem_rect.x,
    492 				draw_rect.y - pix_emblem_rect.y,
    493 				draw_rect.x,
    494 				draw_rect.y,
    495 				draw_rect.width,
    496 				draw_rect.height,
    497 				GDK_RGB_DITHER_NORMAL,
    498 				0, 0);
    499 		}
    500 	}
    501 }