diff options
Diffstat (limited to 'panels/sharing/cc-sharing-networks.c')
-rw-r--r-- | panels/sharing/cc-sharing-networks.c | 567 |
1 files changed, 567 insertions, 0 deletions
diff --git a/panels/sharing/cc-sharing-networks.c b/panels/sharing/cc-sharing-networks.c new file mode 100644 index 0000000..39ebf76 --- /dev/null +++ b/panels/sharing/cc-sharing-networks.c @@ -0,0 +1,567 @@ +/* + * Copyright (C) 2014 Bastien Nocera <hadess@hadess.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include "config.h" + +#include <gtk/gtk.h> +#include <gio/gio.h> +#include <glib/gi18n.h> + +#include "cc-sharing-networks.h" +#include "org.gnome.SettingsDaemon.Sharing.h" +#include "gsd-sharing-enums.h" +#include "list-box-helper.h" + +struct _CcSharingNetworks { + GtkGrid parent_instance; + + GtkWidget *listbox; + + GtkWidget *current_row; + GtkWidget *current_label; + GtkWidget *current_icon; + GtkWidget *current_switch; + + GtkWidget *no_network_row; + + char *service_name; + GsdSharing *proxy; + CcSharingStatus status; + + GList *networks; /* list of CcSharingNetwork */ +}; + + +G_DEFINE_TYPE (CcSharingNetworks, cc_sharing_networks, GTK_TYPE_GRID) + +enum { + PROP_0, + PROP_PROXY, + PROP_SERVICE_NAME, + PROP_STATUS +}; + +static void cc_sharing_networks_class_init (CcSharingNetworksClass *klass); +static void cc_sharing_networks_init (CcSharingNetworks *self); +static void cc_sharing_networks_finalize (GObject *object); + +static void cc_sharing_update_networks_box (CcSharingNetworks *self); + +typedef struct { + char *uuid; + char *network_name; + char *carrier_type; +} CcSharingNetwork; + +static void +cc_sharing_network_free (gpointer data) +{ + CcSharingNetwork *net = data; + + g_free (net->uuid); + g_free (net->network_name); + g_free (net->carrier_type); + g_free (net); +} + +static void +cc_sharing_networks_update_status (CcSharingNetworks *self) +{ + CcSharingStatus status; + + if (self->networks == NULL) + status = CC_SHARING_STATUS_OFF; + else if (gtk_widget_is_visible (self->current_switch) && + gtk_switch_get_active (GTK_SWITCH (self->current_switch))) + status = CC_SHARING_STATUS_ACTIVE; + else + status = CC_SHARING_STATUS_ENABLED; + + if (status != self->status) { + self->status = status; + g_object_notify (G_OBJECT (self), "status"); + } +} + +static void +cc_sharing_update_networks (CcSharingNetworks *self) +{ + g_autoptr(GVariant) networks = NULL; + char *uuid, *network_name, *carrier_type; + GVariantIter iter; + g_autoptr(GError) error = NULL; + + g_list_free_full (self->networks, cc_sharing_network_free); + self->networks = NULL; + + if (!gsd_sharing_call_list_networks_sync (self->proxy, self->service_name, &networks, NULL, &error)) { + g_warning ("couldn't list networks: %s", error->message); + g_dbus_proxy_set_cached_property (G_DBUS_PROXY (self->proxy), + "SharingStatus", + g_variant_new_uint32 (GSD_SHARING_STATUS_OFFLINE)); + cc_list_box_adjust_scrolling (GTK_LIST_BOX (self->listbox)); + return; + } + + g_variant_iter_init (&iter, networks); + while (g_variant_iter_next (&iter, "(sss)", &uuid, &network_name, &carrier_type)) { + CcSharingNetwork *net; + + net = g_new0 (CcSharingNetwork, 1); + net->uuid = uuid; + net->network_name = network_name; + net->carrier_type = carrier_type; + self->networks = g_list_prepend (self->networks, net); + } + self->networks = g_list_reverse (self->networks); + cc_list_box_adjust_scrolling (GTK_LIST_BOX (self->listbox)); +} + +static void +cc_sharing_networks_remove_network (CcSharingNetworks *self, + GtkWidget *button) +{ + GtkWidget *row; + g_autoptr(GError) error = NULL; + gboolean ret; + const char *uuid; + + row = g_object_get_data (G_OBJECT (button), "row"); + uuid = g_object_get_data (G_OBJECT (row), "uuid"); + + ret = gsd_sharing_call_disable_service_sync (self->proxy, + self->service_name, + uuid, + NULL, + &error); + if (!ret) + g_warning ("Failed to remove service %s: %s", + self->service_name, error->message); + + cc_sharing_update_networks (self); + cc_sharing_update_networks_box (self); +} + +static gboolean +cc_sharing_networks_enable_network (CcSharingNetworks *self, + gboolean state, + GtkSwitch *widget) +{ + g_autoptr(GError) error = NULL; + gboolean ret; + + if (state) { + ret = gsd_sharing_call_enable_service_sync (self->proxy, + self->service_name, + NULL, + &error); + } else { + ret = gsd_sharing_call_disable_service_sync (self->proxy, + self->service_name, + gsd_sharing_get_current_network (self->proxy), + NULL, + &error); + } + + if (ret) { + gtk_switch_set_state (widget, state); + } else { + g_warning ("Failed to %s service %s: %s", state ? "enable" : "disable", + self->service_name, error->message); + g_signal_handlers_block_by_func (widget, + cc_sharing_networks_enable_network, self); + gtk_switch_set_active (widget, !state); + g_signal_handlers_unblock_by_func (widget, + cc_sharing_networks_enable_network, self); + } + + cc_sharing_update_networks (self); + cc_sharing_networks_update_status (self); + + return TRUE; +} + +static GtkWidget * +cc_sharing_networks_new_row (const char *uuid, + const char *network_name, + const char *carrier_type, + CcSharingNetworks *self) +{ + GtkWidget *row, *box, *w; + const char *icon_name; + + row = gtk_list_box_row_new (); + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_show (box); + gtk_container_set_border_width (GTK_CONTAINER (box), 3); + gtk_widget_set_margin_start (box, 6); + gtk_container_add (GTK_CONTAINER (row), box); + + if (g_strcmp0 (carrier_type, "802-11-wireless") == 0) { + icon_name = "network-wireless-offline-symbolic"; + } else if (g_strcmp0 (carrier_type, "802-3-ethernet") == 0) { + icon_name = "network-wired-disconnected-symbolic"; + } else { + icon_name = "network-wired-symbolic"; + } + + w = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); + gtk_widget_show (w); + gtk_widget_set_margin_end (w, 12); + gtk_container_add (GTK_CONTAINER (box), w); + + /* Label */ + w = gtk_label_new (network_name); + gtk_widget_show (w); + gtk_widget_set_margin_end (w, 12); + gtk_container_add (GTK_CONTAINER (box), w); + + /* Remove button */ + w = gtk_button_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_widget_show (w); + gtk_button_set_relief (GTK_BUTTON (w), GTK_RELIEF_NONE); + gtk_widget_set_margin_top (w, 3); + gtk_widget_set_margin_bottom (w, 3); + gtk_widget_set_margin_end (w, 12); + gtk_widget_set_valign (w, GTK_ALIGN_CENTER); + gtk_box_pack_end (GTK_BOX (box), w, FALSE, FALSE, 0); + g_signal_connect_object (G_OBJECT (w), "clicked", + G_CALLBACK (cc_sharing_networks_remove_network), self, G_CONNECT_SWAPPED); + g_object_set_data (G_OBJECT (w), "row", row); + + g_object_set_data_full (G_OBJECT (row), "uuid", g_strdup (uuid), g_free); + + return row; +} + +static GtkWidget * +cc_sharing_networks_new_current_row (CcSharingNetworks *self) +{ + GtkWidget *row, *box, *w; + + row = gtk_list_box_row_new (); + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_show (box); + gtk_container_set_border_width (GTK_CONTAINER (box), 3); + gtk_widget_set_margin_start (box, 6); + gtk_container_add (GTK_CONTAINER (row), box); + + /* Icon */ + w = gtk_image_new_from_icon_name ("image-missing", GTK_ICON_SIZE_MENU); + gtk_widget_show (w); + gtk_widget_set_margin_end (w, 12); + gtk_container_add (GTK_CONTAINER (box), w); + self->current_icon = w; + + /* Label */ + w = gtk_label_new (""); + gtk_widget_show (w); + gtk_container_add (GTK_CONTAINER (box), w); + gtk_widget_set_margin_end (w, 12); + self->current_label = w; + + w = gtk_switch_new (); + gtk_widget_show (w); + gtk_widget_set_margin_top (w, 3); + gtk_widget_set_margin_bottom (w, 3); + gtk_widget_set_margin_end (w, 12); + gtk_widget_set_valign (w, GTK_ALIGN_CENTER); + gtk_box_pack_end (GTK_BOX (box), w, FALSE, FALSE, 0); + g_signal_connect_object (G_OBJECT (w), "state-set", + G_CALLBACK (cc_sharing_networks_enable_network), self, G_CONNECT_SWAPPED); + self->current_switch = w; + g_object_set_data (G_OBJECT (w), "row", row); + + return row; +} + +static GtkWidget * +cc_sharing_networks_new_no_network_row (CcSharingNetworks *self) +{ + GtkWidget *row, *box, *w; + + row = gtk_list_box_row_new (); + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_show (box); + gtk_container_set_border_width (GTK_CONTAINER (box), 12); + gtk_container_add (GTK_CONTAINER (row), box); + + /* Label */ + w = gtk_label_new (_("No networks selected for sharing")); + gtk_widget_show (w); + gtk_widget_set_hexpand (w, TRUE); + gtk_widget_set_halign (w, GTK_ALIGN_CENTER); + gtk_style_context_add_class (gtk_widget_get_style_context (w), "dim-label"); + gtk_container_add (GTK_CONTAINER (box), w); + + return row; +} + +static void +cc_sharing_update_networks_box (CcSharingNetworks *self) +{ + gboolean current_visible; + const char *current_network; + g_autoptr(GList) children = NULL; + GList *l; + + children = gtk_container_get_children (GTK_CONTAINER (self->listbox)); + for (l = children; l != NULL; l = l->next) { + GtkWidget *row = l->data; + + if (row != self->current_row && + row != self->no_network_row) + gtk_widget_destroy (row); + } + + current_network = gsd_sharing_get_current_network (self->proxy); + + if (current_network != NULL && + !g_str_equal (current_network, "")) { + gboolean available; + const char *carrier_type, *icon_name, *current_network_name; + + gtk_widget_show (self->current_row); + current_visible = TRUE; + + /* Network name */ + g_object_set_data_full (G_OBJECT (self->current_row), + "uuid", g_strdup (current_network), g_free); + current_network_name = gsd_sharing_get_current_network_name (self->proxy); + gtk_label_set_label (GTK_LABEL (self->current_label), current_network_name); + + /* Icon */ + carrier_type = gsd_sharing_get_carrier_type (self->proxy); + if (g_strcmp0 (carrier_type, "802-11-wireless") == 0) { + icon_name = "network-wireless-signal-excellent-symbolic"; + } else if (g_strcmp0 (carrier_type, "802-3-ethernet") == 0) { + icon_name = "network-wired-symbolic"; + } else { + icon_name = "network-wired-symbolic"; + } + gtk_image_set_from_icon_name (GTK_IMAGE (self->current_icon), icon_name, GTK_ICON_SIZE_SMALL_TOOLBAR); + + /* State */ + available = gsd_sharing_get_sharing_status (self->proxy) == GSD_SHARING_STATUS_AVAILABLE; + gtk_widget_set_sensitive (self->current_switch, available); + //FIXME add a subtitle explaining why it's disabled + } else { + gtk_widget_hide (self->current_row); + current_visible = FALSE; + } + + for (l = self->networks; l != NULL; l = l->next) { + CcSharingNetwork *net = l->data; + GtkWidget *row; + + if (g_strcmp0 (net->uuid, current_network) == 0) { + g_signal_handlers_block_by_func (self->current_switch, + cc_sharing_networks_enable_network, self); + gtk_switch_set_state (GTK_SWITCH (self->current_switch), TRUE); + g_signal_handlers_unblock_by_func (self->current_switch, + cc_sharing_networks_enable_network, self); + continue; + } + + row = cc_sharing_networks_new_row (net->uuid, + net->network_name, + net->carrier_type, + self); + gtk_widget_show (row); + gtk_list_box_insert (GTK_LIST_BOX (self->listbox), row, -1); + } + + if (self->networks == NULL && + !current_visible) { + gtk_widget_show (self->no_network_row); + } else { + gtk_widget_hide (self->no_network_row); + } + + cc_sharing_networks_update_status (self); + + cc_list_box_adjust_scrolling (GTK_LIST_BOX (self->listbox)); +} + +static void +current_network_changed (CcSharingNetworks *self) +{ + cc_sharing_update_networks (self); + cc_sharing_update_networks_box (self); +} + +static void +cc_sharing_networks_constructed (GObject *object) +{ + CcSharingNetworks *self; + + G_OBJECT_CLASS (cc_sharing_networks_parent_class)->constructed (object); + + self = CC_SHARING_NETWORKS (object); + + gtk_list_box_set_header_func (GTK_LIST_BOX (self->listbox), + cc_list_box_update_header_func, NULL, + NULL); + + cc_list_box_setup_scrolling (GTK_LIST_BOX (self->listbox), 3); + + self->current_row = cc_sharing_networks_new_current_row (self); + gtk_list_box_insert (GTK_LIST_BOX (self->listbox), self->current_row, -1); + g_object_set_data (G_OBJECT (self), "switch", self->current_switch); + + self->no_network_row = cc_sharing_networks_new_no_network_row (self); + gtk_list_box_insert (GTK_LIST_BOX (self->listbox), self->no_network_row, -1); + + cc_sharing_update_networks (self); + cc_sharing_update_networks_box (self); + + g_signal_connect_object (self->proxy, "notify::current-network", + G_CALLBACK (current_network_changed), self, G_CONNECT_SWAPPED); +} + +static void +cc_sharing_networks_init (CcSharingNetworks *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} + +GtkWidget * +cc_sharing_networks_new (GDBusProxy *proxy, + const char *service_name) +{ + g_return_val_if_fail (GSD_IS_SHARING (proxy), NULL); + g_return_val_if_fail (service_name != NULL, NULL); + + return GTK_WIDGET (g_object_new (CC_TYPE_SHARING_NETWORKS, + "proxy", proxy, + "service-name", service_name, + NULL)); +} + +static void +cc_sharing_networks_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + CcSharingNetworks *self; + + self = CC_SHARING_NETWORKS (object); + + switch (prop_id) { + case PROP_SERVICE_NAME: + self->service_name = g_value_dup_string (value); + break; + case PROP_PROXY: + self->proxy = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +cc_sharing_networks_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + CcSharingNetworks *self; + + self = CC_SHARING_NETWORKS (object); + + switch (prop_id) { + case PROP_STATUS: + g_value_set_uint (value, self->status); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +cc_sharing_networks_finalize (GObject *object) +{ + CcSharingNetworks *self; + + g_return_if_fail (object != NULL); + g_return_if_fail (CC_IS_SHARING_NETWORKS (object)); + + self = CC_SHARING_NETWORKS (object); + + g_return_if_fail (self != NULL); + + g_clear_object (&self->proxy); + g_clear_pointer (&self->service_name, g_free); + + if (self->networks != NULL) { + g_list_free_full (self->networks, cc_sharing_network_free); + self->networks = NULL; + } + + G_OBJECT_CLASS (cc_sharing_networks_parent_class)->finalize (object); +} + + +static void +cc_sharing_networks_class_init (CcSharingNetworksClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->set_property = cc_sharing_networks_set_property; + object_class->get_property = cc_sharing_networks_get_property; + object_class->finalize = cc_sharing_networks_finalize; + object_class->constructed = cc_sharing_networks_constructed; + + g_object_class_install_property (object_class, + PROP_PROXY, + g_param_spec_object ("proxy", + "proxy", + "proxy", + GSD_TYPE_SHARING_PROXY, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, + PROP_SERVICE_NAME, + g_param_spec_string ("service-name", + "service-name", + "service-name", + NULL, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, + PROP_STATUS, + g_param_spec_uint ("status", + "status", + "status", + CC_SHARING_STATUS_UNSET, CC_SHARING_STATUS_ACTIVE + 1, CC_SHARING_STATUS_OFF, + G_PARAM_READABLE)); + + gtk_widget_class_set_template_from_resource (widget_class, + "/org/gnome/control-center/sharing/cc-sharing-networks.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcSharingNetworks, listbox); +} + +/* + * vim: sw=2 ts=8 cindent noai bs=2 + */ |