Index: gui/modules/dwellmouselistener.c
===================================================================
--- gui/modules/dwellmouselistener.c	(revision 4608)
+++ gui/modules/dwellmouselistener.c	(working copy)
@@ -665,6 +665,8 @@
 					G_CALLBACK (gtk_widget_destroy), NULL);
 				gtk_widget_show (dialog);
 			} else {
+				const char *at_name;
+				const char *ats_launched;
 				GdkCursor *cursor = gdk_cursor_new (GDK_WATCH);
 				gdk_window_set_cursor (gdk_get_default_root_window (),
 					cursor);
@@ -673,6 +675,21 @@
 				latch_core_pointer = FALSE;
 				/* once we've recognized a gesture, we need to *
 				 * leave the pointer alone */
+				
+				/* TODO: it would probably be nicer to pass in some abstract
+				 * description of what the AT is rather than argv[0]; e.g. 
+				 * "screenreader" instead of "orca"
+				 */
+				at_name = g_basename (argv[0]);
+				ats_launched = g_getenv ("GDM_ATS");
+				if (ats_launched == NULL) {
+					g_setenv ("GDM_ATS", at_name, TRUE);
+				} else if (strstr (ats_launched, at_name) == NULL) {
+					char *s;
+					s = g_strdup_printf ("%s %s", ats_launched, at_name);
+					g_setenv ("GDM_ATS", s, TRUE);
+					g_free (s);
+				}
 			}
 		}
 	}
Index: gui/modules/keymouselistener.c
===================================================================
--- gui/modules/keymouselistener.c	(revision 4608)
+++ gui/modules/keymouselistener.c	(working copy)
@@ -918,9 +918,6 @@
 							NULL,
 							NULL);
 
-				g_strfreev (argv);
-				g_strfreev (envp); 
-
 				if ( ! retval) {
 					GtkWidget *dialog = 
 						gtk_message_dialog_new (NULL, 0,
@@ -937,6 +934,8 @@
 						NULL);
 					gtk_widget_show (dialog);
 				} else {
+					const char *at_name;
+					const char *ats_launched;
 					GdkCursor *cursor = gdk_cursor_new (GDK_WATCH);
 					gdk_window_set_cursor (gdk_get_default_root_window (),
 						cursor);
@@ -944,7 +943,26 @@
 					g_timeout_add (2000,
 						       change_cursor_back,
 						       NULL);
+
+					/* TODO: it would probably be nicer to pass in some abstract
+					 * description of what the AT is rather than argv[0]; e.g. 
+					 * "screenreader" instead of "orca"
+					 */
+					at_name = g_basename (argv[0]);
+					ats_launched = g_getenv ("GDM_ATS");
+					if (ats_launched == NULL) {
+						g_setenv ("GDM_ATS", at_name, TRUE);
+					} else if (strstr (ats_launched, at_name) == NULL) {
+						char *s;
+						s = g_strdup_printf ("%s %s", ats_launched, at_name);
+						g_setenv ("GDM_ATS", s, TRUE);
+						g_free (s);
+					}
 				}
+
+				g_strfreev (argv);
+				g_strfreev (envp); 
+
 			}
    			return GDK_FILTER_CONTINUE;
 		}
Index: gui/greeter/greeter.c
===================================================================
--- gui/greeter/greeter.c	(revision 4608)
+++ gui/greeter/greeter.c	(working copy)
@@ -340,6 +340,19 @@
 	g_free (session);
 	break;
 
+    case GDM_A11Y:
+    {
+	const char *ats_launched;
+	/* print out the assistive technologies that we've started for the user */
+	ats_launched = g_getenv ("GDM_ATS");
+	if (ats_launched != NULL)
+		printf ("%c%s\n", STX, ats_launched);
+	else
+		printf ("%c\n", STX);
+	fflush (stdout);
+	break;
+    }
+
     case GDM_LANG:
 	language = greeter_language_get_language (args);
 	if (greeter_language_get_save_language () == GTK_RESPONSE_CANCEL)
Index: daemon/gdm.h
===================================================================
--- daemon/gdm.h	(revision 4608)
+++ daemon/gdm.h	(working copy)
@@ -98,6 +98,7 @@
 #define GDM_PROMPT     'N'
 #define GDM_SESS       'G'
 #define GDM_LANG       '&'
+#define GDM_A11Y       'Z'
 #define GDM_SSESS      'C'
 #define GDM_SLANG      'R'
 #define GDM_RESET      'A'
Index: daemon/slave.c
===================================================================
--- daemon/slave.c	(revision 4608)
+++ daemon/slave.c	(working copy)
@@ -3430,6 +3430,7 @@
 		   const char *session,
 		   const char *save_session,
 		   const char *language,
+		   const char *a11y_ats,
 		   const char *gnome_session,
 		   gboolean usrcfgok,
 		   gboolean savesess,
@@ -3522,6 +3523,9 @@
 		g_setenv ("XDG_SESSION_COOKIE", ck_session_cookie, TRUE);
 	}
 #endif
+	if (a11y_ats != NULL) {
+		g_setenv ("GDM_ATS", a11y_ats, TRUE);
+	}
 	g_setenv ("GDMSESSION", session, TRUE);
 	g_setenv ("DESKTOP_SESSION", session, TRUE);
 	g_setenv ("SHELL", pwent->pw_shell, TRUE);
@@ -4016,7 +4020,7 @@
 {
     struct passwd *pwent;
     const char *home_dir = NULL;
-    char *save_session = NULL, *session = NULL, *language = NULL, *usrsess, *usrlang;
+    char *save_session = NULL, *session = NULL, *language = NULL, *a11y_ats = NULL, *usrsess, *usrlang;
     char *gnome_session = NULL;
 #ifdef WITH_CONSOLE_KIT
     char *ck_session_cookie;
@@ -4187,9 +4191,19 @@
 		    g_free (usrlang);
 		    return;
 	    }
+
+	    a11y_ats = gdm_slave_greeter_ctl (GDM_A11Y, NULL);
+	    if (a11y_ats != NULL && 
+		strcmp (a11y_ats, GDM_RESPONSE_CANCEL) == 0) {
+		    gdm_debug ("User canceled login");
+		    gdm_verify_cleanup (d);
+		    session_started = FALSE;
+		    return;
+	    }
     } else {
 	    session = g_strdup (usrsess);
 	    language = g_strdup (usrlang);
+	    a11y_ats = NULL;
     }
 
     tmp = gdm_strip_extension (session, ".desktop");
@@ -4210,11 +4224,16 @@
 	    language = NULL;
     }
 
+    if G_LIKELY (ve_string_empty (a11y_ats)) {
+	    g_free (a11y_ats);
+	    a11y_ats = NULL;
+    }
+
     g_free (usrsess);
     g_free (usrlang);
 
-    gdm_debug ("Initial setting: session: '%s' language: '%s'\n",
-	       session, ve_sure_string (language));
+    gdm_debug ("Initial setting: session: '%s' language: '%s' ATs enabled in gdm: '%s'\n",
+	       session, ve_sure_string (language), ve_sure_string (a11y_ats));
 
     /* save this session as the users session */
     save_session = g_strdup (session);
@@ -4378,6 +4397,7 @@
 			   session,
 			   save_session,
 			   language,
+			   a11y_ats,
 			   gnome_session,
 			   usrcfgok,
 			   savesess,
