[Xfce4-commits] <xfdesktop:master> drawing routines overhaul

Brian J. Tarricone brian at tarricone.org
Sat Aug 22 10:14:01 CEST 2009


Updating branch refs/heads/master
         to 4cfd4ef72ee6b10445c5f671df364899650e7d3f (commit)
       from fdbd7ad456f39b6da49c55a5b839e9023c7adbf2 (commit)

commit 4cfd4ef72ee6b10445c5f671df364899650e7d3f
Author: Brian J. Tarricone <brian at tarricone.org>
Date:   Sat Jun 13 18:02:26 2009 -0700

    drawing routines overhaul
    
    this is mainly a lot of refactoring and moving common code into
    functions.  XfdesktopIcon keeps track of a bit more information about
    its position and the extents of its pixbuf and text area.  this should
    fix most (if not all) drawing glitches, though there are a few hacks in
    place that i need to fix.

 src/main.c                |    2 +-
 src/xfdesktop-icon-view.c |  684 +++++++++++++++++++++++++++++----------------
 src/xfdesktop-icon.c      |   58 +++-
 src/xfdesktop-icon.h      |   16 +-
 4 files changed, 492 insertions(+), 268 deletions(-)

diff --git a/src/main.c b/src/main.c
index 0b813ab..f98f034 100644
--- a/src/main.c
+++ b/src/main.c
@@ -383,7 +383,7 @@ main(int argc, char **argv)
         g_warning("Unable to set up POSIX signal handlers: %s", error->message);
         g_error_free(error);
     }
-    
+
     gtk_main();
     
     menu_cleanup();
diff --git a/src/xfdesktop-icon-view.c b/src/xfdesktop-icon-view.c
index afa6c51..399d265 100644
--- a/src/xfdesktop-icon-view.c
+++ b/src/xfdesktop-icon-view.c
@@ -1,7 +1,7 @@
 /*
  *  xfdesktop - xfce4's desktop manager
  *
- *  Copyright (c) 2006-2008 Brian Tarricone, <bjt23 at cornell.edu>
+ *  Copyright (c) 2006-2009 Brian Tarricone, <bjt23 at cornell.edu>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -228,14 +228,22 @@ static void xfdesktop_icon_view_drag_data_received(GtkWidget *widget,
                                                       
 static void xfdesktop_icon_view_finalize(GObject *obj);
 
-
 static void xfdesktop_icon_view_add_move_binding(GtkBindingSet *binding_set,
                                                  guint keyval,
                                                  guint modmask,
                                                  GtkMovementStep step,
                                                  gint count);
+
+static gboolean xfdesktop_icon_view_update_icon_extents(XfdesktopIconView *icon_view,
+                                                        XfdesktopIcon *icon,
+                                                        GdkRectangle *pixbuf_extents,
+                                                        GdkRectangle *text_extents,
+                                                        GdkRectangle *total_extents);
 static void xfdesktop_icon_view_invalidate_icon(XfdesktopIconView *icon_view,
-                                                XfdesktopIcon *icon);
+                                                XfdesktopIcon *icon,
+                                                gboolean recalc_extents);
+static void xfdesktop_icon_view_icon_changed(XfdesktopIcon *icon,
+                                             gpointer user_data);
 #ifdef HAVE_LIBEXO
 static void xfdesktop_icon_view_invalidate_icon_pixbuf(XfdesktopIconView *icon_view,
                                                        XfdesktopIcon *icon);
@@ -301,6 +309,9 @@ static void xfdesktop_icon_view_add_item_internal(XfdesktopIconView *icon_view,
                                                   XfdesktopIcon *icon);
 static gboolean xfdesktop_icon_view_icon_find_position(XfdesktopIconView *icon_view,
                                                        XfdesktopIcon *icon);
+static gboolean xfdesktop_icon_view_shift_area_to_cell(XfdesktopIconView *icon_view,
+                                                       XfdesktopIcon *icon,
+                                                       GdkRectangle *text_area);
 #if GTK_CHECK_VERSION(2, 12, 0)
 static gboolean xfdesktop_icon_view_show_tooltip(GtkWidget *widget,
                                                  gint x,
@@ -319,6 +330,13 @@ static gboolean xfdesktop_icon_view_real_move_cursor(XfdesktopIconView *icon_vie
                                                      GtkMovementStep step,
                                                      gint count);
 
+static void xfdesktop_icon_view_move_cursor_left_right(XfdesktopIconView *icon_view,
+                                                       gint count,
+                                                       GdkModifierType modmask);
+static void xfdesktop_icon_view_select_between(XfdesktopIconView *icon_view,
+                                               XfdesktopIcon *start_icon,
+                                               XfdesktopIcon *end_icon);
+
 enum
 {
     TARGET_XFDESKTOP_ICON = 9999,
@@ -699,43 +717,25 @@ xfdesktop_icon_view_button_press(GtkWidget *widget,
                 
                 if(evt->state & GDK_CONTROL_MASK) {
                     /* unselect */
-                    icon_view->priv->selected_icons = g_list_remove(icon_view->priv->selected_icons,
-                                                                    icon);
-                    xfdesktop_icon_view_invalidate_icon(icon_view, icon);
-                } else if(icon != icon_view->priv->cursor) {
-                    /* expand the text */
-                    XfdesktopIcon *old_sel = icon_view->priv->cursor;
-                    
-                    icon_view->priv->cursor = icon;
-                    if(old_sel)
-                        xfdesktop_icon_view_invalidate_icon(icon_view, old_sel);
-                    xfdesktop_icon_view_invalidate_icon(icon_view, icon);
+                    xfdesktop_icon_view_unselect_item(icon_view, icon);
                 }
+
+                icon_view->priv->cursor = icon;
             } else {
                 /* clicked a non-selected icon */
-                XfdesktopIcon *old_sel;
-                
                 if(icon_view->priv->sel_mode != GTK_SELECTION_MULTIPLE
                    || !(evt->state & GDK_CONTROL_MASK))
                 {
                     /* unselect all of the other icons if we haven't held
                      * down the ctrl key.  we'll handle shift in the next block,
                      * but for shift we do need to unselect everything */
-                    GList *repaint_icons = icon_view->priv->selected_icons;
-                    icon_view->priv->selected_icons = NULL;
-                    g_list_foreach(repaint_icons,
-                                   xfdesktop_list_foreach_invalidate,
-                                   icon_view);
-                    g_list_free(repaint_icons);
+                    xfdesktop_icon_view_unselect_all(icon_view);
                     
                     if(!(evt->state & GDK_SHIFT_MASK))
                         icon_view->priv->first_clicked_item = NULL;
                 }
                 
-                old_sel = icon_view->priv->cursor;
                 icon_view->priv->cursor = icon;
-                if(old_sel)
-                    xfdesktop_icon_view_invalidate_icon(icon_view, old_sel);
                 
                 if(!icon_view->priv->first_clicked_item)
                     icon_view->priv->first_clicked_item = icon;
@@ -745,52 +745,11 @@ xfdesktop_icon_view_button_press(GtkWidget *widget,
                    && icon_view->priv->first_clicked_item
                    && icon_view->priv->first_clicked_item != icon)
                 {
-                    /* select all icons between the first-clicked icon in this
-                     * selection run and the newly-clicked icon */
-                    guint16 first_row = 0, first_col = 0, row = 0, col = 0;
-                    if(xfdesktop_icon_get_position(icon_view->priv->first_clicked_item,
-                                                   &first_row, &first_col)
-                       && xfdesktop_icon_get_position(icon, &row, &col))
-                    {
-                        gint i, j, idx;
-                        XfdesktopIcon *icon1 = NULL;
-                        
-                        for(i = (row < first_row ? row : first_row);
-                            i <= (row < first_row ? first_row : row);
-                            ++i)
-                        {
-                            for(j = (col < first_col ? col : first_col);
-                                j <= (col < first_col ? first_col : col);
-                                ++j)
-                            {
-                                idx = j * icon_view->priv->nrows + i;
-                                icon1 = xfdesktop_icon_view_icon_in_cell_raw(icon_view, idx);
-                                if(icon1
-                                   && !g_list_find(icon_view->priv->selected_icons,
-                                                   icon1))
-                                {
-                                    icon_view->priv->selected_icons = g_list_prepend(icon_view->priv->selected_icons,
-                                                                                     icon1);
-                                    xfdesktop_icon_view_invalidate_icon(icon_view,
-                                                                           icon1);
-                                    g_signal_emit(G_OBJECT(icon_view),
-                                                  __signals[SIG_ICON_SELECTION_CHANGED],
-                                                  0, NULL);
-                                    xfdesktop_icon_selected(icon1);
-                                }
-                            }
-                        }
-                    }
-                } else {
-                    icon_view->priv->selected_icons = g_list_prepend(icon_view->priv->selected_icons,
-                                                                     icon);
-                    xfdesktop_icon_view_invalidate_icon(icon_view, icon);
-                    
-                    g_signal_emit(G_OBJECT(icon_view),
-                                  __signals[SIG_ICON_SELECTION_CHANGED],
-                                  0, NULL);
-                    xfdesktop_icon_selected(icon);
-                }
+                    xfdesktop_icon_view_select_between(icon_view,
+                                                       icon_view->priv->first_clicked_item,
+                                                       icon);
+                } else
+                    xfdesktop_icon_view_select_item(icon_view, icon);
             }
             
             if(evt->button == 1) {
@@ -802,7 +761,7 @@ xfdesktop_icon_view_button_press(GtkWidget *widget,
                 icon_view->priv->press_start_x = evt->x;
                 icon_view->priv->press_start_y = evt->y;
             } else if(evt->button == 3) {
-                /* avoid repaint delay -- why the hell is this here? */
+                /* avoid repaint delay -- FIXME: why the hell is this here? */
                 while(gtk_events_pending())
                     gtk_main_iteration();
                 /* XfceDesktop will handle signalling the icon view manager
@@ -816,15 +775,7 @@ xfdesktop_icon_view_button_press(GtkWidget *widget,
             if(icon_view->priv->sel_mode != GTK_SELECTION_MULTIPLE
                || !(evt->state & GDK_CONTROL_MASK))
             {
-                GList *repaint_icons = icon_view->priv->selected_icons;
-                icon_view->priv->selected_icons = NULL;
-                g_list_foreach(repaint_icons, xfdesktop_list_foreach_invalidate,
-                               icon_view);
-                g_list_free(repaint_icons);
-
-                g_signal_emit(G_OBJECT(icon_view),
-                              __signals[SIG_ICON_SELECTION_CHANGED],
-                              0, NULL);
+                xfdesktop_icon_view_unselect_all(icon_view);
             }
             
             icon_view->priv->cursor = NULL;
@@ -907,12 +858,16 @@ xfdesktop_icon_view_focus_in(GtkWidget *widget,
                              gpointer user_data)
 {
     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
+    GList *l;
     
     GTK_WIDGET_SET_FLAGS(GTK_WIDGET(icon_view), GTK_HAS_FOCUS);
     DBG("GOT FOCUS");
     
-    g_list_foreach(icon_view->priv->selected_icons,
-                   xfdesktop_list_foreach_invalidate, icon_view);
+    for(l = icon_view->priv->selected_icons; l; l = l->next) {
+        xfdesktop_icon_view_invalidate_icon(icon_view, l->data, FALSE);
+        while(gtk_events_pending())
+            gtk_main_iteration();
+    }
     
     return FALSE;
 }
@@ -923,13 +878,17 @@ xfdesktop_icon_view_focus_out(GtkWidget *widget,
                               gpointer user_data)
 {
     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
+    GList *l;
     
     GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(icon_view), GTK_HAS_FOCUS);
     DBG("LOST FOCUS");
-    
-    g_list_foreach(icon_view->priv->selected_icons,
-                   xfdesktop_list_foreach_invalidate, icon_view);
-    
+
+    for(l = icon_view->priv->selected_icons; l; l = l->next) {
+        xfdesktop_icon_view_invalidate_icon(icon_view, l->data, FALSE);
+        while(gtk_events_pending())
+            gtk_main_iteration();
+    }
+
     return FALSE;
 }
 
@@ -1071,16 +1030,12 @@ xfdesktop_icon_view_motion_notify(GtkWidget *widget,
                 GdkRectangle extents, dummy;
                 XfdesktopIcon *icon = l->data;
 
-                if(xfdesktop_icon_get_extents(icon, &extents)
+                if(xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)
                    && !gdk_rectangle_intersect(&extents, new_rect, &dummy))
                 {
                     /* remove the icon from the selected list */
-                    GList *to_remove = l;
-
                     l = l->next;
-                    icon_view->priv->selected_icons = g_list_delete_link(icon_view->priv->selected_icons,
-                                                                         to_remove);
-                    xfdesktop_icon_view_invalidate_icon(icon_view, icon);
+                    xfdesktop_icon_view_unselect_item(icon_view, icon);
                 } else
                     l = l->next;
             }
@@ -1095,13 +1050,13 @@ xfdesktop_icon_view_motion_notify(GtkWidget *widget,
                 GdkRectangle extents, dummy;
                 XfdesktopIcon *icon = l->data;
 
-                if(xfdesktop_icon_get_extents(icon, &extents)
+                if(xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)
                    && gdk_rectangle_intersect(&extents, new_rect, &dummy)
                    && !g_list_find(icon_view->priv->selected_icons, icon))
                 {
-                    icon_view->priv->selected_icons = g_list_prepend(icon_view->priv->selected_icons,
-                                                                     icon);
-                    xfdesktop_icon_view_invalidate_icon(icon_view, icon);
+                    /* since _select_item() prepends to the list, we
+                     * should be ok just calling this */
+                    xfdesktop_icon_view_select_item(icon_view, icon);
                 }
             }
         }
@@ -1113,7 +1068,7 @@ xfdesktop_icon_view_motion_notify(GtkWidget *widget,
         
         if(icon_view->priv->item_under_pointer) {
             if(!xfdesktop_icon_get_extents(icon_view->priv->item_under_pointer,
-                                           &extents)
+                                           NULL, NULL, &extents)
                || !xfdesktop_rectangle_contains_point(&extents, evt->x, evt->y))
             {
                 icon = icon_view->priv->item_under_pointer;
@@ -1126,7 +1081,7 @@ xfdesktop_icon_view_motion_notify(GtkWidget *widget,
             icon = xfdesktop_icon_view_widget_coords_to_item(icon_view,
                                                              evt->x,
                                                              evt->y);
-            if(icon && xfdesktop_icon_get_extents(icon, &extents)
+            if(icon && xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)
                && xfdesktop_rectangle_contains_point(&extents, evt->x, evt->y))
             {
                 icon_view->priv->item_under_pointer = icon;
@@ -1153,7 +1108,7 @@ xfdesktop_icon_view_leave_notify(GtkWidget *widget,
 #endif
         icon_view->priv->item_under_pointer = NULL;
 #ifdef HAVE_LIBEXO
-        xfdesktop_icon_view_invalidate_icon(icon_view, icon);
+        xfdesktop_icon_view_invalidate_icon(icon_view, icon, FALSE);
 #endif
     }
     
@@ -1171,7 +1126,7 @@ xfdesktop_icon_view_drag_begin(GtkWidget *widget,
     icon = icon_view->priv->cursor;
     g_return_if_fail(icon);
     
-    if(xfdesktop_icon_get_extents(icon, &extents)) {
+    if(xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)) {
         GdkPixbuf *pix;
         
         pix = xfdesktop_icon_peek_pixbuf(icon, ICON_SIZE);
@@ -1375,7 +1330,6 @@ xfdesktop_icon_view_drag_drop(GtkWidget *widget,
     GdkAtom target = GDK_NONE;
     XfdesktopIcon *icon;
     guint16 old_row, old_col, row, col;
-    GdkRectangle extents;
     XfdesktopIcon *icon_on_dest = NULL;
     
     TRACE("entering: (%d,%d)", x, y);
@@ -1416,7 +1370,7 @@ xfdesktop_icon_view_drag_drop(GtkWidget *widget,
         g_return_val_if_fail(icon, FALSE);
         
         /* clear out old position */
-        xfdesktop_icon_view_invalidate_icon(icon_view, icon);
+        xfdesktop_icon_view_invalidate_icon(icon_view, icon, FALSE);
         if(xfdesktop_icon_get_position(icon, &old_row, &old_col))
             xfdesktop_grid_set_position_free(icon_view, old_row, old_col);
         /* set new position */
@@ -1424,10 +1378,9 @@ xfdesktop_icon_view_drag_drop(GtkWidget *widget,
         xfdesktop_grid_unset_position_free(icon_view, icon);
         
         /* clear out old extents, if any */
-        if(xfdesktop_icon_get_extents(icon, &extents)) {
-            extents.width = extents.height = 0;
-            xfdesktop_icon_set_extents(icon, &extents);
-        }
+        /* FIXME: is this right? */
+        //xfdesktop_icon_mark_extents_dirty(icon);
+        xfdesktop_icon_view_invalidate_icon(icon_view, icon, TRUE);
         
         DBG("drag succeeded");
         
@@ -1738,7 +1691,7 @@ xfdesktop_icon_view_unrealize(GtkWidget *widget)
     /* move all icons into the pending_icons list */
     for(l = icon_view->priv->icons; l; l = l->next) {
         g_signal_handlers_disconnect_by_func(G_OBJECT(l->data),
-                                             G_CALLBACK(xfdesktop_icon_view_invalidate_icon),
+                                             G_CALLBACK(xfdesktop_icon_view_icon_changed),
                                              icon_view);
     }
     icon_view->priv->pending_icons = g_list_concat(icon_view->priv->icons,
@@ -1918,8 +1871,13 @@ xfdesktop_icon_view_select_between(XfdesktopIconView *icon_view,
                 ++j)
             {
                 icon = xfdesktop_icon_view_icon_in_cell(icon_view, i, j);
-                if(icon)
+                if(icon) {
                     xfdesktop_icon_view_select_item(icon_view, icon);
+                    /* hack alert: without waiting for each icon to get
+                     * repainted, we get weird repaint issues */
+                    while(gtk_events_pending())
+                        gtk_main_iteration();
+                }
             }
         }
     }
@@ -2020,8 +1978,10 @@ xfdesktop_icon_view_move_cursor_left_right(XfdesktopIconView *icon_view,
             else
                 icon = xfdesktop_icon_view_find_last_icon(icon_view);
             
-            if(icon)
+            if(icon) {
                 xfdesktop_icon_view_select_item(icon_view, icon);
+                icon_view->priv->cursor = icon;
+            }
         }
     }
 }
@@ -2081,8 +2041,10 @@ xfdesktop_icon_view_move_cursor_up_down(XfdesktopIconView *icon_view,
             else
                 icon = xfdesktop_icon_view_find_last_icon(icon_view);
             
-            if(icon)
+            if(icon) {
                 xfdesktop_icon_view_select_item(icon_view, icon);
+                icon_view->priv->cursor = icon;
+            }
         }
     }
 }
@@ -2197,7 +2159,7 @@ xfdesktop_icon_view_repaint_icons(XfdesktopIconView *icon_view,
     for(l = icon_view->priv->icons; l; l = l->next) {
         icon = (XfdesktopIcon *)l->data;
 
-        if(!xfdesktop_icon_get_extents(icon, &extents)
+        if(!xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)
            || gdk_rectangle_intersect(area, &extents, &dummy))
         {
             /* we can't idle repaint icons while we're rubber banding, or
@@ -2372,19 +2334,45 @@ xfdesktop_rootwin_watch_workarea(GdkXEvent *gxevent,
 
 static void
 xfdesktop_icon_view_invalidate_icon(XfdesktopIconView *icon_view,
-                                    XfdesktopIcon *icon)
+                                    XfdesktopIcon *icon,
+                                    gboolean recalc_extents)
 {
     GdkRectangle extents;
+    gboolean invalidated_something = FALSE;
     
     g_return_if_fail(icon);
     
-    /*TRACE("entering");*/
+    /*TRACE("entering (recalc=%s)", recalc_extents?"true":"false");*/
+
+    /* we always have to invalidate the old extents */
+    if(xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)) {
+        if(GTK_WIDGET_REALIZED(icon_view)) {
+            gtk_widget_queue_draw_area(GTK_WIDGET(icon_view), extents.x,
+                                       extents.y, extents.width,
+                                       extents.height);
+        }
+        invalidated_something = TRUE;
+    } else
+        recalc_extents = TRUE;
     
-    if(xfdesktop_icon_get_extents(icon, &extents)) {
-        gtk_widget_queue_draw_area(GTK_WIDGET(icon_view),
-                                   extents.x, extents.y,
-                                   extents.width, extents.height);
-    } else {
+    if(recalc_extents) {
+        GdkRectangle pixbuf_extents, text_extents, total_extents;
+
+        if(!xfdesktop_icon_view_update_icon_extents(icon_view, icon,
+                                                    &pixbuf_extents,
+                                                    &text_extents,
+                                                    &total_extents))
+        {
+            g_warning("Trying to invalidate icon, but can't recalculate extents");
+        } else if(GTK_WIDGET_REALIZED(icon_view)) {
+            gtk_widget_queue_draw_area(GTK_WIDGET(icon_view),
+                                       total_extents.x, total_extents.y,
+                                       total_extents.width, total_extents.height);
+            invalidated_something = TRUE;
+        }
+    }
+
+    if(!invalidated_something) {
         DBG("Icon '%s' doesn't have extents: need to call paint some other way",
             xfdesktop_icon_peek_label(icon));
     }
@@ -2395,25 +2383,25 @@ static void
 xfdesktop_icon_view_invalidate_icon_pixbuf(XfdesktopIconView *icon_view,
                                            XfdesktopIcon *icon)
 {
-    guint16 row, col;
     GdkPixbuf *pix;
     
-    if(xfdesktop_icon_get_position(icon, &row, &col)
-       && (pix = xfdesktop_icon_peek_pixbuf(icon, ICON_SIZE)))
-    {
-        gint pix_x, pix_y, pix_w, pix_h, cell_x, cell_y;
-        
-        pix_w = gdk_pixbuf_get_width(pix);
-        pix_h = gdk_pixbuf_get_height(pix);
+    pix = xfdesktop_icon_peek_pixbuf(icon, ICON_SIZE);
+    if(pix) {
+        GdkRectangle rect = { 0, };
         
-        cell_x = SCREEN_MARGIN + icon_view->priv->xorigin + col * CELL_SIZE;
-        cell_y = SCREEN_MARGIN + icon_view->priv->yorigin + row * CELL_SIZE;
+        rect.width = gdk_pixbuf_get_width(pix);
+        rect.height = gdk_pixbuf_get_height(pix);
 
-        pix_x = cell_x + CELL_PADDING + ((CELL_SIZE - 2 * CELL_PADDING) - pix_w) / 2;
-        pix_y = cell_y + CELL_PADDING + SPACING;
+        if(!xfdesktop_icon_view_shift_area_to_cell(icon_view, icon, &rect))
+            return;
         
-        gtk_widget_queue_draw_area(GTK_WIDGET(icon_view), pix_x, pix_y,
-                                   pix_w, pix_h);
+        rect.x += CELL_PADDING + ((CELL_SIZE - 2 * CELL_PADDING) - rect.width) / 2;
+        rect.y += CELL_PADDING + SPACING;
+    
+        if(GTK_WIDGET_REALIZED(icon_view)) {
+            gtk_widget_queue_draw_area(GTK_WIDGET(icon_view), rect.x, rect.y,
+                                       rect.width, rect.height);
+        }
     }
 }
 #endif
@@ -2528,19 +2516,19 @@ xfdesktop_paint_rounded_box(XfdesktopIconView *icon_view,
                             GdkRectangle *text_area,
                             GdkRectangle *expose_area)
 {
-    GdkRectangle intersection;
+    GdkRectangle box_area, intersection;
     guchar alpha;
     
-    /* make sure to undo this before returning */
-    text_area->x -= CORNER_ROUNDNESS;
-    text_area->y -= CORNER_ROUNDNESS;
-    text_area->width += CORNER_ROUNDNESS * 2;
-    text_area->height += CORNER_ROUNDNESS * 2;
+    box_area = *text_area;
+    box_area.x -= CORNER_ROUNDNESS;
+    box_area.y -= CORNER_ROUNDNESS;
+    box_area.width += CORNER_ROUNDNESS * 2;
+    box_area.height += CORNER_ROUNDNESS * 2;
     
-    if(gdk_rectangle_intersect(text_area, expose_area, &intersection)) {
+    if(gdk_rectangle_intersect(&box_area, expose_area, &intersection)) {
         GdkPixbuf *box_pix = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
-                                            text_area->width,
-                                            text_area->height);
+                                            box_area.width,
+                                            box_area.height);
         GtkStyle *style = GTK_WIDGET(icon_view)->style;
         
         gdk_pixbuf_fill(box_pix, 0xffffffff);
@@ -2563,20 +2551,156 @@ xfdesktop_paint_rounded_box(XfdesktopIconView *icon_view,
                                                            alpha));
         
         gdk_draw_pixbuf(GDK_DRAWABLE(GTK_WIDGET(icon_view)->window), NULL,
-                        box_pix, intersection.x - text_area->x,
-                        intersection.y - text_area->y,
+                        box_pix, intersection.x - box_area.x,
+                        intersection.y - box_area.y,
                         intersection.x, intersection.y,
                         intersection.width, intersection.height,
                         GDK_RGB_DITHER_NORMAL, 0, 0);
         
         g_object_unref(G_OBJECT(box_pix));
     }
-    
-    /* undone from above */
-    text_area->x += CORNER_ROUNDNESS;
-    text_area->y += CORNER_ROUNDNESS;
-    text_area->width -= CORNER_ROUNDNESS * 2;
-    text_area->height -= CORNER_ROUNDNESS * 2;
+}
+
+static gboolean
+xfdesktop_icon_view_calculate_icon_pixbuf_area(XfdesktopIconView *icon_view,
+                                               XfdesktopIcon *icon,
+                                               GdkRectangle *pixbuf_area)
+{
+    GdkPixbuf *pix;
+
+    g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view)
+                         && XFDESKTOP_IS_ICON(icon)
+                         && pixbuf_area, FALSE);
+
+    pixbuf_area->x = 0;
+    pixbuf_area->y = 0;
+
+    pix = xfdesktop_icon_peek_pixbuf(icon, ICON_SIZE);
+    if(G_LIKELY(pix)) {
+        pixbuf_area->width = gdk_pixbuf_get_width(pix);
+        pixbuf_area->height = gdk_pixbuf_get_height(pix);
+    } else {
+        /* presumably this should never happen, but... */
+        pixbuf_area->width = ICON_SIZE;
+        pixbuf_area->height = ICON_SIZE;
+    }
+
+    return TRUE;
+}
+
+static void
+xfdesktop_icon_view_setup_pango_layout(XfdesktopIconView *icon_view,
+                                       XfdesktopIcon *icon,
+                                       PangoLayout *playout)
+{
+    const gchar *label = xfdesktop_icon_peek_label(icon);
+    PangoRectangle prect;
+
+    pango_layout_set_width(playout, -1);
+    pango_layout_set_ellipsize(playout, PANGO_ELLIPSIZE_NONE);
+    pango_layout_set_wrap(playout, PANGO_WRAP_WORD);
+    pango_layout_set_text(playout, label, -1);
+
+    pango_layout_get_pixel_extents(playout, NULL, &prect);
+    if(prect.width > TEXT_WIDTH) {
+//        if(icon != icon_view->priv->cursor && icon_view->priv->ellipsize_icon_labels)
+        if(!g_list_find(icon_view->priv->selected_icons, icon) && icon_view->priv->ellipsize_icon_labels)
+            pango_layout_set_ellipsize(playout, PANGO_ELLIPSIZE_END);
+        else {
+            pango_layout_set_ellipsize(playout, PANGO_ELLIPSIZE_NONE);
+            pango_layout_set_wrap(playout, PANGO_WRAP_WORD_CHAR);
+        }
+        pango_layout_set_width(playout, TEXT_WIDTH * PANGO_SCALE);
+    }
+}
+
+static gboolean
+xfdesktop_icon_view_calculate_icon_text_area(XfdesktopIconView *icon_view,
+                                             XfdesktopIcon *icon,
+                                             GdkRectangle *text_area)
+{
+    PangoLayout *playout;
+    PangoRectangle prect;
+
+    g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view)
+                         && XFDESKTOP_IS_ICON(icon)
+                         && text_area, FALSE);
+
+    playout = icon_view->priv->playout;
+    xfdesktop_icon_view_setup_pango_layout(icon_view, icon, playout);
+    pango_layout_get_pixel_extents(playout, NULL, &prect);
+
+    text_area->x = prect.x;
+    text_area->y = prect.y;
+    text_area->width = prect.width;
+    text_area->height = prect.height;
+
+    return TRUE;
+}
+
+static gboolean
+xfdesktop_icon_view_shift_area_to_cell(XfdesktopIconView *icon_view,
+                                       XfdesktopIcon *icon,
+                                       GdkRectangle *area)
+{
+    guint16 row, col;
+
+    if(!xfdesktop_icon_get_position(icon, &row, &col)) {
+        g_warning("trying to calculate without a position for icon '%s'",
+                  xfdesktop_icon_peek_label(icon));
+        return FALSE;
+    }
+
+    area->x += SCREEN_MARGIN + icon_view->priv->xorigin + col * CELL_SIZE;
+    area->y += SCREEN_MARGIN + icon_view->priv->yorigin + row * CELL_SIZE;
+
+    return TRUE;
+}
+
+static gboolean
+xfdesktop_icon_view_update_icon_extents(XfdesktopIconView *icon_view,
+                                        XfdesktopIcon *icon,
+                                        GdkRectangle *pixbuf_extents,
+                                        GdkRectangle *text_extents,
+                                        GdkRectangle *total_extents)
+{
+    GdkRectangle tmp_text;
+
+    g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view)
+                         && XFDESKTOP_IS_ICON(icon)
+                         && pixbuf_extents && text_extents
+                         && total_extents, FALSE);
+
+    if(!xfdesktop_icon_view_calculate_icon_pixbuf_area(icon_view, icon,
+                                                       pixbuf_extents)
+       || !xfdesktop_icon_view_shift_area_to_cell(icon_view, icon,
+                                                  pixbuf_extents))
+    {
+        return FALSE;
+    }
+    pixbuf_extents->x += CELL_PADDING + ((CELL_SIZE - CELL_PADDING * 2) - pixbuf_extents->width) / 2;
+    pixbuf_extents->y += CELL_PADDING + SPACING;
+
+    if(!xfdesktop_icon_view_calculate_icon_text_area(icon_view, icon,
+                                                     text_extents)
+       || !xfdesktop_icon_view_shift_area_to_cell(icon_view, icon,
+                                                  text_extents))
+    {
+        return FALSE;
+    }
+    text_extents->x += (CELL_SIZE - text_extents->width) / 2;
+    text_extents->y = pixbuf_extents->y + pixbuf_extents->height + SPACING + CORNER_ROUNDNESS;
+
+    tmp_text = *text_extents;
+    tmp_text.x -= CORNER_ROUNDNESS;
+    tmp_text.y -= CORNER_ROUNDNESS;
+    tmp_text.width += CORNER_ROUNDNESS * 2;
+    tmp_text.height += CORNER_ROUNDNESS * 2;
+    gdk_rectangle_union(pixbuf_extents, &tmp_text, total_extents);
+
+    xfdesktop_icon_set_extents(icon, pixbuf_extents, text_extents, total_extents);
+
+    return TRUE;
 }
 
 static void
@@ -2585,19 +2709,42 @@ xfdesktop_icon_view_paint_icon(XfdesktopIconView *icon_view,
                                GdkRectangle *area)
 {
     GtkWidget *widget = GTK_WIDGET(icon_view);
-    GdkPixbuf *pix = NULL;
-    gint cell_x, cell_y, state;
+    gint state;
     PangoLayout *playout;
-    GdkRectangle pix_area, text_area, intersection, adj_area;
-    const gchar *label;
-    guint16 row, col;
+    GdkRectangle pixbuf_extents, text_extents, total_extents;
+    GdkRectangle intersection;
     gchar x_offset = 0, y_offset = 0;
     GdkColor *sh_text_col = NULL;
     
     /*TRACE("entering (%s)", xfdesktop_icon_peek_label(icon));*/
+
+    playout = icon_view->priv->playout;
     
-    g_return_if_fail(xfdesktop_icon_get_position(icon, &row, &col));
-    
+    if(xfdesktop_icon_get_extents(icon, &pixbuf_extents,
+                                   &text_extents, &total_extents))
+    {
+        xfdesktop_icon_view_setup_pango_layout(icon_view, icon, playout);
+    } else {
+        /* if we get here, it's likely that the expose area doesn't
+         * include everything we *actually* need to repaint.  the
+         * extents should be recalculated before invalidating rects
+         * in the first place.  for now just fix it up and re-expose
+         * the correct area. */
+        if(!xfdesktop_icon_view_update_icon_extents(icon_view, icon,
+                                                    &pixbuf_extents,
+                                                    &text_extents,
+                                                    &total_extents))
+        {
+            g_warning("Can't update extents for icon '%s'",
+                      xfdesktop_icon_peek_label(icon));
+        } else {
+            gtk_widget_queue_draw_area(GTK_WIDGET(icon_view),
+                                       total_extents.x, total_extents.y,
+                                       total_extents.width, total_extents.height);
+        }
+        return;
+    }
+
     if(g_list_find(icon_view->priv->selected_icons, icon)) {
         if(GTK_WIDGET_FLAGS(widget) & GTK_HAS_FOCUS)
             state = GTK_STATE_SELECTED;
@@ -2606,43 +2753,16 @@ xfdesktop_icon_view_paint_icon(XfdesktopIconView *icon_view,
     } else
         state = GTK_STATE_NORMAL;
     
-    pix = xfdesktop_icon_peek_pixbuf(icon, ICON_SIZE);
-    pix_area.width = gdk_pixbuf_get_width(pix);
-    pix_area.height = gdk_pixbuf_get_height(pix);
-    
-    playout = icon_view->priv->playout;
-    pango_layout_set_width(playout, -1);
-    label = xfdesktop_icon_peek_label(icon);
-    pango_layout_set_text(playout, label, -1);
-    pango_layout_get_size(playout, &text_area.width, &text_area.height);
-    if(text_area.width > TEXT_WIDTH * PANGO_SCALE) {
-        if(icon != icon_view->priv->cursor && icon_view->priv->ellipsize_icon_labels)
-            pango_layout_set_ellipsize(playout, PANGO_ELLIPSIZE_END);
-        else {
-            pango_layout_set_wrap(playout, PANGO_WRAP_WORD_CHAR);
-            pango_layout_set_ellipsize(playout, PANGO_ELLIPSIZE_NONE);
-        }
-        pango_layout_set_width(playout, TEXT_WIDTH * PANGO_SCALE);
-    }
-    pango_layout_get_pixel_size(playout, &text_area.width, &text_area.height);
-    
-    cell_x = SCREEN_MARGIN + icon_view->priv->xorigin + col * CELL_SIZE;
-    cell_y = SCREEN_MARGIN + icon_view->priv->yorigin + row * CELL_SIZE;
+    if(gdk_rectangle_intersect(area, &pixbuf_extents, &intersection)) {
+        GdkPixbuf *pix = xfdesktop_icon_peek_pixbuf(icon, ICON_SIZE);
+        GdkPixbuf *pix_free = NULL;
 
-    pix_area.x = cell_x + CELL_PADDING + ((CELL_SIZE - 2 * CELL_PADDING) - pix_area.width) / 2;
-    pix_area.y = cell_y + CELL_PADDING + SPACING;
-    
-    text_area.x = cell_x + CELL_PADDING + ((CELL_SIZE - 2 * CELL_PADDING) - text_area.width) / 2;
-    text_area.y = cell_y + CELL_PADDING + SPACING + pix_area.height + SPACING + 2;
-    
-    if(gdk_rectangle_intersect(area, &pix_area, &intersection)) {
 #ifdef HAVE_LIBEXO
-        GdkPixbuf *pix_free = NULL;
-        
         if(state != GTK_STATE_NORMAL) {
             pix_free = exo_gdk_pixbuf_colorize(pix, &widget->style->base[state]);
             pix = pix_free;
         }
+
         if(icon_view->priv->item_under_pointer == icon) {
             GdkPixbuf *tmp = exo_gdk_pixbuf_spotlight(pix);
             if(pix_free)
@@ -2653,31 +2773,17 @@ xfdesktop_icon_view_paint_icon(XfdesktopIconView *icon_view,
 #endif
         
         gdk_draw_pixbuf(GDK_DRAWABLE(widget->window), widget->style->black_gc,
-                        pix, intersection.x - pix_area.x,
-                        intersection.y - pix_area.y,
+                        pix, intersection.x - pixbuf_extents.x,
+                        intersection.y - pixbuf_extents.y,
                         intersection.x, intersection.y,
                         intersection.width, intersection.height,
                         GDK_RGB_DITHER_NORMAL, 0, 0);
         
-#ifdef HAVE_LIBEXO
         if(pix_free)
             g_object_unref(G_OBJECT(pix_free));
-#endif
     }
     
-    /* this little hack is needed to ensure we paint the full text area even
-     * if the new text area is larger or smaller than the old */
-    if(!xfdesktop_icon_get_extents(icon, &intersection)
-       || text_area.height + CORNER_ROUNDNESS
-          != intersection.height - (pix_area.height + SPACING + 2))
-    {
-        memcpy(&adj_area, &text_area, sizeof(GdkRectangle));
-        adj_area.x -= CORNER_ROUNDNESS;
-        adj_area.y -= CORNER_ROUNDNESS;
-        adj_area.width += CORNER_ROUNDNESS * 2;
-        adj_area.height += CORNER_ROUNDNESS * 2;
-    } else
-        memcpy(&adj_area, area, sizeof(GdkRectangle));
+    xfdesktop_paint_rounded_box(icon_view, state, &text_extents, area);
 
     if (state == GTK_STATE_NORMAL) {
         x_offset = icon_view->priv->shadow_x_offset;
@@ -2690,7 +2796,7 @@ xfdesktop_icon_view_paint_icon(XfdesktopIconView *icon_view,
     }
 
     /* draw text shadow for the label text if an offset was defined */
-    if (x_offset || y_offset) {
+    if(x_offset || y_offset) {
         GdkGC *tmp_gc;
 
         /* FIXME: it's probably not good for performance to create and
@@ -2706,9 +2812,9 @@ xfdesktop_icon_view_paint_icon(XfdesktopIconView *icon_view,
 
         /* paint the shadow */
         gtk_paint_layout(widget->style, widget->window, state, TRUE,
-                         &adj_area, widget, "label",
-                         text_area.x + x_offset,
-                         text_area.y + y_offset,
+                         area, widget, "label",
+                         text_extents.x + x_offset,
+                         text_extents.y + y_offset,
                          playout);
 
         /* restore the original gc */
@@ -2718,15 +2824,51 @@ xfdesktop_icon_view_paint_icon(XfdesktopIconView *icon_view,
         g_object_unref(G_OBJECT(tmp_gc));
     }
     
-    xfdesktop_paint_rounded_box(icon_view, state, &text_area, &adj_area);
     gtk_paint_layout(widget->style, widget->window, state, FALSE,
-                     &adj_area, widget, "label", text_area.x, text_area.y, playout);
-    
-    intersection.x = (pix_area.width > text_area.width + CORNER_ROUNDNESS * 2 ? pix_area.x : text_area.x - CORNER_ROUNDNESS);
-    intersection.y = pix_area.y;
-    intersection.width = (pix_area.width > text_area.width + CORNER_ROUNDNESS * 2 ? pix_area.width : text_area.width + CORNER_ROUNDNESS * 2);
-    intersection.height = pix_area.height + SPACING + 2 + text_area.height + CORNER_ROUNDNESS;
-    xfdesktop_icon_set_extents(icon, &intersection);
+                     area, widget, "label",
+                     text_extents.x, text_extents.y, playout);
+
+#if 0 /*def DEBUG*/
+    {
+        cairo_t *cr = gdk_cairo_create(GDK_DRAWABLE(GTK_WIDGET(icon_view)->window));
+        GdkRectangle cell = { 0, };
+        guint16 row, col;
+
+        xfdesktop_icon_get_position(icon, &row, &col);
+        //DBG("for icon at (%hu,%hu) (%s)", row, col, xfdesktop_icon_peek_label(icon));
+
+        cairo_set_line_width(cr, 1.0);
+
+        cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0);
+        cairo_rectangle(cr, area->x, area->y, area->width, area->height);
+        cairo_stroke(cr);
+
+        cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0);
+        cairo_rectangle(cr, text_extents.x, text_extents.y,
+                        text_extents.width, text_extents.height);
+        cairo_stroke(cr);
+
+        cairo_set_source_rgba(cr, 1.0, 1.0, 0.0, 1.0);
+        cairo_rectangle(cr, total_extents.x, total_extents.y,
+                        total_extents.width, total_extents.height);
+        cairo_stroke(cr);
+
+        /* this might not totally paint, but that's ok */
+        cell.width = cell.height = CELL_SIZE;
+        xfdesktop_icon_view_shift_area_to_cell(icon_view, icon, &cell);
+
+        cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 1.0);
+        cairo_rectangle(cr, cell.x, cell.y, cell.width, cell.height);
+        cairo_stroke(cr);
+
+        cairo_destroy(cr);
+
+        //DBG("cell extents:       %dx%d+%d+%d", cell.width, cell.height, cell.x, cell.y);
+        //DBG("new pixbuf extents: %dx%d+%d+%d", pixbuf_extents.width, pixbuf_extents.height, pixbuf_extents.x, pixbuf_extents.y);
+        //DBG("new text extents:   %dx%d+%d+%d", text_extents.width, text_extents.height, text_extents.x, text_extents.y);
+        //DBG("new total extents:  %dx%d+%d+%d", total_extents.width, total_extents.height, total_extents.x, total_extents.y);
+    }
+#endif
 }
 
 static gboolean
@@ -2751,8 +2893,9 @@ xfdesktop_grid_do_resize(XfdesktopIconView *icon_view)
     
     /* move all icons into the pending_icons list */
     for(l = icon_view->priv->icons; l; l = l->next) {
+        xfdesktop_icon_mark_extents_dirty(XFDESKTOP_ICON(l->data));
         g_signal_handlers_disconnect_by_func(G_OBJECT(l->data),
-                                             G_CALLBACK(xfdesktop_icon_view_invalidate_icon),
+                                             G_CALLBACK(xfdesktop_icon_view_icon_changed),
                                              icon_view);
     }
     icon_view->priv->pending_icons = g_list_concat(icon_view->priv->icons,
@@ -2996,7 +3139,7 @@ xfdesktop_check_icon_clicked(gconstpointer data,
     GdkEventButton *evt = (GdkEventButton *)user_data;
     GdkRectangle extents;
     
-    if(xfdesktop_icon_get_extents(icon, &extents)
+    if(xfdesktop_icon_get_extents(icon, NULL, NULL, &extents)
        && xfdesktop_rectangle_contains_point(&extents, evt->x, evt->y))
     {
         return 0;
@@ -3010,7 +3153,7 @@ xfdesktop_list_foreach_invalidate(gpointer data,
 {
     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
     XfdesktopIcon *icon = XFDESKTOP_ICON(data);
-    xfdesktop_icon_view_invalidate_icon(icon_view, icon);
+    xfdesktop_icon_view_invalidate_icon(icon_view, icon, TRUE);
 }
 
 static void
@@ -3033,6 +3176,16 @@ xfdesktop_icon_view_modify_font_size(XfdesktopIconView *icon_view,
     pango_font_description_free(pfd_new);
 }
 
+static void
+xfdesktop_icon_view_icon_changed(XfdesktopIcon *icon,
+                                 gpointer user_data)
+{
+    /* maybe can pass FALSE here */
+    xfdesktop_icon_view_invalidate_icon(XFDESKTOP_ICON_VIEW(user_data),
+                                        icon, TRUE);
+}
+
+
 
 
 /* public api */
@@ -3065,12 +3218,12 @@ xfdesktop_icon_view_add_item_internal(XfdesktopIconView *icon_view,
     
     icon_view->priv->icons = g_list_prepend(icon_view->priv->icons, icon);
     
-    g_signal_connect_swapped(G_OBJECT(icon), "pixbuf-changed",
-                             G_CALLBACK(xfdesktop_icon_view_invalidate_icon),
-                             icon_view);
-    g_signal_connect_swapped(G_OBJECT(icon), "label-changed",
-                             G_CALLBACK(xfdesktop_icon_view_invalidate_icon),
-                             icon_view);
+    g_signal_connect(G_OBJECT(icon), "pixbuf-changed",
+                     G_CALLBACK(xfdesktop_icon_view_icon_changed),
+                     icon_view);
+    g_signal_connect(G_OBJECT(icon), "label-changed",
+                     G_CALLBACK(xfdesktop_icon_view_icon_changed),
+                     icon_view);
     
     fake_area.x = SCREEN_MARGIN + icon_view->priv->xorigin + col * CELL_SIZE;
     fake_area.y = SCREEN_MARGIN + icon_view->priv->yorigin + row * CELL_SIZE;
@@ -3141,22 +3294,25 @@ xfdesktop_icon_view_remove_item(XfdesktopIconView *icon_view,
                                 XfdesktopIcon *icon)
 {
     guint16 row, col;
+    GList *l;
     
     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view)
                      && XFDESKTOP_IS_ICON(icon));
     
-    if(g_list_find(icon_view->priv->icons, icon)) {
+    l = g_list_find(icon_view->priv->icons, icon);
+    if(l) {
         g_hash_table_remove(icon_view->priv->repaint_queue, icon);
         
         g_signal_handlers_disconnect_by_func(G_OBJECT(icon),
-                                             G_CALLBACK(xfdesktop_icon_view_invalidate_icon),
+                                             G_CALLBACK(xfdesktop_icon_view_icon_changed),
                                              icon_view);
         
         if(xfdesktop_icon_get_position(icon, &row, &col)) {
-            xfdesktop_icon_view_invalidate_icon(icon_view, icon);
+            xfdesktop_icon_view_invalidate_icon(icon_view, icon, FALSE);
+            xfdesktop_icon_mark_extents_dirty(icon);
             xfdesktop_grid_set_position_free(icon_view, row, col);
         }
-        icon_view->priv->icons = g_list_remove(icon_view->priv->icons, icon);
+        icon_view->priv->icons = g_list_delete_link(icon_view->priv->icons, l);
         icon_view->priv->selected_icons = g_list_remove(icon_view->priv->selected_icons,
                                                         icon);
         if(icon_view->priv->cursor == icon) {
@@ -3168,9 +3324,9 @@ xfdesktop_icon_view_remove_item(XfdesktopIconView *icon_view,
             icon_view->priv->first_clicked_item = NULL;
         if(icon_view->priv->item_under_pointer == icon)
             icon_view->priv->item_under_pointer = NULL;
-    } else if(g_list_find(icon_view->priv->pending_icons, icon)) {
-        icon_view->priv->pending_icons = g_list_remove(icon_view->priv->pending_icons,
-                                                       icon);
+    } else if((l = g_list_find(icon_view->priv->pending_icons, icon))) {
+        icon_view->priv->pending_icons = g_list_delete_link(icon_view->priv->pending_icons,
+                                                            l);
     } else {
         g_warning("Attempt to remove icon %p from XfdesktopIconView %p, but it's not in there.",
                   icon, icon_view);
@@ -3200,11 +3356,15 @@ xfdesktop_icon_view_remove_all(XfdesktopIconView *icon_view)
     }
     
     for(l = icon_view->priv->icons; l; l = l->next) {
-        if(xfdesktop_icon_get_position(XFDESKTOP_ICON(l->data), &row, &col))
+        XfdesktopIcon *icon = XFDESKTOP_ICON(l->data);
+        if(xfdesktop_icon_get_position(icon, &row, &col)) {
+            xfdesktop_icon_view_invalidate_icon(icon_view, icon, FALSE);
             xfdesktop_grid_set_position_free(icon_view, row, col);
+            xfdesktop_icon_mark_extents_dirty(icon);
+        }
         
         g_signal_handlers_disconnect_by_func(G_OBJECT(l->data),
-                                             G_CALLBACK(xfdesktop_icon_view_invalidate_icon),
+                                             G_CALLBACK(xfdesktop_icon_view_icon_changed),
                                              icon_view);
         g_object_set_data(G_OBJECT(l->data), "--xfdesktop-icon-view", NULL);
         g_object_unref(G_OBJECT(l->data));
@@ -3223,9 +3383,6 @@ xfdesktop_icon_view_remove_all(XfdesktopIconView *icon_view)
     icon_view->priv->item_under_pointer = NULL;
     icon_view->priv->cursor = NULL;
     icon_view->priv->first_clicked_item = NULL;
-    
-    if(GTK_WIDGET_REALIZED(icon_view))
-        gtk_widget_queue_draw(GTK_WIDGET(icon_view));
 }
 
 void
@@ -3419,7 +3576,12 @@ xfdesktop_icon_view_select_item(XfdesktopIconView *icon_view,
     
     icon_view->priv->selected_icons = g_list_prepend(icon_view->priv->selected_icons,
                                                      icon);
-    xfdesktop_icon_view_invalidate_icon(icon_view, icon);
+    xfdesktop_icon_view_invalidate_icon(icon_view, icon, TRUE);
+    
+    g_signal_emit(G_OBJECT(icon_view),
+                  __signals[SIG_ICON_SELECTION_CHANGED],
+                  0, NULL);
+    xfdesktop_icon_selected(icon);
 }
 
 void
@@ -3429,27 +3591,50 @@ xfdesktop_icon_view_select_all(XfdesktopIconView *icon_view)
 
     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view));
 
+    if(!icon_view->priv->icons)
+        return;
+
+    if(icon_view->priv->selected_icons
+       && g_list_length(icon_view->priv->icons)
+          == g_list_length(icon_view->priv->selected_icons))
+    {
+        return;
+    }
+
     /* simplify: just free the entire list and repopulate it */
-    g_list_free(icon_view->priv->selected_icons);
-    icon_view->priv->selected_icons = NULL;
+    if(icon_view->priv->selected_icons) {
+        g_list_free(icon_view->priv->selected_icons);
+        icon_view->priv->selected_icons = NULL;
+    }
 
     for(l = icon_view->priv->icons; l; l = l->next) {
         icon_view->priv->selected_icons = g_list_prepend(icon_view->priv->selected_icons, l->data);
-        xfdesktop_icon_view_invalidate_icon(icon_view, l->data);
+        xfdesktop_icon_view_invalidate_icon(icon_view, l->data, TRUE);
+        xfdesktop_icon_selected(l->data);
     }
+
+    g_signal_emit(G_OBJECT(icon_view),
+                  __signals[SIG_ICON_SELECTION_CHANGED],
+                  0, NULL);
 }
 
 void
 xfdesktop_icon_view_unselect_item(XfdesktopIconView *icon_view,
                                   XfdesktopIcon *icon)
 {
+    GList *l;
+
     g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view)
                      && XFDESKTOP_IS_ICON(icon));
     
-    if(g_list_find(icon_view->priv->selected_icons, icon)) {
-        icon_view->priv->selected_icons = g_list_remove(icon_view->priv->selected_icons,
-                                                        icon);
-        xfdesktop_icon_view_invalidate_icon(icon_view, icon);
+    l = g_list_find(icon_view->priv->selected_icons, icon);
+    if(l) {
+        icon_view->priv->selected_icons = g_list_delete_link(icon_view->priv->selected_icons,
+                                                             l);
+        xfdesktop_icon_view_invalidate_icon(icon_view, icon, TRUE);
+        g_signal_emit(G_OBJECT(icon_view),
+                      __signals[SIG_ICON_SELECTION_CHANGED],
+                      0, NULL);
     }
 }
 
@@ -3464,6 +3649,9 @@ xfdesktop_icon_view_unselect_all(XfdesktopIconView *icon_view)
         g_list_foreach(repaint_icons, xfdesktop_list_foreach_invalidate,
                        icon_view);
         g_list_free(repaint_icons);
+        g_signal_emit(G_OBJECT(icon_view),
+                      __signals[SIG_ICON_SELECTION_CHANGED],
+                      0, NULL);
     }
 }
 
@@ -3478,7 +3666,7 @@ xfdesktop_icon_view_set_icon_size(XfdesktopIconView *icon_view,
     
     icon_view->priv->icon_size = icon_size;
     
-    if(GTK_WIDGET_REALIZED(GTK_WIDGET(icon_view))) {
+    if(GTK_WIDGET_REALIZED(icon_view)) {
         xfdesktop_grid_do_resize(icon_view);
         gtk_widget_queue_draw(GTK_WIDGET(icon_view));
     }
@@ -3502,7 +3690,7 @@ xfdesktop_icon_view_set_font_size(XfdesktopIconView *icon_view,
     
     icon_view->priv->font_size = font_size_points;
     
-    if(GTK_WIDGET_REALIZED(GTK_WIDGET(icon_view))) {
+    if(GTK_WIDGET_REALIZED(icon_view)) {
         xfdesktop_icon_view_modify_font_size(icon_view, font_size_points);
         xfdesktop_grid_do_resize(icon_view);
         gtk_widget_queue_draw(GTK_WIDGET(icon_view));
diff --git a/src/xfdesktop-icon.c b/src/xfdesktop-icon.c
index c1a747a..431ba79 100644
--- a/src/xfdesktop-icon.c
+++ b/src/xfdesktop-icon.c
@@ -36,7 +36,11 @@ struct _XfdesktopIconPrivate
 {
     gint16 row;
     gint16 col;
-    GdkRectangle extents;
+
+    gboolean extents_dirty;
+    GdkRectangle pixbuf_extents;
+    GdkRectangle text_extents;
+    GdkRectangle total_extents;
 };
 
 enum {
@@ -112,6 +116,7 @@ xfdesktop_icon_init(XfdesktopIcon *icon)
 {
     icon->priv = G_TYPE_INSTANCE_GET_PRIVATE(icon, XFDESKTOP_TYPE_ICON,
                                              XfdesktopIconPrivate);
+    icon->priv->extents_dirty = TRUE;
 }
 
 
@@ -143,25 +148,46 @@ xfdesktop_icon_get_position(XfdesktopIcon *icon,
 
 void
 xfdesktop_icon_set_extents(XfdesktopIcon *icon,
-                           const GdkRectangle *extents)
+                           const GdkRectangle *pixbuf_extents,
+                           const GdkRectangle *text_extents,
+                           const GdkRectangle *total_extents)
 {
-    g_return_if_fail(XFDESKTOP_IS_ICON(icon));
-    
-    memcpy(&icon->priv->extents, extents, sizeof(GdkRectangle));
+    g_return_if_fail(XFDESKTOP_IS_ICON(icon) && pixbuf_extents
+                     && text_extents && total_extents);
+
+    icon->priv->pixbuf_extents = *pixbuf_extents;
+    icon->priv->text_extents = *text_extents;
+    icon->priv->total_extents = *total_extents;
+    icon->priv->extents_dirty = FALSE;
 }
 
 gboolean
 xfdesktop_icon_get_extents(XfdesktopIcon *icon,
-                           GdkRectangle *extents)
+                           GdkRectangle *pixbuf_extents,
+                           GdkRectangle *text_extents,
+                           GdkRectangle *total_extents)
 {
-    g_return_val_if_fail(XFDESKTOP_IS_ICON(icon) && extents, FALSE);
-    
-    if(icon->priv->extents.width > 0 && icon->priv->extents.height > 0) {
-        memcpy(extents, &icon->priv->extents, sizeof(GdkRectangle));
-        return TRUE;
-    }
-    
-    return FALSE;
+    g_return_val_if_fail(XFDESKTOP_IS_ICON(icon), FALSE);
+
+    if(icon->priv->extents_dirty)
+        return FALSE;
+
+    if(pixbuf_extents)
+        *pixbuf_extents = icon->priv->pixbuf_extents;
+    if(text_extents)
+        *text_extents = icon->priv->text_extents;
+    if(total_extents)
+        *total_extents = icon->priv->total_extents;
+
+    return TRUE;
+}
+
+void
+xfdesktop_icon_mark_extents_dirty(XfdesktopIcon *icon)
+{
+    g_return_if_fail(XFDESKTOP_IS_ICON(icon));
+
+    icon->priv->extents_dirty = TRUE;
 }
 
 
@@ -286,6 +312,7 @@ void
 xfdesktop_icon_pixbuf_changed(XfdesktopIcon *icon)
 {
     g_return_if_fail(XFDESKTOP_IS_ICON(icon));
+    xfdesktop_icon_mark_extents_dirty(icon);
     g_signal_emit(icon, __signals[SIG_PIXBUF_CHANGED], 0);
 }
 
@@ -293,6 +320,7 @@ void
 xfdesktop_icon_label_changed(XfdesktopIcon *icon)
 {
     g_return_if_fail(XFDESKTOP_IS_ICON(icon));
+    xfdesktop_icon_mark_extents_dirty(icon);
     g_signal_emit(icon, __signals[SIG_LABEL_CHANGED], 0);
 }
 
@@ -300,6 +328,7 @@ void
 xfdesktop_icon_position_changed(XfdesktopIcon *icon)
 {
     g_return_if_fail(XFDESKTOP_IS_ICON(icon));
+    xfdesktop_icon_mark_extents_dirty(icon);
     g_signal_emit(icon, __signals[SIG_POS_CHANGED], 0);
 }
 
@@ -308,6 +337,7 @@ void
 xfdesktop_icon_selected(XfdesktopIcon *icon)
 {
     g_return_if_fail(XFDESKTOP_IS_ICON(icon));
+    xfdesktop_icon_mark_extents_dirty(icon);
     g_signal_emit(G_OBJECT(icon), __signals[SIG_SELECTED], 0, NULL);
 }
 
diff --git a/src/xfdesktop-icon.h b/src/xfdesktop-icon.h
index f0d311a..f0c84bf 100644
--- a/src/xfdesktop-icon.h
+++ b/src/xfdesktop-icon.h
@@ -93,11 +93,6 @@ gboolean xfdesktop_icon_get_position(XfdesktopIcon *icon,
                                      guint16 *row,
                                      guint16 *col);
 
-void xfdesktop_icon_set_extents(XfdesktopIcon *icon,
-                                const GdkRectangle *extents);
-gboolean xfdesktop_icon_get_extents(XfdesktopIcon *icon,
-                                    GdkRectangle *extents);
-
 GdkDragAction xfdesktop_icon_get_allowed_drag_actions(XfdesktopIcon *icon);
 
 GdkDragAction xfdesktop_icon_get_allowed_drop_actions(XfdesktopIcon *icon);
@@ -119,6 +114,17 @@ void xfdesktop_icon_position_changed(XfdesktopIcon *icon);
 void xfdesktop_icon_selected(XfdesktopIcon *icon);
 gboolean xfdesktop_icon_activated(XfdesktopIcon *icon);
 
+/*< private-ish; only for use by XfdesktopIconView >*/
+void xfdesktop_icon_set_extents(XfdesktopIcon *icon,
+                                const GdkRectangle *pixbuf_extents,
+                                const GdkRectangle *text_extents,
+                                const GdkRectangle *total_extents);
+gboolean xfdesktop_icon_get_extents(XfdesktopIcon *icon,
+                                    GdkRectangle *pixbuf_extents,
+                                    GdkRectangle *text_extents,
+                                    GdkRectangle *total_extents);
+void xfdesktop_icon_mark_extents_dirty(XfdesktopIcon *icon);
+
 G_END_DECLS
 
 #endif  /* __XFDESKTOP_ICON_H__ */



More information about the Xfce4-commits mailing list