Index: libwnck/tasklist.c
===================================================================
RCS file: /cvs/gnome/libwnck/libwnck/tasklist.c,v
retrieving revision 1.99
diff -u -r1.99 tasklist.c
--- libwnck/tasklist.c	28 Mar 2006 21:49:20 -0000	1.99
+++ libwnck/tasklist.c	6 Apr 2006 00:26:01 -0000
@@ -2054,22 +2054,16 @@
 				     WnckTasklist *tasklist)
 {
   WnckWindow *active_window;
-  WnckWindow *initial_window;
   WnckTask *active_task = NULL;
 
-  /* FIXME: check for group modal window */
-  initial_window = active_window = wnck_screen_get_active_window (screen);
-  active_task = g_hash_table_lookup (tasklist->priv->win_hash, active_window);
-  while (active_window && !active_task)
-    {
-      active_window = wnck_window_get_transient (active_window);
-      active_task = g_hash_table_lookup (tasklist->priv->win_hash, 
-                                         active_window);
-      /* Check for transient cycles */
-      if (active_window == initial_window)
-        break;
-    }
+  /* Descend transiency chain: guaranteed to be safe */
+  for (active_window = wnck_screen_get_active_window (screen);
+       active_window && !active_task;
+       active_window = wnck_window_get_transient (active_window))
+    ;
 
+  active_task = g_hash_table_lookup (tasklist->priv->win_hash, 
+                                     active_window);
   wnck_tasklist_change_active_task (tasklist, active_task);
 }
 
@@ -2309,7 +2303,7 @@
           !tasklist->priv->switch_workspace_on_unminimize)
         wnck_workspace_activate (window_ws, timestamp);
 
-      wnck_window_activate_transient (task->window, timestamp);
+      wnck_window_unminimize (task->window, timestamp);
     }
   else
     {
@@ -2838,7 +2832,7 @@
     {
       WnckTask *win_task = NULL;
 
-      /* FIXME: Handle group modal dialogs */
+      /* Descend transiency chain: guaranteed to be safe */
       for (; window && !win_task; window = wnck_window_get_transient (window))
         win_task = g_hash_table_lookup (tasklist->priv->win_hash, window);
 
Index: libwnck/window.c
===================================================================
RCS file: /cvs/gnome/libwnck/libwnck/window.c,v
retrieving revision 1.64
diff -u -r1.64 window.c
--- libwnck/window.c	28 Mar 2006 21:49:20 -0000	1.64
+++ libwnck/window.c	6 Apr 2006 00:26:02 -0000
@@ -89,10 +89,13 @@
   char *res_class;
   char *res_name;
   
-  /* true if transient_for points to root window,
-   * not another app window
+  /* true if window is group-transient */
+  guint transient_for_group : 1;
+  /* True if window is part of a WM_TRANSIENT_FOR cycle.
+   * This is used only for bookkeeping when the hint changes.
+   * Note that pointing into a cycle does not make this true.
    */
-  guint transient_for_root : 1;
+  guint transient_for_cycle : 1;
   
   /* window state */
   guint is_minimized : 1;
@@ -486,11 +489,23 @@
   return window->priv->app;
 }
 
+/**
+ * wnck_window_get_transient:
+ * @window: a #WnckWindow
+ *
+ * Gets the parent of a transient window.
+ * Parent is guaranteed to be distinct from @window, and will be NULL
+ * for a non-transient or group-modal window.
+ *
+ * Return value: parent of the window
+ **/
 WnckWindow*
 wnck_window_get_transient (WnckWindow *window)
 {
   g_return_val_if_fail (WNCK_IS_WINDOW (window), None);
 
+  if (window->priv->transient_for_group)
+    return NULL;
   return wnck_window_get (window->priv->transient_for);
 }
 
@@ -719,10 +734,6 @@
   transient = window;
   while ((transient = find_last_transient_for (windows, transient->priv->xwindow)))
     {
-      /* catch transient cycles */
-      if (transient == window)
-        return FALSE;
-
       if (wnck_window_needs_attention (transient))
         return TRUE;
     }
@@ -1275,8 +1286,9 @@
   while (tmp != NULL)
     {
       WnckWindow *w = tmp->data;
+      WnckWindow *parent = wnck_window_get_transient(w);
 
-      if (w->priv->transient_for == xwindow &&
+      if (parent && parent->priv->xwindow == xwindow &&
 	  w->priv->wintype != WNCK_WINDOW_UTILITY)
         retval = w;
       
@@ -1317,13 +1329,6 @@
   
   while (next != NULL)
     {
-      if (next == window)
-        {
-          /* catch transient cycles */
-          transient = NULL;
-          break;
-        }
-
       transient = next;
       
       next = find_last_transient_for (windows, transient->priv->xwindow);
@@ -1365,10 +1370,6 @@
   transient = window;
   while ((transient = find_last_transient_for (windows, transient->priv->xwindow)))
     {
-      /* catch transient cycles */
-      if (transient == window)
-        return FALSE;
-
       if (wnck_window_is_most_recently_activated (transient))
         return TRUE;
     }
@@ -1870,7 +1871,7 @@
        * for some main application window
        */
       if (window->priv->transient_for != None &&
-          !window->priv->transient_for_root)
+          !window->priv->transient_for_group)
         window->priv->skip_taskbar = TRUE;
       break;
       
@@ -2142,7 +2143,8 @@
 
   if (!found_type)
     {
-      if (window->priv->transient_for != None)
+      if (window->priv->transient_for != None ||
+          window->priv->transient_for_group)
         {
           type = WNCK_WINDOW_DIALOG;
         }
@@ -2159,29 +2161,67 @@
 static void
 update_transient_for (WnckWindow *window)
 {
-  Window parent;
+  Window parent, old_parent;
+  WnckWindow *ancestor;
 
   if (!window->priv->need_update_transient_for)
     return;
 
   window->priv->need_update_transient_for = FALSE;
-  
+
   if (_wnck_get_window (window->priv->xwindow,
                         _wnck_atom_get ("WM_TRANSIENT_FOR"),
-                        &parent) &&
-      parent != window->priv->xwindow)
+                        &parent))
     {
-      window->priv->transient_for = parent;
+      /* 1. Remove transient_for; update members of any broken cycle. */
+      old_parent = window->priv->transient_for;
+      window->priv->transient_for = None;
+      window->priv->transient_for_group = FALSE;
+
+      if (window->priv->transient_for_cycle)
+        {
+          for (ancestor = wnck_window_get (old_parent);
+               ancestor;
+               ancestor = wnck_window_get (ancestor->priv->transient_for))
+            {
+              ancestor->priv->transient_for_cycle = FALSE;
+              ancestor->priv->transient_for_group = FALSE;
+            }
+        }
 
+      /* 2. Add new transient_for; check for root-transiency or cycles. */
+      window->priv->transient_for = parent;
       if (wnck_screen_get_for_root (window->priv->transient_for) != NULL)
-        window->priv->transient_for_root = TRUE;
+        window->priv->transient_for_group = TRUE;
       else
-        window->priv->transient_for_root = FALSE;
+        {
+          /* Halt on group-transient ancestor to avoid entering a cycle. */
+          for (ancestor = window;
+               ancestor && !ancestor->priv->transient_for_group;
+               ancestor = wnck_window_get (ancestor->priv->transient_for))
+            {
+              if (ancestor->priv->transient_for == window->priv->xwindow)
+                {
+                  window->priv->transient_for_cycle = TRUE;
+                  window->priv->transient_for_group = TRUE;
+                }
+            }
+          if (window->priv->transient_for_cycle)
+            {
+              for (ancestor = wnck_window_get (parent);
+                   ancestor != window;
+                   ancestor = wnck_window_get (ancestor->priv->transient_for))
+                {
+                  ancestor->priv->transient_for_cycle = TRUE;
+                  ancestor->priv->transient_for_group = TRUE;
+                }
+            }
+        }
     }
   else
     {
       window->priv->transient_for = None;
-      window->priv->transient_for_root = FALSE;
+      window->priv->transient_for_group = FALSE;
     }
 }
 
