[network-manager-applet] gsm: implement initial unlock dialog for PIN & PUK
- From: Dan Williams <dcbw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [network-manager-applet] gsm: implement initial unlock dialog for PIN & PUK
- Date: Thu, 4 Mar 2010 08:35:57 +0000 (UTC)
commit c6ae5b3c0501deadf89ca78fda578b387d8f73c8
Author: Dan Williams <dcbw redhat com>
Date: Thu Mar 4 00:34:50 2010 -0800
gsm: implement initial unlock dialog for PIN & PUK
Needs some PolicyKit love but that will come later.
src/applet-device-gsm.c | 288 ++++++++++++++++++++++++++++++------
src/applet-dialogs.c | 373 +++++++++++++++++++++++++++++++++++++++++++++++
src/applet-dialogs.h | 33 ++++
src/applet.glade | 261 +++++++++++++++++++++++++++++++++
4 files changed, 907 insertions(+), 48 deletions(-)
---
diff --git a/src/applet-device-gsm.c b/src/applet-device-gsm.c
index fe4ff9a..f1a6a22 100644
--- a/src/applet-device-gsm.c
+++ b/src/applet-device-gsm.c
@@ -44,6 +44,36 @@
#include "mb-menu-item.h"
#include "nma-marshal.h"
+
+typedef struct {
+ NMDevice *device;
+
+ DBusGProxy *props_proxy;
+ DBusGProxy *card_proxy;
+ DBusGProxy *net_proxy;
+
+ gboolean quality_valid;
+ guint32 quality;
+
+ char *unlock_required;
+
+ /* reg_state is (1 + MM reg state) so that 0 means we haven't gotten a
+ * value from MM yet. 0 is a valid MM GSM reg state.
+ */
+ guint reg_state;
+ char *op_code;
+ char *op_name;
+
+ gboolean nopoll;
+ guint32 poll_id;
+
+ /* Unlock dialog stuff */
+ GtkWidget *dialog;
+} GsmDeviceInfo;
+
+static void unlock_dialog_destroy (GsmDeviceInfo *info);
+
+
typedef struct {
NMApplet *applet;
NMDevice *device;
@@ -199,27 +229,6 @@ add_connection_item (NMDevice *device,
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
}
-typedef struct {
- DBusGProxy *props_proxy;
- DBusGProxy *card_proxy;
- DBusGProxy *net_proxy;
-
- gboolean quality_valid;
- guint32 quality;
-
- char *unlock_required;
-
- /* reg_state is (1 + MM reg state) so that 0 means we haven't gotten a
- * value from MM yet. 0 is a valid MM GSM reg state.
- */
- guint reg_state;
- char *op_code;
- char *op_name;
-
- gboolean nopoll;
- guint32 poll_id;
-} GsmDeviceInfo;
-
static guint32
state_for_info (GsmDeviceInfo *info)
{
@@ -467,7 +476,7 @@ pin_entry_changed (GtkEditable *editable, gpointer user_data)
}
static void
-destroy_gsm_dialog (gpointer user_data, GObject *finalized)
+secrets_dialog_destroy (gpointer user_data, GObject *finalized)
{
NMGsmSecretsInfo *info = user_data;
@@ -581,7 +590,7 @@ get_existing_secrets_cb (NMSettingsConnectionInterface *connection,
}
nm_connection_clear_secrets (NM_CONNECTION (info->connection));
- destroy_gsm_dialog (info, NULL);
+ secrets_dialog_destroy (info, NULL);
}
static void
@@ -595,7 +604,7 @@ get_gsm_secrets_cb (GtkDialog *dialog,
/* Got a user response, clear the NMActiveConnection destroy handler for
* this dialog since this function will now take over dialog destruction.
*/
- g_object_weak_unref (G_OBJECT (info->active_connection), destroy_gsm_dialog, info);
+ g_object_weak_unref (G_OBJECT (info->active_connection), secrets_dialog_destroy, info);
if (response == GTK_RESPONSE_OK) {
const char *hints[2] = { info->secret_name, NULL };
@@ -627,13 +636,12 @@ get_gsm_secrets_cb (GtkDialog *dialog,
g_error_free (error);
nm_connection_clear_secrets (NM_CONNECTION (info->connection));
- destroy_gsm_dialog (info, NULL);
+ secrets_dialog_destroy (info, NULL);
}
}
static GtkWidget *
ask_for_pin_puk (NMDevice *device,
- NMConnection *connection,
const char *secret_name,
GtkEntry **out_secret_entry)
{
@@ -702,7 +710,7 @@ gsm_get_secrets (NMDevice *device,
NMApplet *applet,
GError **error)
{
- NMGsmSecretsInfo *info;
+ NMGsmSecretsInfo *secrets_info;
GtkWidget *widget;
GtkEntry *secret_entry = NULL;
@@ -716,9 +724,16 @@ gsm_get_secrets (NMDevice *device,
}
if ( !strcmp (hints[0], NM_SETTING_GSM_PIN)
- || !strcmp (hints[0], NM_SETTING_GSM_PUK))
- widget = ask_for_pin_puk (device, NM_CONNECTION (connection), hints[0], &secret_entry);
- else if (!strcmp (hints[0], NM_SETTING_GSM_PASSWORD))
+ || !strcmp (hints[0], NM_SETTING_GSM_PUK)) {
+ GsmDeviceInfo *info = g_object_get_data (G_OBJECT (device), "devinfo");
+
+ g_assert (info);
+ /* A GetSecrets PIN dialog overrides the initial unlock dialog */
+ if (info->dialog)
+ unlock_dialog_destroy (info);
+
+ widget = ask_for_pin_puk (device, hints[0], &secret_entry);
+ } else if (!strcmp (hints[0], NM_SETTING_GSM_PASSWORD))
widget = applet_mobile_password_dialog_new (device, NM_CONNECTION (connection), &secret_entry);
else {
g_set_error (error,
@@ -738,22 +753,22 @@ gsm_get_secrets (NMDevice *device,
return FALSE;
}
- info = g_malloc0 (sizeof (NMGsmSecretsInfo));
- info->callback = callback;
- info->callback_data = callback_data;
- info->applet = applet;
- info->active_connection = active_connection;
- info->connection = g_object_ref (connection);
- info->secret_name = g_strdup (hints[0]);
- info->dialog = widget;
- info->secret_entry = secret_entry;
+ secrets_info = g_malloc0 (sizeof (NMGsmSecretsInfo));
+ secrets_info->callback = callback;
+ secrets_info->callback_data = callback_data;
+ secrets_info->applet = applet;
+ secrets_info->active_connection = active_connection;
+ secrets_info->connection = g_object_ref (connection);
+ secrets_info->secret_name = g_strdup (hints[0]);
+ secrets_info->dialog = widget;
+ secrets_info->secret_entry = secret_entry;
- g_signal_connect (widget, "response", G_CALLBACK (get_gsm_secrets_cb), info);
+ g_signal_connect (widget, "response", G_CALLBACK (get_gsm_secrets_cb), secrets_info);
/* Attach a destroy notifier to the NMActiveConnection so we can destroy
* the dialog when the active connection goes away.
*/
- g_object_weak_ref (G_OBJECT (active_connection), destroy_gsm_dialog, info);
+ g_object_weak_ref (G_OBJECT (active_connection), secrets_dialog_destroy, secrets_info);
gtk_window_set_position (GTK_WINDOW (widget), GTK_WIN_POS_CENTER_ALWAYS);
gtk_widget_realize (GTK_WIDGET (widget));
@@ -762,6 +777,174 @@ gsm_get_secrets (NMDevice *device,
return TRUE;
}
+/********************************************************************/
+
+static void
+unlock_dialog_destroy (GsmDeviceInfo *info)
+{
+ applet_mobile_pin_dialog_destroy (info->dialog);
+ info->dialog = NULL;
+}
+
+static void
+unlock_pin_reply (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
+{
+ GsmDeviceInfo *info = user_data;
+ GError *error = NULL;
+
+ if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) {
+ unlock_dialog_destroy (info);
+ return;
+ }
+
+ /* FIXME: show the error in the dialog or something */
+
+ applet_mobile_pin_dialog_stop_spinner (info->dialog);
+ g_warning ("%s: error unlocking with PIN: %s", __func__, error->message);
+ g_clear_error (&error);
+}
+
+static void
+unlock_puk_reply (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
+{
+ GsmDeviceInfo *info = user_data;
+ GError *error = NULL;
+
+ if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) {
+ unlock_dialog_destroy (info);
+ return;
+ }
+
+ /* FIXME: show the error in the dialog or something */
+
+ applet_mobile_pin_dialog_stop_spinner (info->dialog);
+ g_warning ("%s: error unlocking with PIN: %s", __func__, error->message);
+ g_clear_error (&error);
+}
+
+#define UNLOCK_CODE_PIN 1
+#define UNLOCK_CODE_PUK 2
+
+static void
+unlock_dialog_response (GtkDialog *dialog,
+ gint response,
+ gpointer user_data)
+{
+ GsmDeviceInfo *info = user_data;
+ const char *code1, *code2;
+ guint32 unlock_code;
+
+ if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT) {
+ unlock_dialog_destroy (info);
+ return;
+ }
+
+ /* Start the spinner to show the progress of the unlock */
+ applet_mobile_pin_dialog_start_spinner (info->dialog, _("Sending unlock code..."));
+
+ unlock_code = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (info->dialog), "unlock-code"));
+ if (!unlock_code) {
+ g_warn_if_fail (unlock_code != 0);
+ unlock_dialog_destroy (info);
+ return;
+ }
+
+ code1 = applet_mobile_pin_dialog_get_entry1 (info->dialog);
+ if (!code1 || !strlen (code1)) {
+ g_warn_if_fail (code1 != NULL);
+ g_warn_if_fail (strlen (code1));
+ unlock_dialog_destroy (info);
+ return;
+ }
+
+ /* Send the code to ModemManager */
+ if (unlock_code == UNLOCK_CODE_PIN) {
+ dbus_g_proxy_begin_call (info->card_proxy, "SendPin",
+ unlock_pin_reply, info, NULL,
+ G_TYPE_STRING, code1, G_TYPE_INVALID);
+ } else if (unlock_code == UNLOCK_CODE_PUK) {
+ code2 = applet_mobile_pin_dialog_get_entry2 (info->dialog);
+ if (!code2) {
+ g_warn_if_fail (code2 != NULL);
+ unlock_dialog_destroy (info);
+ return;
+ }
+
+ dbus_g_proxy_begin_call (info->card_proxy, "SendPuk",
+ unlock_puk_reply, info, NULL,
+ G_TYPE_STRING, code1,
+ G_TYPE_STRING, code2,
+ G_TYPE_INVALID);
+ }
+}
+
+static void
+unlock_dialog_new (NMDevice *device, GsmDeviceInfo *info)
+{
+ const char *header = NULL;
+ const char *title = NULL;
+ char *desc = NULL;
+ const char *label1 = NULL, *label2 = NULL, *label3 = NULL;
+ const char *device_desc;
+ gboolean match23 = FALSE;
+ guint32 label1_min = 0, label2_min = 0, label3_min = 0;
+ guint32 label1_max = 0, label2_max = 0, label3_max = 0;
+ guint32 unlock_code = 0;
+
+ g_return_if_fail (info->unlock_required != NULL);
+
+ if (info->dialog)
+ return;
+
+ /* Figure out the dialog text based on the required unlock code */
+ device_desc = utils_get_device_description (device);
+ if (!strcmp (info->unlock_required, "sim-pin")) {
+ title = _("SIM PIN unlock required");
+ header = _("SIM PIN Unlock Required");
+ /* FIXME: some warning about # of times you can enter incorrect PIN */
+ desc = g_strdup_printf (_("The mobile broadband device '%s' requires a SIM PIN code before it can be used."), device_desc);
+ label1 = _("PIN code:");
+ label1_min = 4;
+ label1_max = 8;
+ unlock_code = UNLOCK_CODE_PIN;
+ } else if (!strcmp (info->unlock_required, "sim-puk")) {
+ title = _("SIM PUK unlock required");
+ header = _("SIM PUK Unlock Required");
+ /* FIXME: some warning about # of times you can enter incorrect PUK */
+ desc = g_strdup_printf (_("The mobile broadband device '%s' requires a SIM PUK code before it can be used."), device_desc);
+ label1 = _("PUK code:");
+ label1_min = label1_max = 8;
+ label2 = _("New PIN code:");
+ label3 = _("Re-enter new PIN code:");
+ label2_min = label3_min = 4;
+ label2_max = label3_max = 8;
+ match23 = TRUE;
+ unlock_code = UNLOCK_CODE_PUK;
+ } else {
+ g_warning ("Unhandled unlock request for '%s'", info->unlock_required);
+ return;
+ }
+
+ /* Construct and run the dialog */
+ info->dialog = applet_mobile_pin_dialog_new (title, header, desc);
+ g_free (desc);
+ g_return_if_fail (info->dialog != NULL);
+
+ g_object_set_data (G_OBJECT (info->dialog), "unlock-code", GUINT_TO_POINTER (unlock_code));
+ applet_mobile_pin_dialog_match_23 (info->dialog, match23);
+
+ applet_mobile_pin_dialog_set_entry1 (info->dialog, label1, label1_min, label1_max);
+ if (label2)
+ applet_mobile_pin_dialog_set_entry2 (info->dialog, label2, label2_min, label2_max);
+ if (label3)
+ applet_mobile_pin_dialog_set_entry3 (info->dialog, label3, label3_min, label3_max);
+
+ g_signal_connect (info->dialog, "response", G_CALLBACK (unlock_dialog_response), info);
+ applet_mobile_pin_dialog_present (info->dialog, FALSE);
+}
+
+/********************************************************************/
+
static void
gsm_device_info_free (gpointer data)
{
@@ -777,6 +960,9 @@ gsm_device_info_free (gpointer data)
if (info->poll_id)
g_source_remove (info->poll_id);
+ if (info->dialog)
+ unlock_dialog_destroy (info);
+
g_free (info->op_code);
g_free (info->op_name);
memset (info, 0, sizeof (GsmDeviceInfo));
@@ -844,17 +1030,19 @@ unlock_reply (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
{
GsmDeviceInfo *info = user_data;
GError *error = NULL;
- char *unlock = NULL;
+ GValue value = { 0 };
if (dbus_g_proxy_end_call (proxy, call, &error,
- G_TYPE_STRING, &unlock,
+ G_TYPE_VALUE, &value,
G_TYPE_INVALID)) {
- g_free (info->unlock_required);
- info->unlock_required = unlock;
+ if (G_VALUE_HOLDS_STRING (&value)) {
+ g_free (info->unlock_required);
+ info->unlock_required = g_value_dup_string (&value);
- if (info->unlock_required) {
- /* Handle unlock */
+ if (info->unlock_required)
+ unlock_dialog_new (info->device, info);
}
+ g_value_unset (&value);
}
g_clear_error (&error);
@@ -924,7 +1112,10 @@ modem_properties_changed (DBusGProxy *proxy,
info->unlock_required = g_value_dup_string (value);
if (info->unlock_required) {
- /* Handle unlock */
+ /* FIXME: handle unlock changes; like if the user enters the wrong
+ * pin too many times we want to show the PUK dialog instead of the
+ * pin dialog.
+ */
}
}
}
@@ -944,6 +1135,7 @@ gsm_device_added (NMDevice *device, NMApplet *applet)
return;
info = g_malloc0 (sizeof (GsmDeviceInfo));
+ info->device = device;
/* Don't bother polling if the device isn't usable */
state = nm_device_get_state (device);
diff --git a/src/applet-dialogs.c b/src/applet-dialogs.c
index 54251ae..149187f 100644
--- a/src/applet-dialogs.c
+++ b/src/applet-dialogs.c
@@ -23,6 +23,7 @@
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
+#include <ctype.h>
#include <nm-device-ethernet.h>
#include <nm-device-wifi.h>
@@ -43,6 +44,7 @@
#include "applet-dialogs.h"
#include "utils.h"
+#include "nma-bling-spinner.h"
static void
@@ -756,3 +758,374 @@ applet_mobile_password_dialog_new (NMDevice *device,
return GTK_WIDGET (dialog);
}
+/**********************************************************************/
+
+static void
+mpd_entry_changed (GtkWidget *widget, gpointer user_data)
+{
+ GtkWidget *dialog = GTK_WIDGET (user_data);
+ GladeXML *xml = g_object_get_data (G_OBJECT (dialog), "xml");
+ GtkWidget *entry;
+ guint32 minlen;
+ gboolean valid = FALSE;
+ const char *text, *text2 = NULL, *text3 = NULL;
+ gboolean match23;
+
+ g_return_if_fail (xml != NULL);
+
+ entry = glade_xml_get_widget (xml, "code1_entry");
+ if (g_object_get_data (G_OBJECT (entry), "active")) {
+ minlen = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (entry), "minlen"));
+ text = gtk_entry_get_text (GTK_ENTRY (entry));
+ if (text && (strlen (text) < minlen))
+ goto done;
+ }
+
+ entry = glade_xml_get_widget (xml, "code2_entry");
+ if (g_object_get_data (G_OBJECT (entry), "active")) {
+ minlen = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (entry), "minlen"));
+ text2 = gtk_entry_get_text (GTK_ENTRY (entry));
+ if (text2 && (strlen (text2) < minlen))
+ goto done;
+ }
+
+ entry = glade_xml_get_widget (xml, "code3_entry");
+ if (g_object_get_data (G_OBJECT (entry), "active")) {
+ minlen = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (entry), "minlen"));
+ text3 = gtk_entry_get_text (GTK_ENTRY (entry));
+ if (text3 && (strlen (text3) < minlen))
+ goto done;
+ }
+
+ /* Validate 2 & 3 if they are supposed to be the same */
+ match23 = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (dialog), "match23"));
+ if (match23) {
+ if (!text2 || !text3 || strcmp (text2, text3))
+ goto done;
+ }
+
+ valid = TRUE;
+
+done:
+ widget = glade_xml_get_widget (xml, "unlock_button");
+ g_warn_if_fail (widget != NULL);
+ gtk_widget_set_sensitive (widget, valid);
+ if (valid)
+ gtk_widget_grab_default (widget);
+}
+
+void
+applet_mobile_pin_dialog_destroy (GtkWidget *widget)
+{
+ gtk_widget_hide (widget);
+ gtk_widget_destroy (widget);
+}
+
+static void
+mpd_cancel_dialog (GtkDialog *dialog)
+{
+ gtk_dialog_response (dialog, GTK_RESPONSE_CANCEL);
+}
+
+GtkWidget *
+applet_mobile_pin_dialog_new (const char *title,
+ const char *header,
+ const char *desc)
+{
+ char *glade_file, *str;
+ GladeXML *xml;
+ GtkWidget *dialog;
+ GtkWidget *widget;
+
+ g_return_val_if_fail (title != NULL, NULL);
+ g_return_val_if_fail (header != NULL, NULL);
+ g_return_val_if_fail (desc != NULL, NULL);
+
+ glade_file = g_build_filename (GLADEDIR, "applet.glade", NULL);
+ g_return_val_if_fail (glade_file != NULL, NULL);
+ xml = glade_xml_new (glade_file, "unlock_dialog", NULL);
+ g_free (glade_file);
+ g_return_val_if_fail (xml != NULL, NULL);
+
+ dialog = glade_xml_get_widget (xml, "unlock_dialog");
+ if (!dialog) {
+ g_object_unref (xml);
+ g_return_val_if_fail (dialog != NULL, NULL);
+ }
+
+ g_object_set_data_full (G_OBJECT (dialog), "xml", xml, (GDestroyNotify) g_object_unref);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), title);
+
+ widget = glade_xml_get_widget (xml, "header_label");
+ str = g_strdup_printf ("<span size=\"larger\" weight=\"bold\">%s</span>", header);
+ gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
+ gtk_label_set_markup (GTK_LABEL (widget), str);
+ g_free (str);
+
+ widget = glade_xml_get_widget (xml, "desc_label");
+ gtk_label_set_text (GTK_LABEL (widget), desc);
+
+ g_signal_connect (dialog, "delete-event", G_CALLBACK (mpd_cancel_dialog), NULL);
+
+ mpd_entry_changed (NULL, dialog);
+
+ return dialog;
+}
+
+void
+applet_mobile_pin_dialog_present (GtkWidget *dialog, gboolean now)
+{
+ GladeXML *xml;
+ GtkWidget *widget;
+
+ g_return_if_fail (dialog != NULL);
+ xml = g_object_get_data (G_OBJECT (dialog), "xml");
+ g_return_if_fail (xml != NULL);
+
+ gtk_widget_show_all (dialog);
+
+ widget = glade_xml_get_widget (xml, "progress_hbox");
+ gtk_widget_hide (widget);
+
+ /* Hide inactive entries */
+
+ widget = glade_xml_get_widget (xml, "code2_entry");
+ if (!g_object_get_data (G_OBJECT (widget), "active")) {
+ gtk_widget_hide (widget);
+ widget = glade_xml_get_widget (xml, "code2_label");
+ gtk_widget_hide (widget);
+ }
+
+ widget = glade_xml_get_widget (xml, "code3_entry");
+ if (!g_object_get_data (G_OBJECT (widget), "active")) {
+ gtk_widget_hide (widget);
+ widget = glade_xml_get_widget (xml, "code3_label");
+ gtk_widget_hide (widget);
+ }
+
+ /* Need to resize the dialog after hiding widgets */
+ gtk_window_resize (GTK_WINDOW (dialog), 400, 100);
+
+ /* Show the dialog */
+ gtk_widget_realize (dialog);
+ if (now)
+ gtk_window_present_with_time (GTK_WINDOW (dialog), gdk_x11_get_server_time (dialog->window));
+ else
+ gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static void
+mpd_entry_filter (GtkEntry *entry,
+ const char *text,
+ gint length,
+ gint *position,
+ gpointer user_data)
+{
+ GtkEditable *editable = GTK_EDITABLE (entry);
+ int i, count = 0;
+ gchar *result = g_malloc0 (length);
+
+ /* Digits only */
+ for (i = 0; i < length; i++) {
+ if (isdigit (text[i]))
+ result[count++] = text[i];
+ }
+
+ if (count > 0) {
+ g_signal_handlers_block_by_func (G_OBJECT (editable),
+ G_CALLBACK (mpd_entry_filter),
+ user_data);
+ gtk_editable_insert_text (editable, result, count, position);
+ g_signal_handlers_unblock_by_func (G_OBJECT (editable),
+ G_CALLBACK (mpd_entry_filter),
+ user_data);
+ }
+ g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
+ g_free (result);
+}
+
+static void
+mpd_set_entry (GtkWidget *dialog,
+ const char *entry_name,
+ const char *label_name,
+ const char *label,
+ guint32 minlen,
+ guint32 maxlen)
+{
+ GladeXML *xml;
+ GtkWidget *widget;
+ gboolean entry2_active = FALSE;
+ gboolean entry3_active = FALSE;
+
+ g_return_if_fail (dialog != NULL);
+ xml = g_object_get_data (G_OBJECT (dialog), "xml");
+ g_return_if_fail (xml != NULL);
+
+ widget = glade_xml_get_widget (xml, label_name);
+ gtk_label_set_text (GTK_LABEL (widget), label);
+
+ widget = glade_xml_get_widget (xml, entry_name);
+ g_signal_connect (widget, "changed", G_CALLBACK (mpd_entry_changed), dialog);
+ g_signal_connect (widget, "insert-text", G_CALLBACK (mpd_entry_filter), NULL);
+
+ if (maxlen)
+ gtk_entry_set_max_length (GTK_ENTRY (widget), maxlen);
+ g_object_set_data (G_OBJECT (widget), "minlen", GUINT_TO_POINTER (minlen));
+
+ /* Tag it so we know it's active */
+ g_object_set_data (G_OBJECT (widget), "active", GUINT_TO_POINTER (1));
+
+ /* Make a single-entry dialog look better */
+ widget = glade_xml_get_widget (xml, "code2_entry");
+ entry2_active = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "active"));
+ widget = glade_xml_get_widget (xml, "code3_entry");
+ entry3_active = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "active"));
+
+ widget = glade_xml_get_widget (xml, "table1");
+ if (entry2_active || entry3_active)
+ gtk_table_set_row_spacings (GTK_TABLE (widget), 6);
+ else
+ gtk_table_set_row_spacings (GTK_TABLE (widget), 0);
+
+ mpd_entry_changed (NULL, dialog);
+}
+
+void
+applet_mobile_pin_dialog_set_entry1 (GtkWidget *dialog,
+ const char *label,
+ guint32 minlen,
+ guint32 maxlen)
+{
+ mpd_set_entry (dialog, "code1_entry", "code1_label", label, minlen, maxlen);
+}
+
+void
+applet_mobile_pin_dialog_set_entry2 (GtkWidget *dialog,
+ const char *label,
+ guint32 minlen,
+ guint32 maxlen)
+{
+ mpd_set_entry (dialog, "code2_entry", "code2_label", label, minlen, maxlen);
+}
+
+void
+applet_mobile_pin_dialog_set_entry3 (GtkWidget *dialog,
+ const char *label,
+ guint32 minlen,
+ guint32 maxlen)
+{
+ mpd_set_entry (dialog, "code3_entry", "code3_label", label, minlen, maxlen);
+}
+
+void applet_mobile_pin_dialog_match_23 (GtkWidget *dialog, gboolean match)
+{
+ g_return_if_fail (dialog != NULL);
+
+ g_object_set_data (G_OBJECT (dialog), "match23", GUINT_TO_POINTER (match));
+}
+
+static const char *
+mpd_get_entry (GtkWidget *dialog, const char *entry_name)
+{
+ GladeXML *xml;
+ GtkWidget *widget;
+
+ g_return_val_if_fail (dialog != NULL, NULL);
+ xml = g_object_get_data (G_OBJECT (dialog), "xml");
+ g_return_val_if_fail (xml != NULL, NULL);
+
+ widget = glade_xml_get_widget (xml, entry_name);
+ return gtk_entry_get_text (GTK_ENTRY (widget));
+}
+
+const char *
+applet_mobile_pin_dialog_get_entry1 (GtkWidget *dialog)
+{
+ return mpd_get_entry (dialog, "code1_entry");
+}
+
+const char *
+applet_mobile_pin_dialog_get_entry2 (GtkWidget *dialog)
+{
+ return mpd_get_entry (dialog, "code2_entry");
+}
+
+const char *
+applet_mobile_pin_dialog_get_entry3 (GtkWidget *dialog)
+{
+ return mpd_get_entry (dialog, "code3_entry");
+}
+
+void
+applet_mobile_pin_dialog_start_spinner (GtkWidget *dialog, const char *text)
+{
+ GladeXML *xml;
+ GtkWidget *spinner, *widget, *hbox, *align;
+
+ g_return_if_fail (dialog != NULL);
+ g_return_if_fail (text != NULL);
+
+ xml = g_object_get_data (G_OBJECT (dialog), "xml");
+ g_return_if_fail (xml != NULL);
+
+ spinner = nma_bling_spinner_new ();
+ g_return_if_fail (spinner != NULL);
+ g_object_set_data (G_OBJECT (dialog), "spinner", spinner);
+
+ align = glade_xml_get_widget (xml, "spinner_alignment");
+ gtk_container_add (GTK_CONTAINER (align), spinner);
+ nma_bling_spinner_start (NMA_BLING_SPINNER (spinner));
+
+ widget = glade_xml_get_widget (xml, "progress_label");
+ gtk_label_set_text (GTK_LABEL (widget), text);
+ gtk_widget_show (widget);
+
+ hbox = glade_xml_get_widget (xml, "progress_hbox");
+ gtk_widget_show_all (hbox);
+
+ /* Desensitize everything while spinning */
+ widget = glade_xml_get_widget (xml, "code1_entry");
+ gtk_widget_set_sensitive (widget, FALSE);
+ widget = glade_xml_get_widget (xml, "code2_entry");
+ gtk_widget_set_sensitive (widget, FALSE);
+ widget = glade_xml_get_widget (xml, "code3_entry");
+ gtk_widget_set_sensitive (widget, FALSE);
+ widget = glade_xml_get_widget (xml, "unlock_button");
+ gtk_widget_set_sensitive (widget, FALSE);
+ widget = glade_xml_get_widget (xml, "cancel_button");
+ gtk_widget_set_sensitive (widget, FALSE);
+}
+
+void
+applet_mobile_pin_dialog_stop_spinner (GtkWidget *dialog)
+{
+ GladeXML *xml;
+ GtkWidget *spinner, *widget;
+
+ g_return_if_fail (dialog != NULL);
+
+ xml = g_object_get_data (G_OBJECT (dialog), "xml");
+ g_return_if_fail (xml != NULL);
+
+ spinner = g_object_get_data (G_OBJECT (dialog), "spinner");
+ g_return_if_fail (spinner != NULL);
+ nma_bling_spinner_stop (NMA_BLING_SPINNER (spinner));
+ gtk_widget_hide (spinner);
+
+ widget = glade_xml_get_widget (xml, "progress_label");
+ gtk_widget_hide (widget);
+
+ /* Resensitize stuff */
+ widget = glade_xml_get_widget (xml, "code1_entry");
+ gtk_widget_set_sensitive (widget, TRUE);
+ widget = glade_xml_get_widget (xml, "code2_entry");
+ gtk_widget_set_sensitive (widget, TRUE);
+ widget = glade_xml_get_widget (xml, "code3_entry");
+ gtk_widget_set_sensitive (widget, TRUE);
+ widget = glade_xml_get_widget (xml, "unlock_button");
+ gtk_widget_set_sensitive (widget, TRUE);
+ widget = glade_xml_get_widget (xml, "cancel_button");
+ gtk_widget_set_sensitive (widget, TRUE);
+}
+
diff --git a/src/applet-dialogs.h b/src/applet-dialogs.h
index fcf54eb..1e7546e 100644
--- a/src/applet-dialogs.h
+++ b/src/applet-dialogs.h
@@ -37,4 +37,37 @@ GtkWidget *applet_mobile_password_dialog_new (NMDevice *device,
NMConnection *connection,
GtkEntry **out_secret_entry);
+/******** Mobile PIN dialog ********/
+
+GtkWidget *applet_mobile_pin_dialog_new (const char *title,
+ const char *header,
+ const char *desc);
+
+void applet_mobile_pin_dialog_present (GtkWidget *dialog, gboolean now);
+
+void applet_mobile_pin_dialog_destroy (GtkWidget *dialog);
+
+void applet_mobile_pin_dialog_set_entry1 (GtkWidget *dialog,
+ const char *label,
+ guint32 minlen,
+ guint32 maxlen);
+const char *applet_mobile_pin_dialog_get_entry1 (GtkWidget *dialog);
+
+void applet_mobile_pin_dialog_set_entry2 (GtkWidget *dialog,
+ const char *label,
+ guint32 minlen,
+ guint32 maxlen);
+const char *applet_mobile_pin_dialog_get_entry2 (GtkWidget *dialog);
+
+void applet_mobile_pin_dialog_set_entry3 (GtkWidget *dialog,
+ const char *label,
+ guint32 minlen,
+ guint32 maxlen);
+const char *applet_mobile_pin_dialog_get_entry3 (GtkWidget *dialog);
+
+void applet_mobile_pin_dialog_match_23 (GtkWidget *dialog, gboolean match);
+
+void applet_mobile_pin_dialog_start_spinner (GtkWidget *dialog, const char *text);
+void applet_mobile_pin_dialog_stop_spinner (GtkWidget *dialog);
+
#endif /* __APPLET_DIALOGS_H__ */
diff --git a/src/applet.glade b/src/applet.glade
index ac8bbde..b506dc5 100644
--- a/src/applet.glade
+++ b/src/applet.glade
@@ -1797,4 +1797,265 @@ Version 1</property>
</widget>
</child>
</widget>
+ <widget class="GtkDialog" id="unlock_dialog">
+ <property name="border_width">5</property>
+ <property name="window_position">center</property>
+ <property name="default_width">400</property>
+ <property name="icon_name">dialog-password</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox4">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ <property name="stock">gtk-dialog-authentication</property>
+ <property name="icon-size">6</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">6</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <widget class="GtkLabel" id="header_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">label</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">12</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="desc_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">label</property>
+ <property name="wrap">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="top_padding">12</property>
+ <property name="bottom_padding">12</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">6</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <widget class="GtkLabel" id="code1_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">label</property>
+ </widget>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="code1_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="invisible_char">●</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="code2_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">label</property>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="code2_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="code3_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">label</property>
+ </widget>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="code3_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="progress_hbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <widget class="GtkAlignment" id="spinner_alignment">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="progress_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ <property name="y_padding">6</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area4">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <widget class="GtkButton" id="cancel_button">
+ <property name="label">gtk-cancel</property>
+ <property name="response_id">-6</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="unlock_button">
+ <property name="label" translatable="yes">_Unlock</property>
+ <property name="response_id">-5</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
</glade-interface>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]