From: Antti Kaijanmäki <antti.kaijanmaki@canonical.com>
Subject: Delay showing the pin dialog in greeter mode; only show it when
 the user actually activates a connection instead of on modem detect.

---
 src/applet-device-gsm.c |  128 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 123 insertions(+), 5 deletions(-)

Index: network-manager-applet-0.9.4.1/src/applet-device-gsm.c
===================================================================
--- network-manager-applet-0.9.4.1.orig/src/applet-device-gsm.c
+++ network-manager-applet-0.9.4.1/src/applet-device-gsm.c
@@ -91,6 +91,8 @@ typedef struct {
 	gboolean skip_reg_poll;
 	gboolean skip_signal_poll;
 
+	gboolean greeter_mode;
+
 	/* Unlock dialog stuff */
 	GtkWidget *dialog;
 	gpointer keyring_id;
@@ -98,6 +100,7 @@ typedef struct {
 
 static void unlock_dialog_destroy (GsmDeviceInfo *info);
 static void check_start_polling (GsmDeviceInfo *info);
+static void unlock_dialog_new (NMDevice *device, GsmDeviceInfo *info);
 
 typedef struct {
 	NMApplet *applet;
@@ -282,10 +285,117 @@ applet_gsm_connect_network (NMApplet *ap
 	do_mobile_wizard (dbus_connect_3g_cb, info);
 }
 
+typedef struct {
+	NMDevice *device;
+	NMConnection *connection;
+	NMApplet *applet;
+	gpointer dclass_data;
+	guint wait_retry;
+} DelayedActivationHelper;
+
+gboolean delayed_activation_cb(gpointer user_data)
+{
+	DelayedActivationHelper *helper = user_data;
+
+	if (!NM_IS_DEVICE (helper->device)) {
+		// the device has been unplugged.
+		return FALSE;
+	}
+
+	GsmDeviceInfo *devinfo = g_object_get_data (G_OBJECT (helper->device), "devinfo");
+
+	if (devinfo->unlock_required == NULL) {
+		// the modem was successfully unlocked
+
+		applet_menu_item_activate_helper (helper->device,
+										  helper->connection,
+										  "/",
+										  helper->applet,
+										  helper->dclass_data);
+		return FALSE;
+	}
+
+	helper->wait_retry -= 1;
+	if (helper->wait_retry == 0) {
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+void gsm_menu_item_activate_unlock_dialog_destroy (GtkWidget *object,
+												   gpointer   user_data)
+{
+	GSMMenuItemInfo *info = (GSMMenuItemInfo *) user_data;
+	GsmDeviceInfo *devinfo;
+	DelayedActivationHelper *helper;
+
+	/*
+	 * The dialog is destroyed. Either the PIN code was successfully
+	 * forwarded to ModemManager or the dialog was cancelled.
+	 * Unfortunately we don't have any means of determine which is the case.
+	 *
+	 * The solution here is to monitor GsmDeviceInfo::unlock_required. If that
+	 * is cleared, then we know that the modem has been activated and we can
+	 * continue with the activation.
+	 *
+	 * Because unlock_required is updated upon receiving a property changed
+	 * signal we have to give MM some time to deliver the change over D-Bus.
+	 *
+	 * Here we set up a timer which checks the state of the modem three times
+	 * with 1 second delay.
+	 *
+	 * If the modem was not successfully activated this delayed activation is
+	 * cancelled after three tries/seconds.
+	 */
+
+	devinfo = g_object_get_data (G_OBJECT (info->device), "devinfo");
+
+	helper = g_malloc (sizeof (DelayedActivationHelper));
+	helper->device = info->device;
+	helper->connection = info->connection;
+	helper->applet = info->applet;
+	helper->dclass_data = info;
+	helper->wait_retry = 3;
+
+	g_timeout_add_full (G_PRIORITY_DEFAULT,
+						1 * 1000,
+						(GSourceFunc)delayed_activation_cb,
+						helper,
+						(GDestroyNotify)g_free);
+}
+
 static void
 gsm_menu_item_activate (GtkMenuItem *item, gpointer user_data)
 {
 	GSMMenuItemInfo *info = (GSMMenuItemInfo *) user_data;
+	GsmDeviceInfo *devinfo;
+
+	devinfo = g_object_get_data (G_OBJECT (info->device), "devinfo");
+	if (devinfo->greeter_mode && devinfo->unlock_required != NULL) {
+
+		/* We need to delay the activation until the modem is unlocked. */
+
+		unlock_dialog_new(devinfo->device, devinfo);
+		/*
+		 * The dialog gets destroyed if
+		 *
+		 * A) User enters the correct PIN and ModemManager tells nm-applet
+		 *    that the modem was successfully activated.
+		 *
+		 *	  The dialog does not get destroyed, however, if the PIN code
+		 *    is incorrect. The dialog shows an error message and the user can
+		 *    either enter a new PIN code or Cancel.
+		 *
+		 *    All this happens in the dialogs response handler or callback that
+		 *    handles the PIN activation return value from ModemManager.
+		 *    See the relevant functions later in this file.
+		 *
+		 * B) The user cancels the dialog.
+		 */
+		g_signal_connect (devinfo->dialog, "destroy", G_CALLBACK (gsm_menu_item_activate_unlock_dialog_destroy), info);
+		return;
+	}
 
 	applet_menu_item_activate_helper (info->device,
 	                                  info->connection,
@@ -1365,8 +1475,10 @@ keyring_pin_check_cb (GnomeKeyringResult
 	info->keyring_id = NULL;
 
 	if (result != GNOME_KEYRING_RESULT_OK) {
-		/* No saved PIN, just ask the user */
-		unlock_dialog_new (info->device, info);
+		if (!info->greeter_mode) {
+			/* No saved PIN, just ask the user */
+			unlock_dialog_new (info->device, info);
+		}
 		return;
 	}
 
@@ -1448,8 +1560,10 @@ simid_reply (DBusGProxy *proxy, DBusGPro
 			                                              info->devid,
 			                                              NULL);
 		} else {
-			/* Couldn't get a device ID, but unlock required; present dialog */
-			unlock_dialog_new (info->device, info);
+			if (!info->greeter_mode) {
+				/* Couldn't get a device ID, but unlock required; present dialog */
+				unlock_dialog_new (info->device, info);
+			}
 		}
 	}
 
@@ -1691,6 +1805,10 @@ gsm_device_added (NMDevice *device, NMAp
 	info->device = device;
 	info->bus = bus;
 
+	info->greeter_mode = FALSE;
+	if (getenv ("INDICATOR_GREETER_MODE"))
+		info->greeter_mode = TRUE;
+
 	info->props_proxy = dbus_g_proxy_new_for_name (info->bus,
 	                                               "org.freedesktop.ModemManager",
 	                                               udi,
