1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 /* Nautilus - Icon canvas item class for icon container.
5 * Copyright (C) 2000 Eazel, Inc
7 * Author: Andy Hertzfeld <andy@eazel.com>
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.
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.
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.
27 #include "nautilus-icon-canvas-item.h"
29 #include <glib/gi18n.h>
31 #include "nautilus-file-utilities.h"
32 #include "nautilus-global-preferences.h"
33 #include "nautilus-icon-private.h"
34 #include <eel/eel-art-extensions.h>
35 #include <eel/eel-gdk-extensions.h>
36 #include <eel/eel-gdk-pixbuf-extensions.h>
37 #include <eel/eel-glib-extensions.h>
38 #include <eel/eel-gnome-extensions.h>
39 #include <eel/eel-graphic-effects.h>
40 #include <eel/eel-gtk-macros.h>
41 #include <eel/eel-pango-extensions.h>
42 #include <eel/eel-string.h>
43 #include <eel/eel-accessibility.h>
44 #include <gdk-pixbuf/gdk-pixbuf.h>
45 #include <gtk/gtksignal.h>
47 #include <librsvg/rsvg.h>
48 #include <glib/gi18n.h>
49 #include <eel/eel-canvas-util.h>
50 #include <atk/atkimage.h>
51 #include <atk/atkcomponent.h>
52 #include <atk/atknoopobject.h>
56 #define EMBLEM_SPACING 2
58 /* gap between bottom of icon and start of text box */
59 #define LABEL_OFFSET 1
60 #define LABEL_LINE_SPACING 0
62 #define MAX_TEXT_WIDTH_STANDARD 135
63 #define MAX_TEXT_WIDTH_TIGHTER 80
64 #define MAX_TEXT_WIDTH_BESIDE 90
66 /* Private part of the NautilusIconCanvasItem structure. */
67 struct NautilusIconCanvasItemDetails
{
68 /* The image, text, font. */
71 GdkPixbuf
*rendered_pixbuf
;
72 GList
*emblem_pixbufs
;
73 char *editable_text
; /* Text that can be modified by a renaming function */
74 char *additional_text
; /* Text that cannot be modifed, such as file size, etc. */
75 GdkPoint
*attach_points
;
78 /* Size of the text at current font. */
86 /* Highlight state. */
87 guint is_highlighted_for_selection
: 1;
88 guint is_highlighted_as_keyboard_focus
: 1;
89 guint is_highlighted_for_drop
: 1;
90 guint show_stretch_handles
: 1;
93 guint rendered_is_active
: 1;
94 guint rendered_is_highlighted_for_selection
: 1;
95 guint rendered_is_highlighted_for_drop
: 1;
96 guint rendered_is_prelit
: 1;
97 guint rendered_is_focused
: 1;
99 guint is_renaming
: 1;
101 guint bounds_cached
: 1;
103 guint is_visible
: 1;
105 GdkRectangle embedded_text_rect
;
108 /* Cached PangoLayouts. Only used if the icon is visible */
109 PangoLayout
*editable_text_layout
;
110 PangoLayout
*additional_text_layout
;
111 PangoLayout
*embedded_text_layout
;
113 /* Cached rectangle in canvas coordinates */
114 EelIRect canvas_rect
;
116 EelIRect emblem_rect
;
118 EelIRect bounds_cache
;
120 /* Accessibility bits */
121 GailTextUtil
*text_util
;
124 /* Object argument IDs. */
128 PROP_ADDITIONAL_TEXT
,
129 PROP_HIGHLIGHTED_FOR_SELECTION
,
130 PROP_HIGHLIGHTED_AS_KEYBOARD_FOCUS
,
131 PROP_HIGHLIGHTED_FOR_DROP
148 char *action_descriptions
[LAST_ACTION
];
149 char *image_description
;
151 } NautilusIconCanvasItemAccessiblePrivate
;
154 NautilusIconCanvasItem
*item
;
156 } NautilusIconCanvasItemAccessibleActionContext
;
159 NautilusIconCanvasItem
*icon_item
;
167 static int click_policy_auto_value
;
170 static void nautilus_icon_canvas_item_class_init (NautilusIconCanvasItemClass
*class);
171 static void nautilus_icon_canvas_item_init (NautilusIconCanvasItem
*item
);
174 static void draw_or_measure_label_text (NautilusIconCanvasItem
*item
,
175 GdkDrawable
*drawable
,
176 gboolean create_mask
,
178 static void draw_label_text (NautilusIconCanvasItem
*item
,
179 GdkDrawable
*drawable
,
180 gboolean create_mask
,
182 static void measure_label_text (NautilusIconCanvasItem
*item
);
183 static void get_icon_canvas_rectangle (NautilusIconCanvasItem
*item
,
185 static void emblem_layout_reset (EmblemLayout
*layout
,
186 NautilusIconCanvasItem
*icon_item
,
189 static gboolean
emblem_layout_next (EmblemLayout
*layout
,
190 GdkPixbuf
**emblem_pixbuf
,
191 EelIRect
*emblem_rect
,
193 static void draw_pixbuf (GdkPixbuf
*pixbuf
,
194 GdkDrawable
*drawable
,
197 static PangoLayout
*get_label_layout (PangoLayout
**layout
,
198 NautilusIconCanvasItem
*item
,
200 static void draw_label_layout (NautilusIconCanvasItem
*item
,
201 GdkDrawable
*drawable
,
204 GdkColor
*label_color
,
208 static gboolean
hit_test_stretch_handle (NautilusIconCanvasItem
*item
,
209 EelIRect canvas_rect
,
210 GtkCornerType
*corner
);
211 static void draw_embedded_text (NautilusIconCanvasItem
*icon_item
,
212 GdkDrawable
*drawable
,
216 static GdkPixbuf
*nautilus_icon_canvas_lighten_pixbuf (GdkPixbuf
* src
, guint lighten_value
);
219 static NautilusIconCanvasItemClass
*parent_class
= NULL
;
220 static gpointer accessible_parent_class
= NULL
;
222 static GQuark accessible_private_data_quark
= 0;
224 static const char *nautilus_icon_canvas_item_accessible_action_names
[] = {
230 static const char *nautilus_icon_canvas_item_accessible_action_descriptions
[] = {
232 "Popup context menu",
237 /* Object initialization function for the icon item. */
239 nautilus_icon_canvas_item_init (NautilusIconCanvasItem
*icon_item
)
241 static gboolean setup_auto_enums
= FALSE
;
243 if (!setup_auto_enums
) {
244 eel_preferences_add_auto_enum
245 (NAUTILUS_PREFERENCES_CLICK_POLICY
,
246 &click_policy_auto_value
);
247 setup_auto_enums
= TRUE
;
250 icon_item
->details
= G_TYPE_INSTANCE_GET_PRIVATE ((icon_item
), NAUTILUS_TYPE_ICON_CANVAS_ITEM
, NautilusIconCanvasItemDetails
);
251 nautilus_icon_canvas_item_invalidate_label_size (icon_item
);
255 nautilus_icon_canvas_item_finalize (GObject
*object
)
257 NautilusIconCanvasItemDetails
*details
;
259 g_return_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (object
));
261 details
= NAUTILUS_ICON_CANVAS_ITEM (object
)->details
;
263 if (details
->pixbuf
!= NULL
) {
264 g_object_unref (details
->pixbuf
);
267 if (details
->text_util
!= NULL
) {
268 g_object_unref (details
->text_util
);
271 eel_gdk_pixbuf_list_free (details
->emblem_pixbufs
);
272 g_free (details
->editable_text
);
273 g_free (details
->additional_text
);
274 g_free (details
->attach_points
);
276 if (details
->rendered_pixbuf
!= NULL
) {
277 g_object_unref (details
->rendered_pixbuf
);
280 if (details
->editable_text_layout
!= NULL
) {
281 g_object_unref (details
->editable_text_layout
);
284 if (details
->additional_text_layout
!= NULL
) {
285 g_object_unref (details
->additional_text_layout
);
288 if (details
->embedded_text_layout
!= NULL
) {
289 g_object_unref (details
->embedded_text_layout
);
292 g_free (details
->embedded_text
);
294 EEL_CALL_PARENT (G_OBJECT_CLASS
, finalize
, (object
));
297 /* Currently we require pixbufs in this format (for hit testing).
298 * Perhaps gdk-pixbuf will be changed so it can do the hit testing
299 * and we won't have this requirement any more.
302 pixbuf_is_acceptable (GdkPixbuf
*pixbuf
)
304 return gdk_pixbuf_get_colorspace (pixbuf
) == GDK_COLORSPACE_RGB
305 && ((!gdk_pixbuf_get_has_alpha (pixbuf
)
306 && gdk_pixbuf_get_n_channels (pixbuf
) == 3)
307 || (gdk_pixbuf_get_has_alpha (pixbuf
)
308 && gdk_pixbuf_get_n_channels (pixbuf
) == 4))
309 && gdk_pixbuf_get_bits_per_sample (pixbuf
) == 8;
313 nautilus_icon_canvas_item_invalidate_bounds_cache (NautilusIconCanvasItem
*item
)
315 item
->details
->bounds_cached
= FALSE
;
318 /* invalidate the text width and height cached in the item details. */
320 nautilus_icon_canvas_item_invalidate_label_size (NautilusIconCanvasItem
*item
)
322 nautilus_icon_canvas_item_invalidate_bounds_cache (item
);
323 item
->details
->text_width
= -1;
324 item
->details
->text_height
= -1;
325 if (item
->details
->editable_text_layout
!= NULL
) {
326 g_object_unref (item
->details
->editable_text_layout
);
327 item
->details
->editable_text_layout
= NULL
;
329 if (item
->details
->additional_text_layout
!= NULL
) {
330 g_object_unref (item
->details
->additional_text_layout
);
331 item
->details
->additional_text_layout
= NULL
;
335 /* Set property handler for the icon item. */
337 nautilus_icon_canvas_item_set_property (GObject
*object
,
342 NautilusIconCanvasItem
*item
;
343 NautilusIconCanvasItemDetails
*details
;
345 item
= NAUTILUS_ICON_CANVAS_ITEM (object
);
346 details
= item
->details
;
348 switch (property_id
) {
350 case PROP_EDITABLE_TEXT
:
351 if (eel_strcmp (details
->editable_text
,
352 g_value_get_string (value
)) == 0) {
356 g_free (details
->editable_text
);
357 details
->editable_text
= g_strdup (g_value_get_string (value
));
358 if (details
->text_util
) {
359 AtkObject
*accessible
;
361 gail_text_util_text_setup (details
->text_util
,
362 details
->editable_text
);
363 accessible
= eel_accessibility_get_atk_object (item
);
364 g_object_notify (G_OBJECT(accessible
), "accessible-name");
367 nautilus_icon_canvas_item_invalidate_label_size (item
);
370 case PROP_ADDITIONAL_TEXT
:
371 if (eel_strcmp (details
->additional_text
,
372 g_value_get_string (value
)) == 0) {
376 g_free (details
->additional_text
);
377 details
->additional_text
= g_strdup (g_value_get_string (value
));
379 nautilus_icon_canvas_item_invalidate_label_size (item
);
382 case PROP_HIGHLIGHTED_FOR_SELECTION
:
383 if (!details
->is_highlighted_for_selection
== !g_value_get_boolean (value
)) {
386 details
->is_highlighted_for_selection
= g_value_get_boolean (value
);
389 case PROP_HIGHLIGHTED_AS_KEYBOARD_FOCUS
:
390 if (!details
->is_highlighted_as_keyboard_focus
== !g_value_get_boolean (value
)) {
393 details
->is_highlighted_as_keyboard_focus
= g_value_get_boolean (value
);
395 if (details
->is_highlighted_as_keyboard_focus
) {
396 AtkObject
*atk_object
= eel_accessibility_for_object (object
);
397 atk_focus_tracker_notify (atk_object
);
401 case PROP_HIGHLIGHTED_FOR_DROP
:
402 if (!details
->is_highlighted_for_drop
== !g_value_get_boolean (value
)) {
405 details
->is_highlighted_for_drop
= g_value_get_boolean (value
);
409 g_warning ("nautilus_icons_view_item_item_set_arg on unknown argument");
413 eel_canvas_item_request_update (EEL_CANVAS_ITEM (object
));
416 /* Get property handler for the icon item */
418 nautilus_icon_canvas_item_get_property (GObject
*object
,
423 NautilusIconCanvasItemDetails
*details
;
425 details
= NAUTILUS_ICON_CANVAS_ITEM (object
)->details
;
427 switch (property_id
) {
429 case PROP_EDITABLE_TEXT
:
430 g_value_set_string (value
, details
->editable_text
);
433 case PROP_ADDITIONAL_TEXT
:
434 g_value_set_string (value
, details
->additional_text
);
437 case PROP_HIGHLIGHTED_FOR_SELECTION
:
438 g_value_set_boolean (value
, details
->is_highlighted_for_selection
);
441 case PROP_HIGHLIGHTED_AS_KEYBOARD_FOCUS
:
442 g_value_set_boolean (value
, details
->is_highlighted_as_keyboard_focus
);
445 case PROP_HIGHLIGHTED_FOR_DROP
:
446 g_value_set_boolean (value
, details
->is_highlighted_for_drop
);
450 g_warning ("invalid property %d", property_id
);
456 nautilus_icon_canvas_item_get_image (NautilusIconCanvasItem
*item
,
458 GdkColormap
*colormap
)
465 int item_offset_x
, item_offset_y
;
467 EelIRect emblem_rect
;
469 GdkPixbuf
*emblem_pixbuf
;
470 EmblemLayout emblem_layout
;
471 double item_x
, item_y
;
475 g_return_val_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (item
), NULL
);
477 canvas
= EEL_CANVAS_ITEM (item
)->canvas
;
478 screen
= gdk_colormap_get_screen (colormap
);
480 /* Assume we're updated so canvas item data is right */
482 /* Calculate the offset from the top-left corner of the
483 new image to the item position (where the pixmap is placed) */
484 eel_canvas_world_to_window (canvas
,
485 item
->details
->x
, item
->details
->y
,
488 item_offset_x
= item_x
- EEL_CANVAS_ITEM (item
)->x1
;
489 item_offset_y
= item_y
- EEL_CANVAS_ITEM (item
)->y1
;
491 /* Calculate the width of the item */
492 width
= EEL_CANVAS_ITEM (item
)->x2
- EEL_CANVAS_ITEM (item
)->x1
;
493 height
= EEL_CANVAS_ITEM (item
)->y2
- EEL_CANVAS_ITEM (item
)->y1
;
495 pixmap
= gdk_pixmap_new (gdk_screen_get_root_window (screen
),
497 gdk_colormap_get_visual (colormap
)->depth
);
498 gdk_drawable_set_colormap (GDK_DRAWABLE (pixmap
), colormap
);
500 pixbuf
= gdk_pixbuf_new (GDK_COLORSPACE_RGB
,
502 gdk_pixbuf_get_bits_per_sample (item
->details
->pixbuf
),
504 gdk_pixbuf_fill (pixbuf
, 0x00000000);
506 gdk_pixbuf_composite (item
->details
->pixbuf
, pixbuf
,
507 item_offset_x
, item_offset_y
,
508 gdk_pixbuf_get_width (item
->details
->pixbuf
),
509 gdk_pixbuf_get_height (item
->details
->pixbuf
),
510 item_offset_x
, item_offset_y
, 1.0, 1.0,
511 GDK_INTERP_BILINEAR
, 255);
513 icon_rect
.x0
= item_offset_x
;
514 icon_rect
.y0
= item_offset_y
;
515 icon_rect
.x1
= item_offset_x
+ gdk_pixbuf_get_width (item
->details
->pixbuf
);
516 icon_rect
.y1
= item_offset_y
+ gdk_pixbuf_get_height (item
->details
->pixbuf
);
519 is_rtl
= nautilus_icon_container_is_layout_rtl (NAUTILUS_ICON_CONTAINER (canvas
));
521 emblem_layout_reset (&emblem_layout
, item
, icon_rect
, is_rtl
);
522 while (emblem_layout_next (&emblem_layout
, &emblem_pixbuf
, &emblem_rect
, is_rtl
)) {
523 gdk_pixbuf_composite (emblem_pixbuf
, pixbuf
,
524 emblem_rect
.x0
, emblem_rect
.y0
,
525 gdk_pixbuf_get_width (emblem_pixbuf
),
526 gdk_pixbuf_get_height (emblem_pixbuf
),
527 emblem_rect
.x0
, emblem_rect
.y0
,
529 GDK_INTERP_BILINEAR
, 255);
532 /* clear the pixmap */
533 cr
= gdk_cairo_create (pixmap
);
534 cairo_set_operator (cr
, CAIRO_OPERATOR_CLEAR
);
538 gc
= gdk_gc_new (pixmap
);
539 gdk_draw_pixbuf (pixmap
, gc
, pixbuf
,
541 gdk_pixbuf_get_width (pixbuf
), gdk_pixbuf_get_height (pixbuf
),
542 GDK_RGB_DITHER_NORMAL
,
546 *mask
= gdk_pixmap_new (gdk_screen_get_root_window (screen
),
549 gc
= gdk_gc_new (*mask
);
550 gdk_draw_rectangle (*mask
, gc
,
556 gdk_pixbuf_render_threshold_alpha (pixbuf
, *mask
,
558 gdk_pixbuf_get_width (pixbuf
), gdk_pixbuf_get_height (pixbuf
),
561 draw_embedded_text (item
, GDK_DRAWABLE (pixmap
),
562 item_offset_x
, item_offset_y
);
564 draw_label_text (item
, GDK_DRAWABLE (pixmap
), FALSE
, icon_rect
);
565 draw_label_text (item
, GDK_DRAWABLE (*mask
), TRUE
, icon_rect
);
567 gdk_pixbuf_unref (pixbuf
);
573 nautilus_icon_canvas_item_set_image (NautilusIconCanvasItem
*item
,
576 NautilusIconCanvasItemDetails
*details
;
578 g_return_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (item
));
579 g_return_if_fail (image
== NULL
|| pixbuf_is_acceptable (image
));
581 details
= item
->details
;
582 if (details
->pixbuf
== image
) {
587 g_object_ref (image
);
589 if (details
->pixbuf
!= NULL
) {
590 g_object_unref (details
->pixbuf
);
592 if (details
->rendered_pixbuf
!= NULL
) {
593 g_object_unref (details
->rendered_pixbuf
);
594 details
->rendered_pixbuf
= NULL
;
597 details
->pixbuf
= image
;
599 nautilus_icon_canvas_item_invalidate_bounds_cache (item
);
600 eel_canvas_item_request_update (EEL_CANVAS_ITEM (item
));
604 nautilus_icon_canvas_item_set_emblems (NautilusIconCanvasItem
*item
,
605 GList
*emblem_pixbufs
)
609 g_return_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (item
));
611 g_assert (item
->details
->emblem_pixbufs
!= emblem_pixbufs
|| emblem_pixbufs
== NULL
);
613 /* The case where the emblems are identical is fairly common,
614 * so lets take the time to check for it.
616 if (eel_g_list_equal (item
->details
->emblem_pixbufs
, emblem_pixbufs
)) {
620 /* Check if they are acceptable. */
621 for (p
= emblem_pixbufs
; p
!= NULL
; p
= p
->next
) {
622 g_return_if_fail (pixbuf_is_acceptable (p
->data
));
625 /* Take in the new list of emblems. */
626 eel_gdk_pixbuf_list_ref (emblem_pixbufs
);
627 eel_gdk_pixbuf_list_free (item
->details
->emblem_pixbufs
);
628 item
->details
->emblem_pixbufs
= g_list_copy (emblem_pixbufs
);
630 nautilus_icon_canvas_item_invalidate_bounds_cache (item
);
631 eel_canvas_item_request_update (EEL_CANVAS_ITEM (item
));
635 nautilus_icon_canvas_item_set_attach_points (NautilusIconCanvasItem
*item
,
636 GdkPoint
*attach_points
,
639 g_free (item
->details
->attach_points
);
640 item
->details
->attach_points
= NULL
;
641 item
->details
->n_attach_points
= 0;
643 if (attach_points
!= NULL
&& n_attach_points
!= 0) {
644 item
->details
->attach_points
= g_memdup (attach_points
, n_attach_points
* sizeof (GdkPoint
));
645 item
->details
->n_attach_points
= n_attach_points
;
648 nautilus_icon_canvas_item_invalidate_bounds_cache (item
);
652 nautilus_icon_canvas_item_set_embedded_text_rect (NautilusIconCanvasItem
*item
,
653 const GdkRectangle
*text_rect
)
655 item
->details
->embedded_text_rect
= *text_rect
;
657 nautilus_icon_canvas_item_invalidate_bounds_cache (item
);
658 eel_canvas_item_request_update (EEL_CANVAS_ITEM (item
));
662 nautilus_icon_canvas_item_set_embedded_text (NautilusIconCanvasItem
*item
,
665 g_free (item
->details
->embedded_text
);
666 item
->details
->embedded_text
= g_strdup (text
);
668 if (item
->details
->embedded_text_layout
!= NULL
) {
670 pango_layout_set_text (item
->details
->embedded_text_layout
, text
, -1);
672 pango_layout_set_text (item
->details
->embedded_text_layout
, "", -1);
676 eel_canvas_item_request_update (EEL_CANVAS_ITEM (item
));
680 /* Recomputes the bounding box of a icon canvas item.
681 * This is a generic implementation that could be used for any canvas item
682 * class, it has no assumptions about how the item is used.
685 recompute_bounding_box (NautilusIconCanvasItem
*icon_item
,
686 double i2w_dx
, double i2w_dy
)
688 /* The bounds stored in the item is the same as what get_bounds
689 * returns, except it's in canvas coordinates instead of the item's
690 * parent's coordinates.
694 EelDPoint top_left
, bottom_right
;
696 item
= EEL_CANVAS_ITEM (icon_item
);
698 eel_canvas_item_get_bounds (item
,
699 &top_left
.x
, &top_left
.y
,
700 &bottom_right
.x
, &bottom_right
.y
);
702 top_left
.x
+= i2w_dx
;
703 top_left
.y
+= i2w_dy
;
704 bottom_right
.x
+= i2w_dx
;
705 bottom_right
.y
+= i2w_dy
;
706 eel_canvas_w2c_d (item
->canvas
,
707 top_left
.x
, top_left
.y
,
708 &item
->x1
, &item
->y1
);
709 eel_canvas_w2c_d (item
->canvas
,
710 bottom_right
.x
, bottom_right
.y
,
711 &item
->x2
, &item
->y2
);
715 compute_text_rectangle (const NautilusIconCanvasItem
*item
,
716 EelIRect icon_rectangle
,
717 gboolean canvas_coords
)
719 EelIRect text_rectangle
;
720 double pixels_per_unit
;
721 double text_width
, text_height
, text_dx
;
723 pixels_per_unit
= EEL_CANVAS_ITEM (item
)->canvas
->pixels_per_unit
;
725 text_width
= item
->details
->text_width
;
726 text_height
= item
->details
->text_height
;
727 text_dx
= item
->details
->text_dx
;
729 text_width
= item
->details
->text_width
/ pixels_per_unit
;
730 text_height
= item
->details
->text_height
/ pixels_per_unit
;
731 text_dx
= item
->details
->text_dx
/ pixels_per_unit
;
734 if (NAUTILUS_ICON_CONTAINER (EEL_CANVAS_ITEM (item
)->canvas
)->details
->label_position
== NAUTILUS_ICON_LABEL_POSITION_BESIDE
) {
735 if (!nautilus_icon_container_is_layout_rtl (NAUTILUS_ICON_CONTAINER (EEL_CANVAS_ITEM (item
)->canvas
))) {
736 text_rectangle
.x0
= icon_rectangle
.x1
;
737 text_rectangle
.x1
= text_rectangle
.x0
+ text_dx
+ text_width
;
739 text_rectangle
.x1
= icon_rectangle
.x0
;
740 text_rectangle
.x0
= text_rectangle
.x1
- text_dx
- text_width
;
742 text_rectangle
.y0
= (icon_rectangle
.y0
+ icon_rectangle
.y1
) / 2- (int) text_height
/ 2;
743 text_rectangle
.y1
= text_rectangle
.y0
+ text_height
+ LABEL_OFFSET
/ pixels_per_unit
;
745 text_rectangle
.x0
= (icon_rectangle
.x0
+ icon_rectangle
.x1
) / 2 - (int) text_width
/ 2;
746 text_rectangle
.y0
= icon_rectangle
.y1
;
747 text_rectangle
.x1
= text_rectangle
.x0
+ text_width
;
748 text_rectangle
.y1
= text_rectangle
.y0
+ text_height
+ LABEL_OFFSET
/ pixels_per_unit
;
751 return text_rectangle
;
755 get_current_canvas_bounds (EelCanvasItem
*item
)
759 g_return_val_if_fail (EEL_IS_CANVAS_ITEM (item
), eel_irect_empty
);
761 bounds
.x0
= item
->x1
;
762 bounds
.y0
= item
->y1
;
763 bounds
.x1
= item
->x2
;
764 bounds
.y1
= item
->y2
;
770 nautilus_icon_canvas_item_update_bounds (NautilusIconCanvasItem
*item
,
771 double i2w_dx
, double i2w_dy
)
773 EelIRect before
, after
, emblem_rect
;
774 EmblemLayout emblem_layout
;
775 EelCanvasItem
*canvas_item
;
776 GdkPixbuf
*emblem_pixbuf
;
779 canvas_item
= EEL_CANVAS_ITEM (item
);
781 /* Compute new bounds. */
782 before
= get_current_canvas_bounds (canvas_item
);
783 recompute_bounding_box (item
, i2w_dx
, i2w_dy
);
784 after
= get_current_canvas_bounds (canvas_item
);
786 /* If the bounds didn't change, we are done. */
787 if (eel_irect_equal (before
, after
)) {
791 is_rtl
= nautilus_icon_container_is_layout_rtl (NAUTILUS_ICON_CONTAINER (canvas_item
->canvas
));
793 /* Update canvas and text rect cache */
794 get_icon_canvas_rectangle (item
, &item
->details
->canvas_rect
);
795 item
->details
->text_rect
= compute_text_rectangle (item
, item
->details
->canvas_rect
, TRUE
);
797 /* Update emblem rect cache */
798 item
->details
->emblem_rect
.x0
= 0;
799 item
->details
->emblem_rect
.x1
= 0;
800 item
->details
->emblem_rect
.y0
= 0;
801 item
->details
->emblem_rect
.y1
= 0;
802 emblem_layout_reset (&emblem_layout
, item
, item
->details
->canvas_rect
, is_rtl
);
803 while (emblem_layout_next (&emblem_layout
, &emblem_pixbuf
, &emblem_rect
, is_rtl
)) {
804 eel_irect_union (&item
->details
->emblem_rect
, &item
->details
->emblem_rect
, &emblem_rect
);
807 /* queue a redraw. */
808 eel_canvas_request_redraw (canvas_item
->canvas
,
809 before
.x0
, before
.y0
,
810 before
.x1
+ 1, before
.y1
+ 1);
813 /* Update handler for the icon canvas item. */
815 nautilus_icon_canvas_item_update (EelCanvasItem
*item
,
816 double i2w_dx
, double i2w_dy
,
819 nautilus_icon_canvas_item_update_bounds (NAUTILUS_ICON_CANVAS_ITEM (item
), i2w_dx
, i2w_dy
);
821 eel_canvas_item_request_redraw (EEL_CANVAS_ITEM (item
));
823 EEL_CALL_PARENT (EEL_CANVAS_ITEM_CLASS
, update
,
824 (item
, i2w_dx
, i2w_dy
, flags
));
829 in_single_click_mode (void)
831 return click_policy_auto_value
== NAUTILUS_CLICK_POLICY_SINGLE
;
835 /* Utility routine to create a rectangle with rounded corners.
836 * This could possibly move to Eel as a general purpose routine.
839 make_round_rect (cairo_t
*cr
,
849 height
-= 2 * radius
;
851 cairo_move_to (cr
, x
+ radius
, y
);
853 cairo_rel_line_to (cr
, width
, 0.0);
855 cairo_get_current_point (cr
, &cx
, &cy
);
856 cairo_arc (cr
, cx
, cy
+ radius
, radius
, 3.0 * G_PI_2
, 0);
858 cairo_rel_line_to (cr
, 0.0, height
);
860 cairo_get_current_point (cr
, &cx
, &cy
);
861 cairo_arc (cr
, cx
- radius
, cy
, radius
, 0, G_PI_2
);
863 cairo_rel_line_to (cr
, - width
, 0.0);
865 cairo_get_current_point (cr
, &cx
, &cy
);
866 cairo_arc (cr
, cx
, cy
- radius
, radius
, G_PI_2
, G_PI
);
868 cairo_rel_line_to (cr
, 0.0, -height
);
870 cairo_get_current_point (cr
, &cx
, &cy
);
871 cairo_arc (cr
, cx
+ radius
, cy
, radius
, G_PI
, 3.0 * G_PI_2
);
873 cairo_close_path (cr
);
877 draw_frame (NautilusIconCanvasItem
*item
,
878 GdkDrawable
*drawable
,
880 gboolean create_mask
,
886 NautilusIconContainer
*container
;
889 container
= NAUTILUS_ICON_CONTAINER (EEL_CANVAS_ITEM (item
)->canvas
);
891 /* Get a cairo context */
892 cr
= gdk_cairo_create (drawable
);
894 /* Set the rounded rect clip region. Magic rounding value taken
897 make_round_rect (cr
, x
, y
, width
, height
, 5);
900 /* Dunno how to do this with cairo...
901 * It used to threshold the rendering so that the
902 * bitmask didn't show white where alpha < 0.5
906 cairo_set_source_rgba (cr
,
907 EEL_RGBA_COLOR_GET_R (color
) / 255.0,
908 EEL_RGBA_COLOR_GET_G (color
) / 255.0,
909 EEL_RGBA_COLOR_GET_B (color
) / 255.0,
910 EEL_RGBA_COLOR_GET_A (color
) / 255.0);
912 /* Paint into drawable now that we have set up the color and opacity */
915 /* Clean up now that drawing is complete */
919 /* Keep these for a bit while we work on performance of draw_or_measure_label_text. */
921 #define PERFORMANCE_TEST_DRAW_DISABLE
922 #define PERFORMANCE_TEST_MEASURE_DISABLE
925 /* This gets the size of the layout from the position of the layout.
926 * This means that if the layout is right aligned we get the full width
927 * of the layout, not just the width of the text snippet on the right side
930 layout_get_full_size (PangoLayout
*layout
,
935 PangoRectangle logical_rect
;
938 pango_layout_get_extents (layout
, NULL
, &logical_rect
);
939 *width
= (logical_rect
.width
+ PANGO_SCALE
/ 2) / PANGO_SCALE
;
940 total_width
= (logical_rect
.x
+ logical_rect
.width
+ PANGO_SCALE
/ 2) / PANGO_SCALE
;
941 *dx
= total_width
- *width
;
942 *height
= (logical_rect
.height
+ PANGO_SCALE
/ 2) / PANGO_SCALE
;
947 draw_or_measure_label_text (NautilusIconCanvasItem
*item
,
948 GdkDrawable
*drawable
,
949 gboolean create_mask
,
952 NautilusIconCanvasItemDetails
*details
;
953 NautilusIconContainer
*container
;
954 gint editable_height
, editable_width
, editable_dx
;
955 gint additional_height
, additional_width
, additional_dx
;
956 EelCanvasItem
*canvas_item
;
957 PangoLayout
*editable_layout
;
958 PangoLayout
*additional_layout
;
959 GdkColor
*label_color
;
961 gboolean have_editable
, have_additional
, needs_highlight
, needs_frame
, prelight_label
, is_rtl_label_beside
;
966 int text_back_padding_x
, text_back_padding_y
;
971 details
= item
->details
;
972 needs_highlight
= details
->is_highlighted_for_selection
|| details
->is_highlighted_for_drop
;
974 have_editable
= details
->editable_text
!= NULL
&& details
->editable_text
[0] != '\0';
975 have_additional
= details
->additional_text
!= NULL
&& details
->additional_text
[0] != '\0';
977 /* No font or no text, then do no work. */
978 if (!have_editable
&& !have_additional
) {
979 details
->text_height
= 0;
980 details
->text_width
= 0;
984 #if (defined PERFORMANCE_TEST_MEASURE_DISABLE && defined PERFORMANCE_TEST_DRAW_DISABLE)
985 /* don't do any drawing and fake out the width */
986 details
->text_width
= 80;
987 details
->text_height
= 20;
991 #ifdef PERFORMANCE_TEST_MEASURE_DISABLE
992 if (drawable
== NULL
) {
993 /* fake out the width */
994 details
->text_width
= 80;
995 details
->text_height
= 20;
1000 #ifdef PERFORMANCE_TEST_DRAW_DISABLE
1001 if (drawable
!= NULL
) {
1006 canvas_item
= EEL_CANVAS_ITEM (item
);
1007 if (drawable
!= NULL
) {
1008 icon_width
= details
->pixbuf
== NULL
? 0 : gdk_pixbuf_get_width (details
->pixbuf
);
1012 editable_height
= 0;
1014 additional_width
= 0;
1015 additional_height
= 0;
1018 max_text_width
= floor (nautilus_icon_canvas_item_get_max_text_width (item
));
1020 container
= NAUTILUS_ICON_CONTAINER (EEL_CANVAS_ITEM (item
)->canvas
);
1021 editable_layout
= NULL
;
1022 additional_layout
= NULL
;
1024 if (have_editable
) {
1025 editable_layout
= get_label_layout (&details
->editable_text_layout
, item
, details
->editable_text
);
1026 layout_get_full_size (editable_layout
, &editable_width
, &editable_height
, &editable_dx
);
1029 if (have_additional
) {
1030 additional_layout
= get_label_layout (&details
->additional_text_layout
, item
, details
->additional_text
);
1031 layout_get_full_size (additional_layout
, &additional_width
, &additional_height
, &additional_dx
);
1034 if (editable_width
> additional_width
) {
1035 details
->text_width
= editable_width
;
1036 details
->text_dx
= editable_dx
;
1038 details
->text_width
= additional_width
;
1039 details
->text_dx
= additional_dx
;
1042 if (have_additional
) {
1043 details
->text_height
= editable_height
+ LABEL_LINE_SPACING
+ additional_height
;
1045 details
->text_height
= editable_height
;
1048 /* add some extra space for highlighting even when we don't highlight so things won't move */
1049 text_back_padding_x
= 4;
1050 text_back_padding_y
= 1;
1052 details
->text_height
+= text_back_padding_y
*2; /* extra slop for nicer highlighting */
1053 details
->text_width
+= text_back_padding_x
*2; /* extra to make it look nicer */
1055 /* if measuring, we are done */
1057 if (editable_layout
) {
1058 g_object_unref (editable_layout
);
1061 if (additional_layout
) {
1062 g_object_unref (additional_layout
);
1068 text_rect
= compute_text_rectangle (item
, icon_rect
, TRUE
);
1070 is_rtl_label_beside
= nautilus_icon_container_is_layout_rtl (container
) &&
1071 container
->details
->label_position
== NAUTILUS_ICON_LABEL_POSITION_BESIDE
;
1073 /* if the icon is highlighted, do some set-up */
1074 if (needs_highlight
&& !details
->is_renaming
&&
1075 details
->text_width
> 0 && details
->text_height
> 0) {
1078 GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (container
)) ? container
->details
->highlight_color_rgba
: container
->details
->active_color_rgba
,
1080 is_rtl_label_beside
? text_rect
.x0
+ item
->details
->text_dx
: text_rect
.x0
,
1082 is_rtl_label_beside
? text_rect
.x1
- text_rect
.x0
- item
->details
->text_dx
: text_rect
.x1
- text_rect
.x0
,
1083 text_rect
.y1
- text_rect
.y0
);
1086 if (container
->details
->label_position
== NAUTILUS_ICON_LABEL_POSITION_BESIDE
) {
1087 x
= text_rect
.x0
+ 2;
1089 x
= text_rect
.x0
+ ((text_rect
.x1
- text_rect
.x0
) - max_text_width
) / 2;
1092 if (have_editable
) {
1093 gtk_widget_style_get (GTK_WIDGET (container
),
1094 "frame_text", &needs_frame
,
1095 "activate_prelight_icon_label", &prelight_label
,
1097 if (needs_frame
&& !needs_highlight
&& details
->text_width
> 0 && details
->text_height
> 0) {
1098 if (!(prelight_label
&& item
->details
->is_prelit
)) {
1101 container
->details
->normal_color_rgba
,
1105 text_rect
.x1
- text_rect
.x0
,
1106 text_rect
.y1
- text_rect
.y0
);
1110 container
->details
->prelight_color_rgba
,
1114 text_rect
.x1
- text_rect
.x0
,
1115 text_rect
.y1
- text_rect
.y0
);
1119 gc
= nautilus_icon_container_get_label_color_and_gc
1120 (NAUTILUS_ICON_CONTAINER (canvas_item
->canvas
),
1121 &label_color
, TRUE
, needs_highlight
,
1122 prelight_label
& item
->details
->is_prelit
);
1124 draw_label_layout (item
, drawable
,
1125 editable_layout
, needs_highlight
,
1128 text_rect
.y0
+ text_back_padding_y
, gc
);
1131 if (have_additional
) {
1132 gc
= nautilus_icon_container_get_label_color_and_gc
1133 (NAUTILUS_ICON_CONTAINER (canvas_item
->canvas
),
1134 &label_color
, FALSE
, needs_highlight
,
1137 draw_label_layout (item
, drawable
,
1138 additional_layout
, needs_highlight
,
1141 text_rect
.y0
+ editable_height
+ LABEL_LINE_SPACING
+ text_back_padding_y
, gc
);
1144 if (!create_mask
&& item
->details
->is_highlighted_as_keyboard_focus
) {
1145 gtk_paint_focus (GTK_WIDGET (EEL_CANVAS_ITEM (item
)->canvas
)->style
,
1147 needs_highlight
? GTK_STATE_SELECTED
: GTK_STATE_NORMAL
,
1149 GTK_WIDGET (EEL_CANVAS_ITEM (item
)->canvas
),
1153 text_rect
.x1
- text_rect
.x0
,
1154 text_rect
.y1
- text_rect
.y0
);
1157 if (editable_layout
) {
1158 g_object_unref (editable_layout
);
1161 if (additional_layout
) {
1162 g_object_unref (additional_layout
);
1167 measure_label_text (NautilusIconCanvasItem
*item
)
1169 EelIRect rect
= {0, };
1171 /* check to see if the cached values are still valid; if so, there's
1175 if (item
->details
->text_width
>= 0 && item
->details
->text_height
>= 0) {
1179 draw_or_measure_label_text (item
, NULL
, FALSE
, rect
);
1183 draw_label_text (NautilusIconCanvasItem
*item
, GdkDrawable
*drawable
,
1184 gboolean create_mask
, EelIRect icon_rect
)
1186 draw_or_measure_label_text (item
, drawable
, create_mask
, icon_rect
);
1190 nautilus_icon_canvas_item_set_is_visible (NautilusIconCanvasItem
*item
,
1193 if (item
->details
->is_visible
== visible
)
1196 item
->details
->is_visible
= visible
;
1199 if (item
->details
->editable_text_layout
) {
1200 g_object_unref (item
->details
->editable_text_layout
);
1201 item
->details
->editable_text_layout
= NULL
;
1203 if (item
->details
->additional_text_layout
) {
1204 g_object_unref (item
->details
->additional_text_layout
);
1205 item
->details
->additional_text_layout
= NULL
;
1207 if (item
->details
->embedded_text_layout
) {
1208 g_object_unref (item
->details
->embedded_text_layout
);
1209 item
->details
->embedded_text_layout
= NULL
;
1216 get_knob_pixbuf (void)
1218 GdkPixbuf
*knob_pixbuf
;
1219 char *knob_filename
;
1221 knob_pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
1222 "stock-nautilus-knob",
1225 knob_filename
= nautilus_pixmap_file ("knob.png");
1226 knob_pixbuf
= gdk_pixbuf_new_from_file (knob_filename
, NULL
);
1227 g_free (knob_filename
);
1234 draw_stretch_handles (NautilusIconCanvasItem
*item
, GdkDrawable
*drawable
,
1235 const EelIRect
*rect
)
1239 GdkPixbuf
*knob_pixbuf
;
1241 int knob_width
, knob_height
;
1243 if (!item
->details
->show_stretch_handles
) {
1247 widget
= GTK_WIDGET (EEL_CANVAS_ITEM (item
)->canvas
);
1249 gc
= gdk_gc_new (drawable
);
1250 knob_pixbuf
= get_knob_pixbuf ();
1251 knob_width
= gdk_pixbuf_get_width (knob_pixbuf
);
1252 knob_height
= gdk_pixbuf_get_height (knob_pixbuf
);
1254 stipple
= eel_stipple_bitmap_for_screen (
1255 gdk_drawable_get_screen (GDK_DRAWABLE (drawable
)));
1257 /* first draw the box */
1258 gdk_gc_set_rgb_fg_color (gc
, &widget
->style
->white
);
1260 (drawable
, gc
, FALSE
,
1263 rect
->x1
- rect
->x0
- 1,
1264 rect
->y1
- rect
->y0
- 1);
1266 gdk_gc_set_rgb_fg_color (gc
, &widget
->style
->black
);
1267 gdk_gc_set_stipple (gc
, stipple
);
1268 gdk_gc_set_fill (gc
, GDK_STIPPLED
);
1270 (drawable
, gc
, FALSE
,
1273 rect
->x1
- rect
->x0
- 1,
1274 rect
->y1
- rect
->y0
- 1);
1276 /* draw the stretch handles themselves */
1278 draw_pixbuf (knob_pixbuf
, drawable
, rect
->x0
, rect
->y0
);
1279 draw_pixbuf (knob_pixbuf
, drawable
, rect
->x0
, rect
->y1
- knob_height
);
1280 draw_pixbuf (knob_pixbuf
, drawable
, rect
->x1
- knob_width
, rect
->y0
);
1281 draw_pixbuf (knob_pixbuf
, drawable
, rect
->x1
- knob_width
, rect
->y1
- knob_height
);
1282 g_object_unref (knob_pixbuf
);
1284 g_object_unref (gc
);
1288 emblem_layout_reset (EmblemLayout
*layout
, NautilusIconCanvasItem
*icon_item
, EelIRect icon_rect
, gboolean is_rtl
)
1290 layout
->icon_item
= icon_item
;
1291 layout
->icon_rect
= icon_rect
;
1292 layout
->side
= is_rtl
? LEFT_SIDE
: RIGHT_SIDE
;
1293 layout
->position
= 0;
1295 layout
->emblem
= icon_item
->details
->emblem_pixbufs
;
1299 emblem_layout_next (EmblemLayout
*layout
,
1300 GdkPixbuf
**emblem_pixbuf
,
1301 EelIRect
*emblem_rect
,
1305 int width
, height
, x
, y
;
1306 GdkPoint
*attach_points
;
1308 /* Check if we have layed out all of the pixbufs. */
1309 if (layout
->emblem
== NULL
) {
1313 /* Get the pixbuf. */
1314 pixbuf
= layout
->emblem
->data
;
1315 width
= gdk_pixbuf_get_width (pixbuf
);
1316 height
= gdk_pixbuf_get_height (pixbuf
);
1319 /* Advance to the next emblem. */
1320 layout
->emblem
= layout
->emblem
->next
;
1322 attach_points
= layout
->icon_item
->details
->attach_points
;
1323 if (attach_points
!= NULL
) {
1324 if (layout
->index
>= layout
->icon_item
->details
->n_attach_points
) {
1328 x
= layout
->icon_rect
.x0
+ attach_points
[layout
->index
].x
;
1329 y
= layout
->icon_rect
.y0
+ attach_points
[layout
->index
].y
;
1333 /* Return the rectangle and pixbuf. */
1334 *emblem_pixbuf
= pixbuf
;
1335 emblem_rect
->x0
= x
- width
/ 2;
1336 emblem_rect
->y0
= y
- height
/ 2;
1337 emblem_rect
->x1
= emblem_rect
->x0
+ width
;
1338 emblem_rect
->y1
= emblem_rect
->y0
+ height
;
1346 /* Find the side to lay out along. */
1347 switch (layout
->side
) {
1349 x
= layout
->icon_rect
.x1
;
1350 y
= is_rtl
? layout
->icon_rect
.y1
: layout
->icon_rect
.y0
;
1353 x
= is_rtl
? layout
->icon_rect
.x0
: layout
->icon_rect
.x1
;
1354 y
= layout
->icon_rect
.y1
;
1357 x
= layout
->icon_rect
.x0
;
1358 y
= is_rtl
? layout
->icon_rect
.y0
: layout
->icon_rect
.y1
;
1361 x
= is_rtl
? layout
->icon_rect
.x1
: layout
->icon_rect
.x0
;
1362 y
= layout
->icon_rect
.y0
;
1365 g_assert_not_reached ();
1370 if (layout
->position
!= 0) {
1371 switch (layout
->side
) {
1373 y
+= (is_rtl
? -1 : 1) * (layout
->position
+ height
/ 2);
1376 x
+= (is_rtl
? 1 : -1 ) * (layout
->position
+ width
/ 2);
1379 y
+= (is_rtl
? 1 : -1) * (layout
->position
+ height
/ 2);
1382 x
+= (is_rtl
? -1 : 1) * (layout
->position
+ width
/ 2);
1387 /* Check to see if emblem fits in current side. */
1388 if (x
>= layout
->icon_rect
.x0
&& x
<= layout
->icon_rect
.x1
1389 && y
>= layout
->icon_rect
.y0
&& y
<= layout
->icon_rect
.y1
) {
1393 /* Advance along the side. */
1394 switch (layout
->side
) {
1397 layout
->position
+= height
+ EMBLEM_SPACING
;
1401 layout
->position
+= width
+ EMBLEM_SPACING
;
1405 /* Return the rectangle and pixbuf. */
1406 *emblem_pixbuf
= pixbuf
;
1407 emblem_rect
->x0
= x
- width
/ 2;
1408 emblem_rect
->y0
= y
- height
/ 2;
1409 emblem_rect
->x1
= emblem_rect
->x0
+ width
;
1410 emblem_rect
->y1
= emblem_rect
->y0
+ height
;
1415 /* It doesn't fit, so move to the next side. */
1416 switch (layout
->side
) {
1418 layout
->side
= is_rtl
? TOP_SIDE
: BOTTOM_SIDE
;
1421 layout
->side
= is_rtl
? RIGHT_SIDE
: LEFT_SIDE
;
1424 layout
->side
= is_rtl
? BOTTOM_SIDE
: TOP_SIDE
;
1430 layout
->position
= 0;
1435 draw_pixbuf (GdkPixbuf
*pixbuf
, GdkDrawable
*drawable
, int x
, int y
)
1437 /* FIXME bugzilla.gnome.org 40703:
1438 * Dither would be better if we passed dither values.
1440 gdk_draw_pixbuf (drawable
, NULL
, pixbuf
, 0, 0, x
, y
,
1441 gdk_pixbuf_get_width (pixbuf
),
1442 gdk_pixbuf_get_height (pixbuf
),
1443 GDK_RGB_DITHER_NORMAL
, 0, 0);
1446 /* should be moved to libeel! */
1448 nautilus_icon_canvas_lighten_pixbuf_component (guchar cur_value
, guint lighten_value
) {
1449 int new_value
= cur_value
;
1450 if (lighten_value
> 0) {
1451 new_value
+= lighten_value
+ (new_value
>> 3);
1452 if (new_value
> 255) {
1456 return (guchar
) new_value
;
1459 /* should be moved to libeel! */
1461 nautilus_icon_canvas_lighten_pixbuf (GdkPixbuf
* src
, guint lighten_value
) {
1464 int width
, height
, has_alpha
, src_row_stride
, dst_row_stride
;
1465 guchar
*target_pixels
, *original_pixels
;
1466 guchar
*pixsrc
, *pixdest
;
1468 g_return_val_if_fail (gdk_pixbuf_get_colorspace (src
) == GDK_COLORSPACE_RGB
, NULL
);
1469 g_return_val_if_fail ((!gdk_pixbuf_get_has_alpha (src
)
1470 && gdk_pixbuf_get_n_channels (src
) == 3)
1471 || (gdk_pixbuf_get_has_alpha (src
)
1472 && gdk_pixbuf_get_n_channels (src
) == 4), NULL
);
1473 g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (src
) == 8, NULL
);
1475 dest
= gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src
),
1476 gdk_pixbuf_get_has_alpha (src
),
1477 gdk_pixbuf_get_bits_per_sample (src
),
1478 gdk_pixbuf_get_width (src
),
1479 gdk_pixbuf_get_height (src
));
1481 has_alpha
= gdk_pixbuf_get_has_alpha (src
);
1482 width
= gdk_pixbuf_get_width (src
);
1483 height
= gdk_pixbuf_get_height (src
);
1484 dst_row_stride
= gdk_pixbuf_get_rowstride (dest
);
1485 src_row_stride
= gdk_pixbuf_get_rowstride (src
);
1486 target_pixels
= gdk_pixbuf_get_pixels (dest
);
1487 original_pixels
= gdk_pixbuf_get_pixels (src
);
1489 for (i
= 0; i
< height
; i
++) {
1490 pixdest
= target_pixels
+ i
* dst_row_stride
;
1491 pixsrc
= original_pixels
+ i
* src_row_stride
;
1492 for (j
= 0; j
< width
; j
++) {
1493 *pixdest
++ = nautilus_icon_canvas_lighten_pixbuf_component (*pixsrc
++, lighten_value
);
1494 *pixdest
++ = nautilus_icon_canvas_lighten_pixbuf_component (*pixsrc
++, lighten_value
);
1495 *pixdest
++ = nautilus_icon_canvas_lighten_pixbuf_component (*pixsrc
++, lighten_value
);
1497 *pixdest
++ = *pixsrc
++;
1507 render_icon (GdkPixbuf
*pixbuf
, guint render_mode
, guint saturation
, guint brightness
, guint lighten_value
, guint color
)
1509 GdkPixbuf
*temp_pixbuf
, *old_pixbuf
;
1511 if (render_mode
== 1) {
1513 temp_pixbuf
= eel_create_spotlight_pixbuf (pixbuf
);
1515 else if (render_mode
== 2) {
1517 temp_pixbuf
= eel_create_colorized_pixbuf (pixbuf
,
1518 EEL_RGBA_COLOR_GET_R (color
),
1519 EEL_RGBA_COLOR_GET_G (color
),
1520 EEL_RGBA_COLOR_GET_B (color
));
1521 } else if (render_mode
== 3) {
1522 /* monochromely colorize icon */
1523 old_pixbuf
= eel_create_darkened_pixbuf (pixbuf
, 0, 255);
1524 temp_pixbuf
= eel_create_colorized_pixbuf (old_pixbuf
,
1525 EEL_RGBA_COLOR_GET_R (color
),
1526 EEL_RGBA_COLOR_GET_G (color
),
1527 EEL_RGBA_COLOR_GET_B (color
));
1528 g_object_unref (old_pixbuf
);
1533 if (saturation
< 255 || brightness
< 255 || temp_pixbuf
== NULL
) { // temp_pixbuf == NULL just for safer code (return copy)
1534 old_pixbuf
= temp_pixbuf
;
1535 temp_pixbuf
= eel_create_darkened_pixbuf (temp_pixbuf
? temp_pixbuf
: pixbuf
, saturation
, brightness
);
1537 g_object_unref (old_pixbuf
);
1541 if (lighten_value
> 0) {
1542 old_pixbuf
= temp_pixbuf
;
1543 temp_pixbuf
= nautilus_icon_canvas_lighten_pixbuf (temp_pixbuf
? temp_pixbuf
: pixbuf
, lighten_value
);
1545 g_object_unref (old_pixbuf
);
1552 /* shared code to highlight or dim the passed-in pixbuf */
1554 real_map_pixbuf (NautilusIconCanvasItem
*icon_item
)
1557 char *audio_filename
;
1558 NautilusIconContainer
*container
;
1559 GdkPixbuf
*temp_pixbuf
, *old_pixbuf
, *audio_pixbuf
;
1561 guint render_mode
, saturation
, brightness
, lighten
;
1563 temp_pixbuf
= icon_item
->details
->pixbuf
;
1564 canvas
= EEL_CANVAS_ITEM(icon_item
)->canvas
;
1565 container
= NAUTILUS_ICON_CONTAINER (canvas
);
1567 g_object_ref (temp_pixbuf
);
1569 if (icon_item
->details
->is_prelit
) {
1570 old_pixbuf
= temp_pixbuf
;
1572 gtk_widget_style_get (GTK_WIDGET (container
),
1573 "prelight_icon_render_mode", &render_mode
,
1574 "prelight_icon_saturation", &saturation
,
1575 "prelight_icon_brightness", &brightness
,
1576 "prelight_icon_lighten", &lighten
,
1579 if (render_mode
> 0 || saturation
< 255 || brightness
< 255) {
1580 temp_pixbuf
= render_icon (temp_pixbuf
,
1585 container
->details
->prelight_icon_color_rgba
);
1586 g_object_unref (old_pixbuf
);
1591 /* FIXME bugzilla.gnome.org 42471: This hard-wired image is inappropriate to
1592 * this level of code, which shouldn't know that the
1593 * preview is audio, nor should it have an icon
1597 /* if the icon is currently being previewed, superimpose an image to indicate that */
1598 /* audio is the only kind of previewing right now, so this code isn't as general as it could be */
1599 if (icon_item
->details
->is_active
) {
1600 zoom
= (double) gdk_pixbuf_get_width (temp_pixbuf
) / NAUTILUS_ICON_SIZE_STANDARD
;
1601 /* Load the audio symbol. */
1602 audio_filename
= nautilus_pixmap_file ("audio.svg");
1603 if (audio_filename
!= NULL
) {
1604 audio_pixbuf
= rsvg_pixbuf_from_file_at_zoom_with_max (audio_filename
, zoom
, zoom
,
1605 NAUTILUS_ICON_MAXIMUM_SIZE
,
1606 NAUTILUS_ICON_MAXIMUM_SIZE
,
1609 audio_pixbuf
= NULL
;
1612 /* Composite it onto the icon. */
1613 if (audio_pixbuf
!= NULL
) {
1614 gdk_pixbuf_composite
1618 gdk_pixbuf_get_width (temp_pixbuf
),
1619 gdk_pixbuf_get_height(temp_pixbuf
),
1622 GDK_INTERP_BILINEAR
, 0xFF);
1624 g_object_unref (audio_pixbuf
);
1627 g_free (audio_filename
);
1631 if (icon_item
->details
->is_highlighted_for_selection
1632 || icon_item
->details
->is_highlighted_for_drop
) {
1635 old_pixbuf
= temp_pixbuf
;
1637 color
= GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (canvas
)) ? NAUTILUS_ICON_CONTAINER (canvas
)->details
->highlight_color_rgba
: NAUTILUS_ICON_CONTAINER (canvas
)->details
->active_color_rgba
;
1639 temp_pixbuf
= eel_create_colorized_pixbuf (temp_pixbuf
,
1640 EEL_RGBA_COLOR_GET_R (color
),
1641 EEL_RGBA_COLOR_GET_G (color
),
1642 EEL_RGBA_COLOR_GET_B (color
));
1644 g_object_unref (old_pixbuf
);
1647 if (!icon_item
->details
->is_active
1648 && !icon_item
->details
->is_prelit
1649 && !icon_item
->details
->is_highlighted_for_selection
1650 && !icon_item
->details
->is_highlighted_for_drop
) {
1651 old_pixbuf
= temp_pixbuf
;
1653 gtk_widget_style_get (GTK_WIDGET (container
),
1654 "normal_icon_render_mode", &render_mode
,
1655 "normal_icon_saturation", &saturation
,
1656 "normal_icon_brightness", &brightness
,
1657 "normal_icon_lighten", &lighten
,
1659 if (render_mode
> 0 || saturation
< 255 || brightness
< 255) {
1660 /* if theme requests colorization */
1661 temp_pixbuf
= render_icon (temp_pixbuf
,
1666 container
->details
->normal_icon_color_rgba
);
1667 g_object_unref (old_pixbuf
);
1675 map_pixbuf (NautilusIconCanvasItem
*icon_item
)
1677 if (!(icon_item
->details
->rendered_pixbuf
!= NULL
1678 && icon_item
->details
->rendered_is_active
== icon_item
->details
->is_active
1679 && icon_item
->details
->rendered_is_prelit
== icon_item
->details
->is_prelit
1680 && icon_item
->details
->rendered_is_highlighted_for_selection
== icon_item
->details
->is_highlighted_for_selection
1681 && icon_item
->details
->rendered_is_highlighted_for_drop
== icon_item
->details
->is_highlighted_for_drop
1682 && (icon_item
->details
->is_highlighted_for_selection
&& icon_item
->details
->rendered_is_focused
== GTK_WIDGET_HAS_FOCUS (EEL_CANVAS_ITEM (icon_item
)->canvas
)))) {
1683 if (icon_item
->details
->rendered_pixbuf
!= NULL
) {
1684 g_object_unref (icon_item
->details
->rendered_pixbuf
);
1686 icon_item
->details
->rendered_pixbuf
= real_map_pixbuf (icon_item
);
1687 icon_item
->details
->rendered_is_active
= icon_item
->details
->is_active
;
1688 icon_item
->details
->rendered_is_prelit
= icon_item
->details
->is_prelit
;
1689 icon_item
->details
->rendered_is_highlighted_for_selection
= icon_item
->details
->is_highlighted_for_selection
;
1690 icon_item
->details
->rendered_is_highlighted_for_drop
= icon_item
->details
->is_highlighted_for_drop
;
1691 icon_item
->details
->rendered_is_focused
= GTK_WIDGET_HAS_FOCUS (EEL_CANVAS_ITEM (icon_item
)->canvas
);
1694 g_object_ref (icon_item
->details
->rendered_pixbuf
);
1696 return icon_item
->details
->rendered_pixbuf
;
1700 draw_embedded_text (NautilusIconCanvasItem
*item
,
1701 GdkDrawable
*drawable
,
1705 GdkRectangle clip_rect
;
1706 PangoLayout
*layout
;
1707 PangoContext
*context
;
1708 PangoFontDescription
*desc
;
1710 if (item
->details
->embedded_text
== NULL
||
1711 item
->details
->embedded_text_rect
.width
== 0 ||
1712 item
->details
->embedded_text_rect
.height
== 0) {
1716 if (item
->details
->embedded_text_layout
!= NULL
) {
1717 layout
= g_object_ref (item
->details
->embedded_text_layout
);
1719 context
= gtk_widget_get_pango_context (GTK_WIDGET (EEL_CANVAS_ITEM (item
)->canvas
));
1720 layout
= pango_layout_new (context
);
1721 pango_layout_set_text (layout
, item
->details
->embedded_text
, -1);
1723 desc
= pango_font_description_from_string ("monospace 6");
1724 pango_layout_set_font_description (layout
, desc
);
1725 pango_font_description_free (desc
);
1727 if (item
->details
->is_visible
) {
1728 item
->details
->embedded_text_layout
= g_object_ref (layout
);
1732 gc
= gdk_gc_new (drawable
);
1734 clip_rect
.x
= x
+ item
->details
->embedded_text_rect
.x
;
1735 clip_rect
.y
= y
+ item
->details
->embedded_text_rect
.y
;
1736 clip_rect
.width
= item
->details
->embedded_text_rect
.width
;
1737 clip_rect
.height
= item
->details
->embedded_text_rect
.height
;
1739 gdk_gc_set_clip_rectangle (gc
, &clip_rect
);
1741 gdk_draw_layout (drawable
, gc
,
1742 x
+ item
->details
->embedded_text_rect
.x
,
1743 y
+ item
->details
->embedded_text_rect
.y
,
1746 g_object_unref (gc
);
1747 g_object_unref (layout
);
1750 /* Draw the icon item for non-anti-aliased mode. */
1752 nautilus_icon_canvas_item_draw (EelCanvasItem
*item
, GdkDrawable
*drawable
,
1753 GdkEventExpose
*expose
)
1755 NautilusIconCanvasItem
*icon_item
;
1756 NautilusIconCanvasItemDetails
*details
;
1757 EelIRect icon_rect
, emblem_rect
;
1758 EmblemLayout emblem_layout
;
1759 GdkPixbuf
*emblem_pixbuf
, *temp_pixbuf
;
1760 GdkRectangle draw_rect
, pixbuf_rect
;
1763 icon_item
= NAUTILUS_ICON_CANVAS_ITEM (item
);
1764 details
= icon_item
->details
;
1766 /* Draw the pixbuf. */
1767 if (details
->pixbuf
== NULL
) {
1771 icon_rect
= icon_item
->details
->canvas_rect
;
1773 /* if the pre-lit or selection flag is set, make a pre-lit or darkened pixbuf and draw that instead */
1774 /* and colorize normal pixbuf if rc wants that */
1775 temp_pixbuf
= map_pixbuf (icon_item
);
1776 pixbuf_rect
.x
= icon_rect
.x0
;
1777 pixbuf_rect
.y
= icon_rect
.y0
;
1778 pixbuf_rect
.width
= gdk_pixbuf_get_width (temp_pixbuf
);
1779 pixbuf_rect
.height
= gdk_pixbuf_get_height (temp_pixbuf
);
1780 if (gdk_rectangle_intersect (&(expose
->area
), &pixbuf_rect
, &draw_rect
)) {
1781 gdk_draw_pixbuf (drawable
,
1784 draw_rect
.x
- pixbuf_rect
.x
,
1785 draw_rect
.y
- pixbuf_rect
.y
,
1790 GDK_RGB_DITHER_NORMAL
,
1793 g_object_unref (temp_pixbuf
);
1795 draw_embedded_text (icon_item
, drawable
, icon_rect
.x0
, icon_rect
.y0
);
1797 is_rtl
= nautilus_icon_container_is_layout_rtl (NAUTILUS_ICON_CONTAINER (item
->canvas
));
1799 /* Draw the emblem pixbufs. */
1800 emblem_layout_reset (&emblem_layout
, icon_item
, icon_rect
, is_rtl
);
1801 while (emblem_layout_next (&emblem_layout
, &emblem_pixbuf
, &emblem_rect
, is_rtl
)) {
1802 draw_pixbuf (emblem_pixbuf
, drawable
, emblem_rect
.x0
, emblem_rect
.y0
);
1805 /* Draw stretching handles (if necessary). */
1806 draw_stretch_handles (icon_item
, drawable
, &icon_rect
);
1808 /* Draw the label text. */
1809 draw_label_text (icon_item
, drawable
, FALSE
, icon_rect
);
1812 #define ZERO_WIDTH_SPACE "\xE2\x80\x8B"
1814 #define ZERO_OR_THREE_DIGITS(p) \
1815 (!g_ascii_isdigit (*p) || \
1816 (g_ascii_isdigit (*(p+1)) && \
1817 g_ascii_isdigit (*(p+2))))
1819 static PangoLayout
*
1820 create_label_layout (NautilusIconCanvasItem
*item
,
1823 PangoLayout
*layout
;
1824 PangoContext
*context
;
1825 PangoFontDescription
*desc
;
1826 NautilusIconContainer
*container
;
1827 EelCanvasItem
*canvas_item
;
1829 char *zeroified_text
;
1832 canvas_item
= EEL_CANVAS_ITEM (item
);
1834 container
= NAUTILUS_ICON_CONTAINER (canvas_item
->canvas
);
1835 context
= gtk_widget_get_pango_context (GTK_WIDGET (canvas_item
->canvas
));
1836 layout
= pango_layout_new (context
);
1838 zeroified_text
= NULL
;
1841 str
= g_string_new (NULL
);
1843 for (p
= text
; *p
!= '\0'; p
++) {
1844 str
= g_string_append_c (str
, *p
);
1846 if (*p
== '_' || *p
== '-' || (*p
== '.' && ZERO_OR_THREE_DIGITS (p
+1))) {
1847 /* Ensure that we allow to break after '_' or '.' characters,
1848 * if they are not likely to be part of a version information, to
1849 * not break wrapping of foobar-0.0.1.
1850 * Wrap before IPs and long numbers, though. */
1851 str
= g_string_append (str
, ZERO_WIDTH_SPACE
);
1855 zeroified_text
= g_string_free (str
, FALSE
);
1858 pango_layout_set_text (layout
, zeroified_text
, -1);
1859 pango_layout_set_width (layout
, floor (nautilus_icon_canvas_item_get_max_text_width (item
)) * PANGO_SCALE
);
1861 pango_layout_set_auto_dir (layout
, FALSE
);
1863 if (container
->details
->label_position
== NAUTILUS_ICON_LABEL_POSITION_BESIDE
) {
1864 if (!nautilus_icon_container_is_layout_rtl (container
)) {
1865 pango_layout_set_alignment (layout
, PANGO_ALIGN_LEFT
);
1867 pango_layout_set_alignment (layout
, PANGO_ALIGN_RIGHT
);
1870 pango_layout_set_alignment (layout
, PANGO_ALIGN_CENTER
);
1873 pango_layout_set_spacing (layout
, LABEL_LINE_SPACING
);
1874 pango_layout_set_wrap (layout
, PANGO_WRAP_WORD_CHAR
);
1876 /* Create a font description */
1877 if (container
->details
->font
) {
1878 desc
= pango_font_description_from_string (container
->details
->font
);
1880 desc
= pango_font_description_copy (pango_context_get_font_description (context
));
1881 pango_font_description_set_size (desc
,
1882 pango_font_description_get_size (desc
) +
1883 container
->details
->font_size_table
[container
->details
->zoom_level
]);
1885 pango_layout_set_font_description (layout
, desc
);
1886 pango_font_description_free (desc
);
1887 g_free (zeroified_text
);
1892 static PangoLayout
*
1893 get_label_layout (PangoLayout
**layout_cache
,
1894 NautilusIconCanvasItem
*item
,
1897 PangoLayout
*layout
;
1899 if (*layout_cache
!= NULL
) {
1900 return g_object_ref (*layout_cache
);
1903 layout
= create_label_layout (item
, text
);
1905 if (item
->details
->is_visible
) {
1906 *layout_cache
= g_object_ref (layout
);
1913 draw_label_layout (NautilusIconCanvasItem
*item
,
1914 GdkDrawable
*drawable
,
1915 PangoLayout
*layout
,
1917 GdkColor
*label_color
,
1922 if (drawable
== NULL
) {
1926 if (item
->details
->is_renaming
) {
1930 if (!highlight
&& (NAUTILUS_ICON_CONTAINER (EEL_CANVAS_ITEM (item
)->canvas
)->details
->use_drop_shadows
)) {
1931 /* draw a drop shadow */
1932 eel_gdk_draw_layout_with_drop_shadow (drawable
, gc
,
1934 >K_WIDGET (EEL_CANVAS_ITEM (item
)->canvas
)->style
->black
,
1938 gdk_draw_layout (drawable
, gc
,
1947 nautilus_icon_canvas_item_event (EelCanvasItem
*item
, GdkEvent
*event
)
1949 NautilusIconCanvasItem
*icon_item
;
1952 icon_item
= NAUTILUS_ICON_CANVAS_ITEM (item
);
1954 switch (event
->type
) {
1955 case GDK_ENTER_NOTIFY
:
1956 if (!icon_item
->details
->is_prelit
) {
1957 icon_item
->details
->is_prelit
= TRUE
;
1958 eel_canvas_item_request_update (item
);
1959 /* show a hand cursor */
1960 if (in_single_click_mode ()) {
1961 cursor
= gdk_cursor_new_for_display (gdk_display_get_default(),
1963 gdk_window_set_cursor (((GdkEventAny
*)event
)->window
, cursor
);
1964 gdk_cursor_unref (cursor
);
1967 /* FIXME bugzilla.gnome.org 42473:
1968 * We should emit our own signal here,
1969 * not one from the container; it could hook
1970 * up to that signal and emit one of its
1971 * own. Doing it this way hard-codes what
1972 * "user_data" is. Also, the two signals
1973 * should be separate. The "unpreview" signal
1974 * does not have a return value.
1976 icon_item
->details
->is_active
= nautilus_icon_container_emit_preview_signal
1977 (NAUTILUS_ICON_CONTAINER (item
->canvas
),
1978 NAUTILUS_ICON_CANVAS_ITEM (item
)->user_data
,
1983 case GDK_LEAVE_NOTIFY
:
1984 if (icon_item
->details
->is_prelit
1985 || icon_item
->details
->is_highlighted_for_drop
) {
1986 /* When leaving, turn of the prelight state and the
1987 * higlighted for drop. The latter gets turned on
1988 * by the drag&drop motion callback.
1990 /* FIXME bugzilla.gnome.org 42473:
1991 * We should emit our own signal here,
1992 * not one from the containe; it could hook up
1993 * to that signal and emit one of its
1994 * ownr. Doing it this way hard-codes what
1995 * "user_data" is. Also, the two signals
1996 * should be separate. The "unpreview" signal
1997 * does not have a return value.
1999 nautilus_icon_container_emit_preview_signal
2000 (NAUTILUS_ICON_CONTAINER (item
->canvas
),
2001 NAUTILUS_ICON_CANVAS_ITEM (item
)->user_data
,
2003 icon_item
->details
->is_prelit
= FALSE
;
2004 icon_item
->details
->is_active
= 0;
2005 icon_item
->details
->is_highlighted_for_drop
= FALSE
;
2006 eel_canvas_item_request_update (item
);
2008 /* show default cursor */
2009 gdk_window_set_cursor (((GdkEventAny
*)event
)->window
, NULL
);
2014 /* Don't eat up other events; icon container might use them. */
2020 hit_test_pixbuf (GdkPixbuf
*pixbuf
, EelIRect pixbuf_location
, EelIRect probe_rect
)
2022 EelIRect relative_rect
, pixbuf_rect
;
2026 /* You can get here without a pixbuf in some strange cases. */
2027 if (pixbuf
== NULL
) {
2031 /* Check to see if it's within the rectangle at all. */
2032 relative_rect
.x0
= probe_rect
.x0
- pixbuf_location
.x0
;
2033 relative_rect
.y0
= probe_rect
.y0
- pixbuf_location
.y0
;
2034 relative_rect
.x1
= probe_rect
.x1
- pixbuf_location
.x0
;
2035 relative_rect
.y1
= probe_rect
.y1
- pixbuf_location
.y0
;
2038 pixbuf_rect
.x1
= gdk_pixbuf_get_width (pixbuf
);
2039 pixbuf_rect
.y1
= gdk_pixbuf_get_height (pixbuf
);
2040 eel_irect_intersect (&relative_rect
, &relative_rect
, &pixbuf_rect
);
2041 if (eel_irect_is_empty (&relative_rect
)) {
2045 /* If there's no alpha channel, it's opaque and we have a hit. */
2046 if (!gdk_pixbuf_get_has_alpha (pixbuf
)) {
2049 g_assert (gdk_pixbuf_get_n_channels (pixbuf
) == 4);
2051 /* Check the alpha channel of the pixel to see if we have a hit. */
2052 for (x
= relative_rect
.x0
; x
< relative_rect
.x1
; x
++) {
2053 for (y
= relative_rect
.y0
; y
< relative_rect
.y1
; y
++) {
2054 pixel
= gdk_pixbuf_get_pixels (pixbuf
)
2055 + y
* gdk_pixbuf_get_rowstride (pixbuf
)
2066 hit_test (NautilusIconCanvasItem
*icon_item
, EelIRect canvas_rect
)
2068 NautilusIconCanvasItemDetails
*details
;
2069 EelIRect emblem_rect
;
2070 EmblemLayout emblem_layout
;
2071 GdkPixbuf
*emblem_pixbuf
;
2074 details
= icon_item
->details
;
2076 /* Quick check to see if the rect hits the icon, text or emblems at all. */
2077 if (!eel_irect_hits_irect (icon_item
->details
->canvas_rect
, canvas_rect
)
2078 && (!eel_irect_hits_irect (details
->text_rect
, canvas_rect
))
2079 && (!eel_irect_hits_irect (details
->emblem_rect
, canvas_rect
))) {
2083 /* Check for hits in the stretch handles. */
2084 if (hit_test_stretch_handle (icon_item
, canvas_rect
, NULL
)) {
2088 /* Check for hit in the icon. */
2089 if (eel_irect_hits_irect (icon_item
->details
->canvas_rect
, canvas_rect
)) {
2093 /* Check for hit in the text. */
2094 if (eel_irect_hits_irect (details
->text_rect
, canvas_rect
)
2095 && !icon_item
->details
->is_renaming
) {
2099 is_rtl
= nautilus_icon_container_is_layout_rtl (NAUTILUS_ICON_CONTAINER (EEL_CANVAS_ITEM (icon_item
)->canvas
));
2101 /* Check for hit in the emblem pixbufs. */
2102 emblem_layout_reset (&emblem_layout
, icon_item
, icon_item
->details
->canvas_rect
, is_rtl
);
2103 while (emblem_layout_next (&emblem_layout
, &emblem_pixbuf
, &emblem_rect
, is_rtl
)) {
2104 if (hit_test_pixbuf (emblem_pixbuf
, emblem_rect
, canvas_rect
)) {
2112 /* Point handler for the icon canvas item. */
2114 nautilus_icon_canvas_item_point (EelCanvasItem
*item
, double x
, double y
, int cx
, int cy
,
2115 EelCanvasItem
**actual_item
)
2117 EelIRect canvas_rect
;
2119 *actual_item
= item
;
2120 canvas_rect
.x0
= cx
;
2121 canvas_rect
.y0
= cy
;
2122 canvas_rect
.x1
= cx
+ 1;
2123 canvas_rect
.y1
= cy
+ 1;
2124 if (hit_test (NAUTILUS_ICON_CANVAS_ITEM (item
), canvas_rect
)) {
2127 /* This value means not hit.
2128 * It's kind of arbitrary. Can we do better?
2130 return item
->canvas
->pixels_per_unit
* 2 + 10;
2135 nautilus_icon_canvas_item_translate (EelCanvasItem
*item
, double dx
, double dy
)
2137 NautilusIconCanvasItem
*icon_item
;
2138 NautilusIconCanvasItemDetails
*details
;
2140 icon_item
= NAUTILUS_ICON_CANVAS_ITEM (item
);
2141 details
= icon_item
->details
;
2147 /* Bounds handler for the icon canvas item. */
2149 nautilus_icon_canvas_item_bounds (EelCanvasItem
*item
,
2150 double *x1
, double *y1
, double *x2
, double *y2
)
2152 NautilusIconCanvasItem
*icon_item
;
2153 NautilusIconCanvasItemDetails
*details
;
2154 EelIRect icon_rect
, text_rect
, total_rect
, emblem_rect
;
2155 double pixels_per_unit
;
2156 EmblemLayout emblem_layout
;
2157 GdkPixbuf
*emblem_pixbuf
;
2160 g_assert (x1
!= NULL
);
2161 g_assert (y1
!= NULL
);
2162 g_assert (x2
!= NULL
);
2163 g_assert (y2
!= NULL
);
2165 icon_item
= NAUTILUS_ICON_CANVAS_ITEM (item
);
2166 details
= icon_item
->details
;
2168 if (details
->bounds_cached
) {
2169 total_rect
= details
->bounds_cache
;
2171 measure_label_text (icon_item
);
2173 pixels_per_unit
= item
->canvas
->pixels_per_unit
;
2175 /* Compute icon rectangle. */
2178 if (details
->pixbuf
== NULL
) {
2179 icon_rect
.x1
= icon_rect
.x0
;
2180 icon_rect
.y1
= icon_rect
.y0
;
2182 icon_rect
.x1
= icon_rect
.x0
+ gdk_pixbuf_get_width (details
->pixbuf
) / pixels_per_unit
;
2183 icon_rect
.y1
= icon_rect
.y0
+ gdk_pixbuf_get_height (details
->pixbuf
) / pixels_per_unit
;
2186 /* Compute text rectangle. */
2187 text_rect
= compute_text_rectangle (icon_item
, icon_rect
, FALSE
);
2189 is_rtl
= nautilus_icon_container_is_layout_rtl (NAUTILUS_ICON_CONTAINER (item
->canvas
));
2191 /* Compute total rectangle, adding in emblem rectangles. */
2192 eel_irect_union (&total_rect
, &icon_rect
, &text_rect
);
2193 emblem_layout_reset (&emblem_layout
, icon_item
, icon_rect
, is_rtl
);
2194 while (emblem_layout_next (&emblem_layout
, &emblem_pixbuf
, &emblem_rect
, is_rtl
)) {
2195 emblem_rect
.x0
= floor (emblem_rect
.x0
/ pixels_per_unit
);
2196 emblem_rect
.y0
= floor (emblem_rect
.y0
/ pixels_per_unit
);
2197 emblem_rect
.x1
= ceil (emblem_rect
.x1
/ pixels_per_unit
);
2198 emblem_rect
.y1
= ceil (emblem_rect
.y1
/ pixels_per_unit
);
2200 eel_irect_union (&total_rect
, &total_rect
, &emblem_rect
);
2203 details
->bounds_cache
= total_rect
;
2204 details
->bounds_cached
= TRUE
;
2207 /* Return the result. */
2208 *x1
= (int)details
->x
+ total_rect
.x0
;
2209 *y1
= (int)details
->y
+ total_rect
.y0
;
2210 *x2
= (int)details
->x
+ total_rect
.x1
+ 1;
2211 *y2
= (int)details
->y
+ total_rect
.y1
+ 1;
2214 /* Get the rectangle of the icon only, in world coordinates. */
2216 nautilus_icon_canvas_item_get_icon_rectangle (const NautilusIconCanvasItem
*item
)
2219 double pixels_per_unit
;
2222 g_return_val_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (item
), eel_drect_empty
);
2224 rectangle
.x0
= item
->details
->x
;
2225 rectangle
.y0
= item
->details
->y
;
2227 pixbuf
= item
->details
->pixbuf
;
2229 pixels_per_unit
= EEL_CANVAS_ITEM (item
)->canvas
->pixels_per_unit
;
2230 rectangle
.x1
= rectangle
.x0
+ (pixbuf
== NULL
? 0 : gdk_pixbuf_get_width (pixbuf
)) / pixels_per_unit
;
2231 rectangle
.y1
= rectangle
.y0
+ (pixbuf
== NULL
? 0 : gdk_pixbuf_get_height (pixbuf
)) / pixels_per_unit
;
2233 eel_canvas_item_i2w (EEL_CANVAS_ITEM (item
),
2236 eel_canvas_item_i2w (EEL_CANVAS_ITEM (item
),
2244 nautilus_icon_canvas_item_get_text_rectangle (NautilusIconCanvasItem
*item
)
2247 EelIRect icon_rectangle
;
2248 EelIRect text_rectangle
;
2250 double pixels_per_unit
;
2253 g_return_val_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (item
), eel_drect_empty
);
2255 icon_rectangle
.x0
= item
->details
->x
;
2256 icon_rectangle
.y0
= item
->details
->y
;
2258 pixbuf
= item
->details
->pixbuf
;
2260 pixels_per_unit
= EEL_CANVAS_ITEM (item
)->canvas
->pixels_per_unit
;
2261 icon_rectangle
.x1
= icon_rectangle
.x0
+ (pixbuf
== NULL
? 0 : gdk_pixbuf_get_width (pixbuf
)) / pixels_per_unit
;
2262 icon_rectangle
.y1
= icon_rectangle
.y0
+ (pixbuf
== NULL
? 0 : gdk_pixbuf_get_height (pixbuf
)) / pixels_per_unit
;
2264 measure_label_text (item
);
2265 text_rectangle
= compute_text_rectangle (item
, icon_rectangle
, FALSE
);
2267 ret
.x0
= text_rectangle
.x0
;
2268 ret
.y0
= text_rectangle
.y0
;
2269 ret
.x1
= text_rectangle
.x1
;
2270 ret
.y1
= text_rectangle
.y1
;
2272 eel_canvas_item_i2w (EEL_CANVAS_ITEM (item
),
2275 eel_canvas_item_i2w (EEL_CANVAS_ITEM (item
),
2283 /* Get the rectangle of the icon only, in canvas coordinates. */
2285 get_icon_canvas_rectangle (NautilusIconCanvasItem
*item
,
2290 g_return_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (item
));
2291 g_return_if_fail (rect
!= NULL
);
2293 eel_canvas_w2c (EEL_CANVAS_ITEM (item
)->canvas
,
2299 pixbuf
= item
->details
->pixbuf
;
2301 rect
->x1
= rect
->x0
+ (pixbuf
== NULL
? 0 : gdk_pixbuf_get_width (pixbuf
));
2302 rect
->y1
= rect
->y0
+ (pixbuf
== NULL
? 0 : gdk_pixbuf_get_height (pixbuf
));
2306 nautilus_icon_canvas_item_set_show_stretch_handles (NautilusIconCanvasItem
*item
,
2307 gboolean show_stretch_handles
)
2309 g_return_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (item
));
2310 g_return_if_fail (show_stretch_handles
== FALSE
|| show_stretch_handles
== TRUE
);
2312 if (!item
->details
->show_stretch_handles
== !show_stretch_handles
) {
2316 item
->details
->show_stretch_handles
= show_stretch_handles
;
2317 eel_canvas_item_request_update (EEL_CANVAS_ITEM (item
));
2320 /* Check if one of the stretch handles was hit. */
2322 hit_test_stretch_handle (NautilusIconCanvasItem
*item
,
2323 EelIRect probe_canvas_rect
,
2324 GtkCornerType
*corner
)
2327 GdkPixbuf
*knob_pixbuf
;
2328 int knob_width
, knob_height
;
2331 g_return_val_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (item
), FALSE
);
2333 /* Make sure there are handles to hit. */
2334 if (!item
->details
->show_stretch_handles
) {
2338 /* Quick check to see if the rect hits the icon at all. */
2339 icon_rect
= item
->details
->canvas_rect
;
2340 if (!eel_irect_hits_irect (probe_canvas_rect
, icon_rect
)) {
2344 knob_pixbuf
= get_knob_pixbuf ();
2345 knob_width
= gdk_pixbuf_get_width (knob_pixbuf
);
2346 knob_height
= gdk_pixbuf_get_height (knob_pixbuf
);
2347 g_object_unref (knob_pixbuf
);
2349 /* Check for hits in the stretch handles. */
2351 if (probe_canvas_rect
.x0
< icon_rect
.x0
+ knob_width
) {
2352 if (probe_canvas_rect
.y0
< icon_rect
.y0
+ knob_height
)
2353 hit_corner
= GTK_CORNER_TOP_LEFT
;
2354 else if (probe_canvas_rect
.y1
>= icon_rect
.y1
- knob_height
)
2355 hit_corner
= GTK_CORNER_BOTTOM_LEFT
;
2357 else if (probe_canvas_rect
.x1
>= icon_rect
.x1
- knob_width
) {
2358 if (probe_canvas_rect
.y0
< icon_rect
.y0
+ knob_height
)
2359 hit_corner
= GTK_CORNER_TOP_RIGHT
;
2360 else if (probe_canvas_rect
.y1
>= icon_rect
.y1
- knob_height
)
2361 hit_corner
= GTK_CORNER_BOTTOM_RIGHT
;
2364 *corner
= hit_corner
;
2366 return hit_corner
!= -1;
2370 nautilus_icon_canvas_item_hit_test_stretch_handles (NautilusIconCanvasItem
*item
,
2371 EelDPoint world_point
,
2372 GtkCornerType
*corner
)
2374 EelIRect canvas_rect
;
2376 g_return_val_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (item
), FALSE
);
2378 eel_canvas_w2c (EEL_CANVAS_ITEM (item
)->canvas
,
2383 canvas_rect
.x1
= canvas_rect
.x0
+ 1;
2384 canvas_rect
.y1
= canvas_rect
.y0
+ 1;
2385 return hit_test_stretch_handle (item
, canvas_rect
, corner
);
2388 /* nautilus_icon_canvas_item_hit_test_rectangle
2390 * Check and see if there is an intersection between the item and the
2394 nautilus_icon_canvas_item_hit_test_rectangle (NautilusIconCanvasItem
*item
, EelIRect canvas_rect
)
2396 g_return_val_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (item
), FALSE
);
2398 return hit_test (item
, canvas_rect
);
2402 nautilus_icon_canvas_item_get_editable_text (NautilusIconCanvasItem
*icon_item
)
2404 g_return_val_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (icon_item
), NULL
);
2406 return icon_item
->details
->editable_text
;
2410 nautilus_icon_canvas_item_set_renaming (NautilusIconCanvasItem
*item
, gboolean state
)
2412 g_return_if_fail (NAUTILUS_IS_ICON_CANVAS_ITEM (item
));
2413 g_return_if_fail (state
== FALSE
|| state
== TRUE
);
2415 if (!item
->details
->is_renaming
== !state
) {
2419 item
->details
->is_renaming
= state
;
2420 eel_canvas_item_request_update (EEL_CANVAS_ITEM (item
));
2424 nautilus_icon_canvas_item_get_max_text_width (NautilusIconCanvasItem
*item
)
2426 EelCanvasItem
*canvas_item
;
2428 canvas_item
= EEL_CANVAS_ITEM (item
);
2429 if (nautilus_icon_container_is_tighter_layout (NAUTILUS_ICON_CONTAINER (canvas_item
->canvas
))) {
2430 return MAX_TEXT_WIDTH_TIGHTER
* canvas_item
->canvas
->pixels_per_unit
;
2433 if (NAUTILUS_ICON_CONTAINER (canvas_item
->canvas
)->details
->label_position
== NAUTILUS_ICON_LABEL_POSITION_BESIDE
) {
2434 return MAX_TEXT_WIDTH_BESIDE
* canvas_item
->canvas
->pixels_per_unit
;
2436 return MAX_TEXT_WIDTH_STANDARD
* canvas_item
->canvas
->pixels_per_unit
;
2444 /* NautilusIconCanvasItemAccessible */
2446 static NautilusIconCanvasItemAccessiblePrivate
*
2447 accessible_get_priv (AtkObject
*accessible
)
2449 NautilusIconCanvasItemAccessiblePrivate
*priv
;
2451 priv
= g_object_get_qdata (G_OBJECT (accessible
),
2452 accessible_private_data_quark
);
2457 /* AtkAction interface */
2460 nautilus_icon_canvas_item_accessible_idle_do_action (gpointer data
)
2462 NautilusIconCanvasItem
*item
;
2463 NautilusIconCanvasItemAccessibleActionContext
*ctx
;
2465 NautilusIconContainer
*container
;
2468 GdkEventButton button_event
= { 0 };
2471 container
= NAUTILUS_ICON_CONTAINER (data
);
2472 container
->details
->a11y_item_action_idle_handler
= 0;
2473 while (!g_queue_is_empty (container
->details
->a11y_item_action_queue
)) {
2474 ctx
= g_queue_pop_head (container
->details
->a11y_item_action_queue
);
2475 action_number
= ctx
->action_number
;
2478 icon
= item
->user_data
;
2480 switch (action_number
) {
2482 file_list
.data
= icon
->data
;
2483 file_list
.next
= NULL
;
2484 file_list
.prev
= NULL
;
2485 g_signal_emit_by_name (container
, "activate", &file_list
);
2488 selection
= nautilus_icon_container_get_selection (container
);
2489 if (selection
== NULL
||
2490 g_list_length (selection
) != 1 ||
2491 selection
->data
!= icon
->data
) {
2492 g_list_free (selection
);
2495 g_list_free (selection
);
2496 g_signal_emit_by_name (container
, "context_click_selection", &button_event
);
2499 g_assert_not_reached ();
2507 nautilus_icon_canvas_item_accessible_do_action (AtkAction
*accessible
, int i
)
2509 NautilusIconCanvasItem
*item
;
2510 NautilusIconCanvasItemAccessibleActionContext
*ctx
;
2512 NautilusIconContainer
*container
;
2514 g_return_val_if_fail (i
< LAST_ACTION
, FALSE
);
2516 item
= eel_accessibility_get_gobject (ATK_OBJECT (accessible
));
2520 icon
= item
->user_data
;
2521 container
= NAUTILUS_ICON_CONTAINER (EEL_CANVAS_ITEM (item
)->canvas
);
2525 if (container
->details
->a11y_item_action_queue
== NULL
) {
2526 container
->details
->a11y_item_action_queue
= g_queue_new ();
2528 ctx
= g_new (NautilusIconCanvasItemAccessibleActionContext
, 1);
2529 ctx
->action_number
= i
;
2531 g_queue_push_head (container
->details
->a11y_item_action_queue
, ctx
);
2532 if (container
->details
->a11y_item_action_idle_handler
== 0) {
2533 container
->details
->a11y_item_action_idle_handler
= g_idle_add (nautilus_icon_canvas_item_accessible_idle_do_action
, container
);
2537 g_warning ("Invalid action passed to NautilusIconCanvasItemAccessible::do_action");
2545 nautilus_icon_canvas_item_accessible_get_n_actions (AtkAction
*accessible
)
2551 nautilus_icon_canvas_item_accessible_action_get_description (AtkAction
*accessible
,
2554 NautilusIconCanvasItemAccessiblePrivate
*priv
;
2556 g_return_val_if_fail (i
< LAST_ACTION
, NULL
);
2558 priv
= accessible_get_priv (ATK_OBJECT (accessible
));
2559 if (priv
->action_descriptions
[i
]) {
2560 return priv
->action_descriptions
[i
];
2562 return nautilus_icon_canvas_item_accessible_action_descriptions
[i
];
2567 nautilus_icon_canvas_item_accessible_action_get_name (AtkAction
*accessible
, int i
)
2569 g_return_val_if_fail (i
< LAST_ACTION
, NULL
);
2571 return nautilus_icon_canvas_item_accessible_action_names
[i
];
2575 nautilus_icon_canvas_item_accessible_action_get_keybinding (AtkAction
*accessible
,
2578 g_return_val_if_fail (i
< LAST_ACTION
, NULL
);
2584 nautilus_icon_canvas_item_accessible_action_set_description (AtkAction
*accessible
,
2586 const char *description
)
2588 NautilusIconCanvasItemAccessiblePrivate
*priv
;
2590 g_return_val_if_fail (i
< LAST_ACTION
, FALSE
);
2592 priv
= accessible_get_priv (ATK_OBJECT (accessible
));
2594 if (priv
->action_descriptions
[i
]) {
2595 g_free (priv
->action_descriptions
[i
]);
2597 priv
->action_descriptions
[i
] = g_strdup (description
);
2603 nautilus_icon_canvas_item_accessible_action_interface_init (AtkActionIface
*iface
)
2605 iface
->do_action
= nautilus_icon_canvas_item_accessible_do_action
;
2606 iface
->get_n_actions
= nautilus_icon_canvas_item_accessible_get_n_actions
;
2607 iface
->get_description
= nautilus_icon_canvas_item_accessible_action_get_description
;
2608 iface
->get_keybinding
= nautilus_icon_canvas_item_accessible_action_get_keybinding
;
2609 iface
->get_name
= nautilus_icon_canvas_item_accessible_action_get_name
;
2610 iface
->set_description
= nautilus_icon_canvas_item_accessible_action_set_description
;
2613 static G_CONST_RETURN gchar
*
2614 nautilus_icon_canvas_item_accessible_get_name (AtkObject
*accessible
)
2616 NautilusIconCanvasItem
*item
;
2618 if (accessible
->name
) {
2619 return accessible
->name
;
2622 item
= eel_accessibility_get_gobject (accessible
);
2626 return item
->details
->editable_text
;
2629 static G_CONST_RETURN gchar
*
2630 nautilus_icon_canvas_item_accessible_get_description (AtkObject
*accessible
)
2632 NautilusIconCanvasItem
*item
;
2634 item
= eel_accessibility_get_gobject (accessible
);
2639 return item
->details
->additional_text
;
2643 nautilus_icon_canvas_item_accessible_get_parent (AtkObject
*accessible
)
2645 NautilusIconCanvasItem
*item
;
2647 item
= eel_accessibility_get_gobject (accessible
);
2652 return gtk_widget_get_accessible (GTK_WIDGET (EEL_CANVAS_ITEM (item
)->canvas
));
2656 nautilus_icon_canvas_item_accessible_get_index_in_parent (AtkObject
*accessible
)
2658 NautilusIconCanvasItem
*item
;
2659 NautilusIconContainer
*container
;
2664 item
= eel_accessibility_get_gobject (accessible
);
2669 container
= NAUTILUS_ICON_CONTAINER (EEL_CANVAS_ITEM (item
)->canvas
);
2671 l
= container
->details
->icons
;
2676 if (icon
->item
== item
) {
2688 nautilus_icon_canvas_item_accessible_ref_state_set (AtkObject
*accessible
)
2690 AtkStateSet
*state_set
;
2691 NautilusIconCanvasItem
*item
;
2692 NautilusIconContainer
*container
;
2695 gboolean one_item_selected
;
2697 state_set
= ATK_OBJECT_CLASS (accessible_parent_class
)->ref_state_set (accessible
);
2699 item
= eel_accessibility_get_gobject (accessible
);
2701 atk_state_set_add_state (state_set
, ATK_STATE_DEFUNCT
);
2704 container
= NAUTILUS_ICON_CONTAINER (EEL_CANVAS_ITEM (item
)->canvas
);
2705 if (item
->details
->is_highlighted_as_keyboard_focus
) {
2706 atk_state_set_add_state (state_set
, ATK_STATE_FOCUSED
);
2707 } else if (!container
->details
->keyboard_focus
) {
2709 one_item_selected
= FALSE
;
2710 l
= container
->details
->icons
;
2714 if (icon
->item
== item
) {
2715 if (icon
->is_selected
) {
2716 one_item_selected
= TRUE
;
2720 } else if (icon
->is_selected
) {
2721 one_item_selected
= FALSE
;
2728 if (one_item_selected
) {
2729 atk_state_set_add_state (state_set
, ATK_STATE_FOCUSED
);
2737 nautilus_icon_canvas_item_accessible_initialize (AtkObject
*accessible
,
2740 NautilusIconCanvasItemAccessiblePrivate
*priv
;
2742 if (ATK_OBJECT_CLASS (accessible_parent_class
)->initialize
) {
2743 ATK_OBJECT_CLASS (accessible_parent_class
)->initialize (accessible
, data
);
2746 priv
= g_new0 (NautilusIconCanvasItemAccessiblePrivate
, 1);
2747 g_object_set_qdata (G_OBJECT (accessible
),
2748 accessible_private_data_quark
,
2753 nautilus_icon_canvas_item_accessible_finalize (GObject
*object
)
2755 NautilusIconCanvasItemAccessiblePrivate
*priv
;
2758 priv
= accessible_get_priv (ATK_OBJECT (object
));
2760 for (i
= 0; i
< LAST_ACTION
; i
++) {
2761 g_free (priv
->action_descriptions
[i
]);
2763 g_free (priv
->image_description
);
2764 g_free (priv
->description
);
2768 G_OBJECT_CLASS (accessible_parent_class
)->finalize (object
);
2772 nautilus_icon_canvas_item_accessible_class_init (AtkObjectClass
*klass
)
2774 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
2776 accessible_parent_class
= g_type_class_peek_parent (klass
);
2778 gobject_class
->finalize
= nautilus_icon_canvas_item_accessible_finalize
;
2780 klass
->get_name
= nautilus_icon_canvas_item_accessible_get_name
;
2781 klass
->get_description
= nautilus_icon_canvas_item_accessible_get_description
;
2782 klass
->get_parent
= nautilus_icon_canvas_item_accessible_get_parent
;
2783 klass
->get_index_in_parent
= nautilus_icon_canvas_item_accessible_get_index_in_parent
;
2784 klass
->ref_state_set
= nautilus_icon_canvas_item_accessible_ref_state_set
;
2785 klass
->initialize
= nautilus_icon_canvas_item_accessible_initialize
;
2786 accessible_private_data_quark
= g_quark_from_static_string ("icon-canvas-item-accessible-private-data");
2790 static G_CONST_RETURN gchar
*
2791 nautilus_icon_canvas_item_accessible_get_image_description
2794 NautilusIconCanvasItemAccessiblePrivate
*priv
;
2795 NautilusIconCanvasItem
*item
;
2797 NautilusIconContainer
*container
;
2800 priv
= accessible_get_priv (ATK_OBJECT (image
));
2801 if (priv
->image_description
) {
2802 return priv
->image_description
;
2804 item
= eel_accessibility_get_gobject (ATK_OBJECT (image
));
2808 icon
= item
->user_data
;
2809 container
= NAUTILUS_ICON_CONTAINER (EEL_CANVAS_ITEM (item
)->canvas
);
2810 description
= nautilus_icon_container_get_icon_description (container
, icon
->data
);
2811 g_free (priv
->description
);
2812 priv
->description
= description
;
2813 return priv
->description
;
2818 nautilus_icon_canvas_item_accessible_get_image_size
2823 NautilusIconCanvasItem
*item
;
2825 item
= eel_accessibility_get_gobject (ATK_OBJECT (image
));
2827 if (!item
|| !item
->details
->pixbuf
) {
2828 *width
= *height
= 0;
2830 *width
= gdk_pixbuf_get_width (item
->details
->pixbuf
);
2831 *height
= gdk_pixbuf_get_height (item
->details
->pixbuf
);
2836 nautilus_icon_canvas_item_accessible_get_image_position
2840 AtkCoordType coord_type
)
2842 NautilusIconCanvasItem
*item
;
2843 gint x_offset
, y_offset
, itmp
;
2845 item
= eel_accessibility_get_gobject (ATK_OBJECT (image
));
2849 if (!item
->details
->canvas_rect
.x0
&& !item
->details
->canvas_rect
.x1
) {
2854 if (item
->details
->text_width
) {
2855 itmp
= item
->details
->canvas_rect
.x0
-
2856 item
->details
->text_rect
.x0
;
2857 if (itmp
> x_offset
) {
2860 itmp
= item
->details
->canvas_rect
.y0
-
2861 item
->details
->text_rect
.y0
;
2862 if (itmp
> y_offset
) {
2866 if (item
->details
->emblem_pixbufs
) {
2867 itmp
= item
->details
->canvas_rect
.x0
-
2868 item
->details
->emblem_rect
.x0
;
2869 if (itmp
> x_offset
) {
2872 itmp
= item
->details
->canvas_rect
.y0
-
2873 item
->details
->emblem_rect
.y0
;
2874 if (itmp
> y_offset
) {
2879 atk_component_get_position (ATK_COMPONENT (image
), x
, y
, coord_type
);
2885 nautilus_icon_canvas_item_accessible_set_image_description
2887 const gchar
*description
)
2889 NautilusIconCanvasItemAccessiblePrivate
*priv
;
2891 priv
= accessible_get_priv (ATK_OBJECT (image
));
2893 g_free (priv
->image_description
);
2894 priv
->image_description
= g_strdup (description
);
2900 nautilus_icon_canvas_item_accessible_image_interface_init (AtkImageIface
*iface
)
2902 iface
->get_image_description
= nautilus_icon_canvas_item_accessible_get_image_description
;
2903 iface
->set_image_description
= nautilus_icon_canvas_item_accessible_set_image_description
;
2904 iface
->get_image_size
= nautilus_icon_canvas_item_accessible_get_image_size
;
2905 iface
->get_image_position
= nautilus_icon_canvas_item_accessible_get_image_position
;
2909 nautilus_icon_canvas_item_accessible_get_offset_at_point (AtkText
*text
,
2912 AtkCoordType coords
)
2914 gint real_x
, real_y
, real_width
, real_height
;
2915 NautilusIconCanvasItem
*item
;
2916 gint editable_height
;
2919 PangoLayout
*layout
, *editable_layout
, *additional_layout
;
2920 PangoRectangle rect0
;
2922 gboolean have_editable
;
2923 gboolean have_additional
;
2926 atk_component_get_extents (ATK_COMPONENT (text
), &real_x
, &real_y
,
2927 &real_width
, &real_height
, coords
);
2932 item
= eel_accessibility_get_gobject (ATK_OBJECT (text
));
2934 if (item
->details
->pixbuf
) {
2935 y
-= gdk_pixbuf_get_height (item
->details
->pixbuf
);
2937 have_editable
= item
->details
->editable_text
!= NULL
&&
2938 item
->details
->editable_text
[0] != '\0';
2939 have_additional
= item
->details
->additional_text
!= NULL
&&item
->details
->additional_text
[0] != '\0';
2941 editable_layout
= NULL
;
2942 additional_layout
= NULL
;
2943 if (have_editable
) {
2944 editable_layout
= get_label_layout (&item
->details
->editable_text_layout
, item
, item
->details
->editable_text
);
2945 pango_layout_get_pixel_size (editable_layout
, NULL
, &editable_height
);
2946 if (y
>= editable_height
&&
2948 additional_layout
= get_label_layout (&item
->details
->additional_text_layout
, item
, item
->details
->additional_text
);
2949 layout
= additional_layout
;
2950 icon_text
= item
->details
->additional_text
;
2951 y
-= editable_height
+ LABEL_LINE_SPACING
;
2953 layout
= editable_layout
;
2954 icon_text
= item
->details
->editable_text
;
2956 } else if (have_additional
) {
2957 additional_layout
= get_label_layout (&item
->details
->additional_text_layout
, item
, item
->details
->additional_text
);
2958 layout
= additional_layout
;
2959 icon_text
= item
->details
->additional_text
;
2965 if (have_editable
) {
2966 pango_layout_index_to_pos (editable_layout
, 0, &rect0
);
2967 text_offset
= PANGO_PIXELS (rect0
.x
);
2969 if (have_additional
) {
2972 pango_layout_index_to_pos (additional_layout
, 0, &rect0
);
2973 itmp
= PANGO_PIXELS (rect0
.x
);
2974 if (itmp
< text_offset
) {
2978 pango_layout_index_to_pos (layout
, 0, &rect0
);
2980 if (!pango_layout_xy_to_index (layout
,
2984 if (x
< 0 || y
< 0) {
2991 offset
= g_utf8_strlen (icon_text
, -1);
2993 offset
= g_utf8_pointer_to_offset (icon_text
, icon_text
+ index
);
2995 if (layout
== additional_layout
) {
2996 offset
+= g_utf8_strlen (item
->details
->editable_text
, -1);
2999 if (editable_layout
!= NULL
) {
3000 g_object_unref (editable_layout
);
3003 if (additional_layout
!= NULL
) {
3004 g_object_unref (additional_layout
);
3011 nautilus_icon_canvas_item_accessible_get_character_extents (AtkText
*text
,
3017 AtkCoordType coords
)
3020 gint len
, byte_offset
;
3021 gint editable_height
;
3023 NautilusIconCanvasItem
*item
;
3024 PangoLayout
*layout
, *editable_layout
, *additional_layout
;
3025 PangoRectangle rect
;
3026 PangoRectangle rect0
;
3027 gboolean have_editable
;
3030 atk_component_get_position (ATK_COMPONENT (text
), &pos_x
, &pos_y
, coords
);
3031 item
= eel_accessibility_get_gobject (ATK_OBJECT (text
));
3033 if (item
->details
->pixbuf
) {
3034 pos_y
+= gdk_pixbuf_get_height (item
->details
->pixbuf
);
3037 have_editable
= item
->details
->editable_text
!= NULL
&&
3038 item
->details
->editable_text
[0] != '\0';
3039 if (have_editable
) {
3040 len
= g_utf8_strlen (item
->details
->editable_text
, -1);
3045 editable_layout
= get_label_layout (&item
->details
->editable_text_layout
, item
, item
->details
->editable_text
);
3046 additional_layout
= get_label_layout (&item
->details
->additional_text_layout
, item
, item
->details
->additional_text
);
3049 icon_text
= item
->details
->editable_text
;
3050 layout
= editable_layout
;
3053 icon_text
= item
->details
->additional_text
;
3054 layout
= additional_layout
;
3055 pos_y
+= LABEL_LINE_SPACING
;
3056 if (have_editable
) {
3057 pango_layout_get_pixel_size (editable_layout
, NULL
, &editable_height
);
3058 pos_y
+= editable_height
;
3061 byte_offset
= g_utf8_offset_to_pointer (icon_text
, offset
) - icon_text
;
3062 pango_layout_index_to_pos (layout
, byte_offset
, &rect
);
3064 if (have_editable
) {
3065 pango_layout_index_to_pos (editable_layout
, 0, &rect0
);
3066 text_offset
= PANGO_PIXELS (rect0
.x
);
3068 if (item
->details
->additional_text
!= NULL
&&
3069 item
->details
->additional_text
[0] != '\0') {
3072 pango_layout_index_to_pos (additional_layout
, 0, &rect0
);
3073 itmp
= PANGO_PIXELS (rect0
.x
);
3074 if (itmp
< text_offset
) {
3079 g_object_unref (editable_layout
);
3080 g_object_unref (additional_layout
);
3082 *x
= pos_x
+ PANGO_PIXELS (rect
.x
) - text_offset
;
3083 *y
= pos_y
+ PANGO_PIXELS (rect
.y
);
3084 *width
= PANGO_PIXELS (rect
.width
);
3085 *height
= PANGO_PIXELS (rect
.height
);
3089 nautilus_icon_canvas_item_accessible_text_interface_init (AtkTextIface
*iface
)
3091 iface
->get_text
= eel_accessibility_text_get_text
;
3092 iface
->get_character_at_offset
= eel_accessibility_text_get_character_at_offset
;
3093 iface
->get_text_before_offset
= eel_accessibility_text_get_text_before_offset
;
3094 iface
->get_text_at_offset
= eel_accessibility_text_get_text_at_offset
;
3095 iface
->get_text_after_offset
= eel_accessibility_text_get_text_after_offset
;
3096 iface
->get_character_count
= eel_accessibility_text_get_character_count
;
3097 iface
->get_character_extents
= nautilus_icon_canvas_item_accessible_get_character_extents
;
3098 iface
->get_offset_at_point
= nautilus_icon_canvas_item_accessible_get_offset_at_point
;
3102 nautilus_icon_canvas_item_accessible_get_type (void)
3104 static GType type
= 0;
3107 const GInterfaceInfo atk_image_info
= {
3108 (GInterfaceInitFunc
)
3109 nautilus_icon_canvas_item_accessible_image_interface_init
,
3110 (GInterfaceFinalizeFunc
) NULL
,
3114 const GInterfaceInfo atk_text_info
= {
3115 (GInterfaceInitFunc
)
3116 nautilus_icon_canvas_item_accessible_text_interface_init
,
3117 (GInterfaceFinalizeFunc
) NULL
,
3121 const GInterfaceInfo atk_action_info
= {
3122 (GInterfaceInitFunc
)
3123 nautilus_icon_canvas_item_accessible_action_interface_init
,
3124 (GInterfaceFinalizeFunc
) NULL
,
3128 type
= eel_accessibility_create_derived_type (
3129 "NautilusIconCanvasItemAccessibility",
3130 EEL_TYPE_CANVAS_ITEM
,
3131 nautilus_icon_canvas_item_accessible_class_init
);
3133 if (type
!= G_TYPE_INVALID
) {
3134 g_type_add_interface_static (
3135 type
, ATK_TYPE_IMAGE
, &atk_image_info
);
3137 g_type_add_interface_static (
3138 type
, ATK_TYPE_TEXT
, &atk_text_info
);
3140 g_type_add_interface_static (
3141 type
, ATK_TYPE_ACTION
, &atk_action_info
);
3150 nautilus_icon_canvas_item_accessible_create (GObject
*for_object
)
3153 AtkObject
*accessible
;
3154 NautilusIconCanvasItem
*item
;
3157 item
= NAUTILUS_ICON_CANVAS_ITEM (for_object
);
3158 g_return_val_if_fail (item
!= NULL
, NULL
);
3160 type
= nautilus_icon_canvas_item_accessible_get_type ();
3162 if (type
== G_TYPE_INVALID
) {
3163 return atk_no_op_object_new (for_object
);
3166 item_text
= g_string_new (NULL
);
3167 if (item
->details
->editable_text
) {
3168 g_string_append (item_text
, item
->details
->editable_text
);
3170 if (item
->details
->additional_text
) {
3171 g_string_append (item_text
, item
->details
->additional_text
);
3173 item
->details
->text_util
= gail_text_util_new ();
3174 gail_text_util_text_setup (item
->details
->text_util
,
3176 g_string_free (item_text
, TRUE
);
3178 accessible
= g_object_new (type
, NULL
);
3179 accessible
= eel_accessibility_set_atk_object_return
3180 (for_object
, accessible
);
3181 atk_object_set_role (accessible
, ATK_ROLE_ICON
);
3185 EEL_ACCESSIBLE_FACTORY (nautilus_icon_canvas_item_accessible_get_type (),
3186 "NautilusIconCanvasItemAccessibilityFactory",
3187 nautilus_icon_canvas_item_accessible
,
3188 nautilus_icon_canvas_item_accessible_create
)
3191 static GailTextUtil
*
3192 nautilus_icon_canvas_item_get_text (GObject
*text
)
3194 return NAUTILUS_ICON_CANVAS_ITEM (text
)->details
->text_util
;
3198 nautilus_icon_canvas_item_text_interface_init (EelAccessibleTextIface
*iface
)
3200 iface
->get_text
= nautilus_icon_canvas_item_get_text
;
3203 /* Class initialization function for the icon canvas item. */
3205 nautilus_icon_canvas_item_class_init (NautilusIconCanvasItemClass
*class)
3207 GObjectClass
*object_class
;
3208 EelCanvasItemClass
*item_class
;
3210 parent_class
= g_type_class_peek_parent (class);
3212 object_class
= G_OBJECT_CLASS (class);
3213 item_class
= EEL_CANVAS_ITEM_CLASS (class);
3215 object_class
->finalize
= nautilus_icon_canvas_item_finalize
;
3216 object_class
->set_property
= nautilus_icon_canvas_item_set_property
;
3217 object_class
->get_property
= nautilus_icon_canvas_item_get_property
;
3219 g_object_class_install_property (
3222 g_param_spec_string ("editable_text",
3224 "the editable label",
3225 "", G_PARAM_READWRITE
));
3227 g_object_class_install_property (
3229 PROP_ADDITIONAL_TEXT
,
3230 g_param_spec_string ("additional_text",
3233 "", G_PARAM_READWRITE
));
3235 g_object_class_install_property (
3237 PROP_HIGHLIGHTED_FOR_SELECTION
,
3238 g_param_spec_boolean ("highlighted_for_selection",
3239 "highlighted for selection",
3240 "whether we are highlighted for a selection",
3241 FALSE
, G_PARAM_READWRITE
));
3243 g_object_class_install_property (
3245 PROP_HIGHLIGHTED_AS_KEYBOARD_FOCUS
,
3246 g_param_spec_boolean ("highlighted_as_keyboard_focus",
3247 "highlighted as keyboard focus",
3248 "whether we are highlighted to render keyboard focus",
3249 FALSE
, G_PARAM_READWRITE
));
3252 g_object_class_install_property (
3254 PROP_HIGHLIGHTED_FOR_DROP
,
3255 g_param_spec_boolean ("highlighted_for_drop",
3256 "highlighted for drop",
3257 "whether we are highlighted for a D&D drop",
3258 FALSE
, G_PARAM_READWRITE
));
3260 item_class
->update
= nautilus_icon_canvas_item_update
;
3261 item_class
->draw
= nautilus_icon_canvas_item_draw
;
3262 item_class
->point
= nautilus_icon_canvas_item_point
;
3263 item_class
->translate
= nautilus_icon_canvas_item_translate
;
3264 item_class
->bounds
= nautilus_icon_canvas_item_bounds
;
3265 item_class
->event
= nautilus_icon_canvas_item_event
;
3267 EEL_OBJECT_SET_FACTORY (NAUTILUS_TYPE_ICON_CANVAS_ITEM
,
3268 nautilus_icon_canvas_item_accessible
);
3270 g_type_class_add_private (class, sizeof (NautilusIconCanvasItemDetails
));
3274 nautilus_icon_canvas_item_get_type (void)
3276 static GType type
= 0;
3279 const GTypeInfo info
= {
3280 sizeof (NautilusIconCanvasItemClass
),
3281 NULL
, /* base_init */
3282 NULL
, /* base_finalize */
3283 (GClassInitFunc
) nautilus_icon_canvas_item_class_init
,
3284 NULL
, /* class_finalize */
3285 NULL
, /* class_data */
3286 sizeof (NautilusIconCanvasItem
),
3287 0, /* n_preallocs */
3288 (GInstanceInitFunc
) nautilus_icon_canvas_item_init
,
3290 const GInterfaceInfo eel_text_info
= {
3291 (GInterfaceInitFunc
)
3292 nautilus_icon_canvas_item_text_interface_init
,
3293 (GInterfaceFinalizeFunc
) NULL
,
3297 type
= g_type_register_static
3298 (EEL_TYPE_CANVAS_ITEM
, "NautilusIconCanvasItem", &info
, 0);
3300 g_type_add_interface_static
3301 (type
, EEL_TYPE_ACCESSIBLE_TEXT
, &eel_text_info
);