/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright © 2012 – 2017 Red Hat, Inc.
* Copyright © 2013 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib/gi18n-lib.h>
#include <tp-account-widgets/tpaw-account-widget.h>
#include <tp-account-widgets/tpaw-user-info.h>
#include <tp-account-widgets/tpaw-utils.h>
#include "goaprovider.h"
#include "goaprovider-priv.h"
#include "goatelepathyprovider.h"
#include "goatpaccountlinker.h"
#include "goaobjectskeletonutils.h"
#include "goautils.h"
typedef struct _GoaTelepathyProviderPrivate GoaTelepathyProviderPrivate;
struct _GoaTelepathyProviderPrivate
{
TpawProtocol *protocol;
gchar *protocol_name;
gchar *provider_type;
};
enum {
PROP_0,
PROP_PROTOCOL,
PROP_PROTOCOL_NAME,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _GoaTelepathyProvider
{
GoaProvider parent_instance;
GoaTelepathyProviderPrivate *priv;
};
typedef struct _GoaTelepathyProviderClass GoaTelepathyProviderClass;
struct _GoaTelepathyProviderClass
{
GoaProviderClass parent_class;
};
G_DEFINE_TYPE (GoaTelepathyProvider, goa_telepathy_provider, GOA_TYPE_PROVIDER);
/* ---------------------------------------------------------------------------------------------------- */
static GoaTpAccountLinker *tp_linker = NULL;
static guint name_watcher_id = 0;
/* ---------------------------------------------------------------------------------------------------- */
/* Telepathy / telepathy-account widgets utility functions. */
static void
account_settings_ready_cb (TpawAccountSettings *settings,
GParamSpec *pspec,
gpointer user_data)
{
GMainLoop *loop = user_data;
g_main_loop_quit (loop);
}
static void
wait_for_account_settings_ready (TpawAccountSettings *settings,
GMainLoop *loop)
{
if (!tpaw_account_settings_is_ready (settings))
{
g_signal_connect (settings, "notify::ready",
G_CALLBACK (account_settings_ready_cb), loop);
g_main_loop_run (loop);
}
}
typedef struct
{
GMainLoop *loop;
GError *error;
gboolean ret;
} PrepareTpProxyData;
static void
proxy_prepared_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
PrepareTpProxyData *data = user_data;
data->ret = tp_proxy_prepare_finish (object, res, &data->error);
g_main_loop_quit (data->loop);
}
static gboolean
prepare_tp_proxy (gpointer proxy,
const GQuark *features,
GMainLoop *loop,
GError **error)
{
PrepareTpProxyData data = { NULL, };
data.loop = loop;
tp_proxy_prepare_async (proxy, features, proxy_prepared_cb, &data);
g_main_loop_run (data.loop);
if (data.error != NULL)
{
g_propagate_error (error, data.error);
g_clear_error (&data.error);
}
return data.ret;
}
static TpAccount *
find_tp_account (GoaObject *goa_object,
GMainLoop *loop,
GError **out_error)
{
GoaAccount *goa_account = NULL;
const gchar *id = NULL;
TpAccountManager *account_manager;
GList *tp_accounts = NULL;
GList *l = NULL;
TpAccount *tp_account = NULL;
GError *error = NULL;
goa_account = goa_object_peek_account (goa_object);
id = goa_account_get_identity (goa_account);
account_manager = tp_account_manager_dup ();
if (!prepare_tp_proxy (account_manager, NULL, loop, &error))
goto out;
tp_accounts = tp_account_manager_dup_valid_accounts (account_manager);
for (l = tp_accounts; l != NULL; l = l->next)
{
if (g_strcmp0 (tp_proxy_get_object_path (l->data), id) == 0)
{
tp_account = g_object_ref (l->data);
break;
}
}
if (tp_account == NULL)
{
g_set_error (&error,
GOA_ERROR,
GOA_ERROR_FAILED,
_("Telepathy chat account not found"));
goto out;
}
out:
if (error != NULL)
g_propagate_error (out_error, error);
g_clear_error (&error);
g_clear_object (&account_manager);
g_list_free_full (tp_accounts, g_object_unref);
return tp_account;
}
/* ---------------------------------------------------------------------------------------------------- */
static const gchar *
get_provider_type (GoaProvider *provider)
{
GoaTelepathyProviderPrivate *priv = GOA_TELEPATHY_PROVIDER (provider)->priv;
return priv->provider_type;
}
static gchar *
get_provider_name (GoaProvider *provider,
GoaObject *object)
{
GoaTelepathyProviderPrivate *priv = GOA_TELEPATHY_PROVIDER (provider)->priv;
return g_strdup (tpaw_protocol_name_to_display_name (priv->protocol_name));
}
static GIcon *
get_provider_icon (GoaProvider *provider,
GoaObject *object)
{
GoaTelepathyProviderPrivate *priv = GOA_TELEPATHY_PROVIDER (provider)->priv;
const gchar *icon_names[3];
gchar *icon_name;
GIcon *icon;
/* Use symbolic icons for generic protocols. Use icons for the
* branded ones if it matches their visual identity. Otherwise do
* not use an icon.
*/
if (g_strcmp0 (priv->protocol_name, "irc") == 0
|| g_strcmp0 (priv->protocol_name, "jabber") == 0
|| g_strcmp0 (priv->protocol_name, "local-xmpp") == 0
|| g_strcmp0 (priv->protocol_name, "sip") == 0)
{
icon_name = g_strdup ("user-available-symbolic");
}
else if (g_strcmp0 (priv->protocol_name, "aim") == 0
|| g_strcmp0 (priv->protocol_name, "gadugadu") == 0
|| g_strcmp0 (priv->protocol_name, "silc") == 0)
{
icon_name = tpaw_protocol_icon_name (priv->protocol_name);
}
else
{
icon_name = g_strdup ("goa-account");
}
icon_names[0] = icon_name;
/* If the icon doesn't exist, just try with the default icon. */
icon_names[1] = "goa-account";
icon_names[2] = NULL;
icon = g_themed_icon_new_from_names ((gchar **) icon_names, -1);
g_free (icon_name);
return icon;
}
static GoaProviderGroup
get_provider_group (GoaProvider *provider)
{
return GOA_PROVIDER_GROUP_CHAT;
}
static GoaProviderFeatures
get_provider_features (GoaProvider *provider)
{
return GOA_PROVIDER_FEATURE_CHAT;
}
/* ---------------------------------------------------------------------------------------------------- */
static void
on_name_acquired (GDBusConnection *connection,
const gchar *name,
const gchar *name_owner,
gpointer user_data)
{
tp_linker = goa_tp_account_linker_new ();
g_bus_unwatch_name (name_watcher_id);
name_watcher_id = 0;
}
static void
initialize (GoaProvider *provider)
{
static gsize once_init_value = 0;
if (g_once_init_enter (&once_init_value))
{
name_watcher_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
"org.gnome.OnlineAccounts",
G_BUS_NAME_WATCHER_FLAGS_NONE,
on_name_acquired,
NULL,
NULL,
NULL);
g_once_init_leave (&once_init_value, 1);
}
}
/* ---------------------------------------------------------------------------------------------------- */
typedef struct
{
GMainLoop *loop;
GoaObject *ret;
GError *error;
GoaTelepathyProvider *provider;
GtkDialog *dialog;
GtkBox *vbox;
gboolean close_received;
TpAccount *tp_account;
GoaClient *goa_client;
guint goa_account_added_id;
} AddAccountData;
static void
quit_main_loop_if_finished (AddAccountData *data)
{
if (data->ret != NULL && data->close_received)
g_main_loop_quit (data->loop);
}
static void
run_main_loop_if_needed (AddAccountData *data)
{
if (data->ret == NULL || !data->close_received)
g_main_loop_run (data->loop);
}
static gboolean
check_goa_object_match (AddAccountData *data,
GoaObject *goa_object)
{
GoaTelepathyProviderPrivate *priv = data->provider->priv;
GoaAccount *goa_account = NULL;
const gchar *provider_type = NULL;
const gchar *goa_id = NULL;
const gchar *tp_id = NULL;
if (data->tp_account == NULL)
{
/* Still waiting for the creation of the TpAccount */
return FALSE;
}
goa_account = goa_object_peek_account (goa_object);
provider_type = goa_account_get_provider_type (goa_account);
if (g_strcmp0 (provider_type, priv->provider_type) != 0)
return FALSE;
/* The backend-specific identity is set to the object path of the
* corresponding Telepathy account object. */
goa_id = goa_account_get_identity (goa_account);
tp_id = tp_proxy_get_object_path (TP_PROXY (data->tp_account));
if (g_strcmp0 (goa_id, tp_id) == 0)
{
/* Found it! */
data->ret = g_object_ref (goa_object);
quit_main_loop_if_finished (data);
return TRUE;
}
return FALSE;
}
static gboolean
check_existing_goa_accounts (AddAccountData *data)
{
GList *goa_accounts = NULL;
GList *l = NULL;
gboolean found = FALSE;
if (data->tp_account == NULL)
return FALSE;
goa_accounts = goa_client_get_accounts (data->goa_client);
for (l = goa_accounts; l != NULL; l = l->next)
{
if (check_goa_object_match (data, l->data))
{
found = TRUE;
break;
}
}
g_list_free_full (goa_accounts, g_object_unref);
return found;
}
static void
tp_account_created_cb (TpawAccountWidget *widget,
TpAccount *tp_account,
AddAccountData *data)
{
g_assert (data->tp_account == NULL);
data->tp_account = g_object_ref (tp_account);
check_existing_goa_accounts (data);
}
static void
goa_account_added_cb (GoaClient *client,
GoaObject *goa_object,
gpointer user_data)
{
AddAccountData *data = user_data;
check_goa_object_match (data, goa_object);
}
static void
account_widget_close_cb (TpawAccountWidget *widget,
GtkResponseType response,
AddAccountData *data)
{
data->close_received = TRUE;
quit_main_loop_if_finished (data);
}
static GoaObject *
add_account (GoaProvider *provider,
GoaClient *client,
GtkDialog *dialog,
GtkBox *vbox,
GError **error)
{
GoaTelepathyProviderPrivate *priv = GOA_TELEPATHY_PROVIDER (provider)->priv;
AddAccountData data;
TpawAccountSettings *settings = NULL;
TpawAccountWidget *account_widget = NULL;
gint response;
gint width;
settings = tpaw_protocol_create_account_settings (priv->protocol);
if (settings == NULL)
{
g_set_error (&data.error,
GOA_ERROR,
GOA_ERROR_FAILED,
_("Failed to create a user interface for %s"),
priv->protocol != NULL ?
tpaw_protocol_get_protocol_name (priv->protocol) :
"(null)");
return NULL;
}
memset (&data, 0, sizeof (AddAccountData));
data.loop = g_main_loop_new (NULL, FALSE);
data.error = NULL;
data.provider = GOA_TELEPATHY_PROVIDER (provider);
data.dialog = dialog;
data.vbox = vbox;
data.goa_client = client;
data.goa_account_added_id = g_signal_connect (data.goa_client,
"account-added", G_CALLBACK (goa_account_added_cb), &data);
wait_for_account_settings_ready (settings, data.loop);
account_widget = tpaw_account_widget_new_for_protocol (settings,
dialog, TRUE);
gtk_container_add (GTK_CONTAINER (vbox), GTK_WIDGET (account_widget));
gtk_widget_show (GTK_WIDGET (account_widget));
g_signal_connect (account_widget, "account-created",
G_CALLBACK (tp_account_created_cb), &data);
g_signal_connect (account_widget, "close",
G_CALLBACK (account_widget_close_cb), &data);
/* The dialog now contains a lot of empty space between the account widget
* and the buttons. We force it's vertical size to be just right to fit the
* widget. */
gtk_window_get_size (GTK_WINDOW (dialog), &width, NULL);
gtk_window_set_default_size (GTK_WINDOW (dialog), width, -1);
response = gtk_dialog_run (GTK_DIALOG (dialog));
if (response != GTK_RESPONSE_OK && response != GTK_RESPONSE_APPLY)
{
g_set_error (&data.error,
GOA_ERROR,
GOA_ERROR_DIALOG_DISMISSED,
_("Dialog was dismissed"));
goto out;
}
if (data.error != NULL)
{
/* An error could have been set by a callback */
goto out;
}
/* We wait for the account to be created */
run_main_loop_if_needed (&data);
out:
if (data.error != NULL)
g_propagate_error (error, data.error);
else
g_assert (data.ret != NULL);
if (data.goa_account_added_id)
g_signal_handler_disconnect (data.goa_client, data.goa_account_added_id);
g_clear_pointer (&data.loop, g_main_loop_unref);
g_clear_object (&data.tp_account);
return data.ret;
}
/* ---------------------------------------------------------------------------------------------------- */
static void
account_dialog_widget_cancelled_cb (TpawAccountWidget *account_widget,
gpointer user_data)
{
GError **error = user_data;
g_set_error (error,
GOA_ERROR,
GOA_ERROR_DIALOG_DISMISSED,
_("Dialog was dismissed"));
}
static gboolean
edit_connection_parameters (GoaObject *goa_object,
GtkWindow *parent,
GError **out_error)
{
GMainLoop *loop = NULL;
TpAccount *tp_account = NULL;
TpawAccountSettings *settings = NULL;
GtkWidget *dialog = NULL;
TpawAccountWidget *account_widget = NULL;
GtkWidget *content_area = NULL;
gboolean ret;
GError *error = NULL;
loop = g_main_loop_new (NULL, FALSE);
tp_account = find_tp_account (goa_object, loop, &error);
if (tp_account == NULL)
goto out;
settings = tpaw_account_settings_new_for_account (tp_account);
wait_for_account_settings_ready (settings, loop);
dialog = gtk_dialog_new_with_buttons (_("Connection Settings"),
parent,
GTK_DIALOG_MODAL
| GTK_DIALOG_DESTROY_WITH_PARENT
| GTK_DIALOG_USE_HEADER_BAR,
NULL, NULL);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
account_widget = tpaw_account_widget_new_for_protocol (settings,
GTK_DIALOG (dialog), FALSE);
gtk_widget_set_margin_end (GTK_WIDGET (account_widget), 6);
gtk_widget_set_margin_start (GTK_WIDGET (account_widget), 6);
gtk_widget_set_margin_top (GTK_WIDGET (account_widget), 6);
g_signal_connect (account_widget, "cancelled",
G_CALLBACK (account_dialog_widget_cancelled_cb), &error);
g_signal_connect_swapped (account_widget, "close",
G_CALLBACK (g_main_loop_quit), loop);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
gtk_box_pack_start (GTK_BOX (content_area), GTK_WIDGET (account_widget),
TRUE, TRUE, 0);
gtk_widget_show (GTK_WIDGET (account_widget));
gtk_widget_show (dialog);
/* Wait for the dialog to be dismissed */
g_main_loop_run (loop);
gtk_widget_destroy (dialog);
out:
if (error != NULL)
{
g_propagate_error (out_error, error);
ret = FALSE;
}
else
{
ret = TRUE;
}
g_clear_object (&settings);
g_clear_object (&tp_account);
g_clear_pointer (&loop, g_main_loop_unref);
return ret;
}
static gboolean
refresh_account (GoaProvider *provider,
GoaClient *client,
GoaObject *object,
GtkWindow *parent,
GError **error)
{
return edit_connection_parameters (object, parent, error);
}
/* ---------------------------------------------------------------------------------------------------- */
typedef struct
{
GMainLoop *loop;
GError *error;
} EditPersonalDetailsData;
static void
user_info_apply_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
EditPersonalDetailsData *data = user_data;
tpaw_user_info_apply_finish (TPAW_USER_INFO (object), res, &data->error);
g_main_loop_quit (data->loop);
}
static gboolean
personal_details_timeout_cb (gpointer user_data)
{
EditPersonalDetailsData *data = user_data;
g_main_loop_quit (data->loop);
return G_SOURCE_REMOVE;
}
static gboolean
edit_personal_details (GoaObject *goa_object,
GtkWindow *parent,
GError **error)
{
EditPersonalDetailsData data;
TpAccount *tp_account = NULL;
GtkWidget *dialog = NULL;
GtkWidget *user_info = NULL;
GtkWidget *content_area = NULL;
gint response;
gboolean ret = FALSE;
memset (&data, 0, sizeof (EditPersonalDetailsData));
data.loop = g_main_loop_new (NULL, FALSE);
tp_account = find_tp_account (goa_object, data.loop, &data.error);
if (tp_account == NULL)
goto out;
dialog = gtk_dialog_new_with_buttons (_("Personal Details"),
parent,
GTK_DIALOG_MODAL
| GTK_DIALOG_DESTROY_WITH_PARENT
| GTK_DIALOG_USE_HEADER_BAR,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
user_info = tpaw_user_info_new (tp_account);
gtk_widget_set_margin_end (user_info, 6);
gtk_widget_set_margin_start (user_info, 6);
gtk_widget_set_margin_top (user_info, 6);
gtk_widget_show (user_info);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
gtk_box_pack_start (GTK_BOX (content_area), user_info, TRUE, TRUE, 0);
g_timeout_add (100, personal_details_timeout_cb, &data);
g_main_loop_run (data.loop);
response = gtk_dialog_run (GTK_DIALOG (dialog));
if (response == GTK_RESPONSE_OK)
{
tpaw_user_info_apply_async (TPAW_USER_INFO (user_info),
user_info_apply_cb, &data);
g_main_loop_run (data.loop);
if (data.error != NULL)
goto out;
}
else
{
g_set_error (&data.error,
GOA_ERROR,
GOA_ERROR_DIALOG_DISMISSED,
_("Dialog was dismissed"));
goto out;
}
ret = TRUE;
out:
if (data.error != NULL)
{
g_propagate_error (error, data.error);
}
g_clear_pointer (&dialog, gtk_widget_destroy);
g_clear_object (&tp_account);
g_clear_pointer (&data.loop, g_main_loop_unref);
return ret;
}
/* ---------------------------------------------------------------------------------------------------- */
static gboolean
build_object (GoaProvider *provider,
GoaObjectSkeleton *object,
GKeyFile *key_file,
const gchar *group,
GDBusConnection *connection,
gboolean just_added,
GError **error)
{
GoaAccount *account;
gboolean chat_enabled;
gboolean ret;
account = NULL;
ret = FALSE;
/* Chain up */
if (!GOA_PROVIDER_CLASS (goa_telepathy_provider_parent_class)->build_object (provider,
object,
key_file,
group,
connection,
just_added,
error))
goto out;
account = goa_object_get_account (GOA_OBJECT (object));
/* Chat */
chat_enabled = g_key_file_get_boolean (key_file, group, "ChatEnabled", NULL);
goa_object_skeleton_attach_chat (object, chat_enabled);
if (just_added)
{
goa_account_set_chat_disabled (account, !chat_enabled);
g_signal_connect (account,
"notify::chat-disabled",
G_CALLBACK (goa_util_account_notify_property_cb),
(gpointer) "ChatEnabled");
}
ret = TRUE;
out:
g_clear_object (&account);
return ret;
}
/* ---------------------------------------------------------------------------------------------------- */
static void
remove_account_remove_tp_account_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GError *error;
GTask *task = G_TASK (user_data);
error = NULL;
if (!goa_tp_account_linker_remove_tp_account_finish (tp_linker, res, &error))
{
g_task_return_error (task, error);
goto out;
}
g_task_return_boolean (task, TRUE);
out:
g_object_unref (task);
}
static void
remove_account (GoaProvider *provider,
GoaObject *object,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GoaTelepathyProvider *self = GOA_TELEPATHY_PROVIDER (provider);
GTask *task;
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, remove_account);
goa_tp_account_linker_remove_tp_account (tp_linker,
object,
cancellable,
remove_account_remove_tp_account_cb,
g_object_ref (task));
g_object_unref (task);
}
static gboolean
remove_account_finish (GoaProvider *provider,
GAsyncResult *res,
GError **error)
{
GoaTelepathyProvider *self = GOA_TELEPATHY_PROVIDER (provider);
GTask *task;
g_return_val_if_fail (g_task_is_valid (res, self), FALSE);
task = G_TASK (res);
g_return_val_if_fail (g_task_get_source_tag (task) == remove_account, FALSE);
return g_task_propagate_boolean (task, error);
}
/* ---------------------------------------------------------------------------------------------------- */
typedef struct
{
guint ref_count;
GoaObject *object;
GtkWindow *parent;
} EditData;
static EditData *
edit_data_new (GoaObject *object,
GtkWindow *parent)
{
EditData *data;
data = g_slice_new0 (EditData);
data->ref_count = 1;
data->object = g_object_ref (object);
data->parent = parent;
return data;
}
static void
edit_data_unref (EditData *data)
{
data->ref_count--;
if (data->ref_count >= 1)
return;
g_object_unref (data->object);
g_slice_free (EditData, data);
}
static void
edit_button_destroy_cb (GtkWidget *button,
gpointer user_data)
{
EditData *data = user_data;
edit_data_unref (data);
}
static void
edit_data_handle_button (EditData *data,
GtkWidget *button,
GCallback cb)
{
g_return_if_fail (GTK_IS_BUTTON (button));
g_signal_connect (button, "clicked", cb, data);
g_signal_connect (button, "destroy", G_CALLBACK (edit_button_destroy_cb), data);
data->ref_count++;
}
static void
maybe_show_error (GtkWindow *parent,
GError *error,
const gchar *msg)
{
GtkWidget *dialog;
if (error->domain == GOA_ERROR && error->code == GOA_ERROR_DIALOG_DISMISSED)
return;
dialog = gtk_message_dialog_new (GTK_WINDOW (parent),
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
"%s: %s (%s, %d)",
msg,
error->message,
g_quark_to_string (error->domain),
error->code);
g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
gtk_dialog_run (GTK_DIALOG (dialog));
}
static void
edit_parameters_clicked_cb (GtkButton *button,
gpointer user_data)
{
EditData *data = user_data;
GError *error = NULL;
if (!edit_connection_parameters (data->object, data->parent, &error))
maybe_show_error (data->parent, error, _("Cannot save the connection parameters"));
g_clear_error (&error);
}
static void
edit_personal_details_clicked_cb (GtkButton *button,
gpointer user_data)
{
EditData *data = user_data;
GError *error = NULL;
if (!edit_personal_details (data->object, data->parent, &error))
maybe_show_error (data->parent, error,
_("Cannot save your personal information on the server"));
g_clear_error (&error);
}
static void
show_account (GoaProvider *provider,
GoaClient *client,
GoaObject *object,
GtkBox *vbox,
G_GNUC_UNUSED GtkGrid *dummy1,
G_GNUC_UNUSED GtkGrid *dummy2)
{
EditData *data = NULL;
GtkWidget *grid;
GtkWidget *params_button = NULL;
GtkWidget *details_button = NULL;
GtkWidget *button_box = NULL;
gint row = 0;
goa_utils_account_add_attention_needed (client, object, provider, vbox);
grid = gtk_grid_new ();
gtk_widget_set_halign (grid, GTK_ALIGN_CENTER);
gtk_widget_set_hexpand (grid, TRUE);
gtk_widget_set_margin_end (grid, 72);
gtk_widget_set_margin_start (grid, 72);
gtk_widget_set_margin_top (grid, 24);
gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
gtk_container_add (GTK_CONTAINER (vbox), grid);
goa_utils_account_add_header (object, GTK_GRID (grid), row++);
goa_util_add_row_switch_from_keyfile_with_blurb (GTK_GRID (grid),
row++,
object,
/* Translators: This is a label for a series of
* options switches. For example: “Use for Mail”. */
_("Use for"),
"chat-disabled",
_("C_hat"));
data = edit_data_new (object, tpaw_get_toplevel_window (GTK_WIDGET (vbox)));
/* Connection Settings button */
params_button = gtk_button_new_with_mnemonic (_("_Connection Settings"));
edit_data_handle_button (data, params_button, G_CALLBACK (edit_parameters_clicked_cb));
/* Edit Personal Information button */
details_button = gtk_button_new_with_mnemonic (_("_Personal Details"));
edit_data_handle_button (data, details_button, G_CALLBACK (edit_personal_details_clicked_cb));
/* Box containing the buttons */
button_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start (GTK_BOX (button_box), params_button,
FALSE, FALSE, 12);
gtk_container_add (GTK_CONTAINER (button_box), details_button);
goa_util_add_row_widget (GTK_GRID (grid), row++, NULL, button_box);
edit_data_unref (data);
}
/* ---------------------------------------------------------------------------------------------------- */
GoaTelepathyProvider *
goa_telepathy_provider_new_from_protocol_name (const gchar *protocol_name)
{
g_return_val_if_fail (protocol_name != NULL, NULL);
return g_object_new (GOA_TYPE_TELEPATHY_PROVIDER,
"protocol-name", protocol_name,
NULL);
}
/* ---------------------------------------------------------------------------------------------------- */
GoaTelepathyProvider *
goa_telepathy_provider_new_from_protocol (TpawProtocol *protocol)
{
g_return_val_if_fail (TPAW_IS_PROTOCOL (protocol), NULL);
return g_object_new (GOA_TYPE_TELEPATHY_PROVIDER,
"protocol", protocol,
NULL);
}
/* ---------------------------------------------------------------------------------------------------- */
static void
goa_telepathy_provider_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GoaTelepathyProviderPrivate *priv = GOA_TELEPATHY_PROVIDER (object)->priv;
switch (property_id) {
case PROP_PROTOCOL:
g_value_set_object (value, priv->protocol);
break;
case PROP_PROTOCOL_NAME:
g_value_set_string (value, priv->protocol_name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
goa_telepathy_provider_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GoaTelepathyProviderPrivate *priv = GOA_TELEPATHY_PROVIDER (object)->priv;
switch (property_id) {
case PROP_PROTOCOL:
priv->protocol = g_value_dup_object (value);
break;
case PROP_PROTOCOL_NAME:
priv->protocol_name = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
goa_telepathy_provider_init (GoaTelepathyProvider *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
GOA_TYPE_TELEPATHY_PROVIDER, GoaTelepathyProviderPrivate);
}
static void
goa_telepathy_provider_constructed (GObject *object)
{
GoaTelepathyProviderPrivate *priv = GOA_TELEPATHY_PROVIDER (object)->priv;
G_OBJECT_CLASS (goa_telepathy_provider_parent_class)->constructed (object);
if (priv->protocol != NULL)
{
if (priv->protocol_name != NULL)
g_error ("You cannot set \"protocol-name\" if you set \"protocol\"");
priv->protocol_name = g_strdup (tpaw_protocol_get_protocol_name (priv->protocol));
}
else
{
if (priv->protocol_name == NULL)
g_error ("You must set \"protocol-name\" or \"protocol\" on GoaTelepathyProvider");
}
priv->provider_type = g_strdup_printf ("%s/%s",
GOA_TELEPATHY_NAME, priv->protocol_name);
}
static void
goa_telepathy_provider_finalize (GObject *object)
{
GoaTelepathyProviderPrivate *priv = GOA_TELEPATHY_PROVIDER (object)->priv;
g_clear_object (&priv->protocol);
g_free (priv->protocol_name);
g_free (priv->provider_type);
(G_OBJECT_CLASS (goa_telepathy_provider_parent_class)->finalize) (object);
}
static void
goa_telepathy_provider_class_init (GoaTelepathyProviderClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GoaProviderClass *provider_class = GOA_PROVIDER_CLASS (klass);
goa_utils_initialize_client_factory ();
object_class->constructed = goa_telepathy_provider_constructed;
object_class->finalize = goa_telepathy_provider_finalize;
object_class->get_property = goa_telepathy_provider_get_property;
object_class->set_property = goa_telepathy_provider_set_property;
provider_class->get_provider_type = get_provider_type;
provider_class->get_provider_name = get_provider_name;
provider_class->get_provider_icon = get_provider_icon;
provider_class->get_provider_group = get_provider_group;
provider_class->get_provider_features = get_provider_features;
provider_class->initialize = initialize;
provider_class->add_account = add_account;
provider_class->refresh_account = refresh_account;
provider_class->build_object = build_object;
provider_class->remove_account = remove_account;
provider_class->remove_account_finish = remove_account_finish;
provider_class->show_account = show_account;
g_type_class_add_private (object_class, sizeof (GoaTelepathyProviderPrivate));
/**
* GoaTelepathyProvider:protocol
*
* A #TpawProtocol associated to this provider (or NULL).
*/
properties[PROP_PROTOCOL] =
g_param_spec_object ("protocol",
"Protocol",
"A #TpawProtocol associated to the provider (or NULL)",
TPAW_TYPE_PROTOCOL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
/**
* GoaTelepathyProvider:protocol-name
*
* The name of the protocol associated to the provider.
*/
properties[PROP_PROTOCOL_NAME] =
g_param_spec_string ("protocol-name",
"Protocol name",
"The name of the protocol associated to the provider",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
}