nautilus-3.6.3/libnautilus-private/nautilus-canvas-item.c

No issues found

   1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
   2 
   3 /* Nautilus - Canvas item class for canvas container.
   4  *
   5  * Copyright (C) 2000 Eazel, Inc
   6  *
   7  * Author: Andy Hertzfeld <andy@eazel.com>
   8  *
   9  * This library is free software; you can redistribute it and/or
  10  * modify it under the terms of the GNU Library General Public
  11  * License as published by the Free Software Foundation; either
  12  * version 2 of the License, or (at your option) any later version.
  13  *
  14  * This library is distributed in the hope that it will be useful,
  15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17  * Library General Public License for more details.
  18  *
  19  * You should have received a copy of the GNU Library General Public
  20  * License along with this library; if not, write to the
  21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  22  * Boston, MA 02111-1307, USA.
  23  */
  24 
  25 #include <config.h>
  26 #include <math.h>
  27 #include "nautilus-canvas-item.h"
  28 
  29 #include <glib/gi18n.h>
  30 
  31 #include "nautilus-file-utilities.h"
  32 #include "nautilus-global-preferences.h"
  33 #include "nautilus-canvas-private.h"
  34 #include <eel/eel-art-extensions.h>
  35 #include <eel/eel-gdk-extensions.h>
  36 #include <eel/eel-glib-extensions.h>
  37 #include <eel/eel-graphic-effects.h>
  38 #include <eel/eel-string.h>
  39 #include <eel/eel-accessibility.h>
  40 #include <gdk-pixbuf/gdk-pixbuf.h>
  41 #include <gtk/gtk.h>
  42 #include <gdk/gdk.h>
  43 #include <glib/gi18n.h>
  44 #include <atk/atkimage.h>
  45 #include <atk/atkcomponent.h>
  46 #include <atk/atknoopobject.h>
  47 #include <stdio.h>
  48 #include <string.h>
  49 
  50 /* gap between bottom of icon and start of text box */
  51 #define LABEL_OFFSET 1
  52 #define LABEL_LINE_SPACING 0
  53 
  54 #define MAX_TEXT_WIDTH_STANDARD 135
  55 
  56 /* special text height handling
  57  * each item has three text height variables:
  58  *  + text_height: actual height of the displayed (i.e. on-screen) PangoLayout.
  59  *  + text_height_for_layout: height used in canvas grid layout algorithms.
  60  *       		      “sane amount” of text.
  61  *   “sane amount“ as of
  62  *      + hard-coded to three lines in text-below-icon mode.
  63  *
  64  *  This layout height is used by grid layout algorithms, even
  65  *  though the actually displayed and/or requested text size may be larger
  66  *  and overlap adjacent icons, if an icon is selected.
  67  *
  68  *  + text_height_for_entire_text: height needed to display the entire PangoLayout,
  69  *    if it wasn't ellipsized.
  70  */
  71 
  72 /* Private part of the NautilusCanvasItem structure. */
  73 struct NautilusCanvasItemDetails {
  74 	/* The image, text, font. */
  75 	double x, y;
  76 	GdkPixbuf *pixbuf;
  77 	GdkPixbuf *rendered_pixbuf;
  78 	char *editable_text;		/* Text that can be modified by a renaming function */
  79 	char *additional_text;		/* Text that cannot be modifed, such as file size, etc. */
  80 	GdkPoint *attach_points;
  81 	int n_attach_points;
  82 	
  83 	/* Size of the text at current font. */
  84 	int text_dx;
  85 	int text_width;
  86 
  87 	/* actual size required for rendering the text to display */
  88 	int text_height;
  89 	/* actual size that would be required for rendering the entire text if it wasn't ellipsized */
  90 	int text_height_for_entire_text;
  91 	/* actual size needed for rendering a “sane amount” of text */
  92 	int text_height_for_layout;
  93 
  94 	int editable_text_height;
  95 
  96 	/* whether the entire text must always be visible. In that case,
  97 	 * text_height_for_layout will always be equal to text_height.
  98 	 * Used for the last line of a line-wise icon layout. */
  99 	guint entire_text : 1;
 100 
 101     	/* Highlight state. */
 102    	guint is_highlighted_for_selection : 1;
 103 	guint is_highlighted_as_keyboard_focus: 1;
 104    	guint is_highlighted_for_drop : 1;
 105 	guint is_highlighted_for_clipboard : 1;
 106 	guint show_stretch_handles : 1;
 107 	guint is_prelit : 1;
 108 
 109 	guint rendered_is_highlighted_for_selection : 1;
 110 	guint rendered_is_highlighted_for_drop : 1;
 111 	guint rendered_is_highlighted_for_clipboard : 1;
 112 	guint rendered_is_prelit : 1;
 113 	guint rendered_is_focused : 1;
 114 	
 115 	guint is_renaming : 1;
 116 	
 117 	guint bounds_cached : 1;
 118 	
 119 	guint is_visible : 1;
 120 
 121 	GdkRectangle embedded_text_rect;
 122 	char *embedded_text;
 123 
 124 	/* Cached PangoLayouts. Only used if the icon is visible */
 125 	PangoLayout *editable_text_layout;
 126 	PangoLayout *additional_text_layout;
 127 	PangoLayout *embedded_text_layout;
 128 
 129 	/* Cached rectangle in canvas coordinates */
 130 	EelIRect icon_rect;
 131 	EelIRect text_rect;
 132 
 133 	EelIRect bounds_cache;
 134 	EelIRect bounds_cache_for_layout;
 135 	EelIRect bounds_cache_for_entire_item;
 136 
 137 	GdkWindow *cursor_window;
 138 
 139 	/* Accessibility bits */
 140 	GailTextUtil *text_util;
 141 };
 142 
 143 /* Object argument IDs. */
 144 enum {
 145 	PROP_0,
 146 	PROP_EDITABLE_TEXT,
 147 	PROP_ADDITIONAL_TEXT,
 148     	PROP_HIGHLIGHTED_FOR_SELECTION,
 149     	PROP_HIGHLIGHTED_AS_KEYBOARD_FOCUS,
 150     	PROP_HIGHLIGHTED_FOR_DROP,
 151 	PROP_HIGHLIGHTED_FOR_CLIPBOARD
 152 };
 153 
 154 typedef enum {
 155 	RIGHT_SIDE,
 156 	BOTTOM_SIDE,
 157 	LEFT_SIDE,
 158 	TOP_SIDE
 159 } RectangleSide;
 160 
 161 static void nautilus_canvas_item_text_interface_init (EelAccessibleTextIface *iface);
 162 static GType nautilus_canvas_item_accessible_factory_get_type (void);
 163 
 164 G_DEFINE_TYPE_WITH_CODE (NautilusCanvasItem, nautilus_canvas_item, EEL_TYPE_CANVAS_ITEM,
 165 			 G_IMPLEMENT_INTERFACE (EEL_TYPE_ACCESSIBLE_TEXT,
 166 						nautilus_canvas_item_text_interface_init));
 167 
 168 /* private */
 169 static void     draw_label_text                      (NautilusCanvasItem        *item,
 170 						      cairo_t                       *cr,
 171 						      EelIRect                       icon_rect);
 172 static void     measure_label_text                   (NautilusCanvasItem        *item);
 173 static void     get_icon_rectangle            (NautilusCanvasItem        *item,
 174 						 EelIRect                      *rect);
 175 static void     draw_pixbuf                          (GdkPixbuf                     *pixbuf,
 176 						      cairo_t                       *cr,
 177 						      int                            x,
 178 						      int                            y);
 179 static PangoLayout *get_label_layout                 (PangoLayout                  **layout,
 180 						      NautilusCanvasItem        *item,
 181 						      const char                    *text);
 182 static gboolean hit_test_stretch_handle              (NautilusCanvasItem        *item,
 183 						      EelIRect                       icon_rect,
 184 						      GtkCornerType *corner);
 185 static void      draw_embedded_text                  (NautilusCanvasItem        *canvas_item,
 186                                                       cairo_t                       *cr,
 187 						      int                            x,
 188 						      int                            y);
 189 
 190 static void       nautilus_canvas_item_ensure_bounds_up_to_date (NautilusCanvasItem *canvas_item);
 191 
 192 /* Object initialization function for the canvas item. */
 193 static void
 194 nautilus_canvas_item_init (NautilusCanvasItem *canvas_item)
 195 {
 196 	canvas_item->details = G_TYPE_INSTANCE_GET_PRIVATE ((canvas_item), NAUTILUS_TYPE_CANVAS_ITEM, NautilusCanvasItemDetails);
 197 	nautilus_canvas_item_invalidate_label_size (canvas_item);
 198 }
 199 
 200 static void
 201 nautilus_canvas_item_finalize (GObject *object)
 202 {
 203 	NautilusCanvasItemDetails *details;
 204 
 205 	g_assert (NAUTILUS_IS_CANVAS_ITEM (object));
 206 
 207 	details = NAUTILUS_CANVAS_ITEM (object)->details;
 208 
 209 	if (details->cursor_window != NULL) {
 210 		gdk_window_set_cursor (details->cursor_window, NULL);
 211 		g_object_unref (details->cursor_window);
 212 	}
 213 
 214 	if (details->pixbuf != NULL) {
 215 		g_object_unref (details->pixbuf);
 216 	}
 217 	
 218 	if (details->text_util != NULL) {
 219 		g_object_unref (details->text_util);
 220 	}
 221 
 222 	g_free (details->editable_text);
 223 	g_free (details->additional_text);
 224 	g_free (details->attach_points);
 225 	
 226 	if (details->rendered_pixbuf != NULL) {
 227 		g_object_unref (details->rendered_pixbuf);
 228 	}
 229 
 230 	if (details->editable_text_layout != NULL) {
 231 		g_object_unref (details->editable_text_layout);
 232 	}
 233 
 234 	if (details->additional_text_layout != NULL) {
 235 		g_object_unref (details->additional_text_layout);
 236 	}
 237 
 238 	if (details->embedded_text_layout != NULL) {
 239 		g_object_unref (details->embedded_text_layout);
 240 	}
 241 
 242 	g_free (details->embedded_text);
 243 
 244 	G_OBJECT_CLASS (nautilus_canvas_item_parent_class)->finalize (object);
 245 }
 246  
 247 /* Currently we require pixbufs in this format (for hit testing).
 248  * Perhaps gdk-pixbuf will be changed so it can do the hit testing
 249  * and we won't have this requirement any more.
 250  */
 251 static gboolean
 252 pixbuf_is_acceptable (GdkPixbuf *pixbuf)
 253 {
 254 	return gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB
 255 		&& ((!gdk_pixbuf_get_has_alpha (pixbuf)
 256 		     && gdk_pixbuf_get_n_channels (pixbuf) == 3)
 257 		    || (gdk_pixbuf_get_has_alpha (pixbuf)
 258 			&& gdk_pixbuf_get_n_channels (pixbuf) == 4))
 259 		&& gdk_pixbuf_get_bits_per_sample (pixbuf) == 8;
 260 }
 261 
 262 static void
 263 nautilus_canvas_item_invalidate_bounds_cache (NautilusCanvasItem *item)
 264 {
 265 	item->details->bounds_cached = FALSE;
 266 }
 267 
 268 /* invalidate the text width and height cached in the item details. */
 269 void
 270 nautilus_canvas_item_invalidate_label_size (NautilusCanvasItem *item)
 271 {
 272 	if (item->details->editable_text_layout != NULL) {
 273 		pango_layout_context_changed (item->details->editable_text_layout);
 274 	}
 275 	if (item->details->additional_text_layout != NULL) {
 276 		pango_layout_context_changed (item->details->additional_text_layout);
 277 	}
 278 	if (item->details->embedded_text_layout != NULL) {
 279 		pango_layout_context_changed (item->details->embedded_text_layout);
 280 	}
 281 	nautilus_canvas_item_invalidate_bounds_cache (item);
 282 	item->details->text_width = -1;
 283 	item->details->text_height = -1;
 284 	item->details->text_height_for_layout = -1;
 285 	item->details->text_height_for_entire_text = -1;
 286 	item->details->editable_text_height = -1;
 287 }
 288 
 289 /* Set property handler for the canvas item. */
 290 static void
 291 nautilus_canvas_item_set_property (GObject        *object,
 292 				   guint           property_id,
 293 				   const GValue   *value,
 294 				   GParamSpec     *pspec)
 295 {
 296 	NautilusCanvasItem *item;
 297 	NautilusCanvasItemDetails *details;
 298 	AtkObject *accessible;
 299 
 300 	item = NAUTILUS_CANVAS_ITEM (object);
 301 	accessible = atk_gobject_accessible_for_object (G_OBJECT (item));
 302 	details = item->details;
 303 
 304 	switch (property_id) {
 305 
 306 	case PROP_EDITABLE_TEXT:
 307 		if (g_strcmp0 (details->editable_text,
 308 			       g_value_get_string (value)) == 0) {
 309 			return;
 310 		}
 311 
 312 		g_free (details->editable_text);
 313 		details->editable_text = g_strdup (g_value_get_string (value));
 314 		if (details->text_util) {
 315 			gail_text_util_text_setup (details->text_util,
 316 						   details->editable_text);
 317 			g_object_notify (G_OBJECT(accessible), "accessible-name");
 318 		}
 319 		
 320 		nautilus_canvas_item_invalidate_label_size (item);
 321 		if (details->editable_text_layout) {
 322 			g_object_unref (details->editable_text_layout);
 323 			details->editable_text_layout = NULL;
 324 		}
 325 		break;
 326 
 327 	case PROP_ADDITIONAL_TEXT:
 328 		if (g_strcmp0 (details->additional_text,
 329 			       g_value_get_string (value)) == 0) {
 330 			return;
 331 		}
 332 
 333 		g_free (details->additional_text);
 334 		details->additional_text = g_strdup (g_value_get_string (value));
 335 		
 336 		nautilus_canvas_item_invalidate_label_size (item);		
 337 		if (details->additional_text_layout) {
 338 			g_object_unref (details->additional_text_layout);
 339 			details->additional_text_layout = NULL;
 340 		}
 341 		break;
 342 
 343 	case PROP_HIGHLIGHTED_FOR_SELECTION:
 344 		if (!details->is_highlighted_for_selection == !g_value_get_boolean (value)) {
 345 			return;
 346 		}
 347 		details->is_highlighted_for_selection = g_value_get_boolean (value);
 348 		nautilus_canvas_item_invalidate_label_size (item);
 349 
 350 		atk_object_notify_state_change (accessible, ATK_STATE_SELECTED,
 351 						details->is_highlighted_for_selection);
 352 
 353 		break;
 354          
 355         case PROP_HIGHLIGHTED_AS_KEYBOARD_FOCUS:
 356 		if (!details->is_highlighted_as_keyboard_focus == !g_value_get_boolean (value)) {
 357 			return;
 358 		}
 359 		details->is_highlighted_as_keyboard_focus = g_value_get_boolean (value);
 360 
 361 		if (details->is_highlighted_as_keyboard_focus) {
 362 			atk_focus_tracker_notify (accessible);
 363 		}
 364 		break;
 365 		
 366         case PROP_HIGHLIGHTED_FOR_DROP:
 367 		if (!details->is_highlighted_for_drop == !g_value_get_boolean (value)) {
 368 			return;
 369 		}
 370 		details->is_highlighted_for_drop = g_value_get_boolean (value);
 371 		break;
 372 
 373 	case PROP_HIGHLIGHTED_FOR_CLIPBOARD:
 374 		if (!details->is_highlighted_for_clipboard == !g_value_get_boolean (value)) {
 375 			return;
 376 		}
 377 		details->is_highlighted_for_clipboard = g_value_get_boolean (value);
 378 		break;
 379 
 380 	default:
 381 		g_warning ("nautilus_canvas_item_set_property on unknown argument");
 382 		return;
 383 	}
 384 	
 385 	eel_canvas_item_request_update (EEL_CANVAS_ITEM (object));
 386 }
 387 
 388 /* Get property handler for the canvas item */
 389 static void
 390 nautilus_canvas_item_get_property (GObject        *object,
 391 				   guint           property_id,
 392 				   GValue         *value,
 393 				   GParamSpec     *pspec)
 394 {
 395 	NautilusCanvasItemDetails *details;
 396 	
 397 	details = NAUTILUS_CANVAS_ITEM (object)->details;
 398 	
 399 	switch (property_id) {
 400 		
 401 	case PROP_EDITABLE_TEXT:
 402 		g_value_set_string (value, details->editable_text);
 403 		break;
 404 
 405 	case PROP_ADDITIONAL_TEXT:
 406 		g_value_set_string (value, details->additional_text);
 407 		break;
 408 		
 409         case PROP_HIGHLIGHTED_FOR_SELECTION:
 410 		g_value_set_boolean (value, details->is_highlighted_for_selection);
 411                 break;
 412 		
 413         case PROP_HIGHLIGHTED_AS_KEYBOARD_FOCUS:
 414 		g_value_set_boolean (value, details->is_highlighted_as_keyboard_focus);
 415                 break;
 416 		
 417         case PROP_HIGHLIGHTED_FOR_DROP:
 418 		g_value_set_boolean (value, details->is_highlighted_for_drop);
 419                 break;
 420 
 421 	case PROP_HIGHLIGHTED_FOR_CLIPBOARD:
 422 		g_value_set_boolean (value, details->is_highlighted_for_clipboard);
 423                 break;
 424 
 425         default:
 426 		g_warning ("invalid property %d", property_id);
 427 		break;
 428 	}
 429 }
 430 
 431 cairo_surface_t *
 432 nautilus_canvas_item_get_drag_surface (NautilusCanvasItem *item)
 433 {
 434 	cairo_surface_t *surface;
 435 	EelCanvas *canvas;
 436 	GdkScreen *screen;
 437 	int width, height;
 438 	int item_offset_x, item_offset_y;
 439 	EelIRect icon_rect;
 440 	double item_x, item_y;
 441 	cairo_t *cr;
 442 	GtkStyleContext *context;
 443 	
 444 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_ITEM (item), NULL);
 445 
 446 	canvas = EEL_CANVAS_ITEM (item)->canvas;
 447 	screen = gtk_widget_get_screen (GTK_WIDGET (canvas));
 448 	context = gtk_widget_get_style_context (GTK_WIDGET (canvas));
 449 
 450 	gtk_style_context_save (context);
 451 	gtk_style_context_add_class (context, "nautilus-canvas-item");
 452 
 453 	/* Assume we're updated so canvas item data is right */
 454 
 455 	/* Calculate the offset from the top-left corner of the
 456 	   new image to the item position (where the pixmap is placed) */
 457 	eel_canvas_world_to_window (canvas,
 458 				    item->details->x, item->details->y,
 459 				    &item_x, &item_y);
 460 
 461 	item_offset_x = item_x - EEL_CANVAS_ITEM (item)->x1;
 462 	item_offset_y = item_y - EEL_CANVAS_ITEM (item)->y1;
 463 
 464 	/* Calculate the width of the item */
 465 	width = EEL_CANVAS_ITEM (item)->x2 - EEL_CANVAS_ITEM (item)->x1;
 466 	height = EEL_CANVAS_ITEM (item)->y2 - EEL_CANVAS_ITEM (item)->y1;
 467 
 468         surface = gdk_window_create_similar_surface (gdk_screen_get_root_window (screen),
 469                                                      CAIRO_CONTENT_COLOR_ALPHA,
 470                                                      width, height);
 471 
 472 	cr = cairo_create (surface);
 473 
 474 	gtk_render_icon (context, cr, item->details->pixbuf,
 475 			   item_offset_x, item_offset_y);
 476 
 477 	icon_rect.x0 = item_offset_x;
 478 	icon_rect.y0 = item_offset_y;
 479 	icon_rect.x1 = item_offset_x + gdk_pixbuf_get_width (item->details->pixbuf);
 480 	icon_rect.y1 = item_offset_y + gdk_pixbuf_get_height (item->details->pixbuf);
 481 
 482 	draw_embedded_text (item, cr,
 483 			    item_offset_x, item_offset_y);
 484 	draw_label_text (item, cr, icon_rect);
 485 	cairo_destroy (cr);
 486 
 487 	gtk_style_context_restore (context);
 488 
 489 	return surface;
 490 }
 491 
 492 void
 493 nautilus_canvas_item_set_image (NautilusCanvasItem *item,
 494 				GdkPixbuf *image)
 495 {
 496 	NautilusCanvasItemDetails *details;	
 497 	
 498 	g_return_if_fail (NAUTILUS_IS_CANVAS_ITEM (item));
 499 	g_return_if_fail (image == NULL || pixbuf_is_acceptable (image));
 500 
 501 	details = item->details;	
 502 	if (details->pixbuf == image) {
 503 		return;
 504 	}
 505 
 506 	if (image != NULL) {
 507 		g_object_ref (image);
 508 	}
 509 	if (details->pixbuf != NULL) {
 510 		g_object_unref (details->pixbuf);
 511 	}
 512 	if (details->rendered_pixbuf != NULL) {
 513 		g_object_unref (details->rendered_pixbuf);
 514 		details->rendered_pixbuf = NULL;
 515 	}
 516 
 517 	details->pixbuf = image;
 518 			
 519 	nautilus_canvas_item_invalidate_bounds_cache (item);
 520 	eel_canvas_item_request_update (EEL_CANVAS_ITEM (item));	
 521 }
 522 
 523 void 
 524 nautilus_canvas_item_set_attach_points (NautilusCanvasItem *item,
 525 					GdkPoint *attach_points,
 526 					int n_attach_points)
 527 {
 528 	g_free (item->details->attach_points);
 529 	item->details->attach_points = NULL;
 530 	item->details->n_attach_points = 0;
 531 
 532 	if (attach_points != NULL && n_attach_points != 0) {
 533 		item->details->attach_points = g_memdup (attach_points, n_attach_points * sizeof (GdkPoint));
 534 		item->details->n_attach_points = n_attach_points;
 535 	}
 536 	
 537 	nautilus_canvas_item_invalidate_bounds_cache (item);
 538 }
 539 
 540 void
 541 nautilus_canvas_item_set_embedded_text_rect (NautilusCanvasItem       *item,
 542 					     const GdkRectangle           *text_rect)
 543 {
 544 	item->details->embedded_text_rect = *text_rect;
 545 
 546 	nautilus_canvas_item_invalidate_bounds_cache (item);
 547 	eel_canvas_item_request_update (EEL_CANVAS_ITEM (item));
 548 }
 549 
 550 void
 551 nautilus_canvas_item_set_embedded_text (NautilusCanvasItem       *item,
 552 					const char                   *text)
 553 {
 554 	g_free (item->details->embedded_text);
 555 	item->details->embedded_text = g_strdup (text);
 556 
 557 	if (item->details->embedded_text_layout != NULL) {
 558 		if (text != NULL) {
 559 			pango_layout_set_text (item->details->embedded_text_layout, text, -1);
 560 		} else {
 561 			pango_layout_set_text (item->details->embedded_text_layout, "", -1);
 562 		}
 563 	}
 564 
 565 	eel_canvas_item_request_update (EEL_CANVAS_ITEM (item));
 566 }
 567 
 568 
 569 /* Recomputes the bounding box of a canvas item.
 570  * This is a generic implementation that could be used for any canvas item
 571  * class, it has no assumptions about how the item is used.
 572  */
 573 static void
 574 recompute_bounding_box (NautilusCanvasItem *canvas_item,
 575 			double i2w_dx, double i2w_dy)
 576 {
 577 	/* The bounds stored in the item is the same as what get_bounds
 578 	 * returns, except it's in canvas coordinates instead of the item's
 579 	 * parent's coordinates.
 580 	 */
 581 
 582 	EelCanvasItem *item;
 583 	EelDRect bounds_rect;
 584 
 585 	item = EEL_CANVAS_ITEM (canvas_item);
 586 
 587 	eel_canvas_item_get_bounds (item,
 588 				    &bounds_rect.x0, &bounds_rect.y0,
 589 				    &bounds_rect.x1, &bounds_rect.y1);
 590 
 591 	bounds_rect.x0 += i2w_dx;
 592 	bounds_rect.y0 += i2w_dy;
 593 	bounds_rect.x1 += i2w_dx;
 594 	bounds_rect.y1 += i2w_dy;
 595 	eel_canvas_w2c_d (item->canvas,
 596 			  bounds_rect.x0, bounds_rect.y0,
 597 			  &item->x1, &item->y1);
 598 	eel_canvas_w2c_d (item->canvas,
 599 			  bounds_rect.x1, bounds_rect.y1,
 600 			  &item->x2, &item->y2);
 601 }
 602 
 603 static EelIRect
 604 compute_text_rectangle (const NautilusCanvasItem *item,
 605 			EelIRect icon_rectangle,
 606 			gboolean canvas_coords,
 607 			NautilusCanvasItemBoundsUsage usage)
 608 {
 609 	EelIRect text_rectangle;
 610 	double pixels_per_unit;
 611 	double text_width, text_height, text_height_for_layout, text_height_for_entire_text, real_text_height;
 612 
 613 	pixels_per_unit = EEL_CANVAS_ITEM (item)->canvas->pixels_per_unit;
 614 	if (canvas_coords) {
 615 		text_width = item->details->text_width;
 616 		text_height = item->details->text_height;
 617 		text_height_for_layout = item->details->text_height_for_layout;
 618 		text_height_for_entire_text = item->details->text_height_for_entire_text;
 619 	} else {
 620 		text_width = item->details->text_width / pixels_per_unit;
 621 		text_height = item->details->text_height / pixels_per_unit;
 622 		text_height_for_layout = item->details->text_height_for_layout / pixels_per_unit;
 623 		text_height_for_entire_text = item->details->text_height_for_entire_text / pixels_per_unit;
 624 	}
 625 
 626 	text_rectangle.x0 = (icon_rectangle.x0 + icon_rectangle.x1) / 2 - (int) text_width / 2;
 627 	text_rectangle.y0 = icon_rectangle.y1;
 628 	text_rectangle.x1 = text_rectangle.x0 + text_width;
 629 
 630 	if (usage == BOUNDS_USAGE_FOR_LAYOUT) {
 631 		real_text_height = text_height_for_layout;
 632 	} else if (usage == BOUNDS_USAGE_FOR_ENTIRE_ITEM) {
 633 		real_text_height = text_height_for_entire_text;
 634 	} else if (usage == BOUNDS_USAGE_FOR_DISPLAY) {
 635 		real_text_height = text_height;
 636 	} else {
 637 		g_assert_not_reached ();
 638 	}
 639 
 640 	text_rectangle.y1 = text_rectangle.y0 + real_text_height + LABEL_OFFSET / pixels_per_unit;
 641 
 642 	return text_rectangle;
 643 }
 644 
 645 static EelIRect
 646 get_current_canvas_bounds (EelCanvasItem *item)
 647 {
 648 	EelIRect bounds;
 649 
 650 	g_assert (EEL_IS_CANVAS_ITEM (item));
 651 
 652 	bounds.x0 = item->x1;
 653 	bounds.y0 = item->y1;
 654 	bounds.x1 = item->x2;
 655 	bounds.y1 = item->y2;
 656 
 657 	return bounds;
 658 }
 659 
 660 void
 661 nautilus_canvas_item_update_bounds (NautilusCanvasItem *item,
 662 				    double i2w_dx, double i2w_dy)
 663 {
 664 	EelIRect before, after;
 665 	EelCanvasItem *canvas_item;
 666 
 667 	canvas_item = EEL_CANVAS_ITEM (item);
 668 	
 669 	/* Compute new bounds. */
 670 	before = get_current_canvas_bounds (canvas_item);
 671 	recompute_bounding_box (item, i2w_dx, i2w_dy);
 672 	after = get_current_canvas_bounds (canvas_item);
 673 
 674 	/* If the bounds didn't change, we are done. */
 675 	if (eel_irect_equal (before, after)) {
 676 		return;
 677 	}
 678 	
 679 	/* Update canvas and text rect cache */
 680 	get_icon_rectangle (item, &item->details->icon_rect);
 681 	item->details->text_rect = compute_text_rectangle (item, item->details->icon_rect,
 682 							   TRUE, BOUNDS_USAGE_FOR_DISPLAY);
 683 
 684 	/* queue a redraw. */
 685 	eel_canvas_request_redraw (canvas_item->canvas,
 686 				   before.x0, before.y0,
 687 				   before.x1 + 1, before.y1 + 1);
 688 }
 689 
 690 /* Update handler for the canvas canvas item. */
 691 static void
 692 nautilus_canvas_item_update (EelCanvasItem *item,
 693 			     double i2w_dx, double i2w_dy,
 694 			     gint flags)
 695 {
 696 	nautilus_canvas_item_update_bounds (NAUTILUS_CANVAS_ITEM (item), i2w_dx, i2w_dy);
 697 
 698 	eel_canvas_item_request_redraw (EEL_CANVAS_ITEM (item));
 699 
 700 	EEL_CANVAS_ITEM_CLASS (nautilus_canvas_item_parent_class)->update (item, i2w_dx, i2w_dy, flags);
 701 }
 702 
 703 /* Rendering */
 704 static gboolean
 705 in_single_click_mode (void)
 706 {
 707 	int click_policy;
 708 
 709 	click_policy = g_settings_get_enum (nautilus_preferences,
 710 					    NAUTILUS_PREFERENCES_CLICK_POLICY);
 711 
 712 	return click_policy == NAUTILUS_CLICK_POLICY_SINGLE;
 713 }
 714 
 715 
 716 /* Keep these for a bit while we work on performance of draw_or_measure_label_text. */
 717 /*
 718   #define PERFORMANCE_TEST_DRAW_DISABLE
 719   #define PERFORMANCE_TEST_MEASURE_DISABLE
 720 */
 721 
 722 /* This gets the size of the layout from the position of the layout.
 723  * This means that if the layout is right aligned we get the full width
 724  * of the layout, not just the width of the text snippet on the right side
 725  */
 726 static void
 727 layout_get_full_size (PangoLayout *layout,
 728 		      int         *width,
 729 		      int         *height,
 730 		      int         *dx)
 731 {
 732 	PangoRectangle logical_rect;
 733 	int the_width, total_width;
 734 	
 735 	pango_layout_get_extents (layout, NULL, &logical_rect);
 736 	the_width = (logical_rect.width + PANGO_SCALE / 2) / PANGO_SCALE;
 737 	total_width = (logical_rect.x + logical_rect.width + PANGO_SCALE / 2) / PANGO_SCALE;
 738 
 739 	if (width != NULL) {
 740 		*width = the_width;
 741 	}
 742 
 743 	if (height != NULL) {
 744 		*height = (logical_rect.height + PANGO_SCALE / 2) / PANGO_SCALE;
 745 	}
 746 
 747 	if (dx != NULL) {
 748 		*dx = total_width - the_width;
 749 	}
 750 }
 751 
 752 static void
 753 layout_get_size_for_layout (PangoLayout *layout,
 754 			    int          max_layout_line_count,
 755 			    int          height_for_entire_text,
 756 			    int         *height_for_layout)
 757 {
 758 	PangoLayoutIter *iter;
 759 	PangoRectangle logical_rect;
 760 	int i;
 761 
 762 	/* only use the first max_layout_line_count lines for the gridded auto layout */
 763 	if (pango_layout_get_line_count (layout) <= max_layout_line_count) {
 764 		*height_for_layout = height_for_entire_text;
 765 	} else {
 766 		*height_for_layout = 0;
 767 		iter = pango_layout_get_iter (layout);
 768 		for (i = 0; i < max_layout_line_count; i++) {
 769 			pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
 770 			*height_for_layout += (logical_rect.height + PANGO_SCALE / 2) / PANGO_SCALE;
 771 
 772 			if (!pango_layout_iter_next_line (iter)) {
 773 				break;
 774 			}
 775 
 776 			*height_for_layout += pango_layout_get_spacing (layout);
 777 		}
 778 		pango_layout_iter_free (iter);
 779 	}
 780 }
 781 
 782 #define TEXT_BACK_PADDING_X 4
 783 #define TEXT_BACK_PADDING_Y 1
 784 
 785 static void
 786 prepare_pango_layout_width (NautilusCanvasItem *item,
 787 			    PangoLayout *layout)
 788 {
 789 	if (nautilus_canvas_item_get_max_text_width (item) < 0) {
 790 		pango_layout_set_width (layout, -1);
 791 	} else {
 792 		pango_layout_set_width (layout, floor (nautilus_canvas_item_get_max_text_width (item)) * PANGO_SCALE);
 793 		pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
 794 	}
 795 }
 796 
 797 static void
 798 prepare_pango_layout_for_measure_entire_text (NautilusCanvasItem *item,
 799 					      PangoLayout *layout)
 800 {
 801 	prepare_pango_layout_width (item, layout);
 802 	pango_layout_set_height (layout, G_MININT);
 803 }
 804 
 805 static void
 806 prepare_pango_layout_for_draw (NautilusCanvasItem *item,
 807 			       PangoLayout *layout)
 808 {
 809 	NautilusCanvasItemDetails *details;
 810 	NautilusCanvasContainer *container;
 811 	gboolean needs_highlight;
 812 
 813 	prepare_pango_layout_width (item, layout);
 814 
 815 	container = NAUTILUS_CANVAS_CONTAINER (EEL_CANVAS_ITEM (item)->canvas);
 816 	details = item->details;
 817 
 818 	needs_highlight = details->is_highlighted_for_selection || details->is_highlighted_for_drop;
 819 
 820 	if (needs_highlight ||
 821 	    details->is_prelit ||
 822 	    details->is_highlighted_as_keyboard_focus ||
 823 	    details->entire_text) {
 824 		/* VOODOO-TODO, cf. compute_text_rectangle() */
 825 		pango_layout_set_height (layout, G_MININT);
 826 	} else {
 827 		/* TODO? we might save some resources, when the re-layout is not neccessary in case
 828 		 * the layout height already fits into max. layout lines. But pango should figure this
 829 		 * out itself (which it doesn't ATM).
 830 		 */
 831 		pango_layout_set_height (layout,
 832 					 nautilus_canvas_container_get_max_layout_lines_for_pango (container));
 833 	}
 834 }
 835 
 836 static void
 837 measure_label_text (NautilusCanvasItem *item)
 838 {
 839 	NautilusCanvasItemDetails *details;
 840 	NautilusCanvasContainer *container;
 841 	gint editable_height, editable_height_for_layout, editable_height_for_entire_text, editable_width, editable_dx;
 842 	gint additional_height, additional_width, additional_dx;
 843 	PangoLayout *editable_layout;
 844 	PangoLayout *additional_layout;
 845 	gboolean have_editable, have_additional;
 846 
 847 	/* check to see if the cached values are still valid; if so, there's
 848 	 * no work necessary
 849 	 */
 850 	
 851 	if (item->details->text_width >= 0 && item->details->text_height >= 0) {
 852 		return;
 853 	}
 854 
 855 	details = item->details;
 856 
 857 	have_editable = details->editable_text != NULL && details->editable_text[0] != '\0';
 858 	have_additional = details->additional_text != NULL && details->additional_text[0] != '\0';
 859 
 860 	/* No font or no text, then do no work. */
 861 	if (!have_editable && !have_additional) {
 862 		details->text_height = 0;
 863 		details->text_height_for_layout = 0;
 864 		details->text_height_for_entire_text = 0;
 865 		details->text_width = 0;			
 866 		return;
 867 	}
 868 
 869 #ifdef PERFORMANCE_TEST_MEASURE_DISABLE
 870 	/* fake out the width */
 871 	details->text_width = 80;
 872 	details->text_height = 20;
 873 	details->text_height_for_layout = 20;
 874 	details->text_height_for_entire_text = 20;
 875 	return;
 876 #endif
 877 
 878 	editable_width = 0;
 879 	editable_height = 0;
 880 	editable_height_for_layout = 0;
 881 	editable_height_for_entire_text = 0;
 882 	editable_dx = 0;
 883 	additional_width = 0;
 884 	additional_height = 0;
 885 	additional_dx = 0;
 886 
 887 	container = NAUTILUS_CANVAS_CONTAINER (EEL_CANVAS_ITEM (item)->canvas);	
 888 	editable_layout = NULL;
 889 	additional_layout = NULL;
 890 
 891 	if (have_editable) {
 892 		/* first, measure required text height: editable_height_for_entire_text
 893 		 * then, measure text height applicable for layout: editable_height_for_layout
 894 		 * next, measure actually displayed height: editable_height
 895 		 */
 896 		editable_layout = get_label_layout (&details->editable_text_layout, item, details->editable_text);
 897 
 898 		prepare_pango_layout_for_measure_entire_text (item, editable_layout);
 899 		layout_get_full_size (editable_layout,
 900 				      NULL,
 901 				      &editable_height_for_entire_text,
 902 				      NULL);
 903 		layout_get_size_for_layout (editable_layout,
 904 					    nautilus_canvas_container_get_max_layout_lines (container),
 905 					    editable_height_for_entire_text,
 906 					    &editable_height_for_layout);
 907 
 908 		prepare_pango_layout_for_draw (item, editable_layout);
 909 		layout_get_full_size (editable_layout,
 910 				      &editable_width,
 911 				      &editable_height,
 912 				      &editable_dx);
 913 	}
 914 
 915 	if (have_additional) {
 916 		additional_layout = get_label_layout (&details->additional_text_layout, item, details->additional_text);
 917 		prepare_pango_layout_for_draw (item, additional_layout);
 918 		layout_get_full_size (additional_layout,
 919 				      &additional_width, &additional_height, &additional_dx);
 920 	}
 921 
 922 	details->editable_text_height = editable_height;
 923 
 924 	if (editable_width > additional_width) {
 925 		details->text_width = editable_width;
 926 		details->text_dx = editable_dx;
 927 	} else {
 928 		details->text_width = additional_width;
 929 		details->text_dx = additional_dx;
 930 	}
 931 
 932 	if (have_additional) {
 933 		details->text_height = editable_height + LABEL_LINE_SPACING + additional_height;
 934 		details->text_height_for_layout = editable_height_for_layout + LABEL_LINE_SPACING + additional_height;
 935 		details->text_height_for_entire_text = editable_height_for_entire_text + LABEL_LINE_SPACING + additional_height;
 936 	} else {
 937 		details->text_height = editable_height;
 938 		details->text_height_for_layout = editable_height_for_layout;
 939 		details->text_height_for_entire_text = editable_height_for_entire_text;
 940 	}
 941 
 942 	/* add some extra space for highlighting even when we don't highlight so things won't move */
 943 	
 944 	/* extra slop for nicer highlighting */
 945 	details->text_height += TEXT_BACK_PADDING_Y*2;
 946 	details->text_height_for_layout += TEXT_BACK_PADDING_Y*2;
 947 	details->text_height_for_entire_text += TEXT_BACK_PADDING_Y*2;
 948 	details->editable_text_height += TEXT_BACK_PADDING_Y*2;
 949 
 950 	/* extra to make it look nicer */
 951 	details->text_width += TEXT_BACK_PADDING_X*2;
 952 
 953 	if (editable_layout) {
 954 		g_object_unref (editable_layout);
 955 	}
 956 
 957 	if (additional_layout) {
 958 		g_object_unref (additional_layout);
 959 	}
 960 }
 961 
 962 static void
 963 draw_label_text (NautilusCanvasItem *item,
 964                  cairo_t *cr,
 965 		 EelIRect icon_rect)
 966 {
 967 	NautilusCanvasItemDetails *details;
 968 	NautilusCanvasContainer *container;
 969 	PangoLayout *editable_layout;
 970 	PangoLayout *additional_layout;
 971 	GtkStyleContext *context;
 972 	GtkStateFlags state, base_state;
 973 	gboolean have_editable, have_additional;
 974 	gboolean needs_highlight, prelight_label;
 975 	EelIRect text_rect;
 976 	int x;
 977 	int max_text_width;
 978 	gdouble frame_w, frame_h, frame_x, frame_y;
 979 	gboolean draw_frame = TRUE;
 980 
 981 #ifdef PERFORMANCE_TEST_DRAW_DISABLE
 982 	return;
 983 #endif
 984 
 985 	details = item->details;
 986 
 987 	measure_label_text (item);
 988 	if (details->text_height == 0 ||
 989 	    details->text_width == 0) {
 990 		return;
 991 	}
 992 
 993 	container = NAUTILUS_CANVAS_CONTAINER (EEL_CANVAS_ITEM (item)->canvas);
 994 	context = gtk_widget_get_style_context (GTK_WIDGET (container));
 995 
 996 	text_rect = compute_text_rectangle (item, icon_rect, TRUE, BOUNDS_USAGE_FOR_DISPLAY);
 997 
 998 	needs_highlight = details->is_highlighted_for_selection || details->is_highlighted_for_drop;
 999 
1000 	editable_layout = NULL;
1001 	additional_layout = NULL;
1002 
1003 	have_editable = details->editable_text != NULL && details->editable_text[0] != '\0';
1004 	have_additional = details->additional_text != NULL && details->additional_text[0] != '\0';
1005 	g_assert (have_editable || have_additional);
1006 
1007 	max_text_width = floor (nautilus_canvas_item_get_max_text_width (item));
1008 
1009 	base_state = gtk_widget_get_state_flags (GTK_WIDGET (container));
1010 	base_state &= ~(GTK_STATE_FLAG_SELECTED | 
1011 			GTK_STATE_FLAG_PRELIGHT);
1012 	state = base_state;
1013 
1014 	gtk_widget_style_get (GTK_WIDGET (container),
1015 			      "activate_prelight_icon_label", &prelight_label,
1016 			      NULL);
1017 
1018 	/* if the canvas is highlighted, do some set-up */
1019 	if (needs_highlight &&
1020 	    !details->is_renaming) {
1021 		state |= GTK_STATE_FLAG_SELECTED;
1022 
1023 		frame_x = text_rect.x0;
1024 		frame_y = text_rect.y0;
1025 		frame_w = text_rect.x1 - text_rect.x0;
1026 		frame_h = text_rect.y1 - text_rect.y0;
1027 	} else if (!needs_highlight && have_editable &&
1028 		   details->text_width > 0 && details->text_height > 0 &&
1029 		   prelight_label && item->details->is_prelit) {
1030 		state |= GTK_STATE_FLAG_PRELIGHT;
1031 
1032 		frame_x = text_rect.x0;
1033 		frame_y = text_rect.y0;
1034 		frame_w = text_rect.x1 - text_rect.x0;
1035 		frame_h = text_rect.y1 - text_rect.y0;
1036 	} else {
1037 		draw_frame = FALSE;
1038 	}
1039 
1040 	if (draw_frame) {
1041 		gtk_style_context_save (context);
1042 		gtk_style_context_set_state (context, state);
1043 
1044 		gtk_render_frame (context, cr,
1045 				  frame_x, frame_y,
1046 				  frame_w, frame_h);
1047 		gtk_render_background (context, cr,
1048 				       frame_x, frame_y,
1049 				       frame_w, frame_h);
1050 
1051 		gtk_style_context_restore (context);
1052 	}
1053 
1054 	x = text_rect.x0 + ((text_rect.x1 - text_rect.x0) - max_text_width) / 2;
1055 
1056 	if (have_editable &&
1057 	    !details->is_renaming) {
1058 		state = base_state;
1059 
1060 		if (prelight_label && item->details->is_prelit) {
1061 			state |= GTK_STATE_FLAG_PRELIGHT;
1062 		}
1063 
1064 		if (needs_highlight) {
1065 			state |= GTK_STATE_FLAG_SELECTED;
1066 		}
1067 
1068 		editable_layout = get_label_layout (&item->details->editable_text_layout, item, item->details->editable_text);
1069 		prepare_pango_layout_for_draw (item, editable_layout);
1070 
1071 		gtk_style_context_save (context);
1072 		gtk_style_context_set_state (context, state);
1073 
1074 		gtk_render_layout (context, cr,
1075 				   x, text_rect.y0 + TEXT_BACK_PADDING_Y,
1076 				   editable_layout);
1077 
1078 		gtk_style_context_restore (context);
1079 	}
1080 
1081 	if (have_additional &&
1082 	    !details->is_renaming) {
1083 		state = base_state;
1084 
1085 		if (needs_highlight) {
1086 			state |= GTK_STATE_FLAG_SELECTED;
1087 		}
1088 
1089 		additional_layout = get_label_layout (&item->details->additional_text_layout, item, item->details->additional_text);
1090 		prepare_pango_layout_for_draw (item, additional_layout);
1091 
1092 		gtk_style_context_save (context);
1093 		gtk_style_context_set_state (context, state);
1094 		gtk_style_context_add_class (context, "dim-label");
1095 
1096 		gtk_render_layout (context, cr,
1097 				   x, text_rect.y0 + details->editable_text_height + LABEL_LINE_SPACING + TEXT_BACK_PADDING_Y,
1098 				   additional_layout);
1099 	}
1100 
1101 	if (item->details->is_highlighted_as_keyboard_focus) {
1102 		if (needs_highlight) {
1103 			state = GTK_STATE_FLAG_SELECTED;
1104 		}
1105 
1106 		gtk_style_context_save (context);
1107 		gtk_style_context_set_state (context, state);
1108 					     
1109 		gtk_render_focus (context,
1110 				  cr,
1111 				  text_rect.x0,
1112 				  text_rect.y0,
1113 				  text_rect.x1 - text_rect.x0,
1114 				  text_rect.y1 - text_rect.y0);
1115 
1116 		gtk_style_context_restore (context);
1117 	}
1118 
1119 	if (editable_layout != NULL) {
1120 		g_object_unref (editable_layout);
1121 	}
1122 	
1123 	if (additional_layout != NULL) {
1124 		g_object_unref (additional_layout);
1125 	}
1126 }
1127 
1128 void
1129 nautilus_canvas_item_set_is_visible (NautilusCanvasItem       *item,
1130 				     gboolean                      visible)
1131 {
1132 	if (item->details->is_visible == visible)
1133 		return;
1134 	
1135 	item->details->is_visible = visible;
1136 
1137 	if (!visible) {
1138 		nautilus_canvas_item_invalidate_label (item);
1139 	}
1140 }
1141 
1142 void
1143 nautilus_canvas_item_invalidate_label (NautilusCanvasItem     *item)
1144 {
1145 	nautilus_canvas_item_invalidate_label_size (item);
1146 
1147 	if (item->details->editable_text_layout) {
1148 		g_object_unref (item->details->editable_text_layout);
1149 		item->details->editable_text_layout = NULL;
1150 	}
1151 
1152 	if (item->details->additional_text_layout) {
1153 		g_object_unref (item->details->additional_text_layout);
1154 		item->details->additional_text_layout = NULL;
1155 	}
1156 
1157 	if (item->details->embedded_text_layout) {
1158 		g_object_unref (item->details->embedded_text_layout);
1159 		item->details->embedded_text_layout = NULL;
1160 	}
1161 }
1162 
1163 
1164 static GdkPixbuf *
1165 get_knob_pixbuf (void)
1166 {
1167 	GdkPixbuf *knob_pixbuf;
1168 
1169 	knob_pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
1170 						    "stock-nautilus-knob",
1171 						    8, 0, NULL);
1172 	if (!knob_pixbuf) {
1173 		GInputStream *stream = g_resources_open_stream ("/org/gnome/nautilus/icons/knob.png", 0, NULL);
1174 		if (stream != NULL) {
1175 			knob_pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, NULL);
1176 			g_object_unref (stream);
1177 		}
1178 	}
1179 
1180 	return knob_pixbuf;
1181 }
1182 
1183 static void
1184 draw_stretch_handles (NautilusCanvasItem *item,
1185                       cairo_t *cr,
1186 		      const EelIRect *rect)
1187 {
1188 	GtkWidget *widget;
1189 	GdkPixbuf *knob_pixbuf;
1190 	int knob_width, knob_height;
1191 	double dash = { 2.0 };
1192 	GtkStyleContext *style;
1193 	GdkRGBA color;
1194 
1195 	if (!item->details->show_stretch_handles) {
1196 		return;
1197 	}
1198 
1199 	widget = GTK_WIDGET (EEL_CANVAS_ITEM (item)->canvas);
1200 	style = gtk_widget_get_style_context (widget);
1201 
1202         cairo_save (cr);
1203 	knob_pixbuf = get_knob_pixbuf ();
1204 	knob_width = gdk_pixbuf_get_width (knob_pixbuf);
1205 	knob_height = gdk_pixbuf_get_height (knob_pixbuf);
1206 
1207 	/* first draw the box */
1208 	gtk_style_context_get_color (style, GTK_STATE_FLAG_SELECTED, &color);
1209 	gdk_cairo_set_source_rgba (cr, &color);
1210 	cairo_set_dash (cr, &dash, 1, 0);
1211 	cairo_set_line_width (cr, 1.0);
1212 	cairo_rectangle (cr,
1213 			 rect->x0 + 0.5,
1214 			 rect->y0 + 0.5,
1215 			 rect->x1 - rect->x0 - 1,
1216 			 rect->y1 - rect->y0 - 1);
1217 	cairo_stroke (cr);
1218 
1219         cairo_restore (cr);
1220 
1221 	/* draw the stretch handles themselves */
1222 	draw_pixbuf (knob_pixbuf, cr, rect->x0, rect->y0);
1223 	draw_pixbuf (knob_pixbuf, cr, rect->x0, rect->y1 - knob_height);
1224 	draw_pixbuf (knob_pixbuf, cr, rect->x1 - knob_width, rect->y0);
1225 	draw_pixbuf (knob_pixbuf, cr, rect->x1 - knob_width, rect->y1 - knob_height);
1226 
1227 	g_object_unref (knob_pixbuf);
1228 }
1229 
1230 static void
1231 draw_pixbuf (GdkPixbuf *pixbuf,
1232              cairo_t *cr,
1233              int x, int y)
1234 {
1235         cairo_save (cr);
1236 	gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y);
1237 	cairo_paint (cr);
1238         cairo_restore (cr);
1239 }
1240 
1241 /* shared code to highlight or dim the passed-in pixbuf */
1242 static GdkPixbuf *
1243 real_map_pixbuf (NautilusCanvasItem *canvas_item)
1244 {
1245 	EelCanvas *canvas;
1246 	GdkPixbuf *temp_pixbuf, *old_pixbuf;
1247 	GtkStyleContext *style;
1248 	GdkRGBA color;
1249 	
1250 	temp_pixbuf = canvas_item->details->pixbuf;
1251 	canvas = EEL_CANVAS_ITEM(canvas_item)->canvas;
1252 
1253 	g_object_ref (temp_pixbuf);
1254 
1255 	if (canvas_item->details->is_prelit ||
1256 	    canvas_item->details->is_highlighted_for_clipboard) {
1257 		old_pixbuf = temp_pixbuf;
1258 
1259 		temp_pixbuf = eel_create_spotlight_pixbuf (temp_pixbuf);
1260 		g_object_unref (old_pixbuf);
1261 	}
1262 
1263 	if (canvas_item->details->is_highlighted_for_selection
1264 	    || canvas_item->details->is_highlighted_for_drop) {
1265 		style = gtk_widget_get_style_context (GTK_WIDGET (canvas));
1266 
1267 		if (gtk_widget_has_focus (GTK_WIDGET (canvas))) {
1268 			gtk_style_context_get_background_color (style, GTK_STATE_FLAG_SELECTED, &color);
1269 		} else {
1270 			gtk_style_context_get_background_color (style, GTK_STATE_FLAG_ACTIVE, &color);	
1271 		}
1272 
1273 		old_pixbuf = temp_pixbuf;
1274 		temp_pixbuf = eel_create_colorized_pixbuf (temp_pixbuf, &color);
1275 
1276 		g_object_unref (old_pixbuf);
1277 	}
1278 	
1279 	return temp_pixbuf;
1280 }
1281 
1282 static GdkPixbuf *
1283 map_pixbuf (NautilusCanvasItem *canvas_item)
1284 {
1285 	if (!(canvas_item->details->rendered_pixbuf != NULL
1286 	      && canvas_item->details->rendered_is_prelit == canvas_item->details->is_prelit
1287 	      && canvas_item->details->rendered_is_highlighted_for_selection == canvas_item->details->is_highlighted_for_selection
1288 	      && canvas_item->details->rendered_is_highlighted_for_drop == canvas_item->details->is_highlighted_for_drop
1289 	      && canvas_item->details->rendered_is_highlighted_for_clipboard == canvas_item->details->is_highlighted_for_clipboard
1290 	      && (canvas_item->details->is_highlighted_for_selection && canvas_item->details->rendered_is_focused == gtk_widget_has_focus (GTK_WIDGET (EEL_CANVAS_ITEM (canvas_item)->canvas))))) {
1291 		if (canvas_item->details->rendered_pixbuf != NULL) {
1292 			g_object_unref (canvas_item->details->rendered_pixbuf);
1293 		}
1294 		canvas_item->details->rendered_pixbuf = real_map_pixbuf (canvas_item);
1295 		canvas_item->details->rendered_is_prelit = canvas_item->details->is_prelit;
1296 		canvas_item->details->rendered_is_highlighted_for_selection = canvas_item->details->is_highlighted_for_selection;
1297 		canvas_item->details->rendered_is_highlighted_for_drop = canvas_item->details->is_highlighted_for_drop;
1298 	        canvas_item->details->rendered_is_highlighted_for_clipboard = canvas_item->details->is_highlighted_for_clipboard;
1299 		canvas_item->details->rendered_is_focused = gtk_widget_has_focus (GTK_WIDGET (EEL_CANVAS_ITEM (canvas_item)->canvas));
1300 	}
1301 
1302 	g_object_ref (canvas_item->details->rendered_pixbuf);
1303 
1304 	return canvas_item->details->rendered_pixbuf;
1305 }
1306 
1307 static void
1308 draw_embedded_text (NautilusCanvasItem *item,
1309                     cairo_t *cr,
1310 		    int x, int y)
1311 {
1312 	PangoLayout *layout;
1313 	PangoContext *context;
1314 	PangoFontDescription *desc;
1315 	GtkWidget *widget;
1316 	GtkStyleContext *style_context;
1317 
1318 	if (item->details->embedded_text == NULL ||
1319 	    item->details->embedded_text_rect.width == 0 ||
1320 	    item->details->embedded_text_rect.height == 0) {
1321 		return;
1322 	}
1323 
1324 	widget = GTK_WIDGET (EEL_CANVAS_ITEM (item)->canvas);
1325 
1326 	if (item->details->embedded_text_layout != NULL) {
1327 		layout = g_object_ref (item->details->embedded_text_layout);
1328 	} else {
1329 		context = gtk_widget_get_pango_context (widget);
1330 		layout = pango_layout_new (context);
1331 		pango_layout_set_text (layout, item->details->embedded_text, -1);
1332 		
1333 		desc = pango_font_description_from_string ("monospace 6");
1334 		pango_layout_set_font_description (layout, desc);
1335 		pango_font_description_free (desc);
1336 
1337 		if (item->details->is_visible) {
1338 			item->details->embedded_text_layout = g_object_ref (layout);
1339 		}
1340 	}
1341 
1342 	style_context = gtk_widget_get_style_context (widget);
1343 	gtk_style_context_save (style_context);
1344 	gtk_style_context_add_class (style_context, "icon-embedded-text");
1345 
1346 	cairo_save (cr);
1347 
1348 	cairo_rectangle (cr,
1349 			 x + item->details->embedded_text_rect.x,
1350 			 y + item->details->embedded_text_rect.y,
1351 			 item->details->embedded_text_rect.width,
1352 			 item->details->embedded_text_rect.height);
1353 	cairo_clip (cr);
1354 
1355 	gtk_render_layout (style_context, cr,
1356 			   x + item->details->embedded_text_rect.x,
1357 			   y + item->details->embedded_text_rect.y,
1358 			   layout);
1359 
1360 	gtk_style_context_restore (style_context);
1361 	cairo_restore (cr);
1362 }
1363 
1364 /* Draw the canvas item for non-anti-aliased mode. */
1365 static void
1366 nautilus_canvas_item_draw (EelCanvasItem *item,
1367 			   cairo_t *cr,
1368 			   cairo_region_t *region)
1369 {
1370 	NautilusCanvasContainer *container;
1371 	NautilusCanvasItem *canvas_item;
1372 	NautilusCanvasItemDetails *details;
1373 	EelIRect icon_rect;
1374 	GdkPixbuf *temp_pixbuf;
1375 	GtkStyleContext *context;
1376 
1377 	container = NAUTILUS_CANVAS_CONTAINER (item->canvas);
1378 	canvas_item = NAUTILUS_CANVAS_ITEM (item);
1379 	details = canvas_item->details;
1380 
1381         /* Draw the pixbuf. */
1382      	if (details->pixbuf == NULL) {
1383 		return;
1384 	}
1385 
1386 	context = gtk_widget_get_style_context (GTK_WIDGET (container));
1387 	gtk_style_context_save (context);
1388 	gtk_style_context_add_class (context, "nautilus-canvas-item");
1389 
1390 	icon_rect = canvas_item->details->icon_rect;
1391 	temp_pixbuf = map_pixbuf (canvas_item);
1392 
1393 	gtk_render_icon (context, cr,
1394 			   temp_pixbuf,
1395 			   icon_rect.x0, icon_rect.y0);
1396 	g_object_unref (temp_pixbuf);
1397 
1398 	draw_embedded_text (canvas_item, cr, icon_rect.x0, icon_rect.y0);
1399 	
1400 	/* Draw stretching handles (if necessary). */
1401 	draw_stretch_handles (canvas_item, cr, &icon_rect);
1402 	
1403 	/* Draw the label text. */
1404 	draw_label_text (canvas_item, cr, icon_rect);
1405 
1406 	gtk_style_context_restore (context);
1407 }
1408 
1409 #define ZERO_WIDTH_SPACE "\xE2\x80\x8B"
1410 
1411 #define ZERO_OR_THREE_DIGITS(p)			\
1412 	(!g_ascii_isdigit (*(p)) ||		\
1413 	 (g_ascii_isdigit (*(p+1)) &&		\
1414 	  g_ascii_isdigit (*(p+2))))
1415 
1416 
1417 static PangoLayout *
1418 create_label_layout (NautilusCanvasItem *item,
1419 		     const char *text)
1420 {
1421 	PangoLayout *layout;
1422 	PangoContext *context;
1423 	PangoFontDescription *desc;
1424 	NautilusCanvasContainer *container;
1425 	EelCanvasItem *canvas_item;
1426 	GString *str;
1427 	char *zeroified_text;
1428 	const char *p;
1429 
1430 	canvas_item = EEL_CANVAS_ITEM (item);
1431 
1432 	container = NAUTILUS_CANVAS_CONTAINER (canvas_item->canvas);
1433 	context = gtk_widget_get_pango_context (GTK_WIDGET (canvas_item->canvas));
1434 	layout = pango_layout_new (context);
1435 	
1436 	zeroified_text = NULL;
1437 
1438 	if (text != NULL) {
1439 		str = g_string_new (NULL);
1440 
1441 		for (p = text; *p != '\0'; p++) {
1442 			str = g_string_append_c (str, *p);
1443 
1444 			if (*p == '_' || *p == '-' || (*p == '.' && ZERO_OR_THREE_DIGITS (p+1))) {
1445 				/* Ensure that we allow to break after '_' or '.' characters,
1446 				 * if they are not likely to be part of a version information, to
1447 				 * not break wrapping of foobar-0.0.1.
1448 				 * Wrap before IPs and long numbers, though. */
1449 				str = g_string_append (str, ZERO_WIDTH_SPACE);
1450 			}
1451 		}
1452 
1453 		zeroified_text = g_string_free (str, FALSE);
1454 	}
1455 
1456 	pango_layout_set_text (layout, zeroified_text, -1);
1457 	pango_layout_set_auto_dir (layout, FALSE);
1458 	pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
1459 
1460 	pango_layout_set_spacing (layout, LABEL_LINE_SPACING);
1461 	pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
1462 
1463 	/* Create a font description */
1464 	if (container->details->font) {
1465 		desc = pango_font_description_from_string (container->details->font);
1466 	} else {
1467 		desc = pango_font_description_copy (pango_context_get_font_description (context));
1468 	}
1469 	pango_layout_set_font_description (layout, desc);
1470 	pango_font_description_free (desc);
1471 	g_free (zeroified_text);
1472 	
1473 	return layout;
1474 }
1475 
1476 static PangoLayout *
1477 get_label_layout (PangoLayout **layout_cache,
1478 		  NautilusCanvasItem *item,
1479 		  const char *text)
1480 {
1481 	PangoLayout *layout;
1482 
1483 	if (*layout_cache != NULL) {
1484 		return g_object_ref (*layout_cache);
1485 	}
1486 
1487 	layout = create_label_layout (item, text);
1488 
1489 	if (item->details->is_visible) {
1490 		*layout_cache = g_object_ref (layout);
1491 	}
1492 	
1493 	return layout;
1494 }
1495 
1496 /* handle events */
1497 
1498 static int
1499 nautilus_canvas_item_event (EelCanvasItem *item, GdkEvent *event)
1500 {
1501 	NautilusCanvasItem *canvas_item;
1502 	GdkCursor *cursor;
1503 	GdkWindow *cursor_window;
1504 
1505 	canvas_item = NAUTILUS_CANVAS_ITEM (item);
1506 	cursor_window = ((GdkEventAny *)event)->window;
1507 
1508 	switch (event->type) {
1509 	case GDK_ENTER_NOTIFY:
1510 		if (!canvas_item->details->is_prelit) {
1511 			canvas_item->details->is_prelit = TRUE;
1512 			nautilus_canvas_item_invalidate_label_size (canvas_item);
1513 			eel_canvas_item_request_update (item);
1514 			eel_canvas_item_send_behind (item,
1515 						     NAUTILUS_CANVAS_CONTAINER (item->canvas)->details->rubberband_info.selection_rectangle);
1516 
1517 			/* show a hand cursor */
1518 			if (in_single_click_mode ()) {
1519 				cursor = gdk_cursor_new_for_display (gdk_display_get_default(),
1520 								     GDK_HAND2);
1521 				gdk_window_set_cursor (cursor_window, cursor);
1522 				g_object_unref (cursor);
1523 
1524 				canvas_item->details->cursor_window = g_object_ref (cursor_window);
1525 			}
1526 		}
1527 		return TRUE;
1528 		
1529 	case GDK_LEAVE_NOTIFY:
1530 		if (canvas_item->details->is_prelit 
1531 		    || canvas_item->details->is_highlighted_for_drop) {
1532 			/* When leaving, turn of the prelight state and the
1533 			 * higlighted for drop. The latter gets turned on
1534 			 * by the drag&drop motion callback.
1535 			 */
1536 			canvas_item->details->is_prelit = FALSE;
1537 			canvas_item->details->is_highlighted_for_drop = FALSE;
1538 			nautilus_canvas_item_invalidate_label_size (canvas_item);
1539 			eel_canvas_item_request_update (item);
1540 
1541 			/* show default cursor */
1542 			gdk_window_set_cursor (cursor_window, NULL);
1543 			g_clear_object (&canvas_item->details->cursor_window);
1544 		}
1545 		return TRUE;
1546 		
1547 	default:
1548 		/* Don't eat up other events; canvas container might use them. */
1549 		return FALSE;
1550 	}
1551 }
1552 
1553 static gboolean
1554 hit_test (NautilusCanvasItem *canvas_item, EelIRect icon_rect)
1555 {
1556 	NautilusCanvasItemDetails *details;
1557 	
1558 	details = canvas_item->details;
1559 	
1560 	/* Quick check to see if the rect hits the canvas or text at all. */
1561 	if (!eel_irect_hits_irect (canvas_item->details->icon_rect, icon_rect)
1562 	    && (!eel_irect_hits_irect (details->text_rect, icon_rect))) {
1563 		return FALSE;
1564 	}
1565 
1566 	/* Check for hits in the stretch handles. */
1567 	if (hit_test_stretch_handle (canvas_item, icon_rect, NULL)) {
1568 		return TRUE;
1569 	}
1570 	
1571 	/* Check for hit in the canvas. */
1572 	if (eel_irect_hits_irect (canvas_item->details->icon_rect, icon_rect)) {
1573 		return TRUE;
1574 	}
1575 
1576 	/* Check for hit in the text. */
1577 	if (eel_irect_hits_irect (details->text_rect, icon_rect)
1578 	    && !canvas_item->details->is_renaming) {
1579 		return TRUE;
1580 	}
1581 	
1582 	return FALSE;
1583 }
1584 
1585 /* Point handler for the canvas canvas item. */
1586 static double
1587 nautilus_canvas_item_point (EelCanvasItem *item, double x, double y, int cx, int cy,
1588 			    EelCanvasItem **actual_item)
1589 {
1590 	EelIRect icon_rect;
1591 
1592 	*actual_item = item;
1593 	icon_rect.x0 = cx;
1594 	icon_rect.y0 = cy;
1595 	icon_rect.x1 = cx + 1;
1596 	icon_rect.y1 = cy + 1;
1597 	if (hit_test (NAUTILUS_CANVAS_ITEM (item), icon_rect)) {
1598 		return 0.0;
1599 	} else {
1600 		/* This value means not hit.
1601 		 * It's kind of arbitrary. Can we do better?
1602 		 */
1603 		return item->canvas->pixels_per_unit * 2 + 10;
1604 	}
1605 }
1606 
1607 static void
1608 nautilus_canvas_item_translate (EelCanvasItem *item, double dx, double dy)
1609 {
1610 	NautilusCanvasItem *canvas_item;
1611 	NautilusCanvasItemDetails *details;
1612 	
1613 	canvas_item = NAUTILUS_CANVAS_ITEM (item);
1614 	details = canvas_item->details;
1615 
1616 	details->x += dx;
1617 	details->y += dy;
1618 }
1619 
1620 void
1621 nautilus_canvas_item_get_bounds_for_layout (NautilusCanvasItem *canvas_item,
1622 					    double *x1, double *y1, double *x2, double *y2)
1623 {
1624 	NautilusCanvasItemDetails *details;
1625 	EelIRect *total_rect;
1626 
1627 	details = canvas_item->details;
1628 
1629 	nautilus_canvas_item_ensure_bounds_up_to_date (canvas_item);
1630 	g_assert (details->bounds_cached);
1631 
1632 	total_rect = &details->bounds_cache_for_layout;
1633 
1634 	/* Return the result. */
1635 	if (x1 != NULL) {
1636 		*x1 = (int)details->x + total_rect->x0;
1637 	}
1638 	if (y1 != NULL) {
1639 		*y1 = (int)details->y + total_rect->y0;
1640 	}
1641 	if (x2 != NULL) {
1642 		*x2 = (int)details->x + total_rect->x1 + 1;
1643 	}
1644 	if (y2 != NULL) {
1645 		*y2 = (int)details->y + total_rect->y1 + 1;
1646 	}
1647 }
1648 
1649 void
1650 nautilus_canvas_item_get_bounds_for_entire_item (NautilusCanvasItem *canvas_item,
1651 						 double *x1, double *y1, double *x2, double *y2)
1652 {
1653 	NautilusCanvasItemDetails *details;
1654 	EelIRect *total_rect;
1655 
1656 	details = canvas_item->details;
1657 
1658 	nautilus_canvas_item_ensure_bounds_up_to_date (canvas_item);
1659 	g_assert (details->bounds_cached);
1660 
1661 	total_rect = &details->bounds_cache_for_entire_item;
1662 
1663 	/* Return the result. */
1664 	if (x1 != NULL) {
1665 		*x1 = (int)details->x + total_rect->x0;
1666 	}
1667 	if (y1 != NULL) {
1668 		*y1 = (int)details->y + total_rect->y0;
1669 	}
1670 	if (x2 != NULL) {
1671 		*x2 = (int)details->x + total_rect->x1 + 1;
1672 	}
1673 	if (y2 != NULL) {
1674 		*y2 = (int)details->y + total_rect->y1 + 1;
1675 	}
1676 }
1677 	
1678 /* Bounds handler for the canvas canvas item. */
1679 static void
1680 nautilus_canvas_item_bounds (EelCanvasItem *item,
1681 			     double *x1, double *y1, double *x2, double *y2)
1682 {
1683 	NautilusCanvasItem *canvas_item;
1684 	NautilusCanvasItemDetails *details;
1685 	EelIRect *total_rect;
1686 
1687 	canvas_item = NAUTILUS_CANVAS_ITEM (item);
1688 	details = canvas_item->details;
1689 
1690 	g_assert (x1 != NULL);
1691 	g_assert (y1 != NULL);
1692 	g_assert (x2 != NULL);
1693 	g_assert (y2 != NULL);
1694 
1695 	nautilus_canvas_item_ensure_bounds_up_to_date (canvas_item);
1696 	g_assert (details->bounds_cached);
1697 
1698 	total_rect = &details->bounds_cache;
1699 
1700 	/* Return the result. */
1701 	*x1 = (int)details->x + total_rect->x0;
1702 	*y1 = (int)details->y + total_rect->y0;
1703 	*x2 = (int)details->x + total_rect->x1 + 1;
1704 	*y2 = (int)details->y + total_rect->y1 + 1;
1705 }
1706 
1707 static void
1708 nautilus_canvas_item_ensure_bounds_up_to_date (NautilusCanvasItem *canvas_item)
1709 {
1710 	NautilusCanvasItemDetails *details;
1711 	EelIRect icon_rect, icon_rect_raw;
1712 	EelIRect text_rect, text_rect_for_layout, text_rect_for_entire_text;
1713 	EelIRect total_rect, total_rect_for_layout, total_rect_for_entire_text;
1714 	EelCanvasItem *item;
1715 	double pixels_per_unit;
1716 	
1717 	details = canvas_item->details;
1718 	item = EEL_CANVAS_ITEM (canvas_item);
1719 
1720 	if (!details->bounds_cached) {
1721 		measure_label_text (canvas_item);
1722 
1723 		pixels_per_unit = EEL_CANVAS_ITEM (item)->canvas->pixels_per_unit;
1724 
1725 		/* Compute raw and scaled canvas rectangle. */
1726 		icon_rect.x0 = 0;
1727 		icon_rect.y0 = 0;
1728 		icon_rect_raw.x0 = 0;
1729 		icon_rect_raw.y0 = 0;
1730 		if (details->pixbuf == NULL) {
1731 			icon_rect.x1 = icon_rect.x0;
1732 			icon_rect.y1 = icon_rect.y0;
1733 			icon_rect_raw.x1 = icon_rect_raw.x0;
1734 			icon_rect_raw.y1 = icon_rect_raw.y0;
1735 		} else {
1736 			icon_rect_raw.x1 = icon_rect_raw.x0 + gdk_pixbuf_get_width (details->pixbuf);
1737 			icon_rect_raw.y1 = icon_rect_raw.y0 + gdk_pixbuf_get_height (details->pixbuf);
1738 			icon_rect.x1 = icon_rect_raw.x1 / pixels_per_unit;
1739 			icon_rect.y1 = icon_rect_raw.y1 / pixels_per_unit;
1740 		}
1741 		
1742 		/* Compute text rectangle. */
1743 		text_rect = compute_text_rectangle (canvas_item, icon_rect, FALSE, BOUNDS_USAGE_FOR_DISPLAY);
1744 		text_rect_for_layout = compute_text_rectangle (canvas_item, icon_rect, FALSE, BOUNDS_USAGE_FOR_LAYOUT);
1745 		text_rect_for_entire_text = compute_text_rectangle (canvas_item, icon_rect, FALSE, BOUNDS_USAGE_FOR_ENTIRE_ITEM);
1746 
1747 		/* Compute total rectangle */
1748 		eel_irect_union (&total_rect, &icon_rect, &text_rect);
1749 		eel_irect_union (&total_rect_for_layout, &icon_rect, &text_rect_for_layout);
1750 		eel_irect_union (&total_rect_for_entire_text, &icon_rect, &text_rect_for_entire_text);
1751 
1752 		details->bounds_cache = total_rect;
1753 		details->bounds_cache_for_layout = total_rect_for_layout;
1754 		details->bounds_cache_for_entire_item = total_rect_for_entire_text;
1755 		details->bounds_cached = TRUE;
1756 	}
1757 }
1758 
1759 /* Get the rectangle of the canvas only, in world coordinates. */
1760 EelDRect
1761 nautilus_canvas_item_get_icon_rectangle (const NautilusCanvasItem *item)
1762 {
1763 	EelDRect rectangle;
1764 	double pixels_per_unit;
1765 	GdkPixbuf *pixbuf;
1766 	
1767 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_ITEM (item), eel_drect_empty);
1768 
1769 	rectangle.x0 = item->details->x;
1770 	rectangle.y0 = item->details->y;
1771 	
1772 	pixbuf = item->details->pixbuf;
1773 	
1774 	pixels_per_unit = EEL_CANVAS_ITEM (item)->canvas->pixels_per_unit;
1775 	rectangle.x1 = rectangle.x0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_width (pixbuf)) / pixels_per_unit;
1776 	rectangle.y1 = rectangle.y0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_height (pixbuf)) / pixels_per_unit;
1777 
1778 	eel_canvas_item_i2w (EEL_CANVAS_ITEM (item),
1779 			     &rectangle.x0,
1780 			     &rectangle.y0);
1781 	eel_canvas_item_i2w (EEL_CANVAS_ITEM (item),
1782 			     &rectangle.x1,
1783 			     &rectangle.y1);
1784 
1785 	return rectangle;
1786 }
1787 
1788 EelDRect
1789 nautilus_canvas_item_get_text_rectangle (NautilusCanvasItem *item,
1790 					 gboolean for_layout)
1791 {
1792 	/* FIXME */
1793 	EelIRect icon_rectangle;
1794 	EelIRect text_rectangle;
1795 	EelDRect ret;
1796 	double pixels_per_unit;
1797 	GdkPixbuf *pixbuf;
1798 	
1799 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_ITEM (item), eel_drect_empty);
1800 
1801 	icon_rectangle.x0 = item->details->x;
1802 	icon_rectangle.y0 = item->details->y;
1803 	
1804 	pixbuf = item->details->pixbuf;
1805 	
1806 	pixels_per_unit = EEL_CANVAS_ITEM (item)->canvas->pixels_per_unit;
1807 	icon_rectangle.x1 = icon_rectangle.x0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_width (pixbuf)) / pixels_per_unit;
1808 	icon_rectangle.y1 = icon_rectangle.y0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_height (pixbuf)) / pixels_per_unit;
1809 
1810 	measure_label_text (item);
1811 
1812 	text_rectangle = compute_text_rectangle (item, icon_rectangle, FALSE,
1813 						 for_layout ? BOUNDS_USAGE_FOR_LAYOUT : BOUNDS_USAGE_FOR_DISPLAY);
1814  
1815 	ret.x0 = text_rectangle.x0;
1816 	ret.y0 = text_rectangle.y0;
1817 	ret.x1 = text_rectangle.x1;
1818 	ret.y1 = text_rectangle.y1;
1819 
1820         eel_canvas_item_i2w (EEL_CANVAS_ITEM (item),
1821                              &ret.x0,
1822                              &ret.y0);
1823         eel_canvas_item_i2w (EEL_CANVAS_ITEM (item),
1824                              &ret.x1,
1825                              &ret.y1);
1826  
1827         return ret;
1828 }
1829 
1830 
1831 /* Get the rectangle of the icon only, in canvas coordinates. */
1832 static void
1833 get_icon_rectangle (NautilusCanvasItem *item,
1834 		      EelIRect *rect)
1835 {
1836 	GdkPixbuf *pixbuf;
1837 
1838 	g_assert (NAUTILUS_IS_CANVAS_ITEM (item));
1839 	g_assert (rect != NULL);
1840 
1841 	eel_canvas_w2c (EEL_CANVAS_ITEM (item)->canvas,
1842 			item->details->x,
1843 			item->details->y,
1844 			&rect->x0,
1845 			&rect->y0);
1846 	
1847 	pixbuf = item->details->pixbuf;
1848 	
1849 	rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_width (pixbuf));
1850 	rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : gdk_pixbuf_get_height (pixbuf));
1851 }
1852 
1853 void
1854 nautilus_canvas_item_set_show_stretch_handles (NautilusCanvasItem *item,
1855 					       gboolean show_stretch_handles)
1856 {
1857 	g_return_if_fail (NAUTILUS_IS_CANVAS_ITEM (item));
1858 	g_return_if_fail (show_stretch_handles == FALSE || show_stretch_handles == TRUE);
1859 	
1860 	if (!item->details->show_stretch_handles == !show_stretch_handles) {
1861 		return;
1862 	}
1863 
1864 	item->details->show_stretch_handles = show_stretch_handles;
1865 	eel_canvas_item_request_update (EEL_CANVAS_ITEM (item));
1866 }
1867 
1868 /* Check if one of the stretch handles was hit. */
1869 static gboolean
1870 hit_test_stretch_handle (NautilusCanvasItem *item,
1871 			 EelIRect probe_icon_rect,
1872 			 GtkCornerType *corner)
1873 {
1874 	EelIRect icon_rect;
1875 	GdkPixbuf *knob_pixbuf;
1876 	int knob_width, knob_height;
1877 	int hit_corner;
1878 	
1879 	g_assert (NAUTILUS_IS_CANVAS_ITEM (item));
1880 
1881 	/* Make sure there are handles to hit. */
1882 	if (!item->details->show_stretch_handles) {
1883 		return FALSE;
1884 	}
1885 
1886 	/* Quick check to see if the rect hits the canvas at all. */
1887 	icon_rect = item->details->icon_rect;
1888 	if (!eel_irect_hits_irect (probe_icon_rect, icon_rect)) {
1889 		return FALSE;
1890 	}
1891 	
1892 	knob_pixbuf = get_knob_pixbuf ();
1893 	knob_width = gdk_pixbuf_get_width (knob_pixbuf);
1894 	knob_height = gdk_pixbuf_get_height (knob_pixbuf);
1895 	g_object_unref (knob_pixbuf);
1896 
1897 	/* Check for hits in the stretch handles. */
1898 	hit_corner = -1;
1899 	if (probe_icon_rect.x0 < icon_rect.x0 + knob_width) {
1900 		if (probe_icon_rect.y0 < icon_rect.y0 + knob_height)
1901 			hit_corner = GTK_CORNER_TOP_LEFT;
1902 		else if (probe_icon_rect.y1 >= icon_rect.y1 - knob_height)
1903 			hit_corner = GTK_CORNER_BOTTOM_LEFT;
1904 	}
1905 	else if (probe_icon_rect.x1 >= icon_rect.x1 - knob_width) {
1906 		if (probe_icon_rect.y0 < icon_rect.y0 + knob_height)
1907 			hit_corner = GTK_CORNER_TOP_RIGHT;
1908 		else if (probe_icon_rect.y1 >= icon_rect.y1 - knob_height)
1909 			hit_corner = GTK_CORNER_BOTTOM_RIGHT;
1910 	}
1911 	if (corner)
1912 		*corner = hit_corner;
1913 
1914 	return hit_corner != -1;
1915 }
1916 
1917 gboolean
1918 nautilus_canvas_item_hit_test_stretch_handles (NautilusCanvasItem *item,
1919 					       gdouble world_x,
1920 					       gdouble world_y,
1921 					       GtkCornerType *corner)
1922 {
1923 	EelIRect icon_rect;
1924 
1925 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_ITEM (item), FALSE);
1926 	
1927 	eel_canvas_w2c (EEL_CANVAS_ITEM (item)->canvas,
1928 			world_x,
1929 			world_y,
1930 			&icon_rect.x0,
1931 			&icon_rect.y0);
1932 	icon_rect.x1 = icon_rect.x0 + 1;
1933 	icon_rect.y1 = icon_rect.y0 + 1;
1934 	return hit_test_stretch_handle (item, icon_rect, corner);
1935 }
1936 
1937 /* nautilus_canvas_item_hit_test_rectangle
1938  *
1939  * Check and see if there is an intersection between the item and the
1940  * canvas rect.
1941  */
1942 gboolean
1943 nautilus_canvas_item_hit_test_rectangle (NautilusCanvasItem *item, EelIRect icon_rect)
1944 {
1945 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_ITEM (item), FALSE);
1946 
1947 	return hit_test (item, icon_rect);
1948 }
1949 
1950 const char *
1951 nautilus_canvas_item_get_editable_text (NautilusCanvasItem *canvas_item)
1952 {
1953 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_ITEM (canvas_item), NULL);
1954 
1955 	return canvas_item->details->editable_text;
1956 }
1957 
1958 void
1959 nautilus_canvas_item_set_renaming (NautilusCanvasItem *item, gboolean state)
1960 {
1961 	g_return_if_fail (NAUTILUS_IS_CANVAS_ITEM (item));
1962 	g_return_if_fail (state == FALSE || state == TRUE);
1963 
1964 	if (!item->details->is_renaming == !state) {
1965 		return;
1966 	}
1967 
1968 	item->details->is_renaming = state;
1969 	eel_canvas_item_request_update (EEL_CANVAS_ITEM (item));
1970 }
1971 
1972 double
1973 nautilus_canvas_item_get_max_text_width (NautilusCanvasItem *item)
1974 {
1975 	EelCanvasItem *canvas_item;
1976 
1977 	canvas_item = EEL_CANVAS_ITEM (item);
1978 
1979 	return MAX_TEXT_WIDTH_STANDARD * canvas_item->canvas->pixels_per_unit;
1980 }
1981 
1982 void
1983 nautilus_canvas_item_set_entire_text (NautilusCanvasItem       *item,
1984 				      gboolean                      entire_text)
1985 {
1986 	if (item->details->entire_text != entire_text) {
1987 		item->details->entire_text = entire_text;
1988 
1989 		nautilus_canvas_item_invalidate_label_size (item);
1990 		eel_canvas_item_request_update (EEL_CANVAS_ITEM (item));
1991 	}
1992 }
1993 
1994 /* Class initialization function for the canvas canvas item. */
1995 static void
1996 nautilus_canvas_item_class_init (NautilusCanvasItemClass *class)
1997 {
1998 	GObjectClass *object_class;
1999 	EelCanvasItemClass *item_class;
2000 
2001 	object_class = G_OBJECT_CLASS (class);
2002 	item_class = EEL_CANVAS_ITEM_CLASS (class);
2003 
2004 	object_class->finalize = nautilus_canvas_item_finalize;
2005 	object_class->set_property = nautilus_canvas_item_set_property;
2006 	object_class->get_property = nautilus_canvas_item_get_property;
2007 
2008         g_object_class_install_property (
2009 					 object_class,
2010 					 PROP_EDITABLE_TEXT,
2011 					 g_param_spec_string ("editable_text",
2012 							      "editable text",
2013 							      "the editable label",
2014 							      "", G_PARAM_READWRITE));
2015 
2016         g_object_class_install_property (
2017 					 object_class,
2018 					 PROP_ADDITIONAL_TEXT,
2019 					 g_param_spec_string ("additional_text",
2020 							      "additional text",
2021 							      "some more text",
2022 							      "", G_PARAM_READWRITE));
2023 
2024         g_object_class_install_property (
2025 					 object_class,
2026 					 PROP_HIGHLIGHTED_FOR_SELECTION,
2027 					 g_param_spec_boolean ("highlighted_for_selection",
2028 							       "highlighted for selection",
2029 							       "whether we are highlighted for a selection",
2030 							       FALSE, G_PARAM_READWRITE)); 
2031 
2032         g_object_class_install_property (
2033 					 object_class,
2034 					 PROP_HIGHLIGHTED_AS_KEYBOARD_FOCUS,
2035 					 g_param_spec_boolean ("highlighted_as_keyboard_focus",
2036 							       "highlighted as keyboard focus",
2037 							       "whether we are highlighted to render keyboard focus",
2038 							       FALSE, G_PARAM_READWRITE)); 
2039 
2040 
2041         g_object_class_install_property (
2042 					 object_class,
2043 					 PROP_HIGHLIGHTED_FOR_DROP,
2044 					 g_param_spec_boolean ("highlighted_for_drop",
2045 							       "highlighted for drop",
2046 							       "whether we are highlighted for a D&D drop",
2047 							       FALSE, G_PARAM_READWRITE));
2048 
2049 	g_object_class_install_property (
2050 					 object_class,
2051 					 PROP_HIGHLIGHTED_FOR_CLIPBOARD,
2052 					 g_param_spec_boolean ("highlighted_for_clipboard",
2053 							       "highlighted for clipboard",
2054 							       "whether we are highlighted for a clipboard paste (after we have been cut)",
2055 							       FALSE, G_PARAM_READWRITE));
2056 
2057 	item_class->update = nautilus_canvas_item_update;
2058 	item_class->draw = nautilus_canvas_item_draw;
2059 	item_class->point = nautilus_canvas_item_point;
2060 	item_class->translate = nautilus_canvas_item_translate;
2061 	item_class->bounds = nautilus_canvas_item_bounds;
2062 	item_class->event = nautilus_canvas_item_event;
2063 
2064 	atk_registry_set_factory_type (atk_get_default_registry (),
2065 				       NAUTILUS_TYPE_CANVAS_ITEM,
2066 				       nautilus_canvas_item_accessible_factory_get_type ());
2067 
2068 	g_type_class_add_private (class, sizeof (NautilusCanvasItemDetails));
2069 }
2070 
2071 static GailTextUtil *
2072 nautilus_canvas_item_get_text (GObject *text)
2073 {
2074 	return NAUTILUS_CANVAS_ITEM (text)->details->text_util;
2075 }
2076 
2077 static void
2078 nautilus_canvas_item_text_interface_init (EelAccessibleTextIface *iface)
2079 {
2080 	iface->get_text = nautilus_canvas_item_get_text;
2081 }
2082 
2083 /* ============================= a11y interfaces =========================== */
2084 
2085 static const char *nautilus_canvas_item_accessible_action_names[] = {
2086         "open",
2087         "menu",
2088         NULL
2089 };
2090 
2091 static const char *nautilus_canvas_item_accessible_action_descriptions[] = {
2092         "Open item",
2093         "Popup context menu",
2094         NULL
2095 };
2096 
2097 enum {
2098 	ACTION_OPEN,
2099 	ACTION_MENU,
2100 	LAST_ACTION
2101 };
2102 
2103 typedef struct {
2104         char *action_descriptions[LAST_ACTION];
2105 	char *image_description;
2106 	char *description;
2107 } NautilusCanvasItemAccessiblePrivate;
2108 
2109 typedef struct {
2110 	NautilusCanvasItem *item;
2111 	gint action_number;
2112 } NautilusCanvasItemAccessibleActionContext;
2113 
2114 typedef struct {
2115 	EelCanvasItemAccessible parent;
2116 	NautilusCanvasItemAccessiblePrivate *priv;
2117 } NautilusCanvasItemAccessible;
2118 
2119 typedef struct {
2120 	EelCanvasItemAccessibleClass parent_class;
2121 } NautilusCanvasItemAccessibleClass;
2122 
2123 #define GET_ACCESSIBLE_PRIV(o) ((NautilusCanvasItemAccessible *) o)->priv;
2124 
2125 /* accessible AtkAction interface */
2126 static gboolean
2127 nautilus_canvas_item_accessible_idle_do_action (gpointer data)
2128 {
2129 	NautilusCanvasItem *item;
2130 	NautilusCanvasItemAccessibleActionContext *ctx;
2131 	NautilusCanvasIcon *icon;
2132 	NautilusCanvasContainer *container;
2133 	GList* selection;
2134 	GList file_list;
2135         GdkEventButton button_event = { 0 };
2136 	gint action_number;
2137 
2138 	container = NAUTILUS_CANVAS_CONTAINER (data);
2139 	container->details->a11y_item_action_idle_handler = 0;
2140 	while (!g_queue_is_empty (container->details->a11y_item_action_queue)) {
2141 		ctx = g_queue_pop_head (container->details->a11y_item_action_queue);
2142 		action_number = ctx->action_number;	
2143 		item = ctx->item;
2144 		g_free (ctx);
2145 		icon = item->user_data;
2146 
2147 		switch (action_number) {
2148 		case ACTION_OPEN:
2149 			file_list.data = icon->data;
2150 			file_list.next = NULL;
2151 			file_list.prev = NULL;
2152         		g_signal_emit_by_name (container, "activate", &file_list);
2153 			break;
2154 		case ACTION_MENU:
2155 			selection = nautilus_canvas_container_get_selection (container);
2156 			if (selection == NULL ||
2157 			    g_list_length (selection) != 1 ||
2158  			    selection->data != icon->data)  {
2159 				g_list_free (selection);
2160 				return FALSE;
2161 			}
2162 			g_list_free (selection);
2163         		g_signal_emit_by_name (container, "context_click_selection", &button_event);
2164 			break;
2165 		default :
2166 			g_assert_not_reached ();
2167 			break;
2168 		}
2169 	}
2170 	return FALSE;
2171 }
2172 
2173 static gboolean
2174 nautilus_canvas_item_accessible_do_action (AtkAction *accessible,
2175 					   int i)
2176 {
2177 	NautilusCanvasItem *item;
2178 	NautilusCanvasItemAccessibleActionContext *ctx;
2179 	NautilusCanvasContainer *container;
2180 
2181 	g_assert (i < LAST_ACTION);
2182 
2183 	item = NAUTILUS_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)));
2184 	if (!item) {
2185 		return FALSE;
2186 	}
2187 
2188 	container = NAUTILUS_CANVAS_CONTAINER (EEL_CANVAS_ITEM (item)->canvas);
2189 	switch (i) {
2190 	case ACTION_OPEN:
2191 	case ACTION_MENU:
2192 		if (container->details->a11y_item_action_queue == NULL) {
2193 			container->details->a11y_item_action_queue = g_queue_new ();
2194 		}
2195 		ctx = g_new (NautilusCanvasItemAccessibleActionContext, 1);
2196 		ctx->action_number = i;
2197 		ctx->item = item;
2198 		g_queue_push_head (container->details->a11y_item_action_queue, ctx);
2199 		if (container->details->a11y_item_action_idle_handler == 0) {
2200 			container->details->a11y_item_action_idle_handler = g_idle_add (nautilus_canvas_item_accessible_idle_do_action, container);
2201 		}
2202 		break;
2203         default :
2204                 g_warning ("Invalid action passed to NautilusCanvasItemAccessible::do_action");
2205                 return FALSE;
2206         }
2207 
2208 	return TRUE;
2209 }
2210 
2211 static int
2212 nautilus_canvas_item_accessible_get_n_actions (AtkAction *accessible)
2213 {
2214 	return LAST_ACTION;
2215 }
2216 
2217 static const char *
2218 nautilus_canvas_item_accessible_action_get_description (AtkAction *accessible,
2219 							int i)
2220 {
2221 	NautilusCanvasItemAccessiblePrivate *priv;
2222 
2223 	g_assert (i < LAST_ACTION);
2224 
2225 	priv = GET_ACCESSIBLE_PRIV (accessible);
2226 
2227 	if (priv->action_descriptions[i]) {
2228 		return priv->action_descriptions[i];
2229 	} else {
2230 		return nautilus_canvas_item_accessible_action_descriptions[i];
2231 	}
2232 }
2233 
2234 static const char *
2235 nautilus_canvas_item_accessible_action_get_name (AtkAction *accessible, int i)
2236 {
2237 	g_assert (i < LAST_ACTION);
2238 
2239 	return nautilus_canvas_item_accessible_action_names[i];
2240 }
2241 
2242 static const char *
2243 nautilus_canvas_item_accessible_action_get_keybinding (AtkAction *accessible,
2244 						       int i)
2245 {
2246 	g_assert (i < LAST_ACTION);
2247 
2248 	return NULL;
2249 }
2250 
2251 static gboolean
2252 nautilus_canvas_item_accessible_action_set_description (AtkAction *accessible,
2253 							int i,
2254 							const char *description)
2255 {
2256 	NautilusCanvasItemAccessiblePrivate *priv;
2257 
2258 	g_assert (i < LAST_ACTION);
2259 
2260 	priv = GET_ACCESSIBLE_PRIV (accessible);
2261 
2262 	if (priv->action_descriptions[i]) {
2263 		g_free (priv->action_descriptions[i]);
2264 	}
2265 	priv->action_descriptions[i] = g_strdup (description);
2266 
2267 	return TRUE;
2268 }
2269 
2270 static void
2271 nautilus_canvas_item_accessible_action_interface_init (AtkActionIface *iface)
2272 {
2273 	iface->do_action = nautilus_canvas_item_accessible_do_action;
2274 	iface->get_n_actions = nautilus_canvas_item_accessible_get_n_actions;
2275 	iface->get_description = nautilus_canvas_item_accessible_action_get_description;
2276 	iface->get_keybinding = nautilus_canvas_item_accessible_action_get_keybinding;
2277 	iface->get_name = nautilus_canvas_item_accessible_action_get_name;
2278 	iface->set_description = nautilus_canvas_item_accessible_action_set_description;
2279 }
2280 
2281 static const gchar *
2282 nautilus_canvas_item_accessible_get_name (AtkObject *accessible)
2283 {
2284 	NautilusCanvasItem *item;
2285 
2286 	if (accessible->name) {
2287 		return accessible->name;
2288 	}
2289 
2290 	item = NAUTILUS_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)));
2291 	if (!item) {
2292 		return NULL;
2293 	}
2294 	return item->details->editable_text;
2295 }
2296 
2297 static const gchar*
2298 nautilus_canvas_item_accessible_get_description (AtkObject *accessible)
2299 {
2300 	NautilusCanvasItem *item;
2301 
2302 	item = NAUTILUS_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)));
2303 	if (!item) {
2304 		return NULL;
2305 	}
2306 
2307 	return item->details->additional_text;
2308 }
2309 
2310 static AtkObject *
2311 nautilus_canvas_item_accessible_get_parent (AtkObject *accessible)
2312 {
2313 	NautilusCanvasItem *item;
2314 	
2315 	item = NAUTILUS_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)));
2316 	if (!item) {
2317 		return NULL;
2318 	}
2319 
2320 	return gtk_widget_get_accessible (GTK_WIDGET (EEL_CANVAS_ITEM (item)->canvas));
2321 }
2322 
2323 static int
2324 nautilus_canvas_item_accessible_get_index_in_parent (AtkObject *accessible)
2325 {
2326 	NautilusCanvasItem *item;
2327 	NautilusCanvasContainer *container;
2328 	GList *l;
2329 	NautilusCanvasIcon *icon;
2330 	int i;
2331 
2332 	item = NAUTILUS_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)));
2333 	if (!item) {
2334 		return -1;
2335 	}
2336 	
2337 	container = NAUTILUS_CANVAS_CONTAINER (EEL_CANVAS_ITEM (item)->canvas);
2338 	
2339 	l = container->details->icons;
2340 	i = 0;
2341 	while (l) {
2342 		icon = l->data;
2343 		
2344 		if (icon->item == item) {
2345 			return i;
2346 		}
2347 		
2348 		i++;
2349 		l = l->next;
2350 	}
2351 
2352 	return -1;
2353 }
2354 
2355 static const gchar *
2356 nautilus_canvas_item_accessible_get_image_description (AtkImage *image)
2357 {
2358 	NautilusCanvasItemAccessiblePrivate *priv;
2359 	NautilusCanvasItem *item;
2360 	NautilusCanvasIcon *icon;
2361 	NautilusCanvasContainer *container;
2362 	char *description;
2363 
2364 	priv = GET_ACCESSIBLE_PRIV (image);
2365 
2366 	if (priv->image_description) {
2367 		return priv->image_description;
2368 	} else {
2369 		item = NAUTILUS_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (image)));
2370 		if (item == NULL) {
2371 			return NULL;
2372 		}
2373 		icon = item->user_data;
2374 		container = NAUTILUS_CANVAS_CONTAINER (EEL_CANVAS_ITEM (item)->canvas);
2375 		description = nautilus_canvas_container_get_icon_description (container, icon->data);
2376 		g_free (priv->description);
2377 		priv->description = description;
2378 		return priv->description;
2379 	}
2380 }
2381 
2382 static void
2383 nautilus_canvas_item_accessible_get_image_size
2384 (AtkImage *image, 
2385  gint     *width,
2386  gint     *height)
2387 {
2388 	NautilusCanvasItem *item;
2389 
2390 	item = NAUTILUS_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (image)));
2391 
2392 	if (!item || !item->details->pixbuf) {
2393 		*width = *height = 0;
2394 	} else {
2395 		*width = gdk_pixbuf_get_width (item->details->pixbuf);
2396 		*height = gdk_pixbuf_get_height (item->details->pixbuf);
2397 	}
2398 }
2399 
2400 static void
2401 nautilus_canvas_item_accessible_get_image_position
2402 (AtkImage		 *image,
2403  gint                    *x,
2404  gint	                 *y,
2405  AtkCoordType	         coord_type)
2406 {
2407 	NautilusCanvasItem *item;
2408 	gint x_offset, y_offset, itmp;
2409 
2410 	item = NAUTILUS_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (image)));
2411 	if (!item) {
2412 		return;
2413 	}
2414 	if (!item->details->icon_rect.x0 && !item->details->icon_rect.x1) {
2415 		return;
2416 	} else {
2417 		x_offset = 0;
2418 		y_offset = 0;
2419 		if (item->details->text_width) {
2420 			itmp = item->details->icon_rect.x0 -
2421 				item->details->text_rect.x0;
2422 			if (itmp > x_offset) {
2423 				x_offset = itmp;
2424 			}
2425 			itmp = item->details->icon_rect.y0 -
2426 				item->details->text_rect.y0;
2427 			if (itmp > y_offset) {
2428 				y_offset = itmp;
2429 			}
2430 		}
2431 	}
2432 	atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type);
2433 	*x += x_offset;
2434 	*y += y_offset;
2435 }
2436 
2437 static gboolean
2438 nautilus_canvas_item_accessible_set_image_description (AtkImage    *image,
2439 						       const gchar *description)
2440 {
2441 	NautilusCanvasItemAccessiblePrivate *priv;
2442 
2443 	priv = GET_ACCESSIBLE_PRIV (image);
2444 
2445 	g_free (priv->image_description);
2446 	priv->image_description = g_strdup (description);
2447 
2448 	return TRUE;
2449 }
2450 
2451 static void
2452 nautilus_canvas_item_accessible_image_interface_init (AtkImageIface *iface)
2453 {
2454 	iface->get_image_description = nautilus_canvas_item_accessible_get_image_description;
2455 	iface->set_image_description = nautilus_canvas_item_accessible_set_image_description;
2456 	iface->get_image_size        = nautilus_canvas_item_accessible_get_image_size;
2457 	iface->get_image_position    = nautilus_canvas_item_accessible_get_image_position;
2458 }
2459 
2460 /* accessible text interface */
2461 static gint
2462 nautilus_canvas_item_accessible_get_offset_at_point (AtkText	 *text,
2463 						     gint           x,
2464 						     gint           y,
2465 						     AtkCoordType coords)
2466 {
2467 	gint real_x, real_y, real_width, real_height;
2468 	NautilusCanvasItem *item;
2469 	gint editable_height;
2470 	gint offset = 0;
2471 	gint index;
2472 	PangoLayout *layout, *editable_layout, *additional_layout;
2473 	PangoRectangle rect0;
2474 	char *canvas_text;
2475 	gboolean have_editable;
2476 	gboolean have_additional;
2477 	gint text_offset;
2478 
2479 	atk_component_get_extents (ATK_COMPONENT (text), &real_x, &real_y,
2480                                    &real_width, &real_height, coords);
2481 
2482 	x -= real_x;
2483 	y -= real_y; 
2484 
2485 	item = NAUTILUS_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)));
2486 
2487 	if (item->details->pixbuf) {
2488 		y -= gdk_pixbuf_get_height (item->details->pixbuf);
2489 	}
2490 	have_editable = item->details->editable_text != NULL &&
2491 		item->details->editable_text[0] != '\0';
2492 	have_additional = item->details->additional_text != NULL &&item->details->additional_text[0] != '\0';
2493 
2494 	editable_layout = NULL;
2495 	additional_layout = NULL;
2496 	if (have_editable) {
2497 		editable_layout = get_label_layout (&item->details->editable_text_layout, item, item->details->editable_text);
2498 		prepare_pango_layout_for_draw (item, editable_layout);
2499 		pango_layout_get_pixel_size (editable_layout, NULL, &editable_height);
2500 		if (y >= editable_height &&
2501                     have_additional) {
2502 			prepare_pango_layout_for_draw (item, editable_layout);
2503 			additional_layout = get_label_layout (&item->details->additional_text_layout, item, item->details->additional_text);
2504 			layout = additional_layout;
2505 			canvas_text = item->details->additional_text;
2506 			y -= editable_height + LABEL_LINE_SPACING;
2507 		} else {
2508 			layout = editable_layout;
2509 			canvas_text = item->details->editable_text;
2510 		}
2511 	} else if (have_additional) {
2512 		additional_layout = get_label_layout (&item->details->additional_text_layout, item, item->details->additional_text);
2513 		prepare_pango_layout_for_draw (item, additional_layout);
2514 		layout = additional_layout;
2515 		canvas_text = item->details->additional_text;
2516 	} else {
2517 		return 0;
2518 	}
2519 
2520 	text_offset = 0;
2521 	if (have_editable) {
2522 		pango_layout_index_to_pos (editable_layout, 0, &rect0);
2523 		text_offset = PANGO_PIXELS (rect0.x);
2524 	}
2525 	if (have_additional) {
2526 		gint itmp;
2527 
2528 		pango_layout_index_to_pos (additional_layout, 0, &rect0);
2529 		itmp = PANGO_PIXELS (rect0.x);
2530 		if (itmp < text_offset) {
2531 			text_offset = itmp;
2532 		}
2533 	}
2534 	pango_layout_index_to_pos (layout, 0, &rect0);
2535 	x += text_offset;
2536 	if (!pango_layout_xy_to_index (layout, 
2537                                        x * PANGO_SCALE, 
2538                                        y * PANGO_SCALE, 
2539                                        &index, NULL)) {
2540 		if (x < 0 || y < 0) {
2541 			index = 0;
2542 		} else {
2543 			index = -1;
2544 		}
2545 	}
2546 	if (index == -1) {
2547 		offset = g_utf8_strlen (canvas_text, -1);
2548 	} else {
2549 		offset = g_utf8_pointer_to_offset (canvas_text, canvas_text + index);
2550 	}
2551 	if (layout == additional_layout) {
2552 		offset += g_utf8_strlen (item->details->editable_text, -1);	
2553 	}
2554 
2555 	if (editable_layout != NULL) {
2556 		g_object_unref (editable_layout);
2557 	}
2558 	
2559 	if (additional_layout != NULL) {
2560 		g_object_unref (additional_layout);
2561 	}
2562 	
2563 	return offset;
2564 }
2565 
2566 static void
2567 nautilus_canvas_item_accessible_get_character_extents (AtkText	   *text,
2568 						       gint	   offset,
2569 						       gint	   *x,
2570 						       gint	   *y,
2571 						       gint	   *width,
2572 						       gint	   *height,
2573 						       AtkCoordType coords)
2574 {
2575 	gint pos_x, pos_y;
2576 	gint len, byte_offset;
2577 	gint editable_height;
2578 	gchar *canvas_text;
2579 	NautilusCanvasItem *item;
2580 	PangoLayout *layout, *editable_layout, *additional_layout;
2581 	PangoRectangle rect;
2582 	PangoRectangle rect0;
2583 	gboolean have_editable;
2584 	gint text_offset;
2585 
2586 	atk_component_get_position (ATK_COMPONENT (text), &pos_x, &pos_y, coords);
2587 	item = NAUTILUS_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)));
2588 
2589 	if (item->details->pixbuf) {
2590 		pos_y += gdk_pixbuf_get_height (item->details->pixbuf);
2591 	}
2592 
2593 	have_editable = item->details->editable_text != NULL &&
2594 		item->details->editable_text[0] != '\0';
2595 	if (have_editable) {
2596 		len = g_utf8_strlen (item->details->editable_text, -1);
2597 	} else {
2598 		len = 0;
2599 	}
2600 
2601 	editable_layout = get_label_layout (&item->details->editable_text_layout, item, item->details->editable_text);
2602 	additional_layout = get_label_layout (&item->details->additional_text_layout, item, item->details->additional_text);
2603 	
2604 	if (offset < len) {
2605 		canvas_text = item->details->editable_text;
2606 		layout = editable_layout;
2607 	} else {
2608 		offset -= len;
2609 		canvas_text = item->details->additional_text;
2610 		layout = additional_layout;
2611 		pos_y += LABEL_LINE_SPACING;
2612 		if (have_editable) {
2613 			pango_layout_get_pixel_size (editable_layout, NULL, &editable_height);
2614 			pos_y += editable_height;
2615 		}
2616 	}
2617 	byte_offset = g_utf8_offset_to_pointer (canvas_text, offset) - canvas_text;
2618 	pango_layout_index_to_pos (layout, byte_offset, &rect);
2619 	text_offset = 0;
2620 	if (have_editable) {
2621 		pango_layout_index_to_pos (editable_layout, 0, &rect0);
2622 		text_offset = PANGO_PIXELS (rect0.x);
2623 	}
2624 	if (item->details->additional_text != NULL &&
2625 	    item->details->additional_text[0] != '\0') {
2626 		gint itmp;
2627 
2628 		pango_layout_index_to_pos (additional_layout, 0, &rect0);
2629 		itmp = PANGO_PIXELS (rect0.x);
2630 		if (itmp < text_offset) {
2631 			text_offset = itmp;
2632 		}
2633 	}
2634 
2635 	g_object_unref (editable_layout);
2636 	g_object_unref (additional_layout);
2637 
2638 	*x = pos_x + PANGO_PIXELS (rect.x) - text_offset;
2639 	*y = pos_y + PANGO_PIXELS (rect.y);
2640 	*width = PANGO_PIXELS (rect.width);
2641 	*height = PANGO_PIXELS (rect.height);
2642 }
2643 
2644 static void
2645 nautilus_canvas_item_accessible_text_interface_init (AtkTextIface *iface)
2646 {
2647  	iface->get_text                = eel_accessibility_text_get_text;
2648 	iface->get_character_at_offset = eel_accessibility_text_get_character_at_offset;
2649         iface->get_text_before_offset  = eel_accessibility_text_get_text_before_offset;
2650         iface->get_text_at_offset      = eel_accessibility_text_get_text_at_offset;
2651    	iface->get_text_after_offset   = eel_accessibility_text_get_text_after_offset;
2652       	iface->get_character_count     = eel_accessibility_text_get_character_count;
2653 	iface->get_character_extents   = nautilus_canvas_item_accessible_get_character_extents;
2654 	iface->get_offset_at_point     = nautilus_canvas_item_accessible_get_offset_at_point;
2655 }
2656 
2657 static GType nautilus_canvas_item_accessible_get_type (void);
2658 
2659 G_DEFINE_TYPE_WITH_CODE (NautilusCanvasItemAccessible,
2660 			 nautilus_canvas_item_accessible,
2661 			 eel_canvas_item_accessible_get_type (),
2662 			 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMAGE,
2663 						nautilus_canvas_item_accessible_image_interface_init)
2664 			 G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT,
2665 						nautilus_canvas_item_accessible_text_interface_init)
2666 			 G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION,
2667 						nautilus_canvas_item_accessible_action_interface_init));
2668 
2669 static AtkStateSet*
2670 nautilus_canvas_item_accessible_ref_state_set (AtkObject *accessible)
2671 {
2672 	AtkStateSet *state_set;
2673 	NautilusCanvasItem *item;
2674 	NautilusCanvasContainer *container;
2675 	NautilusCanvasIcon *icon;
2676 	GList *l;
2677 	gboolean one_item_selected;
2678 
2679 	state_set = ATK_OBJECT_CLASS (nautilus_canvas_item_accessible_parent_class)->ref_state_set (accessible);
2680 
2681 	item = NAUTILUS_CANVAS_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)));
2682 	if (!item) {
2683 		atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
2684 		return state_set;
2685 	}
2686 	container = NAUTILUS_CANVAS_CONTAINER (EEL_CANVAS_ITEM (item)->canvas);
2687 	if (item->details->is_highlighted_as_keyboard_focus) {
2688 		atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
2689 	} else if (!container->details->keyboard_focus) {
2690 
2691 		one_item_selected = FALSE;
2692 		l = container->details->icons;
2693 		while (l) {
2694 			icon = l->data;
2695 		
2696 			if (icon->item == item) {
2697 				if (icon->is_selected) {
2698 					one_item_selected = TRUE;
2699 				} else {
2700 					break;
2701 				}
2702 			} else if (icon->is_selected) {
2703 				one_item_selected = FALSE;
2704 				break;
2705 			}
2706 
2707 			l = l->next;
2708 		}
2709 
2710 		if (one_item_selected) {
2711 			atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
2712 		}
2713 	}
2714 
2715 	return state_set;
2716 }
2717 
2718 static void
2719 nautilus_canvas_item_accessible_finalize (GObject *object)
2720 {
2721 	NautilusCanvasItemAccessiblePrivate *priv;
2722 	int i;
2723 
2724 	priv = GET_ACCESSIBLE_PRIV (object);
2725 
2726 	for (i = 0; i < LAST_ACTION; i++) {
2727 		g_free (priv->action_descriptions[i]);
2728 	}
2729 	g_free (priv->image_description);
2730 	g_free (priv->description);
2731 
2732         G_OBJECT_CLASS (nautilus_canvas_item_accessible_parent_class)->finalize (object);
2733 }
2734 
2735 static void
2736 nautilus_canvas_item_accessible_initialize (AtkObject *accessible,
2737 					    gpointer widget)
2738 {
2739 	ATK_OBJECT_CLASS (nautilus_canvas_item_accessible_parent_class)->initialize (accessible, widget);
2740 
2741 	atk_object_set_role (accessible, ATK_ROLE_CANVAS);
2742 }
2743 
2744 static void
2745 nautilus_canvas_item_accessible_class_init (NautilusCanvasItemAccessibleClass *klass)
2746 {
2747 	AtkObjectClass *aclass = ATK_OBJECT_CLASS (klass);
2748 	GObjectClass *oclass = G_OBJECT_CLASS (klass);
2749 
2750 	oclass->finalize = nautilus_canvas_item_accessible_finalize;
2751 
2752 	aclass->initialize = nautilus_canvas_item_accessible_initialize;
2753 
2754 	aclass->get_name = nautilus_canvas_item_accessible_get_name;
2755 	aclass->get_description = nautilus_canvas_item_accessible_get_description;
2756 	aclass->get_parent = nautilus_canvas_item_accessible_get_parent;
2757 	aclass->get_index_in_parent = nautilus_canvas_item_accessible_get_index_in_parent;
2758 	aclass->ref_state_set = nautilus_canvas_item_accessible_ref_state_set;
2759 
2760 	g_type_class_add_private (klass, sizeof (NautilusCanvasItemAccessiblePrivate));
2761 }
2762 
2763 static void
2764 nautilus_canvas_item_accessible_init (NautilusCanvasItemAccessible *self)
2765 {
2766 	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, nautilus_canvas_item_accessible_get_type (),
2767 						  NautilusCanvasItemAccessiblePrivate);
2768 }
2769 
2770 /* dummy typedef */
2771 typedef AtkObjectFactory      NautilusCanvasItemAccessibleFactory;
2772 typedef AtkObjectFactoryClass NautilusCanvasItemAccessibleFactoryClass;
2773 
2774 G_DEFINE_TYPE (NautilusCanvasItemAccessibleFactory, nautilus_canvas_item_accessible_factory,
2775 	       ATK_TYPE_OBJECT_FACTORY);
2776 
2777 static AtkObject *
2778 nautilus_canvas_item_accessible_factory_create_accessible (GObject *for_object)
2779 {
2780 	AtkObject *accessible;
2781 	NautilusCanvasItem *item;
2782 	GString *item_text;
2783 
2784 	item = NAUTILUS_CANVAS_ITEM (for_object);
2785 	g_assert (item != NULL);
2786 
2787 	item_text = g_string_new (NULL);
2788 	if (item->details->editable_text) {
2789         	g_string_append (item_text, item->details->editable_text);
2790 	}
2791 	if (item->details->additional_text) {
2792         	g_string_append (item_text, item->details->additional_text);
2793 	}
2794 
2795 	item->details->text_util = gail_text_util_new ();
2796 	gail_text_util_text_setup (item->details->text_util,
2797 				   item_text->str);
2798 	g_string_free (item_text, TRUE);
2799 
2800 	accessible = g_object_new (nautilus_canvas_item_accessible_get_type (), NULL);
2801 	atk_object_initialize (accessible, for_object);
2802 
2803 	return accessible;
2804 }
2805 
2806 static GType
2807 nautilus_canvas_item_accessible_factory_get_accessible_type (void)
2808 {
2809 	return nautilus_canvas_item_accessible_get_type ();
2810 }
2811 
2812 static void
2813 nautilus_canvas_item_accessible_factory_init (NautilusCanvasItemAccessibleFactory *self)
2814 {
2815 }
2816 
2817 static void
2818 nautilus_canvas_item_accessible_factory_class_init (NautilusCanvasItemAccessibleFactoryClass *klass)
2819 {
2820 	klass->create_accessible = nautilus_canvas_item_accessible_factory_create_accessible;
2821 	klass->get_accessible_type = nautilus_canvas_item_accessible_factory_get_accessible_type;
2822 }