*** a/applets/notification_area/na-tray.c	2010-05-26 04:31:06.000000000 -0400
--- b/applets/notification_area/na-tray.c	2010-11-16 14:42:22.000000000 -0500
***************
*** 33,39 ****
  #include "na-tray.h"
  
  #define ICON_SPACING 1
! #define MIN_BOX_SIZE 3
  
  typedef struct
  {
--- 33,40 ----
  #include "na-tray.h"
  
  #define ICON_SPACING 1
! #define MIN_TABLE_SIZE 3
! #define MIN_ICON_SIZE 22
  
  typedef struct
  {
***************
*** 48,54 ****
    GdkScreen   *screen;
    TraysScreen *trays_screen;
  
!   GtkWidget *box;
    GtkWidget *frame;
  
    guint idle_redraw_id;
--- 49,55 ----
    GdkScreen   *screen;
    TraysScreen *trays_screen;
  
!   GtkWidget *table;
    GtkWidget *frame;
  
    guint idle_redraw_id;
***************
*** 85,109 ****
  
  static void icon_tip_show_next (IconTip *icontip);
  
- /* NaBox, an instantiable GtkBox */
- 
- typedef GtkBox      NaBox;
- typedef GtkBoxClass NaBoxClass;
- 
- static GType na_box_get_type (void);
- 
- G_DEFINE_TYPE (NaBox, na_box, GTK_TYPE_BOX)
- 
- static void
- na_box_init (NaBox *box)
- {
- }
- 
- static void
- na_box_class_init (NaBoxClass *klass)
- {
- }
- 
  /* NaTray */
  
  G_DEFINE_TYPE (NaTray, na_tray, GTK_TYPE_BIN)
--- 86,91 ----
***************
*** 135,219 ****
    NULL,
  };
  
! static const char *
! find_role (const char *wmclass)
  {
!   int i;
! 
!   for (i = 0; wmclass_roles[i]; i += 2)
!     {
!       if (strcmp (wmclass, wmclass_roles[i]) == 0)
!         return wmclass_roles[i + 1];
!     }
! 
!   return NULL;
! }
! 
! static int
! find_role_position (const char *role)
! {
!   int i;
! 
!   for (i = 0; ordered_roles[i]; i++)
!     {
!       if (strcmp (role, ordered_roles[i]) == 0)
!         break;
!     }
  
!   return i + 1;
  }
  
! static int
! find_icon_position (NaTray    *tray,
!                     GtkWidget *icon)
  {
    NaTrayPrivate *priv;
!   int            position;
!   char          *class_a;
!   const char    *role;
!   int            role_position;
!   GList         *l, *children;
! 
!   /* We insert the icons with a known roles in a specific order (the one
!    * defined by ordered_roles), and all other icons at the beginning of the box
!    * (left in LTR). */
! 
!   priv = tray->priv;
!   position = 0;
  
!   class_a = NULL;
!   na_tray_child_get_wm_class (NA_TRAY_CHILD (icon), NULL, &class_a);
!   if (!class_a)
!     return position;
! 
!   role = find_role (class_a);
!   g_free (class_a);
!   if (!role)
!     return position;
! 
!   role_position = find_role_position (role);
!   g_object_set_data (G_OBJECT (icon), "role-position", GINT_TO_POINTER (role_position));
! 
!   children = gtk_container_get_children (GTK_CONTAINER (priv->box));
!   for (l = g_list_last (children); l; l = l->prev)
!     {
!       GtkWidget *child = l->data;
!       int        rp;
! 
!       rp = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (child), "role-position"));
!       if (rp == 0 || rp < role_position)
!         {
!           position = g_list_index (children, child) + 1;
!           break;
!         }
!     }
!   g_list_free (children);
  
!   /* should never happen, but it doesn't hurt to be on the safe side */
!   if (position < 0)
!     position = 0;
  
!   return position;
  }
  
  static void
--- 117,206 ----
    NULL,
  };
  
! typedef struct _PackData {
!   GtkOrientation orient;
!   guint n_rows;
!   guint n_cols;
!   guint index;
! } PackData;
! 
! static void repack_icon_with_data(GtkWidget *icon,
!                                   NaTray *tray,
!                                   PackData *data)
  {
!   NaTrayPrivate *priv;
!   priv = tray->priv;
!   guint row, col;
!   guint left, right, top, bottom;
  
!   /* row / col number depends on whether we are horizontal or vertical */
!   if (data->orient == GTK_ORIENTATION_HORIZONTAL) {
!     col = data->index / data->n_rows;
!     row = data->index %  data->n_rows;
!   } else {
!     row = data->index / data->n_cols;
!     col = data->index %  data->n_cols;
!   }
!   /* only update icon position if has changed from current */
!   gtk_container_child_get (GTK_CONTAINER (priv->table),
!                            icon,
!                            "left-attach", &left,
!                            "right-attach", &right,
!                            "top-attach", &top,
!                            "bottom-attach", &bottom,
!                            NULL);
!   if (left != col || right != col + 1 ||
!       top != row || bottom != row + 1)
!   {
!     gtk_container_child_set (GTK_CONTAINER (priv->table),
!                              icon,
!                              "left-attach", col,
!                              "right-attach", col + 1,
!                              "top-attach", row,
!                              "bottom-attach", row + 1,
!                              NULL);
!   }
!   /* increment to index of next icon */
!   data->index++;
  }
  
! static void
! repack_icon_table(TraysScreen *trays_screen)
  {
+   NaTray *tray;
    NaTrayPrivate *priv;
!   guint rows, cols;
!   PackData pack_data;
  
!   tray = get_tray (trays_screen);
!   if (tray == NULL)
!     return;
  
!   priv = tray->priv;
  
!   if (trays_screen->icon_table)
!   {
!     if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) {
!       rows = MAX (1, GTK_WIDGET (tray)->allocation.height / MIN_ICON_SIZE);
!       cols = MAX (1, g_hash_table_size (trays_screen->icon_table) / rows);
!       if (g_hash_table_size (trays_screen->icon_table) % rows)
!         cols++;
!     } else {
!       cols = MAX (1, GTK_WIDGET (tray)->allocation.width / MIN_ICON_SIZE);
!       rows = MAX (1, g_hash_table_size (trays_screen->icon_table) / cols);
!       if (g_hash_table_size (trays_screen->icon_table) % cols)
!         rows++;
!     }
!     gtk_table_resize (GTK_TABLE (priv->table), rows, cols);
!     pack_data.n_rows = rows;
!     pack_data.n_cols = cols;
!     pack_data.orient = priv->orientation;
!     pack_data.index = 0;
! 
!     g_hash_table_foreach (trays_screen->icon_table,
!                          (GHFunc)repack_icon_with_data,
!                          &pack_data);
!   }
  }
  
  static void
***************
*** 223,229 ****
  {
    NaTray *tray;
    NaTrayPrivate *priv;
!   int position;
  
    tray = get_tray (trays_screen);
    if (tray == NULL)
--- 210,216 ----
  {
    NaTray *tray;
    NaTrayPrivate *priv;
!   guint rows, cols;
  
    tray = get_tray (trays_screen);
    if (tray == NULL)
***************
*** 235,243 ****
  
    g_hash_table_insert (trays_screen->icon_table, icon, tray);
  
!   position = find_icon_position (tray, icon);
!   gtk_box_pack_start (GTK_BOX (priv->box), icon, FALSE, FALSE, 0);
!   gtk_box_reorder_child (GTK_BOX (priv->box), icon, position);
  
    gtk_widget_show (icon);
  }
--- 222,244 ----
  
    g_hash_table_insert (trays_screen->icon_table, icon, tray);
  
!   /* append to table */
!   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) {
!     rows = MAX (1, GTK_WIDGET (tray)->allocation.height / MIN_ICON_SIZE);
!     cols = MAX (1, g_hash_table_size (trays_screen->icon_table) / rows);
!     if (g_hash_table_size (trays_screen->icon_table) % rows)
!       cols++;
!   } else {
!     cols = MAX (1, GTK_WIDGET (tray)->allocation.width / MIN_ICON_SIZE);
!     rows = MAX (1, g_hash_table_size (trays_screen->icon_table) / cols);
!     if (g_hash_table_size (trays_screen->icon_table) % cols)
!       rows++;
!   }
!   gtk_table_resize (GTK_TABLE (priv->table), rows, cols);
!   gtk_table_attach_defaults (GTK_TABLE (priv->table),
!                              icon,
!                              cols - 1, cols,
!                              rows - 1, rows);
  
    gtk_widget_show (icon);
  }
***************
*** 248,261 ****
--- 249,267 ----
                TraysScreen   *trays_screen)
  {
    NaTray *tray;
+   NaTrayPrivate *priv;
  
    tray = g_hash_table_lookup (trays_screen->icon_table, icon);
    if (tray == NULL)
      return;
  
+   priv = tray->priv;
    g_assert (tray->priv->trays_screen == trays_screen);
  
    g_hash_table_remove (trays_screen->icon_table, icon);
+   repack_icon_table (trays_screen);
+   gtk_container_remove (GTK_CONTAINER (priv->table), icon);
+ 
    /* this will also destroy the tip associated to this icon */
    g_hash_table_remove (trays_screen->tip_table, icon);
  }
***************
*** 498,505 ****
  {
    NaTrayPrivate *priv = tray->priv;
  
-   gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->box), priv->orientation);
- 
    /* This only happens when setting the property during object construction */
    if (!priv->trays_screen)
      return;
--- 504,509 ----
***************
*** 515,527 ****
    switch (priv->orientation)
      {
      case GTK_ORIENTATION_VERTICAL:
!       /* Give box a min size so the frame doesn't look dumb */
!       gtk_widget_set_size_request (priv->box, MIN_BOX_SIZE, -1);
        break;
      case GTK_ORIENTATION_HORIZONTAL:
!       gtk_widget_set_size_request (priv->box, -1, MIN_BOX_SIZE);
        break;
      }
  }
  
  /* Children with alpha channels have been set to be composited by calling
--- 519,533 ----
    switch (priv->orientation)
      {
      case GTK_ORIENTATION_VERTICAL:
!       /* Give table a min size so the frame doesn't look dumb */
!       gtk_widget_set_size_request (priv->table, MIN_TABLE_SIZE, -1);
        break;
      case GTK_ORIENTATION_HORIZONTAL:
!       gtk_widget_set_size_request (priv->table, -1, MIN_TABLE_SIZE);
        break;
      }
+ 
+   repack_icon_table (priv->trays_screen);
  }
  
  /* Children with alpha channels have been set to be composited by calling
***************
*** 543,557 ****
  }
  
  static void
! na_tray_expose_box (GtkWidget      *box,
  		    GdkEventExpose *event)
  {
!   cairo_t *cr = gdk_cairo_create (box->window);
  
    gdk_cairo_region (cr, event->region);
    cairo_clip (cr);
  
!   gtk_container_foreach (GTK_CONTAINER (box), na_tray_expose_icon, cr);
  
    cairo_destroy (cr);
  }
--- 549,563 ----
  }
  
  static void
! na_tray_expose_table (GtkWidget      *table,
  		    GdkEventExpose *event)
  {
!   cairo_t *cr = gdk_cairo_create (table->window);
  
    gdk_cairo_region (cr, event->region);
    cairo_clip (cr);
  
!   gtk_container_foreach (GTK_CONTAINER (table), na_tray_expose_icon, cr);
  
    cairo_destroy (cr);
  }
***************
*** 570,581 ****
    gtk_container_add (GTK_CONTAINER (tray), priv->frame);
    gtk_widget_show (priv->frame);
  
!   priv->box = g_object_new (na_box_get_type (), NULL);
!   g_signal_connect (priv->box, "expose-event",
! 		    G_CALLBACK (na_tray_expose_box), tray);
!   gtk_box_set_spacing (GTK_BOX (priv->box), ICON_SPACING);
!   gtk_container_add (GTK_CONTAINER (priv->frame), priv->box);
!   gtk_widget_show (priv->box);
  }
  
  static GObject *
--- 576,588 ----
    gtk_container_add (GTK_CONTAINER (tray), priv->frame);
    gtk_widget_show (priv->frame);
  
!   priv->table = gtk_table_new (0, 0, TRUE);
!   g_signal_connect (priv->table, "expose-event",
!                     G_CALLBACK (na_tray_expose_table), tray);
!   gtk_table_set_row_spacings (GTK_TABLE (priv->table), ICON_SPACING);
!   gtk_table_set_col_spacings (GTK_TABLE (priv->table), ICON_SPACING);
!   gtk_container_add (GTK_CONTAINER (priv->frame), priv->table);
!   gtk_widget_show (priv->table);
  }
  
  static GObject *
***************
*** 736,742 ****
--- 743,753 ----
  na_tray_size_allocate (GtkWidget        *widget,
                         GtkAllocation    *allocation)
  {
+   NaTray *tray = NA_TRAY (widget);
+ 
+   widget->allocation = *allocation;
    gtk_widget_size_allocate (gtk_bin_get_child (GTK_BIN (widget)), allocation);
+   repack_icon_table (tray->priv->trays_screen);
  }
  
  static void
***************
*** 813,819 ****
  {
    NaTrayPrivate *priv = tray->priv;
  
!   gtk_container_foreach (GTK_CONTAINER (priv->box), (GtkCallback)na_tray_child_force_redraw, tray);
    
    priv->idle_redraw_id = 0;
  
--- 824,830 ----
  {
    NaTrayPrivate *priv = tray->priv;
  
!   gtk_container_foreach (GTK_CONTAINER (priv->table), (GtkCallback)na_tray_child_force_redraw, tray);
    
    priv->idle_redraw_id = 0;
  
