[network-manager-netbook] Fix the status icon (again).



commit eca2bb21b4e1a4da40cb4250ca9cc8a017b872e2
Author: Tambet Ingo <tambet gmail com>
Date:   Tue Jul 28 09:11:08 2009 +0300

    Fix the status icon (again).
    
    2nd rewrite.

 src/nmn-status-icon.c |  513 ++++++++++++++++++++++++++-----------------------
 1 files changed, 272 insertions(+), 241 deletions(-)
---
diff --git a/src/nmn-status-icon.c b/src/nmn-status-icon.c
index 34046ed..8003996 100644
--- a/src/nmn-status-icon.c
+++ b/src/nmn-status-icon.c
@@ -1,5 +1,6 @@
 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 
+#include <string.h>
 #include <gdk/gdk.h>
 #include <gtk/gtk.h>
 #include <nm-device-ethernet.h>
@@ -10,18 +11,6 @@
 #include "nmn-status-icon.h"
 #include "nmn-icon-cache.h"
 
-typedef enum {
-    STATUS_IMAGE_NO_NETWORK,
-    STATUS_IMAGE_ETHERNET,
-    STATUS_IMAGE_WWAN,
-    STATUS_IMAGE_WIFI_00,
-    STATUS_IMAGE_WIFI_25,
-    STATUS_IMAGE_WIFI_50,
-    STATUS_IMAGE_WIFI_75,
-    STATUS_IMAGE_WIFI_100,
-    STATUS_IMAGE_ACTIVATING,
-} StatusImage;
-
 #define ACTIVATION_STEPS 6
 
 G_DEFINE_TYPE (NmnStatusIcon, nmn_status_icon, GTK_TYPE_STATUS_ICON)
@@ -29,92 +18,46 @@ G_DEFINE_TYPE (NmnStatusIcon, nmn_status_icon, GTK_TYPE_STATUS_ICON)
 #define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NMN_TYPE_STATUS_ICON, NmnStatusIconPrivate))
 
 typedef struct {
+    NmnStatusIcon *icon;
+    void (*destroy) (gpointer);
+} NmnIconHandler;
+
+typedef struct {
     NMClient *client;
-    StatusImage current_image;
+    char *current_image;
     gboolean active;
-    guint activation_step;
 
-    NMActiveConnection *default_ac;
-    gulong ac_state_changed_id;
-
-    guint activation_animation_id;
-    guint activation_animation_index;
+    GSList *ac_list;
+    NmnIconHandler *ac_icon_handler;
 } NmnStatusIconPrivate;
 
-static StatusImage get_active_wifi_icon (NmnStatusIcon *self, NMDeviceWifi *device);
-
-static char *
-get_icon_filename (StatusImage image,
-                   guint activation_step,
-                   gboolean active)
+GtkStatusIcon *
+nmn_status_icon_new (void)
 {
-    GString *str;
-
-    str = g_string_sized_new (32);
-
-    switch (image) {
-    case STATUS_IMAGE_NO_NETWORK:
-        g_string_append (str, "nm-no-connection");
-        break;
-    case STATUS_IMAGE_ETHERNET:
-        g_string_append (str, "nm-device-wired");
-        break;
-    case STATUS_IMAGE_WWAN:
-        g_string_append (str, "nm-device-wwan");
-        break;
-    case STATUS_IMAGE_WIFI_00:
-        g_string_append (str, "nm-signal-00");
-        break;
-    case STATUS_IMAGE_WIFI_25:
-        g_string_append (str, "nm-signal-25");
-        break;
-    case STATUS_IMAGE_WIFI_50:
-        g_string_append (str, "nm-signal-50");
-        break;
-    case STATUS_IMAGE_WIFI_75:
-        g_string_append (str, "nm-signal-75");
-        break;
-    case STATUS_IMAGE_WIFI_100:
-        g_string_append (str, "nm-signal-100");
-        break;
-    case STATUS_IMAGE_ACTIVATING:
-        g_string_append_printf (str, "nm-progress-working-%02d", activation_step);
-        break;
-    }
-
-    g_string_append (str, active ? "-active" : "-normal");
-
-    return g_string_free (str, FALSE);
+    return GTK_STATUS_ICON (g_object_new (NMN_TYPE_STATUS_ICON, NULL));
 }
 
 static void
-update_icon (NmnStatusIcon *self, StatusImage image)
+update_icon (NmnStatusIcon *self, const char *image)
 {
     NmnStatusIconPrivate *priv = GET_PRIVATE (self);
-    char *filename;
+    char *real_image;
     GdkPixbuf *pixbuf;
 
-    filename = get_icon_filename (image, priv->activation_step, priv->active);
-    pixbuf = nmn_icon_cache_get (filename);
-    g_free (filename);
+    real_image = g_strconcat (image, priv->active ? "-active" : "-normal", NULL);
+    pixbuf = nmn_icon_cache_get (real_image);
+    g_free (real_image);
 
     if (pixbuf) {
-        GtkStatusIcon *s = GTK_STATUS_ICON (self);
-
-        priv->current_image = image;
-        if (!(gtk_status_icon_get_storage_type (s) == GTK_IMAGE_PIXBUF &&
-              gtk_status_icon_get_pixbuf (s) == pixbuf))
+        if (priv->current_image == NULL || strcmp (priv->current_image, image)) {
+            g_free (priv->current_image);
+            priv->current_image = g_strdup (image);
+        }
 
-            gtk_status_icon_set_from_pixbuf (s, pixbuf);
+        gtk_status_icon_set_from_pixbuf (GTK_STATUS_ICON (self), pixbuf);
     }
 }
 
-GtkStatusIcon *
-nmn_status_icon_new (void)
-{
-    return GTK_STATUS_ICON (g_object_new (NMN_TYPE_STATUS_ICON, NULL));
-}
-
 void
 nmn_status_icon_set_active (NmnStatusIcon *self,
                             gboolean active)
@@ -130,223 +73,287 @@ nmn_status_icon_set_active (NmnStatusIcon *self,
     }
 }
 
-static StatusImage
-get_active_ap_icon (NmnStatusIcon *self, NMAccessPoint *ap)
+static void
+icon_handler_destroy (NmnIconHandler *handler)
 {
-    StatusImage icon;
-    guint32 strength;
-
-    strength = nm_access_point_get_strength (ap);
-    strength = CLAMP (strength, 0, 100);
+    g_return_if_fail (handler != NULL);
 
-    if (strength > 80)
-        icon = STATUS_IMAGE_WIFI_100;
-    else if (strength > 55)
-        icon = STATUS_IMAGE_WIFI_75;
-    else if (strength > 30)
-        icon = STATUS_IMAGE_WIFI_50;
-    else if (strength > 5)
-        icon = STATUS_IMAGE_WIFI_25;
+    if (handler->destroy)
+        handler->destroy (handler);
     else
-        icon = STATUS_IMAGE_WIFI_00;
-
-    return icon;
+        g_warning ("Missing destroy method");
 }
 
+/* Pending activation animation handler */
+
+typedef struct {
+    NmnIconHandler parent;
+    guint step;
+    guint animation_id;
+    guint animation_index;
+} NmnPendingActivationHandler;
+
 static void
-ap_strength_changed (NMAccessPoint *ap, GParamSpec *pspec, gpointer user_data)
+icon_handler_pending_activation_destroy (gpointer data)
 {
-    NmnStatusIcon *self = NMN_STATUS_ICON (user_data);
+    NmnPendingActivationHandler *handler = (NmnPendingActivationHandler *) data;
+
+    g_source_remove (handler->animation_id);
+    g_free (handler);
+}
+
+static gboolean
+activation_animation (gpointer data)
+{
+    NmnPendingActivationHandler *handler = (NmnPendingActivationHandler *) data;
+    char *image;
+
+    if (++handler->step > ACTIVATION_STEPS)
+        handler->step = 1;
+
+    image = g_strdup_printf ("nm-progress-working-%02d", handler->step);
+    update_icon (handler->parent.icon, image);
+    g_free (image);
+
+    return TRUE;
+}
+
+static NmnIconHandler *
+icon_handler_pending_activation_new (NmnStatusIcon *icon)
+{
+    NmnPendingActivationHandler *handler;
+
+    handler = g_new0 (NmnPendingActivationHandler, 1);
+    handler->parent.icon = icon;
+    handler->parent.destroy = icon_handler_pending_activation_destroy;
+
+    handler->animation_id = g_timeout_add (200, activation_animation, handler);
+    activation_animation (handler);
+
+    return (NmnIconHandler *) handler;
+}
+
+
+/* Ethernet handler */
+
+static NmnIconHandler *
+icon_handler_ethernet_new (NmnStatusIcon *icon)
+{
+    NmnIconHandler *handler;
 
-    update_icon (self, get_active_ap_icon (self, ap));
+    handler = g_new0 (NmnIconHandler, 1);
+    handler->destroy = g_free;
+    update_icon (icon, "nm-device-wired");
+
+    return handler;
 }
 
+
+/* Wifi handler */
+
 typedef struct {
-    NmnStatusIcon *status_icon;
-    NMDeviceWifi *device;
+    NmnIconHandler parent;
+
+    NMDevice *device;
+    gulong active_ap_id;
+
     NMAccessPoint *ap;
     gulong ap_strength_id;
-    gulong active_ap_id;
-} WifiIconInfo;
+} NmnWifiHandler;
 
 static void
-wifi_icon_info_destroy (gpointer data,
-                        GClosure *closure)
+icon_handler_wifi_destroy (gpointer data)
 {
-    WifiIconInfo *info = (WifiIconInfo *) data;
+    NmnWifiHandler *handler = (NmnWifiHandler *) data;
+
+    g_signal_handler_disconnect (handler->device, handler->active_ap_id);
+
+    if (handler->ap_strength_id)
+        g_signal_handler_disconnect (handler->ap, handler->ap_strength_id);
 
-    g_object_unref (info->ap);
-    g_slice_free (WifiIconInfo, data);
+    g_free (handler);
 }
 
 static void
-device_active_ap_changed (NMDeviceWifi *device, GParamSpec *pspec, gpointer user_data)
+ap_strength_changed (NMAccessPoint *ap, GParamSpec *pspec, gpointer user_data)
 {
-    WifiIconInfo *info = (WifiIconInfo *) user_data;
-    NmnStatusIcon *self = info->status_icon;
+    NmnIconHandler *handler = (NmnIconHandler *) user_data;
+    const char *image;
+    guint32 strength;
 
-    /* First, remove the old signal handlers */
-    g_signal_handler_disconnect (info->device, info->active_ap_id);
-    g_signal_handler_disconnect (info->ap, info->ap_strength_id);
+    /* Hack: libnm-glib emits this signal sometimes with AP == NULL.
+       Should fix that instead */
+    strength = ap ? nm_access_point_get_strength (ap) : 0;
+    strength = CLAMP (strength, 0, 100);
 
-    /* If the device is still active, it means we've roamed to another AP,
-       set up new signal handlers and update the icon */
-    if (nm_device_get_state (NM_DEVICE (device)) == NM_DEVICE_STATE_ACTIVATED)
-        update_icon (self, get_active_wifi_icon (self, device));
-}
+    if (strength > 80)
+        image = "nm-signal-100";
+    else if (strength > 55)
+        image = "nm-signal-75";
+    else if (strength > 30)
+        image = "nm-signal-50";
+    else if (strength > 5)
+        image = "nm-signal-25";
+    else
+        image = "nm-signal-00";
 
-static StatusImage
-get_active_wifi_icon (NmnStatusIcon *self, NMDeviceWifi *device)
-{
-    NMAccessPoint *ap;
-    StatusImage icon;
-
-    ap = nm_device_wifi_get_active_access_point (device);
-    if (ap) {
-        WifiIconInfo *info;
-
-        info = g_slice_new0 (WifiIconInfo);
-        info->status_icon = self;
-        info->device = device;
-        info->ap = g_object_ref (ap);
-
-        info->active_ap_id = g_signal_connect_data (device,
-                                                    "notify::" NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT,
-                                                    G_CALLBACK (device_active_ap_changed),
-                                                    info,
-                                                    wifi_icon_info_destroy,
-                                                    0);
-
-        info->ap_strength_id = g_signal_connect (ap,
-                                                 "notify::" NM_ACCESS_POINT_STRENGTH,
-                                                 G_CALLBACK (ap_strength_changed),
-                                                 self);
-
-        icon = get_active_ap_icon (self, ap);
-    } else
-        icon = STATUS_IMAGE_WIFI_00;
-
-    return icon;
+    update_icon (handler->icon, image);
 }
 
-static StatusImage
-get_active_device_icon (NmnStatusIcon *self, NMDevice *device)
+static void
+active_ap_changed (NMDeviceWifi *device, GParamSpec *pspec, gpointer user_data)
 {
-    StatusImage icon;
-
-    if (NM_IS_DEVICE_ETHERNET (device))
-        icon = STATUS_IMAGE_ETHERNET;
-    else if (NM_IS_DEVICE_WIFI (device))
-        icon = get_active_wifi_icon (self, NM_DEVICE_WIFI (device));
-    else if (NM_IS_GSM_DEVICE (device) || NM_IS_CDMA_DEVICE (device))
-        icon = STATUS_IMAGE_WWAN;
-    else {
-        g_warning ("Unhandled device type: '%s'", G_OBJECT_TYPE_NAME (device));
-        icon = STATUS_IMAGE_NO_NETWORK;
+    NmnWifiHandler *handler = (NmnWifiHandler *) user_data;
+
+    if (handler->ap_strength_id) {
+        g_signal_handler_disconnect (handler->ap, handler->ap_strength_id);
+
+        handler->ap = NULL;
+        handler->ap_strength_id = 0;
     }
 
-    return icon;
+    handler->ap = nm_device_wifi_get_active_access_point (device);
+    if (handler->ap) {
+        handler->ap_strength_id = g_signal_connect (handler->ap, "notify::" NM_ACCESS_POINT_STRENGTH,
+                                                    G_CALLBACK (ap_strength_changed), handler);
+    }
+
+    ap_strength_changed (handler->ap, NULL, handler);
 }
 
-static gboolean
-activation_animation (gpointer data)
+static NmnIconHandler *
+icon_handler_wifi_new (NmnStatusIcon *icon, NMActiveConnection *ac)
 {
-    NmnStatusIcon *self = NMN_STATUS_ICON (data);
-    NmnStatusIconPrivate *priv = GET_PRIVATE (self);
+    const GPtrArray *active_devices;
+    NMDevice *device;
+    NmnWifiHandler *handler;
 
-    if (++priv->activation_step > ACTIVATION_STEPS)
-        priv->activation_step = 1;
+    active_devices = nm_active_connection_get_devices (ac);
+    if (!active_devices)
+        return NULL;
 
-    update_icon (self, STATUS_IMAGE_ACTIVATING);
+    device = NM_DEVICE (g_ptr_array_index (active_devices, 0));
 
-    return TRUE;
+    handler = g_new0 (NmnWifiHandler, 1);
+    handler->parent.icon = icon;
+    handler->parent.destroy = icon_handler_wifi_destroy;
+
+    handler->device = device;
+    handler->active_ap_id = g_signal_connect (device, "notify::" NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT,
+                                              G_CALLBACK (active_ap_changed),
+                                              handler);
+
+    active_ap_changed (NM_DEVICE_WIFI (device), NULL, handler);
+
+    return (NmnIconHandler *) handler;
 }
 
-/***********************************************************************************/
 
-static void
-ac_state_changed (NMActiveConnection *ac,
-                  GParamSpec *pspec,
-                  gpointer user_data)
+/* 3G handler */
+
+static NmnIconHandler *
+icon_handler_3g_new (NmnStatusIcon *icon)
 {
-    NmnStatusIcon *self = NMN_STATUS_ICON (user_data);
-    NmnStatusIconPrivate *priv = GET_PRIVATE (self);
-    const GPtrArray *active_devices;
-    NMDevice *device = NULL;
-    StatusImage icon;
-    NMActiveConnectionState state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
-
-    /* Cancel any ongoing activation animantion */
-    if (priv->activation_animation_id) {
-        g_source_remove (priv->activation_animation_id);
-        priv->activation_animation_id = 0;
-        priv->activation_animation_index = 0;
-    }
+    NmnIconHandler *handler;
+
+    handler = g_new0 (NmnIconHandler, 1);
+    handler->destroy = g_free;
+    update_icon (icon, "nm-device-wwan");
+
+    return handler;
+}
+
+
+/* Handler creator */
+
+static NmnIconHandler *
+icon_handler_create (NmnStatusIcon *self, NMActiveConnection *ac)
+{
+    NmnIconHandler *handler = NULL;
+    NMActiveConnectionState state;
+
+    state = nm_active_connection_get_state (ac);
+
+    if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING)
+        handler = icon_handler_pending_activation_new (self);
+    else if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
+        const GPtrArray *active_devices;
+        NMDevice *device = NULL;
 
-    if (ac) {
         active_devices = nm_active_connection_get_devices (ac);
-        if (active_devices) {
+        if (active_devices)
             device = NM_DEVICE (g_ptr_array_index (active_devices, 0));
-            state = nm_active_connection_get_state (ac);
-        }
-    }
 
-    switch (state) {
-    case NM_ACTIVE_CONNECTION_STATE_UNKNOWN:
-        icon = STATUS_IMAGE_NO_NETWORK;;
-        break;
-    case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
-        priv->activation_animation_id = g_timeout_add (200, activation_animation, self);
-        activation_animation (self);
-        return;
-        break;
-    case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
-        icon = get_active_device_icon (self, device);
-        break;
+        if (NM_IS_DEVICE_ETHERNET (device))
+            handler = icon_handler_ethernet_new (self);
+        else if (NM_IS_DEVICE_WIFI (device))
+            handler = icon_handler_wifi_new (self, ac);
+        else if (NM_IS_GSM_DEVICE (device) || NM_IS_CDMA_DEVICE (device))
+            handler = icon_handler_3g_new (self);
+        else
+            g_warning ("Unhandled device type: '%s'", G_OBJECT_TYPE_NAME (device));
     }
 
-    update_icon (self, icon);
+    return handler;
 }
 
+typedef struct {
+    NMActiveConnection *ac;
+    gulong signal_id;
+} AcListItem;
+
 static void
 update_best_ac (NmnStatusIcon *self)
 {
     NmnStatusIconPrivate *priv = GET_PRIVATE (self);
-    const GPtrArray *acs;
+    GSList *iter;
     NMActiveConnection *best_ac = NULL;
-    int i;
 
-    if (nm_client_get_manager_running (priv->client))
-        acs = nm_client_get_active_connections (priv->client);
-    else
-        acs = NULL;
+    for (iter = priv->ac_list; iter; iter = iter->next) {
+        AcListItem *item = (AcListItem *) iter->data;
 
-    for (i = 0; acs && i < acs->len; i++) {
-        NMActiveConnection *ac = g_ptr_array_index (acs, i);
-
-        if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_UNKNOWN)
+        if (nm_active_connection_get_state (item->ac) == NM_ACTIVE_CONNECTION_STATE_UNKNOWN)
             continue;
 
         if (!best_ac ||
-            nm_active_connection_get_state (ac) > nm_active_connection_get_state (best_ac) ||
-            nm_active_connection_get_default (ac) == TRUE)
-            best_ac = ac;
+            nm_active_connection_get_state (item->ac) > nm_active_connection_get_state (best_ac) ||
+            nm_active_connection_get_default (item->ac) == TRUE)
+            best_ac = item->ac;
     }
 
-    if (priv->default_ac && priv->default_ac != best_ac) {
-        g_signal_handler_disconnect (priv->default_ac, priv->ac_state_changed_id);
-        g_object_unref (priv->default_ac);
-        priv->default_ac = NULL;
+    if (priv->ac_icon_handler) {
+        icon_handler_destroy (priv->ac_icon_handler);
+        priv->ac_icon_handler = NULL;
     }
 
-    if (best_ac) {
-        priv->default_ac = best_ac;
-        priv->default_ac = g_object_ref (best_ac);
-        priv->ac_state_changed_id = g_signal_connect (best_ac, "notify",
-                                                      G_CALLBACK (ac_state_changed), self);
-    }
+    if (best_ac)
+        priv->ac_icon_handler = icon_handler_create (self, best_ac);
+
+    if (!priv->ac_icon_handler)
+        update_icon (self, "nm-no-connection");
+}
+
+static void
+ac_state_changed (NMActiveConnection *ac,
+                  GParamSpec *pspec,
+                  gpointer user_data)
+{
+    update_best_ac (NMN_STATUS_ICON (user_data));
+}
+
+static void
+ac_list_destroy (NmnStatusIcon *self)
+{
+    NmnStatusIconPrivate *priv = GET_PRIVATE (self);
+
+    while (priv->ac_list) {
+        AcListItem *item = (AcListItem *) priv->ac_list->data;
 
-    ac_state_changed (best_ac, NULL, self);
+        g_signal_handler_disconnect (item->ac, item->signal_id);
+        g_object_unref (item->ac);
+        g_free (item);
+        priv->ac_list = g_slist_delete_link (priv->ac_list, priv->ac_list);
+    }
 }
 
 static void
@@ -354,7 +361,31 @@ active_connections_changed (NMClient *client,
                             GParamSpec *pspec,
                             gpointer user_data)
 {
-    update_best_ac (NMN_STATUS_ICON (user_data));
+    NmnStatusIcon *self = NMN_STATUS_ICON (user_data);
+    NmnStatusIconPrivate *priv = GET_PRIVATE (self);
+    const GPtrArray *ac_list;
+    int i;
+
+    /* First, disconnect all previous handlers */
+    ac_list_destroy (self);
+
+    /* add signal handlers for each AC */
+    if (nm_client_get_manager_running (client))
+        ac_list = nm_client_get_active_connections (client);
+    else
+        ac_list = NULL;
+
+    for (i = 0; ac_list && i < ac_list->len; i++) {
+        NMActiveConnection *ac = (NMActiveConnection *) g_ptr_array_index (ac_list, i);
+        AcListItem *item;
+
+        item = g_new (AcListItem, 1);
+        item->ac = g_object_ref (ac);
+        item->signal_id = g_signal_connect (ac, "notify", G_CALLBACK (ac_state_changed), self);
+        priv->ac_list = g_slist_prepend (priv->ac_list, item);
+    }
+
+    update_best_ac (self);
 }
 
 void
@@ -373,7 +404,7 @@ nmn_status_icon_set_client (NmnStatusIcon *self,
 	                  G_CALLBACK (active_connections_changed),
 	                  self);
 
-    update_best_ac (self);
+    active_connections_changed (client, NULL, self);
 }
 
 /*****************************************************************************/
@@ -381,7 +412,7 @@ nmn_status_icon_set_client (NmnStatusIcon *self,
 static gboolean
 set_initial_icon (gpointer data)
 {
-    update_icon (NMN_STATUS_ICON (data), STATUS_IMAGE_NO_NETWORK);
+    update_icon (NMN_STATUS_ICON (data), "nm-no-connection");
 
     return FALSE;
 }
@@ -397,10 +428,10 @@ finalize (GObject *object)
 {
     NmnStatusIconPrivate *priv = GET_PRIVATE (object);
 
-    if (priv->activation_animation_id) {
-        g_source_remove (priv->activation_animation_id);
-        priv->activation_animation_id = 0;
-    }
+    if (priv->ac_icon_handler)
+        icon_handler_destroy (priv->ac_icon_handler);
+
+    ac_list_destroy (NMN_STATUS_ICON (object));
 
     if (priv->client)
         g_object_unref (priv->client);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]